Skip to content

Commit 3e5cfc5

Browse files
Merge bitcoin#741: Remove unnecessary sign variable from wnaf_const
37dba32 Remove unnecessary sign variable from wnaf_const (Jonas Nick) 6bb0b77 Fix test_constant_wnaf for -1 and add a test for it. (Jonas Nick) Pull request description: There currently is a single branch in the `ecmul_const` function that is not being exercised by the tests. This branch is unreachable and therefore I'm suggesting to remove it. For your convenience the paper the wnaf algorithm can be found [here (The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar Multiplications Secure against Side Channel Attacks)](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.563.1267&rep=rep1&type=pdf). Similarly, unless I'm missing something important, I don't see how their algorithm needs to consider `sign(u[i-1])` unless `d` can be negative - which doesn't make much sense to me either. ACKs for top commit: real-or-random: ACK 37dba32 I verified the correctness of the change and claimed invariant by manual inspection. I tested the code, both with 32bit and 64bit scalars. Tree-SHA512: 9db45f76bd881d00a81923b6d2ae1c3e0f49a82a5d55347f01e1ce4e924d9a3bf55483a0697f25039c327e33edca6796ba3205c068d9f2f99aa5d655e46b15be
2 parents 66bb932 + 37dba32 commit 3e5cfc5

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

src/ecmult_const_impl.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,22 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
105105
/* 4 */
106106
u_last = secp256k1_scalar_shr_int(&s, w);
107107
do {
108-
int sign;
109108
int even;
110109

111110
/* 4.1 4.4 */
112111
u = secp256k1_scalar_shr_int(&s, w);
113112
/* 4.2 */
114113
even = ((u & 1) == 0);
115-
sign = 2 * (u_last > 0) - 1;
116-
u += sign * even;
117-
u_last -= sign * even * (1 << w);
114+
/* In contrast to the original algorithm, u_last is always > 0 and
115+
* therefore we do not need to check its sign. In particular, it's easy
116+
* to see that u_last is never < 0 because u is never < 0. Moreover,
117+
* u_last is never = 0 because u is never even after a loop
118+
* iteration. The same holds analogously for the initial value of
119+
* u_last (in the first loop iteration). */
120+
VERIFY_CHECK(u_last > 0);
121+
VERIFY_CHECK((u_last & 1) == 1);
122+
u += even;
123+
u_last -= even * (1 << w);
118124

119125
/* 4.3, adapted for global sign change */
120126
wnaf[word++] = u_last * global_sign;

src/tests.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3234,6 +3234,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
32343234
int skew;
32353235
int bits = 256;
32363236
secp256k1_scalar num = *number;
3237+
secp256k1_scalar scalar_skew;
32373238

32383239
secp256k1_scalar_set_int(&x, 0);
32393240
secp256k1_scalar_set_int(&shift, 1 << w);
@@ -3264,7 +3265,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
32643265
secp256k1_scalar_add(&x, &x, &t);
32653266
}
32663267
/* Skew num because when encoding numbers as odd we use an offset */
3267-
secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
3268+
secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2));
3269+
secp256k1_scalar_add(&num, &num, &scalar_skew);
32683270
CHECK(secp256k1_scalar_eq(&x, &num));
32693271
}
32703272

@@ -3376,13 +3378,32 @@ void run_wnaf(void) {
33763378
int i;
33773379
secp256k1_scalar n = {{0}};
33783380

3381+
test_constant_wnaf(&n, 4);
33793382
/* Sanity check: 1 and 2 are the smallest odd and even numbers and should
33803383
* have easier-to-diagnose failure modes */
33813384
n.d[0] = 1;
33823385
test_constant_wnaf(&n, 4);
33833386
n.d[0] = 2;
33843387
test_constant_wnaf(&n, 4);
3385-
/* Test 0 */
3388+
/* Test -1, because it's a special case in wnaf_const */
3389+
n = secp256k1_scalar_one;
3390+
secp256k1_scalar_negate(&n, &n);
3391+
test_constant_wnaf(&n, 4);
3392+
3393+
/* Test -2, which may not lead to overflows in wnaf_const */
3394+
secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one);
3395+
secp256k1_scalar_negate(&n, &n);
3396+
test_constant_wnaf(&n, 4);
3397+
3398+
/* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1
3399+
as corner cases of negation handling in wnaf_const */
3400+
secp256k1_scalar_inverse(&n, &n);
3401+
test_constant_wnaf(&n, 4);
3402+
3403+
secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one);
3404+
test_constant_wnaf(&n, 4);
3405+
3406+
/* Test 0 for fixed wnaf */
33863407
test_fixed_wnaf_small();
33873408
/* Random tests */
33883409
for (i = 0; i < count; i++) {

0 commit comments

Comments
 (0)