Skip to content

Commit fe71f06

Browse files
authored
r1cs: provide BP generators later in the proving/verifying workflow (#257)
This change allows users to provide Bulletproofs generators closer to the point where they are needed. This allows a prover, for instance, to know exactly how many multipliers were allocated to prepare a necessary number of generators, and also specify this number in the envelope that holds the proof. Verifier then also has an option to generate a necessary amount of generators based on actual usage, or preallocate as many as specified in the envelope (if not determined by some other factors). For the verifier, the same thing is done for PedersenGens: since it does not create commitments, but only verifies them. ```rust let p = Prover::new(&pc_gens, transcript); ... let proof = p.prove(&bp_gens)?; ``` ```rust let v = Verifier::new(transcript); ... v.verify(proof, &pc_gens, &bp_gens)?; ```
1 parent 20f2749 commit fe71f06

File tree

5 files changed

+69
-79
lines changed

5 files changed

+69
-79
lines changed

benches/r1cs.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ impl KShuffleGadget {
139139
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
140140
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
141141

142-
let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);
142+
let mut prover = Prover::new(&pc_gens, transcript);
143143

144144
// Construct blinding factors using an RNG.
145145
// Note: a non-example implementation would want to operate on existing commitments.
@@ -156,7 +156,7 @@ impl KShuffleGadget {
156156
.unzip();
157157

158158
Self::fill_cs(&mut prover, input_vars, output_vars)?;
159-
let proof = prover.prove()?;
159+
let proof = prover.prove(&bp_gens)?;
160160

161161
Ok((proof, input_commitments, output_commitments))
162162
}
@@ -174,7 +174,7 @@ impl KShuffleGadget {
174174
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
175175
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
176176

177-
let mut verifier = Verifier::new(&bp_gens, &pc_gens, transcript);
177+
let mut verifier = Verifier::new(transcript);
178178

179179
let input_vars: Vec<_> = input_commitments
180180
.iter()
@@ -187,7 +187,7 @@ impl KShuffleGadget {
187187
.collect();
188188

189189
Self::fill_cs(&mut verifier, input_vars, output_vars)?;
190-
verifier.verify(proof)
190+
verifier.verify(proof, &pc_gens, &bp_gens)
191191
}
192192
}
193193

docs/r1cs-docs-example.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl ShuffleProof {
212212
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
213213
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
214214

215-
let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);
215+
let mut prover = Prover::new(&pc_gens, transcript);
216216

217217
// Construct blinding factors using an RNG.
218218
// Note: a non-example implementation would want to operate on existing commitments.
@@ -232,7 +232,7 @@ impl ShuffleProof {
232232

233233
ShuffleProof::gadget(&mut prover, input_vars, output_vars)?;
234234

235-
let proof = prover.prove()?;
235+
let proof = prover.prove(&bp_gens)?;
236236

237237
Ok((ShuffleProof(proof), input_commitments, output_commitments))
238238
}
@@ -319,7 +319,7 @@ The verifier receives a proof, and a list of committed inputs and outputs, from
319319
# transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
320320
# transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
321321
#
322-
# let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);
322+
# let mut prover = Prover::new(&pc_gens, transcript);
323323
#
324324
# // Construct blinding factors using an RNG.
325325
# // Note: a non-example implementation would want to operate on existing commitments.
@@ -339,7 +339,7 @@ The verifier receives a proof, and a list of committed inputs and outputs, from
339339
#
340340
# ShuffleProof::gadget(&mut prover, input_vars, output_vars)?;
341341
#
342-
# let proof = prover.prove()?;
342+
# let proof = prover.prove(&bp_gens)?;
343343
#
344344
# Ok((ShuffleProof(proof), input_commitments, output_commitments))
345345
# }
@@ -359,7 +359,7 @@ impl ShuffleProof {
359359
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
360360
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
361361

362-
let mut verifier = Verifier::new(&bp_gens, &pc_gens, transcript);
362+
let mut verifier = Verifier::new(transcript);
363363

364364
let input_vars: Vec<_> = input_commitments.iter().map(|commitment| {
365365
verifier.commit(*commitment)
@@ -371,7 +371,7 @@ impl ShuffleProof {
371371

372372
ShuffleProof::gadget(&mut verifier, input_vars, output_vars)?;
373373

374-
verifier.verify(&self.0)
374+
verifier.verify(&self.0, &pc_gens, &bp_gens)
375375
}
376376
}
377377
```
@@ -459,7 +459,7 @@ Because only the prover knows the scalar values of the inputs and outputs, and t
459459
# transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
460460
# transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
461461
#
462-
# let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);
462+
# let mut prover = Prover::new(&pc_gens, transcript);
463463
#
464464
# // Construct blinding factors using an RNG.
465465
# // Note: a non-example implementation would want to operate on existing commitments.
@@ -479,7 +479,7 @@ Because only the prover knows the scalar values of the inputs and outputs, and t
479479
#
480480
# ShuffleProof::gadget(&mut prover, input_vars, output_vars)?;
481481
#
482-
# let proof = prover.prove()?;
482+
# let proof = prover.prove(&bp_gens)?;
483483
#
484484
# Ok((ShuffleProof(proof), input_commitments, output_commitments))
485485
# }
@@ -499,7 +499,7 @@ Because only the prover knows the scalar values of the inputs and outputs, and t
499499
# transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
500500
# transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
501501
#
502-
# let mut verifier = Verifier::new(&bp_gens, &pc_gens, transcript);
502+
# let mut verifier = Verifier::new(transcript);
503503
#
504504
# let input_vars: Vec<_> = input_commitments.iter().map(|commitment| {
505505
# verifier.commit(*commitment)
@@ -511,7 +511,7 @@ Because only the prover knows the scalar values of the inputs and outputs, and t
511511
#
512512
# ShuffleProof::gadget(&mut verifier, input_vars, output_vars)?;
513513
#
514-
# verifier.verify(&self.0)
514+
# verifier.verify(&self.0, &pc_gens, &bp_gens)
515515
# }
516516
# }
517517
# fn main() {

src/r1cs/prover.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ use transcript::TranscriptProtocol;
2323
/// When all constraints are added, the proving code calls `prove`
2424
/// which consumes the `Prover` instance, samples random challenges
2525
/// that instantiate the randomized constraints, and creates a complete proof.
26-
pub struct Prover<'a, 'b> {
27-
transcript: &'a mut Transcript,
28-
bp_gens: &'b BulletproofGens,
29-
pc_gens: &'b PedersenGens,
26+
pub struct Prover<'t, 'g> {
27+
transcript: &'t mut Transcript,
28+
pc_gens: &'g PedersenGens,
3029
/// The constraints accumulated so far.
3130
constraints: Vec<LinearCombination>,
3231
/// Stores assignments to the "left" of multiplication gates
@@ -42,7 +41,7 @@ pub struct Prover<'a, 'b> {
4241

4342
/// This list holds closures that will be called in the second phase of the protocol,
4443
/// when non-randomized variables are committed.
45-
deferred_constraints: Vec<Box<Fn(&mut RandomizingProver<'a, 'b>) -> Result<(), R1CSError>>>,
44+
deferred_constraints: Vec<Box<Fn(&mut RandomizingProver<'t, 'g>) -> Result<(), R1CSError>>>,
4645

4746
/// Index of a pending multiplier that's not fully assigned yet.
4847
pending_multiplier: Option<usize>,
@@ -55,12 +54,12 @@ pub struct Prover<'a, 'b> {
5554
/// monomorphize the closures for the proving and verifying code.
5655
/// However, this type cannot be instantiated by the user and therefore can only be used within
5756
/// the callback provided to `specify_randomized_constraints`.
58-
pub struct RandomizingProver<'a, 'b> {
59-
prover: Prover<'a, 'b>,
57+
pub struct RandomizingProver<'t, 'g> {
58+
prover: Prover<'t, 'g>,
6059
}
6160

6261
/// Overwrite secrets with null bytes when they go out of scope.
63-
impl<'a, 'b> Drop for Prover<'a, 'b> {
62+
impl<'t, 'g> Drop for Prover<'t, 'g> {
6463
fn drop(&mut self) {
6564
self.v.clear();
6665
self.v_blinding.clear();
@@ -83,8 +82,8 @@ impl<'a, 'b> Drop for Prover<'a, 'b> {
8382
}
8483
}
8584

86-
impl<'a, 'b> ConstraintSystem for Prover<'a, 'b> {
87-
type RandomizedCS = RandomizingProver<'a, 'b>;
85+
impl<'t, 'g> ConstraintSystem for Prover<'t, 'g> {
86+
type RandomizedCS = RandomizingProver<'t, 'g>;
8887

8988
fn multiply(
9089
&mut self,
@@ -169,7 +168,7 @@ impl<'a, 'b> ConstraintSystem for Prover<'a, 'b> {
169168
}
170169
}
171170

172-
impl<'a, 'b> ConstraintSystem for RandomizingProver<'a, 'b> {
171+
impl<'t, 'g> ConstraintSystem for RandomizingProver<'t, 'g> {
173172
type RandomizedCS = Self;
174173

175174
fn multiply(
@@ -203,13 +202,13 @@ impl<'a, 'b> ConstraintSystem for RandomizingProver<'a, 'b> {
203202
}
204203
}
205204

206-
impl<'a, 'b> RandomizedConstraintSystem for RandomizingProver<'a, 'b> {
205+
impl<'t, 'g> RandomizedConstraintSystem for RandomizingProver<'t, 'g> {
207206
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
208207
self.prover.transcript.challenge_scalar(label)
209208
}
210209
}
211210

212-
impl<'a, 'b> Prover<'a, 'b> {
211+
impl<'t, 'g> Prover<'t, 'g> {
213212
/// Construct an empty constraint system with specified external
214213
/// input variables.
215214
///
@@ -230,16 +229,11 @@ impl<'a, 'b> Prover<'a, 'b> {
230229
/// # Returns
231230
///
232231
/// Returns a new `Prover` instance.
233-
pub fn new(
234-
bp_gens: &'b BulletproofGens,
235-
pc_gens: &'b PedersenGens,
236-
transcript: &'a mut Transcript,
237-
) -> Self {
232+
pub fn new(pc_gens: &'g PedersenGens, transcript: &'t mut Transcript) -> Self {
238233
transcript.r1cs_domain_sep();
239234

240235
Prover {
241236
pc_gens,
242-
bp_gens,
243237
transcript,
244238
v: Vec::new(),
245239
v_blinding: Vec::new(),
@@ -365,7 +359,7 @@ impl<'a, 'b> Prover<'a, 'b> {
365359
}
366360

367361
/// Consume this `ConstraintSystem` to produce a proof.
368-
pub fn prove(mut self) -> Result<R1CSProof, R1CSError> {
362+
pub fn prove(mut self, bp_gens: &BulletproofGens) -> Result<R1CSProof, R1CSError> {
369363
use std::iter;
370364
use util;
371365

@@ -403,12 +397,12 @@ impl<'a, 'b> Prover<'a, 'b> {
403397
// Commit to the first-phase low-level witness variables.
404398
let n1 = self.a_L.len();
405399

406-
if self.bp_gens.gens_capacity < n1 {
400+
if bp_gens.gens_capacity < n1 {
407401
return Err(R1CSError::InvalidGeneratorsLength);
408402
}
409403

410404
// We are performing a single-party circuit proof, so party index is 0.
411-
let gens = self.bp_gens.share(0);
405+
let gens = bp_gens.share(0);
412406

413407
let i_blinding1 = Scalar::random(&mut rng);
414408
let o_blinding1 = Scalar::random(&mut rng);
@@ -461,7 +455,7 @@ impl<'a, 'b> Prover<'a, 'b> {
461455
let padded_n = self.a_L.len().next_power_of_two();
462456
let pad = padded_n - n;
463457

464-
if self.bp_gens.gens_capacity < padded_n {
458+
if bp_gens.gens_capacity < padded_n {
465459
return Err(R1CSError::InvalidGeneratorsLength);
466460
}
467461

src/r1cs/verifier.rs

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ use transcript::TranscriptProtocol;
2121
/// When all constraints are added, the verifying code calls `verify`
2222
/// which consumes the `Verifier` instance, samples random challenges
2323
/// that instantiate the randomized constraints, and verifies the proof.
24-
pub struct Verifier<'a, 'b> {
25-
bp_gens: &'b BulletproofGens,
26-
pc_gens: &'b PedersenGens,
27-
transcript: &'a mut Transcript,
24+
pub struct Verifier<'t> {
25+
transcript: &'t mut Transcript,
2826
constraints: Vec<LinearCombination>,
2927

3028
/// Records the number of low-level variables allocated in the
@@ -41,7 +39,7 @@ pub struct Verifier<'a, 'b> {
4139
/// when non-randomized variables are committed.
4240
/// After that, the option will flip to None and additional calls to `randomize_constraints`
4341
/// will invoke closures immediately.
44-
deferred_constraints: Vec<Box<Fn(&mut RandomizingVerifier<'a, 'b>) -> Result<(), R1CSError>>>,
42+
deferred_constraints: Vec<Box<Fn(&mut RandomizingVerifier<'t>) -> Result<(), R1CSError>>>,
4543

4644
/// Index of a pending multiplier that's not fully assigned yet.
4745
pending_multiplier: Option<usize>,
@@ -54,12 +52,12 @@ pub struct Verifier<'a, 'b> {
5452
/// monomorphize the closures for the proving and verifying code.
5553
/// However, this type cannot be instantiated by the user and therefore can only be used within
5654
/// the callback provided to `specify_randomized_constraints`.
57-
pub struct RandomizingVerifier<'a, 'b> {
58-
verifier: Verifier<'a, 'b>,
55+
pub struct RandomizingVerifier<'t> {
56+
verifier: Verifier<'t>,
5957
}
6058

61-
impl<'a, 'b> ConstraintSystem for Verifier<'a, 'b> {
62-
type RandomizedCS = RandomizingVerifier<'a, 'b>;
59+
impl<'t> ConstraintSystem for Verifier<'t> {
60+
type RandomizedCS = RandomizingVerifier<'t>;
6361

6462
fn multiply(
6563
&mut self,
@@ -129,7 +127,7 @@ impl<'a, 'b> ConstraintSystem for Verifier<'a, 'b> {
129127
}
130128
}
131129

132-
impl<'a, 'b> ConstraintSystem for RandomizingVerifier<'a, 'b> {
130+
impl<'t> ConstraintSystem for RandomizingVerifier<'t> {
133131
type RandomizedCS = Self;
134132

135133
fn multiply(
@@ -163,24 +161,18 @@ impl<'a, 'b> ConstraintSystem for RandomizingVerifier<'a, 'b> {
163161
}
164162
}
165163

166-
impl<'a, 'b> RandomizedConstraintSystem for RandomizingVerifier<'a, 'b> {
164+
impl<'t> RandomizedConstraintSystem for RandomizingVerifier<'t> {
167165
fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
168166
self.verifier.transcript.challenge_scalar(label)
169167
}
170168
}
171169

172-
impl<'a, 'b> Verifier<'a, 'b> {
170+
impl<'t> Verifier<'t> {
173171
/// Construct an empty constraint system with specified external
174172
/// input variables.
175173
///
176174
/// # Inputs
177175
///
178-
/// The `bp_gens` and `pc_gens` are generators for Bulletproofs
179-
/// and for the Pedersen commitments, respectively. The
180-
/// [`BulletproofGens`] should have `gens_capacity` greater than
181-
/// the number of multiplication constraints that will eventually
182-
/// be added into the constraint system.
183-
///
184176
/// The `transcript` parameter is a Merlin proof transcript. The
185177
/// `VerifierCS` holds onto the `&mut Transcript` until it consumes
186178
/// itself during [`VerifierCS::verify`], releasing its borrow of the
@@ -201,16 +193,10 @@ impl<'a, 'b> Verifier<'a, 'b> {
201193
///
202194
/// The second element is a list of [`Variable`]s corresponding to
203195
/// the external inputs, which can be used to form constraints.
204-
pub fn new(
205-
bp_gens: &'b BulletproofGens,
206-
pc_gens: &'b PedersenGens,
207-
transcript: &'a mut Transcript,
208-
) -> Self {
196+
pub fn new(transcript: &'t mut Transcript) -> Self {
209197
transcript.r1cs_domain_sep();
210198

211199
Verifier {
212-
bp_gens,
213-
pc_gens,
214200
transcript,
215201
num_vars: 0,
216202
V: Vec::new(),
@@ -317,7 +303,17 @@ impl<'a, 'b> Verifier<'a, 'b> {
317303
}
318304

319305
/// Consume this `VerifierCS` and attempt to verify the supplied `proof`.
320-
pub fn verify(mut self, proof: &R1CSProof) -> Result<(), R1CSError> {
306+
/// The `pc_gens` and `bp_gens` are generators for Pedersen commitments and
307+
/// Bulletproofs vector commitments, respectively. The
308+
/// [`BulletproofGens`] should have `gens_capacity` greater than
309+
/// the number of multiplication constraints that will eventually
310+
/// be added into the constraint system.
311+
pub fn verify(
312+
mut self,
313+
proof: &R1CSProof,
314+
pc_gens: &PedersenGens,
315+
bp_gens: &BulletproofGens,
316+
) -> Result<(), R1CSError> {
321317
// Commit a length _suffix_ for the number of high-level variables.
322318
// We cannot do this in advance because user can commit variables one-by-one,
323319
// but this suffix provides safe disambiguation because each variable
@@ -342,11 +338,11 @@ impl<'a, 'b> Verifier<'a, 'b> {
342338
use std::iter;
343339
use util;
344340

345-
if self.bp_gens.gens_capacity < padded_n {
341+
if bp_gens.gens_capacity < padded_n {
346342
return Err(R1CSError::InvalidGeneratorsLength);
347343
}
348344
// We are performing a single-party circuit proof, so party index is 0.
349-
let gens = self.bp_gens.share(0);
345+
let gens = bp_gens.share(0);
350346

351347
self.transcript.commit_point(b"A_I2", &proof.A_I2);
352348
self.transcript.commit_point(b"A_O2", &proof.A_O2);
@@ -458,8 +454,8 @@ impl<'a, 'b> Verifier<'a, 'b> {
458454
.chain(iter::once(proof.S2.decompress()))
459455
.chain(self.V.iter().map(|V_i| V_i.decompress()))
460456
.chain(T_points.iter().map(|T_i| T_i.decompress()))
461-
.chain(iter::once(Some(self.pc_gens.B)))
462-
.chain(iter::once(Some(self.pc_gens.B_blinding)))
457+
.chain(iter::once(Some(pc_gens.B)))
458+
.chain(iter::once(Some(pc_gens.B_blinding)))
463459
.chain(gens.G(padded_n).map(|&G_i| Some(G_i)))
464460
.chain(gens.H(padded_n).map(|&H_i| Some(H_i)))
465461
.chain(proof.ipp_proof.L_vec.iter().map(|L_i| L_i.decompress()))

0 commit comments

Comments
 (0)