xrpld
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/Slice.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/basics/hardened_hash.h>
11#include <xrpl/basics/partitioned_unordered_map.h>
12#include <xrpl/basics/strHex.h>
13#include <xrpl/beast/utility/Zero.h>
14#include <xrpl/beast/utility/instrumentation.h>
15
16#include <boost/endian/conversion.hpp>
17#include <boost/functional/hash.hpp>
18
19#include <algorithm>
20#include <array>
21#include <cstring>
22#include <expected>
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
49template <typename...>
53
54} // namespace detail
55
69template <std::size_t Bits, class Tag = void>
71{
72 static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
73
74 static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
75
76 static constexpr std::size_t kWidth = Bits / 32;
77
78 // This is really big-endian in byte order.
79 // We sometimes use std::uint32_t for speed.
80
82
83public:
84 //--------------------------------------------------------------------------
85 //
86 // STL Container Interface
87 //
88
89 static constexpr std::size_t kBytes = Bits / 8;
90 static_assert(sizeof(data_) == kBytes, "");
91
94 using value_type = unsigned char;
97 using const_pointer = value_type const*;
103 using tag_type = Tag;
104
105 pointer
107 {
108 return reinterpret_cast<pointer>(data_.data());
109 }
110 [[nodiscard]] const_pointer
111 data() const
112 {
113 return reinterpret_cast<const_pointer>(data_.data());
114 }
115
116 iterator
118 {
119 return data();
120 }
121 iterator
123 {
124 return data() + kBytes;
125 }
126 [[nodiscard]] const_iterator
127 begin() const
128 {
129 return data();
130 }
131 [[nodiscard]] const_iterator
132 end() const
133 {
134 return data() + kBytes;
135 }
136 [[nodiscard]] const_iterator
137 cbegin() const
138 {
139 return data();
140 }
141 [[nodiscard]] const_iterator
142 cend() const
143 {
144 return data() + kBytes;
145 }
146
152
153 //--------------------------------------------------------------------------
154
155private:
162 // NIKB TODO Remove the need for this constructor.
164 {
165 explicit VoidHelper() = default;
166 };
167
168 explicit BaseUInt(void const* data, VoidHelper)
169 {
170 memcpy(data_.data(), data, kBytes);
171 }
172
173 // Helper function to initialize a base_uint from a std::string_view.
174 enum class ParseResult {
175 Okay,
176 BadLength,
177 BadChar,
178 };
179
180 constexpr std::expected<decltype(data_), ParseResult>
182 {
183 // Local lambda that converts a single hex char to four bits and
184 // ORs those bits into a uint32_t.
185 auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
186 std::uint32_t nibble = 0xFFu;
187 if (c < '0' || c > 'f')
188 return ParseResult::BadChar;
189
190 if (c >= 'a')
191 {
192 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
193 }
194 else if (c >= 'A')
195 {
196 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
197 }
198 else if (c <= '9')
199 {
200 nibble = static_cast<std::uint32_t>(c - '0');
201 }
202
203 if (nibble > 0xFu)
204 return ParseResult::BadChar;
205
206 accum |= (nibble << shift);
207
208 return ParseResult::Okay;
209 };
210
211 decltype(data_) ret{};
212
213 if (sv == "0")
214 {
215 return ret;
216 }
217
218 if (sv.size() != size() * 2)
219 return std::unexpected(ParseResult::BadLength);
220
221 std::size_t i = 0u;
222 auto in = sv.begin();
223 while (in != sv.end())
224 {
225 std::uint32_t accum = {};
226 for (std::uint32_t const shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
227 {
228 if (auto const result = hexCharToUInt(*in++, shift, accum);
229 result != ParseResult::Okay)
230 return std::unexpected(result);
231 }
232 ret[i++] = accum;
233 }
234 return ret;
235 }
236
237 constexpr decltype(data_)
239 {
240 auto const result = parseFromStringView(sv);
241 if (!result)
242 {
243 if (result.error() == ParseResult::BadLength)
244 Throw<std::invalid_argument>("invalid length for hex string");
245
246 Throw<std::range_error>("invalid hex character");
247 }
248 return *result;
249 }
250
251public:
252 constexpr BaseUInt() : data_{}
253 {
254 }
255
257 {
258 }
259
261 {
262 *this = b;
263 }
264
265 // This constructor is intended to be used at compile time since it might
266 // throw at runtime. Consider declaring this constructor consteval once
267 // we get to C++23.
268 explicit constexpr BaseUInt(std::string_view sv) noexcept(false)
270 {
271 }
272
273 template <
274 class Container,
275 class = std::enable_if_t<
278 explicit BaseUInt(Container const& c)
279 {
280 // Use AlwaysFalseT so the static_assert condition is dependent
281 // and only triggers when this constructor template is instantiated.
282 static_assert(
284 "This constructor is not intended to be used and will be soon removed. "
285 "Use base_uint::fromRaw instead.");
286 }
287
288 template <
289 class Container,
290 class = std::enable_if_t<
293 static BaseUInt
294 fromRaw(Container const& c)
295 {
296 BaseUInt result;
297 XRPL_ASSERT(
298 c.size() * sizeof(typename Container::value_type) == size(),
299 "xrpl::BaseUInt::fromRaw(Container auto) : input size match");
300 std::memcpy(result.data_.data(), c.data(), size());
301 return result;
302 }
303
304 template <class Container>
308 BaseUInt&>
309 operator=(Container const& c)
310 {
311 XRPL_ASSERT(
312 c.size() * sizeof(typename Container::value_type) == size(),
313 "xrpl::BaseUInt::operator=(Container auto) : input size match");
314 std::memcpy(data_.data(), c.data(), size());
315 return *this;
316 }
317
318 /* Construct from a raw pointer.
319 The buffer pointed to by `data` must be at least Bits/8 bytes.
320 */
321 static BaseUInt
322 fromVoid(void const* data)
323 {
324 return BaseUInt(data, VoidHelper());
325 }
326
327 template <class T>
329 fromVoidChecked(T const& from)
330 {
331 if (from.size() != size())
332 return {};
333 return fromVoid(from.data());
334 }
335
336 [[nodiscard]] constexpr int
337 signum() const
338 {
339 for (int i = 0; i < kWidth; i++)
340 {
341 if (data_[i] != 0)
342 return 1;
343 }
344
345 return 0;
346 }
347
348 bool
349 operator!() const
350 {
351 return *this == beast::kZero;
352 }
353
354 constexpr BaseUInt
355 operator~() const
356 {
357 BaseUInt ret;
358
359 for (int i = 0; i < kWidth; i++)
360 ret.data_[i] = ~data_[i];
361
362 return ret;
363 }
364
365 BaseUInt&
367 {
368 *this = beast::kZero;
369 // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
370 union
371 {
372 unsigned u[2];
373 std::uint64_t ul;
374 };
375 // NOLINTEND(cppcoreguidelines-pro-type-member-init)
376 // Put in least significant bits.
377 ul = boost::endian::native_to_big(uHost);
378 data_[kWidth - 2] = u[0];
379 data_[kWidth - 1] = u[1];
380 return *this;
381 }
382
383 BaseUInt&
385 {
386 for (int i = 0; i < kWidth; i++)
387 data_[i] ^= b.data_[i];
388
389 return *this;
390 }
391
392 BaseUInt&
394 {
395 for (int i = 0; i < kWidth; i++)
396 data_[i] &= b.data_[i];
397
398 return *this;
399 }
400
401 BaseUInt&
403 {
404 for (int i = 0; i < kWidth; i++)
405 data_[i] |= b.data_[i];
406
407 return *this;
408 }
409
410 BaseUInt&
412 {
413 // prefix operator
414 for (int i = kWidth - 1; i >= 0; --i)
415 {
416 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
417 if (data_[i] != 0)
418 break;
419 }
420
421 return *this;
422 }
423
426 {
427 // postfix operator
428 BaseUInt const ret = *this;
429 ++(*this);
430
431 return ret;
432 }
433
434 BaseUInt&
436 {
437 for (int i = kWidth - 1; i >= 0; --i)
438 {
439 auto prev = data_[i];
440 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
441
442 if (prev != 0)
443 break;
444 }
445
446 return *this;
447 }
448
451 {
452 // postfix operator
453 BaseUInt const ret = *this;
454 --(*this);
455
456 return ret;
457 }
458
459 [[nodiscard]] BaseUInt
460 next() const
461 {
462 auto ret = *this;
463 return ++ret;
464 }
465
466 [[nodiscard]] BaseUInt
467 prev() const
468 {
469 auto ret = *this;
470 return --ret;
471 }
472
473 BaseUInt&
475 {
476 std::uint64_t carry = 0;
477
478 for (int i = kWidth - 1; i >= 0; i--)
479 {
480 std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
481 boost::endian::big_to_native(b.data_[i]);
482
483 data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
484 carry = n >> 32;
485 }
486
487 return *this;
488 }
489
490 template <class Hasher>
491 friend void
492 hash_append(Hasher& h, BaseUInt const& a) noexcept
493 {
494 // Do not allow any endian transformations on this memory
495 h(a.data_.data(), sizeof(a.data_));
496 }
497
506 [[nodiscard]] constexpr bool
508 {
509 auto const result = parseFromStringView(sv);
510 if (!result)
511 return false;
512
513 data_ = *result;
514 return true;
515 }
516
517 [[nodiscard]] constexpr bool
518 parseHex(char const* str)
519 {
520 return parseHex(std::string_view{str});
521 }
522
523 [[nodiscard]] bool
525 {
526 return parseHex(std::string_view{str});
527 }
528
529 static constexpr std::size_t
531 {
532 return kBytes;
533 }
534
537 {
538 data_.fill(0);
539 return *this;
540 }
541
542 // Deprecated.
543 [[nodiscard]] bool
544 isZero() const
545 {
546 return *this == beast::kZero;
547 }
548 [[nodiscard]] bool
549 isNonZero() const
550 {
551 return *this != beast::kZero;
552 }
553 void
555 {
556 *this = beast::kZero;
557 }
558};
559
564
565template <std::size_t Bits, class Tag>
566[[nodiscard]] constexpr std::strong_ordering
568{
569 // This comparison might seem wrong on a casual inspection because it
570 // compares data internally stored as std::uint32_t byte-by-byte. But
571 // note that the underlying data is stored in big endian, even if the
572 // platform is little endian. This makes the comparison correct.
573 //
574 // FIXME: use std::lexicographical_compare_three_way once support is
575 // added to MacOS.
576
577 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
578
579 // a == b
580 if (ret.first == lhs.cend())
581 return std::strong_ordering::equivalent;
582
583 return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less;
584}
585
586template <std::size_t Bits, typename Tag>
587[[nodiscard]] constexpr bool
589{
590 return (lhs <=> rhs) == 0;
591}
592
593//------------------------------------------------------------------------------
594template <std::size_t Bits, class Tag>
595constexpr bool
597{
598 return a == BaseUInt<Bits, Tag>(b);
599}
600
601//------------------------------------------------------------------------------
602template <std::size_t Bits, class Tag>
603constexpr BaseUInt<Bits, Tag>
605{
606 return BaseUInt<Bits, Tag>(a) ^= b;
607}
608
609template <std::size_t Bits, class Tag>
610constexpr BaseUInt<Bits, Tag>
612{
613 return BaseUInt<Bits, Tag>(a) &= b;
614}
615
616template <std::size_t Bits, class Tag>
617constexpr BaseUInt<Bits, Tag>
619{
620 return BaseUInt<Bits, Tag>(a) |= b;
621}
622
623template <std::size_t Bits, class Tag>
624constexpr BaseUInt<Bits, Tag>
626{
627 return BaseUInt<Bits, Tag>(a) += b;
628}
629
630//------------------------------------------------------------------------------
631template <std::size_t Bits, class Tag>
632inline std::string
634{
635 return strHex(a.cbegin(), a.cend());
636}
637
638template <std::size_t Bits, class Tag>
639inline std::string
641{
642 static_assert(BaseUInt<Bits, Tag>::kBytes > 4, "For 4 bytes or less, use a native type");
643 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
644}
645
646template <std::size_t Bits, class Tag>
649{
650 return out << to_string(u);
651}
652
653template <>
654inline std::size_t
655extract(uint256 const& key)
656{
657 std::size_t result = 0;
658 // Use memcpy to avoid unaligned UB
659 // (will optimize to equivalent code)
660 std::memcpy(&result, key.data(), sizeof(std::size_t));
661 return result;
662}
663
664#ifndef __INTELLISENSE__
665static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
666static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
667static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
668static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
669#endif
670
671} // namespace xrpl
672
673namespace beast {
674
675template <std::size_t Bits, class Tag>
676struct IsUniquelyRepresented<xrpl::BaseUInt<Bits, Tag>> : public std::true_type
677{
678 explicit IsUniquelyRepresented() = default;
679};
680
681} // namespace beast
T begin(T... args)
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:71
std::size_t size_type
Definition base_uint.h:92
bool operator!() const
Definition base_uint.h:349
static BaseUInt fromRaw(Container const &c)
Definition base_uint.h:294
value_type * pointer
Definition base_uint.h:95
unsigned char value_type
Definition base_uint.h:94
std::reverse_iterator< iterator > reverse_iterator
Definition base_uint.h:101
BaseUInt operator++(int)
Definition base_uint.h:425
BaseUInt(std::uint64_t b)
Definition base_uint.h:260
std::ptrdiff_t difference_type
Definition base_uint.h:93
static BaseUInt fromVoid(void const *data)
Definition base_uint.h:322
const_iterator cend() const
Definition base_uint.h:142
BaseUInt & operator++()
Definition base_uint.h:411
constexpr BaseUInt(std::string_view sv) noexcept(false)
Definition base_uint.h:268
BaseUInt & operator&=(BaseUInt const &b)
Definition base_uint.h:393
bool parseHex(std::string const &str)
Definition base_uint.h:524
constexpr int signum() const
Definition base_uint.h:337
BaseUInt & operator+=(BaseUInt const &b)
Definition base_uint.h:474
constexpr bool parseHex(char const *str)
Definition base_uint.h:518
value_type const * const_pointer
Definition base_uint.h:97
const_iterator begin() const
Definition base_uint.h:127
bool isZero() const
Definition base_uint.h:544
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:238
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition base_uint.h:102
BaseUInt & operator--()
Definition base_uint.h:435
constexpr std::expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition base_uint.h:181
bool isNonZero() const
Definition base_uint.h:549
BaseUInt & operator|=(BaseUInt const &b)
Definition base_uint.h:402
const_pointer data() const
Definition base_uint.h:111
iterator end()
Definition base_uint.h:122
static constexpr std::size_t kWidth
Definition base_uint.h:76
value_type & reference
Definition base_uint.h:96
BaseUInt< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:536
std::array< std::uint32_t, kWidth > data_
Definition base_uint.h:81
pointer data()
Definition base_uint.h:106
constexpr BaseUInt(beast::Zero)
Definition base_uint.h:256
HardenedHash<> hasher
Value hashing function.
Definition base_uint.h:151
BaseUInt(void const *data, VoidHelper)
Definition base_uint.h:168
friend void hash_append(Hasher &h, BaseUInt const &a) noexcept
Definition base_uint.h:492
const_pointer const_iterator
Definition base_uint.h:100
BaseUInt next() const
Definition base_uint.h:460
BaseUInt & operator^=(BaseUInt const &b)
Definition base_uint.h:384
constexpr BaseUInt()
Definition base_uint.h:252
std::enable_if_t< detail::IsContiguousContainer< Container >::value &&std::is_trivially_copyable_v< typename Container::value_type >, BaseUInt & > operator=(Container const &c)
Definition base_uint.h:309
constexpr BaseUInt operator~() const
Definition base_uint.h:355
static constexpr std::size_t kBytes
Definition base_uint.h:89
static std::optional< BaseUInt > fromVoidChecked(T const &from)
Definition base_uint.h:329
const_iterator end() const
Definition base_uint.h:132
BaseUInt & operator=(std::uint64_t uHost)
Definition base_uint.h:366
iterator begin()
Definition base_uint.h:117
static constexpr std::size_t size()
Definition base_uint.h:530
BaseUInt operator--(int)
Definition base_uint.h:450
value_type const & const_reference
Definition base_uint.h:98
BaseUInt(Container const &c)
Definition base_uint.h:278
BaseUInt prev() const
Definition base_uint.h:467
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
const_iterator cbegin() const
Definition base_uint.h:137
pointer iterator
Definition base_uint.h:99
Seed functor once per construction.
An immutable linear range of bytes.
Definition Slice.h:26
T data(T... args)
T end(T... args)
T is_trivially_copyable_v
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
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:625
constexpr BaseUInt< Bits, Tag > operator^(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:604
std::size_t extract(uint256 const &key)
Definition base_uint.h:655
BaseUInt< 192 > uint192
Definition base_uint.h:563
constexpr BaseUInt< Bits, Tag > operator&(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:611
constexpr bool operator==(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
Definition base_uint.h:588
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
constexpr BaseUInt< Bits, Tag > operator|(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:618
BaseUInt< 128 > uint128
Definition base_uint.h:560
std::ostream & operator<<(std::ostream &out, BaseUInt< Bits, Tag > const &u)
Definition base_uint.h:648
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
Dir::ConstIterator const_iterator
Definition Dir.cpp:16
std::string toShortString(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:640
constexpr std::strong_ordering operator<=>(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
Definition base_uint.h:567
BaseUInt< 160 > uint160
Definition base_uint.h:561
BaseUInt< 256 > uint256
Definition base_uint.h:562
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
T size(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:25
T unexpected(T... args)