@@ -4052,6 +4052,174 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
4052
4052
}
4053
4053
}
4054
4054
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
+ /* If expected=0 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 scalars,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
+ secp256k1_scalar v , iv ;
4167
+ /* Shuffle the entries. */
4168
+ for (j = 0 ; j < num_nonzero ; ++ j ) {
4169
+ int k = secp256k1_testrand_int (num_nonzero - j );
4170
+ if (k != 0 ) {
4171
+ secp256k1_gej gej = gejs [j ];
4172
+ secp256k1_scalar sc = scalars [j ];
4173
+ gejs [j ] = gejs [j + k ];
4174
+ scalars [j ] = scalars [j + k ];
4175
+ gejs [j + k ] = gej ;
4176
+ scalars [j + k ] = sc ;
4177
+ }
4178
+ }
4179
+ /* Perturb all consecutive pairs of inputs:
4180
+ * a*P + b*Q -> (a+b)*P + b*(Q-P). */
4181
+ for (j = 0 ; j + 1 < num_nonzero ; j += 2 ) {
4182
+ secp256k1_gej gej ;
4183
+ secp256k1_scalar_add (& scalars [j ], & scalars [j ], & scalars [j + 1 ]);
4184
+ secp256k1_gej_neg (& gej , & gejs [j ]);
4185
+ secp256k1_gej_add_var (& gejs [j + 1 ], & gejs [j + 1 ], & gej , NULL );
4186
+ }
4187
+ /* Transform the last input: a*P -> (v*a) * ((1/v)*P). */
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
+ /* Shuffle all entries (0..num-1). */
4197
+ for (i = 0 ; i < num ; ++ i ) {
4198
+ int j = secp256k1_testrand_int (num - i );
4199
+ if (j != 0 ) {
4200
+ secp256k1_gej gej = gejs [i ];
4201
+ secp256k1_scalar sc = scalars [i ];
4202
+ gejs [i ] = gejs [i + j ];
4203
+ scalars [i ] = scalars [i + j ];
4204
+ gejs [i + j ] = gej ;
4205
+ scalars [i + j ] = sc ;
4206
+ }
4207
+ }
4208
+
4209
+ /* Compute affine versions of all inputs. */
4210
+ secp256k1_ge_set_all_gej_var (ges , gejs , filled );
4211
+ /* Invoke ecmult_multi code. */
4212
+ data .sc = scalars ;
4213
+ data .pt = ges ;
4214
+ CHECK (ecmult_multi (& ctx -> error_callback , scratch , & computed , g_scalar_ptr , ecmult_multi_callback , & data , filled ));
4215
+ mults += num_nonzero + g_nonzero ;
4216
+ /* Compare with expected result. */
4217
+ secp256k1_gej_neg (& computed , & computed );
4218
+ secp256k1_gej_add_var (& computed , & computed , & expected , NULL );
4219
+ CHECK (secp256k1_gej_is_infinity (& computed ));
4220
+ return mults ;
4221
+ }
4222
+
4055
4223
void test_ecmult_multi_batch_single (secp256k1_ecmult_multi_func ecmult_multi ) {
4056
4224
secp256k1_scalar szero ;
4057
4225
secp256k1_scalar sc ;
@@ -4242,6 +4410,7 @@ void test_ecmult_multi_batching(void) {
4242
4410
4243
4411
void run_ecmult_multi_tests (void ) {
4244
4412
secp256k1_scratch * scratch ;
4413
+ int64_t todo = (int64_t )320 * count ;
4245
4414
4246
4415
test_secp256k1_pippenger_bucket_window_inv ();
4247
4416
test_ecmult_multi_pippenger_max_points ();
@@ -4252,6 +4421,9 @@ void run_ecmult_multi_tests(void) {
4252
4421
test_ecmult_multi_batch_single (secp256k1_ecmult_pippenger_batch_single );
4253
4422
test_ecmult_multi (scratch , secp256k1_ecmult_strauss_batch_single );
4254
4423
test_ecmult_multi_batch_single (secp256k1_ecmult_strauss_batch_single );
4424
+ while (todo > 0 ) {
4425
+ todo -= test_ecmult_multi_random (scratch );
4426
+ }
4255
4427
secp256k1_scratch_destroy (& ctx -> error_callback , scratch );
4256
4428
4257
4429
/* Run test_ecmult_multi with space for exactly one point */
0 commit comments