Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
bip32_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-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 <clientversion.h>
8#include <key.h>
9#include <key_io.h>
10#include <streams.h>
11#include <test/util/common.h>
13#include <util/bip32.h>
14#include <util/strencodings.h>
15
16#include <string>
17#include <vector>
18
19namespace {
20
21struct TestDerivation {
22 std::string pub;
23 std::string prv;
24 unsigned int nChild;
25};
26
27struct TestVector {
28 std::string strHexMaster;
29 std::vector<TestDerivation> vDerive;
30
31 explicit TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
32
33 TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {
34 vDerive.emplace_back();
35 TestDerivation &der = vDerive.back();
36 der.pub = pub;
37 der.prv = prv;
38 der.nChild = nChild;
39 return *this;
40 }
41};
42
43TestVector test1 =
44 TestVector("000102030405060708090a0b0c0d0e0f")
45 ("xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
46 "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
48 ("xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
49 "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
50 1)
51 ("xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
52 "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
54 ("xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
55 "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
56 2)
57 ("xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
58 "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
59 1000000000)
60 ("xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
61 "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
62 0);
63
64TestVector test2 =
65 TestVector("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542")
66 ("xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
67 "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
68 0)
69 ("xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
70 "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
71 0xFFFFFFFF)
72 ("xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
73 "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
74 1)
75 ("xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
76 "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
77 0xFFFFFFFE)
78 ("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
79 "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
80 2)
81 ("xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
82 "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
83 0);
84
85TestVector test3 =
86 TestVector("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be")
87 ("xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13",
88 "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6",
90 ("xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y",
91 "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L",
92 0);
93
94TestVector test4 =
95 TestVector("3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678")
96 ("xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa",
97 "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv",
99 ("xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m",
100 "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G",
102 ("xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt",
103 "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1",
104 0);
105
106const std::vector<std::string> TEST5 = {
107 "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm",
108 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH",
109 "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn",
110 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ",
111 "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4",
112 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J",
113 "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv",
114 "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ",
115 "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN",
116 "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8",
117 "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4",
118 "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9",
119 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx",
120 "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G",
121 "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY",
122 "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL"
123};
124
125void RunTest(const TestVector& test)
126{
127 std::vector<std::byte> seed{ParseHex<std::byte>(test.strHexMaster)};
128 CExtKey key;
129 CExtPubKey pubkey;
130 key.SetSeed(seed);
131 pubkey = key.Neuter();
132 for (const TestDerivation &derive : test.vDerive) {
133 // Test serialization round trip
134 DataStream ss{};
135 ss << key;
136 ss << pubkey;
140 ss >> key_deser;
141 ss >> pubkey_deser;
144
145 // Test private key
146 BOOST_CHECK(EncodeExtKey(key) == derive.prv);
147 BOOST_CHECK_EQUAL(DecodeExtKey(derive.prv), key); //ensure a base58 decoded key also matches
148
149 // Test public key
150 BOOST_CHECK(EncodeExtPubKey(pubkey) == derive.pub);
151 BOOST_CHECK_EQUAL(DecodeExtPubKey(derive.pub), pubkey); //ensure a base58 decoded pubkey also matches
152
153 // Derive new keys
155 BOOST_CHECK(key.Derive(keyNew, derive.nChild));
156 CExtPubKey pubkeyNew = keyNew.Neuter();
157 if (!(derive.nChild & BIP32_HARDENED_FLAG)) {
158 // Compare with public derivation
160 BOOST_CHECK(pubkey.Derive(pubkeyNew2, derive.nChild));
162 }
163 key = keyNew;
164 pubkey = pubkeyNew;
165 }
166}
167
168} // namespace
169
171
175
179
183
187
189 for (const auto& str : TEST5) {
190 auto dec_extkey = DecodeExtKey(str);
191 auto dec_extpubkey = DecodeExtPubKey(str);
192 BOOST_CHECK_MESSAGE(!dec_extkey.key.IsValid(), "Decoding '" + str + "' as xprv should fail");
193 BOOST_CHECK_MESSAGE(!dec_extpubkey.pubkey.IsValid(), "Decoding '" + str + "' as xpub should fail");
194 }
195}
196
198{
199 // A serialized extended key is exactly BIP32_EXTKEY_SIZE bytes. A shorter
200 // stream must throw rather than read past the end.
201 for (size_t len{0}; len < BIP32_EXTKEY_SIZE; ++len) {
202 CExtKey key;
203 CExtPubKey pubkey;
204 DataStream ss_key{std::vector<unsigned char>(len)};
205 DataStream ss_pubkey{std::vector<unsigned char>(len)};
206 BOOST_CHECK_THROW(ss_key >> key, std::ios_base::failure);
207 BOOST_CHECK_THROW(ss_pubkey >> pubkey, std::ios_base::failure);
208 }
209
210 // Serialize a valid depth-0 xprv/xpub to mutate below.
211 const CExtKey master{DecodeExtKey(test1.vDerive[0].prv)};
212 const CExtPubKey master_pub{master.Neuter()};
213 BOOST_REQUIRE(master.nDepth == 0);
214 std::vector<unsigned char> key_bytes, pubkey_bytes;
215 {
216 DataStream ss{};
217 ss << master;
218 const auto ss_span{MakeUCharSpan(ss)};
219 key_bytes.assign(ss_span.begin(), ss_span.end());
220 DataStream sp{};
221 sp << master_pub;
222 const auto sp_span{MakeUCharSpan(sp)};
223 pubkey_bytes.assign(sp_span.begin(), sp_span.end());
224 }
227
228 // A longer stream is not invalid: exactly BIP32_EXTKEY_SIZE bytes are consumed
229 // and the trailing byte is left unread.
230 {
231 std::vector<unsigned char> extra{key_bytes};
232 extra.push_back(0);
234 CExtKey key;
235 ss >> key;
238 }
239 {
240 std::vector<unsigned char> extra{pubkey_bytes};
241 extra.push_back(0);
243 CExtPubKey pubkey;
244 ss >> pubkey;
247 }
248
249 const auto deser_extkey{[](std::vector<unsigned char> bytes) {
250 DataStream ss{bytes};
251 CExtKey key;
252 ss >> key;
253 return key;
254 }};
255 const auto deser_extpubkey{[](std::vector<unsigned char> bytes) {
256 DataStream ss{bytes};
257 CExtPubKey pubkey;
258 ss >> pubkey;
259 return pubkey;
260 }};
261
262 // Non-zero private key prefix (offset 41) => invalid.
263 {
264 auto bytes{key_bytes};
265 bytes[41] = 1;
266 BOOST_CHECK(!deser_extkey(bytes).key.IsValid());
267 }
268 // Non-zero child index with nDepth == 0 (offset 8) => invalid.
269 {
270 auto bytes{key_bytes};
271 bytes[8] = 1;
272 BOOST_CHECK(!deser_extkey(bytes).key.IsValid());
273 }
274 // Non-zero parent fingerprint with nDepth == 0 (offset 1) => invalid.
275 {
276 auto bytes{key_bytes};
277 bytes[1] = 1;
278 BOOST_CHECK(!deser_extkey(bytes).key.IsValid());
279 }
280 // Invalid public key header (offset 41) => invalid.
281 {
282 auto bytes{pubkey_bytes};
283 bytes[41] = 0;
284 BOOST_CHECK(!deser_extpubkey(bytes).pubkey.IsValid());
285 }
286 // Non-zero child index with nDepth == 0 (offset 8) => invalid.
287 {
288 auto bytes{pubkey_bytes};
289 bytes[8] = 1;
290 BOOST_CHECK(!deser_extpubkey(bytes).pubkey.IsValid());
291 }
292 // Non-zero parent fingerprint with nDepth == 0 (offset 1) => invalid.
293 {
294 auto bytes{pubkey_bytes};
295 bytes[1] = 1;
296 BOOST_CHECK(!deser_extpubkey(bytes).pubkey.IsValid());
297 }
298}
299
301{
302 const CExtKey master{DecodeExtKey(test1.vDerive[0].prv)};
303 const std::vector<uint32_t> path{test1.vDerive[0].nChild, test1.vDerive[1].nChild};
304 const auto derived{DeriveExtKey(master, path)};
306 BOOST_CHECK(EncodeExtKey(derived->first) == test1.vDerive[2].prv);
307
309 expected_origin.fingerprint = master.id_key_fingerprint();
310 expected_origin.path = path;
312
313 const auto root{DeriveExtKey(master, {})};
314 BOOST_REQUIRE(root);
315 BOOST_CHECK_EQUAL(root->first, master);
316 expected_origin.path.clear();
317 BOOST_CHECK_EQUAL(root->second, expected_origin);
318
320 for (auto i{0}; i++ < 255;) {
322 BOOST_REQUIRE(max_depth.Derive(next_key, 0));
324 }
326}
327
329{
330 const std::vector<uint32_t> empty;
331 const std::vector<uint32_t> unhardened{0, 1, 2};
332 const std::vector<uint32_t> hardened{BIP32_HARDENED_FLAG};
333 const std::vector<uint32_t> mixed{0, BIP32_HARDENED_FLAG | 1, 2};
338}
339
343
344 // We can derive up to the 255th depth..
345 for (auto i = 0; i++ < 255;) {
346 BOOST_CHECK(key_parent.Derive(key_child, 0));
347 std::swap(key_parent, key_child);
349 std::swap(pubkey_parent, pubkey_child);
350 }
351
352 // But trying to derive a non-existent 256th depth will fail!
353 BOOST_CHECK(key_parent.nDepth == 255);
354 BOOST_CHECK(pubkey_parent.nDepth == 255);
355 BOOST_CHECK(!key_parent.Derive(key_child, 0));
357}
358
360{
361 static constexpr uint32_t H0{0x80000000U}; // 0'
362 static constexpr uint32_t H1{0x80000001U}; // 1'
363
364 struct TestCase {
365 bool is_valid;
366 std::string keypath;
367 std::vector<uint32_t> expected;
368 };
369
370 const std::vector<TestCase> tests{
371 // 28 unhardened ones, no trailing slash
372 {true, "1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1",
373 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}},
374 {false, "///////////////////////////", {}},
375 // 26 unhardened ones, then hardened 1, then unhardened 1
376 {true, "1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1'/1",
377 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,H1,1}},
378 {false, "//////////////////////////'/", {}},
379 // 27 unhardened ones, trailing slash ignored
380 {true, "1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/",
381 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}},
382 {false, "1///////////////////////////", {}},
383 // 26 unhardened ones, hardened 1, trailing slash ignored
384 {true, "1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1'/",
385 {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,H1}},
386 {false, "1/'//////////////////////////", {}},
387 {true, "", {}},
388 {false, " ", {}},
389 {true, "0", {0}},
390 {false, "O", {}},
391 {true, "0000'/0000'/0000'", {H0, H0, H0}},
392 {false, "0000,/0000,/0000,", {}},
393 {true, "01234", {1234}},
394 {false, "0x1234", {}},
395 {true, "1", {1}},
396 {false, " 1", {}},
397 {true, "42", {42}},
398 {false, "m42", {}},
399 // A path element's numeric part is capped at 2^31-1; the top bit is
400 // reserved for the hardened marker (h or ').
401 {true, "2147483647", {0x7FFFFFFF}}, // 0x7fffffff, largest normal index
402 {false, "2147483648", {}}, // 0x80000000, would set the hardened bit
403 {false, "4294967295", {}}, // 0xffffffff
404 {false, "4294967296", {}}, // 0xffffffff + 1
405 {true, "m", {}},
406 {false, "n", {}},
407 {true, "m/", {}},
408 {false, "n/", {}},
409 {true, "m/0", {0}},
410 {false, "n/0", {}},
411 {true, "m/0'", {H0}},
412 {false, "m/0''", {}},
413
414 {true, "m/0h", {H0}},
415 {false, "m/0hh", {}},
416 {false, "m/0x", {}},
417 {false, "m/0a", {}},
418 {false, "m/0G", {}},
419 {false, "m/h0", {}},
420 {true, "m/0h/1h/2h", {H0, H1, 0x80000002U}},
421 {true, "m/0'/0'", {H0, H0}},
422 {true, "m/0h/0h", {H0, H0}},
423 {true, "m/0'/0h", {H0, H0}},
424 {false, "m/'0/0'", {}},
425 {false, "m/h0/0'", {}},
426 {true, "m/0/0", {0, 0}},
427 {false, "n/0/0", {}},
428 {true, "m/0/0/00", {0, 0, 0}},
429 {false, "m/0/0/f00", {}},
430 {true, "m/0/0/000000000000000000000000000000000000000000000000000000000000000000000000000000000000", {0, 0, 0}},
431 {false, "m/1/1/111111111111111111111111111111111111111111111111111111111111111111111111111111111111", {}},
432 {true, "m/0/00/0", {0, 0, 0}},
433 {false, "m/0'/00/'0", {}},
434 {true, "m/1/", {1}},
435 {false, "m/1//", {}},
436 // The cap applies to every element, wherever it sits in the path.
437 {true, "m/2147483647", {0x7FFFFFFF}},
438 {false, "m/2147483648", {}},
439 {false, "m/4294967295", {}},
440 {false, "m/4294967296", {}},
441 {true, "m/0/2147483647", {0, 0x7FFFFFFF}},
442 {false, "m/0/2147483648", {}},
443 {false, "m/0/4294967295", {}},
444 {false, "m/0/4294967296", {}},
445 {false, "1/2H/3H", {}},
446 {false, "1/2h/3h ", {}},
447 {false, "1/2h /3h", {}},
448 {true, "1/2h/3h", {1, 0x80000002, 0x80000003}},
449 {true, "1/2'/3h", {1, 0x80000002, 0x80000003}},
450 };
451
452 for (const auto& [is_valid, keypath_str, expected] : tests) {
453 std::vector<uint32_t> keypath_num;
455 if (!is_valid) {
456 BOOST_CHECK_EQUAL(res1, false);
457 } else {
458 BOOST_CHECK_EQUAL(res1, true);
459 BOOST_REQUIRE_EQUAL(keypath_num.size(), expected.size());
460 for (size_t i{0}; i < keypath_num.size(); ++i) {
461 BOOST_CHECK_EQUAL(keypath_num[i], expected[i]);
462 }
463
464 // Round-trip test:
465 const std::string keypath_str2{FormatHDKeypath(keypath_num, /*apostrophe=*/true)};
466 // Note keypath_str2 may differ from keypath_str. Leading '/' is not parsed, it is removed
468 if (keypath_str2_adjusted.starts_with('/')) {
469 keypath_str2_adjusted.erase(0, 1);
470 }
471 std::vector<uint32_t> keypath_num2;
474 for (size_t i{0}; i < keypath_num2.size(); ++i) {
476 }
477 const std::string keypath_str3{FormatHDKeypath(keypath_num2, /*apostrophe=*/true)};
479 }
480 }
481}
482
bool ParseHDKeypath(const std::string &keypath_str, std::vector< uint32_t > &keypath)
Parse an HD keypaths like "m/7/0'/2000".
Definition bip32.cpp:41
std::string FormatHDKeypath(const std::vector< uint32_t > &path, bool apostrophe)
Definition bip32.cpp:62
bool HasHardenedDerivation(std::span< const uint32_t > keypath)
Whether a parsed HD keypath contains at least one hardened derivation step.
Definition bip32.cpp:77
static constexpr uint32_t BIP32_HARDENED_FLAG
BIP32 hardened derivation flag (2^31)
Definition bip32.h:17
BOOST_AUTO_TEST_CASE(bip32_test1)
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:165
size_type size() const
Definition streams.h:198
const std::string test1
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::optional< std::pair< CExtKey, KeyOriginInfo > > DeriveExtKey(const CExtKey &ext_key, const std::vector< uint32_t > &path)
Get extended key and origin info for a given path.
Definition key.cpp:369
CExtPubKey DecodeExtPubKey(std::string_view str)
Definition key_io.cpp:246
std::string EncodeExtKey(const CExtKey &key)
Definition key_io.cpp:302
std::string EncodeExtPubKey(const CExtPubKey &key)
Definition key_io.cpp:259
CExtKey DecodeExtKey(std::string_view str)
Definition key_io.cpp:267
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition object.cpp:18
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:17
#define BOOST_CHECK(expr)
Definition object.cpp:16
constexpr unsigned int BIP32_EXTKEY_SIZE
Definition pubkey.h:22
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Definition span.h:111
Utilities for converting data from/to strings.
Basic testing setup.
Definition key.h:238
CExtPubKey Neuter() const
Definition key.cpp:394
unsigned int nChild
Definition key.h:241
void SetSeed(std::span< const std::byte > seed)
Definition key.cpp:381
KeyFingerprint fingerprint
First 32 bits of the Hash160 of the public key at the root of the path.
Definition keyorigin.h:14
DataStream ss
constexpr std::array tests
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82