docs: clarify signing fallback behavior
What changed, and why it matters
This commit only adds documentation comments and does not change any program behavior. It explains that when a security feature called anti-klepto is left out of older Bitcoin and Ethereum signing requests, the device falls back to a historical, deterministic signing method that lacks anti-klepto protection. For EIP-712 typed messages, it falls back to plain RFC6979. No code logic is altered.
No action required; review the documentation for accuracy and consider whether users or SDK maintainers should be encouraged to always supply anti-klepto commitments.
Security signals we found
No functional code changes
Documentation clarifies existing anti-klepto fallback behavior
Mentions lack of anti-klepto protection when host nonce commitment is omitted
Distinguishes legacy S2C fallback from RFC6979
Evidence from the diff
The commit is a documentation-only change across protobuf definitions and generated Rust structs plus inline Rust comments. It clarifies that omitting AntiKleptoHostNonceCommitment in BTC/ETH sign message, sign transaction, ETH sign, and EIP-1559 requests uses a historical deterministic zero-contribution S2C fallback, while ETHSignTypedMessageRequest falls back to plain RFC6979. The actual fallback code (None => [0; 32]) remains unchanged.
Changed components
messages/btc.protomessages/eth.protosrc/rust/bitbox-proto/src/generated/shiftcrypto.bitbox02.rssrc/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rssrc/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rssrc/rust/bitbox02-rust/src/hww/api/ethereum/sign.rssrc/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rsInspect captured patch +34 / −4
### messages/btc.proto
@@ -152,6 +152,8 @@ message BTCSignInputRequest {
repeated uint32 keypath = 6; // all inputs must be ours.
// References a script config from BTCSignInitRequest
uint32 script_config_index = 7;
+ // If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ // This differs from plain RFC6979 and does not provide anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 8;
}
@@ -281,6 +283,8 @@ message BTCSignMessageRequest {
BTCCoin coin = 1;
BTCScriptConfigWithKeypath script_config = 2;
bytes msg = 3;
+ // If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ // This differs from plain RFC6979 and does not provide anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 4;
}
### messages/eth.proto
@@ -48,6 +48,8 @@ message ETHSignRequest {
bytes recipient = 6; // 20 byte recipient
bytes value = 7; // smallest big endian serialization, max. 32 bytes
bytes data = 8;
+ // If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ // This differs from plain RFC6979 and does not provide anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 9;
// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
uint64 chain_id = 10;
@@ -67,6 +69,8 @@ message ETHSignEIP1559Request {
bytes recipient = 7; // 20 byte recipient
bytes value = 8; // smallest big endian serialization, max. 32 bytes
bytes data = 9;
+ // If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ // This differs from plain RFC6979 and does not provide anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 10;
ETHAddressCase address_case = 11;
// For streaming: if non-zero, data field should be empty and data will be requested in chunks
@@ -88,6 +92,8 @@ message ETHSignMessageRequest {
ETHCoin coin = 1;
repeated uint32 keypath = 2;
bytes msg = 3;
+ // If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ // This differs from plain RFC6979 and does not provide anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 4;
// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
uint64 chain_id = 5;
@@ -131,6 +137,7 @@ message ETHSignTypedMessageRequest {
repeated uint32 keypath = 2;
repeated StructType types = 3;
string primary_type = 4;
+ // If omitted, plain RFC6979 signing is used without anti-klepto protection.
AntiKleptoHostNonceCommitment host_nonce_commitment = 5;
}
### src/rust/bitbox-proto/src/generated/shiftcrypto.bitbox02.rs
@@ -804,6 +804,8 @@ pub struct BtcSignInputRequest {
/// References a script config from BTCSignInitRequest
#[prost(uint32, tag = "7")]
pub script_config_index: u32,
+ /// If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ /// This differs from plain RFC6979 and does not provide anti-klepto protection.
#[prost(message, optional, tag = "8")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
}
@@ -1047,6 +1049,8 @@ pub struct BtcSignMessageRequest {
pub script_config: ::core::option::Option<BtcScriptConfigWithKeypath>,
#[prost(bytes = "vec", tag = "3")]
pub msg: ::prost::alloc::vec::Vec<u8>,
+ /// If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ /// This differs from plain RFC6979 and does not provide anti-klepto protection.
#[prost(message, optional, tag = "4")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
}
@@ -1564,6 +1568,8 @@ pub struct EthSignRequest {
pub value: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "8")]
pub data: ::prost::alloc::vec::Vec<u8>,
+ /// If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ /// This differs from plain RFC6979 and does not provide anti-klepto protection.
#[prost(message, optional, tag = "9")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
/// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
@@ -1603,6 +1609,8 @@ pub struct EthSignEip1559Request {
pub value: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "9")]
pub data: ::prost::alloc::vec::Vec<u8>,
+ /// If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ /// This differs from plain RFC6979 and does not provide anti-klepto protection.
#[prost(message, optional, tag = "10")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
#[prost(enumeration = "EthAddressCase", tag = "11")]
@@ -1637,6 +1645,8 @@ pub struct EthSignMessageRequest {
pub keypath: ::prost::alloc::vec::Vec<u32>,
#[prost(bytes = "vec", tag = "3")]
pub msg: ::prost::alloc::vec::Vec<u8>,
+ /// If omitted, the signature uses the historical deterministic zero-contribution S2C fallback.
+ /// This differs from plain RFC6979 and does not provide anti-klepto protection.
#[prost(message, optional, tag = "4")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
/// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
@@ -1661,6 +1671,7 @@ pub struct EthSignTypedMessageRequest {
pub types: ::prost::alloc::vec::Vec<eth_sign_typed_message_request::StructType>,
#[prost(string, tag = "4")]
pub primary_type: ::prost::alloc::string::String,
+ /// If omitted, plain RFC6979 signing is used without anti-klepto protection.
#[prost(message, optional, tag = "5")]
pub host_nonce_commitment: ::core::option::Option<AntiKleptoHostNonceCommitment>,
}
### src/rust/bitbox02-rust/src/hww/api/bitcoin/signmsg.rs
@@ -112,7 +112,9 @@ pub async fn process(
super::antiklepto_get_host_nonce(signer_commitment).await?
}
- // Return signature directly without the anti-klepto protocol, for backwards compatibility.
+ // Return the signature directly without the anti-klepto protocol for backwards
+ // compatibility. Preserve the historical zero-contribution S2C signature; this differs
+ // from plain RFC6979 and does not provide anti-klepto protection.
None => [0; 32],
};
### src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
@@ -1314,7 +1314,9 @@ async fn _process(
.try_into()
.or(Err(Error::InvalidInput))?
}
- // Return signature directly without the anti-klepto protocol, for backwards compatibility.
+ // Return the signature directly without the anti-klepto protocol for backwards
+ // compatibility. Preserve the historical zero-contribution S2C signature; this
+ // differs from plain RFC6979 and does not provide anti-klepto protection.
None => [0; 32],
};
### src/rust/bitbox02-rust/src/hww/api/ethereum/sign.rs
@@ -614,7 +614,9 @@ pub async fn _process(
super::antiklepto_get_host_nonce(signer_commitment).await?
}
- // Return signature directly without the anti-klepto protocol, for backwards compatibility.
+ // Return the signature directly without the anti-klepto protocol for backwards
+ // compatibility. Preserve the historical zero-contribution S2C signature; this differs
+ // from plain RFC6979 and does not provide anti-klepto protection.
None => [0; 32],
};
let sign_result = crate::secp256k1::secp256k1_sign(
### src/rust/bitbox02-rust/src/hww/api/ethereum/signmsg.rs
@@ -71,7 +71,9 @@ pub async fn process(
super::antiklepto_get_host_nonce(signer_commitment).await?
}
- // Return signature directly without the anti-klepto protocol, for backwards compatibility.
+ // Return the signature directly without the anti-klepto protocol for backwards
+ // compatibility. Preserve the historical zero-contribution S2C signature; this differs
+ // from plain RFC6979 and does not provide anti-klepto protection.
None => [0; 32],
};
Why this scored 15/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.