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