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