Skip to content

Commit f65f23a

Browse files
committed
Add another ecmult_multi test
1 parent be6944a commit f65f23a

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

src/tests.c

+171
Original file line numberDiff line numberDiff line change
@@ -4052,6 +4052,173 @@ 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+
if (g_nonzero) {
4110+
/* If g_nonzero, set g_scalar to nonzero value r. */
4111+
random_scalar_order_test(&g_scalar);
4112+
if (!nonzero_result) {
4113+
/* And if 0 expected is desired, add a (a*r, -(1/a)*g) term to compensate. */
4114+
CHECK(num_nonzero > filled);
4115+
random_scalar_order_test(&sc_tmp);
4116+
secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar);
4117+
secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp);
4118+
secp256k1_scalar_negate(&sc_tmp, &sc_tmp);
4119+
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &gejs[filled], &sc_tmp);
4120+
++filled;
4121+
++mults;
4122+
}
4123+
}
4124+
4125+
if (nonzero_result && filled < num_nonzero) {
4126+
/* If a nonzero result is desired, and there is space, add a random nonzero term. */
4127+
random_scalar_order_test(&scalars[filled]);
4128+
random_group_element_test(&ge_tmp);
4129+
secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
4130+
++filled;
4131+
}
4132+
4133+
if (nonzero_result) {
4134+
/* Compute the expected result using normal ecmult. */
4135+
CHECK(filled <= 1);
4136+
secp256k1_ecmult(&expected, filled ? &gejs[0] : &expected, &scalars[0], &g_scalar);
4137+
mults += filled + g_nonzero;
4138+
}
4139+
4140+
/* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */
4141+
CHECK(filled <= 1 + !nonzero_result);
4142+
CHECK(filled <= num_nonzero);
4143+
4144+
/* Add entries to sclalars,gejs so that there are num of them. All the added entries
4145+
* either have scalar=0 or point=infinity, so these do not change the expected result. */
4146+
while (filled < num) {
4147+
if (secp256k1_testrand_bits(1)) {
4148+
secp256k1_gej_set_infinity(&gejs[filled]);
4149+
random_scalar_order_test(&scalars[filled]);
4150+
} else {
4151+
secp256k1_scalar_set_int(&scalars[filled], 0);
4152+
random_group_element_test(&ge_tmp);
4153+
secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
4154+
}
4155+
++filled;
4156+
}
4157+
4158+
/* Now perform cheapish transformations on gejs and scalars, for indices
4159+
* 0..num_nonzero-1, which do not change the expected result, but may
4160+
* convert some of them to be both non-0-scalar and non-infinity-point. */
4161+
for (i = 0; i < rands; ++i) {
4162+
int j;
4163+
/* Shuffle the entries. */
4164+
for (j = 0; j < num_nonzero; ++j) {
4165+
int k = secp256k1_testrand_int(num_nonzero - j);
4166+
if (k != 0) {
4167+
secp256k1_gej gej = gejs[j];
4168+
secp256k1_scalar sc = scalars[j];
4169+
gejs[j] = gejs[j + k];
4170+
scalars[j] = scalars[j + k];
4171+
gejs[j + k] = gej;
4172+
scalars[j + k] = sc;
4173+
}
4174+
}
4175+
/* Perturb all consecutive pairs of inputs:
4176+
* a*P + b*Q -> (a+b)*P + b*(Q-P). */
4177+
for (j = 0; j + 1 < num_nonzero; j += 2) {
4178+
secp256k1_gej gej;
4179+
secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]);
4180+
secp256k1_gej_neg(&gej, &gejs[j]);
4181+
secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL);
4182+
}
4183+
/* Transform the last input: a*P -> (v*a) * ((1/v)*P). */
4184+
{
4185+
secp256k1_scalar v, iv;
4186+
CHECK(num_nonzero >= 1);
4187+
random_scalar_order_test(&v);
4188+
secp256k1_scalar_inverse(&iv, &v);
4189+
secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v);
4190+
secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL);
4191+
++mults;
4192+
}
4193+
}
4194+
4195+
/* Shuffle all entries (0..num-1). */
4196+
for (i = 0; i < num; ++i) {
4197+
int j = secp256k1_testrand_int(num - i);
4198+
if (j != 0) {
4199+
secp256k1_gej gej = gejs[i];
4200+
secp256k1_scalar sc = scalars[i];
4201+
gejs[i] = gejs[i + j];
4202+
scalars[i] = scalars[i + j];
4203+
gejs[i + j] = gej;
4204+
scalars[i + j] = sc;
4205+
}
4206+
}
4207+
4208+
/* Compute affine versions of all inputs. */
4209+
secp256k1_ge_set_all_gej_var(ges, gejs, filled);
4210+
/* Invoke ecmult_multi code. */
4211+
data.sc = scalars;
4212+
data.pt = ges;
4213+
CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
4214+
mults += num_nonzero + g_nonzero;
4215+
/* Compare with expected result. */
4216+
secp256k1_gej_neg(&computed, &computed);
4217+
secp256k1_gej_add_var(&computed, &computed, &expected, NULL);
4218+
CHECK(secp256k1_gej_is_infinity(&computed));
4219+
return mults;
4220+
}
4221+
40554222
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
40564223
secp256k1_scalar szero;
40574224
secp256k1_scalar sc;
@@ -4242,6 +4409,7 @@ void test_ecmult_multi_batching(void) {
42424409

42434410
void run_ecmult_multi_tests(void) {
42444411
secp256k1_scratch *scratch;
4412+
int64_t todo = (int64_t)320 * count;
42454413

42464414
test_secp256k1_pippenger_bucket_window_inv();
42474415
test_ecmult_multi_pippenger_max_points();
@@ -4252,6 +4420,9 @@ void run_ecmult_multi_tests(void) {
42524420
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
42534421
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
42544422
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
4423+
while (todo > 0) {
4424+
todo -= test_ecmult_multi_random(scratch);
4425+
}
42554426
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
42564427

42574428
/* Run test_ecmult_multi with space for exactly one point */

0 commit comments

Comments
 (0)