Skip to content

Commit 776565e

Browse files
authored
Merge pull request #109 from dalek-cryptography/circuit
Circuit work tracker [WIP]
2 parents 7d6bfc2 + 4b1aeb1 commit 776565e

27 files changed

+3501
-285
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ rust:
66

77
env:
88
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES=''
9-
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='avx2_backend'
9+
- TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='yoloproofs'
1010
# run cargo bench with a filter that matches no benchmarks.
1111
# this ensures the benchmarks build but doesn't run them on the CI server.
12-
- TEST_COMMAND=bench EXTRA_FLAGS='"DONTRUNBENCHMARKS"' FEATURES='avx2_backend'
12+
- TEST_COMMAND=bench EXTRA_FLAGS='"DONTRUNBENCHMARKS"' FEATURES=''
1313

1414
before_script:
1515
- rustup component add rustfmt-preview

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ bincode = "1"
3131

3232
[features]
3333
avx2_backend = ["curve25519-dalek/avx2_backend"]
34+
yoloproofs = []
3435

3536
[[bench]]
36-
name = "bulletproofs"
37+
name = "range_proof"
3738
harness = false
3839

40+
#[[bench]]
41+
#name = "r1cs"
42+
#harness = false

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ This library provides implementations of:
2828

2929
* A programmable constraint system API for expressing rank-1
3030
constraint systems, and proving and verifying proofs of arbitrary
31-
statements (under development in the `circuit` branch);
31+
statements (unstable, under development with the `yoloproofs` feature);
3232

33-
* Online multi-party computation for aggregated circuit proofs
33+
* Online multi-party computation for aggregated constraint system proofs
3434
(planned future work).
3535

3636
These proofs are implemented using [Merlin transcripts][doc_merlin],
@@ -48,9 +48,9 @@ the library's [internal documentation][doc_internal]:
4848
* how [the range proof protocol works][rp_notes];
4949
* how [the inner product proof protocol works][ipp_notes];
5050
* how [the aggregation protocol works][agg_notes];
51-
* how the Bulletproof circuit proofs work (under development);
51+
* how the Bulletproof constraint system proofs work (under development);
5252
* how the constraint system reduction works (under development);
53-
* how the aggregated circuit proofs work (future work).
53+
* how the aggregated constraint system proofs work (future work).
5454

5555
## Comparative Performance
5656

