scratch space: thread error_callback into all scratch space functions

Use it when checking magic bytes
This commit is contained in:
Andrew Poelstra 2019-03-13 23:30:51 +00:00
parent 0be1a4ae62
commit c2b028a281
9 changed files with 130 additions and 104 deletions

View File

@ -295,11 +295,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_sc
/** Destroy a secp256k1 scratch space. /** Destroy a secp256k1 scratch space.
* *
* The pointer may not be used afterwards. * The pointer may not be used afterwards.
* Args: scratch: space to destroy * Args: ctx: a secp256k1 context object.
* scratch: space to destroy
*/ */
SECP256K1_API void secp256k1_scratch_space_destroy( SECP256K1_API void secp256k1_scratch_space_destroy(
const secp256k1_context* ctx,
secp256k1_scratch_space* scratch secp256k1_scratch_space* scratch
); ) SECP256K1_ARG_NONNULL(1);
/** Parse a variable-length public key into the pubkey object. /** Parse a variable-length public key into the pubkey object.
* *

View File

@ -64,7 +64,7 @@ static void bench_ecmult(void* arg) {
size_t iter; size_t iter;
for (iter = 0; iter < iters; ++iter) { for (iter = 0; iter < iters; ++iter) {
data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g); data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
data->offset1 = (data->offset1 + count) % POINTS; data->offset1 = (data->offset1 + count) % POINTS;
data->offset2 = (data->offset2 + count - 1) % POINTS; data->offset2 = (data->offset2 + count - 1) % POINTS;
} }
@ -154,7 +154,7 @@ int main(int argc, char **argv) {
} else if(have_flag(argc, argv, "simple")) { } else if(have_flag(argc, argv, "simple")) {
printf("Using simple algorithm:\n"); printf("Using simple algorithm:\n");
data.ecmult_multi = secp256k1_ecmult_multi_var; data.ecmult_multi = secp256k1_ecmult_multi_var;
secp256k1_scratch_space_destroy(data.scratch); secp256k1_scratch_space_destroy(data.ctx, data.scratch);
data.scratch = NULL; data.scratch = NULL;
} else { } else {
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]); fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
@ -193,10 +193,10 @@ int main(int argc, char **argv) {
run_test(&data, i << p, 1); run_test(&data, i << p, 1);
} }
} }
secp256k1_context_destroy(data.ctx);
if (data.scratch != NULL) { if (data.scratch != NULL) {
secp256k1_scratch_space_destroy(data.scratch); secp256k1_scratch_space_destroy(data.ctx, data.scratch);
} }
secp256k1_context_destroy(data.ctx);
free(data.scalars); free(data.scalars);
free(data.pubkeys); free(data.pubkeys);
free(data.seckeys); free(data.seckeys);

View File

@ -43,6 +43,6 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge
* 0 if there is not enough scratch space for a single point or * 0 if there is not enough scratch space for a single point or
* callback returns 0 * callback returns 0
*/ */
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); static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, 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);
#endif /* SECP256K1_ECMULT_H */ #endif /* SECP256K1_ECMULT_H */

View File

