Branch data Line data Source code
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 : 304421 : util::Expected<KeyPathElement, std::string> ParseKeyPathElement(std::span<const char> elem)
18 : : {
19 [ + + ]: 304421 : const std::string_view raw{elem.begin(), elem.end()};
20 [ + + ]: 304421 : if (elem.empty()) {
21 : 14 : return util::Unexpected{strprintf("Key path value '%s' is not valid", raw)};
22 : : }
23 : :
24 : 304407 : bool is_hardened = false;
25 [ + + ]: 304407 : const char last = elem.back();
26 [ + + ]: 304407 : if (last == '\'' || last == 'h') {
27 : 69923 : elem = elem.first(elem.size() - 1);
28 : 69923 : is_hardened = true;
29 : : }
30 : :
31 : 304407 : const auto number{ToIntegral<uint32_t>(std::string_view{elem.begin(), elem.end()})};
32 [ + + ]: 304407 : if (!number) {
33 : 139 : return util::Unexpected{strprintf("Key path value '%s' is not a valid uint32", raw)};
34 : : }
35 [ + + ]: 304268 : if (*number >= BIP32_HARDENED_FLAG) {
36 : 10 : return util::Unexpected{strprintf("Key path value %u is out of range", *number)};
37 : : }
38 : 304258 : return KeyPathElement{*number, is_hardened};
39 : : }
40 : :
41 : 261 : bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
42 : : {
43 : 261 : std::stringstream ss(keypath_str);
44 : 261 : std::string item;
45 : 261 : bool first = true;
46 [ + - + + : 37352 : while (std::getline(ss, item, '/') || std::getline(ss, item, 'h')) {
+ - - + ]
47 [ + + ]: 37155 : if (item.compare("m") == 0) {
48 [ + + ]: 181 : if (first) {
49 : 178 : first = false;
50 : 178 : continue;
51 : : }
52 : : return false;
53 : : }
54 [ - + + - ]: 36974 : const auto parsed{ParseKeyPathElement(std::span<const char>{item.data(), item.size()})};
55 [ + + ]: 36974 : if (!parsed) return false;
56 [ + + + - ]: 72065 : keypath.push_back(parsed->ChildNumber());
57 : 36913 : first = false;
58 : 36974 : }
59 : : return true;
60 : 261 : }
61 : :
62 : 5014303 : std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe)
63 : : {
64 : 5014303 : std::string ret;
65 [ + + ]: 9821673 : for (auto i : path) {
66 [ + - ]: 9614740 : ret += strprintf("/%i", (i << 1) >> 1);
67 [ + + + + ]: 7047097 : if (i >> 31) ret += apostrophe ? '\'' : 'h';
68 : : }
69 : 5014303 : return ret;
70 : 0 : }
71 : :
72 : 336 : std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe)
73 : : {
74 [ + - ]: 672 : return "m" + FormatHDKeypath(keypath, apostrophe);
75 : : }
76 : :
77 : 1544077 : bool HasHardenedDerivation(std::span<const uint32_t> keypath)
78 : : {
79 : 1544077 : return std::any_of(keypath.begin(), keypath.end(), [](uint32_t index) {
80 [ + + ]: 1612172 : return index >> 31;
81 : 1544077 : });
82 : : }
|