Branch data Line data Source code
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 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(valid_keys)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
28 : : {
29 : : // BIP 328 test vectors
30 : 1 : 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 [ - + + + : 4 : };
- - ]
62 : :
63 : : // Iterate through all test vectors
64 [ - + + + ]: 4 : for (int i = 0; i < (int) test_vectors.size(); ++i) {
65 : 3 : const auto& test = test_vectors[i];
66 : :
67 : : // Parse public keys
68 : 3 : std::vector<CPubKey> pubkeys;
69 [ + + ]: 12 : for (const auto& hex_pubkey : test.pubkeys) {
70 [ - + + - ]: 9 : std::vector<unsigned char> data = ParseHex(hex_pubkey);
71 : 9 : CPubKey pubkey(data.begin(), data.end());
72 [ + - ]: 9 : pubkeys.push_back(pubkey);
73 : 9 : }
74 : :
75 : : // Aggregate public keys
76 [ + - ]: 3 : std::optional<CPubKey> m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys);
77 [ + - + - : 6 : BOOST_CHECK_MESSAGE(m_aggregate_pubkey.has_value(), "Test vector " << i << ": Failed to aggregate pubkeys");
+ - ]
78 : :
79 : : // Check aggregate pubkey
80 [ + - + - ]: 3 : std::string combined_keys = HexStr(m_aggregate_pubkey.value());
81 [ + - + - : 6 : BOOST_CHECK_MESSAGE(combined_keys == test.expected_aggregate_pubkey, "Test vector " << i << ": Aggregate pubkey mismatch");
+ - ]
82 : :
83 : : // Create extended public key
84 [ + - + - ]: 3 : CExtPubKey extpub = CreateMuSig2SyntheticXpub(m_aggregate_pubkey.value());
85 : :
86 : : // Check xpub
87 [ + - ]: 3 : std::string xpub = EncodeExtPubKey(extpub);
88 [ + - + - ]: 6 : BOOST_CHECK_MESSAGE(xpub == test.expected_aggregate_xpub, "Test vector " << i << ": Synthetic xpub mismatch");
89 : 3 : }
90 [ + - + - : 2 : }
+ - + - +
- + - + -
+ - + - -
- - - - -
- - ]
91 : :
92 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(invalid_key)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
93 : : {
94 : 1 : std::vector<std::string> test_vectors = {
95 : : "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
96 : : "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
97 : 1 : };
98 : :
99 : : // Parse public keys
100 : 1 : std::vector<CPubKey> pubkeys;
101 [ + + ]: 3 : for (const auto& hex_pubkey : test_vectors) {
102 [ - + + - ]: 2 : std::vector<unsigned char> data = ParseHex(hex_pubkey);
103 : 2 : CPubKey pubkey(data.begin(), data.end());
104 [ + - ]: 2 : pubkeys.push_back(pubkey);
105 : 2 : }
106 : :
107 : : // Aggregate public keys
108 [ + - ]: 1 : std::optional<CPubKey> m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys);
109 [ + - + - ]: 2 : BOOST_CHECK_MESSAGE(!m_aggregate_pubkey.has_value(), "Aggregate key with an invalid public key is null");
110 : 1 : }
111 : :
112 : : BOOST_AUTO_TEST_SUITE_END()
113 : :
114 : : }
|