Coverage Report

Created: 2026-05-30 09:47

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
698
{
21
698
    if (pubkeys.empty()) {
22
1
        return false;
23
1
    }
24
25
    // Parse the pubkeys
26
697
    std::vector<secp256k1_pubkey> secp_pubkeys;
27
697
    std::vector<const secp256k1_pubkey*> pubkey_ptrs;
28
1.96k
    for (const CPubKey& pubkey : pubkeys) {
29
1.96k
        if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pubkeys.emplace_back(), pubkey.data(), pubkey.size())) {
30
1
            return false;
31
1
        }
32
1.96k
    }
33
696
    pubkey_ptrs.reserve(secp_pubkeys.size());
34
1.96k
    for (const secp256k1_pubkey& p : secp_pubkeys) {
35
1.96k
        pubkey_ptrs.push_back(&p);
36
1.96k
    }
37
38
    // Aggregate the pubkey
39
696
    if (!secp256k1_musig_pubkey_agg(secp256k1_context_static, nullptr, &keyagg_cache, pubkey_ptrs.data(), pubkey_ptrs.size())) {
40
0
        return false;
41
0
    }
42
696
    return true;
43
696
}
44
45
static std::optional<CPubKey> GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& keyagg_cache)
46
696
{
47
    // Get the plain aggregated pubkey
48
696
    secp256k1_pubkey agg_pubkey;
49
696
    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
696
    unsigned char ser_agg_pubkey[CPubKey::COMPRESSED_SIZE];
55
696
    size_t ser_agg_pubkey_len = CPubKey::COMPRESSED_SIZE;
56
696
    secp256k1_ec_pubkey_serialize(secp256k1_context_static, ser_agg_pubkey, &ser_agg_pubkey_len, &agg_pubkey, SECP256K1_EC_COMPRESSED);
57
696
    return CPubKey(ser_agg_pubkey, ser_agg_pubkey + ser_agg_pubkey_len);
58
696
}
59
60
std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache, const std::optional<CPubKey>& expected_aggregate)
61
698
{
62
698
    if (!GetMuSig2KeyAggCache(pubkeys, keyagg_cache)) {
63
2
        return std::nullopt;
64
2
    }
65
696
    std::optional<CPubKey> agg_key = GetCPubKeyFromMuSig2KeyAggCache(keyagg_cache);
66
696
    if (!agg_key.has_value()) return std::nullopt;
67
696
    if (expected_aggregate.has_value() && expected_aggregate != agg_key) return std::nullopt;
68
696
    return agg_key;
69
696
}
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
1.56k
{
79
1.56k
    CExtPubKey extpub;
80
1.56k
    extpub.nDepth = 0;
81
1.56k
    std::memset(extpub.vchFingerprint, 0, 4);
82
1.56k
    extpub.nChild = 0;
83
1.56k
    extpub.chaincode = MUSIG_CHAINCODE;
84
1.56k
    extpub.pubkey = pubkey;
85
1.56k
    return extpub;
86
1.56k
}
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
79
    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
150
    secp256k1_musig_secnonce* Get() const { return m_nonce.get(); }
102
71
    void Invalidate() { m_nonce.reset(); }
103
142
    bool IsValid() { return m_nonce != nullptr; }
104
};
105
106
79
MuSig2SecNonce::MuSig2SecNonce() : m_impl{std::make_unique<MuSig2SecNonceImpl>()} {}
107
108
79
MuSig2SecNonce::MuSig2SecNonce(MuSig2SecNonce&&) noexcept = default;
109
0
MuSig2SecNonce& MuSig2SecNonce::operator=(MuSig2SecNonce&&) noexcept = default;
110
111
158
MuSig2SecNonce::~MuSig2SecNonce() = default;
112
113
secp256k1_musig_secnonce* MuSig2SecNonce::Get() const
114
150
{
115
150
    return m_impl->Get();
116
150
}
117
118
void MuSig2SecNonce::Invalidate()
119
71
{
120
71
    return m_impl->Invalidate();
121
71
}
122
123
bool MuSig2SecNonce::IsValid()
124
142
{
125
142
    return m_impl->IsValid();
126
142
}
127
128
uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash)
129
205
{
130
205
    HashWriter hasher;
131
205
    hasher << script_pubkey << part_pubkey << sighash;
132
205
    return hasher.GetSHA256();
133
205
}
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
79
{
137
    // Get the keyagg cache and aggregate pubkey
138
79
    secp256k1_musig_keyagg_cache keyagg_cache;
139
79
    if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return {};
140
141
    // Parse participant pubkey
142
79
    CPubKey our_pubkey = our_seckey.GetPubKey();
143
79
    secp256k1_pubkey pubkey;
144
79
    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
79
    uint256 rand;
150
79
    GetStrongRandBytes(rand);
151
152
    // Generate nonce
153
79
    secp256k1_musig_pubnonce pubnonce;
154
79
    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
79
    std::vector<uint8_t> out;
160
79
    out.resize(MUSIG2_PUBNONCE_SIZE);
161
79
    if (!secp256k1_musig_pubnonce_serialize(secp256k1_context_static, out.data(), &pubnonce)) {
162
0
        return {};
163
0
    }
164
165
79
    return out;
166
79
}
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
71
{
170
71
    secp256k1_keypair keypair;
171
71
    if (!secp256k1_keypair_create(GetSecp256k1SignContext(), &keypair, UCharCast(our_seckey.begin()))) return std::nullopt;
172
173
    // Get the keyagg cache and aggregate pubkey
174
71
    secp256k1_musig_keyagg_cache keyagg_cache;
175
71
    if (!MuSig2AggregatePubkeys(pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
176
177
    // Check that there are enough pubnonces
178
71
    if (pubnonces.size() != pubkeys.size()) return std::nullopt;
179
180
    // Parse the pubnonces
181
71
    std::vector<std::pair<secp256k1_pubkey, secp256k1_musig_pubnonce>> signers_data;
182
71
    std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
183
71
    std::optional<size_t> our_pubkey_idx;
184
71
    CPubKey our_pubkey = our_seckey.GetPubKey();
185
201
    for (const CPubKey& part_pk : pubkeys) {
186
201
        const auto& pn_it = pubnonces.find(part_pk);
187
201
        if (pn_it == pubnonces.end()) return std::nullopt;
188
201
        const std::vector<uint8_t> pubnonce = pn_it->second;
189
201
        if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
190
201
        if (part_pk == our_pubkey) {
191
71
            our_pubkey_idx = signers_data.size();
192
71
        }
193
194
201
        auto& [secp_pk, secp_pn] = signers_data.emplace_back();
195
196
201
        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
201
        if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
201
0
            return std::nullopt;
202
0
        }
203
201
    }
204
71
    if (our_pubkey_idx == std::nullopt) {
205
0
        return std::nullopt;
206
0
    }
207
71
    pubnonce_ptrs.reserve(signers_data.size());
208
201
    for (auto& [_, pn] : signers_data) {
209
201
        pubnonce_ptrs.push_back(&pn);
210
201
    }
211
212
    // Aggregate nonces
213
71
    secp256k1_musig_aggnonce aggnonce;
214
71
    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
108
    for (const auto& [tweak, xonly] : tweaks) {
220
108
        if (xonly) {
221
18
            if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
222
0
                return std::nullopt;
223
0
            }
224
90
        } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
225
0
            return std::nullopt;
226
0
        }
227
108
    }
