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