Skip to content

Commit 9bc2e26

Browse files
committed
Merge bitcoin#522: parameterize ecmult_const over input size
7c1b91b parameterize ecmult_const over input size (Andrew Poelstra) Pull request description: Tree-SHA512: 0afd0c0156add54209e79c623d780559dfd85910ef0a0c476bcabd1074ad468d7983b7b6bb6e8bd3fe6e9b8bc703d78d09c3b99f8da990dfe004bbdc65496e66
2 parents dbc3ddd + 7c1b91b commit 9bc2e26

7 files changed

+78
-49
lines changed

src/bench_internal.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ void bench_wnaf_const(void* arg) {
251251
bench_inv *data = (bench_inv*)arg;
252252

253253
for (i = 0; i < 20000; i++) {
254-
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A);
254+
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256);
255255
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
256256
}
257257
}

src/ecmult_const.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "scalar.h"
1111
#include "group.h"
1212

13-
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
13+
/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
14+
* one because we internally sometimes add 2 to the number during the WNAF conversion. */
15+
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
1416

1517
#endif /* SECP256K1_ECMULT_CONST_H */

src/ecmult_const_impl.h

+57-33
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
*
4949
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
5050
*/
51-
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
51+
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) {
5252
int global_sign;
5353
int skew = 0;
5454
int word = 0;
@@ -67,9 +67,14 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
6767
* and we'd lose any performance benefit. Instead, we use a technique from
6868
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
6969
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
70-
* this, and having the caller compensate after doing the multiplication. */
71-
72-
/* Negative numbers will be negated to keep their bit representation below the maximum width */
70+
* this, and having the caller compensate after doing the multiplication.
71+
*
72+
* In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
73+
* particular, to ensure that the outputs from the endomorphism-split fit into
74+
* 128 bits). If we negate, the parity of our number flips, inverting which of
75+
* {1, 2} we want to add to the scalar when ensuring that it's odd. Further
76+
* complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
77+
* we need to special-case it in this logic. */
7378
flip = secp256k1_scalar_is_high(&s);
7479
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
7580
bit = flip ^ !secp256k1_scalar_is_even(&s);
@@ -88,7 +93,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
8893

8994
/* 4 */
9095
u_last = secp256k1_scalar_shr_int(&s, w);
91-
while (word * w < WNAF_BITS) {
96+
while (word * w < size) {
9297
int sign;
9398
int even;
9499

@@ -108,37 +113,44 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
108113
wnaf[word] = u * global_sign;
109114

110115
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
111-
VERIFY_CHECK(word == WNAF_SIZE(w));
116+
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
112117
return skew;
113118
}
114119

115-
116-
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
120+
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
117121
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
118122
secp256k1_ge tmpa;
119123
secp256k1_fe Z;
120124

121125
int skew_1;
122-
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
123126
#ifdef USE_ENDOMORPHISM
124127
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
125128
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
126129
int skew_lam;
127130
secp256k1_scalar q_1, q_lam;
128131
#endif
132+
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
129133

130134
int i;
131135
secp256k1_scalar sc = *scalar;
132136

133137
/* build wnaf representation for q. */
138+
int rsize = size;
134139
#ifdef USE_ENDOMORPHISM
135-
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
136-
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
137-
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
138-
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
139-
#else
140-
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
140+
if (size > 128) {
141+
rsize = 128;
142+
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
143+
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
144+
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128);
145+
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128);
146+
} else
141147
#endif
148+
{
149+
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size);
150+
#ifdef USE_ENDOMORPHISM
151+
skew_lam = 0;
152+
#endif
153+
}
142154