benches/r1cs.rs

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
extern crate bulletproofs;
2+
use bulletproofs::r1cs::{ConstraintSystem, ProverCS, R1CSError, R1CSProof, Variable, VerifierCS};
3+
use bulletproofs::{BulletproofGens, PedersenGens};
4+
5+
#[macro_use]
6+
extern crate criterion;
7+
use criterion::Criterion;
8+
9+
extern crate curve25519_dalek;
10+
use curve25519_dalek::ristretto::CompressedRistretto;
11+
use curve25519_dalek::scalar::Scalar;
12+
13+
extern crate merlin;
14+
use merlin::Transcript;
15+
16+
extern crate rand;
17+
use rand::Rng;
18+
19+
/*
20+
K-SHUFFLE GADGET SPECIFICATION:
21+
22+
Represents a permutation of a list of `k` scalars `{x_i}` into a list of `k` scalars `{y_i}`.
23+
24+
Algebraically it can be expressed as a statement that for a free variable `z`,
25+
the roots of the two polynomials in terms of `z` are the same up to a permutation:
26+
27+
∏(x_i - z) == ∏(y_i - z)
28+
29+
Prover can commit to blinded scalars `x_i` and `y_i` then receive a random challenge `z`,
30+
and build a proof that the above relation holds.
31+
32+
K-shuffle requires `2*(K-1)` multipliers.
33+
34+
For K > 1:
35+
36+
(x_0 - z)---⊗------⊗---(y_0 - z) // mulx[0], muly[0]
37+
| |
38+
(x_1 - z)---⊗ ⊗---(y_1 - z) // mulx[1], muly[1]
39+
| |
40+
... ...
41+
| |
42+
(x_{k-2} - z)---⊗ ⊗---(y_{k-2} - z) // mulx[k-2], muly[k-2]
43+
/ \
44+
(x_{k-1} - z)_/ \_(y_{k-1} - z)
45+
46+
// Connect left and right sides of the shuffle statement
47+
mulx_out[0] = muly_out[0]
48+
49+
// For i == [0, k-3]:
50+
mulx_left[i] = x_i - z
51+
mulx_right[i] = mulx_out[i+1]
52+
muly_left[i] = y_i - z
53+
muly_right[i] = muly_out[i+1]
54+
55+
// last multipliers connect two last variables (on each side)
56+
mulx_left[k-2] = x_{k-2} - z
57+
mulx_right[k-2] = x_{k-1} - z
58+
muly_left[k-2] = y_{k-2} - z
59+
muly_right[k-2] = y_{k-1} - z
60+
61+
For K = 1:
62+
63+
(x_0 - z)--------------(y_0 - z)
64+
65+
// Connect x to y directly, omitting the challenge entirely as it cancels out
66+
x_0 = y_0
67+
*/
68+
69+
// Make a gadget that adds constraints to a ConstraintSystem, such that the
70+
// y variables are constrained to be a valid shuffle of the x variables.
71+
struct KShuffleGadget {}
72+
73+
impl KShuffleGadget {
74+
fn fill_cs<CS: ConstraintSystem>(cs: &mut CS, x: &[Variable], y: &[Variable]) {
75+
let one = Scalar::one();
76+
let z = cs.challenge_scalar(b"k-scalar shuffle challenge");
77+
78+
assert_eq!(x.len(), y.len());
79+
80+
let k = x.len();
81+
if k == 1 {
82+
cs.add_auxiliary_constraint([(x[0], -one), (y[0], one)].iter().collect());
83+
return;
84+
}
85+
86+
// Make last x multiplier for i = k-1 and k-2
87+
let (_, _, last_mulx_out) = cs.add_partial_constraint(x[k - 1] - z, x[k - 2] - z);
88+
89+
// Make multipliers for x from i == [0, k-3]
90+
let first_mulx_out = (0..k - 2).rev().fold(last_mulx_out, |prev_out, i| {
91+
let (_, _, o) = cs.add_partial_constraint(prev_out.into(), x[i] - z);
92+
o
93+
});
94+
95+
// Make last y multiplier for i = k-1 and k-2
96+
let (_, _, last_muly_out) = cs.add_partial_constraint(y[k - 1] - z, y[k - 2] - z);
97+
98+
// Make multipliers for y from i == [0, k-3]
99+
let first_muly_out = (0..k - 2).rev().fold(last_muly_out, |prev_out, i| {
100+
let (_, _, o) = cs.add_partial_constraint(prev_out.into(), y[i] - z);
101+
o
102+
});
103+
104+
// Check equality between last x mul output and last y mul output
105+
cs.add_auxiliary_constraint(
106+
[(first_muly_out, -one), (first_mulx_out, one)]
107+
.iter()
108+
.collect(),
109+
);
110+
}
111+
112+
pub fn prove<'a, 'b>(
113+
pc_gens: &'b PedersenGens,
114+
bp_gens: &'b BulletproofGens,
115+
transcript: &'a mut Transcript,
116+
input: &[Scalar],
117+
output: &[Scalar],
118+
) -> Result<(R1CSProof, Vec<CompressedRistretto>), R1CSError> {
119+
let k = input.len();
120+
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))
148+
}
149+
150+
pub fn verify<'a, 'b>(
151+
pc_gens: &'b PedersenGens,
152+
bp_gens: &'b BulletproofGens,
153+
transcript: &'a mut Transcript,
154+
proof: &R1CSProof,
155+
commitments: &Vec<CompressedRistretto>,
156+
) -> Result<(), R1CSError> {
157+
let k = commitments.len() / 2;
158+
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());
162+
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);
166+
167+
// Verifier verifies proof
168+
verifier_cs.verify(&proof)
169+
}
170+
}
171+
172+
fn kshuffle_prove_helper(k: usize, c: &mut Criterion) {
173+
let label = format!("{}-shuffle proof creation", k);
174+
175+
c.bench_function(&label, move |b| {
176+
// Generate inputs and outputs to kshuffle
177+
let mut rng = rand::thread_rng();
178+
let (min, max) = (0u64, std::u64::MAX);
179+
let input: Vec<Scalar> = (0..k)
180+
.map(|_| Scalar::from(rng.gen_range(min, max)))
181+
.collect();
182+
let mut output = input.clone();
183+
rand::thread_rng().shuffle(&mut output);
184+
185+
// Make kshuffle proof
186+
let pc_gens = PedersenGens::default();
187+
let bp_gens = BulletproofGens::new(128, 1);
188+
b.iter(|| {
189+
let mut prover_transcript = Transcript::new(b"ShuffleTest");
190+
KShuffleGadget::prove(&pc_gens, &bp_gens, &mut prover_transcript, &input, &output)
191+
.unwrap();
192+
})
193+
});
194+
}
195+
196+
fn kshuffle_prove_8(c: &mut Criterion) {
197+
kshuffle_prove_helper(8, c);
198+
}
199+
fn kshuffle_prove_16(c: &mut Criterion) {
200+
kshuffle_prove_helper(16, c);
201+
}
202+
fn kshuffle_prove_32(c: &mut Criterion) {
203+
kshuffle_prove_helper(32, c);
204+
}
205+
fn kshuffle_prove_64(c: &mut Criterion) {
206+
kshuffle_prove_helper(64, c);
207+
}
208+
fn kshuffle_prove_17(c: &mut Criterion) {
209+
kshuffle_prove_helper(17, c);
210+
}
211+
212+
criterion_group!{
213+
name = kshuffle_prove;
214+
config = Criterion::default();
215+
targets =
216+
kshuffle_prove_8,
217+
kshuffle_prove_16,
218+
kshuffle_prove_32,
219+
kshuffle_prove_64,
220+
kshuffle_prove_17,
221+
}
222+
223+
fn kshuffle_verify_helper(k: usize, c: &mut Criterion) {
224+
let label = format!("{}-shuffle proof verification", k);
225+
226+
c.bench_function(&label, move |b| {
227+
// Generate inputs and outputs to kshuffle
228+
let mut rng = rand::thread_rng();
229+
let (min, max) = (0u64, std::u64::MAX);
230+
let input: Vec<Scalar> = (0..k)
231+
.map(|_| Scalar::from(rng.gen_range(min, max)))
232+
.collect();
233+
let mut output = input.clone();
234+
rand::thread_rng().shuffle(&mut output);
235+
236+
// Make kshuffle proof
237+
let pc_gens = PedersenGens::default();
238+
let bp_gens = BulletproofGens::new(128, 1);
239+
let mut prover_transcript = Transcript::new(b"ShuffleTest");
240+
let (proof, commitments) =
241+
KShuffleGadget::prove(&pc_gens, &bp_gens, &mut prover_transcript, &input, &output)
242+
.unwrap();
243+
244+
// Verify kshuffle proof
245+
b.iter(|| {
246+
let mut verifier_transcript = Transcript::new(b"ShuffleTest");
247+
KShuffleGadget::verify(
248+
&pc_gens,
249+
&bp_gens,
250+
&mut verifier_transcript,
251+
&proof,
252+
&commitments,
253+
)
254+
.unwrap();
255+
})
256+
});
257+
}
258+
259+
fn kshuffle_verify_8(c: &mut Criterion) {
260+
kshuffle_verify_helper(8, c);
261+
}
262+
fn kshuffle_verify_16(c: &mut Criterion) {
263+
kshuffle_verify_helper(16, c);
264+
}
265+
fn kshuffle_verify_32(c: &mut Criterion) {
266+
kshuffle_verify_helper(32, c);
267+
}
268+
fn kshuffle_verify_64(c: &mut Criterion) {
269+
kshuffle_verify_helper(64, c);
270+
}
271+
fn kshuffle_verify_17(c: &mut Criterion) {
272+
kshuffle_verify_helper(17, c);
273+
}
274+
275+
criterion_group!{
276+
name = kshuffle_verify;
277+
config = Criterion::default();
278+
targets =
279+
kshuffle_verify_8,
280+
kshuffle_verify_16,
281+
kshuffle_verify_32,
282+
kshuffle_verify_64,
283+
kshuffle_verify_17,
284+
}
285+
286+
criterion_main!(kshuffle_prove, kshuffle_verify);

benches/bulletproofs.rs renamed to benches/range_proof.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ fn verify_aggregated_rangeproof_helper(n: usize, c: &mut Criterion) {
8888
&values,
8989
&blindings,
9090
n,
91-
).unwrap();
91+
)
92+
.unwrap();
9293

9394
b.iter(|| {
9495
// Each proof creation requires a clean transcript.

docs/aggregation-api.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
The `aggregation` module contains the API for performing the aggregated multiparty computation protocol.
1+
The `range_proof_mpc` module contains the API for performing the aggregated multiparty computation protocol for joint range proof proving.
2+
3+
Only the range proofs are supported, while aggregation of constraint system proofs is under development.
24

35
API for the aggregated multiparty computation protocol
46
------------------------------------------------------

0 commit comments

Comments
 (0)