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 (#5)

* 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>;
- 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
  • Loading branch information
huitseeker authored Aug 19, 2023
1 parent 9d7aedd commit 46b0ba9
Show file tree
Hide file tree
Showing 21 changed files with 213 additions and 55 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, TrivialTestCircuit},
snark::RelaxedR1CSSNARKTrait,
Group,
},
CompressedSNARK, PublicParams, RecursiveSNARK,
Expand Down Expand Up @@ -65,7 +66,12 @@ fn bench_compressed_snark(c: &mut Criterion) {
let c_secondary = TrivialTestCircuit::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,
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();
Expand Down Expand Up @@ -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::<G1, G2, C1, C2>::setup(&c_primary, &c_secondary);

let pp = PublicParams::<G1, G2, C1, C2>::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();

Expand Down
7 changes: 6 additions & 1 deletion benches/compute-digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,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(None),
black_box(None),
)
})
});
}
Expand Down
8 changes: 4 additions & 4 deletions benches/recursive-snark-supernova.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion benches/recursive-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn bench_recursive_snark(c: &mut Criterion) {
let c_secondary = TrivialTestCircuit::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, None, None);

// Bench time to produce a recursive SNARK;
// we execute a certain number of warm-up steps since executing
Expand Down
2 changes: 1 addition & 1 deletion benches/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ fn bench_recursive_snark(c: &mut Criterion) {

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

let circuit_secondary = TrivialTestCircuit::default();
let z0_primary = vec![<G1 as Group>::Scalar::from(2u64)];
Expand Down
2 changes: 1 addition & 1 deletion examples/minroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn main() {
G2,
MinRootCircuit<<G1 as Group>::Scalar>,
TrivialTestCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);
println!("PublicParams::setup, took {:?} ", start.elapsed());

println!(
Expand Down
4 changes: 2 additions & 2 deletions examples/minroot_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ fn main() {
G2,
MinRootCircuit<<G1 as Group>::Scalar>,
TrivialTestCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);
println!("PublicParams::setup, took {:?} ", start.elapsed());
encode(&pp, &mut file).unwrap()
};
Expand All @@ -193,7 +193,7 @@ fn main() {
G2,
MinRootCircuit<<G1 as Group>::Scalar>,
TrivialTestCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);
assert!(result.clone() == pp, "not equal!");
assert!(remaining.is_empty());
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/bellpepper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ mod tests {
// First create the shape
let mut cs: ShapeCS<G> = 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<G> = SatisfyingAssignment::new();
Expand Down
12 changes: 9 additions & 3 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, R1CS},
r1cs::{CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, R1CS},
traits::Group,
CommitmentKey,
};
Expand All @@ -25,9 +25,15 @@ 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_and_key(&self) -> (R1CSShape<G>, CommitmentKey<G>) {
/// 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<CommitmentKeyHint<G>>,
) -> (R1CSShape<G>, CommitmentKey<G>) {
let S = self.r1cs_shape();
let ck = R1CS::<G>::commitment_key(&S);
let ck = R1CS::<G>::commitment_key(&S, optfn);

(S, ck)
}
Expand Down
4 changes: 2 additions & 2 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ mod tests {
NovaAugmentedCircuit::new(primary_params, None, &ttc1, ro_consts1.clone());
let mut cs: TestShapeCS<G1> = 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();
Expand All @@ -409,7 +409,7 @@ mod tests {
NovaAugmentedCircuit::new(secondary_params, None, &ttc2, ro_consts2.clone());
let mut cs: TestShapeCS<G2> = 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
Expand Down
6 changes: 3 additions & 3 deletions src/gadgets/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,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_and_key();
let (shape, ck) = cs.r1cs_shape_and_key(None);

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down Expand Up @@ -1045,7 +1045,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_and_key();
let (shape, ck) = cs.r1cs_shape_and_key(None);

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down Expand Up @@ -1102,7 +1102,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_and_key();
let (shape, ck) = cs.r1cs_shape_and_key(None);

// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
Expand Down
85 changes: 72 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -96,8 +98,53 @@ where
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
{
/// 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<G1> = EvaluationEngine<G1>;
/// type EE2<G2> = EvaluationEngine<G2>;
/// type S1Prime<G1> = RelaxedR1CSSNARK<G1, EE1<G1>>;
/// type S2Prime<G2> = RelaxedR1CSSNARK<G2, EE2<G2>>;
///
/// let circuit1 = TrivialTestCircuit::<<G1 as Group>::Scalar>::default();
/// let circuit2 = TrivialTestCircuit::<<G2 as Group>::Scalar>::default();
/// // Only relevant for a SNARK using computational commitments, pass None otherwise.
/// let pp_hint1 = Some(S1Prime::<G1>::commitment_key_floor());
/// let pp_hint2 = Some(S2Prime::<G2>::commitment_key_floor());
///
/// let pp = PublicParams::setup(&circuit1, &circuit2, pp_hint1, pp_hint2);
/// ```
pub fn setup(
c_primary: &C1,
c_secondary: &C2,
optfn1: Option<CommitmentKeyHint<G1>>,
optfn2: Option<CommitmentKeyHint<G2>>,
) -> Self {
let augmented_circuit_params_primary =
NovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, true);
let augmented_circuit_params_secondary =
Expand All @@ -122,7 +169,7 @@ where
);
let mut cs: ShapeCS<G1> = 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(
Expand All @@ -133,7 +180,7 @@ where
);
let mut cs: ShapeCS<G2> = 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,
Expand Down Expand Up @@ -922,8 +969,15 @@ mod tests {
G2: Group<Base = <G1 as Group>::Scalar>,
T1: StepCircuit<G1::Scalar>,
T2: StepCircuit<G2::Scalar>,
<G1::CE as CommitmentEngineTrait<G1>>::CommitmentKey: CommitmentKeyExtTrait<G1>,
<G2::CE as CommitmentEngineTrait<G2>>::CommitmentKey: CommitmentKeyExtTrait<G2>,
<G1::Scalar as PrimeField>::Repr: Abomonation,
<G2::Scalar as PrimeField>::Repr: Abomonation,
{
let pp = PublicParams::<G1, G2, T1, T2>::setup(circuit1, circuit2);
// this tests public parameters with a size specifically intended for a spark-compressed SNARK
let pp_hint1 = Some(S1Prime::<G1>::commitment_key_floor());
let pp_hint2 = Some(S2Prime::<G2>::commitment_key_floor());
let pp = PublicParams::<G1, G2, T1, T2>::setup(circuit1, circuit2, pp_hint1, pp_hint2);

let digest_str = pp
.digest
Expand Down Expand Up @@ -987,7 +1041,7 @@ mod tests {
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
TrivialTestCircuit<<G2 as Group>::Scalar>,
>::setup(&test_circuit1, &test_circuit2);
>::setup(&test_circuit1, &test_circuit2, None, None);

let num_steps = 1;

Expand Down Expand Up @@ -1043,7 +1097,7 @@ mod tests {
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);

let num_steps = 3;

Expand Down Expand Up @@ -1131,7 +1185,7 @@ mod tests {
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);

let num_steps = 3;

Expand Down Expand Up @@ -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<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::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;

Expand Down Expand Up @@ -1389,7 +1448,7 @@ mod tests {
G2,
FifthRootCheckingCircuit<<G1 as Group>::Scalar>,
TrivialTestCircuit<<G2 as Group>::Scalar>,
>::setup(&circuit_primary, &circuit_secondary);
>::setup(&circuit_primary, &circuit_secondary, None, None);

let num_steps = 3;

Expand Down Expand Up @@ -1467,7 +1526,7 @@ mod tests {
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::Scalar>,
>::setup(&test_circuit1, &test_circuit2);
>::setup(&test_circuit1, &test_circuit2, None, None);

let num_steps = 1;

Expand Down
4 changes: 2 additions & 2 deletions src/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ mod tests {
// First create the shape
let mut cs: TestShapeCS<G> = 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 =
<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new();

Expand Down Expand Up @@ -326,7 +326,7 @@ mod tests {
};

// generate generators and ro constants
let ck = R1CS::<G>::commitment_key(&S);
let ck = R1CS::<G>::commitment_key(&S, None);
let ro_consts =
<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new();

Expand Down
Loading

0 comments on commit 46b0ba9

Please sign in to comment.