bip328_tests.cpp raw

   1  // Copyright (c) 2026-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 <boost/test/unit_test.hpp>
   6  
   7  #include <key.h>
   8  #include <key_io.h>
   9  #include <musig.h>
  10  #include <test/util/setup_common.h>
  11  #include <util/strencodings.h>
  12  #include <crypto/hex_base.h>
  13  
  14  #include <string>
  15  #include <vector>
  16  
  17  namespace {
  18  
  19  struct BIP328TestVector {
  20      std::vector<std::string> pubkeys;
  21      std::string expected_aggregate_pubkey;
  22      std::string expected_aggregate_xpub;
  23  };
  24  
  25  BOOST_FIXTURE_TEST_SUITE(bip328_tests, BasicTestingSetup)
  26  
  27  BOOST_AUTO_TEST_CASE(valid_keys)
  28  {
  29      // BIP 328 test vectors
  30      std::vector<BIP328TestVector> test_vectors = {
  31          // Test vector 0
  32          {
  33              .pubkeys = {
  34                  "03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
  35                  "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"
  36              },
  37              .expected_aggregate_pubkey = "0354240c76b8f2999143301a99c7f721ee57eee0bce401df3afeaa9ae218c70f23",
  38              .expected_aggregate_xpub = "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwXEKGEouzXE6QLLRxjatMcLLzJ5LV5Nib1BN7vJg6yp45yHHRbm"
  39          },
  40          // Test vector 1
  41          {
  42              .pubkeys = {
  43                  "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
  44                  "03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
  45                  "023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66"
  46              },
  47              .expected_aggregate_pubkey = "0290539eede565f5d054f32cc0c220126889ed1e5d193baf15aef344fe59d4610c",
  48              .expected_aggregate_xpub = "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwVk5TFJk8Tw5WAdV3DhrGfbFA216sE9BsQQiSFTdudkETnKdg8k"
  49          },
  50          // Test vector 2
  51          {
  52              .pubkeys = {
  53                  "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
  54                  "023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
  55                  "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
  56                  "03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
  57              },
  58              .expected_aggregate_pubkey = "022479f134cdb266141dab1a023cbba30a870f8995b95a91fc8464e56a7d41f8ea",
  59              .expected_aggregate_xpub = "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwUvaZYpysLX4wN59tjwU5pBuDjNrPEJbfxjLwn7ruzbXTcUTHkZ"
  60          }
  61      };
  62  
  63      // Iterate through all test vectors
  64      for (int i = 0; i < (int) test_vectors.size(); ++i) {
  65          const auto& test = test_vectors[i];
  66  
  67          // Parse public keys
  68          std::vector<CPubKey> pubkeys;
  69          for (const auto& hex_pubkey : test.pubkeys) {
  70              std::vector<unsigned char> data = ParseHex(hex_pubkey);
  71              CPubKey pubkey(data.begin(), data.end());
  72              pubkeys.push_back(pubkey);
  73          }
  74  
  75          // Aggregate public keys
  76          std::optional<CPubKey> m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys);
  77          BOOST_CHECK_MESSAGE(m_aggregate_pubkey.has_value(), "Test vector " << i << ": Failed to aggregate pubkeys");
  78  
  79          // Check aggregate pubkey
  80          std::string combined_keys = HexStr(m_aggregate_pubkey.value());
  81          BOOST_CHECK_MESSAGE(combined_keys == test.expected_aggregate_pubkey, "Test vector " << i << ": Aggregate pubkey mismatch");
  82  
  83          // Create extended public key
  84          CExtPubKey extpub = CreateMuSig2SyntheticXpub(m_aggregate_pubkey.value());
  85  
  86          // Check xpub
  87          std::string xpub = EncodeExtPubKey(extpub);
  88          BOOST_CHECK_MESSAGE(xpub == test.expected_aggregate_xpub, "Test vector " << i << ": Synthetic xpub mismatch");
  89      }
  90  }
  91  
  92  BOOST_AUTO_TEST_CASE(empty_pubkey_list)
  93  {
  94      const std::optional<CPubKey> aggregate_pubkey{MuSig2AggregatePubkeys({})};
  95      BOOST_CHECK(!aggregate_pubkey.has_value());
  96  }
  97  
  98  BOOST_AUTO_TEST_CASE(invalid_key)
  99  {
 100      std::vector<std::string> test_vectors = {
 101          "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
 102          "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
 103      };
 104  
 105      // Parse public keys
 106      std::vector<CPubKey> pubkeys;
 107      for (const auto& hex_pubkey : test_vectors) {
 108          std::vector<unsigned char> data = ParseHex(hex_pubkey);
 109          CPubKey pubkey(data.begin(), data.end());
 110          pubkeys.push_back(pubkey);
 111      }
 112  
 113      // Aggregate public keys
 114      std::optional<CPubKey> m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys);
 115      BOOST_CHECK_MESSAGE(!m_aggregate_pubkey.has_value(), "Aggregate key with an invalid public key is null");
 116  }
 117  
 118  BOOST_AUTO_TEST_SUITE_END()
 119  
 120  }
 121