143155
/* Calculate odd multiples of a.
144156
* All multiples are brought to the same Z 'denominator', which is stored
@@ -152,26 +164,30 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
152164
secp256k1_fe_normalize_weak(&pre_a[i].y);
153165
}
154166
#ifdef USE_ENDOMORPHISM
155-
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
156-
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
167+
if (size > 128) {
168+
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
169+
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
170+
}
157171
}
158172
#endif
159173

160174
/* first loop iteration (separated out so we can directly set r, rather
161175
* than having it start at infinity, get doubled several times, then have
162176
* its new value added to it) */
163-
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
177+
i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
164178
VERIFY_CHECK(i != 0);
165179
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
166180
secp256k1_gej_set_ge(r, &tmpa);
167181
#ifdef USE_ENDOMORPHISM
168-
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
169-
VERIFY_CHECK(i != 0);
170-
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
171-
secp256k1_gej_add_ge(r, r, &tmpa);
182+
if (size > 128) {
183+
i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
184+
VERIFY_CHECK(i != 0);
185+
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
186+
secp256k1_gej_add_ge(r, r, &tmpa);
187+
}
172188
#endif
173189
/* remaining loop iterations */
174-
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
190+
for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
175191
int n;
176192
int j;
177193
for (j = 0; j < WINDOW_A - 1; ++j) {
@@ -183,10 +199,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
183199
VERIFY_CHECK(n != 0);
184200
secp256k1_gej_add_ge(r, r, &tmpa);
185201
#ifdef USE_ENDOMORPHISM
186-
n = wnaf_lam[i];
187-
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
188-
VERIFY_CHECK(n != 0);
189-
secp256k1_gej_add_ge(r, r, &tmpa);
202+
if (size > 128) {
203+
n = wnaf_lam[i];
204+
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
205+
VERIFY_CHECK(n != 0);
206+
secp256k1_gej_add_ge(r, r, &tmpa);
207+
}
190208
#endif
191209
}
192210

@@ -206,14 +224,18 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
206224
secp256k1_ge_set_gej(&correction, &tmpj);
207225
secp256k1_ge_to_storage(&correction_1_stor, a);
208226
#ifdef USE_ENDOMORPHISM
209-
secp256k1_ge_to_storage(&correction_lam_stor, a);
227+
if (size > 128) {
228+
secp256k1_ge_to_storage(&correction_lam_stor, a);
229+
}
210230
#endif
211231
secp256k1_ge_to_storage(&a2_stor, &correction);
212232

213233
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
214234
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
215235
#ifdef USE_ENDOMORPHISM
216-
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
236+
if (size > 128) {
237+
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
238+
}
217239
#endif
218240

219241
/* Apply the correction */
@@ -222,10 +244,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
222244
secp256k1_gej_add_ge(r, r, &correction);
223245

224246
#ifdef USE_ENDOMORPHISM
225-
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
226-
secp256k1_ge_neg(&correction, &correction);
227-
secp256k1_ge_mul_lambda(&correction, &correction);
228-
secp256k1_gej_add_ge(r, r, &correction);
247+
if (size > 128) {
248+
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
249+
secp256k1_ge_neg(&correction, &correction);
250+
secp256k1_ge_mul_lambda(&correction, &correction);
251+
secp256k1_gej_add_ge(r, r, &correction);
252+
}
229253
#endif
230254
}
231255
}

src/ecmult_impl.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
#else
4848
#define WNAF_BITS 256
4949
#endif
50-
#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w))
50+
#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w))
51+
#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
5152

5253
/** The number of entries a table with precomputed multiples needs to have. */
5354
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))

src/modules/ecdh/main_impl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
3030
unsigned char y[1];
3131
secp256k1_sha256 sha;
3232

