/tmp/bitcoin/src/util/bip32.cpp
Line | Count | Source |
1 | | // Copyright (c) 2019-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 <util/bip32.h> |
6 | | |
7 | | #include <tinyformat.h> |
8 | | #include <util/strencodings.h> |
9 | | |
10 | | #include <algorithm> |
11 | | #include <cstdint> |
12 | | #include <optional> |
13 | | #include <span> |
14 | | #include <sstream> |
15 | | #include <string_view> |
16 | | |
17 | | util::Expected<KeyPathElement, std::string> ParseKeyPathElement(std::span<const char> elem) |
18 | 32.3k | { |
19 | 32.3k | const std::string_view raw{elem.begin(), elem.end()}; |
20 | 32.3k | if (elem.empty()) { |
21 | 10 | return util::Unexpected{strprintf("Key path value '%s' is not valid", raw)}; |
22 | 10 | } |
23 | | |
24 | 32.3k | bool is_hardened = false; |
25 | 32.3k | const char last = elem.back(); |
26 | 32.3k | if (last == '\'' || last == 'h') { |
27 | 23.4k | elem = elem.first(elem.size() - 1); |
28 | 23.4k | is_hardened = true; |
29 | 23.4k | } |
30 | | |
31 | 32.3k | const auto number{ToIntegral<uint32_t>(std::string_view{elem.begin(), elem.end()})}; |
32 | 32.3k | if (!number) { |
33 | 35 | return util::Unexpected{strprintf("Key path value '%s' is not a valid uint32", raw)}; |
34 | 35 | } |
35 | 32.3k | if (*number >= BIP32_HARDENED_FLAG) { |
36 | 11 | return util::Unexpected{strprintf("Key path value %u is out of range", *number)}; |
37 | 11 | } |
38 | 32.3k | return KeyPathElement{*number, is_hardened}; |
39 | 32.3k | } |
40 | | |
41 | | bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath) |
42 | 140 | { |
43 | 140 | std::stringstream ss(keypath_str); |
44 | 140 | std::string item; |
45 | 140 | bool first = true; |
46 | 861 | while (std::getline(ss, item, '/') || std::getline(ss, item, 'h')) { |
47 | 759 | if (item.compare("m") == 0) { |
48 | 112 | if (first) { |
49 | 112 | first = false; |
50 | 112 | continue; |
51 | 112 | } |
52 | 0 | return false; |
53 | 112 | } |
54 | 647 | const auto parsed{ParseKeyPathElement(std::span<const char>{item.data(), item.size()})}; |
55 | 647 | if (!parsed) return false; |
56 | 609 | keypath.push_back(parsed->ChildNumber()); |
57 | 609 | first = false; |
58 | 609 | } |
59 | 102 | return true; |
60 | 140 | } |
61 | | |
62 | | std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe) |
63 | 239k | { |
64 | 239k | std::string ret; |
65 | 693k | for (auto i : path) { |
66 | 693k | ret += strprintf("/%i", (i << 1) >> 1); |
67 | 693k | if (i >> 31) ret += apostrophe ? '\'' : 'h'; |
68 | 693k | } |
69 | 239k | return ret; |
70 | 239k | } |
71 | | |
72 | | std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe) |
73 | 2.94k | { |
74 | 2.94k | return "m" + FormatHDKeypath(keypath, apostrophe); |
75 | 2.94k | } |
76 | | |
77 | | bool HasHardenedDerivation(std::span<const uint32_t> keypath) |
78 | 28.9k | { |
79 | 28.9k | return std::any_of(keypath.begin(), keypath.end(), [](uint32_t index) { |
80 | 28.7k | return index >> 31; |
81 | 28.7k | }); |
82 | 28.9k | } |