rippled
Loading...
Searching...
No Matches
base_uint.h
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2011 The Bitcoin developers
3// Distributed under the MIT/X11 software license, see the accompanying
4// file license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6#pragma once
7
8#include <xrpl/basics/Expected.h>
9#include <xrpl/basics/Slice.h>
10#include <xrpl/basics/contract.h>
11#include <xrpl/basics/hardened_hash.h>
12#include <xrpl/basics/partitioned_unordered_map.h>
13#include <xrpl/basics/strHex.h>
14#include <xrpl/beast/utility/Zero.h>
15#include <xrpl/beast/utility/instrumentation.h>
16
17#include <boost/endian/conversion.hpp>
18#include <boost/functional/hash.hpp>
19
20#include <algorithm>
21#include <array>
22#include <cstring>
23#include <type_traits>
24
25namespace xrpl {
26
27namespace detail {
28
29template <class Container, class = std::void_t<>>
33
34template <class Container>
36 Container,
37 std::void_t<
38 decltype(std::declval<Container const>().size()),
39 decltype(std::declval<Container const>().data()),
40 typename Container::value_type>> : std::true_type
41{
42};
43
44template <>
48
49} // namespace detail
50
64template <std::size_t Bits, class Tag = void>
66{
67 static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
68
69 static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
70
71 static constexpr std::size_t WIDTH = Bits / 32;
72
73 // This is really big-endian in byte order.
74 // We sometimes use std::uint32_t for speed.
75
77
78public:
79 //--------------------------------------------------------------------------
80 //
81 // STL Container Interface
82 //
83
84 static std::size_t constexpr bytes = Bits / 8;
85 static_assert(sizeof(data_) == bytes, "");
86
89 using value_type = unsigned char;
92 using const_pointer = value_type const*;
98 using tag_type = Tag;
99
100 pointer
102 {
103 return reinterpret_cast<pointer>(data_.data());
104 }
106 data() const
107 {
108 return reinterpret_cast<const_pointer>(data_.data());
109 }
110
113 {
114 return data();
115 }
118 {
119 return data() + bytes;
120 }
122 begin() const
123 {
124 return data();
125 }
127 end() const
128 {
129 return data() + bytes;
130 }
132 cbegin() const
133 {
134 return data();
135 }
137 cend() const
138 {
139 return data() + bytes;
140 }
141
147
148 //--------------------------------------------------------------------------
149
150private:
157 // NIKB TODO Remove the need for this constructor.
159 {
160 explicit VoidHelper() = default;
161 };
162
163 explicit base_uint(void const* data, VoidHelper)
164 {
165 memcpy(data_.data(), data, bytes);
166 }
167
168 // Helper function to initialize a base_uint from a std::string_view.
169 enum class ParseResult {
170 okay,
171 badLength,
172 badChar,
173 };
174
175 constexpr Expected<decltype(data_), ParseResult>
177 {
178 // Local lambda that converts a single hex char to four bits and
179 // ORs those bits into a uint32_t.
180 auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
181 std::uint32_t nibble = 0xFFu;
182 if (c < '0' || c > 'f')
184
185 if (c >= 'a')
186 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
187 else if (c >= 'A')
188 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
189 else if (c <= '9')
190 nibble = static_cast<std::uint32_t>(c - '0');
191
192 if (nibble > 0xFu)
194
195 accum |= (nibble << shift);
196
197 return ParseResult::okay;
198 };
199
200 decltype(data_) ret{};
201
202 if (sv == "0")
203 {
204 return ret;
205 }
206
207 if (sv.size() != size() * 2)
209
210 std::size_t i = 0u;
211 auto in = sv.begin();
212 while (in != sv.end())
213 {
214 std::uint32_t accum = {};
215 for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
216 {
217 if (auto const result = hexCharToUInt(*in++, shift, accum); result != ParseResult::okay)
218 return Unexpected(result);
219 }
220 ret[i++] = accum;
221 }
222 return ret;
223 }
224
225 constexpr decltype(data_)
227 {
228 auto const result = parseFromStringView(sv);
229 if (!result)
230 {
231 if (result.error() == ParseResult::badLength)
232 Throw<std::invalid_argument>("invalid length for hex string");
233
234 Throw<std::range_error>("invalid hex character");
235 }
236 return *result;
237 }
238
239public:
240 constexpr base_uint() : data_{}
241 {
242 }
243
245 {
246 }
247
249 {
250 *this = b;
251 }
252
253 // This constructor is intended to be used at compile time since it might
254 // throw at runtime. Consider declaring this constructor consteval once
255 // we get to C++23.
256 explicit constexpr base_uint(std::string_view sv) noexcept(false) : data_(parseFromStringViewThrows(sv))
257 {
258 }
259
260 template <
261 class Container,
262 class = std::enable_if_t<
265 explicit base_uint(Container const& c)
266 {
267 XRPL_ASSERT(
268 c.size() * sizeof(typename Container::value_type) == size(),
269 "xrpl::base_uint::base_uint(Container auto) : input size match");
270 std::memcpy(data_.data(), c.data(), size());
271 }
272
273 template <class Container>
277 base_uint&>
278 operator=(Container const& c)
279 {
280 XRPL_ASSERT(
281 c.size() * sizeof(typename Container::value_type) == size(),
282 "xrpl::base_uint::operator=(Container auto) : input size match");
283 std::memcpy(data_.data(), c.data(), size());
284 return *this;
285 }
286
287 /* Construct from a raw pointer.
288 The buffer pointed to by `data` must be at least Bits/8 bytes.
289 */
290 static base_uint
291 fromVoid(void const* data)
292 {
293 return base_uint(data, VoidHelper());
294 }
295
296 template <class T>
298 fromVoidChecked(T const& from)
299 {
300 if (from.size() != size())
301 return {};
302 return fromVoid(from.data());
303 }
304
305 constexpr int
306 signum() const
307 {
308 for (int i = 0; i < WIDTH; i++)
309 if (data_[i] != 0)
310 return 1;
311
312 return 0;
313 }
314
315 bool
316 operator!() const
317 {
318 return *this == beast::zero;
319 }
320
321 constexpr base_uint
322 operator~() const
323 {
324 base_uint ret;
325
326 for (int i = 0; i < WIDTH; i++)
327 ret.data_[i] = ~data_[i];
328
329 return ret;
330 }
331
332 base_uint&
334 {
335 *this = beast::zero;
336 union
337 {
338 unsigned u[2];
339 std::uint64_t ul;
340 };
341 // Put in least significant bits.
342 ul = boost::endian::native_to_big(uHost);
343 data_[WIDTH - 2] = u[0];
344 data_[WIDTH - 1] = u[1];
345 return *this;
346 }
347
348 base_uint&
350 {
351 for (int i = 0; i < WIDTH; i++)
352 data_[i] ^= b.data_[i];
353
354 return *this;
355 }
356
357 base_uint&
359 {
360 for (int i = 0; i < WIDTH; i++)
361 data_[i] &= b.data_[i];
362
363 return *this;
364 }
365
366 base_uint&
368 {
369 for (int i = 0; i < WIDTH; i++)
370 data_[i] |= b.data_[i];
371
372 return *this;
373 }
374
375 base_uint&
377 {
378 // prefix operator
379 for (int i = WIDTH - 1; i >= 0; --i)
380 {
381 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
382 if (data_[i] != 0)
383 break;
384 }
385
386 return *this;
387 }
388
389 base_uint const
391 {
392 // postfix operator
393 base_uint const ret = *this;
394 ++(*this);
395
396 return ret;
397 }
398
399 base_uint&
401 {
402 for (int i = WIDTH - 1; i >= 0; --i)
403 {
404 auto prev = data_[i];
405 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
406
407 if (prev != 0)
408 break;
409 }
410
411 return *this;
412 }
413
414 base_uint const
416 {
417 // postfix operator
418 base_uint const ret = *this;
419 --(*this);
420
421 return ret;
422 }
423
425 next() const
426 {
427 auto ret = *this;
428 return ++ret;
429 }
430
432 prev() const
433 {
434 auto ret = *this;
435 return --ret;
436 }
437
438 base_uint&
440 {
441 std::uint64_t carry = 0;
442
443 for (int i = WIDTH; i--;)
444 {
445 std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) + boost::endian::big_to_native(b.data_[i]);
446
447 data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
448 carry = n >> 32;
449 }
450
451 return *this;
452 }
453
454 template <class Hasher>
455 friend void
456 hash_append(Hasher& h, base_uint const& a) noexcept
457 {
458 // Do not allow any endian transformations on this memory
459 h(a.data_.data(), sizeof(a.data_));
460 }
461
470 [[nodiscard]] constexpr bool
472 {
473 auto const result = parseFromStringView(sv);
474 if (!result)
475 return false;
476
477 data_ = *result;
478 return true;
479 }
480
481 [[nodiscard]] constexpr bool
482 parseHex(char const* str)
483 {
484 return parseHex(std::string_view{str});
485 }
486
487 [[nodiscard]] bool
489 {
490 return parseHex(std::string_view{str});
491 }
492
493 constexpr static std::size_t
495 {
496 return bytes;
497 }
498
501 {
502 data_.fill(0);
503 return *this;
504 }
505
506 // Deprecated.
507 bool
508 isZero() const
509 {
510 return *this == beast::zero;
511 }
512 bool
513 isNonZero() const
514 {
515 return *this != beast::zero;
516 }
517 void
519 {
520 *this = beast::zero;
521 }
522};
523
528
529template <std::size_t Bits, class Tag>
530[[nodiscard]] inline constexpr std::strong_ordering
532{
533 // This comparison might seem wrong on a casual inspection because it
534 // compares data internally stored as std::uint32_t byte-by-byte. But
535 // note that the underlying data is stored in big endian, even if the
536 // platform is little endian. This makes the comparison correct.
537 //
538 // FIXME: use std::lexicographical_compare_three_way once support is
539 // added to MacOS.
540
541 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
542
543 // a == b
544 if (ret.first == lhs.cend())
545 return std::strong_ordering::equivalent;
546
547 return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less;
548}
549
550template <std::size_t Bits, typename Tag>
551[[nodiscard]] inline constexpr bool
553{
554 return (lhs <=> rhs) == 0;
555}
556
557//------------------------------------------------------------------------------
558template <std::size_t Bits, class Tag>
559inline constexpr bool
561{
562 return a == base_uint<Bits, Tag>(b);
563}
564
565//------------------------------------------------------------------------------
566template <std::size_t Bits, class Tag>
567inline constexpr base_uint<Bits, Tag>
569{
570 return base_uint<Bits, Tag>(a) ^= b;
571}
572
573template <std::size_t Bits, class Tag>
574inline constexpr base_uint<Bits, Tag>
576{
577 return base_uint<Bits, Tag>(a) &= b;
578}
579
580template <std::size_t Bits, class Tag>
581inline constexpr base_uint<Bits, Tag>
583{
584 return base_uint<Bits, Tag>(a) |= b;
585}
586
587template <std::size_t Bits, class Tag>
588inline constexpr base_uint<Bits, Tag>
590{
591 return base_uint<Bits, Tag>(a) += b;
592}
593
594//------------------------------------------------------------------------------
595template <std::size_t Bits, class Tag>
596inline std::string
598{
599 return strHex(a.cbegin(), a.cend());
600}
601
602template <std::size_t Bits, class Tag>
603inline std::string
605{
606 static_assert(base_uint<Bits, Tag>::bytes > 4, "For 4 bytes or less, use a native type");
607 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
608}
609
610template <std::size_t Bits, class Tag>
613{
614 return out << to_string(u);
615}
616
617template <>
618inline std::size_t
619extract(uint256 const& key)
620{
621 std::size_t result;
622 // Use memcpy to avoid unaligned UB
623 // (will optimize to equivalent code)
624 std::memcpy(&result, key.data(), sizeof(std::size_t));
625 return result;
626}
627
628#ifndef __INTELLISENSE__
629static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
630static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
631static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
632static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
633#endif
634
635} // namespace xrpl
636
637namespace beast {
638
639template <std::size_t Bits, class Tag>
640struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>> : public std::true_type
641{
642 explicit is_uniquely_represented() = default;
643};
644
645} // namespace beast
T begin(T... args)
An immutable linear range of bytes.
Definition Slice.h:26
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:66
const_iterator cend() const
Definition base_uint.h:137
base_uint(std::uint64_t b)
Definition base_uint.h:248
static base_uint fromVoid(void const *data)
Definition base_uint.h:291
iterator begin()
Definition base_uint.h:112
value_type * pointer
Definition base_uint.h:90
base_uint(void const *data, VoidHelper)
Definition base_uint.h:163
const_iterator cbegin() const
Definition base_uint.h:132
base_uint & operator&=(base_uint const &b)
Definition base_uint.h:358
base_uint prev() const
Definition base_uint.h:432
base_uint & operator^=(base_uint const &b)
Definition base_uint.h:349
bool parseHex(std::string const &str)
Definition base_uint.h:488
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:226
base_uint & operator=(std::uint64_t uHost)
Definition base_uint.h:333
base_uint & operator++()
Definition base_uint.h:376
bool operator!() const
Definition base_uint.h:316
pointer iterator
Definition base_uint.h:94
base_uint & operator|=(base_uint const &b)
Definition base_uint.h:367
std::enable_if_t< detail::is_contiguous_container< Container >::value &&std::is_trivially_copyable< typename Container::value_type >::value, base_uint & > operator=(Container const &c)
Definition base_uint.h:278
constexpr base_uint(std::string_view sv) noexcept(false)
Definition base_uint.h:256
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:471
iterator end()
Definition base_uint.h:117
base_uint next() const
Definition base_uint.h:425
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition base_uint.h:298
unsigned char value_type
Definition base_uint.h:89
bool isZero() const
Definition base_uint.h:508
base_uint & operator--()
Definition base_uint.h:400
const_pointer data() const
Definition base_uint.h:106
constexpr base_uint()
Definition base_uint.h:240
const_pointer const_iterator
Definition base_uint.h:95
static constexpr std::size_t WIDTH
Definition base_uint.h:71
base_uint(Container const &c)
Definition base_uint.h:265
value_type const & const_reference
Definition base_uint.h:93
constexpr int signum() const
Definition base_uint.h:306
base_uint< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:500
base_uint & operator+=(base_uint const &b)
Definition base_uint.h:439
value_type & reference
Definition base_uint.h:91
constexpr bool parseHex(char const *str)
Definition base_uint.h:482
value_type const * const_pointer
Definition base_uint.h:92
constexpr base_uint operator~() const
Definition base_uint.h:322
constexpr Expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition base_uint.h:176
pointer data()
Definition base_uint.h:101
const_iterator begin() const
Definition base_uint.h:122
std::array< std::uint32_t, WIDTH > data_
Definition base_uint.h:76
constexpr base_uint(beast::Zero)
Definition base_uint.h:244
base_uint const operator++(int)
Definition base_uint.h:390
base_uint const operator--(int)
Definition base_uint.h:415
static std::size_t constexpr bytes
Definition base_uint.h:84
const_iterator end() const
Definition base_uint.h:127
static constexpr std::size_t size()
Definition base_uint.h:494
bool isNonZero() const
Definition base_uint.h:513
friend void hash_append(Hasher &h, base_uint const &a) noexcept
Definition base_uint.h:456
Seed functor once per construction.
T data(T... args)
T end(T... args)
T fill(T... args)
T memcpy(T... args)
T mismatch(T... args)
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::size_t extract(uint256 const &key)
Definition base_uint.h:619
base_uint< 192 > uint192
Definition base_uint.h:527
base_uint< 128 > uint128
Definition base_uint.h:524
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:589
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:597
constexpr base_uint< Bits, Tag > operator|(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:582
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:612
constexpr base_uint< Bits, Tag > operator^(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:568
constexpr base_uint< Bits, Tag > operator&(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:575
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:552
base_uint< 256 > uint256
Definition base_uint.h:526
constexpr std::strong_ordering operator<=>(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:531
base_uint< 160 > uint160
Definition base_uint.h:525
std::string to_short_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:604
T size(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
Construct from a raw pointer.
Definition base_uint.h:159