228
229
    // Create musig_session
230
71
    secp256k1_musig_session session;
231
71
    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
71
    secp256k1_musig_partial_sig psig;
237
71
    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
71
    secnonce.Invalidate();
242
243
    // Verify partial signature
244
71
    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
71
    uint256 sig;
250
71
    if (!secp256k1_musig_partial_sig_serialize(secp256k1_context_static, sig.data(), &psig)) {
251
0
        return std::nullopt;
252
0
    }
253
254
71
    return sig;
255
71
}
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
46
{
259
46
    if (!part_pubkeys.size()) return std::nullopt;
260
261
    // Get the keyagg cache and aggregate pubkey
262
46
    secp256k1_musig_keyagg_cache keyagg_cache;
263
46
    if (!MuSig2AggregatePubkeys(part_pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
264
265
    // Check if enough pubnonces and partial sigs
266
46
    if (pubnonces.size() != part_pubkeys.size()) return std::nullopt;
267
46
    if (partial_sigs.size() != part_pubkeys.size()) return std::nullopt;
268
269
    // Parse the pubnonces and partial sigs
270
46
    std::vector<std::tuple<secp256k1_pubkey, secp256k1_musig_pubnonce, secp256k1_musig_partial_sig>> signers_data;
271
46
    std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
272
46
    std::vector<const secp256k1_musig_partial_sig*> partial_sig_ptrs;
273
130
    for (const CPubKey& part_pk : part_pubkeys) {
274
130
        const auto& pn_it = pubnonces.find(part_pk);
275
130
        if (pn_it == pubnonces.end()) return std::nullopt;
276
130
        const std::vector<uint8_t> pubnonce = pn_it->second;
277
130
        if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
278
130
        const auto& it = partial_sigs.find(part_pk);
279
130
        if (it == partial_sigs.end()) return std::nullopt;
280
130
        const uint256& partial_sig = it->second;
281
282
130
        auto& [secp_pk, secp_pn, secp_ps] = signers_data.emplace_back();
283
284
130
        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
130
        if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
289
0
            return std::nullopt;
290
0
        }
291
292
130
        if (!secp256k1_musig_partial_sig_parse(secp256k1_context_static, &secp_ps, partial_sig.data())) {
293
0
            return std::nullopt;
294
0
        }
295
130
    }
296
46
    pubnonce_ptrs.reserve(signers_data.size());
297
46
    partial_sig_ptrs.reserve(signers_data.size());
298
130
    for (auto& [_, pn, ps] : signers_data) {
299
130
        pubnonce_ptrs.push_back(&pn);
300
130
        partial_sig_ptrs.push_back(&ps);
301
130
    }
302
303
    // Aggregate nonces
304
46
    secp256k1_musig_aggnonce aggnonce;
305
46
    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
72
    for (const auto& [tweak, xonly] : tweaks) {
311
72
        if (xonly) {
312
12
            if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
313
0
                return std::nullopt;
314
0
            }
315
60
        } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
316
0
            return std::nullopt;
317
0
        }
318
72
    }
319
320
    // Create musig_session
321
46
    secp256k1_musig_session session;
322
46
    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
130
    for (const auto& [pk, pb, ps] : signers_data) {
328
130
        if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &ps, &pb, &pk, &keyagg_cache, &session)) {
329
0
            return std::nullopt;
330
0
        }
331
130
    }
332
333
    // Aggregate partial sigs
334
46
    std::vector<uint8_t> sig;
335
46
    sig.resize(64);
336
46
    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
46
    return sig;
341
46
}