Skip to content

Commit 90ff155

Browse files
committed
Fix integer overflow in ecmult_multi_var when n is large
1 parent 197bf24 commit 90ff155

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

src/ecmult_impl.h

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -972,12 +972,33 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
972972
return res;
973973
}
974974

975+
/* Compute the number and size of batches given the maximum number of points in a batch and the
976+
* total number of points */
977+
static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_points, size_t n) {
978+
if (max_points == 0) {
979+
return 0;
980+
}
981+
if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
982+
max_points = ECMULT_MAX_POINTS_PER_BATCH;
983+
}
984+
/* Check overflow */
985+
if (n > (size_t)-1 - (max_points-1)) {
986+
return 0;
987+
}
988+
*n_batches = (n + (max_points-1)) / max_points;
989+
/* Check overflow */
990+
if (n_batches == 0 || n > (size_t)-1 - (*n_batches-1)) {
991+
return 0;
992+
}
993+
*n_batch_points = (n + (*n_batches-1)) / *n_batches;
994+
return 1;
995+
}
996+
975997
typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
976998
static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
977999
size_t i;
9781000

9791001
int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
980-
size_t max_points;
9811002
size_t n_batches;
9821003
size_t n_batch_points;
9831004

@@ -991,24 +1012,17 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
9911012
return 1;
9921013
}
9931014

994-
max_points = secp256k1_pippenger_max_points(scratch);
995-
if (max_points == 0) {
1015+
/* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold
1016+
* use pippenger. Otherwise use strauss */
1017+
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
9961018
return 0;
997-
} else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
998-
max_points = ECMULT_MAX_POINTS_PER_BATCH;
9991019
}
1000-
n_batches = (n+max_points-1)/max_points;
1001-
n_batch_points = (n+n_batches-1)/n_batches;
1002-
10031020
if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
10041021
f = secp256k1_ecmult_pippenger_batch;
10051022
} else {
1006-
max_points = secp256k1_strauss_max_points(scratch);
1007-
if (max_points == 0) {
1023+
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
10081024
return 0;
10091025
}
1010-
n_batches = (n+max_points-1)/max_points;
1011-
n_batch_points = (n+n_batches-1)/n_batches;
10121026
f = secp256k1_ecmult_strauss_batch;
10131027
}
10141028
for(i = 0; i < n_batches; i++) {

src/tests.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,6 +2903,27 @@ void test_ecmult_multi_batching(void) {
29032903
free(pt);
29042904
}
29052905

2906+
void test_ecmult_multi_overflow_n(void) {
2907+
secp256k1_scratch *scratch;
2908+
secp256k1_gej r;
2909+
ecmult_multi_data data;
2910+
2911+
/* Set number of points n to (size_t)-1 and max_points to 2. n_batches is computed as (n+2-1)/2 =
2912+
* 0, so if the overflow wasn't caught ecmult_multi wouldn't do any multiplication. */
2913+
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(2, secp256k1_pippenger_bucket_window(2)) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
2914+
CHECK(secp256k1_pippenger_max_points(scratch) == 2);
2915+
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, (size_t)-1) == 0);
2916+
secp256k1_scratch_destroy(scratch);
2917+
2918+
/* Set number of points n to (size_t)-1/2+2 and max_points to 1. n_batches is computed as n and
2919+
* n_batch_points = (n + n-1)/n = 1/n = 0 which would result in an infinite loop if the overflow
2920+
* wasn't caught */
2921+
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
2922+
CHECK(secp256k1_strauss_max_points(scratch) == 1);
2923+
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, ((size_t)-1)/2+2) == 0);
2924+
secp256k1_scratch_destroy(scratch);
2925+
}
2926+
29062927
void run_ecmult_multi_tests(void) {
29072928
secp256k1_scratch *scratch;
29082929

@@ -2920,6 +2941,7 @@ void run_ecmult_multi_tests(void) {
29202941
secp256k1_scratch_destroy(scratch);
29212942

29222943
test_ecmult_multi_batching();
2944+
test_ecmult_multi_overflow_n();
29232945
}
29242946

29252947
void test_wnaf(const secp256k1_scalar *number, int w) {

0 commit comments

Comments
 (0)