From 32f11cd9600492c8dea0ef419153335d6bcdc9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Thu, 13 Jul 2023 13:03:40 -0400 Subject: [PATCH] feat: Make commitment key generation configurable with an optional parameter - Implemented the `Len` trait within `CommitmentKey` to allow length quantification in terms of group generators. Made ppSnark fail setup if given commitment key with insufficient length, as measured by its own commitment_key_floor() (see below) - Made RelaxedR1CSTrait include a fn commitment_key_floor() -> Box Fn(&'a R1CSShape) -> usize> with default implementation to quantify the Snark's commitment key size requirements in the shape of a closure, - Made PublicParameters accept optional Box Fn(&'a R1CSShape) -> usize> parameters for each circuit's group, to parametrize the CommitmentKey creation. Implementation details: - defined type alias CommitmentKeyHint = Box) -> usize>; (only used internally) - Modified numerous function calls and parameter setups to include optional parameter `CommitmentKeyHint` that gives a more flexible commitment key generation. - Added the `CommitmentKeyHint` to the `r1cs` import list and expanded `NovaShape` trait to optionally accept it. --- benches/compressed-snark.rs | 15 +++++- benches/compute-digest.rs | 7 ++- benches/recursive-snark.rs | 3 +- benches/sha256.rs | 8 +++- examples/minroot.rs | 7 ++- src/bellperson/mod.rs | 2 +- src/bellperson/r1cs.rs | 10 ++-- src/circuit.rs | 4 +- src/gadgets/ecc.rs | 6 +-- src/lib.rs | 95 ++++++++++++++++++++++++++++++++----- src/nifs.rs | 4 +- src/provider/pedersen.rs | 8 +++- src/r1cs.rs | 24 ++++++++-- src/spartan/direct.rs | 3 +- src/spartan/ppsnark.rs | 11 ++++- src/traits/commitment.rs | 10 +++- src/traits/snark.rs | 9 ++++ 17 files changed, 186 insertions(+), 40 deletions(-) diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index 4ea7156fd..d30fa0b62 100644 --- a/benches/compressed-snark.rs +++ b/benches/compressed-snark.rs @@ -7,6 +7,7 @@ use ff::PrimeField; use nova_snark::{ traits::{ circuit::{StepCircuit, TrivialTestCircuit}, + snark::RelaxedR1CSSNARKTrait, Group, }, CompressedSNARK, PublicParams, RecursiveSNARK, @@ -65,7 +66,12 @@ fn bench_compressed_snark(c: &mut Criterion) { let c_secondary = TrivialTestCircuit::default(); // Produce public parameters - let pp = PublicParams::::setup(c_primary.clone(), c_secondary.clone()); + let pp = PublicParams::::setup( + c_primary.clone(), + c_secondary.clone(), + Some(S1::commitment_key_floor()), + Some(S2::commitment_key_floor()), + ); // Produce prover and verifier keys for CompressedSNARK let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap(); @@ -152,7 +158,12 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) { let c_secondary = TrivialTestCircuit::default(); // Produce public parameters - let pp = PublicParams::::setup(c_primary.clone(), c_secondary.clone()); + let pp = PublicParams::::setup( + c_primary.clone(), + c_secondary.clone(), + Some(SS1::commitment_key_floor()), + Some(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 47bdda1dc..74a8e86c2 100644 --- a/benches/compute-digest.rs +++ b/benches/compute-digest.rs @@ -27,7 +27,12 @@ criterion_main!(compute_digest); fn bench_compute_digest(c: &mut Criterion) { c.bench_function("compute_digest", |b| { b.iter(|| { - PublicParams::::setup(black_box(C1::new(10)), black_box(C2::default())) + PublicParams::::setup( + black_box(C1::new(10)), + black_box(C2::default()), + black_box(None), + black_box(None), + ) }) }); } diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs index eed8d48fa..067fc4409 100644 --- a/benches/recursive-snark.rs +++ b/benches/recursive-snark.rs @@ -56,7 +56,8 @@ fn bench_recursive_snark(c: &mut Criterion) { let c_secondary = TrivialTestCircuit::default(); // Produce public parameters - let pp = PublicParams::::setup(c_primary.clone(), c_secondary.clone()); + let pp = + PublicParams::::setup(c_primary.clone(), c_secondary.clone(), None, None); // 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 f35500f86..4eeea3aaf 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -200,8 +200,12 @@ fn bench_recursive_snark(c: &mut Criterion) { group.sample_size(10); // Produce public parameters - let pp = - PublicParams::::setup(circuit_primary.clone(), TrivialTestCircuit::default()); + let pp = PublicParams::::setup( + circuit_primary.clone(), + TrivialTestCircuit::default(), + None, + None, + ); let circuit_secondary = TrivialTestCircuit::default(); let z0_primary = vec![::Scalar::from(2u64)]; diff --git a/examples/minroot.rs b/examples/minroot.rs index 75c2d41df..ddbffd4ea 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -172,7 +172,12 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(circuit_primary.clone(), circuit_secondary.clone()); + >::setup( + circuit_primary.clone(), + circuit_secondary.clone(), + None, + None, + ); println!("PublicParams::setup, took {:?} ", start.elapsed()); println!( diff --git a/src/bellperson/mod.rs b/src/bellperson/mod.rs index 74588d833..1ee44cece 100644 --- a/src/bellperson/mod.rs +++ b/src/bellperson/mod.rs @@ -49,7 +49,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(); + let (shape, ck) = cs.r1cs_shape(None); // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/bellperson/r1cs.rs b/src/bellperson/r1cs.rs index 56710f76e..13c43ca05 100644 --- a/src/bellperson/r1cs.rs +++ b/src/bellperson/r1cs.rs @@ -5,7 +5,7 @@ use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment}; use crate::{ errors::NovaError, - r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS}, + r1cs::{CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, R1CS}, traits::Group, CommitmentKey, }; @@ -25,7 +25,9 @@ pub trait NovaWitness { /// `NovaShape` provides methods for acquiring `R1CSShape` and `CommitmentKey` from implementers. pub trait NovaShape { /// Return an appropriate `R1CSShape` and `CommitmentKey` structs. - fn r1cs_shape(&self) -> (R1CSShape, CommitmentKey); + /// Optionally, a `CommitmentKeyHint` can be provided to help guide the + /// construction of the `CommitmentKey`. This parameter is documented in `r1cs::R1CS::commitment_key`. + fn r1cs_shape(&self, optfn: Option>) -> (R1CSShape, CommitmentKey); } impl NovaWitness for SatisfyingAssignment @@ -52,7 +54,7 @@ impl NovaShape for ShapeCS where G::Scalar: PrimeField, { - fn r1cs_shape(&self) -> (R1CSShape, CommitmentKey) { + fn r1cs_shape(&self, optfn: Option>) -> (R1CSShape, CommitmentKey) { let mut A: Vec<(usize, usize, G::Scalar)> = Vec::new(); let mut B: Vec<(usize, usize, G::Scalar)> = Vec::new(); let mut C: Vec<(usize, usize, G::Scalar)> = Vec::new(); @@ -82,7 +84,7 @@ where res.unwrap() }; - let ck = R1CS::::commitment_key(&S); + let ck = R1CS::::commitment_key(&S, optfn); (S, ck) } diff --git a/src/circuit.rs b/src/circuit.rs index 60744f0e2..5ef70c3be 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -406,7 +406,7 @@ mod tests { ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit1.synthesize(&mut cs); - let (shape1, ck1) = cs.r1cs_shape(); + let (shape1, ck1) = cs.r1cs_shape(None); assert_eq!(cs.num_constraints(), num_constraints_primary); // Initialize the shape and ck for the secondary @@ -419,7 +419,7 @@ mod tests { ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit2.synthesize(&mut cs); - let (shape2, ck2) = cs.r1cs_shape(); + let (shape2, ck2) = cs.r1cs_shape(None); 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 d24cc5d4a..57e6e562b 100644 --- a/src/gadgets/ecc.rs +++ b/src/gadgets/ecc.rs @@ -994,7 +994,7 @@ mod tests { let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_smul::(cs.namespace(|| "synthesize")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape(); + let (shape, ck) = cs.r1cs_shape(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1047,7 +1047,7 @@ mod tests { let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_add_equal::(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape(); + let (shape, ck) = cs.r1cs_shape(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1104,7 +1104,7 @@ mod tests { let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_add_negation::(cs.namespace(|| "synthesize add equal")); println!("Number of constraints: {}", cs.num_constraints()); - let (shape, ck) = cs.r1cs_shape(); + let (shape, ck) = cs.r1cs_shape(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/lib.rs b/src/lib.rs index 59391e7b5..e0d1925fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,9 @@ use errors::NovaError; use ff::Field; use gadgets::utils::scalar_as_base; use nifs::NIFS; -use r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness}; +use r1cs::{ + CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, +}; use serde::{Deserialize, Serialize}; use sha3::{Digest, Sha3_256}; use traits::{ @@ -82,8 +84,53 @@ where C1: StepCircuit, C2: StepCircuit, { - /// Create a new `PublicParams` - pub fn setup(c_primary: C1, c_secondary: C2) -> Self { + /// Creates a new `PublicParams` for a pair of circuits `C1` and `C2`. + /// + /// # 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 + /// implementing `RelaxedR1CSSNARKTrait::commitment_key_floor()`, which can be passed to this function. + /// If you're not using such a SNARK, pass `None` 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 + /// 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. + /// + /// # Example + /// + /// ```rust + /// # use pasta_curves::{vesta, pallas}; + /// # use nova_snark::spartan::ppsnark::RelaxedR1CSSNARK; + /// # use nova_snark::provider::ipa_pc::EvaluationEngine; + /// # use nova_snark::traits::{circuit::TrivialTestCircuit, Group, snark::RelaxedR1CSSNARKTrait}; + /// use nova_snark::PublicParams; + /// + /// type G1 = pallas::Point; + /// type G2 = vesta::Point; + /// type EE1 = EvaluationEngine; + /// type EE2 = EvaluationEngine; + /// type S1Prime = RelaxedR1CSSNARK>; + /// type S2Prime = RelaxedR1CSSNARK>; + /// + /// let circuit1 = TrivialTestCircuit::<::Scalar>::default(); + /// let circuit2 = TrivialTestCircuit::<::Scalar>::default(); + /// + /// let pp_hint1 = Some(S1Prime::::commitment_key_floor()); + /// let pp_hint2 = Some(S2Prime::::commitment_key_floor()); + /// + /// let pp = PublicParams::setup(circuit1, circuit2, pp_hint1, pp_hint2); + /// ``` + pub fn setup( + c_primary: C1, + c_secondary: C2, + optfn1: Option>, + optfn2: Option>, + ) -> Self { let augmented_circuit_params_primary = NovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true); let augmented_circuit_params_secondary = @@ -108,7 +155,7 @@ where ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_primary.synthesize(&mut cs); - let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape(); + let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape(optfn1); // Initialize ck for the secondary let circuit_secondary: NovaAugmentedCircuit = NovaAugmentedCircuit::new( @@ -119,7 +166,7 @@ where ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_secondary.synthesize(&mut cs); - let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape(); + let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape(optfn2); let mut pp = Self { F_arity_primary, @@ -864,8 +911,15 @@ mod tests { G2: Group::Scalar>, T1: StepCircuit, T2: StepCircuit, + >::CommitmentKey: + CommitmentKeyExtTrait::CE>, + >::CommitmentKey: + CommitmentKeyExtTrait::CE>, { - let pp = PublicParams::::setup(circuit1, circuit2); + // this tests public parameters with a size specifically intended for a spark-compressed SNARK + let pp_hint1 = Some(S1Prime::::commitment_key_floor()); + let pp_hint2 = Some(S2Prime::::commitment_key_floor()); + let pp = PublicParams::::setup(circuit1, circuit2, pp_hint1, pp_hint2); let digest_str = pp .digest @@ -929,7 +983,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(test_circuit1.clone(), test_circuit2.clone()); + >::setup(test_circuit1.clone(), test_circuit2.clone(), None, None); let num_steps = 1; @@ -985,7 +1039,12 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(circuit_primary.clone(), circuit_secondary.clone()); + >::setup( + circuit_primary.clone(), + circuit_secondary.clone(), + None, + None, + ); let num_steps = 3; @@ -1072,7 +1131,12 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(circuit_primary.clone(), circuit_secondary.clone()); + >::setup( + circuit_primary.clone(), + circuit_secondary.clone(), + None, + None, + ); let num_steps = 3; @@ -1161,13 +1225,18 @@ mod tests { let circuit_primary = TrivialTestCircuit::default(); let circuit_secondary = CubicCircuit::default(); - // produce public parameters + // produce public parameters, which we'll use with a spark-compressed SNARK let pp = PublicParams::< G1, G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(circuit_primary.clone(), circuit_secondary.clone()); + >::setup( + circuit_primary.clone(), + circuit_secondary.clone(), + Some(S1Prime::commitment_key_floor()), + Some(S2Prime::commitment_key_floor()), + ); let num_steps = 3; @@ -1339,7 +1408,7 @@ mod tests { G2, FifthRootCheckingCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(circuit_primary, circuit_secondary.clone()); + >::setup(circuit_primary, circuit_secondary.clone(), None, None); let num_steps = 3; @@ -1417,7 +1486,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(test_circuit1.clone(), test_circuit2.clone()); + >::setup(test_circuit1.clone(), test_circuit2.clone(), None, None); let num_steps = 1; diff --git a/src/nifs.rs b/src/nifs.rs index 4f2d5ef0c..25be0d83b 100644 --- a/src/nifs.rs +++ b/src/nifs.rs @@ -174,7 +174,7 @@ mod tests { // First create the shape let mut cs: ShapeCS = ShapeCS::new(); let _ = synthesize_tiny_r1cs_bellperson(&mut cs, None); - let (shape, ck) = cs.r1cs_shape(); + let (shape, ck) = cs.r1cs_shape(None); let ro_consts = <::RO as ROTrait<::Base, ::Scalar>>::Constants::new(); @@ -326,7 +326,7 @@ mod tests { }; // generate generators and ro constants - let ck = R1CS::::commitment_key(&S); + let ck = R1CS::::commitment_key(&S, None); let ro_consts = <::RO as ROTrait<::Base, ::Scalar>>::Constants::new(); diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index fe00c52fd..8c09954a4 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -2,7 +2,7 @@ use crate::{ errors::NovaError, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, AbsorbInROTrait, CompressedGroup, Group, ROTrait, TranscriptReprTrait, }, }; @@ -22,6 +22,12 @@ pub struct CommitmentKey { _p: PhantomData, } +impl Len for CommitmentKey { + fn len(&self) -> usize { + self.ck.len() + } +} + /// A type that holds a commitment #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(bound = "")] diff --git a/src/r1cs.rs b/src/r1cs.rs index 4b204e9eb..a5ee1f740 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -67,13 +67,29 @@ pub struct RelaxedR1CSInstance { pub(crate) u: G::Scalar, } +pub type CommitmentKeyHint = Box) -> usize>; + impl R1CS { - /// Samples public parameters for the specified number of constraints and variables in an R1CS - pub fn commitment_key(S: &R1CSShape) -> CommitmentKey { + /// Generates public parameters for a Rank-1 Constraint System (R1CS). + /// + /// This function takes into consideration the shape of the R1CS matrices and a hint function + /// for the number of generators. It returns a `CommitmentKey`. + /// + /// # 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 floot function is provided, the default number of generators will be max(S.num_cons, S.num_vars). + /// + pub fn commitment_key( + S: &R1CSShape, + commitment_key_floor: Option>, + ) -> CommitmentKey { let num_cons = S.num_cons; let num_vars = S.num_vars; - let total_nz = S.A.len() + S.B.len() + S.C.len(); - G::CE::setup(b"ck", max(max(num_cons, num_vars), total_nz)) + let generators_hint = commitment_key_floor.map(|f| f(S)).unwrap_or(0); + G::CE::setup(b"ck", max(max(num_cons, num_vars), generators_hint)) } } diff --git a/src/spartan/direct.rs b/src/spartan/direct.rs index 9c4665ee4..7dff7d851 100644 --- a/src/spartan/direct.rs +++ b/src/spartan/direct.rs @@ -97,7 +97,8 @@ impl, C: StepCircuit> DirectSNA let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit.synthesize(&mut cs); - let (shape, ck) = cs.r1cs_shape(); + + let (shape, ck) = cs.r1cs_shape(Some(S::commitment_key_floor())); let (pk, vk) = S::setup(&ck, &shape)?; diff --git a/src/spartan/ppsnark.rs b/src/spartan/ppsnark.rs index 0011f463b..581844bcd 100644 --- a/src/spartan/ppsnark.rs +++ b/src/spartan/ppsnark.rs @@ -14,7 +14,7 @@ use crate::{ PolyEvalInstance, PolyEvalWitness, SparsePolynomial, }, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, Group, TranscriptEngineTrait, TranscriptReprTrait, @@ -918,10 +918,19 @@ impl> RelaxedR1CSSNARKTrait; type VerifierKey = VerifierKey; + fn commitment_key_floor() -> Box Fn(&'a R1CSShape) -> usize> { + Box::new(|shape: &R1CSShape| -> usize { + // the commitment key should be large enough to commit to the R1CS matrices + shape.A.len() + shape.B.len() + shape.C.len() + }) + } + fn setup( ck: &CommitmentKey, S: &R1CSShape, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError> { + // check the provided commitment key meets minimal requirements + assert!(ck.len() >= Self::commitment_key_floor()(S)); let (pk_ee, vk_ee) = EE::setup(ck); // pad the R1CS matrices diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 9b4725fc3..d5b38e645 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -76,12 +76,20 @@ pub trait CommitmentTrait: fn decompress(c: &Self::CompressedCommitment) -> Result; } +/// A trait that helps determine the lenght of a structure. +/// Note this does not impose any memory representation contraints on the structure. +pub trait Len { + /// Returns the length of the structure. + fn len(&self) -> usize; +} + /// A trait that ties different pieces of the commitment generation together pub trait CommitmentEngineTrait: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> { /// Holds the type of the commitment key - type CommitmentKey: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; + /// The key should quantify its length in terms of group generators. + type CommitmentKey: Len + Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// Holds the type of the commitment type Commitment: CommitmentTrait; diff --git a/src/traits/snark.rs b/src/traits/snark.rs index e2c22d0ae..625a2ac98 100644 --- a/src/traits/snark.rs +++ b/src/traits/snark.rs @@ -18,6 +18,15 @@ pub trait RelaxedR1CSSNARKTrait: /// A type that represents the verifier's key type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de>; + /// This associated function (not a method) provides a hint that offers + /// a minimum sizing cue for the commitment key used by this SNARK + /// implementation. The commitment key passed in setup should then + /// be at least as large as this hint. + fn commitment_key_floor() -> Box Fn(&'a R1CSShape) -> usize> { + // The default is to not put an additional floor on the size of the commitment key + Box::new(|_shape: &R1CSShape| 0) + } + /// Produces the keys for the prover and the verifier fn setup( ck: &CommitmentKey,