Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix integer overflow in ecmult_multi_var when n is large #568

Merged
merged 1 commit into from
Feb 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions src/ecmult_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1111,12 +1111,31 @@ static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx
return 1;
}

/* Compute the number of batches and the batch size given the maximum batch size and the
* total number of points */
static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) {
if (max_n_batch_points == 0) {
return 0;
}
if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) {
max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
}
if (n == 0) {
*n_batches = 0;
*n_batch_points = 0;
return 1;
}
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
*n_batches = 1 + (n - 1) / max_n_batch_points;
*n_batch_points = 1 + (n - 1) / *n_batches;
return 1;
}

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);
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) {
size_t i;

int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
size_t max_points;
size_t n_batches;
size_t n_batch_points;

Expand All @@ -1133,24 +1152,17 @@ 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);
}

max_points = secp256k1_pippenger_max_points(scratch);
if (max_points == 0) {
/* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold
* use pippenger. Otherwise use strauss */
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
return 0;
} else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
max_points = ECMULT_MAX_POINTS_PER_BATCH;
}
n_batches = (n+max_points-1)/max_points;
n_batch_points = (n+n_batches-1)/n_batches;

if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
f = secp256k1_ecmult_pippenger_batch;
} else {
max_points = secp256k1_strauss_max_points(scratch);
if (max_points == 0) {
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
return 0;
}
n_batches = (n+max_points-1)/max_points;
n_batch_points = (n+n_batches-1)/n_batches;
f = secp256k1_ecmult_strauss_batch;
}
for(i = 0; i < n_batches; i++) {
Expand Down
45 changes: 45 additions & 0 deletions src/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -2854,6 +2854,50 @@ void test_ecmult_multi_pippenger_max_points(void) {
CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
}

void test_ecmult_multi_batch_size_helper(void) {
size_t n_batches, n_batch_points, max_n_batch_points, n;

max_n_batch_points = 0;
n = 1;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0);

max_n_batch_points = 1;
n = 0;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 0);
CHECK(n_batch_points == 0);

max_n_batch_points = 2;
n = 5;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 3);
CHECK(n_batch_points == 2);

max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
n = ECMULT_MAX_POINTS_PER_BATCH;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 1);
CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH);

max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1;
n = ECMULT_MAX_POINTS_PER_BATCH + 1;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 2);
CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1);

max_n_batch_points = 1;
n = SIZE_MAX;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == SIZE_MAX);
CHECK(n_batch_points == 1);

max_n_batch_points = 2;
n = SIZE_MAX;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == SIZE_MAX/2 + 1);
CHECK(n_batch_points == 2);
}

/**
* Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to
* 1 <= i <= num points.
Expand Down Expand Up @@ -2936,6 +2980,7 @@ void run_ecmult_multi_tests(void) {
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
secp256k1_scratch_destroy(scratch);

test_ecmult_multi_batch_size_helper();
test_ecmult_multi_batching();
}

Expand Down