diff --git a/Cargo.toml b/Cargo.toml index 3f77d0516..41c52ef43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nova-snark" -version = "0.24.0" +version = "0.26.0" authors = ["Srinath Setty <srinath@microsoft.com>"] edition = "2021" description = "Recursive zkSNARKs without trusted setup" diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index ca5528d21..4e08aee99 100644 --- a/benches/compressed-snark.rs +++ b/benches/compressed-snark.rs @@ -82,18 +82,13 @@ fn bench_compressed_snark(c: &mut Criterion) { &pp, &c_primary, &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + &[<G1 as Group>::Scalar::from(2u64)], + &[<G2 as Group>::Scalar::from(2u64)], + ) + .unwrap(); for i in 0..num_steps { - let res = recursive_snark.prove_step( - &pp, - &c_primary, - &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + let res = recursive_snark.prove_step(&pp, &c_primary, &c_secondary); assert!(res.is_ok()); // verify the recursive snark at each step of recursion @@ -128,8 +123,8 @@ fn bench_compressed_snark(c: &mut Criterion) { .verify( black_box(&vk), black_box(num_steps), - black_box(vec![<G1 as Group>::Scalar::from(2u64)]), - black_box(vec![<G2 as Group>::Scalar::from(2u64)]), + black_box(&[<G1 as Group>::Scalar::from(2u64)]), + black_box(&[<G2 as Group>::Scalar::from(2u64)]), ) .is_ok()); }) @@ -173,18 +168,13 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) { &pp, &c_primary, &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + &[<G1 as Group>::Scalar::from(2u64)], + &[<G2 as Group>::Scalar::from(2u64)], + ) + .unwrap(); for i in 0..num_steps { - let res = recursive_snark.prove_step( - &pp, - &c_primary, - &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + let res = recursive_snark.prove_step(&pp, &c_primary, &c_secondary); assert!(res.is_ok()); // verify the recursive snark at each step of recursion @@ -219,8 +209,8 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) { .verify( black_box(&vk), black_box(num_steps), - black_box(vec![<G1 as Group>::Scalar::from(2u64)]), - black_box(vec![<G2 as Group>::Scalar::from(2u64)]), + black_box(&[<G1 as Group>::Scalar::from(2u64)]), + black_box(&[<G2 as Group>::Scalar::from(2u64)]), ) .is_ok()); }) diff --git a/benches/recursive-snark-supernova.rs b/benches/recursive-snark-supernova.rs index 57624b150..ca3fcd5eb 100644 --- a/benches/recursive-snark-supernova.rs +++ b/benches/recursive-snark-supernova.rs @@ -142,8 +142,6 @@ fn bench_one_augmented_circuit_recursive_snark(c: &mut Criterion) { 0, &bench.primary_circuit(0), &bench.secondary_circuit(), - &z0_primary, - &z0_secondary, ); if let Err(e) = &res { println!("res failed {:?}", e); @@ -170,8 +168,6 @@ fn bench_one_augmented_circuit_recursive_snark(c: &mut Criterion) { black_box(0), &bench.primary_circuit(0), &bench.secondary_circuit(), - black_box(&[<G1 as Group>::Scalar::from(2u64)]), - black_box(&[<G2 as Group>::Scalar::from(2u64)]), ) .is_ok()); }) @@ -250,8 +246,6 @@ fn bench_two_augmented_circuit_recursive_snark(c: &mut Criterion) { 0, &bench.primary_circuit(0), &bench.secondary_circuit(), - &z0_primary, - &z0_secondary, ); if let Err(e) = &res { println!("res failed {:?}", e); @@ -268,8 +262,6 @@ fn bench_two_augmented_circuit_recursive_snark(c: &mut Criterion) { 1, &bench.primary_circuit(1), &bench.secondary_circuit(), - &z0_primary, - &z0_secondary, ); if let Err(e) = &res { println!("res failed {:?}", e); @@ -300,8 +292,6 @@ fn bench_two_augmented_circuit_recursive_snark(c: &mut Criterion) { black_box(0), &bench.primary_circuit(0), &bench.secondary_circuit(), - black_box(&[<G1 as Group>::Scalar::from(2u64)]), - black_box(&[<G2 as Group>::Scalar::from(2u64)]), ) .is_ok()); }) diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs index 4d48b3a11..bfcc2d624 100644 --- a/benches/recursive-snark.rs +++ b/benches/recursive-snark.rs @@ -67,18 +67,13 @@ fn bench_recursive_snark(c: &mut Criterion) { &pp, &c_primary, &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + &[<G1 as Group>::Scalar::from(2u64)], + &[<G2 as Group>::Scalar::from(2u64)], + ) + .unwrap(); for i in 0..num_warmup_steps { - let res = recursive_snark.prove_step( - &pp, - &c_primary, - &c_secondary, - vec![<G1 as Group>::Scalar::from(2u64)], - vec![<G2 as Group>::Scalar::from(2u64)], - ); + let res = recursive_snark.prove_step(&pp, &c_primary, &c_secondary); assert!(res.is_ok()); // verify the recursive snark at each step of recursion @@ -99,8 +94,6 @@ fn bench_recursive_snark(c: &mut Criterion) { black_box(&pp), black_box(&c_primary), black_box(&c_secondary), - black_box(vec![<G1 as Group>::Scalar::from(2u64)]), - black_box(vec![<G2 as Group>::Scalar::from(2u64)]), ) .is_ok()); }) diff --git a/benches/sha256.rs b/benches/sha256.rs index cf43d8eaa..e802e83c8 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -167,17 +167,17 @@ fn bench_recursive_snark(c: &mut Criterion) { black_box(&pp), black_box(&circuit_primary), black_box(&circuit_secondary), - black_box(z0_primary.clone()), - black_box(z0_secondary.clone()), - ); + black_box(&z0_primary), + black_box(&z0_secondary), + ) + .unwrap(); + // produce a recursive SNARK for a step of the recursion assert!(recursive_snark .prove_step( black_box(&pp), black_box(&circuit_primary), black_box(&circuit_secondary), - black_box(z0_primary.clone()), - black_box(z0_secondary.clone()), ) .is_ok()); }) diff --git a/examples/minroot.rs b/examples/minroot.rs index 1f82aec83..7cc1e0c6e 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -215,23 +215,19 @@ fn main() { type C2 = TrivialCircuit<<G2 as Group>::Scalar>; // produce a recursive SNARK println!("Generating a RecursiveSNARK..."); - let mut recursive_snark: RecursiveSNARK<G1, G2, C1, C2> = RecursiveSNARK::<G1, G2, C1, C2>::new( - &pp, - &minroot_circuits[0], - &circuit_secondary, - z0_primary.clone(), - z0_secondary.clone(), - ); + let mut recursive_snark: RecursiveSNARK<G1, G2, C1, C2> = + RecursiveSNARK::<G1, G2, C1, C2>::new( + &pp, + &minroot_circuits[0], + &circuit_secondary, + &z0_primary, + &z0_secondary, + ) + .unwrap(); for (i, circuit_primary) in minroot_circuits.iter().take(num_steps).enumerate() { let start = Instant::now(); - let res = recursive_snark.prove_step( - &pp, - circuit_primary, - &circuit_secondary, - z0_primary.clone(), - z0_secondary.clone(), - ); + let res = recursive_snark.prove_step(&pp, circuit_primary, &circuit_secondary); assert!(res.is_ok()); println!( "RecursiveSNARK::prove_step {}: {:?}, took {:?} ", @@ -282,7 +278,7 @@ fn main() { // verify the compressed SNARK println!("Verifying a CompressedSNARK..."); let start = Instant::now(); - let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary); + let res = compressed_snark.verify(&vk, num_steps, &z0_primary, &z0_secondary); println!( "CompressedSNARK::verify: {:?}, took {:?}", res.is_ok(), diff --git a/src/lib.rs b/src/lib.rs index eef3ec2a0..de65caa33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,6 +274,8 @@ where C1: StepCircuit<G1::Scalar>, C2: StepCircuit<G2::Scalar>, { + z0_primary: Vec<G1::Scalar>, + z0_secondary: Vec<G2::Scalar>, r_W_primary: RelaxedR1CSWitness<G1>, r_U_primary: RelaxedR1CSInstance<G1>, r_W_secondary: RelaxedR1CSWitness<G2>, @@ -299,15 +301,19 @@ where pp: &PublicParams<G1, G2, C1, C2>, c_primary: &C1, c_secondary: &C2, - z0_primary: Vec<G1::Scalar>, - z0_secondary: Vec<G2::Scalar>, - ) -> Self { + z0_primary: &[G1::Scalar], + z0_secondary: &[G2::Scalar], + ) -> Result<Self, NovaError> { + if z0_primary.len() != pp.F_arity_primary || z0_secondary.len() != pp.F_arity_secondary { + return Err(NovaError::InvalidInitialInputLength); + } + // base case for the primary let mut cs_primary: SatisfyingAssignment<G1> = SatisfyingAssignment::new(); let inputs_primary: NovaAugmentedCircuitInputs<G2> = NovaAugmentedCircuitInputs::new( scalar_as_base::<G1>(pp.digest()), G1::Scalar::ZERO, - z0_primary, + z0_primary.to_vec(), None, None, None, @@ -334,7 +340,7 @@ where let inputs_secondary: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new( pp.digest(), G2::Scalar::ZERO, - z0_secondary, + z0_secondary.to_vec(), None, None, Some(u_primary.clone()), @@ -390,7 +396,9 @@ where .collect::<Result<Vec<<G2 as Group>::Scalar>, NovaError>>() .expect("Nova error synthesis"); - Self { + Ok(Self { + z0_primary: z0_primary.to_vec(), + z0_secondary: z0_secondary.to_vec(), r_W_primary, r_U_primary, r_W_secondary, @@ -402,7 +410,7 @@ where zi_secondary, _p_c1: Default::default(), _p_c2: Default::default(), - } + }) } /// Create a new `RecursiveSNARK` (or updates the provided `RecursiveSNARK`) @@ -413,14 +421,8 @@ where pp: &PublicParams<G1, G2, C1, C2>, c_primary: &C1, c_secondary: &C2, - z0_primary: Vec<G1::Scalar>, - z0_secondary: Vec<G2::Scalar>, ) -> Result<(), NovaError> { - if z0_primary.len() != pp.F_arity_primary || z0_secondary.len() != pp.F_arity_secondary { - return Err(NovaError::InvalidInitialInputLength); - } - - // First step was already done in the constructor + // first step was already done in the constructor if self.i == 0 { self.i = 1; return Ok(()); @@ -443,7 +445,7 @@ where let inputs_primary: NovaAugmentedCircuitInputs<G2> = NovaAugmentedCircuitInputs::new( scalar_as_base::<G1>(pp.digest()), G1::Scalar::from(self.i as u64), - z0_primary, + self.z0_primary.to_vec(), Some(self.zi_primary.clone()), Some(self.r_U_secondary.clone()), Some(self.l_u_secondary.clone()), @@ -483,7 +485,7 @@ where let inputs_secondary: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new( pp.digest(), G2::Scalar::from(self.i as u64), - z0_secondary, + self.z0_secondary.to_vec(), Some(self.zi_secondary.clone()), Some(self.r_U_primary.clone()), Some(l_u_primary), @@ -546,6 +548,11 @@ where return Err(NovaError::ProofVerifyError); } + // check if the initial inputs match + if self.z0_primary != z0_primary || self.z0_secondary != z0_secondary { + return Err(NovaError::ProofVerifyError); + } + // check if the (relaxed) R1CS instances have two public outputs if self.l_u_secondary.X.len() != 2 || self.r_U_primary.X.len() != 2 @@ -823,8 +830,8 @@ where &self, vk: &VerifierKey<G1, G2, C1, C2, S1, S2>, num_steps: usize, - z0_primary: Vec<G1::Scalar>, - z0_secondary: Vec<G2::Scalar>, + z0_primary: &[G1::Scalar], + z0_secondary: &[G2::Scalar], ) -> Result<(Vec<G1::Scalar>, Vec<G2::Scalar>), NovaError> { // number of steps cannot be zero if num_steps == 0 { @@ -848,7 +855,7 @@ where hasher.absorb(vk.pp_digest); hasher.absorb(G1::Scalar::from(num_steps as u64)); for e in z0_primary { - hasher.absorb(e); + hasher.absorb(*e); } for e in &self.zn_primary { hasher.absorb(*e); @@ -862,7 +869,7 @@ where hasher2.absorb(scalar_as_base::<G1>(vk.pp_digest)); hasher2.absorb(G2::Scalar::from(num_steps as u64)); for e in z0_secondary { - hasher2.absorb(e); + hasher2.absorb(*e); } for e in &self.zn_secondary { hasher2.absorb(*e); @@ -1112,17 +1119,12 @@ mod tests { &pp, &test_circuit1, &test_circuit2, - vec![<G1 as Group>::Scalar::ZERO], - vec![<G2 as Group>::Scalar::ZERO], - ); + &[<G1 as Group>::Scalar::ZERO], + &[<G2 as Group>::Scalar::ZERO], + ) + .unwrap(); - let res = recursive_snark.prove_step( - &pp, - &test_circuit1, - &test_circuit2, - vec![<G1 as Group>::Scalar::ZERO], - vec![<G2 as Group>::Scalar::ZERO], - ); + let res = recursive_snark.prove_step(&pp, &test_circuit1, &test_circuit2); assert!(res.is_ok()); @@ -1174,18 +1176,13 @@ mod tests { &pp, &circuit_primary, &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], + ) + .unwrap(); for i in 0..num_steps { - let res = recursive_snark.prove_step( - &pp, - &circuit_primary, - &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + let res = recursive_snark.prove_step(&pp, &circuit_primary, &circuit_secondary); assert!(res.is_ok()); // verify the recursive snark at each step of recursion @@ -1262,18 +1259,13 @@ mod tests { &pp, &circuit_primary, &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], + ) + .unwrap(); for _i in 0..num_steps { - let res = recursive_snark.prove_step( - &pp, - &circuit_primary, - &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + let res = recursive_snark.prove_step(&pp, &circuit_primary, &circuit_secondary); assert!(res.is_ok()); } @@ -1310,8 +1302,8 @@ mod tests { let res = compressed_snark.verify( &vk, num_steps, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], ); assert!(res.is_ok()); } @@ -1364,18 +1356,13 @@ mod tests { &pp, &circuit_primary, &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], + ) + .unwrap(); for _i in 0..num_steps { - let res = recursive_snark.prove_step( - &pp, - &circuit_primary, - &circuit_secondary, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + let res = recursive_snark.prove_step(&pp, &circuit_primary, &circuit_secondary); assert!(res.is_ok()); } @@ -1418,8 +1405,8 @@ mod tests { let res = compressed_snark.verify( &vk, num_steps, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], ); assert!(res.is_ok()); } @@ -1545,18 +1532,13 @@ mod tests { &pp, &roots[0], &circuit_secondary, - z0_primary.clone(), - z0_secondary.clone(), - ); + &z0_primary, + &z0_secondary, + ) + .unwrap(); for circuit_primary in roots.iter().take(num_steps) { - let res = recursive_snark.prove_step( - &pp, - circuit_primary, - &circuit_secondary.clone(), - z0_primary.clone(), - z0_secondary.clone(), - ); + let res = recursive_snark.prove_step(&pp, circuit_primary, &circuit_secondary); assert!(res.is_ok()); } @@ -1574,7 +1556,7 @@ mod tests { let compressed_snark = res.unwrap(); // verify the compressed SNARK - let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary); + let res = compressed_snark.verify(&vk, num_steps, &z0_primary, &z0_secondary); assert!(res.is_ok()); } @@ -1616,18 +1598,13 @@ mod tests { &pp, &test_circuit1, &test_circuit2, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + &[<G1 as Group>::Scalar::ONE], + &[<G2 as Group>::Scalar::ZERO], + ) + .unwrap(); // produce a recursive SNARK - let res = recursive_snark.prove_step( - &pp, - &test_circuit1, - &test_circuit2, - vec![<G1 as Group>::Scalar::ONE], - vec![<G2 as Group>::Scalar::ZERO], - ); + let res = recursive_snark.prove_step(&pp, &test_circuit1, &test_circuit2); assert!(res.is_ok()); diff --git a/src/supernova/mod.rs b/src/supernova/mod.rs index 78eb5086c..b23a5cb25 100644 --- a/src/supernova/mod.rs +++ b/src/supernova/mod.rs @@ -372,6 +372,8 @@ where l_u_secondary: R1CSInstance<G2>, pp_digest: G1::Scalar, i: usize, + z0_primary: Vec<G1::Scalar>, + z0_secondary: Vec<G2::Scalar>, zi_primary: Vec<G1::Scalar>, zi_secondary: Vec<G2::Scalar>, program_counter: G1::Scalar, @@ -531,6 +533,8 @@ where l_u_secondary, pp_digest: pp.digest(), i: 0_usize, // after base case, next iteration start from 1 + z0_primary: z0_primary.to_vec(), + z0_secondary: z0_secondary.to_vec(), zi_primary, zi_secondary, program_counter: zi_primary_pc_next, @@ -538,6 +542,7 @@ where num_augmented_circuits, }) } + /// executing a step of the incremental computation #[allow(clippy::too_many_arguments)] #[tracing::instrument(skip_all, name = "supernova::RecursiveSNARK::prove_step")] @@ -547,8 +552,6 @@ where circuit_index: usize, c_primary: &C1, c_secondary: &C2, - z0_primary: &[G1::Scalar], - z0_secondary: &[G2::Scalar], ) -> Result<(), SuperNovaError> { // First step was already done in the constructor if self.i == 0 { @@ -560,14 +563,6 @@ where return Err(NovaError::ProofVerifyError.into()); } - if z0_primary.len() != pp[circuit_index].F_arity - || z0_secondary.len() != pp.circuit_shape_secondary.F_arity - { - return Err(SuperNovaError::NovaError( - NovaError::InvalidInitialInputLength, - )); - } - // fold the secondary circuit's instance let (nifs_secondary, (r_U_secondary_folded, r_W_secondary_folded)) = NIFS::prove( &pp.ck_secondary, @@ -592,7 +587,7 @@ where SuperNovaAugmentedCircuitInputs::new( scalar_as_base::<G1>(self.pp_digest), G1::Scalar::from(self.i as u64), - z0_primary, + &self.z0_primary, Some(&self.zi_primary), Some(&self.r_U_secondary), Some(&self.l_u_secondary), @@ -659,7 +654,7 @@ where SuperNovaAugmentedCircuitInputs::new( self.pp_digest, G2::Scalar::from(self.i as u64), - z0_secondary, + &self.z0_secondary, Some(&self.zi_secondary), Some(&self.r_U_primary), Some(&l_u_primary), diff --git a/src/supernova/test.rs b/src/supernova/test.rs index d60713cfb..e08d32d19 100644 --- a/src/supernova/test.rs +++ b/src/supernova/test.rs @@ -505,8 +505,6 @@ where augmented_circuit_index, &circuit_primary, &circuit_secondary, - &z0_primary, - &z0_secondary, ) .unwrap(); recursive_snark