Skip to content

Commit 63d2cf5

Browse files
committed
Remove old ecmult_gen code and always use multi-comb
1 parent 1b45383 commit 63d2cf5

File tree

4 files changed

+11
-161
lines changed

4 files changed

+11
-161
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,11 @@ Implementation details
4949
* Use a much larger window for multiples of G, using precomputed multiples.
5050
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
5151
* Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
52-
* Point multiplication for signing
53-
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
52+
* Point multiplication for signing using Mike Hamburg's signed-digit multi-comb method (see https://eprint.iacr.org/2012/309, section 3.3)
5453
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
5554
* Access the table with branch-free conditional moves so memory access is uniform.
5655
* No data-dependent branches
5756
* Optional runtime blinding which attempts to frustrate differential power analysis.
58-
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
5957

6058
Build steps
6159
-----------

src/ecmult_gen.h

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@
1010
#include "scalar.h"
1111
#include "group.h"
1212

13-
#define USE_COMB 1
14-
15-
#ifdef USE_COMB
16-
1713
#if defined(EXHAUSTIVE_TEST_ORDER)
1814

1915
/* We need to control these values for exhaustive tests because
@@ -71,19 +67,7 @@
7167
# error "COMB_BITS must be in the range [256, 288]"
7268
#endif
7369

74-
#else
75-
76-
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
77-
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
78-
#endif
79-
#define ECMULT_GEN_PREC_B ECMULT_GEN_PREC_BITS
80-
#define ECMULT_GEN_PREC_G (1 << ECMULT_GEN_PREC_B)
81-
#define ECMULT_GEN_PREC_N (256 / ECMULT_GEN_PREC_B)
82-
83-
#endif
84-
8570
typedef struct {
86-
#ifdef USE_COMB
8771
/* Precomputation data for the signed-digit multi-comb algorithm as described in section 3.3 of:
8872
* "Fast and compact elliptic-curve cryptography", Mike Hamburg
8973
* (https://eprint.iacr.org/2012/309)
@@ -96,21 +80,6 @@ typedef struct {
9680
* for the (COMB_SPACING - 1) doublings in the _ecmult_gen ladder.
9781
*/
9882
secp256k1_ge offset;
99-
#endif
100-
#else
101-
/* For accelerating the computation of a*G:
102-
* To harden against timing attacks, use the following mechanism:
103-
* * Break up the multiplicand into groups of PREC_B bits, called n_0, n_1, n_2, ..., n_(PREC_N-1).
104-
* * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where:
105-
* * U_i = U * 2^i, for i=0 ... PREC_N-2
106-
* * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1
107-
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0.
108-
* For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is
109-
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1).
110-
* None of the resulting prec group elements have a known scalar, and neither do any of
111-
* the intermediate sums while computing a*G.
112-
*/
113-
secp256k1_ge_storage (*prec)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G]; /* prec[j][i] = (PREC_G)^j * i * G + U_i */
11483
#endif
11584
secp256k1_scalar blind;
11685
secp256k1_gej initial;

src/ecmult_gen_impl.h

Lines changed: 10 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,9 @@ static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx)
2828

2929
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) {
3030
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
31-
#ifdef USE_COMB
3231
secp256k1_ge prec[COMB_POINTS_TOTAL + COMB_OFFSET];
3332
secp256k1_gej u, sum;
3433
int block, index, spacing, stride, tooth;
35-
#else
36-
secp256k1_ge prec[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G];
37-
secp256k1_gej gj;
38-
secp256k1_gej nums_gej;
39-
int i, j;
40-
#endif
4134
size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
4235
void* const base = *prealloc;
4336
#endif
@@ -46,7 +39,6 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
4639
return;
4740
}
4841
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
49-
#ifdef USE_COMB
5042
ctx->prec = (secp256k1_ge_storage (*)[COMB_BLOCKS][COMB_POINTS])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
5143

5244
/* get the generator */
@@ -95,72 +87,12 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
9587
ctx->offset = prec[COMB_POINTS_TOTAL];
9688
#endif
9789