33-
secp256k1_ecmult_const(&res, &pt, &s);
33+
secp256k1_ecmult_const(&res, &pt, &s, 256);
3434
secp256k1_ge_set_gej(&pt, &res);
3535
/* Compute a hash of the point in compressed form
3636
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not

src/tests.c

+13-11
Original file line numberDiff line numberDiff line change
@@ -2443,7 +2443,7 @@ void ecmult_const_random_mult(void) {
24432443
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
24442444
);
24452445
secp256k1_gej b;
2446-
secp256k1_ecmult_const(&b, &a, &xn);
2446+
secp256k1_ecmult_const(&b, &a, &xn, 256);
24472447

24482448
CHECK(secp256k1_ge_is_valid_var(&a));
24492449
ge_equals_gej(&expected_b, &b);
@@ -2459,12 +2459,12 @@ void ecmult_const_commutativity(void) {
24592459
random_scalar_order_test(&a);
24602460
random_scalar_order_test(&b);
24612461

2462-
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
2463-
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
2462+
secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256);
2463+
secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256);
24642464
secp256k1_ge_set_gej(&mid1, &res1);
24652465
secp256k1_ge_set_gej(&mid2, &res2);
2466-
secp256k1_ecmult_const(&res1, &mid1, &b);
2467-
secp256k1_ecmult_const(&res2, &mid2, &a);
2466+
secp256k1_ecmult_const(&res1, &mid1, &b, 256);
2467+
secp256k1_ecmult_const(&res2, &mid2, &a, 256);
24682468
secp256k1_ge_set_gej(&mid1, &res1);
24692469
secp256k1_ge_set_gej(&mid2, &res2);
24702470
ge_equals_ge(&mid1, &mid2);
@@ -2480,13 +2480,13 @@ void ecmult_const_mult_zero_one(void) {
24802480
secp256k1_scalar_negate(&negone, &one);
24812481

24822482
random_group_element_test(&point);
2483-
secp256k1_ecmult_const(&res1, &point, &zero);
2483+
secp256k1_ecmult_const(&res1, &point, &zero, 3);
24842484
secp256k1_ge_set_gej(&res2, &res1);
24852485
CHECK(secp256k1_ge_is_infinity(&res2));
2486-
secp256k1_ecmult_const(&res1, &point, &one);
2486+
secp256k1_ecmult_const(&res1, &point, &one, 2);
24872487
secp256k1_ge_set_gej(&res2, &res1);
24882488
ge_equals_ge(&res2, &point);
2489-
secp256k1_ecmult_const(&res1, &point, &negone);
2489+
secp256k1_ecmult_const(&res1, &point, &negone, 256);
24902490
secp256k1_gej_neg(&res1, &res1);
24912491
secp256k1_ge_set_gej(&res2, &res1);
24922492
ge_equals_ge(&res2, &point);
@@ -2512,7 +2512,7 @@ void ecmult_const_chain_multiply(void) {
25122512
for (i = 0; i < 100; ++i) {
25132513
secp256k1_ge tmp;
25142514
secp256k1_ge_set_gej(&tmp, &point);
2515-
secp256k1_ecmult_const(&point, &tmp, &scalar);
2515+
secp256k1_ecmult_const(&point, &tmp, &scalar, 256);
25162516
}
25172517
secp256k1_ge_set_gej(&res, &point);
25182518
ge_equals_gej(&res, &expected_point);
@@ -2968,6 +2968,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
29682968
int wnaf[256] = {0};
29692969
int i;
29702970
int skew;
2971+
int bits = 256;
29712972
secp256k1_scalar num = *number;
29722973

29732974
secp256k1_scalar_set_int(&x, 0);
@@ -2977,10 +2978,11 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
29772978
for (i = 0; i < 16; ++i) {
29782979
secp256k1_scalar_shr_int(&num, 8);
29792980
}
2981+
bits = 128;
29802982
#endif
2981-
skew = secp256k1_wnaf_const(wnaf, num, w);
2983+
skew = secp256k1_wnaf_const(wnaf, num, w, bits);
29822984

2983-
for (i = WNAF_SIZE(w); i >= 0; --i) {
2985+
for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) {
29842986
secp256k1_scalar t;
29852987
int v = wnaf[i];
29862988
CHECK(v != 0); /* check nonzero */

src/tests_exhaustive.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *gr
174174
ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
175175

176176
if (i > 0) {
177-
secp256k1_ecmult_const(&tmp, &group[i], &ng);
177+
secp256k1_ecmult_const(&tmp, &group[i], &ng, 256);
178178
ge_equals_gej(&group[(i * j) % order], &tmp);
179179
}
180180
}

0 commit comments

Comments
 (0)