Use trivial algorithm in ecmult_multi if scratch space is small

This commit is contained in:
Jonas Nick 2019-02-27 10:46:42 +00:00
parent aa15154a48
commit 9ab96f7b12
2 changed files with 37 additions and 15 deletions

View File

@ -1152,16 +1152,18 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n); return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
} }
/* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than
* use pippenger. Otherwise use strauss */ * a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm.
* As a first step check if there's enough space for Pippenger's algo (which requires less space
* than Strauss' algo) and if not, use the simple algorithm. */
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) { if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
return 0; return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
} }
if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
f = secp256k1_ecmult_pippenger_batch; f = secp256k1_ecmult_pippenger_batch;
} else { } else {
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) { if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
return 0; return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
} }
f = secp256k1_ecmult_strauss_batch; f = secp256k1_ecmult_strauss_batch;
} }

View File

@ -2572,7 +2572,6 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej r; secp256k1_gej r;
secp256k1_gej r2; secp256k1_gej r2;
ecmult_multi_data data; ecmult_multi_data data;
secp256k1_scratch *scratch_empty;
data.sc = sc; data.sc = sc;
data.pt = pt; data.pt = pt;
@ -2607,11 +2606,6 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej_add_var(&r, &r, &r2, NULL); secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
/* Try to multiply 1 point, but scratch space is empty */
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch_empty);
/* Try to multiply 1 point, but callback returns false */ /* Try to multiply 1 point, but callback returns false */
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
@ -2809,6 +2803,24 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
} }
} }
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar szero;
secp256k1_scalar sc[32];
secp256k1_ge pt[32];
secp256k1_gej r;
ecmult_multi_data data;
secp256k1_scratch *scratch_empty;
data.sc = sc;
data.pt = pt;
secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch_empty);
}
void test_secp256k1_pippenger_bucket_window_inv(void) { void test_secp256k1_pippenger_bucket_window_inv(void) {
int i; int i;
@ -2932,19 +2944,25 @@ void test_ecmult_multi_batching(void) {
} }
data.sc = sc; data.sc = sc;
data.pt = pt; data.pt = pt;
secp256k1_gej_neg(&r2, &r2);
/* Test with empty scratch space */ /* Test with empty scratch space. It should compute the correct result using
* ecmult_mult_simple algorithm which doesn't require a scratch space. */
scratch = secp256k1_scratch_create(&ctx->error_callback, 0); scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(scratch);
/* Test with space for 1 point in pippenger. That's not enough because /* Test with space for 1 point in pippenger. That's not enough because
* ecmult_multi selects strauss which requires more memory. */ * ecmult_multi selects strauss which requires more memory. It should
* therefore select the simple algorithm. */
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(scratch);
secp256k1_gej_neg(&r2, &r2);
for(i = 1; i <= n_points; i++) { for(i = 1; i <= n_points; i++) {
if (i > ECMULT_PIPPENGER_THRESHOLD) { if (i > ECMULT_PIPPENGER_THRESHOLD) {
int bucket_window = secp256k1_pippenger_bucket_window(i); int bucket_window = secp256k1_pippenger_bucket_window(i);
@ -2972,7 +2990,9 @@ void run_ecmult_multi_tests(void) {
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
test_ecmult_multi(NULL, secp256k1_ecmult_multi_var); test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single); test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single); test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(scratch);
/* Run test_ecmult_multi with space for exactly one point */ /* Run test_ecmult_multi with space for exactly one point */