Skip to content

Commit 8c1c831

Browse files
sipajonasnick
authored andcommitted
Generalize Strauss to support multiple points
API by Andrew Poelstra.
1 parent 548de42 commit 8c1c831

File tree

4 files changed

+216
-56
lines changed

4 files changed

+216
-56
lines changed

src/ecmult.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**********************************************************************
2-
* Copyright (c) 2013, 2014 Pieter Wuille *
2+
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
33
* Distributed under the MIT software license, see the accompanying *
44
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
55
**********************************************************************/
@@ -9,6 +9,8 @@
99

1010
#include "num.h"
1111
#include "group.h"
12+
#include "scalar.h"
13+
#include "scratch.h"
1214

1315
typedef struct {
1416
/* For accelerating the computation of a*P + b*G: */
@@ -28,4 +30,9 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
2830
/** Double multiply: R = na*A + ng*G */
2931
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
3032

33+
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
34+
35+
/** Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. */
36+
static int secp256k1_ecmult_multi(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);
37+
3138
#endif /* SECP256K1_ECMULT_H */

src/ecmult_impl.h

+199-55
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**********************************************************************
2-
* Copyright (c) 2013, 2014 Pieter Wuille *
2+
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
33
* Distributed under the MIT software license, see the accompanying *
44
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
55
**********************************************************************/
@@ -283,50 +283,78 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
283283
return last_set_bit + 1;
284284
}
285285

286-
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
287-
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
288-
secp256k1_ge tmpa;
289-
secp256k1_fe Z;
286+
struct secp256k1_strauss_point_state {
290287
#ifdef USE_ENDOMORPHISM
291-
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
292288
secp256k1_scalar na_1, na_lam;
293-
/* Splitted G factors. */
294-
secp256k1_scalar ng_1, ng_128;
295289
int wnaf_na_1[130];
296290
int wnaf_na_lam[130];
297291
int bits_na_1;
298292
int bits_na_lam;
299-
int wnaf_ng_1[129];
300-
int bits_ng_1;
301-
int wnaf_ng_128[129];
302-
int bits_ng_128;
303293
#else
304294
int wnaf_na[256];
305295
int bits_na;
296+
#endif
297+
size_t input_pos;
298+
};
299+
300+
struct secp256k1_strauss_state {
301+
secp256k1_gej* prej;
302+
secp256k1_fe* zr;
303+
secp256k1_ge* pre_a;
304+
#ifdef USE_ENDOMORPHISM
305+
secp256k1_ge* pre_a_lam;
306+
#endif
307+
struct secp256k1_strauss_point_state* ps;
308+
};
309+
310+
static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, const struct secp256k1_strauss_state *state, secp256k1_gej *r, int num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
311+
secp256k1_ge tmpa;
312+
secp256k1_fe Z;
313+
#ifdef USE_ENDOMORPHISM
314+
/* Splitted G factors. */
315+
secp256k1_scalar ng_1, ng_128;
316+
int wnaf_ng_1[129];
317+
int bits_ng_1 = 0;
318+
int wnaf_ng_128[129];
319+
int bits_ng_128 = 0;
320+
#else
306321
int wnaf_ng[256];
307-
int bits_ng;
322+
int bits_ng = 0;
308323
#endif
309324
int i;
310-
int bits;
325+
int bits = 0;
326+
int np;
327+
int no = 0;
311328

329+
for (np = 0; np < num; ++np) {
330+
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
331+
continue;
332+
}
333+
state->ps[no].input_pos = np;
312334
#ifdef USE_ENDOMORPHISM
313-
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
314-
secp256k1_scalar_split_lambda(&na_1, &na_lam, na);
315-
316-
/* build wnaf representation for na_1 and na_lam. */
317-
bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A);
318-
bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A);
319-
VERIFY_CHECK(bits_na_1 <= 130);
320-
VERIFY_CHECK(bits_na_lam <= 130);
321-
bits = bits_na_1;
322-
if (bits_na_lam > bits) {
323-
bits = bits_na_lam;
324-
}
335+
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
336+
secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]);
337+
338+
/* build wnaf representation for na_1 and na_lam. */
339+
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 130, &state->ps[no].na_1, WINDOW_A);
340+
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 130, &state->ps[no].na_lam, WINDOW_A);
341+
VERIFY_CHECK(state->ps[no].bits_na_1 <= 130);
342+
VERIFY_CHECK(state->ps[no].bits_na_lam <= 130);
343+
if (state->ps[no].bits_na_1 > bits) {
344+
bits = state->ps[no].bits_na_1;
345+
}
346+
if (state->ps[no].bits_na_lam > bits) {
347+
bits = state->ps[no].bits_na_lam;
348+
}
325349
#else
326-
/* build wnaf representation for na. */
327-
bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A);
328-
bits = bits_na;
350+
/* build wnaf representation for na. */
351+
state->ps[no].bits_na = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na, 256, &na[np], WINDOW_A);
352+
if (state->ps[no].bits_na > bits) {
353+
bits = state->ps[no].bits_na;
354+
}
329355
#endif
356+
++no;
357+
}
330358

