Skip to content

Commit 13ca4bf

Browse files
authored
Merge pull request #152 from dalek-cryptography/generators-capacity
Add a notion of capacity to the Generators struct
2 parents ba4c168 + 706ff60 commit 13ca4bf

File tree

8 files changed

+246
-124
lines changed

8 files changed

+246
-124
lines changed

rust-toolchain

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-07-16
1+
nightly-2018-09-04

src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ impl From<MPCError> for ProofError {
3939
match e {
4040
MPCError::InvalidBitsize => ProofError::InvalidBitsize,
4141
MPCError::InvalidAggregation => ProofError::InvalidAggregation,
42+
MPCError::InvalidGeneratorsLength => ProofError::InvalidGeneratorsLength,
4243
_ => ProofError::ProvingError(e),
4344
}
4445
}
@@ -65,6 +66,9 @@ pub enum MPCError {
6566
/// proof with non-power-of-two aggregation size.
6667
#[fail(display = "Invalid aggregation size, m must be a power of 2")]
6768
InvalidAggregation,
69+
/// This error occurs when the generators are of the wrong length.
70+
#[fail(display = "Invalid generators length, must be equal to n.")]
71+
InvalidGeneratorsLength,
6872
/// This error occurs when the dealer is given the wrong number of
6973
/// value commitments.
7074
#[fail(display = "Wrong number of value commitments")]

src/generators.rs

Lines changed: 191 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,36 @@ use curve25519_dalek::traits::MultiscalarMul;
1111
use digest::{ExtendableOutput, Input, XofReader};
1212
use sha3::{Sha3XofReader, Shake256};
1313

14+
/// Represents a pair of base points for Pedersen commitments.
15+
#[derive(Copy, Clone)]
16+
pub struct PedersenGenerators {
17+
/// Base for the committed value
18+
pub B: RistrettoPoint,
19+
20+
/// Base for the blinding factor
21+
pub B_blinding: RistrettoPoint,
22+
}
23+
24+
impl PedersenGenerators {
25+
/// Creates a Pedersen commitment using the value scalar and a blinding factor.
26+
pub fn commit(&self, value: Scalar, blinding: Scalar) -> RistrettoPoint {
27+
RistrettoPoint::multiscalar_mul(&[value, blinding], &[self.B, self.B_blinding])
28+
}
29+
}
30+
31+
impl Default for PedersenGenerators {
32+
fn default() -> Self {
33+
PedersenGenerators {
34+
B: GeneratorsChain::new(b"Bulletproofs.Generators.B")
35+
.next()
36+
.unwrap(),
37+
B_blinding: GeneratorsChain::new(b"Bulletproofs.Generators.B_blinding")
38+
.next()
39+
.unwrap(),
40+
}
41+
}
42+
}
43+
1444
/// The `GeneratorsChain` creates an arbitrary-long sequence of orthogonal generators.
1545
/// The sequence can be deterministically produced starting with an arbitrary point.
1646
struct GeneratorsChain {
@@ -55,108 +85,160 @@ impl Iterator for GeneratorsChain {
5585
/// aggregating `m` range proofs of `n` bits each.
5686
#[derive(Clone)]
5787
pub struct Generators {
58-
/// Number of bits in a rangeproof
59-
pub n: usize,
60-
/// Number of values or parties
61-
pub m: usize,
6288
/// Bases for Pedersen commitments
6389
pub pedersen_gens: PedersenGenerators,
90+
/// The maximum number of usable generators for each party.
91+
pub gens_capacity: usize,
92+
/// Number of values or parties
93+
pub party_capacity: usize,
6494
/// Per-bit generators for the bit values
65-
pub G: Vec<RistrettoPoint>,
66-
/// Per-bit generators for the bit blinding factors
67-
pub H: Vec<RistrettoPoint>,
68-
}
69-
70-
/// The `GeneratorsView` is produced by `Generators::share()`.
71-
///
72-
/// The `Generators` struct represents generators for an aggregated
73-
/// range proof `m` proofs of `n` bits each; the `GeneratorsView`
74-
/// represents the generators for one of the `m` parties' shares.
75-
#[derive(Copy, Clone)]
76-
pub struct GeneratorsView<'a> {
77-
/// Bases for Pedersen commitments
78-
pub pedersen_gens: &'a PedersenGenerators,
79-
/// Per-bit generators for the bit values
80-
pub G: &'a [RistrettoPoint],
95+
G_vec: Vec<Vec<RistrettoPoint>>,
8196
/// Per-bit generators for the bit blinding factors
82-
pub H: &'a [RistrettoPoint],
83-
}
84-
85-
/// Represents a pair of base points for Pedersen commitments.
86-
#[derive(Copy, Clone)]
87-
pub struct PedersenGenerators {
88-
/// Base for the committed value
89-
pub B: RistrettoPoint,
90-
91-
/// Base for the blinding factor
92-
pub B_blinding: RistrettoPoint,
93-
}
94-
95-
impl PedersenGenerators {
96-
/// Creates a Pedersen commitment using the value scalar and a blinding factor.
97-
pub fn commit(&self, value: Scalar, blinding: Scalar) -> RistrettoPoint {
98-
RistrettoPoint::multiscalar_mul(&[value, blinding], &[self.B, self.B_blinding])
99-
}
100-
}
101-
102-
impl Default for PedersenGenerators {
103-
fn default() -> Self {
104-
PedersenGenerators {
105-
B: GeneratorsChain::new(b"Bulletproofs.Generators.B")
106-
.next()
107-
.unwrap(),
108-
B_blinding: GeneratorsChain::new(b"Bulletproofs.Generators.B_blinding")
109-
.next()
110-
.unwrap(),
111-
}
112-
}
97+
H_vec: Vec<Vec<RistrettoPoint>>,
11398
}
11499

115100
impl Generators {
116-
/// Creates generators for `m` range proofs of `n` bits each.
117-
pub fn new(pedersen_gens: PedersenGenerators, n: usize, m: usize) -> Self {
101+
/// Create a new `Generators` object.
102+
///
103+
/// # Inputs
104+
///
105+
/// * `pedersen_gens` is a pair of generators used for Pedersen
106+
/// commitments.
107+
/// * `gens_capacity` is the number of generators to precompute
108+
/// for each party. For rangeproofs, it is sufficient to pass
109+
/// `64`, the maximum bitsize of the rangeproofs. For circuit
110+
/// proofs, the capacity must be greater than the number of
111+
/// multipliers, rounded up to the next power of two.
112+
/// * `party_capacity` is the maximum number of parties that can
113+
/// produce an aggregated proof.
114+
pub fn new(
115+
pedersen_gens: PedersenGenerators,
116+
gens_capacity: usize,
117+
party_capacity: usize,
118+
) -> Self {
118119
use byteorder::{ByteOrder, LittleEndian};
119120

120-
let G = (0..m)
121-
.flat_map(|i| {
121+
let G_vec = (0..party_capacity)
122+
.map(|i| {
122123
let party_index = i as u32;
123124
let mut label = [b'G', 0, 0, 0, 0];
124125
LittleEndian::write_u32(&mut label[1..5], party_index);
125126

126-
GeneratorsChain::new(&label).take(n)
127-
})
128-
.collect();
127+
GeneratorsChain::new(&label)
128+
.take(gens_capacity)
129+
.collect::<Vec<_>>()
130+
}).collect();
129131

130-
let H = (0..m)
131-
.flat_map(|i| {
132+
let H_vec = (0..party_capacity)
133+
.map(|i| {
132134
let party_index = i as u32;
133135
let mut label = [b'H', 0, 0, 0, 0];
134136
LittleEndian::write_u32(&mut label[1..5], party_index);
135137

136-
GeneratorsChain::new(&label).take(n)
137-
})
138-
.collect();
138+
GeneratorsChain::new(&label)
139+
.take(gens_capacity)
140+
.collect::<Vec<_>>()
141+
}).collect();
139142

140143
Generators {
141144
pedersen_gens,
142-
n,
143-
m,
144-
G,
145-
H,
145+
gens_capacity,
146+
party_capacity,
147+
G_vec,
148+
H_vec,
146149
}
147150
}
148151

149152
/// Returns j-th share of generators, with an appropriate
150153
/// slice of vectors G and H for the j-th range proof.
151154
pub fn share(&self, j: usize) -> GeneratorsView {
152-
let lower = self.n * j;
153-
let upper = self.n * (j + 1);
154155
GeneratorsView {
155156
pedersen_gens: &self.pedersen_gens,
156-
G: &self.G[lower..upper],
157-
H: &self.H[lower..upper],
157+
gens: &self,
158+
share: j,
159+
}
160+
}
161+
162+
/// Return an iterator over the aggregation of the parties' G generators with given size `n`.
163+
pub(crate) fn G(&self, n: usize, m: usize) -> impl Iterator<Item = &RistrettoPoint> {
164+
AggregatedGensIter {
165+
n,
166+
m,
167+
array: &self.G_vec,
168+
party_idx: 0,
169+
gen_idx: 0,
170+
}
171+
}
172+
173+
/// Return an iterator over the aggregation of the parties' H generators with given size `n`.
174+
pub(crate) fn H(&self, n: usize, m: usize) -> impl Iterator<Item = &RistrettoPoint> {
175+
AggregatedGensIter {
176+
n,
177+
m,
178+
array: &self.H_vec,
179+
party_idx: 0,
180+
gen_idx: 0,
181+
}
182+
}
183+
}
184+
185+
struct AggregatedGensIter<'a> {
186+
array: &'a Vec<Vec<RistrettoPoint>>,
187+
n: usize,
188+
m: usize,
189+
party_idx: usize,
190+
gen_idx: usize,
191+
}
192+
193+
impl<'a> Iterator for AggregatedGensIter<'a> {
194+
type Item = &'a RistrettoPoint;
195+
196+
fn next(&mut self) -> Option<Self::Item> {
197+
if self.gen_idx >= self.n {
198+
self.gen_idx = 0;
199+
self.party_idx += 1;
200+
}
201+
202+
if self.party_idx >= self.m {
203+
None
204+
} else {
205+
let cur_gen = self.gen_idx;
206+
self.gen_idx += 1;
207+
Some(&self.array[self.party_idx][cur_gen])
158208
}
159209
}
210+
211+
fn size_hint(&self) -> (usize, Option<usize>) {
212+
let size = self.n * self.m;
213+
(size, Some(size))
214+
}
215+
}
216+
217+
/// The `GeneratorsView` is produced by `Generators::share()`.
218+
///
219+
/// The `Generators` struct represents generators for an aggregated
220+
/// range proof `m` proofs of `n` bits each; the `GeneratorsView`
221+
/// represents the generators for one of the `m` parties' shares.
222+
#[derive(Copy, Clone)]
223+
pub struct GeneratorsView<'a> {
224+
/// Bases for Pedersen commitments
225+
pub pedersen_gens: &'a PedersenGenerators,
226+
/// The parent object that this is a view into
227+
gens: &'a Generators,
228+
/// Which share we are
229+
share: usize,
230+
}
231+
232+
impl<'a> GeneratorsView<'a> {
233+
/// Return an iterator over this party's G generators with given size `n`.
234+
pub(crate) fn G(&self, n: usize) -> impl Iterator<Item = &'a RistrettoPoint> {
235+
self.gens.G_vec[self.share].iter().take(n)
236+
}
237+
238+
/// Return an iterator over this party's H generators with given size `n`.
239+
pub(crate) fn H(&self, n: usize) -> impl Iterator<Item = &'a RistrettoPoint> {
240+
self.gens.H_vec[self.share].iter().take(n)
241+
}
160242
}
161243

