Line | Count | Source |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-present The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #ifndef BITCOIN_UINT256_H |
7 | | #define BITCOIN_UINT256_H |
8 | | |
9 | | #include <crypto/common.h> |
10 | | #include <span.h> |
11 | | #include <util/strencodings.h> |
12 | | #include <util/string.h> |
13 | | |
14 | | #include <algorithm> |
15 | | #include <array> |
16 | | #include <cassert> |
17 | | #include <cstdint> |
18 | | #include <cstring> |
19 | | #include <optional> |
20 | | #include <string> |
21 | | #include <string_view> |
22 | | |
23 | | /** Template base class for fixed-sized opaque blobs. */ |
24 | | template<unsigned int BITS> |
25 | | class base_blob |
26 | | { |
27 | | protected: |
28 | | static constexpr int WIDTH = BITS / 8; |
29 | | static_assert(BITS % 8 == 0, "base_blob currently only supports whole bytes."); |
30 | | std::array<uint8_t, WIDTH> m_data; |
31 | | static_assert(WIDTH == sizeof(m_data), "Sanity check"); |
32 | | |
33 | | public: |
34 | | /* construct 0 value by default */ |
35 | 11.7G | constexpr base_blob() : m_data() {} base_blob<256u>::base_blob() Line | Count | Source | 35 | 11.7G | constexpr base_blob() : m_data() {} |
base_blob<160u>::base_blob() Line | Count | Source | 35 | 9.97M | constexpr base_blob() : m_data() {} |
|
36 | | |
37 | | /* constructor for constants between 1 and 255 */ |
38 | 0 | constexpr explicit base_blob(uint8_t v) : m_data{v} {} |
39 | | |
40 | | constexpr explicit base_blob(std::span<const unsigned char> vch) |
41 | 221k | { |
42 | 221k | assert(vch.size() == WIDTH); Branch (42:9): [True: 221k, False: 0]
Branch (42:9): [True: 0, False: 0]
|
43 | 221k | std::copy(vch.begin(), vch.end(), m_data.begin()); |
44 | 221k | } base_blob<256u>::base_blob(std::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 41 | 221k | { | 42 | 221k | assert(vch.size() == WIDTH); Branch (42:9): [True: 221k, False: 0]
| 43 | 221k | std::copy(vch.begin(), vch.end(), m_data.begin()); | 44 | 221k | } |
Unexecuted instantiation: base_blob<160u>::base_blob(std::span<unsigned char const, 18446744073709551615ul>) |
45 | | |
46 | | consteval explicit base_blob(std::string_view hex_str); |
47 | | |
48 | | constexpr bool IsNull() const |
49 | 138M | { |
50 | 4.15G | return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) { |
51 | 4.15G | return val == 0; |
52 | 4.15G | }); base_blob<256u>::IsNull() const::{lambda(unsigned char)#1}::operator()(unsigned char) const Line | Count | Source | 50 | 4.15G | return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) { | 51 | 4.15G | return val == 0; | 52 | 4.15G | }); |
Unexecuted instantiation: base_blob<160u>::IsNull() const::{lambda(unsigned char)#1}::operator()(unsigned char) const |
53 | 138M | } base_blob<256u>::IsNull() const Line | Count | Source | 49 | 138M | { | 50 | 138M | return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) { | 51 | 138M | return val == 0; | 52 | 138M | }); | 53 | 138M | } |
Unexecuted instantiation: base_blob<160u>::IsNull() const |
54 | | |
55 | | constexpr void SetNull() |
56 | 22.8M | { |
57 | 22.8M | std::fill(m_data.begin(), m_data.end(), 0); |
58 | 22.8M | } base_blob<256u>::SetNull() Line | Count | Source | 56 | 22.8M | { | 57 | 22.8M | std::fill(m_data.begin(), m_data.end(), 0); | 58 | 22.8M | } |
Unexecuted instantiation: base_blob<160u>::SetNull() |
59 | | |
60 | | /** Lexicographic ordering |
61 | | * @note Does NOT match the ordering on the corresponding \ref |
62 | | * base_uint::CompareTo, which starts comparing from the end. |
63 | | */ |
64 | 284M | constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); } base_blob<256u>::Compare(base_blob<256u> const&) const Line | Count | Source | 64 | 284M | constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); } |
base_blob<160u>::Compare(base_blob<160u> const&) const Line | Count | Source | 64 | 177k | constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); } |
|
65 | | |
66 | 53.4M | friend constexpr bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; } operator==(base_blob<256u> const&, base_blob<256u> const&) Line | Count | Source | 66 | 53.4M | friend constexpr bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; } |
Unexecuted instantiation: operator==(base_blob<160u> const&, base_blob<160u> const&) |
67 | 9.31M | friend constexpr bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; } operator!=(base_blob<256u> const&, base_blob<256u> const&) Line | Count | Source | 67 | 9.31M | friend constexpr bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; } |
Unexecuted instantiation: operator!=(base_blob<160u> const&, base_blob<160u> const&) |
68 | 51.1M | friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } operator<(base_blob<256u> const&, base_blob<256u> const&) Line | Count | Source | 68 | 50.9M | friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } |
operator<(base_blob<160u> const&, base_blob<160u> const&) Line | Count | Source | 68 | 177k | friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } |
|
69 | | |
70 | | /** @name Hex representation |
71 | | * |
72 | | * The hex representation used by GetHex(), ToString(), and FromHex() |
73 | | * is unusual, since it shows bytes of the base_blob in reverse order. |
74 | | * For example, a 4-byte blob {0x12, 0x34, 0x56, 0x78} is represented |
75 | | * as "78563412" instead of the more typical "12345678" representation |
76 | | * that would be shown in a hex editor or used by typical |
77 | | * byte-array / hex conversion functions like python's bytes.hex() and |
78 | | * bytes.fromhex(). |
79 | | * |
80 | | * The nice thing about the reverse-byte representation, even though it is |
81 | | * unusual, is that if a blob contains an arithmetic number in little endian |
82 | | * format (with least significant bytes first, and most significant bytes |
83 | | * last), the GetHex() output will match the way the number would normally |
84 | | * be written in base-16 (with most significant digits first and least |
85 | | * significant digits last). |
86 | | * |
87 | | * This means, for example, that ArithToUint256(num).GetHex() can be used to |
88 | | * display an arith_uint256 num value as a number, because |
89 | | * ArithToUint256() converts the number to a blob in little-endian format, |
90 | | * so the arith_uint256 class doesn't need to have its own number parsing |
91 | | * and formatting functions. |
92 | | * |
93 | | * @{*/ |
94 | | std::string GetHex() const; |
95 | | std::string ToString() const; |
96 | | /**@}*/ |
97 | | |
98 | 16.2M | constexpr const unsigned char* data() const { return m_data.data(); } Unexecuted instantiation: base_blob<160u>::data() const base_blob<256u>::data() const Line | Count | Source | 98 | 16.2M | constexpr const unsigned char* data() const { return m_data.data(); } |
|
99 | 41.8M | constexpr unsigned char* data() { return m_data.data(); } Line | Count | Source | 99 | 5.45M | constexpr unsigned char* data() { return m_data.data(); } |
Line | Count | Source | 99 | 36.3M | constexpr unsigned char* data() { return m_data.data(); } |
|
100 | | |
101 | 172M | constexpr unsigned char* begin() { return m_data.data(); } Line | Count | Source | 101 | 1.95M | constexpr unsigned char* begin() { return m_data.data(); } |
Line | Count | Source | 101 | 170M | constexpr unsigned char* begin() { return m_data.data(); } |
|
102 | 0 | constexpr unsigned char* end() { return m_data.data() + WIDTH; } Unexecuted instantiation: base_blob<160u>::end() Unexecuted instantiation: base_blob<256u>::end() |
103 | | |
104 | 50.7M | constexpr const unsigned char* begin() const { return m_data.data(); } base_blob<160u>::begin() const Line | Count | Source | 104 | 887k | constexpr const unsigned char* begin() const { return m_data.data(); } |
base_blob<256u>::begin() const Line | Count | Source | 104 | 49.8M | constexpr const unsigned char* begin() const { return m_data.data(); } |
|
105 | 1.12M | constexpr const unsigned char* end() const { return m_data.data() + WIDTH; } base_blob<160u>::end() const Line | Count | Source | 105 | 887k | constexpr const unsigned char* end() const { return m_data.data() + WIDTH; } |
base_blob<256u>::end() const Line | Count | Source | 105 | 238k | constexpr const unsigned char* end() const { return m_data.data() + WIDTH; } |
|
106 | | |
107 | 53.4M | static constexpr unsigned int size() { return WIDTH; } Line | Count | Source | 107 | 5.45M | static constexpr unsigned int size() { return WIDTH; } |
Line | Count | Source | 107 | 48.0M | static constexpr unsigned int size() { return WIDTH; } |
|
108 | | |
109 | 299M | constexpr uint64_t GetUint64(int pos) const { return ReadLE64(m_data.data() + pos * 8); } |
110 | | |
111 | | template<typename Stream> |
112 | | void Serialize(Stream& s) const |
113 | 167M | { |
114 | 167M | s << std::span(m_data); |
115 | 167M | } void base_blob<256u>::Serialize<ParamsStream<SizeComputer&, TransactionSerParams> >(ParamsStream<SizeComputer&, TransactionSerParams>&) const Line | Count | Source | 113 | 33.5M | { | 114 | 33.5M | s << std::span(m_data); | 115 | 33.5M | } |
void base_blob<256u>::Serialize<VectorWriter>(VectorWriter&) const Line | Count | Source | 113 | 10.4M | { | 114 | 10.4M | s << std::span(m_data); | 115 | 10.4M | } |
void base_blob<256u>::Serialize<ParamsStream<VectorWriter&, TransactionSerParams> >(ParamsStream<VectorWriter&, TransactionSerParams>&) const Line | Count | Source | 113 | 27.2k | { | 114 | 27.2k | s << std::span(m_data); | 115 | 27.2k | } |
void base_blob<256u>::Serialize<DataStream>(DataStream&) const Line | Count | Source | 113 | 26.5M | { | 114 | 26.5M | s << std::span(m_data); | 115 | 26.5M | } |
void base_blob<256u>::Serialize<HashWriter>(HashWriter&) const Line | Count | Source | 113 | 76.9M | { | 114 | 76.9M | s << std::span(m_data); | 115 | 76.9M | } |
void base_blob<256u>::Serialize<BufferedWriter<AutoFile> >(BufferedWriter<AutoFile>&) const Line | Count | Source | 113 | 2.22M | { | 114 | 2.22M | s << std::span(m_data); | 115 | 2.22M | } |
void base_blob<256u>::Serialize<ParamsStream<BufferedWriter<AutoFile>&, TransactionSerParams> >(ParamsStream<BufferedWriter<AutoFile>&, TransactionSerParams>&) const Line | Count | Source | 113 | 6.82M | { | 114 | 6.82M | s << std::span(m_data); | 115 | 6.82M | } |
void base_blob<256u>::Serialize<ParamsStream<AutoFile&, TransactionSerParams> >(ParamsStream<AutoFile&, TransactionSerParams>&) const Line | Count | Source | 113 | 29.1k | { | 114 | 29.1k | s << std::span(m_data); | 115 | 29.1k | } |
void base_blob<256u>::Serialize<AutoFile>(AutoFile&) const Line | Count | Source | 113 | 2.26M | { | 114 | 2.26M | s << std::span(m_data); | 115 | 2.26M | } |
Unexecuted instantiation: void base_blob<256u>::Serialize<ParamsStream<DataStream&, TransactionSerParams> >(ParamsStream<DataStream&, TransactionSerParams>&) const void base_blob<256u>::Serialize<SizeComputer>(SizeComputer&) const Line | Count | Source | 113 | 2.23M | { | 114 | 2.23M | s << std::span(m_data); | 115 | 2.23M | } |
void base_blob<256u>::Serialize<ParamsStream<HashedSourceWriter<AutoFile>&, CAddress::SerParams> >(ParamsStream<HashedSourceWriter<AutoFile>&, CAddress::SerParams>&) const Line | Count | Source | 113 | 44.3k | { | 114 | 44.3k | s << std::span(m_data); | 115 | 44.3k | } |
Unexecuted instantiation: void base_blob<256u>::Serialize<ParamsStream<DataStream&, CAddress::SerParams> >(ParamsStream<DataStream&, CAddress::SerParams>&) const Unexecuted instantiation: void base_blob<160u>::Serialize<DataStream>(DataStream&) const void base_blob<256u>::Serialize<ParamsStream<HashWriter&, TransactionSerParams> >(ParamsStream<HashWriter&, TransactionSerParams>&) const Line | Count | Source | 113 | 6.02M | { | 114 | 6.02M | s << std::span(m_data); | 115 | 6.02M | } |
|
116 | | |
117 | | template<typename Stream> |
118 | | void Unserialize(Stream& s) |
119 | 10.5M | { |
120 | 10.5M | s.read(MakeWritableByteSpan(m_data)); |
121 | 10.5M | } void base_blob<256u>::Unserialize<DataStream>(DataStream&) Line | Count | Source | 119 | 787k | { | 120 | 787k | s.read(MakeWritableByteSpan(m_data)); | 121 | 787k | } |
void base_blob<256u>::Unserialize<ParamsStream<DataStream&, TransactionSerParams> >(ParamsStream<DataStream&, TransactionSerParams>&) Line | Count | Source | 119 | 7.45M | { | 120 | 7.45M | s.read(MakeWritableByteSpan(m_data)); | 121 | 7.45M | } |
void base_blob<256u>::Unserialize<BufferedReader<AutoFile> >(BufferedReader<AutoFile>&) Line | Count | Source | 119 | 2.22M | { | 120 | 2.22M | s.read(MakeWritableByteSpan(m_data)); | 121 | 2.22M | } |
void base_blob<256u>::Unserialize<ParamsStream<SpanReader&, TransactionSerParams> >(ParamsStream<SpanReader&, TransactionSerParams>&) Line | Count | Source | 119 | 113k | { | 120 | 113k | s.read(MakeWritableByteSpan(m_data)); | 121 | 113k | } |
Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<AutoFile&, TransactionSerParams> >(ParamsStream<AutoFile&, TransactionSerParams>&) Unexecuted instantiation: void base_blob<256u>::Unserialize<AutoFile>(AutoFile&) Unexecuted instantiation: void base_blob<256u>::Unserialize<BufferedFile>(BufferedFile&) Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<BufferedFile&, TransactionSerParams> >(ParamsStream<BufferedFile&, TransactionSerParams>&) Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<AutoFile&, CAddress::SerParams> >(ParamsStream<AutoFile&, CAddress::SerParams>&) Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<HashVerifier<AutoFile>&, CAddress::SerParams> >(ParamsStream<HashVerifier<AutoFile>&, CAddress::SerParams>&) Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<DataStream&, CAddress::SerParams> >(ParamsStream<DataStream&, CAddress::SerParams>&) Unexecuted instantiation: void base_blob<256u>::Unserialize<ParamsStream<HashVerifier<DataStream>&, CAddress::SerParams> >(ParamsStream<HashVerifier<DataStream>&, CAddress::SerParams>&) Unexecuted instantiation: void base_blob<160u>::Unserialize<DataStream>(DataStream&) Unexecuted instantiation: void base_blob<256u>::Unserialize<SpanReader>(SpanReader&) |
122 | | }; |
123 | | |
124 | | template <unsigned int BITS> |
125 | | consteval base_blob<BITS>::base_blob(std::string_view hex_str) |
126 | | { |
127 | | if (hex_str.length() != m_data.size() * 2) throw "Hex string must fit exactly"; |
128 | | auto str_it = hex_str.rbegin(); |
129 | | for (auto& elem : m_data) { |
130 | | auto lo = util::ConstevalHexDigit(*(str_it++)); |
131 | | elem = (util::ConstevalHexDigit(*(str_it++)) << 4) | lo; |
132 | | } |
133 | | } |
134 | | |
135 | | namespace detail { |
136 | | /** |
137 | | * Writes the hex string (in reverse byte order) into a new uintN_t object |
138 | | * and only returns a value iff all of the checks pass: |
139 | | * - Input length is uintN_t::size()*2 |
140 | | * - All characters are hex |
141 | | */ |
142 | | template <class uintN_t> |
143 | | std::optional<uintN_t> FromHex(std::string_view str) |
144 | 0 | { |
145 | 0 | if (uintN_t::size() * 2 != str.size() || !IsHex(str)) return std::nullopt; Branch (145:9): [True: 0, False: 0]
Branch (145:46): [True: 0, False: 0]
|
146 | 0 | uintN_t rv; |
147 | 0 | unsigned char* p1 = rv.begin(); |
148 | 0 | unsigned char* pend = rv.end(); |
149 | 0 | size_t digits = str.size(); |
150 | 0 | while (digits > 0 && p1 < pend) { Branch (150:12): [True: 0, False: 0]
Branch (150:26): [True: 0, False: 0]
|
151 | 0 | *p1 = ::HexDigit(str[--digits]); |
152 | 0 | if (digits > 0) { Branch (152:13): [True: 0, False: 0]
|
153 | 0 | *p1 |= ((unsigned char)::HexDigit(str[--digits]) << 4); |
154 | 0 | p1++; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | return rv; |
158 | 0 | } Unexecuted instantiation: std::optional<uint160> detail::FromHex<uint160>(std::basic_string_view<char, std::char_traits<char> >) Unexecuted instantiation: std::optional<uint256> detail::FromHex<uint256>(std::basic_string_view<char, std::char_traits<char> >) |
159 | | /** |
160 | | * @brief Like FromHex(std::string_view str), but allows an "0x" prefix |
161 | | * and pads the input with leading zeroes if it is shorter than |
162 | | * the expected length of uintN_t::size()*2. |
163 | | * |
164 | | * Designed to be used when dealing with user input. |
165 | | */ |
166 | | template <class uintN_t> |
167 | | std::optional<uintN_t> FromUserHex(std::string_view input) |
168 | 0 | { |
169 | 0 | input = util::RemovePrefixView(input, "0x"); |
170 | 0 | constexpr auto expected_size{uintN_t::size() * 2}; |
171 | 0 | if (input.size() < expected_size) { Branch (171:9): [True: 0, False: 0]
|
172 | 0 | auto padded = std::string(expected_size, '0'); |
173 | 0 | std::copy(input.begin(), input.end(), padded.begin() + expected_size - input.size()); |
174 | 0 | return FromHex<uintN_t>(padded); |
175 | 0 | } |
176 | 0 | return FromHex<uintN_t>(input); |
177 | 0 | } |
178 | | } // namespace detail |
179 | | |
180 | | /** 160-bit opaque blob. |
181 | | * @note This type is called uint160 for historical reasons only. It is an opaque |
182 | | * blob of 160 bits and has no integer operations. |
183 | | */ |
184 | | class uint160 : public base_blob<160> { |
185 | | public: |
186 | 0 | static std::optional<uint160> FromHex(std::string_view str) { return detail::FromHex<uint160>(str); } |
187 | 9.97M | constexpr uint160() = default; |
188 | 0 | constexpr explicit uint160(std::span<const unsigned char> vch) : base_blob<160>(vch) {} |
189 | | }; |
190 | | |
191 | | /** 256-bit opaque blob. |
192 | | * @note This type is called uint256 for historical reasons only. It is an |
193 | | * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if |
194 | | * those are required. |
195 | | */ |
196 | | class uint256 : public base_blob<256> { |
197 | | public: |
198 | 0 | static std::optional<uint256> FromHex(std::string_view str) { return detail::FromHex<uint256>(str); } |
199 | 0 | static std::optional<uint256> FromUserHex(std::string_view str) { return detail::FromUserHex<uint256>(str); } |
200 | 11.7G | constexpr uint256() = default; |
201 | 0 | consteval explicit uint256(std::string_view hex_str) : base_blob<256>(hex_str) {} |
202 | 0 | constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {} |
203 | 221k | constexpr explicit uint256(std::span<const unsigned char> vch) : base_blob<256>(vch) {} |
204 | | static const uint256 ZERO; |
205 | | static const uint256 ONE; |
206 | | }; |
207 | | |
208 | | #endif // BITCOIN_UINT256_H |