331359
/* Calculate odd multiples of a.
332360
* All multiples are brought to the same Z 'denominator', which is stored
@@ -338,29 +366,51 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
338366
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
339367
* isomorphism to efficiently add with a known Z inverse.
340368
*/
341-
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a);
369+
if (no > 0) {
370+
/* Compute the odd multiples in Jacobian form. */
371+
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
372+
for (np = 1; np < no; ++np) {
373+
secp256k1_gej tmp = a[state->ps[np].input_pos];
374+
#ifdef VERIFY
375+
secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
376+
#endif
377+
secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
378+
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
379+
secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
380+
}
381+
/* Bring them to the same Z denominator. */
382+
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
383+
} else {
384+
secp256k1_fe_set_int(&Z, 1);
385+
}
342386

343387
#ifdef USE_ENDOMORPHISM
344-
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
345-
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
388+
for (np = 0; np < no; ++np) {
389+
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
390+
secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]);
391+
}
346392
}
347393

348-
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
349-
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
394+
if (ng) {
395+
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
396+
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
350397

351-
/* Build wnaf representation for ng_1 and ng_128 */
352-
bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
353-
bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
354-
if (bits_ng_1 > bits) {
355-
bits = bits_ng_1;
356-
}
357-
if (bits_ng_128 > bits) {
358-
bits = bits_ng_128;
398+
/* Build wnaf representation for ng_1 and ng_128 */
399+
bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
400+
bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
401+
if (bits_ng_1 > bits) {
402+
bits = bits_ng_1;
403+
}
404+
if (bits_ng_128 > bits) {
405+
bits = bits_ng_128;
406+
}
359407
}
360408
#else
361-
bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
362-
if (bits_ng > bits) {
363-
bits = bits_ng;
409+
if (ng) {
410+
bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
411+
if (bits_ng > bits) {
412+
bits = bits_ng;
413+
}
364414
}
365415
#endif
366416

@@ -370,13 +420,15 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
370420
int n;
371421
secp256k1_gej_double_var(r, r, NULL);
372422
#ifdef USE_ENDOMORPHISM
373-
if (i < bits_na_1 && (n = wnaf_na_1[i])) {
374-
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
375-
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
376-
}
377-
if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
378-
ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
379-
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
423+
for (np = 0; np < no; ++np) {
424+
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
425+
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
426+
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
427+
}
428+
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
429+
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
430+
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
431+
}
380432
}
381433
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
382434
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
@@ -387,9 +439,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
387439
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
388440
}
389441
#else
390-
if (i < bits_na && (n = wnaf_na[i])) {
391-
ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
392-
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
442+
for (np = 0; np < no; ++np) {
443+
if (i < state->ps[np].bits_na && (n = state->ps[np].wnaf_na[i])) {
444+
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
445+
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
446+
}
393447
}
394448
if (i < bits_ng && (n = wnaf_ng[i])) {
395449
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
@@ -403,4 +457,94 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
403457
}
404458
}
405459

