Skip to content

Commit

Permalink
HyperNova Gadgets (nexus-xyz#141)
Browse files Browse the repository at this point in the history
* Restructure gadgets folder.

* Start to scratch out rough IVC.

* Start to scratch out in-circuit verifier folding.

* Various fixes and reconfigurations.

* More cleanup.

* More scratching at in-circuit sumcheck.

* More work on in-circuit recursive sumcheck.

* Various fixes to trait bounds and related rearrangement.

* More fixes.

* Rename.

* Remove IVC to separate gadgets and IVC PRs.

* Debug verification circuit.

* More updates.

* Get gadgets building.

* Update proof objects.

* Formatting and work towards tests.

* Test compiling.

* More work on gadgets.

* Get tests passing.

* Fix clippy.

* Remove debugging call forgot to remove.

* Remove debugging call forgot to remove, again.

* Remove part of IVC sketching that I missed previously.
  • Loading branch information
sjudson authored Apr 9, 2024
1 parent a3a2b15 commit 01a006b
Show file tree
Hide file tree
Showing 17 changed files with 1,757 additions and 686 deletions.
47 changes: 44 additions & 3 deletions nova/src/ccs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ pub struct CCSWitness<G: CurveGroup> {
}

/// A type that holds an CCS instance.
#[derive(Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct CCSInstance<G: CurveGroup, C: PolyCommitmentScheme<G>> {
/// Commitment to witness.
pub commitment_W: C::Commitment,
Expand Down Expand Up @@ -254,6 +254,35 @@ impl<G: CurveGroup, C: PolyCommitmentScheme<G>> CCSInstance<G, C> {
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> fmt::Debug for CCSInstance<G, C>
where
C::Commitment: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CCSInstance")
.field("commitment_W", &self.commitment_W)
.field("X", &self.X)
.finish()
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> Clone for CCSInstance<G, C> {
fn clone(&self) -> Self {
Self {
commitment_W: self.commitment_W.clone(),
X: self.X.clone(),
}
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> PartialEq for CCSInstance<G, C> {
fn eq(&self, other: &Self) -> bool {
self.commitment_W == other.commitment_W && self.X == other.X
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> Eq for CCSInstance<G, C> where C::Commitment: Eq {}

impl<G, C> Absorb for LCCSInstance<G, C>
where
G: CurveGroup + AbsorbNonNative<G::ScalarField>,
Expand Down Expand Up @@ -313,7 +342,8 @@ impl<G: CurveGroup, C: PolyCommitmentScheme<G>> LCCSInstance<G, C> {
sigmas: &[G::ScalarField],
thetas: &[G::ScalarField],
) -> Result<Self, Error> {
// uX1 = (u, X_1), oX2 = (1, x_2)
// in concept, uX1 = (u_1, x_1), oX2 = (1, x_2)
// however, we don't guarantee oX2[0] = 1 during construction, so elide it during folding
let (uX1, comm_W1) = (&self.X, self.commitment_W.clone());
let (oX2, comm_W2) = (&U2.X, U2.commitment_W.clone());

Expand Down Expand Up @@ -351,7 +381,7 @@ impl<G: CurveGroup, C: PolyCommitmentScheme<G>> LCCSInstance<G, C> {
}

/// A type that holds an LCCS instance.
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct LCCSInstance<G: CurveGroup, C: PolyCommitmentScheme<G>> {
/// Commitment to MLE of witness.
///
Expand Down Expand Up @@ -379,6 +409,17 @@ where
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> Clone for LCCSInstance<G, C> {
fn clone(&self) -> Self {
Self {
commitment_W: self.commitment_W.clone(),
X: self.X.clone(),
rs: self.rs.clone(),
vs: self.vs.clone(),
}
}
}

impl<G: CurveGroup, C: PolyCommitmentScheme<G>> PartialEq for LCCSInstance<G, C> {
fn eq(&self, other: &Self) -> bool {
self.commitment_W == other.commitment_W
Expand Down
4 changes: 3 additions & 1 deletion nova/src/circuits/nova/pcd/augmented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ use crate::{
secondary::Circuit as SecondaryCircuit,
},
gadgets::cyclefold::{
multifold, multifold_with_relaxed, primary, secondary, NonNativeAffineVar,
nova::{multifold, multifold_with_relaxed, primary},
secondary,
},
gadgets::nonnative::short_weierstrass::NonNativeAffineVar,
};

pub const SQUEEZE_NATIVE_ELEMENTS_NUM: usize = 1;
Expand Down
6 changes: 5 additions & 1 deletion nova/src/circuits/nova/sequential/augmented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ use crate::{
nimfs::{NIMFSProof, R1CSInstance, R1CSShape, RelaxedR1CSInstance},
secondary::Circuit as SecondaryCircuit,
},
gadgets::cyclefold::{multifold, primary, secondary, NonNativeAffineVar},
gadgets::cyclefold::{
nova::{multifold, primary},
secondary,
},
gadgets::nonnative::short_weierstrass::NonNativeAffineVar,
};

pub const SQUEEZE_NATIVE_ELEMENTS_NUM: usize = 1;
Expand Down
6 changes: 5 additions & 1 deletion nova/src/circuits/supernova/augmented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ use crate::{
nimfs::{NIMFSProof, R1CSInstance, RelaxedR1CSInstance},
secondary::Circuit as SecondaryCircuit,
},
gadgets::cyclefold::{multifold, primary, secondary, NonNativeAffineVar},
gadgets::cyclefold::{
nova::{multifold, primary},
secondary,
},
gadgets::nonnative::short_weierstrass::NonNativeAffineVar,
};

pub const SQUEEZE_NATIVE_ELEMENTS_NUM: usize = 1;
Expand Down
5 changes: 0 additions & 5 deletions nova/src/folding/cyclefold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,3 @@ pub(crate) type R1CSInstance<G, C> = r1cs::R1CSInstance<Projective<G>, C>;
pub(crate) type R1CSWitness<G> = r1cs::R1CSWitness<Projective<G>>;
pub(crate) type RelaxedR1CSInstance<G, C> = r1cs::RelaxedR1CSInstance<Projective<G>, C>;
pub(crate) type RelaxedR1CSWitness<G> = r1cs::RelaxedR1CSWitness<Projective<G>>;

pub(crate) type CCSShape<G> = ccs::CCSShape<Projective<G>>;
pub(crate) type CCSInstance<G, C> = ccs::CCSInstance<Projective<G>, C>;
pub(crate) type CCSWitness<G> = ccs::CCSWitness<Projective<G>>;
pub(crate) type LCCSInstance<G, C> = ccs::LCCSInstance<Projective<G>, C>;
9 changes: 9 additions & 0 deletions nova/src/folding/hypernova/cyclefold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
pub(crate) mod nimfs;
pub(crate) use super::super::cyclefold::secondary;

use crate::ccs;
use ark_ec::short_weierstrass::Projective;
use ark_std::fmt::Display;

use super::nimfs::Error as HNFoldingError;
use crate::ccs::Error as CCSError;
use crate::r1cs::Error as R1CSError;

pub(crate) type HNProof<G, RO> = super::nimfs::NIMFSProof<Projective<G>, RO>;

pub(crate) type CCSShape<G> = ccs::CCSShape<Projective<G>>;
pub(crate) type CCSInstance<G, C> = ccs::CCSInstance<Projective<G>, C>;
pub(crate) type CCSWitness<G> = ccs::CCSWitness<Projective<G>>;
pub(crate) type LCCSInstance<G, C> = ccs::LCCSInstance<Projective<G>, C>;

#[derive(Debug, Clone, Copy)]
pub enum Error {
R1CS(R1CSError),
Expand Down
12 changes: 3 additions & 9 deletions nova/src/folding/hypernova/cyclefold/nimfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@ use ark_spartan::polycommitments::{PolyCommitmentScheme, PolyCommitmentTrait};

use crate::commitment::{Commitment, CommitmentScheme};

use crate::folding::hypernova::nimfs::NIMFSProof as HNProof;
pub(crate) use crate::folding::hypernova::nimfs::NIMFSProof as HNProof;
pub use crate::folding::hypernova::nimfs::SQUEEZE_ELEMENTS_BIT_SIZE;

use super::{secondary, Error};
pub(crate) use super::{secondary, CCSInstance, CCSShape, CCSWitness, Error, LCCSInstance};
pub(crate) use crate::folding::cyclefold::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness};
use crate::{absorb::CryptographicSpongeExt, r1cs, utils::cast_field_element_unique};

pub(crate) use crate::folding::cyclefold::{
CCSInstance, CCSShape, CCSWitness, LCCSInstance, R1CSShape, RelaxedR1CSInstance,
RelaxedR1CSWitness,
};

/// Non-interactive multi-folding scheme proof.
pub struct NIMFSProof<
G1: SWCurveConfig,
Expand All @@ -28,7 +24,6 @@ pub struct NIMFSProof<
C2: CommitmentScheme<Projective<G2>>,
RO,
> {
pub(crate) commitment_T: C2::Commitment,
pub(crate) commitment_W_proof: secondary::Proof<G2, C2>,
pub(crate) hypernova_proof: HNProof<Projective<G1>, RO>,
_poly_commitment: PhantomData<C1::Commitment>,
Expand Down Expand Up @@ -121,7 +116,6 @@ where
let commitment_W_proof = secondary::Proof { commitment_T, U: W_comm_trace.0 };

let proof = Self {
commitment_T,
commitment_W_proof,
hypernova_proof,
_poly_commitment: PhantomData,
Expand Down
2 changes: 1 addition & 1 deletion nova/src/folding/hypernova/ml_sumcheck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use ark_ff::PrimeField;
use ark_std::{fmt::Display, marker::PhantomData};

mod data_structures;
mod protocol;
pub(crate) mod protocol;

#[cfg(test)]
mod tests;
Expand Down
2 changes: 1 addition & 1 deletion nova/src/folding/hypernova/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod cyclefold;
pub mod nimfs;

mod ml_sumcheck;
pub(crate) mod ml_sumcheck;
47 changes: 26 additions & 21 deletions nova/src/folding/hypernova/nimfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,9 @@ where
unsafe { cast_field_element::<G::BaseField, G::ScalarField>(&rho) };

let s: usize = ((shape.num_constraints - 1).checked_ilog2().unwrap_or(0) + 1) as usize;
let rvec_shape = vec![SQUEEZE_ELEMENTS_BIT_SIZE; s];

let gamma: G::ScalarField =
random_oracle.squeeze_field_elements_with_sizes(&[SQUEEZE_ELEMENTS_BIT_SIZE])[0];
let beta = random_oracle.squeeze_field_elements_with_sizes(rvec_shape.as_slice());
let gamma: G::ScalarField = random_oracle.squeeze_field_elements(1)[0];
let beta = random_oracle.squeeze_field_elements(s);

let z1 = [U1.X.as_slice(), W1.W.as_slice()].concat();
let z2 = [U2.X.as_slice(), W2.W.as_slice()].concat();
Expand Down Expand Up @@ -150,17 +148,17 @@ where

let (sumcheck_proof, sumcheck_state) = MLSumcheck::prove_as_subprotocol(random_oracle, &g);

let rs = sumcheck_state.randomness;
let rs_p = sumcheck_state.randomness;

let sigmas: Vec<G::ScalarField> = ark_std::cfg_iter!(&shape.Ms)
.map(|M| vec_to_ark_mle(M.multiply_vec(&z1).as_slice()).evaluate(&rs))
.map(|M| vec_to_ark_mle(M.multiply_vec(&z1).as_slice()).evaluate(&rs_p))
.collect();

let thetas: Vec<G::ScalarField> = ark_std::cfg_iter!(&shape.Ms)
.map(|M| vec_to_ark_mle(M.multiply_vec(&z2).as_slice()).evaluate(&rs))
.map(|M| vec_to_ark_mle(M.multiply_vec(&z2).as_slice()).evaluate(&rs_p))
.collect();

let U = U1.fold(U2, &rho_scalar, &rs, &sigmas, &thetas)?;
let U = U1.fold(U2, &rho_scalar, &rs_p, &sigmas, &thetas)?;
let W = W1.fold(W2, &rho_scalar)?;

Ok((
Expand Down Expand Up @@ -195,14 +193,18 @@ where
unsafe { cast_field_element::<G::BaseField, G::ScalarField>(&rho) };

let s: usize = ((shape.num_constraints - 1).checked_ilog2().unwrap_or(0) + 1) as usize;
let rvec_shape = vec![SQUEEZE_ELEMENTS_BIT_SIZE; s];

let gamma: G::ScalarField =
random_oracle.squeeze_field_elements_with_sizes(&[SQUEEZE_ELEMENTS_BIT_SIZE])[0];
let beta = random_oracle.squeeze_field_elements_with_sizes(rvec_shape.as_slice());
let gamma: G::ScalarField = random_oracle.squeeze_field_elements(1)[0];
let beta = random_oracle.squeeze_field_elements(s);

let gamma_powers: Vec<G::ScalarField> = (1..=shape.num_matrices)
.map(|j| gamma.pow([j as u64]))
.collect();

let claimed_sum = (1..=shape.num_matrices)
.map(|j| gamma.pow([j as u64]) * U1.vs[j - 1])
let claimed_sum = gamma_powers
.iter()
.zip(U1.vs.iter())
.map(|(a, b)| *a * b)
.sum();

let sumcheck_subclaim = MLSumcheck::verify_as_subprotocol(
Expand All @@ -212,19 +214,22 @@ where
&self.sumcheck_proof,
)?;

let rs = sumcheck_subclaim.point;
let rs_p = sumcheck_subclaim.point;

let eq1 = EqPolynomial::new(U1.rs.clone());
let eqrs = vec_to_ark_mle(eq1.evals().as_slice());
let e1 = eqrs.evaluate(&rs);
let e1 = eqrs.evaluate(&rs_p);

let eq2 = EqPolynomial::new(beta);
let eqb = vec_to_ark_mle(eq2.evals().as_slice());
let e2 = eqb.evaluate(&rs);
let e2 = eqb.evaluate(&rs_p);

let cl: G::ScalarField = (1..=shape.num_matrices)
.map(|j| gamma.pow([j as u64]) * e1 * self.sigmas[j - 1])
.sum();
let cl: G::ScalarField = gamma_powers
.iter()
.zip(self.sigmas.iter())
.map(|(a, b)| *a * b)
.sum::<G::ScalarField>()
* e1;

let cr: G::ScalarField = (0..shape.num_multisets)
.map(|i| {
Expand All @@ -241,7 +246,7 @@ where
return Err(Error::InconsistentSubclaim);
}

let U = U1.fold(U2, &rho_scalar, &rs, &self.sigmas, &self.thetas)?;
let U = U1.fold(U2, &rho_scalar, &rs_p, &self.sigmas, &self.thetas)?;

Ok((U, rho))
}
Expand Down
2 changes: 1 addition & 1 deletion nova/src/folding/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod hypernova;
pub mod nova;

mod cyclefold;
pub(crate) mod cyclefold;
Loading

0 comments on commit 01a006b

Please sign in to comment.