162244
#[cfg(test)]
@@ -165,23 +247,43 @@ mod tests {
165247
use super::*;
166248

167249
#[test]
168-
fn rangeproof_generators() {
169-
let n = 2;
170-
let m = 3;
171-
let gens = Generators::new(PedersenGenerators::default(), n, m);
172-
173-
// The concatenation of shares must be the full generator set
174-
assert_eq!(
175-
[gens.G[..n].to_vec(), gens.H[..n].to_vec()],
176-
[gens.share(0).G[..].to_vec(), gens.share(0).H[..].to_vec()]
177-
);
178-
assert_eq!(
179-
[gens.G[n..][..n].to_vec(), gens.H[n..][..n].to_vec()],
180-
[gens.share(1).G[..].to_vec(), gens.share(1).H[..].to_vec()]
181-
);
182-
assert_eq!(
183-
[gens.G[2 * n..][..n].to_vec(), gens.H[2 * n..][..n].to_vec()],
184-
[gens.share(2).G[..].to_vec(), gens.share(2).H[..].to_vec()]
185-
);
250+
fn aggregated_gens_iter_matches_flat_map() {
251+
let gens = Generators::new(PedersenGenerators::default(), 64, 8);
252+
253+
let helper = |n: usize, m: usize| {
254+
let agg_G: Vec<RistrettoPoint> = gens.G(n, m).cloned().collect();
255+
let flat_G: Vec<RistrettoPoint> = gens
256+
.G_vec
257+
.iter()
258+
.take(m)
259+
.flat_map(move |G_j| G_j.iter().take(n))
260+
.cloned()
261+
.collect();
262+
263+
let agg_H: Vec<RistrettoPoint> = gens.H(n, m).cloned().collect();
264+
let flat_H: Vec<RistrettoPoint> = gens
265+
.H_vec
266+
.iter()
267+
.take(m)
268+
.flat_map(move |H_j| H_j.iter().take(n))
269+
.cloned()
270+
.collect();
271+
272+
assert_eq!(agg_G, flat_G);
273+
assert_eq!(agg_H, flat_H);
274+
};
275+
276+
helper(64, 8);
277+
helper(64, 4);
278+
helper(64, 2);
279+
helper(64, 1);
280+
helper(32, 8);
281+
helper(32, 4);
282+
helper(32, 2);
283+
helper(32, 1);
284+
helper(16, 8);
285+
helper(16, 4);
286+
helper(16, 2);
287+
helper(16, 1);
186288
}
187289
}

src/inner_product_proof.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ impl InnerProductProof {
300300
}
301301

302302
let pos = 2 * lg_n * 32;
303-
let a = Scalar::from_canonical_bytes(read32(&slice[pos..])).ok_or(ProofError::FormatError)?;
303+
let a =
304+
Scalar::from_canonical_bytes(read32(&slice[pos..])).ok_or(ProofError::FormatError)?;
304305
let b = Scalar::from_canonical_bytes(read32(&slice[pos + 32..]))
305306
.ok_or(ProofError::FormatError)?;
306307

@@ -337,8 +338,8 @@ mod tests {
337338

338339
use generators::{Generators, PedersenGenerators};
339340
let gens = Generators::new(PedersenGenerators::default(), n, 1);
340-
let G = gens.share(0).G.to_vec();
341-
let H = gens.share(0).H.to_vec();
341+
let G: Vec<RistrettoPoint> = gens.share(0).G(n).cloned().collect();
342+
let H: Vec<RistrettoPoint> = gens.share(0).H(n).cloned().collect();
342343

343344
// Q would be determined upstream in the protocol, so we pick a random one.
344345
let Q = RistrettoPoint::hash_from_bytes::<Sha3_512>(b"test point");

0 commit comments

Comments
 (0)