Skip to content

Commit 80ecce4

Browse files
authored
Allow committing high-level variables one-by-one (#221)
Addresses #218. The API entry points are now `Prover` and `Verifier` types that let you commit high-level variables individually, so that one can organize resulting variables in the way matching the outer protocol (e.g. in tuples). After all high-level variables are committed, user calls `finalize_inputs` which consumes `Prover/Verifier` and returns `ProverCS/VerifierCS`. After that point, no more input variables can be committed. The user fills in the CS instance using gadgets (allocates variables, adds constraints). Finally, the user calls `cs.{prove,verify}` to create or verify the proof, accordingly.
1 parent bf4568b commit 80ecce4

File tree

7 files changed

+396
-312
lines changed

7 files changed

+396
-312
lines changed

benches/r1cs.rs

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
extern crate bulletproofs;
2-
use bulletproofs::r1cs::{ConstraintSystem, ProverCS, R1CSError, R1CSProof, Variable, VerifierCS};
2+
use bulletproofs::r1cs::{ConstraintSystem, Prover, R1CSError, R1CSProof, Variable, Verifier};
33
use bulletproofs::{BulletproofGens, PedersenGens};
44

55
#[macro_use]
@@ -115,57 +115,74 @@ impl KShuffleGadget {
115115
transcript: &'a mut Transcript,
116116
input: &[Scalar],
117117
output: &[Scalar],
118-
) -> Result<(R1CSProof, Vec<CompressedRistretto>), R1CSError> {
118+
) -> Result<
119+
(
120+
R1CSProof,
121+
Vec<CompressedRistretto>,
122+
Vec<CompressedRistretto>,
123+
),
124+
R1CSError,
125+
> {
126+
// Apply a domain separator with the shuffle parameters to the transcript
119127
let k = input.len();
128+
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
129+
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
120130

121-
// Prover makes a `ConstraintSystem` instance representing a shuffle gadget
122-
// Make v vector
123-
let mut v = Vec::with_capacity(2 * k);
124-
v.extend_from_slice(input);
125-
v.extend_from_slice(output);
126-
127-
// Make v_blinding vector using RNG from transcript
128-
let mut rng = {
129-
let mut builder = transcript.build_rng();
130-
// commit the secret values
131-
for &v_i in &v {
132-
builder = builder.commit_witness_bytes(b"v_i", v_i.as_bytes());
133-
}
134-
use rand::thread_rng;
135-
builder.finalize(&mut thread_rng())
136-
};
137-
let v_blinding: Vec<Scalar> = (0..2 * k).map(|_| Scalar::random(&mut rng)).collect();
138-
let (mut prover_cs, variables, commitments) =
139-
ProverCS::new(&bp_gens, &pc_gens, transcript, v, v_blinding.clone());
140-
141-
// Prover allocates variables and adds constraints to the constraint system
142-
let (input_vars, output_vars) = variables.split_at(k);
143-
KShuffleGadget::fill_cs(&mut prover_cs, input_vars, output_vars);
144-
145-
// Prover generates proof
146-
let proof = prover_cs.prove()?;
147-
Ok((proof, commitments))
131+
let mut prover = Prover::new(&bp_gens, &pc_gens, transcript);
132+
133+
// Construct blinding factors using an RNG.
134+
// Note: a non-example implementation would want to operate on existing commitments.
135+
let mut blinding_rng = rand::thread_rng();
136+
137+
let (input_commitments, input_vars): (Vec<_>, Vec<_>) = input
138+
.into_iter()
139+
.map(|v| prover.commit(*v, Scalar::random(&mut blinding_rng)))
140+
.unzip();
141+
142+
let (output_commitments, output_vars): (Vec<_>, Vec<_>) = output
143+
.into_iter()
144+
.map(|v| prover.commit(*v, Scalar::random(&mut blinding_rng)))
145+
.unzip();
146+
147+
let cs = prover.finalize_inputs();
148+
149+
Self::fill_cs(&mut cs, &input_vars, &output_vars);
150+
151+
let proof = cs.prove()?;
152+
153+
Ok((proof, input_commitments, output_commitments))
148154
}
149155

150156
pub fn verify<'a, 'b>(
151157
pc_gens: &'b PedersenGens,
152158
bp_gens: &'b BulletproofGens,
153159
transcript: &'a mut Transcript,
154160
proof: &R1CSProof,
155-
commitments: &Vec<CompressedRistretto>,
161+
input_commitments: &Vec<CompressedRistretto>,
162+
output_commitments: &Vec<CompressedRistretto>,
156163
) -> Result<(), R1CSError> {
157-
let k = commitments.len() / 2;
164+
// Apply a domain separator with the shuffle parameters to the transcript
165+
let k = input_commitments.len();
166+
transcript.commit_bytes(b"dom-sep", b"ShuffleProof");
167+
transcript.commit_bytes(b"k", Scalar::from(k as u64).as_bytes());
168+
169+
let mut verifier = Verifier::new(&bp_gens, &pc_gens, transcript);
170+
171+
let input_vars: Vec<_> = input_commitments
172+
.iter()
173+
.map(|commitment| verifier.commit(*commitment))
174+
.collect();
175+
176+
let output_vars: Vec<_> = output_commitments
177+
.iter()
178+
.map(|commitment| verifier.commit(*commitment))
179+
.collect();
158180

159-
// Verifier makes a `ConstraintSystem` instance representing a shuffle gadget
160-
let (mut verifier_cs, variables) =
161-
VerifierCS::new(&bp_gens, &pc_gens, transcript, commitments.to_vec());
181+
let cs = verifier.finalize_inputs();
162182

163-
// Verifier allocates variables and adds constraints to the constraint system
164-
let (input_vars, output_vars) = variables.split_at(k);
165-
KShuffleGadget::fill_cs(&mut verifier_cs, input_vars, output_vars);
183+
Self::fill_cs(&mut cs, &input_vars, &output_vars);
166184

167-
// Verifier verifies proof
168-
verifier_cs.verify(&proof)
185+
cs.verify(proof)
169186
}
170187
}
171188

@@ -237,7 +254,7 @@ fn kshuffle_verify_helper(k: usize, c: &mut Criterion) {
237254
let pc_gens = PedersenGens::default();
238255
let bp_gens = BulletproofGens::new(128, 1);
239256
let mut prover_transcript = Transcript::new(b"ShuffleTest");
240-
let (proof, commitments) =
257+
let (proof, in_commitments, out_commitments) =
241258
KShuffleGadget::prove(&pc_gens, &bp_gens, &mut prover_transcript, &input, &output)
242259
.unwrap();
243260

@@ -249,7 +266,8 @@ fn kshuffle_verify_helper(k: usize, c: &mut Criterion) {
249266
&bp_gens,
250267
&mut verifier_transcript,
251268
&proof,
252-
&commitments,
269+
&in_commitments,
270+
&out_commitments,
253271
)
254272
.unwrap();
255273
})

0 commit comments

Comments
 (0)