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