What changed, and why it matters
This commit is a size-optimization cleanup, not a security fix. It replaces libsecp256k1's default fatal-error callbacks with smaller stubs so the firmware binary no longer pulls in unused standard-library printing and abort code. The behavior stays the same: on an internal or illegal-argument failure, the device still hangs forever instead of returning.
No security action required. Treat as a normal firmware optimization commit. If desired, verify that the infinite-loop stubs still satisfy the project's watchdog/reset expectations for unrecoverable failures.
Security signals we found
No security signal present: change is a binary-size optimization
Fatal callback behavior preserved (infinite loop, no return)
No new attack surface introduced
No input validation, memory safety, or cryptographic logic changed
Evidence from the diff
The change adds USE_EXTERNAL_DEFAULT_CALLBACKS=1 and supplies default_callbacks.c with two non-returning functions: secp256k1_default_illegal_callback_fn and secp256k1_default_error_callback_fn. The new stubs ignore arguments and loop forever, matching the original non-returning contract while removing newlib stdio/signal dependencies (abort, raise, fprintf, printf, etc.). This is a code-size reduction of 2672 bytes with no functional change to the failure path.
Changed components
src/rust/bitbox-secp256k1/build.rssrc/rust/bitbox-secp256k1/src/default_callbacks.cVendored libsecp256k1-zkp default error/illegal callbacksInspect captured patch +21 / −0
diff --git a/src/rust/bitbox-secp256k1/build.rs b/src/rust/bitbox-secp256k1/build.rs
index 2552cfd..ac3c453 100644
--- a/src/rust/bitbox-secp256k1/build.rs
+++ b/src/rust/bitbox-secp256k1/build.rs
@@ -4,23 +4,27 @@ use std::path::PathBuf;
fn main() {
let secp_dir = PathBuf::from("depend/secp256k1-zkp");
+ let callbacks = PathBuf::from("src/default_callbacks.c");
println!(
"cargo::rerun-if-changed={}",
secp_dir.join("include").display()
);
println!("cargo::rerun-if-changed={}", secp_dir.join("src").display());
+ println!("cargo::rerun-if-changed={}", callbacks.display());
let mut build = cc::Build::new();
build
.file(secp_dir.join("src/secp256k1.c"))
.file(secp_dir.join("src/precomputed_ecmult.c"))
.file(secp_dir.join("src/precomputed_ecmult_gen.c"))
+ .file(&callbacks)
.include(secp_dir.join("include"))
// Suppress all warnings in this dependency, we don't have control over them.
.flag_if_supported("-w")
.define("ECMULT_WINDOW_SIZE", Some("2"))
.define("ECMULT_GEN_PREC_BITS", Some("2"))
+ .define("USE_EXTERNAL_DEFAULT_CALLBACKS", Some("1"))
.define("ENABLE_MODULE_RECOVERY", Some("1")) // needed only in Rust unit tests.
.define("ENABLE_MODULE_EXTRAKEYS", Some("1"))
.define("ENABLE_MODULE_SCHNORRSIG", Some("1"))
diff --git a/src/rust/bitbox-secp256k1/src/default_callbacks.c b/src/rust/bitbox-secp256k1/src/default_callbacks.c
new file mode 100644
index 0000000..161e731
--- /dev/null
+++ b/src/rust/bitbox-secp256k1/src/default_callbacks.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: Apache-2.0
+
+void secp256k1_default_illegal_callback_fn(const char* str, void* data)
+{
+ (void)str;
+ (void)data;
+ while (1) {
+ }
+}
+
+void secp256k1_default_error_callback_fn(const char* str, void* data)
+{
+ (void)str;
+ (void)data;
+ while (1) {
+ }
+}
Why this scored 14/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.