98-
#else
99-
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
100-
101-
/* get the generator */
102-
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
103-
104-
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
105-
{
106-
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
107-
secp256k1_fe nums_x;
108-
secp256k1_ge nums_ge;
109-
int r;
110-
r = secp256k1_fe_set_b32(&nums_x, nums_b32);
111-
(void)r;
112-
VERIFY_CHECK(r);
113-
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
114-
(void)r;
115-
VERIFY_CHECK(r);
116-
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
117-
/* Add G to make the bits in x uniformly distributed. */
118-
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL);
119-
}
120-
121-
/* compute prec. */
122-
{
123-
secp256k1_gej precj[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G]; /* Jacobian versions of prec. */
124-
secp256k1_gej gbase;
125-
secp256k1_gej numsbase;
126-
gbase = gj; /* PREC_G^j * G */
127-
numsbase = nums_gej; /* 2^j * nums. */
128-
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
129-
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
130-
precj[j*ECMULT_GEN_PREC_G] = numsbase;
131-
for (i = 1; i < ECMULT_GEN_PREC_G; i++) {
132-
secp256k1_gej_add_var(&precj[j*ECMULT_GEN_PREC_G + i], &precj[j*ECMULT_GEN_PREC_G + i - 1], &gbase, NULL);
133-
}
134-
/* Multiply gbase by PREC_G. */
135-
for (i = 0; i < ECMULT_GEN_PREC_B; i++) {
136-
secp256k1_gej_double_var(&gbase, &gbase, NULL);
137-
}
138-
/* Multiply numbase by 2. */
139-
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
140-
if (j == ECMULT_GEN_PREC_N - 2) {
141-
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
142-
secp256k1_gej_neg(&numsbase, &numsbase);
143-
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
144-
}
145-
}
146-
secp256k1_ge_set_all_gej_var(prec, precj, ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G);
147-
}
148-
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
149-
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
150-
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*ECMULT_GEN_PREC_G + i]);
151-
}
152-
}
153-
#endif
15490
#else
15591
(void)prealloc;
156-
#if USE_COMB
15792
ctx->prec = (secp256k1_ge_storage (*)[COMB_BLOCKS][COMB_POINTS])secp256k1_ecmult_gen_ctx_prec;
15893
#if COMB_OFFSET
15994
secp256k1_ge_from_storage(&ctx->offset, &secp256k1_ecmult_gen_ctx_offset);
16095
#endif
161-
#else
162-
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])secp256k1_ecmult_static_context;
163-
#endif
16496
#endif
16597
secp256k1_ecmult_gen_blind(ctx, NULL);
16698
}
@@ -171,28 +103,20 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
171103

172104
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
173105
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
174-
#ifdef USE_COMB
175106
if (src->prec != NULL) {
176107
/* We cast to void* first to suppress a -Wcast-align warning. */
177108
dst->prec = (secp256k1_ge_storage (*)[COMB_BLOCKS][COMB_POINTS])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
178109
}
179110
#if COMB_OFFSET
180111
dst->offset = src->offset;
181112
#endif
182-
#else
183-
if (src->prec != NULL) {
184-
dst->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
185-
}
186-
#endif
187113
#endif
188114
(void)dst, (void)src;
189115
}
190116

191117
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
192-
#ifdef USE_COMB
193118
#if COMB_OFFSET
194119
secp256k1_ge_clear(&ctx->offset);
195-
#endif
196120
#endif
197121
secp256k1_scalar_clear(&ctx->blind);
198122
secp256k1_gej_clear(&ctx->initial);
@@ -205,8 +129,6 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
205129
secp256k1_scalar gnb;
206130
uint32_t bits;
207131

208-
#ifdef USE_COMB
209-
210132
uint32_t abs, bit_pos, block, comb_off, index, sign;
211133
#if !COMB_GROUPED
212134
uint32_t bit, tooth;
@@ -245,6 +167,16 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
245167
VERIFY_CHECK(abs < COMB_POINTS);
246168

247169
for (index = 0; index < COMB_POINTS; ++index) {
170+
/** This uses a conditional move to avoid any secret data in array indexes.
171+
* _Any_ use of secret indexes has been demonstrated to result in timing
172+
* sidechannels, even when the cache-line access patterns are uniform.
173+
* See also:
174+
* "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe
175+
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
176+
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
177+
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
178+
* (http://www.tau.ac.il/~tromer/papers/cache.pdf)
179+
*/
248180
secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[block][index], index == abs);
249181
}
250182

@@ -266,33 +198,6 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
266198
memset(recoded, 0, sizeof(recoded));
267199
abs = 0;
268200
sign = 0;
269-
270-
#else
271-
int i, j;
272-
memset(&adds, 0, sizeof(adds));
273-
*r = ctx->initial;
274-
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
275-
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
276-
add.infinity = 0;
277-
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
278-
bits = secp256k1_scalar_get_bits(&gnb, j * ECMULT_GEN_PREC_B, ECMULT_GEN_PREC_B);
279-
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
280-
/** This uses a conditional move to avoid any secret data in array indexes.
281-
* _Any_ use of secret indexes has been demonstrated to result in timing
282-
* sidechannels, even when the cache-line access patterns are uniform.
283-
* See also:
284-
* "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe
285-
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
286-
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
287-
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
288-
* (https://www.tau.ac.il/~tromer/papers/cache.pdf)
289-
*/
290-
secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], (uint32_t)i == bits);
291-
}
292-
secp256k1_ge_from_storage(&add, &adds);
293-
secp256k1_gej_add_ge(r, r, &add);
294-
}
295-
#endif
296201
bits = 0;
297202
secp256k1_ge_clear(&add);
298203
memset(&adds, 0, sizeof(adds));
@@ -301,9 +206,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
301206

