Skip to content

Commit

Permalink
feat: Make commitment key generation configurable with an optional pa…
Browse files Browse the repository at this point in the history
…rameter (#203)

* 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<dyn for<'a> Fn(&'a R1CSShape<G>) -> usize> with default implementation to quantify the Snark's commitment key size requirements
  in the shape of a closure,
- Made PublicParameters accept optional Box<dyn for<'a> Fn(&'a R1CSShape<G>) -> usize> parameters for each circuit's group, to parametrize the CommitmentKey creation.

Implementation details:
- defined type alias CommitmentKeyHint<G> = Box<dyn Fn(&R1CSShape<G>) -> 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.

* fix: rename Len::len -> Len::length to avoid unrelated clippy lint

* refactor: Refactor public parameters setup to remove optionality of commitment key size hint

- Converted `CommitmentKeyHint<G>` 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.

* feat: Refactor to use `default_commitment_key_hint` across codebase

- Introduced a new function `default_commitment_key_hint` in `nova_snark` package to provide a clearer default sizing hint for the commitment key,
- Replaced hard-coded zero values throughout the codebase with calls to `default_commitment_key_hint` function,

* feat: Refactor error handling and variable naming

- Implement marking of `NovaError` enum as non-exhaustive in `errors.rs`.
- Introduce a new error case `InvalidCommitmentKeyLength` in `NovaError` enum that checks the length of the provided commitment key.
- Improve code readability by renaming `generators_hint` variable to `ck_hint` in the `commitment_key` function.
  • Loading branch information
