Skip to content

Commit 94e527b

Browse files
committed
feat: Refactor R1CS shape to split the commitment key generation
TL;DR: splits off one major source of diff lines from PR microsoft#283. Inherently, there are many R1CS shapes to consider when tailoring public parameter creation to non-uniform step-circuits. However, the commitment key generation should only be done once for all circuits (once a suitable size has been determined by looking at all R1CS shapes). This splits the relevant Nova functions into `r1cs_shape_and_key`, `r1cs_shape` and `commitment_key` to enable the flexibility deamnded by the above model. In detail: - Renamed the `r1cs_shape` method across various files to `r1cs_shape_and_key`, indicating its functionality is to return both `R1CSShape` and `CommitmentKey`. - Altered function calls from `r1cs_shape` to `r1cs_shape_and_key` in files such as `direct.rs`, `nifs.rs`, `lib.rs` and `circuit.rs`, - Split the creation of `R1CSShape` and `CommitmentKey` into separate functions in the `NovaShape` object in `r1cs.rs` - Removed the `R1CS` struct in `mod.rs` as it only contained a phantom data, with related operations performed elsewhere. - Implemented changes to enhance code readability, including the addition of a new `commitment_key_size` function, and overall code reformatting for clarity.
1 parent fec3e2a commit 94e527b

File tree

8 files changed

+51
-45
lines changed

8 files changed

+51
-45
lines changed

src/bellpepper/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ mod tests {
4545
// First create the shape
4646
let mut cs: ShapeCS<E> = ShapeCS::new();
4747
synthesize_alloc_bit(&mut cs);
48-
let (shape, ck) = cs.r1cs_shape(&*default_ck_hint());
48+
let (shape, ck) = cs.r1cs_shape_and_key(&*default_ck_hint());
4949

5050
// Now get the assignment
5151
let mut cs = SatisfyingAssignment::<E>::new();

src/bellpepper/r1cs.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment, test_shape_cs::TestShapeCS};
66
use crate::{
77
errors::NovaError,
8-
r1cs::{CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix, R1CS},
8+
r1cs::{commitment_key, CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, SparseMatrix},
99
traits::Engine,
1010
CommitmentKey,
1111
};
@@ -27,7 +27,14 @@ pub trait NovaShape<E: Engine> {
2727
/// Return an appropriate `R1CSShape` and `CommitmentKey` structs.
2828
/// A `CommitmentKeyHint` should be provided to help guide the construction of the `CommitmentKey`.
2929
/// This parameter is documented in `r1cs::R1CS::commitment_key`.
30-
fn r1cs_shape(&self, ck_hint: &CommitmentKeyHint<E>) -> (R1CSShape<E>, CommitmentKey<E>);
30+
fn r1cs_shape_and_key(&self, ck_hint: &CommitmentKeyHint<E>) -> (R1CSShape<E>, CommitmentKey<E>) {
31+
let S = self.r1cs_shape();
32+
let ck = commitment_key(&S, ck_hint);
33+
34+
(S, ck)
35+
}
36+
/// Return an appropriate `R1CSShape`.
37+
fn r1cs_shape(&self) -> R1CSShape<E>;
3138
}
3239

