From 7ae327b1decdf5656fa9511b4c4d4a855d0a477e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Fri, 3 Nov 2023 09:00:51 -0400 Subject: [PATCH] refactor: Refactor public parameters setup to remove optionality of commitment key size hint - Converted `CommitmentKeyHint` from a boxed dynamic trait object to a direct dynamic trait object in `r1cs/mod.rs`. - Changed the `commitment_key` function to always require a commitment key floor, eliminating the need for default behavior when a floor function isn't provided. - Updated the `r1cs_shape` function across various files to take in a `CommitmentKeyHint` instead of it being optional and introduce a closure as an argument. - Relevant modifications and updates were made in the `r1cs_shape` and `commitment_key` function calls within the test functions for various modules. - Ported use of commitment key hint to Supernova, closing #53. - This PR puts Arecibo in line with https://github.com/microsoft/Nova/pull/203 --- benches/compressed-snark.rs | 8 +++--- benches/compute-digest.rs | 4 +-- benches/recursive-snark-supernova.rs | 4 +-- benches/recursive-snark.rs | 2 +- benches/sha256.rs | 2 +- examples/minroot.rs | 2 +- examples/minroot_serde.rs | 4 +-- src/bellpepper/mod.rs | 2 +- src/bellpepper/r1cs.rs | 4 +-- src/circuit.rs | 4 +-- src/gadgets/ecc.rs | 6 ++-- src/lib.rs | 41 +++++++++++++++------------- src/nifs.rs | 4 +-- src/r1cs/mod.rs | 13 ++++----- src/spartan/direct.rs | 2 +- src/supernova/mod.rs | 12 ++++---- src/supernova/test.rs | 8 +++--- 17 files changed, 62 insertions(+), 60 deletions(-) diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index 4e08aee99..9c4341a71 100644 --- a/benches/compressed-snark.rs +++ b/benches/compressed-snark.rs @@ -69,8 +69,8 @@ fn bench_compressed_snark(c: &mut Criterion) { let pp = PublicParams::::new( &c_primary, &c_secondary, - Some(S1::commitment_key_floor()), - Some(S2::commitment_key_floor()), + &*S1::commitment_key_floor(), + &*S2::commitment_key_floor(), ); // Produce prover and verifier keys for CompressedSNARK @@ -156,8 +156,8 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) { let pp = PublicParams::::new( &c_primary, &c_secondary, - Some(SS1::commitment_key_floor()), - Some(SS2::commitment_key_floor()), + &*SS1::commitment_key_floor(), + &*SS2::commitment_key_floor(), ); // Produce prover and verifier keys for CompressedSNARK let (pk, vk) = CompressedSNARK::<_, _, _, _, SS1, SS2>::setup(&pp).unwrap(); diff --git a/benches/compute-digest.rs b/benches/compute-digest.rs index 41ba9be04..adceb8550 100644 --- a/benches/compute-digest.rs +++ b/benches/compute-digest.rs @@ -30,8 +30,8 @@ fn bench_compute_digest(c: &mut Criterion) { PublicParams::::new( black_box(&C1::new(10)), black_box(&C2::default()), - black_box(None), - black_box(None), + black_box(&(|_| 0)), + black_box(&(|_| 0)), ) }) }); diff --git a/benches/recursive-snark-supernova.rs b/benches/recursive-snark-supernova.rs index ca3fcd5eb..504489506 100644 --- a/benches/recursive-snark-supernova.rs +++ b/benches/recursive-snark-supernova.rs @@ -104,7 +104,7 @@ fn bench_one_augmented_circuit_recursive_snark(c: &mut Criterion) { let bench: NonUniformBench::Scalar>> = NonUniformBench::new(1, num_cons); - let pp = PublicParams::new(&bench); + let pp = PublicParams::new(&bench, &(|_| 0), &(|_| 0)); // Bench time to produce a recursive SNARK; // we execute a certain number of warm-up steps since executing @@ -206,7 +206,7 @@ fn bench_two_augmented_circuit_recursive_snark(c: &mut Criterion) { let bench: NonUniformBench::Scalar>> = NonUniformBench::new(2, num_cons); - let pp = PublicParams::new(&bench); + let pp = PublicParams::new(&bench, &(|_| 0), &(|_| 0)); // Bench time to produce a recursive SNARK; // we execute a certain number of warm-up steps since executing diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs index bfcc2d624..7520ddcf9 100644 --- a/benches/recursive-snark.rs +++ b/benches/recursive-snark.rs @@ -56,7 +56,7 @@ fn bench_recursive_snark(c: &mut Criterion) { let c_secondary = TrivialCircuit::default(); // Produce public parameters - let pp = PublicParams::::new(&c_primary, &c_secondary, None, None); + let pp = PublicParams::::new(&c_primary, &c_secondary, &(|_| 0), &(|_| 0)); // Bench time to produce a recursive SNARK; // we execute a certain number of warm-up steps since executing diff --git a/benches/sha256.rs b/benches/sha256.rs index e802e83c8..c2fb45755 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -155,7 +155,7 @@ fn bench_recursive_snark(c: &mut Criterion) { // Produce public parameters let ttc = TrivialCircuit::default(); - let pp = PublicParams::::new(&circuit_primary, &ttc, None, None); + let pp = PublicParams::::new(&circuit_primary, &ttc, &(|_| 0), &(|_| 0)); let circuit_secondary = TrivialCircuit::default(); let z0_primary = vec![::Scalar::from(2u64)]; diff --git a/examples/minroot.rs b/examples/minroot.rs index 7cc1e0c6e..0c0900ff9 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -169,7 +169,7 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); println!("PublicParams::setup, took {:?} ", start.elapsed()); println!( diff --git a/examples/minroot_serde.rs b/examples/minroot_serde.rs index 5bd805150..83a5c030c 100644 --- a/examples/minroot_serde.rs +++ b/examples/minroot_serde.rs @@ -167,7 +167,7 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); println!("PublicParams::setup, took {:?} ", start.elapsed()); encode(&pp, &mut file).unwrap() }; @@ -193,7 +193,7 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); assert!(result.clone() == pp, "not equal!"); assert!(remaining.is_empty()); } else { diff --git a/src/bellpepper/mod.rs b/src/bellpepper/mod.rs index ff1a51c89..ad9751092 100644 --- a/src/bellpepper/mod.rs +++ b/src/bellpepper/mod.rs @@ -50,7 +50,7 @@ mod tests { // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_alloc_bit(&mut cs); - let (shape, ck) = cs.r1cs_shape_and_key(None); + let (shape, ck) = cs.r1cs_shape_and_key(&(|_| 0)); // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/bellpepper/r1cs.rs b/src/bellpepper/r1cs.rs index 3fa69c1cd..bc7beadb0 100644 --- a/src/bellpepper/r1cs.rs +++ b/src/bellpepper/r1cs.rs @@ -30,10 +30,10 @@ pub trait NovaShape { /// `r1cs::R1CS::commitment_key`. fn r1cs_shape_and_key( &self, - optfn: Option>, + ck_hint: &CommitmentKeyHint, ) -> (R1CSShape, CommitmentKey) { let S = self.r1cs_shape(); - let ck = commitment_key(&S, optfn); + let ck = commitment_key(&S, ck_hint); (S, ck) } diff --git a/src/circuit.rs b/src/circuit.rs index 7307e1359..e95470c40 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -393,7 +393,7 @@ mod tests { NovaAugmentedCircuit::new(primary_params, None, &tc1, ro_consts1.clone()); let mut cs: TestShapeCS = TestShapeCS::new(); let _ = circuit1.synthesize(&mut cs); - let (shape1, ck1) = cs.r1cs_shape_and_key(None); + let (shape1, ck1) = cs.r1cs_shape_and_key(&(|_| 0)); assert_eq!(cs.num_constraints(), num_constraints_primary); let tc2 = TrivialCircuit::default(); @@ -402,7 +402,7 @@ mod tests { NovaAugmentedCircuit::new(secondary_params, None, &tc2, ro_consts2.clone()); let mut cs: TestShapeCS = TestShapeCS::new(); let _ = circuit2.synthesize(&mut cs); - let (shape2, ck2) = cs.r1cs_shape_and_key(None); + let (shape2, ck2) = cs.r1cs_shape_and_key(&(|_| 0)); assert_eq!(cs.num_constraints(), num_constraints_secondary); // Execute the base case for the primary diff --git a/src/gadgets/ecc.rs b/src/gadgets/ecc.rs index 3edbfea75..d75be5240 100644 --- a/src/gadgets/ecc.rs +++ b/src/gadgets/ecc.rs @@ -1001,7 +1001,7 @@ mod tests { let mut cs: TestShapeCS = TestShapeCS::new(); let _ = synthesize_smul::(cs.namespace(|| "synthesize")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape_and_key(None); + let (shape, ck) = cs.r1cs_shape_and_key(&(|_| 0)); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1057,7 +1057,7 @@ mod tests { let mut cs: TestShapeCS = TestShapeCS::new(); let _ = synthesize_add_equal::(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape_and_key(None); + let (shape, ck) = cs.r1cs_shape_and_key(&(|_| 0)); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1117,7 +1117,7 @@ mod tests { let mut cs: TestShapeCS = TestShapeCS::new(); let _ = synthesize_add_negation::(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape_and_key(None); + let (shape, ck) = cs.r1cs_shape_and_key(&(|_| 0)); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/lib.rs b/src/lib.rs index de65caa33..bdb766c03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,18 +140,21 @@ where /// /// # Note /// - /// Some SNARKs, like variants of Spartan, use computation commitments that require - /// larger sizes for some parameters. These SNARKs provide a hint for these values by + /// Public parameters set up a number of bases for the homomorphic commitment scheme of Nova. + /// + /// Some final ocmpressing SNARKs, like variants of Spartan, use computation commitments that require + /// larger sizes for these parameters. These SNARKs provide a hint for these values by /// implementing `RelaxedR1CSSNARKTrait::commitment_key_floor()`, which can be passed to this function. - /// If you're not using such a SNARK, pass `None` instead. + /// + /// If you're not using such a SNARK, pass `&(|_| 0)` instead. /// /// # Arguments /// /// * `c_primary`: The primary circuit of type `C1`. /// * `c_secondary`: The secondary circuit of type `C2`. - /// * `optfn1`: An optional `CommitmentKeyHint` for `G1`, which is a function that provides a hint + /// * `optfn1`: A `CommitmentKeyHint` for `G1`, which is a function that provides a hint /// for the number of generators required in the commitment scheme for the primary circuit. - /// * `optfn2`: An optional `CommitmentKeyHint` for `G2`, similar to `optfn1`, but for the secondary circuit. + /// * `optfn2`: A `CommitmentKeyHint` for `G2`, similar to `optfn1`, but for the secondary circuit. /// /// # Example /// @@ -169,17 +172,17 @@ where /// /// let circuit1 = TrivialCircuit::<::Scalar>::default(); /// let circuit2 = TrivialCircuit::<::Scalar>::default(); - /// // Only relevant for a SNARK using computational commitments, pass None otherwise. - /// let pp_hint1 = Some(SPrime::::commitment_key_floor()); - /// let pp_hint2 = Some(SPrime::::commitment_key_floor()); + /// // Only relevant for a SNARK using computational commitments, pass &(|_| 0) otherwise. + /// let pp_hint1 = &*SPrime::::commitment_key_floor(); + /// let pp_hint2 = &*SPrime::::commitment_key_floor(); /// /// let pp = PublicParams::new(&circuit1, &circuit2, pp_hint1, pp_hint2); /// ``` pub fn new( c_primary: &C1, c_secondary: &C2, - optfn1: Option>, - optfn2: Option>, + optfn1: &CommitmentKeyHint, + optfn2: &CommitmentKeyHint, ) -> Self { let augmented_circuit_params_primary = NovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true); @@ -1029,8 +1032,8 @@ mod tests { ::Repr: Abomonation, { // this tests public parameters with a size specifically intended for a spark-compressed SNARK - let pp_hint1 = Some(SPrime::::commitment_key_floor()); - let pp_hint2 = Some(SPrime::::commitment_key_floor()); + let pp_hint1 = &*SPrime::::commitment_key_floor(); + let pp_hint2 = &*SPrime::::commitment_key_floor(); let pp = PublicParams::::new(circuit1, circuit2, pp_hint1, pp_hint2); let digest_str = pp @@ -1111,7 +1114,7 @@ mod tests { G2, TrivialCircuit<::Scalar>, TrivialCircuit<::Scalar>, - >::new(&test_circuit1, &test_circuit2, None, None); + >::new(&test_circuit1, &test_circuit2, &(|_| 0), &(|_| 0)); let num_steps = 1; // produce a recursive SNARK @@ -1162,7 +1165,7 @@ mod tests { G2, TrivialCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); let num_steps = 3; @@ -1245,7 +1248,7 @@ mod tests { G2, TrivialCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); let num_steps = 3; @@ -1340,8 +1343,8 @@ mod tests { >::new( &circuit_primary, &circuit_secondary, - Some(SPrime::<_, E1>::commitment_key_floor()), - Some(SPrime::<_, E2>::commitment_key_floor()), + &*SPrime::<_, E1>::commitment_key_floor(), + &*SPrime::<_, E2>::commitment_key_floor(), ); let num_steps = 3; @@ -1509,7 +1512,7 @@ mod tests { G2, FifthRootCheckingCircuit<::Scalar>, TrivialCircuit<::Scalar>, - >::new(&circuit_primary, &circuit_secondary, None, None); + >::new(&circuit_primary, &circuit_secondary, &(|_| 0), &(|_| 0)); let num_steps = 3; @@ -1584,7 +1587,7 @@ mod tests { G2, TrivialCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::new(&test_circuit1, &test_circuit2, None, None); + >::new(&test_circuit1, &test_circuit2, &(|_| 0), &(|_| 0)); let num_steps = 1; diff --git a/src/nifs.rs b/src/nifs.rs index d2b8872a0..9dfbfbfac 100644 --- a/src/nifs.rs +++ b/src/nifs.rs @@ -171,7 +171,7 @@ mod tests { // First create the shape let mut cs: TestShapeCS = TestShapeCS::new(); let _ = synthesize_tiny_r1cs_bellpepper(&mut cs, None); - let (shape, ck) = cs.r1cs_shape_and_key(None); + let (shape, ck) = cs.r1cs_shape_and_key(&(|_| 0)); let ro_consts = <::RO as ROTrait<::Base, ::Scalar>>::Constants::default(); @@ -332,7 +332,7 @@ mod tests { }; // generate generators and ro constants - let ck = commitment_key(&S, None); + let ck = commitment_key(&S, &(|_| 0)); let ro_consts = <::RO as ROTrait<::Base, ::Scalar>>::Constants::default(); diff --git a/src/r1cs/mod.rs b/src/r1cs/mod.rs index 83b260dd9..781461077 100644 --- a/src/r1cs/mod.rs +++ b/src/r1cs/mod.rs @@ -76,7 +76,7 @@ pub struct RelaxedR1CSInstance { } /// A type for functions that hints commitment key sizing by returning the floor of the number of required generators. -pub type CommitmentKeyHint = Box) -> usize>; +pub type CommitmentKeyHint = dyn Fn(&R1CSShape) -> usize; /// Generates public parameters for a Rank-1 Constraint System (R1CS). /// @@ -86,13 +86,12 @@ pub type CommitmentKeyHint = Box) -> usize>; /// # Arguments /// /// * `S`: The shape of the R1CS matrices. -/// * `commitment_key_hint`: An optional function that provides a floor for the number of -/// generators. A good function to provide is the `commitment_key_floor` field in the trait `RelaxedR1CSSNARKTrait`. -/// If no floor function is provided, the default number of generators will be `max(S.num_cons`, `S.num_vars`). +/// * `commitment_key_hint`: A function that provides a floor for the number of generators. A good function to +/// provide is the `commitment_key_floor` field in the trait `RelaxedR1CSSNARKTrait`. /// pub fn commitment_key( S: &R1CSShape, - commitment_key_floor: Option>, + commitment_key_floor: &CommitmentKeyHint, ) -> CommitmentKey { let size = commitment_key_size(S, commitment_key_floor); G::CE::setup(b"ck", size) @@ -101,11 +100,11 @@ pub fn commitment_key( /// Computes the number of generators required for the commitment key corresponding to shape `S`. pub fn commitment_key_size( S: &R1CSShape, - commitment_key_floor: Option>, + commitment_key_floor: &CommitmentKeyHint, ) -> usize { let num_cons = S.num_cons; let num_vars = S.num_vars; - let generators_hint = commitment_key_floor.map_or(0, |f| f(S)); + let generators_hint = commitment_key_floor(S); max(max(num_cons, num_vars), generators_hint) } diff --git a/src/spartan/direct.rs b/src/spartan/direct.rs index c736d6e3c..001717e9a 100644 --- a/src/spartan/direct.rs +++ b/src/spartan/direct.rs @@ -97,7 +97,7 @@ impl, C: StepCircuit> DirectSNA let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit.synthesize(&mut cs); - let (shape, ck) = cs.r1cs_shape_and_key(Some(S::commitment_key_floor())); + let (shape, ck) = cs.r1cs_shape_and_key(&*S::commitment_key_floor()); let (pk, vk) = S::setup(&ck, &shape)?; diff --git a/src/supernova/mod.rs b/src/supernova/mod.rs index b23a5cb25..e885ee9fa 100644 --- a/src/supernova/mod.rs +++ b/src/supernova/mod.rs @@ -8,7 +8,7 @@ use crate::{ constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_HASH_BITS}, digest::{DigestComputer, SimpleDigestible}, errors::NovaError, - r1cs::{commitment_key_size, R1CSInstance, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness}, + r1cs::{commitment_key_size, R1CSInstance, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, CommitmentKeyHint}, scalar_as_base, traits::{ circuit_supernova::StepCircuit, @@ -168,7 +168,7 @@ where C2: StepCircuit, { /// Construct a new [PublicParams] - pub fn new>(non_unifrom_circuit: &NC) -> Self { + pub fn new>(non_unifrom_circuit: &NC, ck_hint1: &CommitmentKeyHint, ck_hint2: &CommitmentKeyHint) -> Self { let num_circuits = non_unifrom_circuit.num_circuits(); let augmented_circuit_params_primary = @@ -197,7 +197,7 @@ where }) .collect::>(); - let ck_primary = Self::compute_primary_ck(&circuit_shapes); + let ck_primary = Self::compute_primary_ck(&circuit_shapes, ck_hint1); let augmented_circuit_params_secondary = SuperNovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false); @@ -215,7 +215,7 @@ where ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_secondary.synthesize(&mut cs); - let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(None); + let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(ck_hint2); let circuit_shape_secondary = CircuitShape::new(r1cs_shape_secondary, F_arity_secondary); let pp = PublicParams { @@ -322,10 +322,10 @@ where /// Compute primary and secondary commitment keys sized to handle the largest of the circuits in the provided /// `CircuitShape`. - fn compute_primary_ck(circuit_params: &[CircuitShape]) -> CommitmentKey { + fn compute_primary_ck(circuit_params: &[CircuitShape], ck_hint1: &CommitmentKeyHint) -> CommitmentKey { let size_primary = circuit_params .iter() - .map(|circuit| commitment_key_size(&circuit.r1cs_shape, None)) + .map(|circuit| commitment_key_size(&circuit.r1cs_shape, ck_hint1)) .max() .unwrap(); diff --git a/src/supernova/test.rs b/src/supernova/test.rs index e08d32d19..6665b3216 100644 --- a/src/supernova/test.rs +++ b/src/supernova/test.rs @@ -448,7 +448,7 @@ where let test_rom = TestROM::>::new(rom); let num_steps = test_rom.num_steps(); - let pp = PublicParams::new(&test_rom); + let pp = PublicParams::new(&test_rom, &(|_| 0), &(|_| 0)); let initial_program_counter = test_rom.initial_program_counter(); @@ -571,7 +571,7 @@ fn test_recursive_circuit_with( if let Err(e) = circuit1.synthesize(&mut cs) { panic!("{}", e) } - let (shape1, ck1) = cs.r1cs_shape_and_key(None); + let (shape1, ck1) = cs.r1cs_shape_and_key(&(|_| 0)); assert_eq!(cs.num_constraints(), num_constraints_primary); // Initialize the shape and ck for the secondary @@ -589,7 +589,7 @@ fn test_recursive_circuit_with( if let Err(e) = circuit2.synthesize(&mut cs) { panic!("{}", e) } - let (shape2, ck2) = cs.r1cs_shape_and_key(None); + let (shape2, ck2) = cs.r1cs_shape_and_key(&(|_| 0)); assert_eq!(cs.num_constraints(), num_constraints_secondary); // Execute the base case for the primary @@ -673,7 +673,7 @@ where // // this tests public parameters with a size specifically intended for a spark-compressed SNARK // let pp_hint1 = Some(SPrime::::commitment_key_floor()); // let pp_hint2 = Some(SPrime::::commitment_key_floor()); - let pp = PublicParams::::new(non_uniform_circuit); + let pp = PublicParams::::new(non_uniform_circuit, &(|_| 0), &(|_| 0)); let digest_str = pp .digest()