@@ -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 = num_nonzero <= 1 ? 0 : (int )secp256k1_testrand_bits (3 );
4106+
4107+ secp256k1_gej_set_infinity (& expected );
4108+
4109+ printf ("num=%i/%i g=%i r=%i\n" , num_nonzero , num , g_nonzero , nonzero_result );
4110+
4111+ if (g_nonzero ) {
4112+ /* If g_nonzero, set g_scalar to nonzero value r. */
4113+ random_scalar_order_test (& g_scalar );
4114+ if (!nonzero_result ) {
4115+ /* And if 0 expected is desired, add a (a*r, -(1/a)*g) term to compensate. */
4116+ CHECK (num_nonzero > filled );
4117+ random_scalar_order_test (& sc_tmp );
4118+ secp256k1_scalar_mul (& scalars [filled ], & sc_tmp , & g_scalar );
4119+ secp256k1_scalar_inverse_var (& sc_tmp , & sc_tmp );
4120+ secp256k1_scalar_negate (& sc_tmp , & sc_tmp );
4121+ secp256k1_ecmult_gen (& ctx -> ecmult_gen_ctx , & gejs [filled ], & sc_tmp );
4122+ ++ filled ;
4123+ ++ mults ;
4124+ }
4125+ }
4126+
4127+ if (nonzero_result && filled < num_nonzero ) {
4128+ /* If a nonzero result is desired, and there is space, add a random nonzero term. */
4129+ random_scalar_order_test (& scalars [filled ]);
4130+ random_group_element_test (& ge_tmp );
4131+ secp256k1_gej_set_ge (& gejs [filled ], & ge_tmp );
4132+ ++ filled ;
4133+ }
4134+
4135+ if (nonzero_result ) {
4136+ /* Compute the expected result using normal ecmult. */
4137+ CHECK (filled <= 1 );
4138+ secp256k1_ecmult (& expected , filled ? & gejs [0 ] : & expected , & scalars [0 ], & g_scalar );
4139+ mults += filled + g_nonzero ;
4140+ }
4141+
4142+ /* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */
4143+ CHECK (filled <= 1 + !nonzero_result );
4144+ CHECK (filled <= num_nonzero );
4145+
4146+ /* Add entries to sclalars,gejs so that there are num of them. All the added entries
4147+ * either have scalar=0 or point=infinity, so these do not change the expected result. */
4148+ while (filled < num ) {
4149+ if (secp256k1_testrand_bits (1 )) {
4150+ secp256k1_gej_set_infinity (& gejs [filled ]);
4151+ random_scalar_order_test (& scalars [filled ]);
4152+ } else {
4153+ secp256k1_scalar_set_int (& scalars [filled ], 0 );
4154+ random_group_element_test (& ge_tmp );
4155+ secp256k1_gej_set_ge (& gejs [filled ], & ge_tmp );
4156+ }
4157+ ++ filled ;
4158+ }
4159+
4160+ /* Now perform cheapish transformations on gejs and scalars, for indices
4161+ * 0..num_nonzero-1, which do not change the expected result, but may
4162+ * convert some of them to be both non-0-scalar and non-infinity-point. */
4163+ for (i = 0 ; i < rands ; ++ i ) {
4164+ int j ;
4165+ /* Shuffle the entries. */
4166+ for (j = 0 ; j < num_nonzero ; ++ j ) {
4167+ int k = secp256k1_testrand_int (num_nonzero - j );
4168+ if (k != 0 ) {
4169+ secp256k1_gej gej = gejs [j ];
4170+ secp256k1_scalar sc = scalars [j ];
4171+ gejs [j ] = gejs [j + k ];
4172+ scalars [j ] = scalars [j + k ];
4173+ gejs [j + k ] = gej ;
4174+ scalars [j + k ] = sc ;
4175+ }
4176+ }
4177+ /* Perturb all consecutive pairs of inputs:
4178+ * a*P + b*Q -> (a+b)*P + b*(Q-P). */
4179+ for (j = 0 ; j + 1 < num_nonzero ; j += 2 ) {
4180+ secp256k1_gej gej ;
4181+ secp256k1_scalar_add (& scalars [j ], & scalars [j ], & scalars [j + 1 ]);
4182+ secp256k1_gej_neg (& gej , & gejs [j ]);
4183+ secp256k1_gej_add_var (& gejs [j + 1 ], & gejs [j + 1 ], & gej , NULL );
4184+ }
4185+ /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */
4186+ {
4187+ secp256k1_scalar v , iv ;
4188+ CHECK (num_nonzero >= 1 );
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