Skip to content

Commit 227a4f2

Browse files
committed
Merge #709: Remove secret-dependant non-constant time operation in ecmult_const.
d567b77 Clarify comments about use of rzr on ge functions and abs function. (Gregory Maxwell) 2241ae6 Remove secret-dependant non-constant time operation in ecmult_const. (Gregory Maxwell) Pull request description: ECMULT_CONST_TABLE_GET_GE was branching on its secret input. Also makes secp256k1_gej_double_var implemented as a wrapper on secp256k1_gej_double_nonzero instead of the other way around. This wasn't a constant time bug but it was fragile and could easily become one in the future if the double_var algorithm is changed. ACKs for top commit: real-or-random: ACK d567b77 I read the diff carefully and tested the code with ECDH enabled and various settings, also on valgrind sipa: ACK d567b77 Tree-SHA512: f00a921dcc6cc024cfb3ac1a34c1be619b96f1f17ec0ee0f3ff4ea02035ee288e55469491ed3183e2c4e5560cc068c10aafb657dff95a610706e5b9a8cd13966
2 parents f45d897 + d567b77 commit 227a4f2

File tree

5 files changed

+42
-36
lines changed

5 files changed

+42
-36
lines changed

src/ecmult_const_impl.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
1616
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
1717
int m; \
18-
int abs_n = (n) * (((n) > 0) * 2 - 1); \
19-
int idx_n = abs_n / 2; \
18+
/* Extract the sign-bit for a constant time absolute-value. */ \
19+
int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
20+
int abs_n = ((n) + mask) ^ mask; \
21+
int idx_n = abs_n >> 1; \
2022
secp256k1_fe neg_y; \
2123
VERIFY_CHECK(((n) & 1) == 1); \
2224
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
@@ -172,6 +174,7 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
172174
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
173175
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
174176
}
177+
175178
}
176179
#endif
177180

@@ -195,7 +198,7 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
195198
int n;
196199
int j;
197200
for (j = 0; j < WINDOW_A - 1; ++j) {
198-
secp256k1_gej_double_nonzero(r, r, NULL);
201+
secp256k1_gej_double_nonzero(r, r);
199202
}
200203

201204
n = wnaf_1[i];

src/group.h

+5-6
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,21 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
9595
/** Check whether a group element's y coordinate is a quadratic residue. */
9696
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
9797

98-
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
99-
* a may not be zero. Constant time. */
100-
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
98+
/** Set r equal to the double of a, a cannot be infinity. Constant time. */
99+
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a);
101100

102-
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
101+
/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
103102
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
104103

105-
/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
104+
/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
106105
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
107106

108107
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
109108
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b);
110109

111110
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
112111
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
113-
guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
112+
guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
114113
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
115114

116115
/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */

src/group_impl.h

+29-26
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
303303
return secp256k1_fe_equal_var(&y2, &x3);
304304
}
305305

306-
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
306+
static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a) {
307307
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
308308
*
309309
* Note that there is an implementation described at
@@ -312,29 +312,9 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
312312
* mainly because it requires more normalizations.
313313
*/
314314
secp256k1_fe t1,t2,t3,t4;
315-
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
316-
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
317-
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
318-
*
319-
* Having said this, if this function receives a point on a sextic twist, e.g. by
320-
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
321-
* since -6 does have a cube root mod p. For this point, this function will not set
322-
* the infinity flag even though the point doubles to infinity, and the result
323-
* point will be gibberish (z = 0 but infinity = 0).
324-
*/
325-
r->infinity = a->infinity;
326-
if (r->infinity) {
327-
if (rzr != NULL) {
328-
secp256k1_fe_set_int(rzr, 1);
329-
}
330-
return;
331-
}
332315

333-
if (rzr != NULL) {
334-
*rzr = a->y;
335-
secp256k1_fe_normalize_weak(rzr);
336-
secp256k1_fe_mul_int(rzr, 2);
337-
}
316+
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
317+
r->infinity = 0;
338318

339319
secp256k1_fe_mul(&r->z, &a->z, &a->y);
340320
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
@@ -358,9 +338,32 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
358338
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
359339
}
360340

361-
static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
362-
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
363-
secp256k1_gej_double_var(r, a, rzr);
341+
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
342+
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
343+
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
344+
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
345+
*
346+
* Having said this, if this function receives a point on a sextic twist, e.g. by
347+
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
348+
* since -6 does have a cube root mod p. For this point, this function will not set
349+
* the infinity flag even though the point doubles to infinity, and the result
350+
* point will be gibberish (z = 0 but infinity = 0).
351+
*/
352+
if (a->infinity) {
353+
r->infinity = 1;
354+
if (rzr != NULL) {
355+
secp256k1_fe_set_int(rzr, 1);
356+
}
357+
return;
358+
}
359+
360+
if (rzr != NULL) {
361+
*rzr = a->y;
362+
secp256k1_fe_normalize_weak(rzr);
363+
secp256k1_fe_mul_int(rzr, 2);
364+
}
365+
366+
secp256k1_gej_double_nonzero(r, a);
364367
}
365368

366369
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {

src/tests_exhaustive.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr
142142
for (i = 0; i < order; i++) {
143143
secp256k1_gej tmp;
144144
if (i > 0) {
145-
secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL);
145+
secp256k1_gej_double_nonzero(&tmp, &groupj[i]);
146146
ge_equals_gej(&group[(2 * i) % order], &tmp);
147147
}
148148
secp256k1_gej_double_var(&tmp, &groupj[i], NULL);

src/util.h

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <stdlib.h>
1515
#include <stdint.h>
1616
#include <stdio.h>
17+
#include <limits.h>
1718

1819
typedef struct {
1920
void (*fn)(const char *text, void* data);

0 commit comments

Comments
 (0)