3340
impl<E: Engine> NovaWitness<E> for SatisfyingAssignment<E> {
@@ -53,7 +60,7 @@ macro_rules! impl_nova_shape {
5360
where
5461
E::Scalar: PrimeField,
5562
{
56-
fn r1cs_shape(&self, ck_hint: &CommitmentKeyHint<E>) -> (R1CSShape<E>, CommitmentKey<E>) {
63+
fn r1cs_shape(&self) -> R1CSShape<E> {
5764
let mut A = SparseMatrix::<E::Scalar>::empty();
5865
let mut B = SparseMatrix::<E::Scalar>::empty();
5966
let mut C = SparseMatrix::<E::Scalar>::empty();
@@ -80,10 +87,8 @@ macro_rules! impl_nova_shape {
8087
C.cols = num_vars + num_inputs;
8188

8289
// Don't count One as an input for shape's purposes.
83-
let S = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, A, B, C).unwrap();
84-
let ck = R1CS::<E>::commitment_key(&S, ck_hint);
85-
86-
(S, ck)
90+
let res = R1CSShape::new(num_constraints, num_vars, num_inputs - 1, A, B, C);
91+
res.unwrap()
8792
}
8893
}
8994
};

src/circuit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ mod tests {
396396
NovaAugmentedCircuit::new(primary_params, None, &tc1, ro_consts1.clone());
397397
let mut cs: TestShapeCS<E1> = TestShapeCS::new();
398398
let _ = circuit1.synthesize(&mut cs);
399-
let (shape1, ck1) = cs.r1cs_shape(&*default_ck_hint());
399+
let (shape1, ck1) = cs.r1cs_shape_and_key(&*default_ck_hint());
400400
assert_eq!(cs.num_constraints(), num_constraints_primary);
401401

402402
let tc2 = TrivialCircuit::default();
@@ -405,7 +405,7 @@ mod tests {
405405
NovaAugmentedCircuit::new(secondary_params, None, &tc2, ro_consts2.clone());
406406
let mut cs: TestShapeCS<E2> = TestShapeCS::new();
407407
let _ = circuit2.synthesize(&mut cs);
408-
let (shape2, ck2) = cs.r1cs_shape(&*default_ck_hint());
408+
let (shape2, ck2) = cs.r1cs_shape_and_key(&*default_ck_hint());
409409
assert_eq!(cs.num_constraints(), num_constraints_secondary);
410410

411411
// Execute the base case for the primary

src/gadgets/ecc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ mod tests {
10331033
let mut cs: TestShapeCS<E2> = TestShapeCS::new();
10341034
let _ = synthesize_smul::<E1, _>(cs.namespace(|| "synthesize"));
10351035
println!("Number of constraints: {}", cs.num_constraints());
1036-
let (shape, ck) = cs.r1cs_shape(&*default_ck_hint());
1036+
let (shape, ck) = cs.r1cs_shape_and_key(&*default_ck_hint());
10371037

10381038
// Then the satisfying assignment
10391039
let mut cs = SatisfyingAssignment::<E2>::new();
@@ -1089,7 +1089,7 @@ mod tests {
10891089
let mut cs: TestShapeCS<E2> = TestShapeCS::new();
10901090
let _ = synthesize_add_equal::<E1, _>(cs.namespace(|| "synthesize add equal"));
10911091
println!("Number of constraints: {}", cs.num_constraints());
1092-
let (shape, ck) = cs.r1cs_shape(&*default_ck_hint());
1092+
let (shape, ck) = cs.r1cs_shape_and_key(&*default_ck_hint());
10931093

10941094
// Then the satisfying assignment
10951095
let mut cs = SatisfyingAssignment::<E2>::new();
@@ -1149,7 +1149,7 @@ mod tests {
11491149
let mut cs: TestShapeCS<E2> = TestShapeCS::new();
11501150
let _ = synthesize_add_negation::<E1, _>(cs.namespace(|| "synthesize add equal"));
11511151
println!("Number of constraints: {}", cs.num_constraints());
1152-
let (shape, ck) = cs.r1cs_shape(&*default_ck_hint());
1152+
let (shape, ck) = cs.r1cs_shape_and_key(&*default_ck_hint());
11531153

11541154
// Then the satisfying assignment
11551155
let mut cs = SatisfyingAssignment::<E2>::new();

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ where
168168
);
169169
let mut cs: ShapeCS<E1> = ShapeCS::new();
170170
let _ = circuit_primary.synthesize(&mut cs);
171-
let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape(ck_hint1);
171+
let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape_and_key(ck_hint1);
172172

173173
// Initialize ck for the secondary
174174
let circuit_secondary: NovaAugmentedCircuit<'_, E1, C2> = NovaAugmentedCircuit::new(
@@ -179,7 +179,7 @@ where
179179
);
180180
let mut cs: ShapeCS<E2> = ShapeCS::new();
181181
let _ = circuit_secondary.synthesize(&mut cs);
182-
let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape(ck_hint2);
182+
let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(ck_hint2);
183183

184184
if r1cs_shape_primary.num_io != 2 || r1cs_shape_secondary.num_io != 2 {
185185
return Err(NovaError::InvalidStepCircuitIO);

src/nifs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ mod tests {
124124
test_shape_cs::TestShapeCS,
125125
},
126126
provider::{Bn256EngineKZG, PallasEngine, Secp256k1Engine},
127-
r1cs::{SparseMatrix, R1CS},
127+
r1cs::{commitment_key, SparseMatrix},
128128
traits::{snark::default_ck_hint, Engine},
129129
};
130130
use ::bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
@@ -168,7 +168,7 @@ mod tests {
168168
// First create the shape
169169
let mut cs: TestShapeCS<E> = TestShapeCS::new();
170170
let _ = synthesize_tiny_r1cs_bellpepper(&mut cs, None);
171-
let (shape, ck) = cs.r1cs_shape(&*default_ck_hint());
171+
let (shape, ck) = cs.r1cs_shape_and_key(&*default_ck_hint());
172172
let ro_consts =
173173
<<E as Engine>::RO as ROTrait<<E as Engine>::Base, <E as Engine>::Scalar>>::Constants::default();
174174

@@ -327,7 +327,7 @@ mod tests {
327327
};
328328

329329
// generate generators and ro constants
330-
let ck = R1CS::<E>::commitment_key(&S, &*default_ck_hint());
330+
let ck = commitment_key(&S, &*default_ck_hint());
331331
let ro_consts =
332332
<<E as Engine>::RO as ROTrait<<E as Engine>::Base, <E as Engine>::Scalar>>::Constants::default();
333333

src/r1cs/mod.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
},
1313
Commitment, CommitmentKey, CE,
1414
};
15-
use core::{cmp::max, marker::PhantomData};
15+
use core::cmp::max;
1616
use ff::Field;
1717
use once_cell::sync::OnceCell;
1818

@@ -22,13 +22,6 @@ use serde::{Deserialize, Serialize};
2222
mod sparse;
2323
pub(crate) use sparse::SparseMatrix;
2424

25-
/// Public parameters for a given R1CS
26-
#[derive(Clone, Serialize, Deserialize)]
27-
#[serde(bound = "")]
28-
pub struct R1CS<E: Engine> {
29-
_p: PhantomData<E>,
30-
}
31-
3225
/// A type that holds the shape of the R1CS matrices
3326
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
3427
pub struct R1CSShape<E: Engine> {
@@ -77,24 +70,31 @@ pub struct RelaxedR1CSInstance<E: Engine> {
7770

7871
pub type CommitmentKeyHint<E> = dyn Fn(&R1CSShape<E>) -> usize;
7972

80-
impl<E: Engine> R1CS<E> {
81-
/// Generates public parameters for a Rank-1 Constraint System (R1CS).
82-
///
83-
/// This function takes into consideration the shape of the R1CS matrices and a hint function
84-
/// for the number of generators. It returns a `CommitmentKey`.
85-
///
86-
/// # Arguments
87-
///
88-
/// * `S`: The shape of the R1CS matrices.
89-
/// * `ck_floor`: A function that provides a floor for the number of generators. A good function
90-
/// to provide is the ck_floor field defined in the trait `RelaxedR1CSSNARKTrait`.
91-
///
92-
pub fn commitment_key(S: &R1CSShape<E>, ck_floor: &CommitmentKeyHint<E>) -> CommitmentKey<E> {
93-
let num_cons = S.num_cons;
94-
let num_vars = S.num_vars;
95-
let ck_hint = ck_floor(S);
96-
E::CE::setup(b"ck", max(max(num_cons, num_vars), ck_hint))
97-
}
73+
/// Generates public parameters for a Rank-1 Constraint System (R1CS).
74+
///
75+
/// This function takes into consideration the shape of the R1CS matrices and a hint function
76+
/// for the number of generators. It returns a `CommitmentKey`.
77+
///
78+
/// # Arguments
79+
///
80+
/// * `S`: The shape of the R1CS matrices.
81+
/// * `ck_floor`: A function that provides a floor for the number of generators. A good function
82+
/// to provide is the ck_floor field defined in the trait `RelaxedR1CSSNARKTrait`.
83+
///
84+
pub fn commitment_key<E: Engine>(
85+
S: &R1CSShape<E>,
86+
ck_floor: &CommitmentKeyHint<E>,
87+
) -> CommitmentKey<E> {
88+
let size = commitment_key_size(S, ck_floor);
89+
E::CE::setup(b"ck", size)
90+
}
91+
92+
/// Computes the number of generators required for the commitment key corresponding to shape `S`.
93+
fn commitment_key_size<E: Engine>(S: &R1CSShape<E>, ck_floor: &CommitmentKeyHint<E>) -> usize {
94+
let num_cons = S.num_cons;
95+
let num_vars = S.num_vars;
96+
let ck_hint = ck_floor(S);
97+
max(max(num_cons, num_vars), ck_hint)
9898
}
9999

100100
impl<E: Engine> R1CSShape<E> {
@@ -157,6 +157,7 @@ impl<E: Engine> R1CSShape<E> {
157157
cons_valid && vars_valid && io_lt_vars
158158
}
159159

160+
/// multiplies a vector with the matrix
160161
pub fn multiply_vec(
161162
&self,
162163
z: &[E::Scalar],

src/spartan/direct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<E: Engine, S: RelaxedR1CSSNARKTrait<E>, C: StepCircuit<E::Scalar>> DirectSN
109109
let mut cs: ShapeCS<E> = ShapeCS::new();
110110
let _ = circuit.synthesize(&mut cs);
111111

112-
let (shape, ck) = cs.r1cs_shape(&*S::ck_floor());
112+
let (shape, ck) = cs.r1cs_shape_and_key(&*S::ck_floor());
113113

114114
let (pk, vk) = S::setup(&ck, &shape)?;
115115

0 commit comments

Comments
 (0)