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 <support/allocators/secure.h>
7 : :
8 : : #include <secp256k1_musig.h>
9 : :
10 : : //! MuSig2 chaincode as defined by BIP 328
11 : : using namespace util::hex_literals;
12 : : constexpr uint256 MUSIG_CHAINCODE{
13 : : // Use immediate lambda to work around GCC-14 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117966
14 : : []() consteval { return uint256{"868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965"_hex_u8}; }(),
15 : : };
16 : :
17 : 613 : static bool GetMuSig2KeyAggCache(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache)
18 : : {
19 : : // Parse the pubkeys
20 : 613 : std::vector<secp256k1_pubkey> secp_pubkeys;
21 : 613 : std::vector<const secp256k1_pubkey*> pubkey_ptrs;
22 [ + + ]: 2348 : for (const CPubKey& pubkey : pubkeys) {
23 [ + - + - : 1735 : if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pubkeys.emplace_back(), pubkey.data(), pubkey.size())) {
+ - ]
24 : : return false;
25 : : }
26 : : }
27 [ - + + - ]: 613 : pubkey_ptrs.reserve(secp_pubkeys.size());
28 [ + + ]: 2348 : for (const secp256k1_pubkey& p : secp_pubkeys) {
29 [ + - ]: 1735 : pubkey_ptrs.push_back(&p);
30 : : }
31 : :
32 : : // Aggregate the pubkey
33 [ - + + - : 613 : if (!secp256k1_musig_pubkey_agg(secp256k1_context_static, nullptr, &keyagg_cache, pubkey_ptrs.data(), pubkey_ptrs.size())) {
- + ]
34 : 0 : return false;
35 : : }
36 : : return true;
37 : 613 : }
38 : :
39 : 613 : static std::optional<CPubKey> GetCPubKeyFromMuSig2KeyAggCache(secp256k1_musig_keyagg_cache& keyagg_cache)
40 : : {
41 : : // Get the plain aggregated pubkey
42 : 613 : secp256k1_pubkey agg_pubkey;
43 [ - + ]: 613 : if (!secp256k1_musig_pubkey_get(secp256k1_context_static, &agg_pubkey, &keyagg_cache)) {
44 : 0 : return std::nullopt;
45 : : }
46 : :
47 : : // Turn into CPubKey
48 : 613 : unsigned char ser_agg_pubkey[CPubKey::COMPRESSED_SIZE];
49 : 613 : size_t ser_agg_pubkey_len = CPubKey::COMPRESSED_SIZE;
50 : 613 : secp256k1_ec_pubkey_serialize(secp256k1_context_static, ser_agg_pubkey, &ser_agg_pubkey_len, &agg_pubkey, SECP256K1_EC_COMPRESSED);
51 : 613 : return CPubKey(ser_agg_pubkey, ser_agg_pubkey + ser_agg_pubkey_len);
52 : : }
53 : :
54 : 613 : std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys, secp256k1_musig_keyagg_cache& keyagg_cache, const std::optional<CPubKey>& expected_aggregate)
55 : : {
56 [ - + ]: 613 : if (!GetMuSig2KeyAggCache(pubkeys, keyagg_cache)) {
57 : 0 : return std::nullopt;
58 : : }
59 : 613 : std::optional<CPubKey> agg_key = GetCPubKeyFromMuSig2KeyAggCache(keyagg_cache);
60 [ - + ]: 613 : if (!agg_key.has_value()) return std::nullopt;
61 [ + + - + ]: 613 : if (expected_aggregate.has_value() && expected_aggregate != agg_key) return std::nullopt;
62 : 613 : return agg_key;
63 : : }
64 : :
65 : 461 : std::optional<CPubKey> MuSig2AggregatePubkeys(const std::vector<CPubKey>& pubkeys)
66 : : {
67 : 461 : secp256k1_musig_keyagg_cache keyagg_cache;
68 : 461 : return MuSig2AggregatePubkeys(pubkeys, keyagg_cache, std::nullopt);
69 : : }
70 : :
71 : 1068 : CExtPubKey CreateMuSig2SyntheticXpub(const CPubKey& pubkey)
72 : : {
73 : 1068 : CExtPubKey extpub;
74 : 1068 : extpub.nDepth = 0;
75 : 1068 : std::memset(extpub.vchFingerprint, 0, 4);
76 : 1068 : extpub.nChild = 0;
77 : 1068 : extpub.chaincode = MUSIG_CHAINCODE;
78 : 1068 : extpub.pubkey = pubkey;
79 : 1068 : return extpub;
80 : : }
81 : :
82 : 63 : class MuSig2SecNonceImpl
83 : : {
84 : : private:
85 : : //! The actual secnonce itself
86 : : secure_unique_ptr<secp256k1_musig_secnonce> m_nonce;
87 : :
88 : : public:
89 [ + - ]: 63 : MuSig2SecNonceImpl() : m_nonce{make_secure_unique<secp256k1_musig_secnonce>()} {}
90 : :
91 : : // Delete copy constructors
92 : : MuSig2SecNonceImpl(const MuSig2SecNonceImpl&) = delete;
93 : : MuSig2SecNonceImpl& operator=(const MuSig2SecNonceImpl&) = delete;
94 : :
95 : 118 : secp256k1_musig_secnonce* Get() const { return m_nonce.get(); }
96 : 55 : void Invalidate() { m_nonce.reset(); }
97 : 110 : bool IsValid() { return m_nonce != nullptr; }
98 : : };
99 : :
100 : 63 : MuSig2SecNonce::MuSig2SecNonce() : m_impl{std::make_unique<MuSig2SecNonceImpl>()} {}
101 : :
102 : 63 : MuSig2SecNonce::MuSig2SecNonce(MuSig2SecNonce&&) noexcept = default;
103 : 0 : MuSig2SecNonce& MuSig2SecNonce::operator=(MuSig2SecNonce&&) noexcept = default;
104 : :
105 : 126 : MuSig2SecNonce::~MuSig2SecNonce() = default;
106 : :
107 : 118 : secp256k1_musig_secnonce* MuSig2SecNonce::Get() const
108 : : {
109 : 118 : return m_impl->Get();
110 : : }
111 : :
112 : 55 : void MuSig2SecNonce::Invalidate()
113 : : {
114 : 55 : return m_impl->Invalidate();
115 : : }
116 : :
117 : 110 : bool MuSig2SecNonce::IsValid()
118 : : {
119 : 110 : return m_impl->IsValid();
120 : : }
121 : :
122 : 161 : uint256 MuSig2SessionID(const CPubKey& script_pubkey, const CPubKey& part_pubkey, const uint256& sighash)
123 : : {
124 : 161 : HashWriter hasher;
125 : 161 : hasher << script_pubkey << part_pubkey << sighash;
126 : 161 : return hasher.GetSHA256();
127 : : }
128 : :
129 : 34 : 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)
130 : : {
131 [ - + - + ]: 34 : if (!part_pubkeys.size()) return std::nullopt;
132 : :
133 : : // Get the keyagg cache and aggregate pubkey
134 : 34 : secp256k1_musig_keyagg_cache keyagg_cache;
135 [ - + ]: 34 : if (!MuSig2AggregatePubkeys(part_pubkeys, keyagg_cache, aggregate_pubkey)) return std::nullopt;
136 : :
137 : : // Check if enough pubnonces and partial sigs
138 [ - + - + ]: 34 : if (pubnonces.size() != part_pubkeys.size()) return std::nullopt;
139 [ - + ]: 34 : if (partial_sigs.size() != part_pubkeys.size()) return std::nullopt;
140 : :
141 : : // Parse the pubnonces and partial sigs
142 : 34 : std::vector<std::tuple<secp256k1_pubkey, secp256k1_musig_pubnonce, secp256k1_musig_partial_sig>> signers_data;
143 : 34 : std::vector<const secp256k1_musig_pubnonce*> pubnonce_ptrs;
144 : 34 : std::vector<const secp256k1_musig_partial_sig*> partial_sig_ptrs;
145 [ + + ]: 132 : for (const CPubKey& part_pk : part_pubkeys) {
146 : 98 : const auto& pn_it = pubnonces.find(part_pk);
147 [ - + ]: 98 : if (pn_it == pubnonces.end()) return std::nullopt;
148 [ + - ]: 98 : const std::vector<uint8_t> pubnonce = pn_it->second;
149 [ - + - + ]: 98 : if (pubnonce.size() != MUSIG2_PUBNONCE_SIZE) return std::nullopt;
150 : 98 : const auto& it = partial_sigs.find(part_pk);
151 [ - + ]: 98 : if (it == partial_sigs.end()) return std::nullopt;
152 [ + - ]: 98 : const uint256& partial_sig = it->second;
153 : :
154 [ + - + - ]: 98 : auto& [secp_pk, secp_pn, secp_ps] = signers_data.emplace_back();
155 : :
156 [ + - - + ]: 98 : if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &secp_pk, part_pk.data(), part_pk.size())) {
157 : 0 : return std::nullopt;
158 : : }
159 : :
160 [ + - - + ]: 98 : if (!secp256k1_musig_pubnonce_parse(secp256k1_context_static, &secp_pn, pubnonce.data())) {
161 : 0 : return std::nullopt;
162 : : }
163 : :
164 [ + - - + ]: 98 : if (!secp256k1_musig_partial_sig_parse(secp256k1_context_static, &secp_ps, partial_sig.data())) {
165 : 0 : return std::nullopt;
166 : : }
167 : 98 : }
168 [ - + + - ]: 34 : pubnonce_ptrs.reserve(signers_data.size());
169 [ - + + - ]: 34 : partial_sig_ptrs.reserve(signers_data.size());
170 [ + - + + ]: 132 : for (auto& [_, pn, ps] : signers_data) {
171 [ + - ]: 98 : pubnonce_ptrs.push_back(&pn);
172 [ + - ]: 98 : partial_sig_ptrs.push_back(&ps);
173 : : }
174 : :
175 : : // Aggregate nonces
176 : 34 : secp256k1_musig_aggnonce aggnonce;
177 [ - + + - : 34 : if (!secp256k1_musig_nonce_agg(secp256k1_context_static, &aggnonce, pubnonce_ptrs.data(), pubnonce_ptrs.size())) {
- + ]
178 : 0 : return std::nullopt;
179 : : }
180 : :
181 : : // Apply tweaks
182 [ + + + + ]: 82 : for (const auto& [tweak, xonly] : tweaks) {
183 [ + + ]: 48 : if (xonly) {
184 [ + - - + ]: 12 : if (!secp256k1_musig_pubkey_xonly_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
185 : 0 : return std::nullopt;
186 : : }
187 [ + - - + ]: 36 : } else if (!secp256k1_musig_pubkey_ec_tweak_add(secp256k1_context_static, nullptr, &keyagg_cache, tweak.data())) {
188 : 0 : return std::nullopt;
189 : : }
190 : : }
191 : :
192 : : // Create musig_session
193 : 34 : secp256k1_musig_session session;
194 [ + - - + ]: 34 : if (!secp256k1_musig_nonce_process(secp256k1_context_static, &session, &aggnonce, sighash.data(), &keyagg_cache)) {
195 : 0 : return std::nullopt;
196 : : }
197 : :
198 : : // Verify partial sigs
199 [ + - + + ]: 132 : for (const auto& [pk, pb, ps] : signers_data) {
200 [ + - - + ]: 98 : if (!secp256k1_musig_partial_sig_verify(secp256k1_context_static, &ps, &pb, &pk, &keyagg_cache, &session)) {
201 : 0 : return std::nullopt;
202 : : }
203 : : }
204 : :
205 : : // Aggregate partial sigs
206 : 34 : std::vector<uint8_t> sig;
207 [ + - ]: 34 : sig.resize(64);
208 [ - + + - : 34 : if (!secp256k1_musig_partial_sig_agg(secp256k1_context_static, sig.data(), &session, partial_sig_ptrs.data(), partial_sig_ptrs.size())) {
- + ]
209 : 0 : return std::nullopt;
210 : : }
211 : :
212 : 34 : return sig;
213 : 68 : }
|