From 1acbf8c8fbc216c63f3c5063ce78716cbc89cbe5 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 | 2 +- benches/sha256.rs | 2 +- examples/minroot.rs | 2 +- src/bellperson/mod.rs | 2 +- src/bellperson/r1cs.rs | 10 +++-- src/circuit.rs | 4 +- src/gadgets/ecc.rs | 6 +-- src/lib.rs | 85 +++++++++++++++++++++++++++++++------ 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, 165 insertions(+), 39 deletions(-) diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index 2402217e2..95bcb9c55 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, &c_secondary); + let pp = PublicParams::::setup( + &c_primary, + &c_secondary, + 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, &c_secondary); + let pp = PublicParams::::setup( + &c_primary, + &c_secondary, + 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 501055656..af2ed418c 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 5af803f83..3182777d8 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 = TrivialTestCircuit::default(); // Produce public parameters - let pp = PublicParams::::setup(&c_primary, &c_secondary); + let pp = PublicParams::::setup(&c_primary, &c_secondary, 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 642c69912..0a9084bfc 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -201,7 +201,7 @@ fn bench_recursive_snark(c: &mut Criterion) { // Produce public parameters let ttc = TrivialTestCircuit::default(); - let pp = PublicParams::::setup(&circuit_primary, &ttc); + let pp = PublicParams::::setup(&circuit_primary, &ttc, 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 dd5c8d60c..07689f5e7 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -172,7 +172,7 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, 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 ae3388dfb..84832b19d 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 { @@ -46,7 +48,7 @@ impl NovaWitness for SatisfyingAssignment { } impl NovaShape for ShapeCS { - 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(); @@ -76,7 +78,7 @@ impl NovaShape for ShapeCS { 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 426ce18a5..967ef4969 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -402,7 +402,7 @@ mod tests { NovaAugmentedCircuit::new(&primary_params, None, &ttc1, ro_consts1.clone()); 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); let ttc2 = TrivialTestCircuit::default(); @@ -411,7 +411,7 @@ mod tests { NovaAugmentedCircuit::new(&secondary_params, None, &ttc2, ro_consts2.clone()); 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 b1eb27670..fd2b5b01a 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 3394fc71c..316eed7df 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(); + /// // Only relevant for a SNARK using computational commitments, pass None otherwise. + /// 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<'_, G1, C2> = 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, &test_circuit2); + >::setup(&test_circuit1, &test_circuit2, None, None); let num_steps = 1; @@ -985,7 +1039,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1072,7 +1126,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1161,13 +1215,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, &circuit_secondary); + >::setup( + &circuit_primary, + &circuit_secondary, + Some(S1Prime::commitment_key_floor()), + Some(S2Prime::commitment_key_floor()), + ); let num_steps = 3; @@ -1339,7 +1398,7 @@ mod tests { G2, FifthRootCheckingCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1417,7 +1476,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(&test_circuit1, &test_circuit2); + >::setup(&test_circuit1, &test_circuit2, 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 4894e70d0..7d5d68028 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 57bec8fe7..75afe6e91 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, @@ -835,10 +835,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 4ac8349ce..1fd156b3d 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -72,12 +72,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,