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 : 2227 : util::Expected<KeyPathElement, std::string> ParseKeyPathElement(std::span<const char> elem)
18 : : {
19 [ + + ]: 2227 : const std::string_view raw{elem.begin(), elem.end()};
20 [ + + ]: 2227 : if (elem.empty()) {
21 : 10 : return util::Unexpected{strprintf("Key path value '%s' is not valid", raw)};
22 : : }
23 : :
24 : 2217 : bool is_hardened = false;
25 [ + + ]: 2217 : const char last = elem.back();
26 [ + + ]: 2217 : if (last == '\'' || last == 'h') {
27 : 978 : elem = elem.first(elem.size() - 1);
28 : 978 : is_hardened = true;
29 : : }
30 : :
31 : 2217 : const auto number{ToIntegral<uint32_t>(std::string_view{elem.begin(), elem.end()})};
32 [ + + ]: 2217 : if (!number) {
33 : 33 : return util::Unexpected{strprintf("Key path value '%s' is not a valid uint32", raw)};
34 : : }
35 [ + + ]: 2184 : if (*number >= BIP32_HARDENED_FLAG) {
36 : 8 : return util::Unexpected{strprintf("Key path value %u is out of range", *number)};
37 : : }
38 : 2176 : return KeyPathElement{*number, is_hardened};
39 : : }
40 : :
41 : 62 : bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
42 : : {
43 : 62 : std::stringstream ss(keypath_str);
44 : 62 : std::string item;
45 : 62 : bool first = true;
46 [ + - + + : 253 : while (std::getline(ss, item, '/') || std::getline(ss, item, 'h')) {
+ - - + ]
47 [ + + ]: 226 : if (item.compare("m") == 0) {
48 [ + - ]: 34 : if (first) {
49 : 34 : first = false;
50 : 34 : continue;
51 : : }
52 : : return false;
53 : : }
54 [ - + + - ]: 192 : const auto parsed{ParseKeyPathElement(std::span<const char>{item.data(), item.size()})};
55 [ + + ]: 192 : if (!parsed) return false;
56 [ + + + - ]: 297 : keypath.push_back(parsed->ChildNumber());
57 : 157 : first = false;
58 : 192 : }
59 : : return true;
60 : 62 : }
61 : :
62 : 15220 : std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe)
63 : : {
64 : 15220 : std::string ret;
65 [ + + ]: 70032 : for (auto i : path) {
66 [ + - ]: 109624 : ret += strprintf("/%i", (i << 1) >> 1);
67 [ + + + + ]: 94755 : if (i >> 31) ret += apostrophe ? '\'' : 'h';
68 : : }
69 : 15220 : return ret;
70 : 0 : }
71 : :
72 : 0 : std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe)
73 : : {
74 [ # # ]: 0 : return "m" + FormatHDKeypath(keypath, apostrophe);
75 : : }
76 : :
77 : 3633 : bool HasHardenedDerivation(std::span<const uint32_t> keypath)
78 : : {
79 : 3633 : return std::any_of(keypath.begin(), keypath.end(), [](uint32_t index) {
80 [ + + ]: 3334 : return index >> 31;
81 : 3633 : });
82 : : }
|