pubkey: Return tweaks from BIP32 derivation
What changed, and why it matters
This commit is a small, additive change to Bitcoin Core's public-key derivation code. It adds an optional way for callers to retrieve the 'tweak' value used when deriving child public keys under the BIP32 standard. The change is needed so that a newer multi-signature scheme called MuSig2 can sign with derived keys. There is no direct evidence in the commit that this fixes a security bug; it appears to be a feature or API improvement.
No immediate security action required. Treat as normal code review: verify that callers passing bip32_tweak_out ensure the pointer is valid and that the tweak is handled securely in any future MuSig2 code.
Security signals we found
No security-relevant keywords in commit title or message
No CVE, advisory, or bug-fix language present
Change is purely additive and backward-compatible (optional output pointer)
No new memory allocations or parsing of untrusted input
No changes to consensus-critical validation logic
Evidence from the diff
The patch modifies CPubKey::Derive and CExtPubKey::Derive in src/pubkey.cpp and src/pubkey.h to accept an optional uint256* bip32_tweak_out parameter. When provided, the first 32 bytes of the BIP32Hash output (the chain-code/hash-derived scalar tweak) are copied to the caller. The parameter defaults to nullptr, preserving existing behavior. The commit message states this is needed so MuSig2 can sign with keys derived from an aggregate pubkey. No existing callers are changed in the diff, and no bounds-checking or memory-safety issues are introduced.
Changed components
src/pubkey.cppsrc/pubkey.hCPubKey::DeriveCExtPubKey::DeriveInspect captured patch +8 / −5
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 6041c89e..264f861b 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -338,13 +338,16 @@ bool CPubKey::Decompress() {
return true;
}
-bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
+bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, uint256* bip32_tweak_out) const {
assert(IsValid());
assert((nChild >> 31) == 0);
assert(size() == COMPRESSED_SIZE);
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
+ if (bip32_tweak_out) {
+ memcpy(bip32_tweak_out->begin(), out, 32);
+ }
secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
@@ -409,13 +412,13 @@ void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VE
Decode(&code[4]);
}
-bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
+bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild, uint256* bip32_tweak_out) const {
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(out.vchFingerprint, &id, 4);
out.nChild = _nChild;
- return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);
+ return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode, bip32_tweak_out);
}
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
diff --git a/src/pubkey.h b/src/pubkey.h
index 442dc2d6..5ae7f75d 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -224,7 +224,7 @@ public:
bool Decompress();
//! Derive BIP32 child pubkey.
- [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
+ [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, uint256* bip32_tweak_out = nullptr) const;
};
class XOnlyPubKey
@@ -379,7 +379,7 @@ struct CExtPubKey {
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const;
void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]);
- [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
+ [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild, uint256* bip32_tweak_out = nullptr) const;
};
#endif // BITCOIN_PUBKEY_H
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.