Merge bitcoin-core/secp256k1#1845: Improve checks for scalar _get_bits methods

0cad3df503 Improve checks for scalar _get_bits methods (Peter.Dettman)

Pull request description:

  Improves the `VERIFY_CHECK`s in all `_scalar_get_bits_limb32` and `_scalar_get_bits_var` methods.

  The initial prompt was noticing that scalar_4x64_impl/`secp256k1_scalar_get_bits_limb32` was not restricting to 32-bit limbs correctly. Then missing range checks for `offset` were added and all such checks rewritten to avoid overflow.

  With these changes, the _low and _4x64 impls of `_get_bits_var` can no longer forward to `_get_bits_limb32`, so those calls were inlined instead.

ACKs for top commit:
  sipa:
    ACK 0cad3df503
  theStack:
    ACK 0cad3df503
  real-or-random:
    utACK 0cad3df503

Tree-SHA512: 753991d586fe5695dd33af6c261c5458ab659be94204626166503af7d403748abb76d791846857a16383cbd38a1f84af9fde74b4327d68d706f88b6531ee7546
This commit is contained in:
merge-script
2026-06-25 17:02:04 +02:00
3 changed files with 17 additions and 6 deletions

View File

@@ -41,7 +41,8 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
VERIFY_CHECK(offset <= 256 - count);
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count));
}
@@ -49,12 +50,13 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK(offset + count <= 256);
VERIFY_CHECK(offset <= 256 - count);
if ((offset + count - 1) >> 6 == offset >> 6) {
return secp256k1_scalar_get_bits_limb32(a, offset, count);
return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count));
} else {
VERIFY_CHECK((offset >> 6) + 1 < 4);
VERIFY_CHECK((offset & 0x3F) > 0);
return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count));
}
}

View File

@@ -54,6 +54,7 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK(offset <= 256 - count);
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count));
@@ -62,7 +63,7 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK(offset + count <= 256);
VERIFY_CHECK(offset <= 256 - count);
if ((offset + count - 1) >> 5 == offset >> 5) {
return secp256k1_scalar_get_bits_limb32(a, offset, count);

View File

@@ -27,8 +27,10 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK(offset <= 256 - count);
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
if (offset < 32) {
return (*a >> offset) & (0xFFFFFFFF >> (32 - count));
} else {
@@ -38,8 +40,14 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k
SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
SECP256K1_SCALAR_VERIFY(a);
VERIFY_CHECK(count > 0 && count <= 32);
VERIFY_CHECK(offset <= 256 - count);
return secp256k1_scalar_get_bits_limb32(a, offset, count);
if (offset < 32) {
return (*a >> offset) & (0xFFFFFFFF >> (32 - count));
} else {
return 0;
}
}
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }