Coverage Report

Created: 2026-06-03 10:44

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