ecdsa: VERIFY_CHECK result of _fe_set_b32_limit
What changed, and why it matters
This is a small code-quality change in Bitcoin Core's secp256k1 cryptographic library. It adds an explicit safety check confirming that a value converted from one internal format to another stays within the expected range, and it silences a compiler warning about an unused return value. The commit message frames this as avoiding a compiler warning, not fixing a security bug.
No urgent action required. Treat as routine hardening/maintenance. Reviewers may verify that VERIFY_CHECK is enabled in CI/test builds and that the assertion cannot fire for any valid ECDSA signature verification input.
Security signals we found
Adds VERIFY_CHECK on result of field-element conversion
Previously ignored return value of set_b32_limit was asserted in-range by comment only
No input validation bypass introduced
No memory-safety or cryptographic weakness evident in diff
Evidence from the diff
In secp256k1_ecdsa_sig_verify(), the code converts a 32-byte scalar (sigr) to a field element using secp256k1_fe_set_b32_limit(). Previously the return value was cast to void with a comment asserting the input is always in range. The patch captures the return value, asserts it under VERIFY builds via VERIFY_CHECK(range), and explicitly discards it otherwise to suppress a GCC 16 -Wmaybe-uninitialized warning when -DDETERMINISTIC is used. No functional behavior changes in production builds; the change is defensive and diagnostic.
Changed components
src/ecdsa_impl.hsecp256k1_ecdsa_sig_verify()secp256k1_fe_set_b32_limit() return-value handlingInspect captured patch +10 / −2
diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h
index ce36e85..163539e 100644
--- a/src/ecdsa_impl.h
+++ b/src/ecdsa_impl.h
@@ -196,6 +196,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
unsigned char c[32];
secp256k1_scalar sn, u1, u2;
#if !defined(EXHAUSTIVE_TEST_ORDER)
+ int range;
secp256k1_fe xr;
#endif
secp256k1_gej pubkeyj;
@@ -226,9 +227,16 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
return secp256k1_scalar_eq(sigr, &computed_r);
}
#else
+
+ /* Interpret sigr as a field element xr */
secp256k1_scalar_get_b32(c, sigr);
- /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
- (void)secp256k1_fe_set_b32_limit(&xr, c);
+ range = secp256k1_fe_set_b32_limit(&xr, c);
+#ifdef VERIFY
+ /* We know that c is in range; it comes from a scalar. */
+ VERIFY_CHECK(range);
+#else
+ (void)range;
+#endif
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.