Changeset View
Changeset View
Standalone View
Standalone View
src/secp256k1/src/ecmult_impl.h
Show First 20 Lines • Show All 642 Lines • ▼ Show 20 Lines | |||||
#ifdef USE_ENDOMORPHISM | #ifdef USE_ENDOMORPHISM | ||||
static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); | static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); | ||||
#else | #else | ||||
static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); | static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); | ||||
#endif | #endif | ||||
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; | ||||
size_t i; | size_t i; | ||||
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); | |||||
secp256k1_gej_set_infinity(r); | secp256k1_gej_set_infinity(r); | ||||
if (inp_g_sc == NULL && n_points == 0) { | if (inp_g_sc == NULL && n_points == 0) { | ||||
return 1; | return 1; | ||||
} | } | ||||
if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) { | points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej)); | ||||
return 0; | scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); | ||||
} | state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); | ||||
points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej)); | state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); | ||||
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(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.zr = (secp256k1_fe*)secp256k1_scratch_alloc(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)); | ||||
if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL) { | |||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | |||||
return 0; | |||||
} | |||||
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_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | ||||
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_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | ||||
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. | ||||
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. | * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. | ||||
* It has the following guarantees: | * It has the following guarantees: | ||||
* - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) | * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) | ||||
* - the number of words set is always WNAF_SIZE(w) | * - the number of words set is always WNAF_SIZE(w) | ||||
* - the returned skew is 0 or 1 | * - the returned skew is 0 or 1 | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 Lines | #ifdef USE_ENDOMORPHISM | ||||
size_t entries = 2*n_points + 2; | size_t entries = 2*n_points + 2; | ||||
#else | #else | ||||
size_t entries = n_points + 1; | size_t entries = n_points + 1; | ||||
#endif | #endif | ||||
size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); | size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); | ||||
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) { | ||||
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); | |||||
/* 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. */ | ||||
#ifdef USE_ENDOMORPHISM | #ifdef USE_ENDOMORPHISM | ||||
size_t entries = 2*n_points + 2; | size_t entries = 2*n_points + 2; | ||||
#else | #else | ||||
size_t entries = n_points + 1; | size_t entries = n_points + 1; | ||||
#endif | #endif | ||||
secp256k1_ge *points; | secp256k1_ge *points; | ||||
secp256k1_scalar *scalars; | secp256k1_scalar *scalars; | ||||
secp256k1_gej *buckets; | secp256k1_gej *buckets; | ||||
struct secp256k1_pippenger_state *state_space; | struct secp256k1_pippenger_state *state_space; | ||||
size_t idx = 0; | size_t idx = 0; | ||||
size_t point_idx = 0; | size_t point_idx = 0; | ||||
int i, j; | int i, j; | ||||
int bucket_window; | int bucket_window; | ||||
(void)ctx; | (void)ctx; | ||||
secp256k1_gej_set_infinity(r); | secp256k1_gej_set_infinity(r); | ||||
if (inp_g_sc == NULL && n_points == 0) { | if (inp_g_sc == NULL && n_points == 0) { | ||||
return 1; | return 1; | ||||
} | } | ||||
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)) { | points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points)); | ||||
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars)); | |||||
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space)); | |||||
if (points == NULL || scalars == NULL || state_space == NULL) { | |||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | |||||
return 0; | |||||
} | |||||
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(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); | |||||
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets)); | |||||
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { | |||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | |||||
return 0; | return 0; | ||||
} | } | ||||
points = (secp256k1_ge *) secp256k1_scratch_alloc(scratch, entries * sizeof(*points)); | |||||
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(scratch, entries * sizeof(*scalars)); | |||||
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(scratch, sizeof(*state_space)); | |||||
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps)); | |||||
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); | |||||
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, sizeof(*buckets) << bucket_window); | |||||
if (inp_g_sc != NULL) { | if (inp_g_sc != NULL) { | ||||
scalars[0] = *inp_g_sc; | scalars[0] = *inp_g_sc; | ||||
points[0] = secp256k1_ge_const_g; | points[0] = secp256k1_ge_const_g; | ||||
idx++; | idx++; | ||||
#ifdef USE_ENDOMORPHISM | #ifdef USE_ENDOMORPHISM | ||||
secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); | secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); | ||||
idx++; | idx++; | ||||
#endif | #endif | ||||
} | } | ||||
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_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | ||||
return 0; | return 0; | ||||
} | } | ||||
idx++; | idx++; | ||||
#ifdef USE_ENDOMORPHISM | #ifdef USE_ENDOMORPHISM | ||||
secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); | secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); | ||||
idx++; | idx++; | ||||
#endif | #endif | ||||
point_idx++; | point_idx++; | ||||
} | } | ||||
secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); | secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx); | ||||
/* Clear data */ | /* Clear data */ | ||||
for(i = 0; (size_t)i < idx; i++) { | for(i = 0; (size_t)i < idx; i++) { | ||||
secp256k1_scalar_clear(&scalars[i]); | secp256k1_scalar_clear(&scalars[i]); | ||||
state_space->ps[i].skew_na = 0; | state_space->ps[i].skew_na = 0; | ||||
for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) { | for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) { | ||||
state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0; | state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0; | ||||
} | } | ||||
} | } | ||||
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_apply_checkpoint(error_callback, scratch, scratch_checkpoint); | ||||
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); | ||||
} | } | ||||
/** | /** | ||||
* Returns the maximum number of points in addition to G that can be used with | * Returns the maximum number of points in addition to G that can be used with | ||||
* 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; | ||||
for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { | for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) { | ||||
size_t n_points; | size_t n_points; | ||||
size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window); | size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window); | ||||
size_t space_for_points; | size_t space_for_points; | ||||
size_t space_overhead; | size_t space_overhead; | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | if (n == 0) { | ||||
return 1; | return 1; | ||||
} | } | ||||
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ | /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */ | ||||
*n_batches = 1 + (n - 1) / max_n_batch_points; | *n_batches = 1 + (n - 1) / max_n_batch_points; | ||||
*n_batch_points = 1 + (n - 1) / *n_batches; | *n_batch_points = 1 + (n - 1) / *n_batches; | ||||
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; | ||||
secp256k1_gej_set_infinity(r); | secp256k1_gej_set_infinity(r); | ||||
if (inp_g_sc == NULL && n == 0) { | if (inp_g_sc == NULL && n == 0) { | ||||
return 1; | return 1; | ||||
} else if (n == 0) { | } else if (n == 0) { | ||||
secp256k1_scalar szero; | secp256k1_scalar szero; | ||||
secp256k1_scalar_set_int(&szero, 0); | secp256k1_scalar_set_int(&szero, 0); | ||||
secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc); | secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc); | ||||
return 1; | return 1; | ||||
} | } | ||||
if (scratch == NULL) { | if (scratch == NULL) { | ||||
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's algorithm given a scratch space. If it's greater than | /* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than | ||||
* 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; | ||||
} | } | ||||
for(i = 0; i < n_batches; i++) { | for(i = 0; i < n_batches; i++) { | ||||
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); | ||||
n -= nbp; | n -= nbp; | ||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
#endif /* SECP256K1_ECMULT_IMPL_H */ | #endif /* SECP256K1_ECMULT_IMPL_H */ |