Coverage Report

Created: 2026-09-14 20:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}