From 6bb0b77e158fc2f9e56e4b65b08bcb660d4c588b Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 17 Apr 2020 18:05:50 +0000 Subject: [PATCH 1/2] Fix test_constant_wnaf for -1 and add a test for it. Before, test_constant_wnaf used scalar_cadd_bit to correct for the skew. But this function does not correctly deal with overflows which is why num = -1 couldn't be tested. This commit also adds tests for 0, 1/2 and 1/2-1 as they are corner cases in constant_wnaf. --- src/tests.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/tests.c b/src/tests.c index 2f2cb71539049..1040b6e508df8 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3190,6 +3190,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { int skew; int bits = 256; secp256k1_scalar num = *number; + secp256k1_scalar scalar_skew; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); @@ -3220,7 +3221,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar_add(&x, &x, &t); } /* Skew num because when encoding numbers as odd we use an offset */ - secp256k1_scalar_cadd_bit(&num, skew == 2, 1); + secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2)); + secp256k1_scalar_add(&num, &num, &scalar_skew); CHECK(secp256k1_scalar_eq(&x, &num)); } @@ -3332,13 +3334,32 @@ void run_wnaf(void) { int i; secp256k1_scalar n = {{0}}; + test_constant_wnaf(&n, 4); /* Sanity check: 1 and 2 are the smallest odd and even numbers and should * have easier-to-diagnose failure modes */ n.d[0] = 1; test_constant_wnaf(&n, 4); n.d[0] = 2; test_constant_wnaf(&n, 4); - /* Test 0 */ + /* Test -1, because it's a special case in wnaf_const */ + n = secp256k1_scalar_one; + secp256k1_scalar_negate(&n, &n); + test_constant_wnaf(&n, 4); + + /* Test -2, which may not lead to overflows in wnaf_const */ + secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one); + secp256k1_scalar_negate(&n, &n); + test_constant_wnaf(&n, 4); + + /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1 + as corner cases of negation handling in wnaf_const */ + secp256k1_scalar_inverse(&n, &n); + test_constant_wnaf(&n, 4); + + secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one); + test_constant_wnaf(&n, 4); + + /* Test 0 for fixed wnaf */ test_fixed_wnaf_small(); /* Random tests */ for (i = 0; i < count; i++) { From 37dba329c6cb0f7a4228a11dc26aa3a342a3a5d0 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 17 Apr 2020 18:06:47 +0000 Subject: [PATCH 2/2] Remove unnecessary sign variable from wnaf_const --- src/ecmult_const_impl.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index d0d963182464a..0c26b1e767e2c 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -101,16 +101,22 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w /* 4 */ u_last = secp256k1_scalar_shr_int(&s, w); do { - int sign; int even; /* 4.1 4.4 */ u = secp256k1_scalar_shr_int(&s, w); /* 4.2 */ even = ((u & 1) == 0); - sign = 2 * (u_last > 0) - 1; - u += sign * even; - u_last -= sign * even * (1 << w); + /* In contrast to the original algorithm, u_last is always > 0 and + * therefore we do not need to check its sign. In particular, it's easy + * to see that u_last is never < 0 because u is never < 0. Moreover, + * u_last is never = 0 because u is never even after a loop + * iteration. The same holds analogously for the initial value of + * u_last (in the first loop iteration). */ + VERIFY_CHECK(u_last > 0); + VERIFY_CHECK((u_last & 1) == 1); + u += even; + u_last -= even * (1 << w); /* 4.3, adapted for global sign change */ wnaf[word++] = u_last * global_sign;