302207
/* Setup blinding values for secp256k1_ecmult_gen. */
303208
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
304-
#ifdef USE_COMB
305209
int spacing;
306-
#endif
307210
secp256k1_scalar b;
308211
secp256k1_gej gb;
309212
secp256k1_fe s;
@@ -316,13 +219,11 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
316219
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
317220
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
318221
secp256k1_scalar_set_int(&ctx->blind, 1);
319-
#ifdef USE_COMB
320222
for (spacing = 1; spacing < COMB_SPACING; ++spacing) {
321223
secp256k1_scalar_add(&ctx->blind, &ctx->blind, &ctx->blind);
322224
}
323225
#if COMB_OFFSET
324226
secp256k1_gej_add_ge(&ctx->initial, &ctx->initial, &ctx->offset);
325-
#endif
326227
#endif
327228
}
328229
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
@@ -355,13 +256,11 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
355256
secp256k1_scalar_negate(&b, &b);
356257
ctx->blind = b;
357258
ctx->initial = gb;
358-
#ifdef USE_COMB
359259
for (spacing = 1; spacing < COMB_SPACING; ++spacing) {
360260
secp256k1_scalar_add(&ctx->blind, &ctx->blind, &ctx->blind);
361261
}
362262
#if COMB_OFFSET
363263
secp256k1_gej_add_ge(&ctx->initial, &ctx->initial, &ctx->offset);
364-
#endif
365264
#endif
366265
secp256k1_scalar_clear(&b);
367266
secp256k1_gej_clear(&gb);

src/gen_context.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,11 @@ int main(int argc, char **argv) {
3939
FILE* fp;
4040
const char *SC_FORMAT = " SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)";
4141

42-
#if USE_COMB
4342
const int blocks = COMB_BLOCKS;
4443
const int points = COMB_POINTS;
4544
#if COMB_OFFSET
4645
secp256k1_ge_storage offset;
4746
#endif
48-
#else
49-
const int blocks = ECMULT_GEN_PREC_N;
50-
const int points = ECMULT_GEN_PREC_G;
51-
#endif
5247

5348
(void)argc;
5449
(void)argv;
@@ -63,31 +58,20 @@ int main(int argc, char **argv) {
6358
fprintf(fp, "#define SECP256K1_ECMULT_STATIC_CONTEXT_H\n");
6459
fprintf(fp, "#include \"src/group.h\"\n");
6560
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
66-
fprintf(fp, "#if USE_COMB != %i\n", USE_COMB);
67-
fprintf(fp, " #error configuration mismatch, invalid USE_COMB. Try deleting ecmult_static_context.h before the build.\n");
68-
fprintf(fp, "#endif\n");
69-
#if USE_COMB
7061
fprintf(fp, "#if COMB_BLOCKS != %i || COMB_TEETH != %i || COMB_SPACING != %i\n", COMB_BLOCKS, COMB_TEETH, COMB_SPACING);
7162
fprintf(fp, " #error configuration mismatch, invalid COMB_BLOCKS, COMB_TEETH, or COMB_SPACING. Try deleting ecmult_static_context.h before the build.\n");
7263
fprintf(fp, "#endif\n");
73-
#else
74-
fprintf(fp, "#if ECMULT_GEN_PREC_N != %d || ECMULT_GEN_PREC_G != %d\n", ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G);
75-
fprintf(fp, " #error configuration mismatch, invalid ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G. Try deleting ecmult_static_context.h before the build.\n");
76-
fprintf(fp, "#endif\n");
77-
#endif
7864

7965
base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE);
8066
prealloc = base;
8167
secp256k1_ecmult_gen_context_init(&ctx);
8268
secp256k1_ecmult_gen_context_build(&ctx, &prealloc);
8369

84-
#if USE_COMB
8570
#if COMB_OFFSET
8671
secp256k1_ge_to_storage(&offset, &ctx.offset);
8772
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_gen_ctx_offset =\n");
8873
fprintf(fp, SC_FORMAT, SECP256K1_GE_STORAGE_CONST_GET(offset));
8974
fprintf(fp, ";\n");
90-
#endif
9175
#endif
9276

9377
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_gen_ctx_prec[%i][%i] = {\n", blocks, points);

0 commit comments

Comments
 (0)