musig.cpp raw

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