diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index d5feb1ad1..f99b210fb 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,8 +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 154c3c52a..0e8b9e423 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-supernova.rs b/benches/recursive-snark-supernova.rs index cd99f7141..14c285e07 100644 --- a/benches/recursive-snark-supernova.rs +++ b/benches/recursive-snark-supernova.rs @@ -66,8 +66,8 @@ fn bench_one_augmented_circuit_recursive_snark(c: &mut Criterion) { >::new(0, c_primary, c_secondary.clone(), 1); let (r1cs_shape_primary, r1cs_shape_secondary) = running_claim1.get_r1cs_shape(); - let ck_primary = gen_commitment_key_by_r1cs(r1cs_shape_primary); - let ck_secondary = gen_commitment_key_by_r1cs(r1cs_shape_secondary); + let ck_primary = gen_commitment_key_by_r1cs(r1cs_shape_primary, None); + let ck_secondary = gen_commitment_key_by_r1cs(r1cs_shape_secondary, None); // set unified ck_primary, ck_secondary and update digest running_claim1.set_commitment_key(ck_primary.clone(), ck_secondary.clone()); @@ -182,8 +182,8 @@ fn bench_two_augmented_circuit_recursive_snark(c: &mut Criterion) { >::new(1, c_primary, c_secondary.clone(), 2); let (r1cs_shape_primary, r1cs_shape_secondary) = running_claim1.get_r1cs_shape(); - let ck_primary = gen_commitment_key_by_r1cs(r1cs_shape_primary); - let ck_secondary = gen_commitment_key_by_r1cs(r1cs_shape_secondary); + let ck_primary = gen_commitment_key_by_r1cs(r1cs_shape_primary, None); + let ck_secondary = gen_commitment_key_by_r1cs(r1cs_shape_secondary, None); // set unified ck_primary, ck_secondary and update digest running_claim1.set_commitment_key(ck_primary.clone(), ck_secondary.clone()); diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs index 8fa2988e8..f50d28c09 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 345aaaaff..cdf5299bb 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 = 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 09c7b7ae7..186880012 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -160,7 +160,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/examples/minroot_serde.rs b/examples/minroot_serde.rs index 377f7a696..019b55829 100644 --- a/examples/minroot_serde.rs +++ b/examples/minroot_serde.rs @@ -167,7 +167,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()); encode(&pp, &mut file).unwrap() }; @@ -193,7 +193,7 @@ fn main() { G2, MinRootCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); assert!(result.clone() == pp, "not equal!"); assert!(remaining.is_empty()); } else { diff --git a/src/bellpepper/mod.rs b/src/bellpepper/mod.rs index 4b47e7d28..1491e1c43 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(); + let (shape, ck) = cs.r1cs_shape_and_key(None); // Now get the assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/bellpepper/r1cs.rs b/src/bellpepper/r1cs.rs index 2aa2a4381..c34b34fe6 100644 --- a/src/bellpepper/r1cs.rs +++ b/src/bellpepper/r1cs.rs @@ -5,7 +5,7 @@ use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS}; use crate::{ errors::NovaError, - r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS}, + r1cs::{CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, R1CS}, traits::Group, CommitmentKey, }; @@ -25,9 +25,15 @@ 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_and_key(&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_and_key( + &self, + optfn: Option>, + ) -> (R1CSShape, CommitmentKey) { let S = self.r1cs_shape(); - 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 5cd7aee52..d222355f7 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -400,7 +400,7 @@ mod tests { NovaAugmentedCircuit::new(primary_params, None, &ttc1, ro_consts1.clone()); let mut cs: TestShapeCS = TestShapeCS::new(); let _ = circuit1.synthesize(&mut cs); - let (shape1, ck1) = cs.r1cs_shape_and_key(); + let (shape1, ck1) = cs.r1cs_shape_and_key(None); assert_eq!(cs.num_constraints(), num_constraints_primary); let ttc2 = TrivialTestCircuit::default(); @@ -409,7 +409,7 @@ mod tests { NovaAugmentedCircuit::new(secondary_params, None, &ttc2, ro_consts2.clone()); let mut cs: TestShapeCS = TestShapeCS::new(); let _ = circuit2.synthesize(&mut cs); - let (shape2, ck2) = cs.r1cs_shape_and_key(); + let (shape2, ck2) = cs.r1cs_shape_and_key(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 e40e7ac77..33373f95c 100644 --- a/src/gadgets/ecc.rs +++ b/src/gadgets/ecc.rs @@ -992,7 +992,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(); + let (shape, ck) = cs.r1cs_shape_and_key(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1045,7 +1045,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(); + let (shape, ck) = cs.r1cs_shape_and_key(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); @@ -1102,7 +1102,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(); + let (shape, ck) = cs.r1cs_shape_and_key(None); // Then the satisfying assignment let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); diff --git a/src/lib.rs b/src/lib.rs index 2996120e9..7319871b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,9 @@ use errors::NovaError; use ff::{Field, PrimeField}; 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::{ @@ -96,8 +98,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 = @@ -122,7 +169,7 @@ where ); let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_primary.synthesize(&mut cs); - let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape_and_key(); + let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape_and_key(optfn1); // Initialize ck for the secondary let circuit_secondary: NovaAugmentedCircuit<'_, G1, C2> = NovaAugmentedCircuit::new( @@ -133,7 +180,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(); + let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(optfn2); let mut pp = Self { F_arity_primary, @@ -922,8 +969,15 @@ mod tests { G2: Group::Scalar>, T1: StepCircuit, T2: StepCircuit, + >::CommitmentKey: CommitmentKeyExtTrait, + >::CommitmentKey: CommitmentKeyExtTrait, + ::Repr: Abomonation, + ::Repr: Abomonation, { - 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 @@ -987,7 +1041,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(&test_circuit1, &test_circuit2); + >::setup(&test_circuit1, &test_circuit2, None, None); let num_steps = 1; @@ -1043,7 +1097,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1131,7 +1185,7 @@ mod tests { G2, TrivialTestCircuit<::Scalar>, CubicCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1221,13 +1275,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; @@ -1389,7 +1448,7 @@ mod tests { G2, FifthRootCheckingCircuit<::Scalar>, TrivialTestCircuit<::Scalar>, - >::setup(&circuit_primary, &circuit_secondary); + >::setup(&circuit_primary, &circuit_secondary, None, None); let num_steps = 3; @@ -1467,7 +1526,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 2df5bcc9a..914666f61 100644 --- a/src/nifs.rs +++ b/src/nifs.rs @@ -174,7 +174,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(); + let (shape, ck) = cs.r1cs_shape_and_key(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 e711f851a..b6bd7d20e 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, }, }; @@ -24,6 +24,12 @@ pub struct CommitmentKey { ck: Vec, } +impl Len for CommitmentKey { + fn length(&self) -> usize { + self.ck.len() + } +} + /// A type that holds a commitment #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Abomonation)] #[serde(bound = "")] diff --git a/src/r1cs.rs b/src/r1cs.rs index 35ebdb5bb..3e2f1df63 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -73,13 +73,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 34e8cd9e1..4138c8301 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(); + let (shape, ck) = cs.r1cs_shape_and_key(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 9ac0b1152..3a0c5d826 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, @@ -856,10 +856,19 @@ where type ProverKey = ProverKey; 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.length() >= Self::commitment_key_floor()(S)); let (pk_ee, vk_ee) = EE::setup(ck); // pad the R1CS matrices diff --git a/src/supernova/mod.rs b/src/supernova/mod.rs index 9c3a91f8b..98157c051 100644 --- a/src/supernova/mod.rs +++ b/src/supernova/mod.rs @@ -6,7 +6,10 @@ use crate::{ bellpepper::shape_cs::ShapeCS, constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_HASH_BITS}, errors::NovaError, - r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, R1CS}, + r1cs::{ + CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, + RelaxedR1CSWitness, R1CS, + }, scalar_as_base, traits::{ circuit_supernova::StepCircuit, commitment::CommitmentTrait, AbsorbInROTrait, Group, @@ -775,7 +778,29 @@ where } } -/// genenate commitmentkey by r1cs shape -pub fn gen_commitment_key_by_r1cs(shape: &R1CSShape) -> CommitmentKey { - R1CS::::commitment_key(shape) +/// Generates public parameters (a `CommitmentKey`) for a Rank-1 Constraint System (R1CS) circuit, +/// appropriate for use with a particular SNARK protocol. +/// +/// To generate a commitment key that is tailored to a specific R1CS circuit and SNARK protocol, +/// this function considers the 'shape' of the R1CS circuit (provided via the `R1CSShape` parameter `shape`) +/// and optionally specific requirements of the SNARK protocol’s methodology. +/// +/// # Arguments +/// +/// * `shape`: The shape of the R1CS matrices, which is essential to understanding the structure of the +/// R1CS circuit for which the `CommitmentKey` is being generated. +/// +/// * `optfn`: An optional parameter that encapsulates specific requirements of the +/// SNARK protocol's methodology. For "classical" SNARKs with no special needs, this can be `None`. +/// For specific SNARKs, like Spartan with computational commitments, a particular value should be +/// passed here. This value is typically provided in the SNARK's trait or implementation details. +/// +/// # Returns +/// +/// A `CommitmentKey` tailored to the given R1CS circuit shape and SNARK protocol specifics. +pub fn gen_commitment_key_by_r1cs( + shape: &R1CSShape, + optfn: Option>, +) -> CommitmentKey { + R1CS::::commitment_key(shape, optfn) } diff --git a/src/supernova/test.rs b/src/supernova/test.rs index fc3e3ffbc..63c0fe62f 100644 --- a/src/supernova/test.rs +++ b/src/supernova/test.rs @@ -339,10 +339,14 @@ where .max_by(|(_, circuit_size1), (_, circuit_size2)| circuit_size1.cmp(circuit_size2)) .unwrap(); - let ck_primary = - gen_commitment_key_by_r1cs(&circuit_public_params[max_index_circuit].r1cs_shape_primary); - let ck_secondary = - gen_commitment_key_by_r1cs(&circuit_public_params[max_index_circuit].r1cs_shape_secondary); + let ck_primary = gen_commitment_key_by_r1cs( + &circuit_public_params[max_index_circuit].r1cs_shape_primary, + None, + ); + let ck_secondary = gen_commitment_key_by_r1cs( + &circuit_public_params[max_index_circuit].r1cs_shape_secondary, + None, + ); // set unified ck_primary, ck_secondary and update digest running_claim1.params.ck_primary = Some(ck_primary.clone()); @@ -484,7 +488,7 @@ fn test_recursive_circuit_with( if let Err(e) = circuit1.synthesize(&mut cs) { panic!("{}", e) } - let (shape1, ck1) = cs.r1cs_shape_and_key(); + let (shape1, ck1) = cs.r1cs_shape_and_key(None); assert_eq!(cs.num_constraints(), num_constraints_primary); // Initialize the shape and ck for the secondary @@ -502,7 +506,7 @@ fn test_recursive_circuit_with( if let Err(e) = circuit2.synthesize(&mut cs) { panic!("{}", e) } - let (shape2, ck2) = cs.r1cs_shape_and_key(); + let (shape2, ck2) = cs.r1cs_shape_and_key(None); assert_eq!(cs.num_constraints(), num_constraints_secondary); // Execute the base case for the primary diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 07374449c..e13726735 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -74,10 +74,19 @@ 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 length(&self) -> usize; +} + /// A trait that ties different pieces of the commitment generation together pub trait CommitmentEngineTrait: Clone + Send + Sync { /// Holds the type of the commitment key - type CommitmentKey: Clone + /// The key should quantify its length in terms of group generators. + type CommitmentKey: Len + + Clone + PartialEq + Debug + Send diff --git a/src/traits/snark.rs b/src/traits/snark.rs index 4ef1b30a6..3fec8fd4f 100644 --- a/src/traits/snark.rs +++ b/src/traits/snark.rs @@ -19,6 +19,15 @@ pub trait RelaxedR1CSSNARKTrait: /// A type that represents the verifier's key type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de> + Abomonation; + /// 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,