@ -648,7 +648,7 @@ static size_t secp256k1_strauss_scratch_size(size_t n_points) {
return n_points*point_size; return n_points*point_size;
} }
static int secp256k1_ecmult_strauss_batch(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_points, size_t cb_offset) { static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, 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_points, size_t cb_offset) {
secp256k1_gej* points; secp256k1_gej* points;
secp256k1_scalar* scalars; secp256k1_scalar* scalars;
struct secp256k1_strauss_state state; struct secp256k1_strauss_state state;
@ -659,41 +659,41 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_ecmult_context *ctx, s
return 1; return 1;
} }
if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) { if (!secp256k1_scratch_allocate_frame(error_callback, scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) {
return 0; return 0;
} }
points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej)); points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_scalar)); scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
#ifdef USE_ENDOMORPHISM #ifdef USE_ENDOMORPHISM
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A); state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A);
#else #else
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
#endif #endif
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
for (i = 0; i < n_points; i++) { for (i = 0; i < n_points; i++) {
secp256k1_ge point; secp256k1_ge point;
if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) {
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(error_callback, scratch);
return 0; return 0;
} }
secp256k1_gej_set_ge(&points[i], &point); secp256k1_gej_set_ge(&points[i], &point);
} }
secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc); secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc);
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(error_callback, scratch);
return 1; return 1;
} }
/* Wrapper for secp256k1_ecmult_multi_func interface */ /* Wrapper for secp256k1_ecmult_multi_func interface */
static int secp256k1_ecmult_strauss_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); return secp256k1_ecmult_strauss_batch(error_callback, actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
} }
static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) { static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
return secp256k1_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1); return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1);
} }
/** Convert a number to WNAF notation. /** Convert a number to WNAF notation.
@ -985,7 +985,7 @@ static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_windo
return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size;
} }
static int secp256k1_ecmult_pippenger_batch(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_points, size_t cb_offset) { static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, 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_points, size_t cb_offset) {
/* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch /* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch
* sizes. The reason for +1 is that we add the G scalar to the list of * sizes. The reason for +1 is that we add the G scalar to the list of
* other scalars. */ * other scalars. */
@ -1010,15 +1010,15 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
} }
bucket_window = secp256k1_pippenger_bucket_window(n_points); bucket_window = secp256k1_pippenger_bucket_window(n_points);
if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points, bucket_window), PIPPENGER_SCRATCH_OBJECTS)) { if (!secp256k1_scratch_allocate_frame(error_callback, scratch, secp256k1_pippenger_scratch_size(n_points, bucket_window), PIPPENGER_SCRATCH_OBJECTS)) {
return 0; return 0;
} }
points = (secp256k1_ge *) secp256k1_scratch_alloc(scratch, entries * sizeof(*points)); points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points));
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(scratch, entries * sizeof(*scalars)); scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars));
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(scratch, sizeof(*state_space)); state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space));
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps)); state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, sizeof(*buckets) << bucket_window); buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets));
if (inp_g_sc != NULL) { if (inp_g_sc != NULL) {
scalars[0] = *inp_g_sc; scalars[0] = *inp_g_sc;
@ -1032,7 +1032,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
while (point_idx < n_points) { while (point_idx < n_points) {
if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) { if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) {
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(error_callback, scratch);
return 0; return 0;
} }
idx++; idx++;
@ -1056,13 +1056,13 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
for(i = 0; i < 1<<bucket_window; i++) { for(i = 0; i < 1<<bucket_window; i++) {
secp256k1_gej_clear(&buckets[i]); secp256k1_gej_clear(&buckets[i]);
} }
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(error_callback, scratch);
return 1; return 1;
} }
/* Wrapper for secp256k1_ecmult_multi_func interface */ /* Wrapper for secp256k1_ecmult_multi_func interface */
static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) { static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_pippenger_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); return secp256k1_ecmult_pippenger_batch(error_callback, actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
} }
/** /**
@ -1070,8 +1070,8 @@ static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_ecmult_contex
* a given scratch space. The function ensures that fewer points may also be * a given scratch space. The function ensures that fewer points may also be
* used. * used.
*/ */
static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) { static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
size_t max_alloc = secp256k1_scratch_max_allocation(scratch, PIPPENGER_SCRATCH_OBJECTS); size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS);
int bucket_window; int bucket_window;
size_t res = 0; size_t res = 0;
@ -1153,11 +1153,11 @@ static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n
return 1; 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); typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, 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) { static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, 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; 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); int (*f)(const secp256k1_callback* error_callback, const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
size_t n_batches; size_t n_batches;
size_t n_batch_points; size_t n_batch_points;
@ -1178,13 +1178,13 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
* a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm. * 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 * 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. */ * 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(error_callback, scratch), n)) {
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);
} }
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(error_callback, scratch), n)) {
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);
} }
f = secp256k1_ecmult_strauss_batch; f = secp256k1_ecmult_strauss_batch;
@ -1193,7 +1193,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
size_t nbp = n < n_batch_points ? n : n_batch_points; size_t nbp = n < n_batch_points ? n : n_batch_points;
size_t offset = n_batch_points*i; size_t offset = n_batch_points*i;
secp256k1_gej tmp; secp256k1_gej tmp;
if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { if (!f(error_callback, ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) {
return 0; return 0;
} }
secp256k1_gej_add_var(r, r, &tmp, NULL); secp256k1_gej_add_var(r, r, &tmp, NULL);

View File

@ -23,18 +23,18 @@ typedef struct secp256k1_scratch_space_struct {
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch); static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */ /** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects); static int secp256k1_scratch_allocate_frame(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n, size_t objects);
/** Deallocates a stack frame */ /** Deallocates a stack frame */
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch); static void secp256k1_scratch_deallocate_frame(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
/** Returns the maximum allocation the scratch space will allow */ /** Returns the maximum allocation the scratch space will allow */
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects); static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects);
/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ /** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n); static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n);
#endif #endif

View File

@ -21,10 +21,11 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err
return ret; return ret;
} }
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) { static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) { if (scratch != NULL) {
VERIFY_CHECK(scratch->frame == 0); VERIFY_CHECK(scratch->frame == 0);
if (memcmp(scratch->magic, "scratch", 8) != 0) { if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return; return;
} }
memset(scratch->magic, 0, sizeof(scratch->magic)); memset(scratch->magic, 0, sizeof(scratch->magic));
@ -33,10 +34,11 @@ static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) {
} }
} }
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) { static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) {
size_t i = 0; size_t i = 0;
size_t allocated = 0; size_t allocated = 0;
if (memcmp(scratch->magic, "scratch", 8) != 0) { if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return 0; return 0;
} }
for (i = 0; i < scratch->frame; i++) { for (i = 0; i < scratch->frame; i++) {
@ -48,14 +50,15 @@ static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch,
return scratch->max_size - allocated - objects * ALIGNMENT; return scratch->max_size - allocated - objects * ALIGNMENT;
} }
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) { static int secp256k1_scratch_allocate_frame(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n, size_t objects) {
VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES); VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES);
if (memcmp(scratch->magic, "scratch", 8) != 0) { if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return 0; return 0;
} }
if (n <= secp256k1_scratch_max_allocation(scratch, objects)) { if (n <= secp256k1_scratch_max_allocation(error_callback, scratch, objects)) {
n += objects * ALIGNMENT; n += objects * ALIGNMENT;
scratch->current_frame = scratch->data; scratch->current_frame = scratch->data;
scratch->data = (void *) ((char *) scratch->data + n); scratch->data = (void *) ((char *) scratch->data + n);
@ -68,23 +71,25 @@ static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n
} }
} }
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) { static void secp256k1_scratch_deallocate_frame(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
VERIFY_CHECK(scratch->frame > 0);
if (memcmp(scratch->magic, "scratch", 8) != 0) { if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return; return;
} }
VERIFY_CHECK(scratch->frame > 0);
scratch->frame--; scratch->frame--;
scratch->data = (void *) ((char *) scratch->data - scratch->frame_size[scratch->frame]); scratch->data = (void *) ((char *) scratch->data - scratch->frame_size[scratch->frame]);
} }
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) { static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
void *ret; void *ret;
size_t frame = scratch->frame - 1; size_t frame = scratch->frame - 1;
size = ROUND_TO_ALIGN(size); size = ROUND_TO_ALIGN(size);
if (memcmp(scratch->magic, "scratch", 8) != 0) { if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return NULL; return NULL;
} }

View File

@ -199,8 +199,9 @@ secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context*
return secp256k1_scratch_create(&ctx->error_callback, max_size); return secp256k1_scratch_create(&ctx->error_callback, max_size);
} }
void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) { void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
secp256k1_scratch_destroy(scratch); VERIFY_CHECK(ctx != NULL);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
} }
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {

View File

@ -336,37 +336,55 @@ void run_scratch_tests(void) {
int32_t ecount = 0; int32_t ecount = 0;
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_scratch_space *scratch; secp256k1_scratch_space *scratch;
secp256k1_scratch_space local_scratch;
/* Test public API */ /* Test public API */
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
scratch = secp256k1_scratch_space_create(none, 1000); scratch = secp256k1_scratch_space_create(none, 1000);
CHECK(scratch != NULL); CHECK(scratch != NULL);
CHECK(ecount == 0); CHECK(ecount == 0);
/* Test internal API */ /* Test internal API */
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 1000); CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) < 1000);
/* Allocating 500 bytes with no frame fails */ /* Allocating 500 bytes with no frame fails */
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
/* ...but pushing a new stack frame does affect the max allocation */ /* ...but pushing a new stack frame does affect the max allocation */
CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1 == 1)); CHECK(secp256k1_scratch_allocate_frame(&none->error_callback, scratch, 500, 1) == 1);
CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */ CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) < 500); /* 500 - ALIGNMENT */
CHECK(secp256k1_scratch_alloc(scratch, 500) != NULL); CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1) == 0); CHECK(secp256k1_scratch_allocate_frame(&none->error_callback, scratch, 500, 1) == 0);
/* ...and this effect is undone by popping the frame */ /* ...and this effect is undone by popping the frame */
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(&none->error_callback, scratch);
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000); CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL); CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
/* cleanup */ /* cleanup */
secp256k1_scratch_space_destroy(scratch); secp256k1_scratch_space_destroy(none, scratch);
CHECK(ecount == 0);
/* try to use badly initialized scratch space */
memset(&local_scratch, 0, sizeof(local_scratch));
scratch = &local_scratch;
CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0));
CHECK(ecount == 1);
CHECK(secp256k1_scratch_allocate_frame(&none->error_callback, scratch, 500, 1) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(ecount == 3);
secp256k1_scratch_deallocate_frame(&none->error_callback, scratch);
CHECK(ecount == 4);
secp256k1_scratch_space_destroy(none, scratch);
CHECK(ecount == 5);
secp256k1_context_destroy(none); secp256k1_context_destroy(none);
} }
@ -2655,7 +2673,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_set_int(&szero, 0); secp256k1_scalar_set_int(&szero, 0);
/* No points to multiply */ /* No points to multiply */
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
/* Check 1- and 2-point multiplies against ecmult */ /* Check 1- and 2-point multiplies against ecmult */
for (ncount = 0; ncount < count; ncount++) { for (ncount = 0; ncount < count; ncount++) {
@ -2671,31 +2689,31 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
/* only G scalar */ /* only G scalar */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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));
/* 1-point */ /* 1-point */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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 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->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
/* 2-point */ /* 2-point */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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));
/* 2-point with G scalar */ /* 2-point with G scalar */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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));
@ -2712,7 +2730,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
random_scalar_order(&sc[i]); random_scalar_order(&sc[i]);
secp256k1_ge_set_infinity(&pt[i]); secp256k1_ge_set_infinity(&pt[i]);
} }
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
} }
@ -2722,7 +2740,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[i] = ptg; pt[i] = ptg;
secp256k1_scalar_set_int(&sc[i], 0); secp256k1_scalar_set_int(&sc[i], 0);
} }
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
} }
@ -2735,7 +2753,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[2 * i + 1] = ptg; pt[2 * i + 1] = ptg;
} }
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
random_scalar_order(&sc[0]); random_scalar_order(&sc[0]);
@ -2748,7 +2766,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]); secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
} }
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
} }
@ -2763,7 +2781,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_negate(&sc[i], &sc[i]); secp256k1_scalar_negate(&sc[i], &sc[i]);
} }
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
} }
@ -2782,7 +2800,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
} }
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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));
@ -2805,7 +2823,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej_set_ge(&p0j, &pt[0]); secp256k1_gej_set_ge(&p0j, &pt[0]);
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero); secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2); secp256k1_gej_neg(&r2, &r2);
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));
@ -2818,13 +2836,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
} }
secp256k1_scalar_clear(&sc[0]); secp256k1_scalar_clear(&sc[0]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_scalar_clear(&sc[1]); secp256k1_scalar_clear(&sc[1]);
secp256k1_scalar_clear(&sc[2]); secp256k1_scalar_clear(&sc[2]);
secp256k1_scalar_clear(&sc[3]); secp256k1_scalar_clear(&sc[3]);
secp256k1_scalar_clear(&sc[4]); secp256k1_scalar_clear(&sc[4]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
CHECK(secp256k1_gej_is_infinity(&r)); CHECK(secp256k1_gej_is_infinity(&r));
/* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
@ -2869,7 +2887,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_add(&tmp1, &tmp1, &tmp2); secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero); secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&expected, &expected); secp256k1_gej_neg(&expected, &expected);
secp256k1_gej_add_var(&actual, &actual, &expected, NULL); secp256k1_gej_add_var(&actual, &actual, &expected, NULL);
CHECK(secp256k1_gej_is_infinity(&actual)); CHECK(secp256k1_gej_is_infinity(&actual));
@ -2894,8 +2912,8 @@ void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
/* Try to multiply 1 point, but scratch space is empty.*/ /* Try to multiply 1 point, but scratch space is empty.*/
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0); scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); CHECK(!ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch_empty); secp256k1_scratch_destroy(&ctx->error_callback, scratch_empty);
} }
void test_secp256k1_pippenger_bucket_window_inv(void) { void test_secp256k1_pippenger_bucket_window_inv(void) {
@ -2930,15 +2948,15 @@ void test_ecmult_multi_pippenger_max_points(void) {
for(; scratch_size < max_size; scratch_size+=256) { for(; scratch_size < max_size; scratch_size+=256) {
scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size); scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size);
CHECK(scratch != NULL); CHECK(scratch != NULL);
n_points_supported = secp256k1_pippenger_max_points(scratch); n_points_supported = secp256k1_pippenger_max_points(&ctx->error_callback, scratch);
if (n_points_supported == 0) { if (n_points_supported == 0) {
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
continue; continue;
} }
bucket_window = secp256k1_pippenger_bucket_window(n_points_supported); bucket_window = secp256k1_pippenger_bucket_window(n_points_supported);
CHECK(secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS)); CHECK(secp256k1_scratch_allocate_frame(&ctx->error_callback, scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS));
secp256k1_scratch_deallocate_frame(scratch); secp256k1_scratch_deallocate_frame(&ctx->error_callback, scratch);
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
} }
CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
} }
@ -3026,19 +3044,19 @@ void test_ecmult_multi_batching(void) {
/* Test with empty scratch space. It should compute the correct result using /* Test with empty scratch space. It should compute the correct result using
* ecmult_mult_simple algorithm which doesn't require a scratch space. */ * 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, n_points)); CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
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));
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, 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. It should * ecmult_multi selects strauss which requires more memory. It should
* therefore select the simple algorithm. */ * 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, n_points)); CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
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));
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
for(i = 1; i <= n_points; i++) { for(i = 1; i <= n_points; i++) {
if (i > ECMULT_PIPPENGER_THRESHOLD) { if (i > ECMULT_PIPPENGER_THRESHOLD) {
@ -3049,10 +3067,10 @@ void test_ecmult_multi_batching(void) {
size_t scratch_size = secp256k1_strauss_scratch_size(i); size_t scratch_size = secp256k1_strauss_scratch_size(i);
scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
} }
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
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));
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
} }
free(sc); free(sc);
free(pt); free(pt);
@ -3070,12 +3088,12 @@ void run_ecmult_multi_tests(void) {
test_ecmult_multi_batch_single(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); test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
/* Run test_ecmult_multi with space for exactly one point */ /* Run test_ecmult_multi with space for exactly one point */
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var); test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
test_ecmult_multi_batch_size_helper(); test_ecmult_multi_batch_size_helper();
test_ecmult_multi_batching(); test_ecmult_multi_batching();

View File

@ -212,14 +212,14 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_
data.pt[0] = group[x]; data.pt[0] = group[x];
data.pt[1] = group[y]; data.pt[1] = group[y];
secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp); ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp);
} }
} }
} }
} }
} }
secp256k1_scratch_destroy(scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
} }
void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {