Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251}252const auto& tap_pk_it = sigdata.tap_pubkeys.find(address);253if (tap_pk_it != sigdata.tap_pubkeys.end()) {254pubkey = tap_pk_it->second.GetEvenCorrespondingCPubKey();255return true;256}257// Query the underlying provider258return provider.GetPubKey(address, pubkey);259}261static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion)262{263CKeyID keyid = pubkey.GetID();264const auto it = sigdata.signatures.find(keyid);265if (it != sigdata.signatures.end()) {266sig_out = it->second.second;267return true;268}269KeyOriginInfo info;270if (provider.GetKeyOrigin(keyid, info)) {271sigdata.misc_pubkeys.emplace(keyid, std::make_pair(pubkey, std::move(info)));272}273if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {274auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));275assert(i.second);276return true;277}278// Could not make signature or signature not found, add keyid to missing279sigdata.missing_sigs.push_back(keyid);280return false;281}283static bool SignMuSig2(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const XOnlyPubKey& script_pubkey, const uint256* merkle_root, const uint256* leaf_hash, SigVersion sigversion)284{285Assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);287// Lookup derivation paths for the script pubkey288KeyOriginInfo agg_info;289auto misc_pk_it = sigdata.taproot_misc_pubkeys.find(script_pubkey);290if (misc_pk_it != sigdata.taproot_misc_pubkeys.end()) {291agg_info = misc_pk_it->second.second;292}294for (const auto& [agg_pub, part_pks] : sigdata.musig2_pubkeys) {295if (part_pks.empty()) continue;297// Fill participant derivation path info298for (const auto& part_pk : part_pks) {299KeyOriginInfo part_info;300if (provider.GetKeyOrigin(part_pk.GetID(), part_info)) {301XOnlyPubKey xonly_part(part_pk);302auto it = sigdata.taproot_misc_pubkeys.find(xonly_part);303if (it == sigdata.taproot_misc_pubkeys.end()) {304it = sigdata.taproot_misc_pubkeys.emplace(xonly_part, std::make_pair(std::set<uint256>(), part_info)).first;305}306if (leaf_hash) it->second.first.insert(*leaf_hash);307}308}310// The pubkey in the script may not be the actual aggregate of the participants, but derived from it.311// Check the derivation, and compute the BIP 32 derivation tweaks312std::vector<std::pair<uint256, bool>> tweaks;313CPubKey plain_pub = agg_pub;314if (XOnlyPubKey(agg_pub) != script_pubkey) {315if (agg_info.path.empty()) continue;316if (agg_info.fingerprint != agg_pub.GetID().fingerprint()) {317continue;318}319// Get the BIP32 derivation tweaks320CExtPubKey extpub = CreateMuSig2SyntheticXpub(agg_pub);321for (const uint32_t i : agg_info.path) {322if (i >> 31) return false; // Hardened derivation is not possible from a public key323auto& [t, xonly] = tweaks.emplace_back();324xonly = false;325if (!extpub.Derive(extpub, i, &t)) {326return false;327}328}329if (XOnlyPubKey(extpub.pubkey) != script_pubkey) continue;330plain_pub = extpub.pubkey;331}333// Add the merkle root tweak334if (sigversion == SigVersion::TAPROOT && merkle_root) {335tweaks.emplace_back(script_pubkey.ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root), true);336std::optional<std::pair<XOnlyPubKey, bool>> tweaked = script_pubkey.CreateTapTweak(merkle_root->IsNull() ? nullptr : merkle_root);337if (!Assume(tweaked)) return false;338plain_pub = tweaked->first.GetCPubKeys().at(tweaked->second ? 1 : 0);339}341// First try to aggregate342if (creator.CreateMuSig2AggregateSig(part_pks, sig_out, agg_pub, plain_pub, leaf_hash, tweaks, sigversion, sigdata)) {343if (sigversion == SigVersion::TAPROOT) {344sigdata.taproot_key_path_sig = sig_out;345} else {346auto lookup_key = std::make_pair(script_pubkey, leaf_hash ? *leaf_hash : uint256());347sigdata.taproot_script_sigs[lookup_key] = sig_out;348}349continue;350}351// Cannot aggregate, try making partial sigs for every participant352auto pub_key_leaf_hash = std::make_pair(plain_pub, leaf_hash ? *leaf_hash : uint256());353for (const CPubKey& part_pk : part_pks) {354uint256 partial_sig;355if (creator.CreateMuSig2PartialSig(provider, partial_sig, agg_pub, plain_pub, part_pk, leaf_hash, tweaks, sigversion, sigdata) && Assume(!partial_sig.IsNull())) {356sigdata.musig2_partial_sigs[pub_key_leaf_hash].emplace(part_pk, partial_sig);357}358}359// If there are any partial signatures, continue with next aggregate pubkey360auto partial_sigs_it = sigdata.musig2_partial_sigs.find(pub_key_leaf_hash);361if (partial_sigs_it != sigdata.musig2_partial_sigs.end() && !partial_sigs_it->second.empty()) {362continue;363}364// No partial sigs, try to make pubnonces365std::map<CPubKey, std::vector<uint8_t>>& pubnonces = sigdata.musig2_pubnonces[pub_key_leaf_hash];366for (const CPubKey& part_pk : part_pks) {367if (pubnonces.contains(part_pk)) continue;368std::vector<uint8_t> pubnonce = creator.CreateMuSig2Nonce(provider, agg_pub, plain_pub, part_pk, leaf_hash, merkle_root, sigversion, sigdata);369if (pubnonce.empty()) continue;370pubnonces[part_pk] = std::move(pubnonce);371}372}373return true;374}376static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const XOnlyPubKey& pubkey, const uint256& leaf_hash, SigVersion sigversion)377{378KeyOriginInfo info;379if (provider.GetKeyOriginByXOnly(pubkey, info)) {380auto it = sigdata.taproot_misc_pubkeys.find(pubkey);381if (it == sigdata.taproot_misc_pubkeys.end()) {382sigdata.taproot_misc_pubkeys.emplace(pubkey, std::make_pair(std::set<uint256>({leaf_hash}), info));383} else {384it->second.first.insert(leaf_hash);385}386}388auto lookup_key = std::make_pair(pubkey, leaf_hash);389auto it = sigdata.taproot_script_sigs.find(lookup_key);390if (it != sigdata.taproot_script_sigs.end()) {391sig_out = it->second;392return true;393}395if (creator.CreateSchnorrSig(provider, sig_out, pubkey, &leaf_hash, nullptr, sigversion)) {396sigdata.taproot_script_sigs[lookup_key] = sig_out;397} else if (!SignMuSig2(creator, sigdata, provider, sig_out, pubkey, /*merkle_root=*/nullptr, &leaf_hash, sigversion)) {398return false;399}401return sigdata.taproot_script_sigs.contains(lookup_key);402}404template<typename M, typename K, typename V>405miniscript::Availability MsLookupHelper(const M& map, const K& key, V& value)406{407auto it = map.find(key);408if (it != map.end()) {409value = it->second;410return miniscript::Availability::YES;411}412return miniscript::Availability::NO;413}415/**416* Context for solving a Miniscript.417* If enough material (access to keys, hash preimages, ..) is given, produces a valid satisfaction.418*/419template<typename Pk>420struct Satisfier {421using Key = Pk;423const SigningProvider& m_provider;424SignatureData& m_sig_data;425const BaseSignatureCreator& m_creator;426const CScript& m_witness_script;427//! The context of the script we are satisfying (either P2WSH or Tapscript).428const miniscript::MiniscriptContext m_script_ctx;430explicit Satisfier(const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,431const BaseSignatureCreator& creator LIFETIMEBOUND,432const CScript& witscript LIFETIMEBOUND,433miniscript::MiniscriptContext script_ctx) : m_provider(provider),434m_sig_data(sig_data),435m_creator(creator),436m_witness_script(witscript),437m_script_ctx(script_ctx) {}439static bool KeyCompare(const Key& a, const Key& b) {440return a < b;441}443//! Get a CPubKey from a key hash. Note the key hash may be of an xonly pubkey.444template<typename I>445std::optional<CPubKey> CPubFromPKHBytes(I first, I last) const {446assert(last - first == 20);447CPubKey pubkey;448CKeyID key_id;449std::copy(first, last, key_id.begin());450if (GetPubKey(m_provider, m_sig_data, key_id, pubkey)) return pubkey;451m_sig_data.missing_pubkeys.push_back(key_id);452return {};453}455//! Conversion to raw public key.456std::vector<unsigned char> ToPKBytes(const Key& key) const { return {key.begin(), key.end()}; }458//! Time lock satisfactions.459bool CheckAfter(uint32_t value) const { return m_creator.Checker().CheckLockTime(CScriptNum(value)); }460bool CheckOlder(uint32_t value) const { return m_creator.Checker().CheckSequence(CScriptNum(value)); }462//! Hash preimage satisfactions.463miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {464return MsLookupHelper(m_sig_data.sha256_preimages, hash, preimage);465}466miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {467return MsLookupHelper(m_sig_data.ripemd160_preimages, hash, preimage);468}469miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {470return MsLookupHelper(m_sig_data.hash256_preimages, hash, preimage);471}472miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {473return MsLookupHelper(m_sig_data.hash160_preimages, hash, preimage);474}476miniscript::MiniscriptContext MsContext() const {477return m_script_ctx;478}479};481/** Miniscript satisfier specific to P2WSH context. */482struct WshSatisfier: Satisfier<CPubKey> {483explicit WshSatisfier(const SigningProvider& provider LIFETIMEBOUND, SignatureData& sig_data LIFETIMEBOUND,484const BaseSignatureCreator& creator LIFETIMEBOUND, const CScript& witscript LIFETIMEBOUND)485: Satisfier(provider, sig_data, creator, witscript, miniscript::MiniscriptContext::P2WSH) {}487//! Conversion from a raw compressed public key.488template <typename I>489std::optional<CPubKey> FromPKBytes(I first, I last) const {490CPubKey pubkey{first, last};491if (pubkey.IsValid()) return pubkey;492return {};493}495//! Conversion from a raw compressed public key hash.496template<typename I>497std::optional<CPubKey> FromPKHBytes(I first, I last) const {498return Satisfier::CPubFromPKHBytes(first, last);499}