@@ -11,6 +11,36 @@ use curve25519_dalek::traits::MultiscalarMul;
1111use digest:: { ExtendableOutput , Input , XofReader } ;
1212use 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.
1646struct GeneratorsChain {
@@ -55,108 +85,160 @@ impl Iterator for GeneratorsChain {
5585/// aggregating `m` range proofs of `n` bits each.
5686#[ derive( Clone ) ]
5787pub 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
115100impl 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}
0 commit comments