diff --git a/src/int128.h b/src/int128.h index 8c1c061a8..5355fbfae 100644 --- a/src/int128.h +++ b/src/int128.h @@ -80,10 +80,10 @@ static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_ /* Compare two 128-bit values for equality. */ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); -/* Tests if r is equal to 2^n. +/* Tests if r is equal to sign*2^n (sign must be 1 or -1). * n must be strictly less than 127. */ -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n); +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign); #endif diff --git a/src/int128_native_impl.h b/src/int128_native_impl.h index 30c26f2d3..996e542cf 100644 --- a/src/int128_native_impl.h +++ b/src/int128_native_impl.h @@ -84,9 +84,10 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con return *a == *b; } -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { VERIFY_CHECK(n < 127); - return (*r == (int128_t)1 << n); + VERIFY_CHECK(sign == 1 || sign == -1); + return (*r == (int128_t)((uint128_t)sign << n)); } #endif diff --git a/src/int128_struct_impl.h b/src/int128_struct_impl.h index 298a7bb1a..2eb337cb5 100644 --- a/src/int128_struct_impl.h +++ b/src/int128_struct_impl.h @@ -189,10 +189,11 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con return a->hi == b->hi && a->lo == b->lo; } -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { - VERIFY_CHECK(n < 127); - return n >= 64 ? r->hi == (uint64_t)1 << (n - 64) && r->lo == 0 - : r->hi == 0 && r->lo == (uint64_t)1 << n; +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 + : r->hi == (uint64_t)((sign - 1) >> 1) && r->lo == (uint64_t)sign << n; } #endif diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index 2b5463a3f..d193844af 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -75,7 +75,7 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) { secp256k1_int128 a; secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); - return secp256k1_i128_check_pow2(&a, n); + return secp256k1_i128_check_pow2(&a, n, 1); } #endif diff --git a/src/tests.c b/src/tests.c index bc5b7cb1f..dadac4c4d 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2022,30 +2022,56 @@ static void run_int128_test_case(void) { } CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); } - /* test secp256k1_i128_check_pow2 */ + /* test secp256k1_i128_check_pow2 (sign == 1) */ { int expect = (uc & 1); int pos = ub % 127; if (expect) { - /* If expect==1, set swz to exactly (2 << pos). */ + /* If expect==1, set swz to exactly 2^pos. */ uint64_t hi = 0; uint64_t lo = 0; - if (pos & 64) { + if (pos >= 64) { hi = (((uint64_t)1) << (pos & 63)); } else { lo = (((uint64_t)1) << (pos & 63)); } secp256k1_i128_load(&swz, hi, lo); } else { - /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal (2 << pos). */ - if (pos & 64) { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ + if (pos >= 64) { if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; } else { if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; } swz = swa; } - CHECK(secp256k1_i128_check_pow2(&swz, pos) == expect); + CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == -1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly -2^pos. */ + uint64_t hi = ~(uint64_t)0; + uint64_t lo = ~(uint64_t)0; + if (pos >= 64) { + hi <<= (pos & 63); + lo = 0; + } else { + lo <<= (pos & 63); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ + if (pos >= 64) { + if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect); } }