diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dac8872080a..ef4fc0bb0d9 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) @@ -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..a3f205bd3a0 --- /dev/null +++ b/src/musig.h @@ -0,0 +1,18 @@ +// 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 + +struct secp256k1_musig_keyagg_cache; + +bool GetMuSig2KeyAggCache(const std::vector& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache); +std::optional GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& cache); +std::optional MuSig2AggregatePubkeys(const std::vector& pubkeys); + +#endif // BITCOIN_MUSIG_H diff --git a/src/pubkey.cpp b/src/pubkey.cpp index a4ca9a170a9..4c77f065b49 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -197,20 +197,29 @@ constexpr XOnlyPubKey XOnlyPubKey::NUMS_H{ []() consteval { return XOnlyPubKey{"50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"_hex_u8}; }(), }; +std::vector XOnlyPubKey::GetCPubKeys() const +{ + 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); + b[0] = 0x03; + fullpubkey.Set(b, b + 33); + out.push_back(fullpubkey); + return out; +} + std::vector XOnlyPubKey::GetKeyIDs() 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. - 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()); - b[0] = 0x03; - fullpubkey.Set(b, b + 33); - out.push_back(fullpubkey.GetID()); + for (const CPubKey& pk : GetCPubKeys()) { + out.push_back(pk.GetID()); + } return out; } diff --git a/src/pubkey.h b/src/pubkey.h index cbc827dc606..3a182f3a847 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -286,6 +286,7 @@ public: * This is needed for key lookups since keys are indexed by CKeyID. */ std::vector GetKeyIDs() const; + std::vector GetCPubKeys() const; CPubKey GetEvenCorrespondingCPubKey() const; diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 0b7cd4a4dc1..ad9534c11fb 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include