musig.cpp raw
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>
6 #include <key.h>
7 #include <random.h>
8 #include <support/allocators/secure.h>
9
10 #include <secp256k1_musig.h>
11
12 //! MuSig2 chaincode as defined by BIP 328
13 using namespace util::hex_literals;
14 const ChainCode MUSIG_CHAINCODE{"868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965"_hex_u8};
15
16 static bool GetMuSig2KeyAggCache(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache)
17 {
18 if (pubkeys.empty()) {
19 return false;
20 }
21
22 // Parse the pubkeys
23 std::vector<secp256k1_pubkey> secp_pubkeys;
24 std::vector<const secp256k1_pubkey*> pubkey_ptrs;
25 for (const CPubKey& pubkey : pubkeys) {
26 if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pubkeys.emplace_back(), pubkey.data(), pubkey.size())) {
27 return false;
28 }
29 }
30 pubkey_ptrs.reserve(secp_pubkeys.size());
31 for (const secp256k1_pubkey& p : secp_pubkeys) {
32 pubkey_ptrs.push_back(&p);
33 }
34
35 // Aggregate the pubkey
36 if (!secp256k1_musig_pubkey_agg(secp256k1_context_static, nullptr, &keyagg_cache, pubkey_ptrs.data(), pubkey_ptrs.size())) {
37 return false;
38 }
39 return true;
40 }
41
42 static std::optional<CPubKey> GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& keyagg_cache)
43 {
44 // Get the plain aggregated pubkey
45 secp256k1_pubkey agg_pubkey;
46 if (!secp256k1_musig_pubkey_get(secp256k1_context_static, &agg_pubkey, &keyagg_cache)) {
47 return std::nullopt;
48 }
49
50 // Turn into CPubKey
51 unsigned char ser_agg_pubkey[CPubKey::COMPRESSED_SIZE];
52 size_t ser_agg_pubkey_len = CPubKey::COMPRESSED_SIZE;
53 secp256k1_ec_pubkey_serialize(secp256k1_context_static, ser_agg_pubkey, &ser_agg_pubkey_len, &agg_pubkey, SECP256K1_EC_COMPRESSED);
54 return CPubKey(ser_agg_pubkey, ser_agg_pubkey + ser_agg_pubkey_len);
55 }
56
57 std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache, const std::optional<CPubKey>& expected_aggregate)
58 {
59 if (!GetMuSig2KeyAggCache(pubkeys, keyagg_cache)) {
60 return std::nullopt;
61 }
62 std::optional<CPubKey> agg_key = GetCPubKeyFromMuSig2KeyAggCache(keyagg_cache);
63 if (!agg_key.has_value()) return std::nullopt;
64 if (expected_aggregate.has_value() && expected_aggregate != agg_key) return std::nullopt;
65 return agg_key;
66 }
67
68 std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys)
69 {
70 secp256k1_musig_keyagg_cache keyagg_cache;
71 return MuSig2AggregatePubkeys(pubkeys, keyagg_cache, std::nullopt);
72 }
73
74 CExtPubKey CreateMuSig2SyntheticXpub(const CPubKey& pubkey)
75 {
76 CExtPubKey extpub;
77 extpub.nDepth = 0;
78 std::memset(extpub.vchFingerprint, 0, 4);
79 extpub.nChild = 0;
80 extpub.chaincode = MUSIG_CHAINCODE;
81 extpub.pubkey = pubkey;
82 return extpub;
83 }
84
85 class MuSig2SecNonceImpl
86 {
87 private:
88 //! The actual secnonce itself
89 secure_unique_ptr<secp256k1_musig_secnonce> m_nonce;
90
91 public:
92 MuSig2SecNonceImpl() : m_nonce{make_secure_unique<secp256k1_musig_secnonce>()} {}
93
94 // Delete copy constructors
95 MuSig2SecNonceImpl(const MuSig2SecNonceImpl&) = delete;
96 MuSig2SecNonceImpl& operator=(const MuSig2SecNonceImpl&) = delete;
97
98 secp256k1_musig_secnonce* Get() const { return m_nonce.get(); }
99 void Invalidate() { m_nonce.reset(); }
100 bool IsValid() { return m_nonce != nullptr; }
101 };
102
103 MuSig2SecNonce::MuSig2SecNonce() : m_impl{std::make_unique<MuSig2SecNonceImpl>()} {}
104
105 MuSig2SecNonce::MuSig2SecNonce(MuSig2SecNonce&&) noexcept = default;
106 MuSig2SecNonce& MuSig2SecNonce::operator=(MuSig2SecNonce&&) noexcept = default;
107
108 MuSig2SecNonce::~MuSig2SecNonce() = default;
109
110 secp256k1_musig_secnonce* MuSig2SecNonce::Get() const
111 {
112 return m_impl->Get();
113 }
114
115 void MuSig2SecNonce::Invalidate()
116 {
117 return m_impl->Invalidate();
118 }
119
120 bool MuSig2SecNonce::IsValid()
121 {
122 return m_impl->IsValid();
123 }
124
125 uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash, const std::vector<uint8_t>& pubnonce)
126 {
127 HashWriter hasher;
128 hasher << script_pubkey << part_pubkey << sighash << pubnonce;
129 return hasher.GetSHA256();
130 }
131
132 std::vector<uint8_t> CreateMuSig2Nonce(MuSig2SecNonce& secnonce, const uint256& sighash, const CKey& our_seckey, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys)
133 {
134 // Get the keyagg cache and aggregate pubkey
135 secp256k1_musig_keyagg_cache keyagg_cache;
136 if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return {};
137
138 // Parse participant pubkey
139 CPubKey our_pubkey = our_seckey.GetPubKey();
140 secp256k1_pubkey pubkey;
141 if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, our_pubkey.data(), our_pubkey.size())) {
142 return {};
143 }
144
145 // Generate randomness for nonce
146 uint256 rand;
147 GetStrongRandBytes(rand);
148
149 // Generate nonce
150 secp256k1_musig_pubnonce pubnonce;
151 if (!secp256k1_musig_nonce_gen(GetSecp256k1SignContext(), secnonce.Get(), &pubnonce, rand.data(), UCharCast(our_seckey.begin()), &pubkey, sighash.data(), &keyagg_cache, nullptr)) {
152 return {};
153 }
154
155 // Serialize pubnonce
156 std::vector<uint8_t> out;
157 out.resize(MUSIG2_PUBNONCE_SIZE);
158 if (!secp256k1_musig_pubnonce_serialize(secp256k1_context_static, out.data(), &pubnonce)) {
159 return {};
160 }
161
162 return out;
163 }
164
165 std::optional<uint256> CreateMuSig2PartialSig(const uint256& sighash, const CKey& our_seckey, const CPubKey& aggregate_pubkey, const std::vector<CPubKey>& pubkeys, const std::map<CPubKey, std::vector<uint8_t>>& pubnonces, MuSig2SecNonce& secnonce, const std::vector<std::pair<uint256, bool>>& tweaks)
166 {
167 secp256k1_keypair keypair;
168 if (!secp256k1_keypair_create(GetSecp256k1SignContext(), &keypair, UCharCast(our_seckey.begin()))) return std::nullopt;
169
170 // Get the keyagg cache and aggregate pubkey
171 secp256k1_musig_keyagg_cache keyagg_cache;
172 if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
173
174 // Check that there are enough pubnonces
175 if (pubnonces.size() != pubkeys.size()) return std::nullopt;
176
177 // Parse the pubnonces
178 std::vector<std::pair<secp256k1_pubkey, secp256k1_musig_pubnonce>> signers_data;
179 std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
180 std::optional<size_t> our_pubkey_idx;
181 CPubKey our_pubkey = our_seckey.GetPubKey();
182 for (const CPubKey& part_pk : pubkeys) {
183 const auto& pn_it = pubnonces.find(part_pk);
184 if (pn_it == pubnonces.end()) return std::nullopt;
185 const std::vector<uint8_t> pubnonce = pn_it->second;
186 if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
187 if (part_pk == our_pubkey) {
188 our_pubkey_idx = signers_data.size();
189 }
190
191 auto& [secp_pk, secp_pn] = signers_data.emplace_back();
192
193 if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
194 return std::nullopt;
195 }
196
197 if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
198 return std::nullopt;
199 }
200 }
201 if (our_pubkey_idx == std::nullopt) {
202 return std::nullopt;
203 }
204 pubnonce_ptrs.reserve(signers_data.size());
205 for (auto& [_, pn] : signers_data) {
206 pubnonce_ptrs.push_back(&pn);
207 }
208
209 // Aggregate nonces
210 secp256k1_musig_aggnonce aggnonce;
211 if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
212 return std::nullopt;
213 }
214
215 // Apply tweaks
216 for (const auto& [tweak, xonly] : tweaks) {
217 if (xonly) {
218 if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
219 return std::nullopt;
220 }
221 } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
222 return std::nullopt;
223 }
224 }
225
226 // Create musig_session
227 secp256k1_musig_session session;
228 if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
229 return std::nullopt;
230 }
231
232 // Create partial signature
233 secp256k1_musig_partial_sig psig;
234 if (!secp256k1_musig_partial_sign(secp256k1_context_static, &psig, secnonce.Get(), &keypair, &keyagg_cache, &session)) {
235 return std::nullopt;
236 }
237 // The secnonce must be deleted after signing to prevent nonce reuse.
238 secnonce.Invalidate();
239
240 // Verify partial signature
241 if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &psig, &(signers_data.at(*our_pubkey_idx).second), &(signers_data.at(*our_pubkey_idx).first), &keyagg_cache, &session)) {
242 return std::nullopt;
243 }
244
245 // Serialize
246 uint256 sig;
247 if (!secp256k1_musig_partial_sig_serialize(secp256k1_context_static, sig.data(), &psig)) {
248 return std::nullopt;
249 }
250
251 return sig;
252 }
253
254 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)
255 {
256 if (!part_pubkeys.size()) return std::nullopt;
257
258 // Get the keyagg cache and aggregate pubkey
259 secp256k1_musig_keyagg_cache keyagg_cache;
260 if (!MuSig2AggregatePubkeys(part_pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
261
262 // Check if enough pubnonces and partial sigs
263 if (pubnonces.size() != part_pubkeys.size()) return std::nullopt;
264 if (partial_sigs.size() != part_pubkeys.size()) return std::nullopt;
265
266 // Parse the pubnonces and partial sigs
267 std::vector<std::tuple<secp256k1_pubkey, secp256k1_musig_pubnonce, secp256k1_musig_partial_sig>> signers_data;
268 std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
269 std::vector<const secp256k1_musig_partial_sig*> partial_sig_ptrs;
270 for (const CPubKey& part_pk : part_pubkeys) {
271 const auto& pn_it = pubnonces.find(part_pk);
272 if (pn_it == pubnonces.end()) return std::nullopt;
273 const std::vector<uint8_t> pubnonce = pn_it->second;
274 if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
275 const auto& it = partial_sigs.find(part_pk);
276 if (it == partial_sigs.end()) return std::nullopt;
277 const uint256& partial_sig = it->second;
278
279 auto& [secp_pk, secp_pn, secp_ps] = signers_data.emplace_back();
280
281 if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
282 return std::nullopt;
283 }
284
285 if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
286 return std::nullopt;
287 }
288
289 if (!secp256k1_musig_partial_sig_parse(secp256k1_context_static, &secp_ps, partial_sig.data())) {
290 return std::nullopt;
291 }
292 }
293 pubnonce_ptrs.reserve(signers_data.size());
294 partial_sig_ptrs.reserve(signers_data.size());
295 for (auto& [_, pn, ps] : signers_data) {
296 pubnonce_ptrs.push_back(&pn);
297 partial_sig_ptrs.push_back(&ps);
298 }
299
300 // Aggregate nonces
301 secp256k1_musig_aggnonce aggnonce;
302 if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
303 return std::nullopt;
304 }
305
306 // Apply tweaks
307 for (const auto& [tweak, xonly] : tweaks) {
308 if (xonly) {
309 if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
310 return std::nullopt;
311 }
312 } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
313 return std::nullopt;
314 }
315 }
316
317 // Create musig_session
318 secp256k1_musig_session session;
319 if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
320 return std::nullopt;
321 }
322
323 // Verify partial sigs
324 for (const auto& [pk, pb, ps] : signers_data) {
325 if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &ps, &pb, &pk, &keyagg_cache, &session)) {
326 return std::nullopt;
327 }
328 }
329
330 // Aggregate partial sigs
331 std::vector<uint8_t> sig;
332 sig.resize(64);
333 if (!secp256k1_musig_partial_sig_agg(secp256k1_context_static, sig.data(), &session, partial_sig_ptrs.data(), partial_sig_ptrs.size())) {
334 return std::nullopt;
335 }
336
337 return sig;
338 }
339