pass rust secp256k1 context to keystore_secp256k1_nonce_commit
What changed, and why it matters
This commit is a routine internal cleanup: it changes a cryptographic helper function so that callers pass in the secp256k1 context explicitly, instead of the function fetching a global context internally. There is no direct security vulnerability visible in the diff. It is part of a gradual migration away from an old context accessor (`wally_get_secp_context()`).
No immediate action required. Treat as normal refactoring. Continue monitoring the broader `wally_get_secp_context()` removal series for any context-lifetime or signing-routine regressions.
Security signals we found
Refactoring of secp256k1 context plumbing
Anti-Klepto / anti-exfil nonce commitment code touched
No bounds-check changes, no new allocations, no new parsing
No vendor security framing in commit message or diff
Evidence from the diff
The C function keystore_secp256k1_nonce_commit() now takes a const secp256k1_context* ctx parameter, and all Rust call sites (Bitcoin/Ethereum signing paths) pass SECP256K1. The function no longer calls wally_get_secp_context() internally. Unit tests are updated accordingly. The change is architectural/plumbing and does not alter the anti-klepto protocol logic or introduce observable cryptographic weaknesses in the shown code.
Changed components
src/keystore.csrc/keystore.hRust HWW API Bitcoin/Ethereum signing modulesbitbox02 Rust keystore FFI wrapperunit test test_keystore_antiklepto.cInspect captured patch +30 / −5
diff --git a/src/keystore.c b/src/keystore.c
index 34aa514..cefb3f9 100644
--- a/src/keystore.c
+++ b/src/keystore.c
@@ -497,12 +497,12 @@ bool keystore_get_bip39_word_stack(uint16_t idx, char* word_out, size_t word_out
}
bool keystore_secp256k1_nonce_commit(
+ const secp256k1_context* ctx,
const uint8_t* private_key,
const uint8_t* msg32,
const uint8_t* host_commitment,
uint8_t* signer_commitment_out)
{
- const secp256k1_context* ctx = wally_get_secp_context();
secp256k1_ecdsa_s2c_opening signer_commitment;
if (!secp256k1_ecdsa_anti_exfil_signer_commit(
ctx, &signer_commitment, msg32, private_key, host_commitment)) {
diff --git a/src/keystore.h b/src/keystore.h
index de35b36..a0bbe24 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -133,6 +133,7 @@ USE_RESULT bool keystore_get_bip39_word_stack(uint16_t idx, char* word_out, size
* Get a commitment to the original nonce before tweaking it with the host nonce. This is part of
* the ECDSA Anti-Klepto Protocol. For more details, check the docs of
* `secp256k1_ecdsa_anti_exfil_signer_commit`.
+ * @param[in] ctx secp256k1 context
* @param[in] private_key 32 byte private key
* @param[in] msg32 32 byte message which will be signed by `keystore_secp256k1_sign`.
* @param[in] host_commitment must be `sha256(sha256(tag)||shas256(tag)||host_nonce)` where
@@ -141,6 +142,7 @@ USE_RESULT bool keystore_get_bip39_word_stack(uint16_t idx, char* word_out, size
* @param[out] client_commitment_out EC_PUBLIC_KEY_LEN bytes compressed signer nonce pubkey.
*/
USE_RESULT bool keystore_secp256k1_nonce_commit(
+ const secp256k1_context* ctx,
const uint8_t* private_key,
const uint8_t* msg32,
const uint8_t* host_commitment,
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs
index cad8986..4239f2f 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs
@@ -27,6 +27,7 @@ use pb::btc_response::Response;
use bitbox02::keystore;
use crate::hal::Ui;
+use crate::secp256k1::SECP256K1;
use crate::workflow::{confirm, verify_message};
const MAX_MESSAGE_SIZE: usize = 1024;
@@ -98,6 +99,7 @@ pub async fn process(
// Engage in the anti-klepto protocol if the host sends a host nonce commitment.
Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => {
let signer_commitment = keystore::secp256k1_nonce_commit(
+ SECP256K1,
crate::keystore::secp256k1_get_private_key(keypath)?
.as_slice()
.try_into()
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
index a59b570..77599b1 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
@@ -1206,6 +1206,7 @@ async fn _process(
let host_nonce: [u8; 32] = match tx_input.host_nonce_commitment {
Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => {
let signer_commitment = bitbox02::keystore::secp256k1_nonce_commit(
+ SECP256K1,
private_key.as_slice().try_into().unwrap(),
&sighash,
commitment
diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs
index 01d68a6..433e791 100644
--- a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs
@@ -20,6 +20,7 @@ use super::Error;
use bitbox02::keystore;
use crate::hal::Ui;
+use crate::secp256k1::SECP256K1;
use crate::workflow::{confirm, transaction};
use alloc::vec::Vec;
@@ -389,6 +390,7 @@ pub async fn _process(
// Engage in the anti-klepto protocol if the host sends a host nonce commitment.
Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => {
let signer_commitment = keystore::secp256k1_nonce_commit(
+ SECP256K1,
&crate::keystore::secp256k1_get_private_key(request.keypath())?
.as_slice()
.try_into()
diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign_typed_msg.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign_typed_msg.rs
index cc81800..a45a5cd 100644
--- a/src/rust/bitbox02-rust/src/hww/api/ethereum/sign_typed_msg.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/sign_typed_msg.rs
@@ -23,6 +23,7 @@ use super::pb;
use super::Error;
use crate::hal::Ui;
+use crate::secp256k1::SECP256K1;
use crate::workflow::confirm;
use bitbox02::keystore;
@@ -563,6 +564,7 @@ pub async fn process(
let host_nonce = match request.host_nonce_commitment {
Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => {
let signer_commitment = keystore::secp256k1_nonce_commit(
+ SECP256K1,
crate::keystore::secp256k1_get_private_key(&request.keypath)?
.as_slice()
.try_into()
diff --git a/src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs b/src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs
index 6cdeb75..d11efdd 100644
--- a/src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs
@@ -17,6 +17,7 @@ use super::Error;
use bitbox02::keystore;
+use crate::secp256k1::SECP256K1;
use crate::workflow::verify_message;
use pb::eth_response::Response;
@@ -67,6 +68,7 @@ pub async fn process(
// Engage in the anti-klepto protocol if the host sends a host nonce commitment.
Some(pb::AntiKleptoHostNonceCommitment { ref commitment }) => {
let signer_commitment = keystore::secp256k1_nonce_commit(
+ SECP256K1,
crate::keystore::secp256k1_get_private_key(&request.keypath)?
.as_slice()
.try_into()
diff --git a/src/rust/bitbox02/src/keystore.rs b/src/rust/bitbox02/src/keystore.rs
index 89f54be..c383fcf 100644
--- a/src/rust/bitbox02/src/keystore.rs
+++ b/src/rust/bitbox02/src/keystore.rs
@@ -18,6 +18,8 @@ use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
+use bitcoin::secp256k1::{All, Secp256k1};
+
use core::convert::TryInto;
use bitbox02_sys::keystore_error_t;
@@ -173,6 +175,7 @@ pub fn secp256k1_sign(
}
pub fn secp256k1_nonce_commit(
+ secp: &Secp256k1<All>,
private_key: &[u8; 32],
msg: &[u8; 32],
host_commitment: &[u8; 32],
@@ -180,6 +183,7 @@ pub fn secp256k1_nonce_commit(
let mut signer_commitment = [0u8; EC_PUBLIC_KEY_LEN];
match unsafe {
bitbox02_sys::keystore_secp256k1_nonce_commit(
+ secp.ctx().as_ptr().cast(),
private_key.as_ptr(),
msg.as_ptr(),
host_commitment.as_ptr(),
@@ -347,15 +351,21 @@ mod tests {
#[test]
fn test_secp256k1_nonce_commit() {
+ let secp = secp256k1::Secp256k1::new();
+
let private_key =
hex::decode("a2d8cf543c60d65162b5a06f0cef9760c883f8aa09f31236859faa85d0b74c7c")
.unwrap();
let msg = [0x88u8; 32];
let host_commitment = [0xabu8; 32];
- let client_commitment =
- secp256k1_nonce_commit(&private_key.try_into().unwrap(), &msg, &host_commitment)
- .unwrap();
+ let client_commitment = secp256k1_nonce_commit(
+ &secp,
+ &private_key.try_into().unwrap(),
+ &msg,
+ &host_commitment,
+ )
+ .unwrap();
assert_eq!(
hex::encode(client_commitment),
"0381e4136251c87f2947b735159c6dd644a7b58d35b437e20c878e5129f1320e5e",
diff --git a/test/unit-test/test_keystore_antiklepto.c b/test/unit-test/test_keystore_antiklepto.c
index c3d6010..50fa6f7 100644
--- a/test/unit-test/test_keystore_antiklepto.c
+++ b/test/unit-test/test_keystore_antiklepto.c
@@ -93,7 +93,11 @@ static void _test_keystore_antiklepto(void** state)
// Commit - protocol step 2.
assert_true(keystore_secp256k1_nonce_commit(
- xprv_derived.priv_key + 1, msg, host_nonce_commitment, signer_commitment));
+ wally_get_secp_context(),
+ xprv_derived.priv_key + 1,
+ msg,
+ host_nonce_commitment,
+ signer_commitment));
// Protocol step 3: host_nonce sent from host to signer to be used in step 4
// Sign - protocol step 4.
assert_true(
Why this scored 19/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.