From 21ff3cf1ab825dd1c741cf0f028ac5934ef0f19d Mon Sep 17 00:00:00 2001 From: Pierre Date: Mon, 29 Jul 2024 12:15:15 +0200 Subject: [PATCH] Enable hiding commitments in nova and hypernova (#129) * feat: enable hiding commitments in nova and hypernova * fix: set blinding values for witness vector * fix: remove cloning of the cyclefold running instance * fix: do not re-use blinding values between prove steps * fix: specify whether the witness should use blinding values using a const generic * feat: create a `dummy` method for nova witnesses as well * chore: clippy - removed unused imports --- examples/circom_full_flow.rs | 3 +- examples/external_inputs.rs | 1 + examples/full_flow.rs | 3 +- examples/multi_inputs.rs | 1 + examples/sha256.rs | 1 + .../src/folding/circuits/cyclefold.rs | 16 +- folding-schemes/src/folding/hypernova/cccs.rs | 2 +- .../src/folding/hypernova/circuits.rs | 18 +- .../src/folding/hypernova/lcccs.rs | 10 +- folding-schemes/src/folding/hypernova/mod.rs | 140 +++++++++---- .../src/folding/hypernova/nimfs.rs | 20 +- .../src/folding/hypernova/utils.rs | 4 +- .../src/folding/nova/decider_eth.rs | 24 ++- .../src/folding/nova/decider_eth_circuit.rs | 30 +-- folding-schemes/src/folding/nova/mod.rs | 196 ++++++++++++------ folding-schemes/src/folding/nova/nifs.rs | 37 ++-- folding-schemes/src/folding/nova/serialize.rs | 18 +- folding-schemes/src/folding/nova/traits.rs | 4 +- folding-schemes/src/lib.rs | 2 + folding-schemes/src/utils/mod.rs | 6 +- .../src/verifiers/nova_cyclefold.rs | 11 +- 21 files changed, 349 insertions(+), 198 deletions(-) diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index 35a3f49..a78dfa4 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -64,7 +64,8 @@ fn main() { let f_circuit_params = (r1cs_path, wasm_path, 1, 2); let f_circuit = CircomFCircuit::::new(f_circuit_params).unwrap(); - pub type N = Nova, KZG<'static, Bn254>, Pedersen>; + pub type N = + Nova, KZG<'static, Bn254>, Pedersen, false>; pub type D = DeciderEth< G1, GVar, diff --git a/examples/external_inputs.rs b/examples/external_inputs.rs index 4939b32..2f70809 100644 --- a/examples/external_inputs.rs +++ b/examples/external_inputs.rs @@ -181,6 +181,7 @@ fn main() { ExternalInputsCircuit, KZG<'static, Bn254>, Pedersen, + false, >; let mut rng = rand::rngs::OsRng; diff --git a/examples/full_flow.rs b/examples/full_flow.rs index 6db6733..5c9ce18 100644 --- a/examples/full_flow.rs +++ b/examples/full_flow.rs @@ -81,7 +81,8 @@ fn main() { let f_circuit = CubicFCircuit::::new(()).unwrap(); - pub type N = Nova, KZG<'static, Bn254>, Pedersen>; + pub type N = + Nova, KZG<'static, Bn254>, Pedersen, false>; pub type D = DeciderEth< G1, GVar, diff --git a/examples/multi_inputs.rs b/examples/multi_inputs.rs index 5560e74..f781952 100644 --- a/examples/multi_inputs.rs +++ b/examples/multi_inputs.rs @@ -137,6 +137,7 @@ fn main() { MultiInputsFCircuit, KZG<'static, Bn254>, Pedersen, + false, >; println!("Prepare Nova ProverParams & VerifierParams"); diff --git a/examples/sha256.rs b/examples/sha256.rs index eea1887..705dcb8 100644 --- a/examples/sha256.rs +++ b/examples/sha256.rs @@ -119,6 +119,7 @@ fn main() { Sha256FCircuit, KZG<'static, Bn254>, Pedersen, + false, >; let poseidon_config = poseidon_canonical_config::(); diff --git a/folding-schemes/src/folding/circuits/cyclefold.rs b/folding-schemes/src/folding/circuits/cyclefold.rs index 4a22eb2..288c957 100644 --- a/folding-schemes/src/folding/circuits/cyclefold.rs +++ b/folding-schemes/src/folding/circuits/cyclefold.rs @@ -16,6 +16,7 @@ use ark_relations::r1cs::{ ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, SynthesisError, }; use ark_std::fmt::Debug; +use ark_std::rand::RngCore; use ark_std::Zero; use core::{borrow::Borrow, marker::PhantomData}; @@ -382,7 +383,7 @@ where /// scheme struct because it is used both by Nova & HyperNova's CycleFold. #[allow(clippy::type_complexity)] #[allow(clippy::too_many_arguments)] -pub fn fold_cyclefold_circuit( +pub fn fold_cyclefold_circuit( _n_points: usize, transcript: &mut impl Transcript, cf_r1cs: R1CS, @@ -392,6 +393,7 @@ pub fn fold_cyclefold_circuit( cf_U_i: CommittedInstance, // running instance cf_u_i_x: Vec, cf_circuit: CycleFoldCircuit, + mut rng: impl RngCore, ) -> Result< ( Witness, @@ -409,8 +411,8 @@ where C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -432,11 +434,11 @@ where assert_eq!(cf_x_i.len(), cf_io_len(_n_points)); // fold cyclefold instances - let cf_w_i = Witness::::new(cf_w_i.clone(), cf_r1cs.A.n_rows); - let cf_u_i: CommittedInstance = cf_w_i.commit::(&cf_cs_params, cf_x_i.clone())?; + let cf_w_i = Witness::::new::(cf_w_i.clone(), cf_r1cs.A.n_rows, &mut rng); + let cf_u_i: CommittedInstance = cf_w_i.commit::(&cf_cs_params, cf_x_i.clone())?; // compute T* and cmT* for CycleFoldCircuit - let (cf_T, cf_cmT) = NIFS::::compute_cyclefold_cmT( + let (cf_T, cf_cmT) = NIFS::::compute_cyclefold_cmT( &cf_cs_params, &cf_r1cs, &cf_w_i, @@ -455,7 +457,7 @@ where let cf_r_Fq = C1::BaseField::from_bigint(BigInteger::from_bits_le(&cf_r_bits)) .expect("cf_r_bits out of bounds"); - let (cf_W_i1, cf_U_i1) = NIFS::::fold_instances( + let (cf_W_i1, cf_U_i1) = NIFS::::fold_instances( cf_r_Fq, &cf_W_i, &cf_U_i, &cf_w_i, &cf_u_i, &cf_T, cf_cmT, )?; Ok((cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, cf_r_Fq)) diff --git a/folding-schemes/src/folding/hypernova/cccs.rs b/folding-schemes/src/folding/hypernova/cccs.rs index 6be8ab6..8de9ca7 100644 --- a/folding-schemes/src/folding/hypernova/cccs.rs +++ b/folding-schemes/src/folding/hypernova/cccs.rs @@ -26,7 +26,7 @@ pub struct CCCS { } impl CCS { - pub fn to_cccs>( + pub fn to_cccs, const H: bool>( &self, rng: &mut R, cs_params: &CS::ProverParams, diff --git a/folding-schemes/src/folding/hypernova/circuits.rs b/folding-schemes/src/folding/hypernova/circuits.rs index 78a28d2..004f49f 100644 --- a/folding-schemes/src/folding/hypernova/circuits.rs +++ b/folding-schemes/src/folding/hypernova/circuits.rs @@ -949,7 +949,7 @@ mod tests { let mut lcccs_instances = Vec::new(); for z_i in z_lcccs.iter() { let (inst, _) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_lcccs::<_, _, Pedersen, true>(&mut rng, &pedersen_params, z_i) .unwrap(); lcccs_instances.push(inst); } @@ -957,7 +957,7 @@ mod tests { let mut cccs_instances = Vec::new(); for z_i in z_cccs.iter() { let (inst, _) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); cccs_instances.push(inst); } @@ -1045,7 +1045,11 @@ mod tests { let mut w_lcccs = Vec::new(); for z_i in z_lcccs.iter() { let (running_instance, w) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_lcccs::<_, _, Pedersen, false>( + &mut rng, + &pedersen_params, + z_i, + ) .unwrap(); lcccs_instances.push(running_instance); w_lcccs.push(w); @@ -1055,7 +1059,7 @@ mod tests { let mut w_cccs = Vec::new(); for z_i in z_cccs.iter() { let (new_instance, w) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); cccs_instances.push(new_instance); w_cccs.push(w); @@ -1139,7 +1143,7 @@ mod tests { let z_0 = vec![Fr::from(3_u32)]; let z_i = vec![Fr::from(3_u32)]; let (lcccs, _) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z1) + .to_lcccs::<_, _, Pedersen, true>(&mut rng, &pedersen_params, &z1) .unwrap(); let h = lcccs .clone() @@ -1378,6 +1382,7 @@ mod tests { CubicFCircuit, Pedersen, Pedersen, + false, >( mu + nu, &mut transcript_p, @@ -1388,6 +1393,7 @@ mod tests { cf_U_i.clone(), // CycleFold running instance cf_u_i_x, // CycleFold incoming instance cf_circuit, + &mut rng, ) .unwrap(); @@ -1439,7 +1445,7 @@ mod tests { // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we // assign them directly to w_i, u_i. (u_i, w_i) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &r1cs_z) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &r1cs_z) .unwrap(); u_i.check_relation(&ccs, &w_i).unwrap(); diff --git a/folding-schemes/src/folding/hypernova/lcccs.rs b/folding-schemes/src/folding/hypernova/lcccs.rs index 801ec4e..1969a4b 100644 --- a/folding-schemes/src/folding/hypernova/lcccs.rs +++ b/folding-schemes/src/folding/hypernova/lcccs.rs @@ -30,7 +30,7 @@ pub struct LCCCS { } impl CCS { - pub fn to_lcccs>( + pub fn to_lcccs, const H: bool>( &self, rng: &mut R, cs_params: &CS::ProverParams, @@ -221,7 +221,11 @@ pub mod tests { Pedersen::::setup(&mut rng, ccs.n - ccs.l - 1).unwrap(); let (lcccs, _) = ccs - .to_lcccs::<_, Projective, Pedersen>(&mut rng, &pedersen_params, &z) + .to_lcccs::<_, Projective, Pedersen, false>( + &mut rng, + &pedersen_params, + &z, + ) .unwrap(); // with our test vector coming from R1CS, v should have length 3 assert_eq!(lcccs.v.len(), 3); @@ -255,7 +259,7 @@ pub mod tests { Pedersen::::setup(&mut rng, ccs.n - ccs.l - 1).unwrap(); // Compute v_j with the right z let (lcccs, _) = ccs - .to_lcccs::<_, Projective, Pedersen>(&mut rng, &pedersen_params, &z) + .to_lcccs::<_, Projective, Pedersen, false>(&mut rng, &pedersen_params, &z) .unwrap(); // with our test vector coming from R1CS, v should have length 3 assert_eq!(lcccs.v.len(), 3); diff --git a/folding-schemes/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs index 5a15655..8cc2707 100644 --- a/folding-schemes/src/folding/hypernova/mod.rs +++ b/folding-schemes/src/folding/hypernova/mod.rs @@ -61,12 +61,12 @@ impl Witness { } #[derive(Debug, Clone)] -pub struct ProverParams +pub struct ProverParams where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { pub poseidon_config: PoseidonConfig, pub cs_params: CS1::ProverParams, @@ -81,8 +81,9 @@ where pub struct VerifierParams< C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, + const H: bool, > { pub poseidon_config: PoseidonConfig, pub ccs: CCS, @@ -91,16 +92,16 @@ pub struct VerifierParams< pub cf_cs_vp: CS2::VerifierParams, } -impl VerifierParams +impl VerifierParams where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { /// returns the hash of the public parameters of HyperNova pub fn pp_hash(&self) -> Result { - pp_hash::( + pp_hash::( &self.ccs, &self.cf_r1cs, &self.cs_vp, @@ -114,15 +115,15 @@ where /// [HyperNova](https://eprint.iacr.org/2023/573.pdf) and /// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait #[derive(Clone, Debug)] -pub struct HyperNova +pub struct HyperNova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { _gc1: PhantomData, _c2: PhantomData, @@ -159,16 +160,16 @@ where pub cf_U_i: CommittedInstance, } -impl MultiFolding - for HyperNova +impl MultiFolding + for HyperNova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -195,7 +196,7 @@ where // assign them directly to w_i, u_i. let (U_i, W_i) = self .ccs - .to_lcccs::<_, _, CS1>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_lcccs::<_, _, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; #[cfg(test)] U_i.check_relation(&self.ccs, &W_i)?; @@ -217,7 +218,7 @@ where // assign them directly to w_i, u_i. let (u_i, w_i) = self .ccs - .to_cccs::<_, _, CS1>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_cccs::<_, _, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; #[cfg(test)] u_i.check_relation(&self.ccs, &w_i)?; @@ -226,15 +227,15 @@ where } } -impl HyperNova +impl HyperNova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -333,16 +334,16 @@ where } } -impl FoldingScheme - for HyperNova +impl FoldingScheme + for HyperNova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -354,9 +355,9 @@ where /// Reuse Nova's PreprocessorParam, together with two usize values, which are mu & nu /// respectively, which indicate the amount of LCCCS & CCCS instances to be folded at each /// folding step. - type PreprocessorParam = (PreprocessorParam, usize, usize); - type ProverParam = ProverParams; - type VerifierParam = VerifierParams; + type PreprocessorParam = (PreprocessorParam, usize, usize); + type ProverParam = ProverParams; + type VerifierParam = VerifierParams; type RunningInstance = (LCCCS, Witness); type IncomingInstance = (CCCS, Witness); type MultiCommittedInstanceWithWitness = @@ -403,7 +404,7 @@ where (cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1)?; } - let pp = ProverParams:: { + let pp = ProverParams:: { poseidon_config: prep_param.poseidon_config.clone(), cs_params: cs_pp.clone(), cf_cs_params: cf_cs_pp.clone(), @@ -411,7 +412,7 @@ where mu: *mu, nu: *nu, }; - let vp = VerifierParams:: { + let vp = VerifierParams:: { poseidon_config: prep_param.poseidon_config.clone(), ccs, cf_r1cs, @@ -505,6 +506,22 @@ where external_inputs: Vec, other_instances: Option, ) -> Result<(), Error> { + // ensure that commitments are blinding if user has specified so. + + if H { + let blinding_commitments = if self.i == C1::ScalarField::zero() { + vec![self.w_i.r_w] + } else { + vec![self.w_i.r_w, self.W_i.r_w] + }; + if blinding_commitments.contains(&C1::ScalarField::zero()) { + return Err(Error::IncorrectBlinding( + H, + format!("{:?}", blinding_commitments), + )); + } + } + // `sponge` is for digest computation. let sponge = PoseidonSponge::::new(&self.poseidon_config); @@ -572,10 +589,11 @@ where // u_{i+1}.x[1] = H(cf_U_{i+1}) let cf_u_i1_x: C1::ScalarField; - let (U_i1, W_i1); + let (U_i1, mut W_i1); if self.i == C1::ScalarField::zero() { W_i1 = Witness::::dummy(&self.ccs); + W_i1.r_w = self.W_i.r_w; U_i1 = LCCCS::dummy(self.ccs.l, self.ccs.t, self.ccs.s); let u_i1_x = U_i1.hash( @@ -697,7 +715,7 @@ where }; let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = - fold_cyclefold_circuit::( + fold_cyclefold_circuit::( self.mu + self.nu, &mut transcript_p, self.cf_r1cs.clone(), @@ -707,6 +725,7 @@ where self.cf_U_i.clone(), // CycleFold running instance cf_u_i_x, cf_circuit, + &mut rng, )?; cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash); @@ -762,7 +781,7 @@ where // assign them directly to w_i, u_i. let (u_i, w_i) = self .ccs - .to_cccs::<_, C1, CS1>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_cccs::<_, C1, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; self.u_i = u_i.clone(); self.w_i = w_i.clone(); @@ -861,6 +880,7 @@ mod tests { use crate::commitment::kzg::KZG; use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_std::UniformRand; use super::*; use crate::commitment::pedersen::Pedersen; @@ -874,35 +894,71 @@ mod tests { let F_circuit = CubicFCircuit::::new(()).unwrap(); // run the test using Pedersen commitments on both sides of the curve cycle - test_ivc_opt::, Pedersen>( + test_ivc_opt::, Pedersen, false>( poseidon_config.clone(), F_circuit, ); + + test_ivc_opt::, Pedersen, true>( + poseidon_config.clone(), + F_circuit, + ); + // run the test using KZG for the commitments on the main curve, and Pedersen for the // commitments on the secondary curve - test_ivc_opt::, Pedersen>(poseidon_config, F_circuit); + test_ivc_opt::, Pedersen, false>(poseidon_config, F_circuit); } // test_ivc allowing to choose the CommitmentSchemes - fn test_ivc_opt, CS2: CommitmentScheme>( + fn test_ivc_opt< + CS1: CommitmentScheme, + CS2: CommitmentScheme, + const H: bool, + >( poseidon_config: PoseidonConfig, F_circuit: CubicFCircuit, ) { let mut rng = ark_std::test_rng(); - type HN = - HyperNova, CS1, CS2>; let (mu, nu) = (2, 3); let prep_param = - PreprocessorParam::, CS1, CS2>::new( + PreprocessorParam::, CS1, CS2, H>::new( poseidon_config.clone(), F_circuit, ); - let hypernova_params = HN::preprocess(&mut rng, &(prep_param, mu, nu)).unwrap(); + let hypernova_params = HyperNova::< + Projective, + GVar, + Projective2, + GVar2, + CubicFCircuit, + CS1, + CS2, + H, + >::preprocess(&mut rng, &(prep_param, mu, nu)) + .unwrap(); let z_0 = vec![Fr::from(3_u32)]; - let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap(); + let mut hypernova = HyperNova::< + Projective, + GVar, + Projective2, + GVar2, + CubicFCircuit, + CS1, + CS2, + H, + >::init(&hypernova_params, F_circuit, z_0.clone()) + .unwrap(); + + let (w_i_blinding, W_i_blinding) = if H { + (Fr::rand(&mut rng), Fr::rand(&mut rng)) + } else { + (Fr::zero(), Fr::zero()) + }; + hypernova.w_i.r_w = w_i_blinding; + hypernova.W_i.r_w = W_i_blinding; let num_steps: usize = 3; for _ in 0..num_steps { @@ -932,7 +988,7 @@ mod tests { assert_eq!(Fr::from(num_steps as u32), hypernova.i); let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances(); - HN::verify( + HyperNova::, CS1, CS2, H>::verify( hypernova_params.1, // verifier_params z_0, hypernova.z_i, diff --git a/folding-schemes/src/folding/hypernova/nimfs.rs b/folding-schemes/src/folding/hypernova/nimfs.rs index 2a010a6..15318eb 100644 --- a/folding-schemes/src/folding/hypernova/nimfs.rs +++ b/folding-schemes/src/folding/hypernova/nimfs.rs @@ -441,10 +441,10 @@ pub mod tests { Pedersen::::setup(&mut rng, ccs.n - ccs.l - 1).unwrap(); let (lcccs, w1) = ccs - .to_lcccs::<_, Projective, Pedersen>(&mut rng, &pedersen_params, &z1) + .to_lcccs::<_, Projective, Pedersen, false>(&mut rng, &pedersen_params, &z1) .unwrap(); let (cccs, w2) = ccs - .to_cccs::<_, Projective, Pedersen>(&mut rng, &pedersen_params, &z2) + .to_cccs::<_, Projective, Pedersen, false>(&mut rng, &pedersen_params, &z2) .unwrap(); lcccs.check_relation(&ccs, &w1).unwrap(); @@ -484,11 +484,11 @@ pub mod tests { // Create the LCCCS instance out of z_1 let (running_instance, w1) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z_1) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z_1) .unwrap(); // Create the CCCS instance out of z_2 let (new_instance, w2) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z_2) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z_2) .unwrap(); // Prover's transcript @@ -540,7 +540,7 @@ pub mod tests { // LCCCS witness let z_1 = get_test_z(2); let (mut running_instance, mut w1) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z_1) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z_1) .unwrap(); let poseidon_config = poseidon_canonical_config::(); @@ -557,7 +557,7 @@ pub mod tests { let z_2 = get_test_z(i); let (new_instance, w2) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z_2) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z_2) .unwrap(); // run the prover side of the multifolding @@ -621,7 +621,7 @@ pub mod tests { let mut w_lcccs = Vec::new(); for z_i in z_lcccs.iter() { let (running_instance, w) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); lcccs_instances.push(running_instance); w_lcccs.push(w); @@ -631,7 +631,7 @@ pub mod tests { let mut w_cccs = Vec::new(); for z_i in z_cccs.iter() { let (new_instance, w) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); cccs_instances.push(new_instance); w_cccs.push(w); @@ -717,7 +717,7 @@ pub mod tests { let mut w_lcccs = Vec::new(); for z_i in z_lcccs.iter() { let (running_instance, w) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); lcccs_instances.push(running_instance); w_lcccs.push(w); @@ -727,7 +727,7 @@ pub mod tests { let mut w_cccs = Vec::new(); for z_i in z_cccs.iter() { let (new_instance, w) = ccs - .to_cccs::<_, _, Pedersen>(&mut rng, &pedersen_params, z_i) + .to_cccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, z_i) .unwrap(); cccs_instances.push(new_instance); w_cccs.push(w); diff --git a/folding-schemes/src/folding/hypernova/utils.rs b/folding-schemes/src/folding/hypernova/utils.rs index 160ae5a..8e0b084 100644 --- a/folding-schemes/src/folding/hypernova/utils.rs +++ b/folding-schemes/src/folding/hypernova/utils.rs @@ -242,7 +242,7 @@ pub mod tests { let (pedersen_params, _) = Pedersen::::setup(&mut rng, ccs.n - ccs.l - 1).unwrap(); let (lcccs_instance, _) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z1) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z1) .unwrap(); let sigmas_thetas = @@ -292,7 +292,7 @@ pub mod tests { let (pedersen_params, _) = Pedersen::::setup(&mut rng, ccs.n - ccs.l - 1).unwrap(); let (lcccs_instance, _) = ccs - .to_lcccs::<_, _, Pedersen>(&mut rng, &pedersen_params, &z1) + .to_lcccs::<_, _, Pedersen, false>(&mut rng, &pedersen_params, &z1) .unwrap(); // Compute g(x) with that r_x diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index a8a0136..7508172 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -81,10 +81,10 @@ where for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>, for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>, // constrain FS into Nova, since this is a Decider specifically for Nova - Nova: From, - crate::folding::nova::ProverParams: + Nova: From, + crate::folding::nova::ProverParams: From<>::ProverParam>, - crate::folding::nova::VerifierParams: + crate::folding::nova::VerifierParams: From<>::VerifierParam>, { type PreprocessorParam = (FS::ProverParam, FS::VerifierParam); @@ -108,14 +108,17 @@ where // get the FoldingScheme prover & verifier params from Nova #[allow(clippy::type_complexity)] - let nova_pp: - as FoldingScheme>::ProverParam = - prep_param.0.clone().into() - ; + let nova_pp: as FoldingScheme< + C1, + C2, + FC, + >>::ProverParam = prep_param.0.clone().into(); #[allow(clippy::type_complexity)] - let nova_vp: - as FoldingScheme>::VerifierParam = - prep_param.1.clone().into(); + let nova_vp: as FoldingScheme< + C1, + C2, + FC, + >>::VerifierParam = prep_param.1.clone().into(); let pp_hash = nova_vp.pp_hash()?; let pp = (g16_pk, nova_pp.cs_pp); @@ -338,6 +341,7 @@ pub mod tests { CubicFCircuit, KZG<'static, Bn254>, Pedersen, + false, >; type D = Decider< Projective, diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index 4cd6c65..090026b 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -193,14 +193,14 @@ where /// Circuit that implements the in-circuit checks needed for the onchain (Ethereum's EVM) /// verification. #[derive(Clone, Debug)] -pub struct DeciderEthCircuit +pub struct DeciderEthCircuit where C1: CurveGroup, GC1: CurveVar>, C2: CurveGroup, GC2: CurveVar>, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { _c1: PhantomData, _gc1: PhantomData, @@ -246,25 +246,25 @@ where pub eval_W: Option, pub eval_E: Option, } -impl DeciderEthCircuit +impl DeciderEthCircuit where C1: CurveGroup, C2: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, GC2: CurveVar> + ToConstraintFieldGadget>, - CS1: CommitmentScheme, + CS1: CommitmentScheme, // enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider - CS2: CommitmentScheme>, + CS2: CommitmentScheme>, ::ScalarField: Absorb, ::BaseField: PrimeField, { pub fn from_nova>( - nova: Nova, + nova: Nova, ) -> Result { let mut transcript = PoseidonSponge::::new(&nova.poseidon_config); // compute the U_{i+1}, W_{i+1} - let (T, cmT) = NIFS::::compute_cmT( + let (T, cmT) = NIFS::::compute_cmT( &nova.cs_pp, &nova.r1cs.clone(), &nova.w_i.clone(), @@ -281,7 +281,7 @@ where ); let r_Fr = C1::ScalarField::from_bigint(BigInteger::from_bits_le(&r_bits)) .ok_or(Error::OutOfBounds)?; - let (W_i1, U_i1) = NIFS::::fold_instances( + let (W_i1, U_i1) = NIFS::::fold_instances( r_Fr, &nova.W_i, &nova.U_i, &nova.w_i, &nova.u_i, &T, cmT, )?; @@ -376,8 +376,8 @@ where })?; let u_dummy_native = CommittedInstance::::dummy(2); - let w_dummy_native = Witness::::new( - vec![C1::ScalarField::zero(); self.r1cs.A.n_cols - 3 /* (3=2+1, since u_i.x.len=2) */], + let w_dummy_native = Witness::::dummy( + self.r1cs.A.n_cols - 3, /* (3=2+1, since u_i.x.len=2) */ self.E_len, ); @@ -453,10 +453,8 @@ where use ark_r1cs_std::ToBitsGadget; let cf_u_dummy_native = CommittedInstance::::dummy(cf_io_len(NOVA_CF_N_POINTS)); - let w_dummy_native = Witness::::new( - vec![C2::ScalarField::zero(); self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l], - self.cf_E_len, - ); + let w_dummy_native = + Witness::::dummy(self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l, self.cf_E_len); let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone())) })?; @@ -788,6 +786,7 @@ pub mod tests { CubicFCircuit, Pedersen, Pedersen, + false, >; let prep_param = PreprocessorParam::< @@ -796,6 +795,7 @@ pub mod tests { CubicFCircuit, Pedersen, Pedersen, + false, >::new(poseidon_config, F_circuit); let nova_params = N::preprocess(&mut rng, &prep_param).unwrap(); diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index 99d559d..5d3571f 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -11,7 +11,7 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::fmt::Debug; use ark_std::rand::RngCore; -use ark_std::{One, Zero}; +use ark_std::{One, UniformRand, Zero}; use core::marker::PhantomData; use crate::commitment::CommitmentScheme; @@ -166,17 +166,37 @@ impl Witness where ::ScalarField: Absorb, { - pub fn new(w: Vec, e_len: usize) -> Self { - // note: at the current version, we don't use the blinding factors and we set them to 0 - // always. + pub fn new(w: Vec, e_len: usize, mut rng: impl RngCore) -> Self { + let (rW, rE) = if H { + ( + C::ScalarField::rand(&mut rng), + C::ScalarField::rand(&mut rng), + ) + } else { + (C::ScalarField::zero(), C::ScalarField::zero()) + }; + + Self { + E: vec![C::ScalarField::zero(); e_len], + rE, + W: w, + rW, + } + } + + pub fn dummy(w_len: usize, e_len: usize) -> Self { + let (rW, rE) = (C::ScalarField::zero(), C::ScalarField::zero()); + let w = vec![C::ScalarField::zero(); w_len]; + Self { E: vec![C::ScalarField::zero(); e_len], - rE: C::ScalarField::zero(), + rE, W: w, - rW: C::ScalarField::zero(), + rW, } } - pub fn commit>( + + pub fn commit, const HC: bool>( &self, params: &CS::ProverParams, x: Vec, @@ -196,13 +216,13 @@ where } #[derive(Debug, Clone)] -pub struct PreprocessorParam +pub struct PreprocessorParam where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { pub poseidon_config: PoseidonConfig, pub F: FC, @@ -213,13 +233,13 @@ where pub cf_cs_vp: Option, } -impl PreprocessorParam +impl PreprocessorParam where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { pub fn new(poseidon_config: PoseidonConfig, F: FC) -> Self { Self { @@ -234,12 +254,12 @@ where } #[derive(Debug, Clone)] -pub struct ProverParams +pub struct ProverParams where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { pub poseidon_config: PoseidonConfig, pub cs_pp: CS1::ProverParams, @@ -247,12 +267,12 @@ where } #[derive(Debug, Clone)] -pub struct VerifierParams +pub struct VerifierParams where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { pub poseidon_config: PoseidonConfig, pub r1cs: R1CS, @@ -261,16 +281,16 @@ where pub cf_cs_vp: CS2::VerifierParams, } -impl VerifierParams +impl VerifierParams where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { /// returns the hash of the public parameters of Nova pub fn pp_hash(&self) -> Result { - pp_hash::( + pp_hash::( &self.r1cs, &self.cf_r1cs, &self.cs_vp, @@ -282,16 +302,17 @@ where /// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and /// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait +/// The `H` const generic specifies whether the homorphic commitment scheme is blinding #[derive(Clone, Debug)] -pub struct Nova +pub struct Nova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { _gc1: PhantomData, _c2: PhantomData, @@ -325,16 +346,16 @@ where pub cf_U_i: CommittedInstance, } -impl FoldingScheme - for Nova +impl FoldingScheme + for Nova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -343,9 +364,9 @@ where for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>, for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>, { - type PreprocessorParam = PreprocessorParam; - type ProverParam = ProverParams; - type VerifierParam = VerifierParams; + type PreprocessorParam = PreprocessorParam; + type ProverParam = ProverParams; + type VerifierParam = VerifierParams; type RunningInstance = (CommittedInstance, Witness); type IncomingInstance = (CommittedInstance, Witness); type MultiCommittedInstanceWithWitness = (); @@ -377,12 +398,12 @@ where (cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows)?; } - let prover_params = ProverParams:: { + let prover_params = ProverParams:: { poseidon_config: prep_param.poseidon_config.clone(), cs_pp: cs_pp.clone(), cf_cs_pp: cf_cs_pp.clone(), }; - let verifier_params = VerifierParams:: { + let verifier_params = VerifierParams:: { poseidon_config: prep_param.poseidon_config.clone(), r1cs, cf_r1cs, @@ -455,11 +476,26 @@ where /// Implements IVC.P of Nova+CycleFold fn prove_step( &mut self, - _rng: impl RngCore, + mut rng: impl RngCore, external_inputs: Vec, // Nova does not support multi-instances folding _other_instances: Option, ) -> Result<(), Error> { + // ensure that commitments are blinding if user has specified so. + if H && self.i >= C1::ScalarField::one() { + let blinding_commitments = if self.i == C1::ScalarField::one() { + // blinding values of the running instances are zero at the first iteration + vec![self.w_i.rW, self.w_i.rE] + } else { + vec![self.w_i.rW, self.w_i.rE, self.W_i.rW, self.W_i.rE] + }; + if blinding_commitments.contains(&C1::ScalarField::zero()) { + return Err(Error::IncorrectBlinding( + H, + format!("{:?}", blinding_commitments), + )); + } + } // `sponge` is for digest computation. let sponge = PoseidonSponge::::new(&self.poseidon_config); // `transcript` is for challenge generation. @@ -517,9 +553,10 @@ where .ok_or(Error::OutOfBounds)?; // fold Nova instances - let (W_i1, U_i1): (Witness, CommittedInstance) = NIFS::::fold_instances( - r_Fr, &self.W_i, &self.U_i, &self.w_i, &self.u_i, &T, cmT, - )?; + let (W_i1, U_i1): (Witness, CommittedInstance) = + NIFS::::fold_instances( + r_Fr, &self.W_i, &self.U_i, &self.w_i, &self.u_i, &T, cmT, + )?; // folded instance output (public input, x) // u_{i+1}.x[0] = H(i+1, z_0, z_{i+1}, U_{i+1}) @@ -561,7 +598,7 @@ where }; #[cfg(test)] - NIFS::::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?; + NIFS::::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?; } else { // CycleFold part: // get the vector used as public inputs 'x' in the CycleFold circuit @@ -604,6 +641,7 @@ where self.cf_U_i.clone(), // CycleFold running instance cfW_u_i_x, cfW_circuit, + &mut rng, )?; // fold [the output from folding self.cf_U_i + cfW_U] + cfE_U = folded_running_with_cfW + cfE let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = self.fold_cyclefold_circuit( @@ -612,6 +650,7 @@ where cfW_U_i1.clone(), cfE_u_i_x, cfE_circuit, + &mut rng, )?; cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash); @@ -674,8 +713,8 @@ where // set values for next iteration self.i += C1::ScalarField::one(); self.z_i = z_i1; - self.w_i = Witness::::new(w_i1, self.r1cs.A.n_rows); - self.u_i = self.w_i.commit::(&self.cs_pp, x_i1)?; + self.w_i = Witness::::new::(w_i1, self.r1cs.A.n_rows, &mut rng); + self.u_i = self.w_i.commit::(&self.cs_pp, x_i1)?; self.W_i = W_i1; self.U_i = U_i1; @@ -767,15 +806,15 @@ where } } -impl Nova +impl Nova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::ScalarField: Absorb, ::ScalarField: Absorb, @@ -783,7 +822,7 @@ where { // computes T and cmT for the AugmentedFCircuit fn compute_cmT(&self) -> Result<(Vec, C1), Error> { - NIFS::::compute_cmT( + NIFS::::compute_cmT( &self.cs_pp, &self.r1cs, &self.w_i, @@ -794,15 +833,15 @@ where } } -impl Nova +impl Nova where C1: CurveGroup, GC1: CurveVar> + ToConstraintFieldGadget>, C2: CurveGroup, GC2: CurveVar> + ToConstraintFieldGadget>, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -820,6 +859,7 @@ where cf_U_i: CommittedInstance, // running instance cf_u_i_x: Vec, cf_circuit: CycleFoldCircuit, + rng: &mut impl RngCore, ) -> Result< ( Witness, @@ -831,7 +871,7 @@ where ), Error, > { - fold_cyclefold_circuit::( + fold_cyclefold_circuit::( NOVA_CF_N_POINTS, transcript, self.cf_r1cs.clone(), @@ -841,6 +881,7 @@ where cf_U_i, cf_u_i_x, cf_circuit, + rng, ) } } @@ -929,35 +970,60 @@ pub mod tests { let F_circuit = CubicFCircuit::::new(()).unwrap(); // run the test using Pedersen commitments on both sides of the curve cycle - test_ivc_opt::, Pedersen>( + test_ivc_opt::, Pedersen, false>( poseidon_config.clone(), F_circuit, ); + test_ivc_opt::, Pedersen, true>( + poseidon_config.clone(), + F_circuit, + ); + // run the test using KZG for the commitments on the main curve, and Pedersen for the // commitments on the secondary curve - test_ivc_opt::, Pedersen>(poseidon_config, F_circuit); + test_ivc_opt::, Pedersen, false>(poseidon_config, F_circuit); } // test_ivc allowing to choose the CommitmentSchemes - fn test_ivc_opt, CS2: CommitmentScheme>( + fn test_ivc_opt< + CS1: CommitmentScheme, + CS2: CommitmentScheme, + const H: bool, + >( poseidon_config: PoseidonConfig, F_circuit: CubicFCircuit, ) { let mut rng = ark_std::test_rng(); - type N = Nova, CS1, CS2>; - let prep_param = PreprocessorParam::, CS1, CS2> { - poseidon_config, - F: F_circuit, - cs_pp: None, - cs_vp: None, - cf_cs_pp: None, - cf_cs_vp: None, - }; - let nova_params = N::preprocess(&mut rng, &prep_param).unwrap(); + let prep_param = + PreprocessorParam::, CS1, CS2, H> { + poseidon_config, + F: F_circuit, + cs_pp: None, + cs_vp: None, + cf_cs_pp: None, + cf_cs_vp: None, + }; + let nova_params = Nova::< + Projective, + GVar, + Projective2, + GVar2, + CubicFCircuit, + CS1, + CS2, + H, + >::preprocess(&mut rng, &prep_param) + .unwrap(); let z_0 = vec![Fr::from(3_u32)]; - let mut nova = N::init(&nova_params, F_circuit, z_0.clone()).unwrap(); + let mut nova = + Nova::, CS1, CS2, H>::init( + &nova_params, + F_circuit, + z_0.clone(), + ) + .unwrap(); let num_steps: usize = 3; for _ in 0..num_steps { @@ -966,7 +1032,7 @@ pub mod tests { assert_eq!(Fr::from(num_steps as u32), nova.i); let (running_instance, incoming_instance, cyclefold_instance) = nova.instances(); - N::::verify( + Nova::, CS1, CS2, H>::verify( nova_params.1, // Nova's verifier params z_0, nova.z_i, diff --git a/folding-schemes/src/folding/nova/nifs.rs b/folding-schemes/src/folding/nova/nifs.rs index 725247e..7eb4900 100644 --- a/folding-schemes/src/folding/nova/nifs.rs +++ b/folding-schemes/src/folding/nova/nifs.rs @@ -12,12 +12,13 @@ use crate::Error; /// Implements the Non-Interactive Folding Scheme described in section 4 of /// [Nova](https://eprint.iacr.org/2021/370.pdf) -pub struct NIFS> { +/// `H` specifies whether the NIFS will use a blinding factor +pub struct NIFS, const H: bool = false> { _c: PhantomData, _cp: PhantomData, } -impl> NIFS +impl, const H: bool> NIFS where ::ScalarField: Absorb, { @@ -141,10 +142,10 @@ where ) -> Result<(Witness, CommittedInstance), Error> { // fold witness // use r_T=0 since we don't need hiding property for cm(T) - let w3 = NIFS::::fold_witness(r, w1, w2, T, C::ScalarField::zero())?; + let w3 = NIFS::::fold_witness(r, w1, w2, T, C::ScalarField::zero())?; // fold committed instances - let ci3 = NIFS::::fold_committed_instance(r, ci1, ci2, &cmT); + let ci3 = NIFS::::fold_committed_instance(r, ci1, ci2, &cmT); Ok((w3, ci3)) } @@ -158,7 +159,7 @@ where ci2: &CommittedInstance, cmT: &C, ) -> CommittedInstance { - NIFS::::fold_committed_instance(r, ci1, ci2, cmT) + NIFS::::fold_committed_instance(r, ci1, ci2, cmT) } /// Verify committed folded instance (ci) relations. Notice that this method does not open the @@ -206,7 +207,7 @@ pub mod tests { }; use ark_ff::{BigInteger, PrimeField}; use ark_pallas::{Fr, Projective}; - use ark_std::{ops::Mul, UniformRand}; + use ark_std::{ops::Mul, test_rng, UniformRand}; use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z}; use crate::commitment::pedersen::{Params as PedersenParams, Pedersen}; @@ -241,18 +242,18 @@ pub mod tests { let (w1, x1) = r1cs.split_z(&z1); let (w2, x2) = r1cs.split_z(&z2); - let w1 = Witness::::new(w1.clone(), r1cs.A.n_rows); - let w2 = Witness::::new(w2.clone(), r1cs.A.n_rows); + let w1 = Witness::::new::(w1.clone(), r1cs.A.n_rows, test_rng()); + let w2 = Witness::::new::(w2.clone(), r1cs.A.n_rows, test_rng()); let mut rng = ark_std::test_rng(); let (pedersen_params, _) = Pedersen::::setup(&mut rng, r1cs.A.n_cols).unwrap(); // compute committed instances let ci1 = w1 - .commit::>(&pedersen_params, x1.clone()) + .commit::, false>(&pedersen_params, x1.clone()) .unwrap(); let ci2 = w2 - .commit::>(&pedersen_params, x2.clone()) + .commit::, false>(&pedersen_params, x2.clone()) .unwrap(); // NIFS.P @@ -304,9 +305,9 @@ pub mod tests { let (pedersen_params, _) = Pedersen::::setup(&mut rng, r1cs.A.n_cols).unwrap(); // dummy instance, witness and public inputs zeroes - let w_dummy = Witness::::new(vec![Fr::zero(); w1.len()], r1cs.A.n_rows); + let w_dummy = Witness::::dummy(w1.len(), r1cs.A.n_rows); let mut u_dummy = w_dummy - .commit::>(&pedersen_params, vec![Fr::zero(); x1.len()]) + .commit::, false>(&pedersen_params, vec![Fr::zero(); x1.len()]) .unwrap(); u_dummy.u = Fr::zero(); @@ -353,7 +354,7 @@ pub mod tests { // check that folded commitments from folded instance (ci) are equal to folding the // use folded rE, rW to commit w3 let ci3_expected = w3 - .commit::>(&pedersen_params, ci3.x.clone()) + .commit::, false>(&pedersen_params, ci3.x.clone()) .unwrap(); assert_eq!(ci3_expected.cmE, ci3.cmE); assert_eq!(ci3_expected.cmW, ci3.cmW); @@ -417,9 +418,10 @@ pub mod tests { let (pedersen_params, _) = Pedersen::::setup(&mut rng, r1cs.A.n_cols).unwrap(); // prepare the running instance - let mut running_instance_w = Witness::::new(w.clone(), r1cs.A.n_rows); + let mut running_instance_w = + Witness::::new::(w.clone(), r1cs.A.n_rows, test_rng()); let mut running_committed_instance = running_instance_w - .commit::>(&pedersen_params, x) + .commit::, false>(&pedersen_params, x) .unwrap(); r1cs.check_relaxed_instance_relation(&running_instance_w, &running_committed_instance) @@ -430,9 +432,10 @@ pub mod tests { // prepare the incoming instance let incoming_instance_z = get_test_z(i + 4); let (w, x) = r1cs.split_z(&incoming_instance_z); - let incoming_instance_w = Witness::::new(w.clone(), r1cs.A.n_rows); + let incoming_instance_w = + Witness::::new::(w.clone(), r1cs.A.n_rows, test_rng()); let incoming_committed_instance = incoming_instance_w - .commit::>(&pedersen_params, x) + .commit::, false>(&pedersen_params, x) .unwrap(); r1cs.check_relaxed_instance_relation( &incoming_instance_w, diff --git a/folding-schemes/src/folding/nova/serialize.rs b/folding-schemes/src/folding/nova/serialize.rs index 62dea3f..f87b348 100644 --- a/folding-schemes/src/folding/nova/serialize.rs +++ b/folding-schemes/src/folding/nova/serialize.rs @@ -21,13 +21,14 @@ use crate::{ frontend::FCircuit, }; -impl CanonicalSerialize for Nova +impl CanonicalSerialize + for Nova where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -94,13 +95,13 @@ where // Note that we can't derive or implement `CanonicalDeserialize` directly. // This is because `CurveVar` notably does not implement the `Sync` trait. -impl Nova +impl Nova where C1: CurveGroup, C2: CurveGroup, FC: FCircuit, Params = ()>, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, ::BaseField: PrimeField, ::BaseField: PrimeField, ::ScalarField: Absorb, @@ -117,7 +118,7 @@ where mut reader: R, compress: ark_serialize::Compress, validate: ark_serialize::Validate, - prover_params: ProverParams, + prover_params: ProverParams, poseidon_config: PoseidonConfig, ) -> Result { let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?; @@ -152,7 +153,6 @@ where cs2.finalize(); let cs2 = cs2.into_inner().ok_or(SerializationError::InvalidData)?; let cf_r1cs = extract_r1cs::(&cs2); - Ok(Nova { _gc1: PhantomData, _c2: PhantomData, @@ -207,6 +207,7 @@ pub mod tests { CubicFCircuit, KZG<'static, Bn254>, Pedersen, + false, >; let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit); let nova_params = N::preprocess(&mut rng, &prep_param).unwrap(); @@ -242,6 +243,7 @@ pub mod tests { CubicFCircuit, KZG, Pedersen, + false, >::deserialize_nova( bytes.as_slice(), Compress::No, diff --git a/folding-schemes/src/folding/nova/traits.rs b/folding-schemes/src/folding/nova/traits.rs index 29a4ede..8bb081f 100644 --- a/folding-schemes/src/folding/nova/traits.rs +++ b/folding-schemes/src/folding/nova/traits.rs @@ -1,6 +1,6 @@ use ark_crypto_primitives::sponge::Absorb; use ark_ec::{CurveGroup, Group}; -use ark_std::{One, Zero}; +use ark_std::One; use super::{CommittedInstance, Witness}; use crate::arith::{r1cs::R1CS, Arith}; @@ -34,7 +34,7 @@ where { fn dummy_instance(&self) -> (Witness, CommittedInstance) { let w_len = self.A.n_cols - 1 - self.l; - let w_dummy = Witness::::new(vec![C::ScalarField::zero(); w_len], self.A.n_rows); + let w_dummy = Witness::::dummy(w_len, self.A.n_rows); let u_dummy = CommittedInstance::::dummy(self.l); (w_dummy, u_dummy) } diff --git a/folding-schemes/src/lib.rs b/folding-schemes/src/lib.rs index 73b30e8..4e2764d 100644 --- a/folding-schemes/src/lib.rs +++ b/folding-schemes/src/lib.rs @@ -77,6 +77,8 @@ pub enum Error { PedersenParamsLen(usize, usize), #[error("Blinding factor not 0 for Commitment without hiding")] BlindingNotZero, + #[error("Blinding factors incorrect, blinding is set to {0} but blinding values are {1}")] + IncorrectBlinding(bool, String), #[error("Commitment verification failed")] CommitmentVerificationFail, diff --git a/folding-schemes/src/utils/mod.rs b/folding-schemes/src/utils/mod.rs index ca017d5..c2fdc3a 100644 --- a/folding-schemes/src/utils/mod.rs +++ b/folding-schemes/src/utils/mod.rs @@ -41,7 +41,7 @@ pub fn get_cm_coordinates(cm: &C) -> Vec { } /// returns the hash of the given public parameters of the Folding Scheme -pub fn pp_hash( +pub fn pp_hash( arith: &impl Arith, cf_arith: &impl Arith, cs_vp: &CS1::VerifierParams, @@ -51,8 +51,8 @@ pub fn pp_hash( where C1: CurveGroup, C2: CurveGroup, - CS1: CommitmentScheme, - CS2: CommitmentScheme, + CS1: CommitmentScheme, + CS2: CommitmentScheme, { let mut hasher = Sha3_256::new(); diff --git a/solidity-verifiers/src/verifiers/nova_cyclefold.rs b/solidity-verifiers/src/verifiers/nova_cyclefold.rs index afe7686..391e485 100644 --- a/solidity-verifiers/src/verifiers/nova_cyclefold.rs +++ b/solidity-verifiers/src/verifiers/nova_cyclefold.rs @@ -166,7 +166,7 @@ mod tests { NovaCycleFoldVerifierKey, ProtocolVerifierKey, }; - type NOVA = Nova, Pedersen>; + type NOVA = Nova, Pedersen, false>; type DECIDER = DeciderEth< G1, GVar, @@ -318,10 +318,11 @@ mod tests { let poseidon_config = poseidon_canonical_config::(); let f_circuit = FC::new(()).unwrap(); - let prep_param = PreprocessorParam::, Pedersen>::new( - poseidon_config, - f_circuit.clone(), - ); + let prep_param = + PreprocessorParam::, Pedersen, false>::new( + poseidon_config, + f_circuit.clone(), + ); let nova_params = NOVA::preprocess(&mut rng, &prep_param).unwrap(); let nova = NOVA::init( &nova_params,