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.
251return sig;252}254std::optional<std::vector<uint8_t>> CreateMuSig2AggregateSig(const std::vector<CPubKey>& part_pubkeys, const CPubKey& aggregate_pubkey, const std::vector<std::pair<uint256, bool>>& tweaks, const uint256& sighash, const std::map<CPubKey, std::vector<uint8_t>>& pubnonces, const std::map<CPubKey, uint256>& partial_sigs)255{256if (!part_pubkeys.size()) return std::nullopt;258// Get the keyagg cache and aggregate pubkey259secp256k1_musig_keyagg_cache keyagg_cache;260if (!MuSig2AggregatePubkeys(part_pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;262// Check if enough pubnonces and partial sigs263if (pubnonces.size() != part_pubkeys.size()) return std::nullopt;264if (partial_sigs.size() != part_pubkeys.size()) return std::nullopt;266// Parse the pubnonces and partial sigs267std::vector<std::tuple<secp256k1_pubkey, secp256k1_musig_pubnonce, secp256k1_musig_partial_sig>> signers_data;268std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;269std::vector<const secp256k1_musig_partial_sig*> partial_sig_ptrs;270for (const CPubKey& part_pk : part_pubkeys) {271const auto& pn_it = pubnonces.find(part_pk);272if (pn_it == pubnonces.end()) return std::nullopt;273const std::vector<uint8_t> pubnonce = pn_it->second;274if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;275const auto& it = partial_sigs.find(part_pk);276if (it == partial_sigs.end()) return std::nullopt;277const uint256& partial_sig = it->second;279auto& [secp_pk, secp_pn, secp_ps] = signers_data.emplace_back();281if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {282return std::nullopt;283}285if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {286return std::nullopt;287}289if (!secp256k1_musig_partial_sig_parse(secp256k1_context_static, &secp_ps, partial_sig.data())) {290return std::nullopt;291}292}293pubnonce_ptrs.reserve(signers_data.size());294partial_sig_ptrs.reserve(signers_data.size());295for (auto& [_, pn, ps] : signers_data) {296pubnonce_ptrs.push_back(&pn);297partial_sig_ptrs.push_back(&ps);298}300// Aggregate nonces301secp256k1_musig_aggnonce aggnonce;302if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {303return std::nullopt;304}306// Apply tweaks307for (const auto& [tweak, xonly] : tweaks) {308if (xonly) {309if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {310return std::nullopt;311}312} else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {313return std::nullopt;314}315}317// Create musig_session318secp256k1_musig_session session;319if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {320return std::nullopt;321}323// Verify partial sigs324for (const auto& [pk, pb, ps] : signers_data) {325if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &ps, &pb, &pk, &keyagg_cache, &session)) {326return std::nullopt;327}328}330// Aggregate partial sigs331std::vector<uint8_t> sig;332sig.resize(64);333if (!secp256k1_musig_partial_sig_agg(secp256k1_context_static, sig.data(), &session, partial_sig_ptrs.data(), partial_sig_ptrs.size())) {334return std::nullopt;335}337return sig;338}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.