Skip to content

Commit 9ab96f7

Browse files
committed
Use trivial algorithm in ecmult_multi if scratch space is small
1 parent aa15154 commit 9ab96f7

File tree

2 files changed

+37
-15
lines changed

2 files changed

+37
-15
lines changed

src/ecmult_impl.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -1152,16 +1152,18 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
11521152
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
11531153
}
11541154

1155-
/* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold
1156-
* use pippenger. Otherwise use strauss */
1155+
/* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than
1156+
* a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm.
1157+
* As a first step check if there's enough space for Pippenger's algo (which requires less space
1158+
* than Strauss' algo) and if not, use the simple algorithm. */
11571159
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
1158-
return 0;
1160+
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
11591161
}
11601162
if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
11611163
f = secp256k1_ecmult_pippenger_batch;
11621164
} else {
11631165
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
1164-
return 0;
1166+
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
11651167
}
11661168
f = secp256k1_ecmult_strauss_batch;
11671169
}

src/tests.c

+31-11
Original file line numberDiff line numberDiff line change
@@ -2572,7 +2572,6 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
25722572
secp256k1_gej r;
25732573
secp256k1_gej r2;
25742574
ecmult_multi_data data;
2575-
secp256k1_scratch *scratch_empty;
25762575

25772576
data.sc = sc;
25782577
data.pt = pt;
@@ -2607,11 +2606,6 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
26072606
secp256k1_gej_add_var(&r, &r, &r2, NULL);
26082607
CHECK(secp256k1_gej_is_infinity(&r));
26092608

2610-
/* Try to multiply 1 point, but scratch space is empty */
2611-
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
2612-
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
2613-
secp256k1_scratch_destroy(scratch_empty);
2614-
26152609
/* Try to multiply 1 point, but callback returns false */
26162610
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
26172611

@@ -2809,6 +2803,24 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
28092803
}
28102804
}
28112805

2806+
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
2807+
secp256k1_scalar szero;
2808+
secp256k1_scalar sc[32];
2809+
secp256k1_ge pt[32];
2810+
secp256k1_gej r;
2811+
ecmult_multi_data data;
2812+
secp256k1_scratch *scratch_empty;
2813+
2814+
data.sc = sc;
2815+
data.pt = pt;
2816+
secp256k1_scalar_set_int(&szero, 0);
2817+
2818+
/* Try to multiply 1 point, but scratch space is empty.*/
2819+
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
2820+
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
2821+
secp256k1_scratch_destroy(scratch_empty);
2822+
}
2823+
28122824
void test_secp256k1_pippenger_bucket_window_inv(void) {
28132825
int i;
28142826

@@ -2932,19 +2944,25 @@ void test_ecmult_multi_batching(void) {
29322944
}
29332945
data.sc = sc;
29342946
data.pt = pt;
2947+
secp256k1_gej_neg(&r2, &r2);
29352948

2936-
/* Test with empty scratch space */
2949+
/* Test with empty scratch space. It should compute the correct result using
2950+
* ecmult_mult_simple algorithm which doesn't require a scratch space. */
29372951
scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
2938-
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
2952+
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
2953+
secp256k1_gej_add_var(&r, &r, &r2, NULL);
2954+
CHECK(secp256k1_gej_is_infinity(&r));
29392955
secp256k1_scratch_destroy(scratch);
29402956

29412957
/* Test with space for 1 point in pippenger. That's not enough because
2942-
* ecmult_multi selects strauss which requires more memory. */
2958+
* ecmult_multi selects strauss which requires more memory. It should
2959+
* therefore select the simple algorithm. */
29432960
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
2944-
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
2961+
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
2962+
secp256k1_gej_add_var(&r, &r, &r2, NULL);
2963+
CHECK(secp256k1_gej_is_infinity(&r));
29452964
secp256k1_scratch_destroy(scratch);
29462965

2947-
secp256k1_gej_neg(&r2, &r2);
29482966
for(i = 1; i <= n_points; i++) {
29492967
if (i > ECMULT_PIPPENGER_THRESHOLD) {
29502968
int bucket_window = secp256k1_pippenger_bucket_window(i);
@@ -2972,7 +2990,9 @@ void run_ecmult_multi_tests(void) {
29722990
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
29732991
test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
29742992
test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
2993+
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
29752994
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
2995+
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
29762996
secp256k1_scratch_destroy(scratch);
29772997

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

0 commit comments

Comments
 (0)