460+
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
461+
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
462+
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
463+
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
464+
struct secp256k1_strauss_point_state ps[1];
465+
#ifdef USE_ENDOMORPHISM
466+
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
467+
#endif
468+
struct secp256k1_strauss_state state;
469+
470+
state.prej = prej;
471+
state.zr = zr;
472+
state.pre_a = pre_a;
473+
#ifdef USE_ENDOMORPHISM
474+
state.pre_a_lam = pre_a_lam;
475+
#endif
476+
state.ps = ps;
477+
secp256k1_ecmult_strauss_wnaf(ctx, &state, r, 1, a, na, ng);
478+
}
479+
480+
static int secp256k1_ecmult_multi_split_strauss_wnaf(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) {
481+
secp256k1_gej* points;
482+
secp256k1_scalar* scalars;
483+
secp256k1_gej acc;
484+
size_t in_pos = 0, out_pos = 0;
485+
int first = 1;
486+
487+
#ifdef USE_ENDOMORPHISM
488+
static const size_t point_size = (sizeof(secp256k1_gej) + sizeof(secp256k1_fe) + sizeof(secp256k1_ge) * 2) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
489+
#else
490+
static const size_t point_size = (sizeof(secp256k1_gej) + sizeof(secp256k1_fe) + sizeof(secp256k1_ge)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
491+
#endif
492+
493+
size_t max_points = secp256k1_scratch_max_allocation(scratch, 6) / point_size;
494+
size_t n_batches, points_per_batch;
495+
struct secp256k1_strauss_state state;
496+
497+
if (max_points == 0) return 0;
498+
if (max_points > 160) max_points = 160; /* At this point, gains are not longer compensating for locality degradation */
499+
n_batches = (n + max_points - 1) / max_points;
500+
points_per_batch = (n + n_batches - 1) / n_batches;
501+
502+
/* Attempt to allocate sufficient space for Strauss */
503+
while (!secp256k1_scratch_resize(scratch, max_points * point_size, 6)) {
504+
max_points /= 2;
505+
if (max_points == 0) {
506+
return 0;
507+
}
508+
}
509+
510+
secp256k1_scratch_reset(scratch);
511+
points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, max_points * sizeof(secp256k1_gej));
512+
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, max_points * sizeof(secp256k1_scalar));
513+
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, max_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
514+
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, max_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
515+
#ifdef USE_ENDOMORPHISM
516+
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, max_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
517+
state.pre_a_lam = state.pre_a + max_points * ECMULT_TABLE_SIZE(WINDOW_A);
518+
#else
519+
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, max_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
520+
#endif
521+
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, max_points * sizeof(struct secp256k1_strauss_point_state));
522+
523+
if (n == 0 && inp_g_sc) {
524+
secp256k1_ecmult_strauss_wnaf(ctx, &state, r, 0, NULL, NULL, inp_g_sc);
525+
return 1;
526+
}
527+
528+
while (in_pos < n) {
529+
secp256k1_ge point;
530+
if (!cb(&scalars[out_pos], &point, in_pos, cbdata)) return 0;
531+
secp256k1_gej_set_ge(&points[out_pos], &point);
532+
++in_pos;
533+
++out_pos;
534+
if (out_pos == points_per_batch || in_pos == n) {
535+
secp256k1_ecmult_strauss_wnaf(ctx, &state, first ? r : &acc, out_pos, points, scalars, first ? inp_g_sc : NULL);
536+
if (!first) {
537+
secp256k1_gej_add_var(r, r, &acc, NULL);
538+
}
539+
first = 0;
540+
out_pos = 0;
541+
}
542+
}
543+
return 1;
544+
}
545+
546+
static int secp256k1_ecmult_multi(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) {
547+
return secp256k1_ecmult_multi_split_strauss_wnaf(ctx, scratch, r, inp_g_sc, cb, cbdata, n);
548+
}
549+
406550
#endif /* SECP256K1_ECMULT_IMPL_H */

src/group.h

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej
7979
* stored in globalz. */
8080
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
8181

82+
/** Set a group element (affine) equal to the point at infinity. */
83+
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
84+
8285
/** Set a group element (jacobian) equal to the point at infinity. */
8386
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
8487

src/group_impl.h

+6
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
200200
secp256k1_fe_clear(&r->z);
201201
}
202202

203+
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
204+
r->infinity = 1;
205+
secp256k1_fe_clear(&r->x);
206+
secp256k1_fe_clear(&r->y);
207+
}
208+
203209
static void secp256k1_gej_clear(secp256k1_gej *r) {
204210
r->infinity = 0;
205211
secp256k1_fe_clear(&r->x);

0 commit comments

Comments
 (0)