Use trivial algorithm in ecmult_multi if scratch space is small
This commit is contained in:
parent
aa15154a48
commit
9ab96f7b12
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
42
src/tests.c
42
src/tests.c
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue