Skip to content

Commit 1ae98bb

Browse files
peterdettmansipa
authored andcommitted
Signed-digit multi-comb ecmult_gen algorithm
This introduces the signed-digit multi-comb multiplication algorithm for constant-time G multiplications (ecmult_gen). It is based on section 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg (see https://eprint.iacr.org/2012/309). Original implementation by Peter Dettman, with changes by Pieter Wuille to use scalars for recoding, and additional comments.
1 parent 6a792b6 commit 1ae98bb

8 files changed

+646
-9854
lines changed

src/ecmult_gen.h

+72-5
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, 2021 Pieter Wuille, Peter Dettman *
33
* Distributed under the MIT software license, see the accompanying *
44
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
55
***********************************************************************/
@@ -10,11 +10,78 @@
1010
#include "scalar.h"
1111
#include "group.h"
1212

13-
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
14-
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
13+
/* Configuration parameters for the signed-digit multi-comb algorithm:
14+
*
15+
* - COMB_BLOCKS is the number of lookup tables.
16+
* - COMB_TEETH is the number of bits covered by one table.
17+
*
18+
* The comb's spacing (COMB_SPACING), or the distance between the teeth,
19+
* is defined as ceil(256 / (COMB_BLOCKS * COMB_TEETH)).
20+
*
21+
* The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1))
22+
* secp256k1_ge_storages.
23+
*
24+
* The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point
25+
* addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a
26+
* conditional negation.
27+
*
28+
* The number of point doublings is COMB_SPACING - 1. */
29+
30+
#if defined(EXHAUSTIVE_TEST_ORDER)
31+
/* We need to control these values for exhaustive tests because
32+
* the tables cannot have infinities in them (secp256k1_ge_storage
33+
* doesn't support infinities) */
34+
# undef COMB_BLOCKS
35+
# undef COMB_TEETH
36+
# if EXHAUSTIVE_TEST_ORDER > 32
37+
# define COMB_BLOCKS 52
38+
# define COMB_TEETH 5
39+
# elif EXHAUSTIVE_TEST_ORDER > 16
40+
# define COMB_BLOCKS 64
41+
# define COMB_TEETH 4
42+
# elif EXHAUSTIVE_TEST_ORDER > 8
43+
# define COMB_BLOCKS 86
44+
# define COMB_TEETH 3
45+
# elif EXHAUSTIVE_TEST_ORDER > 4
46+
# define COMB_BLOCKS 128
47+
# define COMB_TEETH 2
48+
# else
49+
# define COMB_BLOCKS 256
50+
# define COMB_TEETH 1
51+
# endif
52+
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
53+
/* Use (11, 6) as default configuration, which results in a 22 kB table. */
54+
# ifndef COMB_BLOCKS
55+
# define COMB_BLOCKS 11
56+
# endif
57+
# ifndef COMB_TEETH
58+
# define COMB_TEETH 6
59+
# endif
60+
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
61+
62+
/* Range checks on the parameters. */
63+
#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256)
64+
# error "COMB_BLOCKS must be in the range [1, 256]"
65+
#endif
66+
#if !(1 <= COMB_TEETH && COMB_TEETH <= 8)
67+
# error "COMB_TEETH must be in the range [1, 8]"
68+
#endif
69+
70+
/* The remaining COMB_* parameters are derived values, don't modify these. */
71+
/* - The distance between the teeth of the comb. */
72+
#define COMB_SPACING ((255 + COMB_BLOCKS * COMB_TEETH) / (COMB_BLOCKS * COMB_TEETH))
73+
/* - The number of bits covered by all the combs; must be at least 256. */
74+
#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING)
75+
/* - The number of points per table. */
76+
#define COMB_POINTS (1 << (COMB_TEETH - 1))
77+
78+
/* Additional sanity checks. */
79+
#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256
80+
# error "COMB_BLOCKS can be reduced"
81+
#endif
82+
#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256
83+
# error "COMB_TEETH can be reduced"
1584
#endif
16-
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
17-
#define ECMULT_GEN_PREC_N(bits) (256 / bits)
1885

1986
typedef struct {
2087
/* Whether the context has been built. */

src/ecmult_gen_compute_table.h

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

1010
#include "ecmult_gen.h"
1111

12-
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits);
12+
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth);
1313

1414
#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */

src/ecmult_gen_compute_table_impl.h

+63-60
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/***********************************************************************
2-
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
3-
* Distributed under the MIT software license, see the accompanying *
4-
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
5-
***********************************************************************/
1+
/*******************************************************************************
2+
* Copyright (c) 2013-2015, 2021 Pieter Wuille, Gregory Maxwell, Peter Dettman *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
5+
*******************************************************************************/
66

77
#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
88
#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
@@ -13,68 +13,71 @@
1313
#include "ecmult_gen.h"
1414
#include "util.h"
1515

16-
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) {
17-
int g = ECMULT_GEN_PREC_G(bits);
18-
int n = ECMULT_GEN_PREC_N(bits);
16+
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth) {
17+
size_t points = ((size_t)1) << (teeth - 1);
18+
size_t points_total = points * blocks;
19+
int spacing = (256 + blocks * teeth - 1) / (blocks * teeth);
20+
secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec));
21+
secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds));
22+
secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs));
23+
secp256k1_gej u;
24+
size_t vs_pos = 0;
25+
int block;
1926

20-
secp256k1_ge* prec = checked_malloc(&default_error_callback, n * g * sizeof(*prec));
21-
secp256k1_gej gj;
22-
secp256k1_gej nums_gej;
23-
int i, j;
24-
25-
/* get the generator */
26-
secp256k1_gej_set_ge(&gj, gen);
27-
28-
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
29-
{
30-
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
31-
secp256k1_fe nums_x;
32-
secp256k1_ge nums_ge;
33-
int r;
34-
r = secp256k1_fe_set_b32(&nums_x, nums_b32);
35-
(void)r;
36-
VERIFY_CHECK(r);
37-
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
38-
(void)r;
39-
VERIFY_CHECK(r);
40-
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
41-
/* Add G to make the bits in x uniformly distributed. */
42-
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, gen, NULL);
43-
}
44-
45-
/* compute prec. */
46-
{
47-
secp256k1_gej gbase;
48-
secp256k1_gej numsbase;
49-
secp256k1_gej* precj = checked_malloc(&default_error_callback, n * g * sizeof(*precj)); /* Jacobian versions of prec. */
50-
gbase = gj; /* PREC_G^j * G */
51-
numsbase = nums_gej; /* 2^j * nums. */
52-
for (j = 0; j < n; j++) {
53-
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
54-
precj[j*g] = numsbase;
55-
for (i = 1; i < g; i++) {
56-
secp256k1_gej_add_var(&precj[j*g + i], &precj[j*g + i - 1], &gbase, NULL);
57-
}
58-
/* Multiply gbase by PREC_G. */
59-
for (i = 0; i < bits; i++) {
60-
secp256k1_gej_double_var(&gbase, &gbase, NULL);
27+
/* u is the running power of two times gen we're working with, initially 1*gen. */
28+
secp256k1_gej_set_ge(&u, gen);
29+
for (block = 0; block < blocks; ++block) {
30+
int tooth;
31+
/* Here u = 2^(block*teeth*spacing) * gen. */
32+
secp256k1_gej sum;
33+
secp256k1_gej_set_infinity(&sum);
34+
for (tooth = 0; tooth < teeth; ++tooth) {
35+
/* Here u = 2^((block*teeth + tooth)*spacing) * gen. */
36+
int bit_off;
37+
/* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth). */
38+
secp256k1_gej_add_var(&sum, &sum, &u, NULL);
39+
/* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen. */
40+
secp256k1_gej_double_var(&u, &u, NULL);
41+
/* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen. */
42+
ds[tooth] = u;
43+
/* Make u = 2^((block*teeth + tooth + 1)*spacing). */
44+
for (bit_off = 1; bit_off < spacing; ++bit_off) {
45+
secp256k1_gej_double_var(&u, &u, NULL);
6146
}
62-
/* Multiply numbase by 2. */
63-
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
64-
if (j == n - 2) {
65-
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
66-
secp256k1_gej_neg(&numsbase, &numsbase);
67-
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
47+
}
48+
/* Now u = 2^(block*(teeth + 1)*spacing) * gen. */
49+
50+
/* Next, compute the table entries for block block in Jacobian coordinates.
51+
* The entries will occupy vs[block*points + i] for i=0..points-1.
52+
* We start by computing the first (i=0) value corresponding to all summed
53+
* powers of two times G being negative. */
54+
secp256k1_gej_neg(&vs[vs_pos++], &sum);
55+
/* And then teeth-1 times "double" the range of i values for which the table
56+
* is computed: in each iteration, double the table by taking an existing
57+
* table entry and adding ds[tooth]. */
58+
for (tooth = 0; tooth < teeth - 1; ++tooth) {
59+
size_t stride = ((size_t)1) << tooth;
60+
size_t index;
61+
for (index = 0; index < stride; ++index, ++vs_pos) {
62+
secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL);
6863
}
6964
}
70-
secp256k1_ge_set_all_gej_var(prec, precj, n * g);
71-
free(precj);
7265
}
73-
for (j = 0; j < n; j++) {
74-
for (i = 0; i < g; i++) {
75-
secp256k1_ge_to_storage(&table[j*g + i], &prec[j*g + i]);
66+
VERIFY_CHECK(vs_pos == points_total);
67+
68+
/* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */
69+
secp256k1_ge_set_all_gej_var(prec, vs, points_total);
70+
/* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */
71+
for (block = 0; block < blocks; ++block) {
72+
size_t index;
73+
for (index = 0; index < points; ++index) {
74+
secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]);
7675
}
7776
}
77+
78+
/* Free memory. */
79+
free(vs);
80+
free(ds);
7881
free(prec);
7982
}
8083

0 commit comments

Comments
 (0)