From 5fe4c66462e6149c2ed3ce24224a7a7b328a2cfa Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 29 Jan 2024 17:32:02 -0500 Subject: [PATCH 01/12] XOnlyPubKey: Add GetCPubKeys We need to retrieve the even and odd compressed pubkeys for xonly pubkeys, so add a function to do that. Also reuse it in GetKeyIDs. --- src/pubkey.cpp | 20 +++++++++++++------- src/pubkey.h | 4 ++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/pubkey.cpp b/src/pubkey.cpp index a4ca9a170a9..6041c89e7f1 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -197,20 +197,26 @@ constexpr XOnlyPubKey XOnlyPubKey::NUMS_H{ []() consteval { return XOnlyPubKey{"50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"_hex_u8}; }(), }; -std::vector XOnlyPubKey::GetKeyIDs() const +std::vector XOnlyPubKey::GetCPubKeys() const { - std::vector out; - // For now, use the old full pubkey-based key derivation logic. As it is indexed by - // Hash160(full pubkey), we need to return both a version prefixed with 0x02, and one - // with 0x03. + std::vector out; unsigned char b[33] = {0x02}; std::copy(m_keydata.begin(), m_keydata.end(), b + 1); CPubKey fullpubkey; fullpubkey.Set(b, b + 33); - out.push_back(fullpubkey.GetID()); + out.push_back(fullpubkey); b[0] = 0x03; fullpubkey.Set(b, b + 33); - out.push_back(fullpubkey.GetID()); + out.push_back(fullpubkey); + return out; +} + +std::vector XOnlyPubKey::GetKeyIDs() const +{ + std::vector out; + for (const CPubKey& pk : GetCPubKeys()) { + out.push_back(pk.GetID()); + } return out; } diff --git a/src/pubkey.h b/src/pubkey.h index cbc827dc606..442dc2d6431 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -283,9 +283,13 @@ public: std::optional> CreateTapTweak(const uint256* merkle_root) const; /** Returns a list of CKeyIDs for the CPubKeys that could have been used to create this XOnlyPubKey. + * As the CKeyID is the Hash160(full pubkey), the produced CKeyIDs are for the versions of this + * XOnlyPubKey with 0x02 and 0x03 prefixes. * This is needed for key lookups since keys are indexed by CKeyID. */ std::vector GetKeyIDs() const; + /** Returns this XOnlyPubKey with 0x02 and 0x03 prefixes */ + std::vector GetCPubKeys() const; CPubKey GetEvenCorrespondingCPubKey() const; From 88113125716c50ce4deb864041840d53a567554c Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 15 Jan 2024 17:08:47 -0500 Subject: [PATCH 02/12] script/parsing: Allow Const to not skip the found constant When parsing a descriptor, it is useful to be able to check whether a string begins with a substring without consuming that substring as another function such as Func() will be used later which requires that substring to be present at the beginning. Specifically, for MuSig2, this modified Const will be used to determine whether a an expression begins with "musig(" before a subsequent Func("musig", ...) is used. --- src/script/parsing.cpp | 4 ++-- src/script/parsing.h | 4 ++-- src/test/util_tests.cpp | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/script/parsing.cpp b/src/script/parsing.cpp index 254ced6f0b0..dd79f67e58e 100644 --- a/src/script/parsing.cpp +++ b/src/script/parsing.cpp @@ -12,10 +12,10 @@ namespace script { -bool Const(const std::string& str, std::span& sp) +bool Const(const std::string& str, std::span& sp, bool skip) { if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) { - sp = sp.subspan(str.size()); + if (skip) sp = sp.subspan(str.size()); return true; } return false; diff --git a/src/script/parsing.h b/src/script/parsing.h index 8986aa57d07..462a42e7b5e 100644 --- a/src/script/parsing.h +++ b/src/script/parsing.h @@ -13,10 +13,10 @@ namespace script { /** Parse a constant. * - * If sp's initial part matches str, sp is updated to skip that part, and true is returned. + * If sp's initial part matches str, sp is optionally updated to skip that part, and true is returned. * Otherwise sp is unmodified and false is returned. */ -bool Const(const std::string& str, std::span& sp); +bool Const(const std::string& str, std::span& sp, bool skip = true); /** Parse a function call. * diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 05d2c914c6a..8016c2d8c56 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1137,13 +1137,24 @@ BOOST_AUTO_TEST_CASE(test_script_parsing) BOOST_CHECK(success); BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney"); + success = Const("Milk", sp, /*skip=*/false); + BOOST_CHECK(success); + BOOST_CHECK_EQUAL(SpanToStr(sp), "MilkToastHoney"); + success = Const("Milk", sp); BOOST_CHECK(success); BOOST_CHECK_EQUAL(SpanToStr(sp), "ToastHoney"); + success = Const("Bread", sp, /*skip=*/false); + BOOST_CHECK(!success); + success = Const("Bread", sp); BOOST_CHECK(!success); + success = Const("Toast", sp, /*skip=*/false); + BOOST_CHECK(success); + BOOST_CHECK_EQUAL(SpanToStr(sp), "ToastHoney"); + success = Const("Toast", sp); BOOST_CHECK(success); BOOST_CHECK_EQUAL(SpanToStr(sp), "Honey"); @@ -1151,10 +1162,13 @@ BOOST_AUTO_TEST_CASE(test_script_parsing) success = Const("Honeybadger", sp); BOOST_CHECK(!success); + success = Const("Honey", sp, /*skip=*/false); + BOOST_CHECK(success); + BOOST_CHECK_EQUAL(SpanToStr(sp), "Honey"); + success = Const("Honey", sp); BOOST_CHECK(success); BOOST_CHECK_EQUAL(SpanToStr(sp), ""); - // Func(...): parse a function call, update span to argument if successful input = "Foo(Bar(xy,z()))"; sp = input; From 12bc1d0b1e9681c338c9d0df0bbac1d4a3162322 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 14 Apr 2025 13:31:31 -0700 Subject: [PATCH 03/12] util/string: Allow Split to include the separator When splitting a string, sometimes the separator needs to be included. Split will now optionally include the separator at the end of the left side of the splits, i.e. it appears at the end of the splits, except for the last one. Specifically, for musig() descriptors, Split is used to separate a musig() from any derivation path that follows it by splitting on the closing parentheses. Since that parentheses is needed for Func() and Expr(), Split() needs to preserve the end parentheses instead of discarding it. --- src/test/util_tests.cpp | 13 +++++++++++++ src/util/string.h | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 8016c2d8c56..f9038c4fc97 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1246,6 +1246,12 @@ BOOST_AUTO_TEST_CASE(test_script_parsing) BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two"); BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three"); + results = Split(input, '#', /*include_sep=*/true); + BOOST_CHECK_EQUAL(results.size(), 3U); + BOOST_CHECK_EQUAL(SpanToStr(results[0]), "one#"); + BOOST_CHECK_EQUAL(SpanToStr(results[1]), "two#"); + BOOST_CHECK_EQUAL(SpanToStr(results[2]), "three"); + input = "*foo*bar*"; results = Split(input, '*'); BOOST_CHECK_EQUAL(results.size(), 4U); @@ -1253,6 +1259,13 @@ BOOST_AUTO_TEST_CASE(test_script_parsing) BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo"); BOOST_CHECK_EQUAL(SpanToStr(results[2]), "bar"); BOOST_CHECK_EQUAL(SpanToStr(results[3]), ""); + + results = Split(input, '*', /*include_sep=*/true); + BOOST_CHECK_EQUAL(results.size(), 4U); + BOOST_CHECK_EQUAL(SpanToStr(results[0]), "*"); + BOOST_CHECK_EQUAL(SpanToStr(results[1]), "foo*"); + BOOST_CHECK_EQUAL(SpanToStr(results[2]), "bar*"); + BOOST_CHECK_EQUAL(SpanToStr(results[3]), ""); } BOOST_AUTO_TEST_CASE(test_SplitString) diff --git a/src/util/string.h b/src/util/string.h index 4b875256275..330c2a2a61e 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -100,18 +100,30 @@ void ReplaceAll(std::string& in_out, const std::string& search, const std::strin * * If sep does not occur in sp, a singleton with the entirety of sp is returned. * + * @param[in] include_sep Whether to include the separator at the end of the left side of the splits. + * * Note that this function does not care about braces, so splitting * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. + * + * If include_sep == true, splitting "foo(bar(1),2),3) on ',' + * will return: + * - foo(bar(1), + * - 2), + * - 3) */ template > -std::vector Split(const std::span& sp, std::string_view separators) +std::vector Split(const std::span& sp, std::string_view separators, bool include_sep = false) { std::vector ret; auto it = sp.begin(); auto start = it; while (it != sp.end()) { if (separators.find(*it) != std::string::npos) { - ret.emplace_back(start, it); + if (include_sep) { + ret.emplace_back(start, it + 1); + } else { + ret.emplace_back(start, it); + } start = it + 1; } ++it; @@ -128,9 +140,9 @@ std::vector Split(const std::span& sp, std::string_view separator * "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}. */ template > -std::vector Split(const std::span& sp, char sep) +std::vector Split(const std::span& sp, char sep, bool include_sep = false) { - return Split(sp, std::string_view{&sep, 1}); + return Split(sp, std::string_view{&sep, 1}, include_sep); } [[nodiscard]] inline std::vector SplitString(std::string_view str, char sep) From 1894f975032013ef855c438654fbb745512e7982 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 15 Jan 2024 17:09:22 -0500 Subject: [PATCH 04/12] descriptors: Add PubkeyProvider::IsBIP32() --- src/script/descriptor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 71645c87462..d5e4bc2195f 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -221,6 +221,9 @@ public: /** Make a deep copy of this PubkeyProvider */ virtual std::unique_ptr Clone() const = 0; + + /** Whether this PubkeyProvider is a BIP 32 extended key that can be derived from */ + virtual bool IsBIP32() const = 0; }; class OriginPubkeyProvider final : public PubkeyProvider @@ -251,6 +254,7 @@ public: } bool IsRange() const override { return m_provider->IsRange(); } size_t GetSize() const override { return m_provider->GetSize(); } + bool IsBIP32() const override { return m_provider->IsBIP32(); } std::string ToString(StringType type) const override { return "[" + OriginString(type) + "]" + m_provider->ToString(type); } bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override { @@ -319,6 +323,7 @@ public: } bool IsRange() const override { return false; } size_t GetSize() const override { return m_pubkey.size(); } + bool IsBIP32() const override { return false; } std::string ToString(StringType type) const override { return m_xonly ? HexStr(m_pubkey).substr(2) : HexStr(m_pubkey); } bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override { @@ -406,6 +411,7 @@ public: BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive, bool apostrophe) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive), m_apostrophe(apostrophe) {} bool IsRange() const override { return m_derive != DeriveType::NO; } size_t GetSize() const override { return 33; } + bool IsBIP32() const override { return true; } std::optional GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override { KeyOriginInfo info; From fac0ee0bfc910a82678a3f8ec13c47967fd7def2 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Tue, 5 Nov 2024 15:09:55 -0500 Subject: [PATCH 05/12] build: Enable secp256k1 musig module --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82bb4de460a..1099ed39218 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,7 +31,7 @@ message("Configuring secp256k1 subtree...") set(SECP256K1_DISABLE_SHARED ON CACHE BOOL "" FORCE) set(SECP256K1_ENABLE_MODULE_ECDH OFF CACHE BOOL "" FORCE) set(SECP256K1_ENABLE_MODULE_RECOVERY ON CACHE BOOL "" FORCE) -set(SECP256K1_ENABLE_MODULE_MUSIG OFF CACHE BOOL "" FORCE) +set(SECP256K1_ENABLE_MODULE_MUSIG ON CACHE BOOL "" FORCE) set(SECP256K1_BUILD_BENCHMARK OFF CACHE BOOL "" FORCE) set(SECP256K1_BUILD_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE) set(SECP256K1_BUILD_EXHAUSTIVE_TESTS ${BUILD_TESTS} CACHE BOOL "" FORCE) From 8ecea91bf296b8fae8b84c3dbf68d5703821cb79 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 22 Jan 2024 16:43:26 -0500 Subject: [PATCH 06/12] sign: Add GetMuSig2ParticipantPubkeys to SigningProvider --- src/script/signingprovider.cpp | 13 +++++++++++++ src/script/signingprovider.h | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index 07a1956eabc..792796b0f14 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -52,6 +52,11 @@ bool HidingSigningProvider::GetTaprootBuilder(const XOnlyPubKey& output_key, Tap { return m_provider->GetTaprootBuilder(output_key, builder); } +std::vector HidingSigningProvider::GetMuSig2ParticipantPubkeys(const CPubKey& pubkey) const +{ + if (m_hide_origin) return {}; + return m_provider->GetMuSig2ParticipantPubkeys(pubkey); +} bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); } @@ -82,6 +87,13 @@ bool FlatSigningProvider::GetTaprootBuilder(const XOnlyPubKey& output_key, Tapro return LookupHelper(tr_trees, output_key, builder); } +std::vector FlatSigningProvider::GetMuSig2ParticipantPubkeys(const CPubKey& pubkey) const +{ + std::vector participant_pubkeys; + LookupHelper(aggregate_pubkeys, pubkey, participant_pubkeys); + return participant_pubkeys; +} + FlatSigningProvider& FlatSigningProvider::Merge(FlatSigningProvider&& b) { scripts.merge(b.scripts); @@ -89,6 +101,7 @@ FlatSigningProvider& FlatSigningProvider::Merge(FlatSigningProvider&& b) keys.merge(b.keys); origins.merge(b.origins); tr_trees.merge(b.tr_trees); + aggregate_pubkeys.merge(b.aggregate_pubkeys); return *this; } diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index f4c823be393..1da58bf6f92 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -161,6 +161,7 @@ public: virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; } virtual bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const { return false; } virtual bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const { return false; } + virtual std::vector GetMuSig2ParticipantPubkeys(const CPubKey& pubkey) const { return {}; } bool GetKeyByXOnly(const XOnlyPubKey& pubkey, CKey& key) const { @@ -204,6 +205,7 @@ public: bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override; bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const override; + std::vector GetMuSig2ParticipantPubkeys(const CPubKey& pubkey) const override; }; struct FlatSigningProvider final : public SigningProvider @@ -213,6 +215,7 @@ struct FlatSigningProvider final : public SigningProvider std::map> origins; std::map keys; std::map tr_trees; /** Map from output key to Taproot tree (which can then make the TaprootSpendData */ + std::map> aggregate_pubkeys; /** MuSig2 aggregate pubkeys */ bool GetCScript(const CScriptID& scriptid, CScript& script) const override; bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override; @@ -221,6 +224,7 @@ struct FlatSigningProvider final : public SigningProvider bool GetKey(const CKeyID& keyid, CKey& key) const override; bool GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const override; bool GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const override; + std::vector GetMuSig2ParticipantPubkeys(const CPubKey& pubkey) const override; FlatSigningProvider& Merge(FlatSigningProvider&& b) LIFETIMEBOUND; }; From d00d95437dd113a23ccd556c25a77bb04bce23f7 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 22 Jan 2024 15:18:28 -0500 Subject: [PATCH 07/12] Add MuSig2 Keyagg Cache helper functions secp256k1 provides us secp256k1_musig_keyagg_cache objects which we are used as part of session info and to get the aggregate pubkey. These helper functions help us convert to/from the secp256k1 C objects into the Bitcoin Core C++ objects. --- src/CMakeLists.txt | 1 + src/musig.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++ src/musig.h | 22 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/musig.cpp create mode 100644 src/musig.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1099ed39218..1dbabb57d67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -161,6 +161,7 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL key.cpp key_io.cpp merkleblock.cpp + musig.cpp net_permissions.cpp net_types.cpp netaddress.cpp diff --git a/src/musig.cpp b/src/musig.cpp new file mode 100644 index 00000000000..b3329543127 --- /dev/null +++ b/src/musig.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +bool GetMuSig2KeyAggCache(const std::vector& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache) +{ + // Parse the pubkeys + std::vector secp_pubkeys; + std::vector pubkey_ptrs; + for (const CPubKey& pubkey : pubkeys) { + if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pubkeys.emplace_back(), pubkey.data(), pubkey.size())) { + return false; + } + } + pubkey_ptrs.reserve(secp_pubkeys.size()); + for (const secp256k1_pubkey& p : secp_pubkeys) { + pubkey_ptrs.push_back(&p); + } + + // Aggregate the pubkey + if (!secp256k1_musig_pubkey_agg(secp256k1_context_static, nullptr, &keyagg_cache, pubkey_ptrs.data(), pubkey_ptrs.size())) { + return false; + } + return true; +} + +std::optional GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& keyagg_cache) +{ + // Get the plain aggregated pubkey + secp256k1_pubkey agg_pubkey; + if (!secp256k1_musig_pubkey_get(secp256k1_context_static, &agg_pubkey, &keyagg_cache)) { + return std::nullopt; + } + + // Turn into CPubKey + unsigned char ser_agg_pubkey[CPubKey::COMPRESSED_SIZE]; + size_t ser_agg_pubkey_len = CPubKey::COMPRESSED_SIZE; + secp256k1_ec_pubkey_serialize(secp256k1_context_static, ser_agg_pubkey, &ser_agg_pubkey_len, &agg_pubkey, SECP256K1_EC_COMPRESSED); + return CPubKey(ser_agg_pubkey, ser_agg_pubkey + ser_agg_pubkey_len); +} + +std::optional MuSig2AggregatePubkeys(const std::vector& pubkeys) +{ + secp256k1_musig_keyagg_cache keyagg_cache; + if (!GetMuSig2KeyAggCache(pubkeys, keyagg_cache)) { + return std::nullopt; + } + return GetCPubKeyFromMuSig2KeyAggCache(keyagg_cache); +} diff --git a/src/musig.h b/src/musig.h new file mode 100644 index 00000000000..91aab1d3364 --- /dev/null +++ b/src/musig.h @@ -0,0 +1,22 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_MUSIG_H +#define BITCOIN_MUSIG_H + +#include + +#include +#include + +struct secp256k1_musig_keyagg_cache; + +//! Create a secp256k1_musig_keyagg_cache from the pubkeys in their current order. This is necessary for most MuSig2 operations +bool GetMuSig2KeyAggCache(const std::vector& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache); +//! Retrieve the full aggregate pubkey from the secp256k1_musig_keyagg_cache +std::optional GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& cache); +//! Compute the full aggregate pubkey from the given participant pubkeys in their current order +std::optional MuSig2AggregatePubkeys(const std::vector& pubkeys); + +#endif // BITCOIN_MUSIG_H From 4af0dca096ca497a6b4e5314c9edea683efe620e Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 15 Jan 2024 17:10:08 -0500 Subject: [PATCH 08/12] descriptor: Add MuSigPubkeyProvider --- src/musig.h | 4 + src/script/descriptor.cpp | 209 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/src/musig.h b/src/musig.h index 91aab1d3364..d46a67f65ec 100644 --- a/src/musig.h +++ b/src/musig.h @@ -12,6 +12,10 @@ struct secp256k1_musig_keyagg_cache; +//! MuSig2 chaincode as defined by BIP 328 +using namespace util::hex_literals; +constexpr uint256 MUSIG_CHAINCODE{"868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965"_hex_u8}; + //! Create a secp256k1_musig_keyagg_cache from the pubkeys in their current order. This is necessary for most MuSig2 operations bool GetMuSig2KeyAggCache(const std::vector& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache); //! Retrieve the full aggregate pubkey from the secp256k1_musig_keyagg_cache diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index d5e4bc2195f..ddf8aecd6c5 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include