From bade6174173797ff4289adf28815dd381561ede3 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 20 Dec 2018 20:48:19 +0000 Subject: [PATCH] Add trivial ecmult_multi algorithm. It is selected when no scratch space is given and just multiplies and adds the points. --- src/ecmult.h | 3 ++- src/ecmult_impl.h | 30 ++++++++++++++++++++++++++++++ src/tests.c | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/ecmult.h b/src/ecmult.h index ea1cd8a..3d75a96 100644 --- a/src/ecmult.h +++ b/src/ecmult.h @@ -37,7 +37,8 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge * Chooses the right algorithm for a given number of points and scratch space * size. Resets and overwrites the given scratch space. If the points do not * fit in the scratch space the algorithm is repeatedly run with batches of - * points. + * points. If no scratch space is given then a simple algorithm is used that + * simply multiplies the points with the corresponding scalars and adds them up. * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) * 0 if there is not enough scratch space for a single point or * callback returns 0 diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index 508bde8..7c37821 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -1084,6 +1084,33 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) { return res; } +/* Computes ecmult_multi by simply multiplying and adding each point. Does not + * require a scratch space */ +static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) { + size_t point_idx; + secp256k1_scalar szero; + secp256k1_gej tmpj; + + secp256k1_scalar_set_int(&szero, 0); + secp256k1_gej_set_infinity(r); + secp256k1_gej_set_infinity(&tmpj); + /* r = inp_g_sc*G */ + secp256k1_ecmult(ctx, r, &tmpj, &szero, inp_g_sc); + for (point_idx = 0; point_idx < n_points; point_idx++) { + secp256k1_ge point; + secp256k1_gej pointj; + secp256k1_scalar scalar; + if (!cb(&scalar, &point, point_idx, cbdata)) { + return 0; + } + /* r += scalar*point */ + secp256k1_gej_set_ge(&pointj, &point); + secp256k1_ecmult(ctx, &tmpj, &pointj, &scalar, NULL); + secp256k1_gej_add_var(r, r, &tmpj, NULL); + } + 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; @@ -1102,6 +1129,9 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2 secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc); return 1; } + if (scratch == NULL) { + 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) { diff --git a/src/tests.c b/src/tests.c index 7189ef5..224ddc6 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2926,6 +2926,7 @@ void run_ecmult_multi_tests(void) { test_ecmult_multi_pippenger_max_points(); scratch = secp256k1_scratch_create(&ctx->error_callback, 819200); test_ecmult_multi(scratch, 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_strauss_batch_single); secp256k1_scratch_destroy(scratch);