What changed, and why it matters
This commit hardens Bitcoin Core's MuSig2 multi-signature code by refusing to save a second secret nonce under the same session ID. Before the change, an attacker or buggy caller could potentially overwrite a nonce, which in multi-signature schemes can lead to nonce reuse and theft of funds. The fix uses try_emplace plus an assertion so duplicate session IDs are caught instead of silently replacing the existing nonce.
Review callers of SetMuSig2SecNonce to confirm session_id generation is unique per signing session and that the assertion cannot be triggered by normal operation. Consider whether the Assert should be a softer error in production builds, since an assertion crash is a denial-of-service vector if an attacker can influence session_id selection.
Security signals we found
nonce-reuse prevention in MuSig2 signing
assertion added to enforce single-secnonce-per-session invariant
cryptographic signing state integrity hardening
Evidence from the diff
In FlatSigningProvider::SetMuSig2SecNonce, the code previously called emplace(session_id, nonce), which would silently leave the existing entry unchanged if the key already existed (because std::map::emplace returns without replacing on duplicate keys). The patch switches to try_emplace and adds Assert(inserted). This ensures that a secret nonce is never stored for a session_id that already has one, preventing any scenario where a second nonce could overwrite or coexist with an existing nonce for the same session. In MuSig2, nonce reuse across signing sessions can leak the secret key, so this is a defensive-in-depth fix.
Changed components
src/script/signingprovider.cppFlatSigningProvider::SetMuSig2SecNonceMuSig2 secret nonce storageInspect captured patch +3 / −1
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index 8557eb77..8b1c2563 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -122,7 +122,9 @@ std::map<CPubKey, std::vector<CPubKey>> FlatSigningProvider::GetAllMuSig2Partici
void FlatSigningProvider::SetMuSig2SecNonce(const uint256& session_id, MuSig2SecNonce&& nonce) const
{
if (!Assume(musig2_secnonces)) return;
- musig2_secnonces->emplace(session_id, std::move(nonce));
+ auto [it, inserted] = musig2_secnonces->try_emplace(session_id, std::move(nonce));
+ // No secnonce should exist for this session yet.
+ Assert(inserted);
}
std::optional<std::reference_wrapper<MuSig2SecNonce>> FlatSigningProvider::GetMuSig2SecNonce(const uint256& session_id) const
Why this scored 60/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.