bip328_tests.cpp
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(invalid_key) 93 { 94 std::vector<std::string> test_vectors = { 95 "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 96 "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659" 97 }; 98 99 // Parse public keys 100 std::vector<CPubKey> pubkeys; 101 for (const auto& hex_pubkey : test_vectors) { 102 std::vector<unsigned char> data = ParseHex(hex_pubkey); 103 CPubKey pubkey(data.begin(), data.end()); 104 pubkeys.push_back(pubkey); 105 } 106 107 // Aggregate public keys 108 std::optional<CPubKey> m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys); 109 BOOST_CHECK_MESSAGE(!m_aggregate_pubkey.has_value(), "Aggregate key with an invalid public key is null"); 110 } 111 112 BOOST_AUTO_TEST_SUITE_END() 113 114 }