sign: Include taproot output key's KeyOriginInfo in sigdata
What changed, and why it matters
This Bitcoin Core change makes the wallet's signing code record key-origin metadata for both the internal key and the final output key of a Taproot address, not just the internal key. That metadata helps external signers (like hardware wallets) understand which key path was used to derive the address. On its own this is a small correctness/data-availability fix; it does not directly change how coins are spent or introduce an obvious exploit, but missing key-origin data could previously have caused signing failures or user confusion for Taproot key-path spends.
Treat as a routine fix. Review related PSBT and hardware-wallet tests to ensure Taproot key-path spends now include output-key KeyOriginInfo. No emergency response is warranted based on this diff alone.
Security signals we found
Missing key-origin metadata for Taproot output key could lead to incomplete PSBT data
External signers may fail to identify the correct derivation path for key-path spends
No direct cryptographic weakness introduced; change is additive metadata recording
Evidence from the diff
In SignTaproot(), the code previously called provider.GetKeyOriginByXOnly() only for sigdata.tr_spenddata.internal_key and stored the resulting KeyOriginInfo in sigdata.taproot_misc_pubkeys. The patch adds the same lookup and storage for the Taproot output key (the tweaked x-only public key). The header comment is updated to note that both internal and output keys are included. This affects PSBT signing flows where key-origin info is propagated to external signers.
Changed components
src/script/sign.cppsrc/script/sign.hTaproot signing / PSBT key-origin propagationInspect captured patch +12 / −4
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 1e40d532..8575c0b9 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -355,11 +355,19 @@ static bool SignTaproot(const SigningProvider& provider, const BaseSignatureCrea
// Try key path spending.
{
- KeyOriginInfo info;
- if (provider.GetKeyOriginByXOnly(sigdata.tr_spenddata.internal_key, info)) {
+ KeyOriginInfo internal_key_info;
+ if (provider.GetKeyOriginByXOnly(sigdata.tr_spenddata.internal_key, internal_key_info)) {
auto it = sigdata.taproot_misc_pubkeys.find(sigdata.tr_spenddata.internal_key);
if (it == sigdata.taproot_misc_pubkeys.end()) {
- sigdata.taproot_misc_pubkeys.emplace(sigdata.tr_spenddata.internal_key, std::make_pair(std::set<uint256>(), info));
+ sigdata.taproot_misc_pubkeys.emplace(sigdata.tr_spenddata.internal_key, std::make_pair(std::set<uint256>(), internal_key_info));
+ }
+ }
+
+ KeyOriginInfo output_key_info;
+ if (provider.GetKeyOriginByXOnly(output, output_key_info)) {
+ auto it = sigdata.taproot_misc_pubkeys.find(output);
+ if (it == sigdata.taproot_misc_pubkeys.end()) {
+ sigdata.taproot_misc_pubkeys.emplace(output, std::make_pair(std::set<uint256>(), output_key_info));
}
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 5af6392b..fea93710 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -80,7 +80,7 @@ struct SignatureData {
std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
std::vector<unsigned char> taproot_key_path_sig; /// Schnorr signature for key path spending
std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> taproot_script_sigs; ///< (Partial) schnorr signatures, indexed by XOnlyPubKey and leaf_hash.
- std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> taproot_misc_pubkeys; ///< Miscellaneous Taproot pubkeys involved in this input along with their leaf script hashes and key origin data. Also includes the Taproot internal key (may have no leaf script hashes).
+ std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> taproot_misc_pubkeys; ///< Miscellaneous Taproot pubkeys involved in this input along with their leaf script hashes and key origin data. Also includes the Taproot internal and output keys (may have no leaf script hashes).
std::map<CKeyID, XOnlyPubKey> tap_pubkeys; ///< Misc Taproot pubkeys involved in this input, by hash. (Equivalent of misc_pubkeys but for Taproot.)
std::vector<CKeyID> missing_pubkeys; ///< KeyIDs of pubkeys which could not be found
std::vector<CKeyID> missing_sigs; ///< KeyIDs of pubkeys for signatures which could not be found
Why this scored 27/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.