@@ -199,64 +199,87 @@ pub fn pedersen_commitment_dleq<G: PrimeGroup, R: RngCore>(
199199 ( instance, witness_vec)
200200}
201201
202- /// Test that a Pedersen commitment is between 0 and 1337 .
202+ /// Test that a Pedersen commitment is in the given range .
203203#[ allow( non_snake_case) ]
204- pub fn test_range < G : PrimeGroup , R : RngCore > (
204+ pub fn range_instance_generation < G : PrimeGroup , R : RngCore > (
205205 mut rng : & mut R ,
206+ input : u64 ,
207+ range : std:: ops:: Range < u64 > ,
206208) -> ( CanonicalLinearRelation < G > , Vec < G :: Scalar > ) {
207209 let G = G :: generator ( ) ;
208210 let H = G :: random ( & mut rng) ;
209211
210- let bases = [ 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 313 , 512 ] . map ( G :: Scalar :: from) ;
211- const BITS : usize = 11 ;
212+ let delta = range. end - range. start ;
213+ let whole_bits = ( delta - 1 ) . ilog2 ( ) as usize ;
214+ let remainder = delta - ( 1 << whole_bits) ;
215+
216+ // Compute the bases used to express the input as a linear combination of the bit decomposition
217+ // of the input.
218+ let mut bases = ( 0 ..whole_bits) . map ( |i| 1 << i) . collect :: < Vec < _ > > ( ) ;
219+ bases. push ( remainder) ;
220+ assert_eq ! ( range. start + bases. iter( ) . sum:: <u64 >( ) , range. end - 1 ) ;
212221
213222 let mut instance = LinearRelation :: new ( ) ;
214223 let [ var_G, var_H] = instance. allocate_elements ( ) ;
215224 let [ var_x, var_r] = instance. allocate_scalars ( ) ;
216- let vars_b = instance. allocate_scalars :: < BITS > ( ) ;
217- let vars_s = instance. allocate_scalars :: < BITS > ( ) ;
218- let var_s2 = instance. allocate_scalars :: < BITS > ( ) ;
219- let var_Ds = instance. allocate_elements :: < BITS > ( ) ;
225+ let vars_b = instance. allocate_scalars_vec ( bases . len ( ) ) ;
226+ let vars_s = instance. allocate_scalars_vec ( bases . len ( ) - 1 ) ;
227+ let var_s2 = instance. allocate_scalars_vec ( bases . len ( ) ) ;
228+ let var_Ds = instance. allocate_elements_vec ( bases . len ( ) ) ;
220229
221- // `var_Ds[i]` are bit commitments.
222- for i in 0 ..BITS {
230+ // `var_C` is a Pedersen commitment to `var_x`.
231+ let var_C = instance. allocate_eq ( var_x * var_G + var_r * var_H) ;
232+ // `var_Ds[i]` are bit commitments...
233+ for i in 1 ..bases. len ( ) {
223234 instance. append_equation ( var_Ds[ i] , vars_b[ i] * var_G + vars_s[ i] * var_H) ;
224235 instance. append_equation ( var_Ds[ i] , vars_b[ i] * var_Ds[ i] + var_s2[ i] * var_H) ;
225236 }
226- // `var_C` is a Pedersen commitment to `var_x`.
227- let var_C = instance. allocate_eq ( var_x * var_G + var_r * var_H) ;
228- // `var_x` = sum(bases[i] * var_b[i])
229- // This equation is "trivial", in that it does not contain any scalar var.
230- // Our linear relation is smart enough to check this outside of the proof,
231- // which is what a normal implementation would do.
237+ // ... satisfying that sum(Ds[i] * bases[i]) = C
232238 instance. append_equation (
233- var_C,
234- ( 0 ..BITS ) . map ( |i| var_Ds[ i] * bases[ i] ) . sum :: < Sum < _ > > ( ) ,
239+ var_Ds[ 0 ] ,
240+ var_C
241+ - var_G * G :: Scalar :: from ( range. start )
242+ - ( 1 ..bases. len ( ) )
243+ . map ( |i| var_Ds[ i] * G :: Scalar :: from ( bases[ i] ) )
244+ . sum :: < Sum < _ > > ( ) ,
235245 ) ;
246+ instance. append_equation ( var_Ds[ 0 ] , vars_b[ 0 ] * var_Ds[ 0 ] + var_s2[ 0 ] * var_H) ;
236247
248+ // Compute the witness
237249 let r = G :: Scalar :: random ( & mut rng) ;
238- let x = G :: Scalar :: from ( 822 ) ;
239-
240- let b = [
241- G :: Scalar :: ZERO ,
242- G :: Scalar :: ONE ,
243- G :: Scalar :: ONE ,
244- G :: Scalar :: ZERO ,
245- G :: Scalar :: ONE ,
246- G :: Scalar :: ONE ,
247- G :: Scalar :: ZERO ,
248- G :: Scalar :: ZERO ,
249- G :: Scalar :: ONE ,
250- G :: Scalar :: ZERO ,
251- G :: Scalar :: ONE ,
252- ] ;
250+ let x = G :: Scalar :: from ( input) ;
251+
252+ // IMPORTANT: this segment of the witness generation is NOT constant-time.
253+ // See PR #80 for details.
254+ let b = {
255+ let mut rest = input - range. start ;
256+ let mut b = vec ! [ G :: Scalar :: ZERO ; bases. len( ) ] ;
257+ assert ! ( rest < delta) ;
258+ for ( i, & base) in bases. iter ( ) . enumerate ( ) . rev ( ) {
259+ if rest >= base {
260+ b[ i] = G :: Scalar :: ONE ;
261+ rest -= base;
262+ }
263+ }
264+
265+ b
266+ } ;
267+ assert_eq ! (
268+ x,
269+ G :: Scalar :: from( range. start)
270+ + ( 0 ..bases. len( ) )
271+ . map( |i| G :: Scalar :: from( bases[ i] ) * b[ i] )
272+ . sum:: <G :: Scalar >( )
273+ ) ;
253274 // set the randomness for the bit decomposition
254- let mut s = ( 0 ..BITS )
275+ let mut s = ( 0 ..bases . len ( ) )
255276 . map ( |_| G :: Scalar :: random ( & mut rng) )
256277 . collect :: < Vec < _ > > ( ) ;
257- let partial_sum = ( 1 ..BITS ) . map ( |i| bases[ i] * s[ i] ) . sum :: < G :: Scalar > ( ) ;
278+ let partial_sum = ( 1 ..bases. len ( ) )
279+ . map ( |i| G :: Scalar :: from ( bases[ i] ) * s[ i] )
280+ . sum :: < G :: Scalar > ( ) ;
258281 s[ 0 ] = r - partial_sum;
259- let s2 = ( 0 ..BITS )
282+ let s2 = ( 0 ..bases . len ( ) )
260283 . map ( |i| ( G :: Scalar :: ONE - b[ i] ) * s[ i] )
261284 . collect :: < Vec < _ > > ( ) ;
262285 let witness = [ x, r]
@@ -269,13 +292,21 @@ pub fn test_range<G: PrimeGroup, R: RngCore>(
269292
270293 instance. set_elements ( [ ( var_G, G ) , ( var_H, H ) ] ) ;
271294 instance. set_element ( var_C, G * x + H * r) ;
272- for i in 0 ..BITS {
295+ for i in 0 ..bases . len ( ) {
273296 instance. set_element ( var_Ds[ i] , G * b[ i] + H * s[ i] ) ;
274297 }
275298
276299 ( instance. canonical ( ) . unwrap ( ) , witness)
277300}
278301
302+ /// Test that a Pedersen commitment is in `[0, bound)` for any `bound >= 0`.
303+ #[ allow( non_snake_case) ]
304+ pub fn test_range < G : PrimeGroup , R : RngCore > (
305+ mut rng : & mut R ,
306+ ) -> ( CanonicalLinearRelation < G > , Vec < G :: Scalar > ) {
307+ range_instance_generation ( & mut rng, 822 , 0 ..1337 )
308+ }
309+
279310/// LinearMap for knowledge of an opening for use in a BBS commitment.
280311// BBS message length is 3
281312#[ allow( non_snake_case) ]
0 commit comments