huitseeker authored Nov 9, 2023
1 parent 3164fe3 commit ded51b5
Show file tree
Hide file tree
Showing 18 changed files with 238 additions and 46 deletions.
16 changes: 13 additions & 3 deletions benches/compressed-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ff::PrimeField;
use nova_snark::{
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::RelaxedR1CSSNARKTrait,
Group,
},
CompressedSNARK, PublicParams, RecursiveSNARK,
Expand Down Expand Up @@ -65,7 +66,12 @@ fn bench_compressed_snark(c: &mut Criterion) {
let c_secondary = TrivialCircuit::default();

// Produce public parameters
let pp = PublicParams::<G1, G2, C1, C2>::setup(&c_primary, &c_secondary);
let pp = PublicParams::<G1, G2, C1, C2>::setup(
&c_primary,
&c_secondary,
&*S1::commitment_key_floor(),
&*S2::commitment_key_floor(),
);

// Produce prover and verifier keys for CompressedSNARK
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
Expand Down Expand Up @@ -147,8 +153,12 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) {
let c_secondary = TrivialCircuit::default();

// Produce public parameters
let pp = PublicParams::<G1, G2, C1, C2>::setup(&c_primary, &c_secondary);

let pp = PublicParams::<G1, G2, C1, C2>::setup(
&c_primary,
&c_secondary,
&*SS1::commitment_key_floor(),
&*SS2::commitment_key_floor(),
);
// Produce prover and verifier keys for CompressedSNARK
let (pk, vk) = CompressedSNARK::<_, _, _, _, SS1, SS2>::setup(&pp).unwrap();

Expand Down
8 changes: 7 additions & 1 deletion benches/compute-digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ff::PrimeField;
use nova_snark::{
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::default_commitment_key_hint,
Group,
},
PublicParams,
Expand All @@ -27,7 +28,12 @@ criterion_main!(compute_digest);
fn bench_compute_digest(c: &mut Criterion) {
c.bench_function("compute_digest", |b| {
b.iter(|| {
PublicParams::<G1, G2, C1, C2>::setup(black_box(&C1::new(10)), black_box(&C2::default()))
PublicParams::<G1, G2, C1, C2>::setup(
black_box(&C1::new(10)),
black_box(&C2::default()),
black_box(&*default_commitment_key_hint()),
black_box(&*default_commitment_key_hint()),
)
})
});
}
Expand Down
8 changes: 7 additions & 1 deletion benches/recursive-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use ff::PrimeField;
use nova_snark::{
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::default_commitment_key_hint,
Group,
},
PublicParams, RecursiveSNARK,
Expand Down Expand Up @@ -56,7 +57,12 @@ fn bench_recursive_snark(c: &mut Criterion) {
let c_secondary = TrivialCircuit::default();

// Produce public parameters
let pp = PublicParams::<G1, G2, C1, C2>::setup(&c_primary, &c_secondary);
let pp = PublicParams::<G1, G2, C1, C2>::setup(
&c_primary,
&c_secondary,
&*default_commitment_key_hint(),
&*default_commitment_key_hint(),
);

// Bench time to produce a recursive SNARK;
// we execute a certain number of warm-up steps since executing
Expand Down
8 changes: 7 additions & 1 deletion benches/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use ff::{PrimeField, PrimeFieldBits};
use nova_snark::{
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::default_commitment_key_hint,
Group,
},
PublicParams, RecursiveSNARK,
Expand Down Expand Up @@ -155,7 +156,12 @@ fn bench_recursive_snark(c: &mut Criterion) {

// Produce public parameters
let ttc = TrivialCircuit::default();
let pp = PublicParams::<G1, G2, C1, C2>::setup(&circuit_primary, &ttc);
let pp = PublicParams::<G1, G2, C1, C2>::setup(
&circuit_primary,
&ttc,
&*default_commitment_key_hint(),
&*default_commitment_key_hint(),
);

let circuit_secondary = TrivialCircuit::default();
let z0_primary = vec![<G1 as Group>::Scalar::from(2u64)];
Expand Down
8 changes: 7 additions & 1 deletion examples/minroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use flate2::{write::ZlibEncoder, Compression};
use nova_snark::{
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::default_commitment_key_hint,
Group,
},
CompressedSNARK, PublicParams, RecursiveSNARK,
Expand Down Expand Up @@ -161,7 +162,12 @@ fn main() {
G2,
MinRootCircuit<<G1 as Group>::Scalar>,
TrivialCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(
&circuit_primary,
&circuit_secondary,
&*default_commitment_key_hint(),
&*default_commitment_key_hint(),
);
println!("PublicParams::setup, took {:?} ", start.elapsed());

println!(
Expand Down
4 changes: 2 additions & 2 deletions src/bellpepper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod tests {
shape_cs::ShapeCS,
solver::SatisfyingAssignment,
},
traits::Group,
traits::{snark::default_commitment_key_hint, Group},
};
use bellpepper_core::{num::AllocatedNum, ConstraintSystem};
use ff::PrimeField;
Expand Down Expand Up @@ -47,7 +47,7 @@ mod tests {
// First create the shape
let mut cs: ShapeCS<G> = ShapeCS::new();
synthesize_alloc_bit(&mut cs);
let (shape, ck) = cs.r1cs_shape();
let (shape, ck) = cs.r1cs_shape(&*default_commitment_key_hint());

// Now get the assignment
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
Expand Down
10 changes: 6 additions & 4 deletions src/bellpepper/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS};
use crate::{
errors::NovaError,
r1cs::{R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix, R1CS},
r1cs::{CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix, R1CS},
traits::Group,
CommitmentKey,
};
Expand All @@ -25,7 +25,9 @@ pub trait NovaWitness<G: Group> {
/// `NovaShape` provides methods for acquiring `R1CSShape` and `CommitmentKey` from implementers.
pub trait NovaShape<G: Group> {
/// Return an appropriate `R1CSShape` and `CommitmentKey` structs.
fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>);
/// A `CommitmentKeyHint` should be provided to help guide the construction of the `CommitmentKey`.
/// This parameter is documented in `r1cs::R1CS::commitment_key`.
fn r1cs_shape(&self, ck_hint: &CommitmentKeyHint<G>) -> (R1CSShape<G>, CommitmentKey<G>);
}

impl<G: Group> NovaWitness<G> for SatisfyingAssignment<G> {
Expand All @@ -51,7 +53,7 @@ macro_rules! impl_nova_shape {
where
G::Scalar: PrimeField,
{
fn r1cs_shape(&self) -> (R1CSShape<G>, CommitmentKey<G>) {
fn r1cs_shape(&self, ck_hint: &CommitmentKeyHint<G>) -> (R1CSShape<G>, CommitmentKey<G>) {
let mut A = SparseMatrix::<G::Scalar>::empty();
let mut B = SparseMatrix::<G::Scalar>::empty();
let mut C = SparseMatrix::<G::Scalar>::empty();
Expand Down Expand Up @@ -79,7 +81,7 @@ macro_rules! impl_nova_shape {

// Don't count One as an input for shape's purposes.
let S = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, A, B, C).unwrap();
let ck = R1CS::<G>::commitment_key(&S);
let ck = R1CS::<G>::commitment_key(&S, ck_hint);

(S, ck)
}
Expand Down
5 changes: 3 additions & 2 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ mod tests {

use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
use crate::provider;
use crate::traits::snark::default_commitment_key_hint;
use crate::{
bellpepper::r1cs::{NovaShape, NovaWitness},
gadgets::utils::scalar_as_base,
Expand All @@ -392,7 +393,7 @@ mod tests {
NovaAugmentedCircuit::new(primary_params, None, &tc1, ro_consts1.clone());
let mut cs: TestShapeCS<G1> = TestShapeCS::new();
let _ = circuit1.synthesize(&mut cs);
let (shape1, ck1) = cs.r1cs_shape();
let (shape1, ck1) = cs.r1cs_shape(&*default_commitment_key_hint());
assert_eq!(cs.num_constraints(), num_constraints_primary);

let tc2 = TrivialCircuit::default();
Expand All @@ -401,7 +402,7 @@ mod tests {
NovaAugmentedCircuit::new(secondary_params, None, &tc2, ro_consts2.clone());
let mut cs: TestShapeCS<G2> = TestShapeCS::new();
let _ = circuit2.synthesize(&mut cs);
let (shape2, ck2) = cs.r1cs_shape();
let (shape2, ck2) = cs.r1cs_shape(&*default_commitment_key_hint());
assert_eq!(cs.num_constraints(), num_constraints_secondary);

// Execute the base case for the primary
Expand Down
4 changes: 4 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use thiserror::Error;

/// Errors returned by Nova
#[derive(Clone, Debug, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum NovaError {
/// returned if the supplied row or col in (row,col,val) tuple is out of range
#[error("InvalidIndex")]
Expand All @@ -26,6 +27,9 @@ pub enum NovaError {
/// returned if proof verification fails
#[error("ProofVerifyError")]
ProofVerifyError,
/// returned if the provided commitment key is not of sufficient length
#[error("InvalidCommitmentKeyLength")]
InvalidCommitmentKeyLength,
/// returned if the provided number of steps is zero
#[error("InvalidNumSteps")]
InvalidNumSteps,
Expand Down
17 changes: 10 additions & 7 deletions src/gadgets/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,14 +748,17 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::bellpepper::{
r1cs::{NovaShape, NovaWitness},
{solver::SatisfyingAssignment, test_shape_cs::TestShapeCS},
};
use crate::provider::{
bn256_grumpkin::{bn256, grumpkin},
secp_secq::{secp256k1, secq256k1},
};
use crate::{
bellpepper::{
r1cs::{NovaShape, NovaWitness},
{solver::SatisfyingAssignment, test_shape_cs::TestShapeCS},
},
traits::snark::default_commitment_key_hint,
};
use ff::{Field, PrimeFieldBits};
use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas, vesta};
use rand::rngs::OsRng;
Expand Down Expand Up @@ -1000,7 +1003,7 @@ mod tests {
let mut cs: TestShapeCS<G2> = TestShapeCS::new();
let _ = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
println!("Number of constraints: {}", cs.num_constraints());
let (shape, ck) = cs.r1cs_shape();
let (shape, ck) = cs.r1cs_shape(&*default_commitment_key_hint());

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down Expand Up @@ -1056,7 +1059,7 @@ mod tests {
let mut cs: TestShapeCS<G2> = TestShapeCS::new();
let _ = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
println!("Number of constraints: {}", cs.num_constraints());
let (shape, ck) = cs.r1cs_shape();
let (shape, ck) = cs.r1cs_shape(&*default_commitment_key_hint());

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down Expand Up @@ -1116,7 +1119,7 @@ mod tests {
let mut cs: TestShapeCS<G2> = TestShapeCS::new();
let _ = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add equal"));
println!("Number of constraints: {}", cs.num_constraints());
let (shape, ck) = cs.r1cs_shape();
let (shape, ck) = cs.r1cs_shape(&*default_commitment_key_hint());

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down
Loading

0 comments on commit ded51b5

Please sign in to comment.