Add another ecmult_multi test
This commit is contained in:
parent
be6944ade9
commit
22d25c8e0a
172
src/tests.c
172
src/tests.c
@ -4052,6 +4052,174 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
|
||||
}
|
||||
}
|
||||
|
||||
int test_ecmult_multi_random(secp256k1_scratch *scratch) {
|
||||
/* Large random test for ecmult_multi_* functions which exercises:
|
||||
* - Few or many inputs (0 up to 128, roughly exponentially distributed).
|
||||
* - Few or many 0*P or a*INF inputs (roughly uniformly distributed).
|
||||
* - Including or excluding an nonzero a*G term (or such a term at all).
|
||||
* - Final expected result equal to infinity or not (roughly 50%).
|
||||
* - ecmult_multi_var, ecmult_strauss_single_batch, ecmult_pippenger_single_batch
|
||||
*/
|
||||
|
||||
/* These 4 variables define the eventual input to the ecmult_multi function.
|
||||
* g_scalar is the G scalar fed to it (or NULL, possibly, if g_scalar=0), and
|
||||
* scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points
|
||||
* which form its normal inputs. */
|
||||
int filled = 0;
|
||||
secp256k1_scalar g_scalar = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
secp256k1_scalar scalars[128];
|
||||
secp256k1_gej gejs[128];
|
||||
/* The expected result, and the computed result. */
|
||||
secp256k1_gej expected, computed;
|
||||
/* Temporaries. */
|
||||
secp256k1_scalar sc_tmp;
|
||||
secp256k1_ge ge_tmp;
|
||||
/* Variables needed for the actual input to ecmult_multi. */
|
||||
secp256k1_ge ges[128];
|
||||
ecmult_multi_data data;
|
||||
|
||||
int i;
|
||||
/* Which multiplication function to use */
|
||||
int fn = secp256k1_testrand_int(3);
|
||||
secp256k1_ecmult_multi_func ecmult_multi = fn == 0 ? secp256k1_ecmult_multi_var :
|
||||
fn == 1 ? secp256k1_ecmult_strauss_batch_single :
|
||||
secp256k1_ecmult_pippenger_batch_single;
|
||||
/* Simulate exponentially distributed num. */
|
||||
int num_bits = 2 + secp256k1_testrand_int(6);
|
||||
/* Number of (scalar, point) inputs (excluding g). */
|
||||
int num = secp256k1_testrand_int((1 << num_bits) + 1);
|
||||
/* Number of those which are nonzero. */
|
||||
int num_nonzero = secp256k1_testrand_int(num + 1);
|
||||
/* Whether we're aiming to create an input with nonzero expected result. */
|
||||
int nonzero_result = secp256k1_testrand_bits(1);
|
||||
/* Whether we will provide nonzero g multiplicand. In some cases our hand
|
||||
* is forced here based on num_nonzero and nonzero_result. */
|
||||
int g_nonzero = num_nonzero == 0 ? nonzero_result :
|
||||
num_nonzero == 1 && !nonzero_result ? 1 :
|
||||
(int)secp256k1_testrand_bits(1);
|
||||
/* Which g_scalar pointer to pass into ecmult_multi(). */
|
||||
const secp256k1_scalar* g_scalar_ptr = (g_nonzero || secp256k1_testrand_bits(1)) ? &g_scalar : NULL;
|
||||
/* How many EC multiplications were performed in this function. */
|
||||
int mults = 0;
|
||||
/* How many randomization steps to apply to the input list. */
|
||||
int rands = (int)secp256k1_testrand_bits(3);
|
||||
if (rands > num_nonzero) rands = num_nonzero;
|
||||
|
||||
secp256k1_gej_set_infinity(&expected);
|
||||
secp256k1_gej_set_infinity(&gejs[0]);
|
||||
secp256k1_scalar_set_int(&scalars[0], 0);
|
||||
|
||||
if (g_nonzero) {
|
||||
/* If g_nonzero, set g_scalar to nonzero value r. */
|
||||
random_scalar_order_test(&g_scalar);
|
||||
if (!nonzero_result) {
|
||||
/* If expected=0 is desired, add a (a*r, -(1/a)*g) term to compensate. */
|
||||
CHECK(num_nonzero > filled);
|
||||
random_scalar_order_test(&sc_tmp);
|
||||
secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar);
|
||||
secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp);
|
||||
secp256k1_scalar_negate(&sc_tmp, &sc_tmp);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &gejs[filled], &sc_tmp);
|
||||
++filled;
|
||||
++mults;
|
||||
}
|
||||
}
|
||||
|
||||
if (nonzero_result && filled < num_nonzero) {
|
||||
/* If a nonzero result is desired, and there is space, add a random nonzero term. */
|
||||
random_scalar_order_test(&scalars[filled]);
|
||||
random_group_element_test(&ge_tmp);
|
||||
secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
|
||||
++filled;
|
||||
}
|
||||
|
||||
if (nonzero_result) {
|
||||
/* Compute the expected result using normal ecmult. */
|
||||
CHECK(filled <= 1);
|
||||
secp256k1_ecmult(&expected, &gejs[0], &scalars[0], &g_scalar);
|
||||
mults += filled + g_nonzero;
|
||||
}
|
||||
|
||||
/* At this point we have expected = scalar_g*G + sum(scalars[i]*gejs[i] for i=0..filled-1). */
|
||||
CHECK(filled <= 1 + !nonzero_result);
|
||||
CHECK(filled <= num_nonzero);
|
||||
|
||||
/* Add entries to scalars,gejs so that there are num of them. All the added entries
|
||||
* either have scalar=0 or point=infinity, so these do not change the expected result. */
|
||||
while (filled < num) {
|
||||
if (secp256k1_testrand_bits(1)) {
|
||||
secp256k1_gej_set_infinity(&gejs[filled]);
|
||||
random_scalar_order_test(&scalars[filled]);
|
||||
} else {
|
||||
secp256k1_scalar_set_int(&scalars[filled], 0);
|
||||
random_group_element_test(&ge_tmp);
|
||||
secp256k1_gej_set_ge(&gejs[filled], &ge_tmp);
|
||||
}
|
||||
++filled;
|
||||
}
|
||||
|
||||
/* Now perform cheapish transformations on gejs and scalars, for indices
|
||||
* 0..num_nonzero-1, which do not change the expected result, but may
|
||||
* convert some of them to be both non-0-scalar and non-infinity-point. */
|
||||
for (i = 0; i < rands; ++i) {
|
||||
int j;
|
||||
secp256k1_scalar v, iv;
|
||||
/* Shuffle the entries. */
|
||||
for (j = 0; j < num_nonzero; ++j) {
|
||||
int k = secp256k1_testrand_int(num_nonzero - j);
|
||||
if (k != 0) {
|
||||
secp256k1_gej gej = gejs[j];
|
||||
secp256k1_scalar sc = scalars[j];
|
||||
gejs[j] = gejs[j + k];
|
||||
scalars[j] = scalars[j + k];
|
||||
gejs[j + k] = gej;
|
||||
scalars[j + k] = sc;
|
||||
}
|
||||
}
|
||||
/* Perturb all consecutive pairs of inputs:
|
||||
* a*P + b*Q -> (a+b)*P + b*(Q-P). */
|
||||
for (j = 0; j + 1 < num_nonzero; j += 2) {
|
||||
secp256k1_gej gej;
|
||||
secp256k1_scalar_add(&scalars[j], &scalars[j], &scalars[j+1]);
|
||||
secp256k1_gej_neg(&gej, &gejs[j]);
|
||||
secp256k1_gej_add_var(&gejs[j+1], &gejs[j+1], &gej, NULL);
|
||||
}
|
||||
/* Transform the last input: a*P -> (v*a) * ((1/v)*P). */
|
||||
CHECK(num_nonzero >= 1);
|
||||
random_scalar_order_test(&v);
|
||||
secp256k1_scalar_inverse(&iv, &v);
|
||||
secp256k1_scalar_mul(&scalars[num_nonzero - 1], &scalars[num_nonzero - 1], &v);
|
||||
secp256k1_ecmult(&gejs[num_nonzero - 1], &gejs[num_nonzero - 1], &iv, NULL);
|
||||
++mults;
|
||||
}
|
||||
|
||||
/* Shuffle all entries (0..num-1). */
|
||||
for (i = 0; i < num; ++i) {
|
||||
int j = secp256k1_testrand_int(num - i);
|
||||
if (j != 0) {
|
||||
secp256k1_gej gej = gejs[i];
|
||||
secp256k1_scalar sc = scalars[i];
|
||||
gejs[i] = gejs[i + j];
|
||||
scalars[i] = scalars[i + j];
|
||||
gejs[i + j] = gej;
|
||||
scalars[i + j] = sc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute affine versions of all inputs. */
|
||||
secp256k1_ge_set_all_gej_var(ges, gejs, filled);
|
||||
/* Invoke ecmult_multi code. */
|
||||
data.sc = scalars;
|
||||
data.pt = ges;
|
||||
CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
|
||||
mults += num_nonzero + g_nonzero;
|
||||
/* Compare with expected result. */
|
||||
secp256k1_gej_neg(&computed, &computed);
|
||||
secp256k1_gej_add_var(&computed, &computed, &expected, NULL);
|
||||
CHECK(secp256k1_gej_is_infinity(&computed));
|
||||
return mults;
|
||||
}
|
||||
|
||||
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
|
||||
secp256k1_scalar szero;
|
||||
secp256k1_scalar sc;
|
||||
@ -4242,6 +4410,7 @@ void test_ecmult_multi_batching(void) {
|
||||
|
||||
void run_ecmult_multi_tests(void) {
|
||||
secp256k1_scratch *scratch;
|
||||
int64_t todo = (int64_t)320 * count;
|
||||
|
||||
test_secp256k1_pippenger_bucket_window_inv();
|
||||
test_ecmult_multi_pippenger_max_points();
|
||||
@ -4252,6 +4421,9 @@ void run_ecmult_multi_tests(void) {
|
||||
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
|
||||
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
|
||||
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
|
||||
while (todo > 0) {
|
||||
todo -= test_ecmult_multi_random(scratch);
|
||||
}
|
||||
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
|
||||
|
||||
/* Run test_ecmult_multi with space for exactly one point */
|
||||
|
Loading…
x
Reference in New Issue
Block a user