Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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.
2001if (pubkey.IsFullyValid()) {2002ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true));2003++key_exp_index;2004return ret;2005}2006}2007error = strprintf("Pubkey '%s' is invalid", str);2008return {};2009}2010CKey key = DecodeSecret(str);2011if (key.IsValid()) {2012if (permit_uncompressed || key.IsCompressed()) {2013CPubKey pubkey = key.GetPubKey();2014out.keys.emplace(pubkey.GetID(), key);2015ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR));2016++key_exp_index;2017return ret;2018} else {2019error = "Uncompressed keys are not allowed";2020return {};2021}2022}2023}2024CExtKey extkey = DecodeExtKey(str);2025CExtPubKey extpubkey = DecodeExtPubKey(str);2026if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) {2027error = strprintf("key '%s' is not valid", str);2028return {};2029}2030std::vector<KeyPath> paths;2031DeriveType type = ParseDeriveType(split, apostrophe);2032if (!ParseKeyPath(split, paths, apostrophe, error, /*allow_multipath=*/true)) return {};2033if (extkey.key.IsValid()) {2034extpubkey = extkey.Neuter();2035out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);2036}2037for (auto& path : paths) {2038ret.emplace_back(std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe));2039}2040++key_exp_index;2041return ret;2042}2044/** Parse a public key including origin information (if enabled). */2045// NOLINTNEXTLINE(misc-no-recursion)2046std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkey(uint32_t& key_exp_index, const std::span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)2047{2048std::vector<std::unique_ptr<PubkeyProvider>> ret;2050using namespace script;2052// musig cannot be nested inside of an origin2053std::span<const char> span = sp;2054if (Const("musig(", span, /*skip=*/false)) {2055if (ctx != ParseScriptContext::P2TR) {2056error = "musig() is only allowed in tr() and rawtr()";2057return {};2058}2060// Split the span on the end parentheses. The end parentheses must2061// be included in the resulting span so that Expr is happy.2062auto split = Split(sp, ')', /*include_sep=*/true);2063if (split.size() > 2) {2064error = "Too many ')' in musig() expression";2065return {};2066}2067std::span<const char> expr(split.at(0).begin(), split.at(0).end());2068if (!Func("musig", expr)) {2069error = "Invalid musig() expression";2070return {};2071}2073// Parse the participant pubkeys2074bool any_ranged = false;2075bool all_bip32 = true;2076std::vector<std::vector<std::unique_ptr<PubkeyProvider>>> providers;2077bool any_key_parsed = false;2078size_t max_multipath_len = 0;2079while (expr.size()) {2080if (any_key_parsed && !Const(",", expr)) {2081error = strprintf("musig(): expected ',', got '%c'", expr[0]);2082return {};2083}2084auto arg = Expr(expr);2085auto pk = ParsePubkey(key_exp_index, arg, ParseScriptContext::MUSIG, out, error);2086if (pk.empty()) {2087error = strprintf("musig(): %s", error);2088return {};2089}2090any_key_parsed = true;2092any_ranged = any_ranged || pk.at(0)->IsRange();2093all_bip32 = all_bip32 && pk.at(0)->IsBIP32();2095max_multipath_len = std::max(max_multipath_len, pk.size());2097providers.emplace_back(std::move(pk));2098}2099if (!any_key_parsed) {2100error = "musig(): Must contain key expressions";2101return {};2102}2104// Parse any derivation2105DeriveType deriv_type = DeriveType::NON_RANGED;2106std::vector<KeyPath> derivation_multipaths;2107if (split.size() == 2 && Const("/", split.at(1), /*skip=*/false)) {2108if (!all_bip32) {2109error = "musig(): derivation requires all participants to be xpubs or xprvs";2110return {};2111}2112if (any_ranged) {2113error = "musig(): Cannot have ranged participant keys if musig() also has derivation";2114return {};2115}2116bool dummy = false;2117auto deriv_split = Split(split.at(1), '/');2118deriv_type = ParseDeriveType(deriv_split, dummy);2119if (deriv_type == DeriveType::HARDENED_RANGED) {2120error = "musig(): Cannot have hardened child derivation";2121return {};2122}2123bool has_hardened = false;2124if (!ParseKeyPath(deriv_split, derivation_multipaths, dummy, error, /*allow_multipath=*/true, has_hardened)) {2125error = "musig(): " + error;2126return {};2127}2128if (has_hardened) {2129error = "musig(): cannot have hardened derivation steps";2130return {};2131}2132} else {2133derivation_multipaths.emplace_back();2134}2136// Makes sure that all providers vectors in providers are the given length, or exactly length 12137// Length 1 vectors have the single provider cloned until it matches the given length.2138const auto& clone_providers = [&providers](size_t length) -> bool {2139for (auto& multipath_providers : providers) {2140if (multipath_providers.size() == 1) {2141for (size_t i = 1; i < length; ++i) {2142multipath_providers.emplace_back(multipath_providers.at(0)->Clone());2143}2144} else if (multipath_providers.size() != length) {2145return false;2146}2147}2148return true;2149};2151// Emplace the final MuSigPubkeyProvider into ret with the pubkey providers from the specified provider vectors index2152// and the path from the specified path index2153const auto& emplace_final_provider = [&ret, &key_exp_index, &deriv_type, &derivation_multipaths, &providers](size_t vec_idx, size_t path_idx) -> void {2154KeyPath& path = derivation_multipaths.at(path_idx);2155std::vector<std::unique_ptr<PubkeyProvider>> pubs;2156pubs.reserve(providers.size());2157for (auto& vec : providers) {2158pubs.emplace_back(std::move(vec.at(vec_idx)));2159}2160ret.emplace_back(std::make_unique<MuSigPubkeyProvider>(key_exp_index, std::move(pubs), path, deriv_type));2161};2163if (max_multipath_len > 1 && derivation_multipaths.size() > 1) {2164error = "musig(): Cannot have multipath participant keys if musig() is also multipath";2165return {};2166} else if (max_multipath_len > 1) {2167if (!clone_providers(max_multipath_len)) {2168error = strprintf("musig(): Multipath derivation paths have mismatched lengths");2169return {};2170}2171for (size_t i = 0; i < max_multipath_len; ++i) {2172// Final MuSigPubkeyProvider uses participant pubkey providers at each multipath position, and the first (and only) path2173emplace_final_provider(i, 0);2174}2175} else if (derivation_multipaths.size() > 1) {2176// All key provider vectors should be length 1. Clone them until they have the same length as paths2177if (!Assume(clone_providers(derivation_multipaths.size()))) {2178error = "musig(): Multipath derivation path with multipath participants is disallowed"; // This error is unreachable due to earlier check2179return {};2180}2181for (size_t i = 0; i < derivation_multipaths.size(); ++i) {2182// Final MuSigPubkeyProvider uses cloned participant pubkey providers, and the multipath derivation paths2183emplace_final_provider(i, i);2184}2185} else {2186// No multipath derivation, MuSigPubkeyProvider uses the first (and only) participant pubkey providers, and the first (and only) path2187emplace_final_provider(0, 0);2188}2189++key_exp_index; // Increment key expression index for the MuSigPubkeyProvider too2190return ret;2191}2193auto origin_split = Split(sp, ']');2194if (origin_split.size() > 2) {2195error = "Multiple ']' characters found for a single pubkey";2196return {};2197}2198// This is set if either the origin or path suffix contains a hardened derivation.2199bool apostrophe = false;2200if (origin_split.size() == 1) {2201return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, apostrophe, error);2202}2203if (origin_split[0].empty() || origin_split[0][0] != '[') {2204error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",2205origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);2206return {};2207}2208auto slash_split = Split(origin_split[0].subspan(1), '/');2209if (slash_split[0].size() != 8) {2210error = strprintf("Fingerprint is not 4 bytes (%u characters instead of 8 characters)", slash_split[0].size());2211return {};2212}2213std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].end());2214if (!IsHex(fpr_hex)) {2215error = strprintf("Fingerprint '%s' is not hex", fpr_hex);2216return {};2217}2218auto fpr_bytes = ParseHex(fpr_hex);2219KeyOriginInfo info;2220static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");2221assert(fpr_bytes.size() == 4);2222std::copy_n(fpr_bytes.begin(), info.fingerprint.size(), info.fingerprint.begin());2223std::vector<KeyPath> path;2224if (!ParseKeyPath(slash_split, path, apostrophe, error, /*allow_multipath=*/false)) return {};2225info.path = path.at(0);2226auto providers = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, apostrophe, error);2227if (providers.empty()) return {};2228ret.reserve(providers.size());2229for (auto& prov : providers) {2230ret.emplace_back(std::make_unique<OriginPubkeyProvider>(prov->m_expr_index, info, std::move(prov), apostrophe));2231}2232return ret;2233}2235std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext ctx, const SigningProvider& provider)2236{2237// Key cannot be hybrid2238if (!pubkey.IsValidNonHybrid()) {2239return nullptr;2240}2241// Uncompressed is only allowed in TOP and P2SH contexts2242if (ctx != ParseScriptContext::TOP && ctx != ParseScriptContext::P2SH && !pubkey.IsCompressed()) {2243return nullptr;2244}2245std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, false);2246KeyOriginInfo info;2247if (provider.GetKeyOrigin(pubkey.GetID(), info)) {2248return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider), /*apostrophe=*/false);2249}2250return key_provider;