@@ -4052,6 +4052,175 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
40524052    }
40534053}
40544054
4055+ int  test_ecmult_multi_random (secp256k1_scratch  * scratch ) {
4056+     /* Large random test for ecmult_multi_* functions which exercises: 
4057+      * - Few or many inputs (0 up to 128, roughly exponentially distributed). 
4058+      * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). 
4059+      * - Including or excluding an nonzero a*G term (or such a term at all). 
4060+      * - Final expected result equal to infinity or not (roughly 50%). 
4061+      * - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch 
4062+      */ 
4063+ 
4064+     /* These 4 variables define the eventual input to the ecmult_multi function. 
4065+      * g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and 
4066+      * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points 
4067+      * which form its normal inputs. */ 
4068+     int  filled  =  0 ;
4069+     secp256k1_scalar  g_scalar  =  SECP256K1_SCALAR_CONST (0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 );
4070+     secp256k1_scalar  scalars [128 ];
4071+     secp256k1_gej  gejs [128 ];
4072+     /* The expected result, and the computed result. */ 
4073+     secp256k1_gej  expected , computed ;
4074+     /* Temporaries. */ 
4075+     secp256k1_scalar  sc_tmp ;
4076+     secp256k1_ge  ge_tmp ;
4077+     /* Variables needed for the actual input to ecmult_multi. */ 
4078+     secp256k1_ge  ges [128 ];
4079+     ecmult_multi_data  data ;
4080+ 
4081+     int  i ;
4082+     /* Which multiplication function to use */ 
4083+     int  fn  =  secp256k1_testrand_int (3 );
4084+     secp256k1_ecmult_multi_func  ecmult_multi  =  fn  ==  0  ? secp256k1_ecmult_multi_var  :
4085+                                                fn  ==  1  ? secp256k1_ecmult_strauss_batch_single  :
4086+                                                secp256k1_ecmult_pippenger_batch_single ;
4087+     /* Simulate exponentially distributed num. */ 
4088+     int  num_bits  =  2  +  secp256k1_testrand_int (6 );
4089+     /* Number of (scalar, point) inputs (excluding g). */ 
4090+     int  num  =  secp256k1_testrand_int ((1  << num_bits ) +  1 );
4091+     /* Number of those which are nonzero. */ 
4092+     int  num_nonzero  =  secp256k1_testrand_int (num  +  1 );
4093+     /* Whether we're aiming to create an input with nonzero expected result. */ 
4094+     int  nonzero_result  =  secp256k1_testrand_bits (1 );
4095+     /* Whether we will provide nonzero g multiplicand. In some cases our hand 
4096+      * is forced here based on num_nonzero and nonzero_result. */ 
4097+     int  g_nonzero  =  num_nonzero  ==  0  ? nonzero_result  :
4098+                     num_nonzero  ==  1  &&  !nonzero_result  ? 1  :
4099+                     (int )secp256k1_testrand_bits (1 );
4100+     /* Which g_scalar pointer to pass into ecmult_multi(). */ 
4101+     const  secp256k1_scalar *  g_scalar_ptr  =  (g_nonzero  ||  secp256k1_testrand_bits (1 )) ? & g_scalar  : NULL ;
4102+     /* How many EC multiplications were performed in this function. */ 
4103+     int  mults  =  0 ;
4104+     /* How many randomization steps to apply to the input list. */ 
4105+     int  rands  =  (int )secp256k1_testrand_bits (3 );
4106+     if  (rands  >  num_nonzero ) rands  =  num_nonzero ;
4107+ 
4108+     secp256k1_gej_set_infinity (& expected );
4109+     secp256k1_gej_set_infinity (& gejs [0 ]);
4110+     secp256k1_scalar_set_int (& scalars [0 ], 0 );
4111+ 
4112+     if  (g_nonzero ) {
4113+         /* If g_nonzero, set g_scalar to nonzero value r. */ 
4114+         random_scalar_order_test (& g_scalar );
4115+         if  (!nonzero_result ) {
4116+             /* And if 0 expected is desired, add a (a*r, -(1/a)*g) term to compensate. */ 
4117+             CHECK (num_nonzero  >  filled );
4118+             random_scalar_order_test (& sc_tmp );
4119+             secp256k1_scalar_mul (& scalars [filled ], & sc_tmp , & g_scalar );
4120+             secp256k1_scalar_inverse_var (& sc_tmp , & sc_tmp );
4121+             secp256k1_scalar_negate (& sc_tmp , & sc_tmp );
4122+             secp256k1_ecmult_gen (& ctx -> ecmult_gen_ctx , & gejs [filled ], & sc_tmp );
4123+             ++ filled ;
4124+             ++ mults ;
4125+         }
4126+     }
4127+ 
4128+     if  (nonzero_result  &&  filled  <  num_nonzero ) {
4129+         /* If a nonzero result is desired, and there is space, add a random nonzero term. */ 
4130+         random_scalar_order_test (& scalars [filled ]);
4131+         random_group_element_test (& ge_tmp );
4132+         secp256k1_gej_set_ge (& gejs [filled ], & ge_tmp );
4133+         ++ filled ;
4134+     }
4135+ 
4136+     if  (nonzero_result ) {
4137+         /* Compute the expected result using normal ecmult. */ 
4138+         CHECK (filled  <= 1 );
4139+         secp256k1_ecmult (& expected , & gejs [0 ], & scalars [0 ], & g_scalar );
4140+         mults  +=  filled  +  g_nonzero ;
4141+     }
4142+ 
4143+     /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */ 
4144+     CHECK (filled  <= 1  +  !nonzero_result );
4145+     CHECK (filled  <= num_nonzero );
4146+ 
4147+     /* Add entries to sclalars,gejs so that there are num of them. All the added entries 
4148+      * either have scalar=0 or point=infinity, so these do not change the expected result. */ 
4149+     while  (filled  <  num ) {
4150+         if  (secp256k1_testrand_bits (1 )) {
4151+             secp256k1_gej_set_infinity (& gejs [filled ]);
4152+             random_scalar_order_test (& scalars [filled ]);
4153+         } else  {
4154+             secp256k1_scalar_set_int (& scalars [filled ], 0 );
4155+             random_group_element_test (& ge_tmp );
4156+             secp256k1_gej_set_ge (& gejs [filled ], & ge_tmp );
4157+         }
4158+         ++ filled ;
4159+     }
4160+ 
4161+     /* Now perform cheapish transformations on gejs and scalars, for indices 
4162+      * 0..num_nonzero-1, which do not change the expected result, but may 
4163+      * convert some of them to be both non-0-scalar and non-infinity-point. */ 
4164+     for  (i  =  0 ; i  <  rands ; ++ i ) {
4165+         int  j ;
4166+         /* Shuffle the entries. */ 
4167+         for  (j  =  0 ; j  <  num_nonzero ; ++ j ) {
4168+             int  k  =  secp256k1_testrand_int (num_nonzero  -  j );
4169+             if  (k  !=  0 ) {
4170+                 secp256k1_gej  gej  =  gejs [j ];
4171+                 secp256k1_scalar  sc  =  scalars [j ];
4172+                 gejs [j ] =  gejs [j  +  k ];
4173+                 scalars [j ] =  scalars [j  +  k ];
4174+                 gejs [j  +  k ] =  gej ;
4175+                 scalars [j  +  k ] =  sc ;
4176+             }
4177+         }
4178+         /* Perturb all consecutive pairs of inputs: 
4179+          * a*P + b*Q -> (a+b)*P + b*(Q-P). */ 
4180+         for  (j  =  0 ; j  +  1  <  num_nonzero ; j  +=  2 ) {
4181+             secp256k1_gej  gej ;
4182+             secp256k1_scalar_add (& scalars [j ], & scalars [j ], & scalars [j + 1 ]);
4183+             secp256k1_gej_neg (& gej , & gejs [j ]);
4184+             secp256k1_gej_add_var (& gejs [j + 1 ], & gejs [j + 1 ], & gej , NULL );
4185+         }
4186+         /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */ 
4187+         if  (num_nonzero  >= 1 ) {
4188+             secp256k1_scalar  v , iv ;
4189+             random_scalar_order_test (& v );
4190+             secp256k1_scalar_inverse (& iv , & v );
4191+             secp256k1_scalar_mul (& scalars [num_nonzero  -  1 ], & scalars [num_nonzero  -  1 ], & v );
4192+             secp256k1_ecmult (& gejs [num_nonzero  -  1 ], & gejs [num_nonzero  -  1 ], & iv , NULL );
4193+             ++ mults ;
4194+         }
4195+     }
4196+ 
4197+     /* Shuffle all entries (0..num-1). */ 
4198+     for  (i  =  0 ; i  <  num ; ++ i ) {
4199+         int  j  =  secp256k1_testrand_int (num  -  i );
4200+         if  (j  !=  0 ) {
4201+             secp256k1_gej  gej  =  gejs [i ];
4202+             secp256k1_scalar  sc  =  scalars [i ];
4203+             gejs [i ] =  gejs [i  +  j ];
4204+             scalars [i ] =  scalars [i  +  j ];
4205+             gejs [i  +  j ] =  gej ;
4206+             scalars [i  +  j ] =  sc ;
4207+         }
4208+     }
4209+ 
4210+     /* Compute affine versions of all inputs. */ 
4211+     secp256k1_ge_set_all_gej_var (ges , gejs , filled );
4212+     /* Invoke ecmult_multi code. */ 
4213+     data .sc  =  scalars ;
4214+     data .pt  =  ges ;
4215+     CHECK (ecmult_multi (& ctx -> error_callback , scratch , & computed , g_scalar_ptr , ecmult_multi_callback , & data , filled ));
4216+     mults  +=  num_nonzero  +  g_nonzero ;
4217+     /* Compare with expected result. */ 
4218+     secp256k1_gej_neg (& computed , & computed );
4219+     secp256k1_gej_add_var (& computed , & computed , & expected , NULL );
4220+     CHECK (secp256k1_gej_is_infinity (& computed ));
4221+     return  mults ;
4222+ }
4223+ 
40554224void  test_ecmult_multi_batch_single (secp256k1_ecmult_multi_func  ecmult_multi ) {
40564225    secp256k1_scalar  szero ;
40574226    secp256k1_scalar  sc ;
@@ -4242,6 +4411,7 @@ void test_ecmult_multi_batching(void) {
42424411
42434412void  run_ecmult_multi_tests (void ) {
42444413    secp256k1_scratch  * scratch ;
4414+     int64_t  todo  =  (int64_t )320  *  count ;
42454415
42464416    test_secp256k1_pippenger_bucket_window_inv ();
42474417    test_ecmult_multi_pippenger_max_points ();
@@ -4252,6 +4422,9 @@ void run_ecmult_multi_tests(void) {
42524422    test_ecmult_multi_batch_single (secp256k1_ecmult_pippenger_batch_single );
42534423    test_ecmult_multi (scratch , secp256k1_ecmult_strauss_batch_single );
42544424    test_ecmult_multi_batch_single (secp256k1_ecmult_strauss_batch_single );
4425+     while  (todo  >  0 ) {
4426+         todo  -=  test_ecmult_multi_random (scratch );
4427+     }
42554428    secp256k1_scratch_destroy (& ctx -> error_callback , scratch );
42564429
42574430    /* Run test_ecmult_multi with space for exactly one point */ 
0 commit comments