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