Bitcoin Core  31.0.0
P2P Digital Currency
musig.cpp
Go to the documentation of this file.
1 // Copyright (c) 2024-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <musig.h>
7 
8 #include <secp256k1_musig.h>
9 
11 using namespace util::hex_literals;
13  // Use immediate lambda to work around GCC-14 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117966
14  []() consteval { return uint256{"868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965"_hex_u8}; }(),
15 };
16 
17 static bool GetMuSig2KeyAggCache(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache)
18 {
19  // Parse the pubkeys
20  std::vector<secp256k1_pubkey> secp_pubkeys;
21  std::vector<const secp256k1_pubkey*> pubkey_ptrs;
22  for (const CPubKey& pubkey : pubkeys) {
23  if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pubkeys.emplace_back(), pubkey.data(), pubkey.size())) {
24  return false;
25  }
26  }
27  pubkey_ptrs.reserve(secp_pubkeys.size());
28  for (const secp256k1_pubkey& p : secp_pubkeys) {
29  pubkey_ptrs.push_back(&p);
30  }
31 
32  // Aggregate the pubkey
33  if (!secp256k1_musig_pubkey_agg(secp256k1_context_static, nullptr, &keyagg_cache, pubkey_ptrs.data(), pubkey_ptrs.size())) {
34  return false;
35  }
36  return true;
37 }
38 
39 static std::optional<CPubKey> GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& keyagg_cache)
40 {
41  // Get the plain aggregated pubkey
42  secp256k1_pubkey agg_pubkey;
43  if (!secp256k1_musig_pubkey_get(secp256k1_context_static, &agg_pubkey, &keyagg_cache)) {
44  return std::nullopt;
45  }
46 
47  // Turn into CPubKey
48  unsigned char ser_agg_pubkey[CPubKey::COMPRESSED_SIZE];
49  size_t ser_agg_pubkey_len = CPubKey::COMPRESSED_SIZE;
50  secp256k1_ec_pubkey_serialize(secp256k1_context_static, ser_agg_pubkey, &ser_agg_pubkey_len, &agg_pubkey, SECP256K1_EC_COMPRESSED);
51  return CPubKey(ser_agg_pubkey, ser_agg_pubkey + ser_agg_pubkey_len);
52 }
53 
54 std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache, const std::optional<CPubKey>& expected_aggregate)
55 {
56  if (!GetMuSig2KeyAggCache(pubkeys, keyagg_cache)) {
57  return std::nullopt;
58  }
59  std::optional<CPubKey> agg_key = GetCPubKeyFromMuSig2KeyAggCache(keyagg_cache);
60  if (!agg_key.has_value()) return std::nullopt;
61  if (expected_aggregate.has_value() && expected_aggregate != agg_key) return std::nullopt;
62  return agg_key;
63 }
64 
65 std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys)
66 {
67  secp256k1_musig_keyagg_cache keyagg_cache;
68  return MuSig2AggregatePubkeys(pubkeys, keyagg_cache, std::nullopt);
69 }
70 
72 {
73  CExtPubKey extpub;
74  extpub.nDepth = 0;
75  std::memset(extpub.vchFingerprint, 0, 4);
76  extpub.nChild = 0;
77  extpub.chaincode = MUSIG_CHAINCODE;
78  extpub.pubkey = pubkey;
79  return extpub;
80 }
81 
83 {
84 private:
87 
88 public:
89  MuSig2SecNonceImpl() : m_nonce{make_secure_unique<secp256k1_musig_secnonce>()} {}
90 
91  // Delete copy constructors
92  MuSig2SecNonceImpl(const MuSig2SecNonceImpl&) = delete;
93  MuSig2SecNonceImpl& operator=(const MuSig2SecNonceImpl&) = delete;
94 
95  secp256k1_musig_secnonce* Get() const { return m_nonce.get(); }
96  void Invalidate() { m_nonce.reset(); }
97  bool IsValid() { return m_nonce != nullptr; }
98 };
99 
100 MuSig2SecNonce::MuSig2SecNonce() : m_impl{std::make_unique<MuSig2SecNonceImpl>()} {}
101 
102 MuSig2SecNonce::MuSig2SecNonce(MuSig2SecNonce&&) noexcept = default;
103 MuSig2SecNonce& MuSig2SecNonce::operator=(MuSig2SecNonce&&) noexcept = default;
104 
105 MuSig2SecNonce::~MuSig2SecNonce() = default;
106 
108 {
109  return m_impl->Get();
110 }
111 
113 {
114  return m_impl->Invalidate();
115 }
116 
118 {
119  return m_impl->IsValid();
120 }
121 
122 uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash)
123 {
124  HashWriter hasher;
125  hasher << script_pubkey << part_pubkey << sighash;
126  return hasher.GetSHA256();
127 }
128 
129 std::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)
130 {
131  if (!part_pubkeys.size()) return std::nullopt;
132 
133  // Get the keyagg cache and aggregate pubkey
134  secp256k1_musig_keyagg_cache keyagg_cache;
135  if (!MuSig2AggregatePubkeys(part_pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
136 
137  // Check if enough pubnonces and partial sigs
138  if (pubnonces.size() != part_pubkeys.size()) return std::nullopt;
139  if (partial_sigs.size() != part_pubkeys.size()) return std::nullopt;
140 
141  // Parse the pubnonces and partial sigs
142  std::vector<std::tuple<secp256k1_pubkey, secp256k1_musig_pubnonce, secp256k1_musig_partial_sig>> signers_data;
143  std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
144  std::vector<const secp256k1_musig_partial_sig*> partial_sig_ptrs;
145  for (const CPubKey& part_pk : part_pubkeys) {
146  const auto& pn_it = pubnonces.find(part_pk);
147  if (pn_it == pubnonces.end()) return std::nullopt;
148  const std::vector<uint8_t> pubnonce = pn_it->second;
149  if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
150  const auto& it = partial_sigs.find(part_pk);
151  if (it == partial_sigs.end()) return std::nullopt;
152  const uint256& partial_sig = it->second;
153 
154  auto& [secp_pk, secp_pn, secp_ps] = signers_data.emplace_back();
155 
156  if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
157  return std::nullopt;
158  }
159 
160  if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
161  return std::nullopt;
162  }
163 
164  if (!secp256k1_musig_partial_sig_parse(secp256k1_context_static, &secp_ps, partial_sig.data())) {
165  return std::nullopt;
166  }
167  }
168  pubnonce_ptrs.reserve(signers_data.size());
169  partial_sig_ptrs.reserve(signers_data.size());
170  for (auto& [_, pn, ps] : signers_data) {
171  pubnonce_ptrs.push_back(&pn);
172  partial_sig_ptrs.push_back(&ps);
173  }
174 
175  // Aggregate nonces
176  secp256k1_musig_aggnonce aggnonce;
177  if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
178  return std::nullopt;
179  }
180 
181  // Apply tweaks
182  for (const auto& [tweak, xonly] : tweaks) {
183  if (xonly) {
184  if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
185  return std::nullopt;
186  }
187  } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
188  return std::nullopt;
189  }
190  }
191 
192  // Create musig_session
193  secp256k1_musig_session session;
194  if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
195  return std::nullopt;
196  }
197 
198  // Verify partial sigs
199  for (const auto& [pk, pb, ps] : signers_data) {
200  if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &ps, &pb, &pk, &keyagg_cache, &session)) {
201  return std::nullopt;
202  }
203  }
204 
205  // Aggregate partial sigs
206  std::vector<uint8_t> sig;
207  sig.resize(64);
208  if (!secp256k1_musig_partial_sig_agg(secp256k1_context_static, sig.data(), &session, partial_sig_ptrs.data(), partial_sig_ptrs.size())) {
209  return std::nullopt;
210  }
211 
212  return sig;
213 }
unsigned char data[132]
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(const secp256k1_context *ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Obtain the aggregate public key from a keyagg_cache.
Definition: keyagg_impl.h:229
This module implements BIP 327 "MuSig2 for BIP340-compatible Multi-Signatures" (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki) v1.0.0.
unsigned char vchFingerprint[4]
Definition: pubkey.h:339
Opaque data structure that holds an aggregate public nonce.
SECP256K1_API const secp256k1_context *const secp256k1_context_static
A built-in constant secp256k1 context object with static storage duration, to be used in conjunction ...
Definition: secp256k1.h:245
SECP256K1_API int secp256k1_musig_nonce_agg(const secp256k1_context *ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce *const *pubnonces, size_t n_pubnonces) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Aggregates the nonces of all signers into a single nonce.
Definition: session_impl.h:522
unsigned char nDepth
Definition: pubkey.h:338
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(const secp256k1_context *ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6)
Verifies an individual signer&#39;s partial signature.
Definition: session_impl.h:719
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse(const secp256k1_context *ctx, secp256k1_musig_pubnonce *nonce, const unsigned char *in66) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a signer&#39;s public nonce.
Definition: session_impl.h:188
MuSig2SecNonce encapsulates a secret nonce in use in a MuSig2 signing session.
Definition: musig.h:39
constexpr size_t MUSIG2_PUBNONCE_SIZE
Definition: musig.h:17
SECP256K1_API int secp256k1_ec_pubkey_serialize(const secp256k1_context *ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey *pubkey, unsigned int flags) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Serialize a pubkey object into a serialized byte sequence.
Definition: secp256k1.c:268
uint256 MuSig2SessionID(const CPubKey &script_pubkey, const CPubKey &part_pubkey, const uint256 &sighash)
Definition: musig.cpp:122
ChainCode chaincode
Definition: pubkey.h:341
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
bool IsValid()
Definition: musig.cpp:97
static int tweak(const secp256k1_context *ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache)
Definition: musig.c:64
unsigned int nChild
Definition: pubkey.h:340
std::unique_ptr< T, SecureUniqueDeleter< T > > secure_unique_ptr
Definition: secure.h:63
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context *ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding the generator multiplied ...
Definition: keyagg_impl.h:279
secure_unique_ptr< secp256k1_musig_secnonce > m_nonce
The actual secnonce itself.
Definition: musig.cpp:86
secp256k1_musig_secnonce * Get() const
Definition: musig.cpp:107
#define SECP256K1_EC_COMPRESSED
Flag to pass to secp256k1_ec_pubkey_serialize.
Definition: secp256k1.h:224
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(const secp256k1_context *ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5)
Takes the aggregate nonce and creates a session that is required for signing and verification of part...
Definition: session_impl.h:603
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:40
uint256 GetSHA256()
Compute the SHA256 hash of all data written to this object.
Definition: hash.h:126
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg(const secp256k1_context *ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey *const *pubkeys, size_t n_pubkeys) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4)
Computes an aggregate public key and uses it to initialize a keyagg_cache.
Definition: keyagg_impl.h:168
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
An encapsulated public key.
Definition: pubkey.h:33
SECP256K1_API int secp256k1_musig_partial_sig_agg(const secp256k1_context *ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig *const *partial_sigs, size_t n_sigs) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Aggregates partial signatures.
Definition: session_impl.h:782
unsigned char data[133]
bool IsValid()
Definition: musig.cpp:117
Opaque data structure that holds a signer&#39;s secret nonce.
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a variable-length public key into the pubkey object.
Definition: secp256k1.c:250
""_hex is a compile-time user-defined literal returning a std::array<std::byte>, equivalent to ParseH...
Definition: strencodings.h:400
static std::optional< CPubKey > GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache &keyagg_cache)
Definition: musig.cpp:39
CExtPubKey CreateMuSig2SyntheticXpub(const CPubKey &pubkey)
Construct the BIP 328 synthetic xpub for a pubkey.
Definition: musig.cpp:71
secp256k1_musig_secnonce * Get() const
Definition: musig.cpp:95
std::unique_ptr< MuSig2SecNonceImpl > m_impl
Definition: musig.h:42
std::optional< CPubKey > MuSig2AggregatePubkeys(const std::vector< CPubKey > &pubkeys, secp256k1_musig_keyagg_cache &keyagg_cache, const std::optional< CPubKey > &expected_aggregate)
Compute the full aggregate pubkey from the given participant pubkeys in their current order...
Definition: musig.cpp:54
256-bit opaque blob.
Definition: uint256.h:195
Opaque data structure that holds a MuSig session.
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context *ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
Apply x-only tweaking to a public key in a given keyagg_cache by adding the generator multiplied with...
Definition: keyagg_impl.h:283
void Invalidate()
Definition: musig.cpp:112
constexpr const unsigned char * data() const
Definition: uint256.h:97
static bool GetMuSig2KeyAggCache(const std::vector< CPubKey > &pubkeys, secp256k1_musig_keyagg_cache &keyagg_cache)
Definition: musig.cpp:17
void Invalidate()
Definition: musig.cpp:96
CPubKey pubkey
Definition: pubkey.h:342
std::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)
Definition: musig.cpp:129
Opaque data structure that holds a parsed and valid public key.
Definition: secp256k1.h:61
constexpr uint256 MUSIG_CHAINCODE
Definition: musig.cpp:12
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse(const secp256k1_context *ctx, secp256k1_musig_partial_sig *sig, const unsigned char *in32) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
Parse a MuSig partial signature.
Definition: session_impl.h:262