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#ifndef XRPL_BASICS_BASE_UINT_H_INCLUDED
7#define XRPL_BASICS_BASE_UINT_H_INCLUDED
8
9#include <xrpl/basics/Expected.h>
10#include <xrpl/basics/Slice.h>
11#include <xrpl/basics/contract.h>
12#include <xrpl/basics/hardened_hash.h>
13#include <xrpl/basics/partitioned_unordered_map.h>
14#include <xrpl/basics/strHex.h>
15#include <xrpl/beast/utility/Zero.h>
16#include <xrpl/beast/utility/instrumentation.h>
17
18#include <boost/endian/conversion.hpp>
19#include <boost/functional/hash.hpp>
20
21#include <algorithm>
22#include <array>
23#include <cstring>
24#include <type_traits>
25
26namespace ripple {
27
28namespace detail {
29
30template <class Container, class = std::void_t<>>
34
35template <class Container>
37 Container,
38 std::void_t<
39 decltype(std::declval<Container const>().size()),
40 decltype(std::declval<Container const>().data()),
41 typename Container::value_type>> : std::true_type
42{
43};
44
45template <>
49
50} // namespace detail
51
65template <std::size_t Bits, class Tag = void>
67{
68 static_assert(
69 (Bits % 32) == 0,
70 "The length of a base_uint in bits must be a multiple of 32.");
71
72 static_assert(
73 Bits >= 64,
74 "The length of a base_uint in bits must be at least 64.");
75
76 static constexpr std::size_t WIDTH = 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 std::size_t constexpr bytes = Bits / 8;
90 static_assert(sizeof(data_) == bytes, "");
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 }
111 data() const
112 {
113 return reinterpret_cast<const_pointer>(data_.data());
114 }
115
118 {
119 return data();
120 }
123 {
124 return data() + bytes;
125 }
127 begin() const
128 {
129 return data();
130 }
132 end() const
133 {
134 return data() + bytes;
135 }
137 cbegin() const
138 {
139 return data();
140 }
142 cend() const
143 {
144 return data() + bytes;
145 }
146
152
153 //--------------------------------------------------------------------------
154
155private:
162 // NIKB TODO Remove the need for this constructor.
164 {
165 explicit VoidHelper() = default;
166 };
167
168 explicit base_uint(void const* data, VoidHelper)
169 {
170 memcpy(data_.data(), data, bytes);
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 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,
186 std::uint32_t shift,
187 std::uint32_t& accum) -> ParseResult {
188 std::uint32_t nibble = 0xFFu;
189 if (c < '0' || c > 'f')
191
192 if (c >= 'a')
193 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
194 else if (c >= 'A')
195 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
196 else if (c <= '9')
197 nibble = static_cast<std::uint32_t>(c - '0');
198
199 if (nibble > 0xFu)
201
202 accum |= (nibble << shift);
203
204 return ParseResult::okay;
205 };
206
207 decltype(data_) ret{};
208
209 if (sv == "0")
210 {
211 return ret;
212 }
213
214 if (sv.size() != size() * 2)
216
217 std::size_t i = 0u;
218 auto in = sv.begin();
219 while (in != sv.end())
220 {
221 std::uint32_t accum = {};
222 for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
223 {
224 if (auto const result = hexCharToUInt(*in++, shift, accum);
225 result != ParseResult::okay)
226 return Unexpected(result);
227 }
228 ret[i++] = accum;
229 }
230 return ret;
231 }
232
233 constexpr decltype(data_)
235 {
236 auto const result = parseFromStringView(sv);
237 if (!result)
238 {
239 if (result.error() == ParseResult::badLength)
240 Throw<std::invalid_argument>("invalid length for hex string");
241
242 Throw<std::range_error>("invalid hex character");
243 }
244 return *result;
245 }
246
247public:
248 constexpr base_uint() : data_{}
249 {
250 }
251
253 {
254 }
255
257 {
258 *this = b;
259 }
260
261 // This constructor is intended to be used at compile time since it might
262 // throw at runtime. Consider declaring this constructor consteval once
263 // we get to C++23.
264 explicit constexpr base_uint(std::string_view sv) noexcept(false)
266 {
267 }
268
269 template <
270 class Container,
271 class = std::enable_if_t<
274 explicit base_uint(Container const& c)
275 {
276 XRPL_ASSERT(
277 c.size() * sizeof(typename Container::value_type) == size(),
278 "ripple::base_uint::base_uint(Container auto) : input size match");
279 std::memcpy(data_.data(), c.data(), size());
280 }
281
282 template <class Container>
286 base_uint&>
287 operator=(Container const& c)
288 {
289 XRPL_ASSERT(
290 c.size() * sizeof(typename Container::value_type) == size(),
291 "ripple::base_uint::operator=(Container auto) : input size match");
292 std::memcpy(data_.data(), c.data(), size());
293 return *this;
294 }
295
296 /* Construct from a raw pointer.
297 The buffer pointed to by `data` must be at least Bits/8 bytes.
298 */
299 static base_uint
300 fromVoid(void const* data)
301 {
302 return base_uint(data, VoidHelper());
303 }
304
305 template <class T>
307 fromVoidChecked(T const& from)
308 {
309 if (from.size() != size())
310 return {};
311 return fromVoid(from.data());
312 }
313
314 constexpr int
315 signum() const
316 {
317 for (int i = 0; i < WIDTH; i++)
318 if (data_[i] != 0)
319 return 1;
320
321 return 0;
322 }
323
324 bool
325 operator!() const
326 {
327 return *this == beast::zero;
328 }
329
330 constexpr base_uint
331 operator~() const
332 {
333 base_uint ret;
334
335 for (int i = 0; i < WIDTH; i++)
336 ret.data_[i] = ~data_[i];
337
338 return ret;
339 }
340
341 base_uint&
343 {
344 *this = beast::zero;
345 union
346 {
347 unsigned u[2];
348 std::uint64_t ul;
349 };
350 // Put in least significant bits.
351 ul = boost::endian::native_to_big(uHost);
352 data_[WIDTH - 2] = u[0];
353 data_[WIDTH - 1] = u[1];
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 for (int i = 0; i < WIDTH; i++)
379 data_[i] |= b.data_[i];
380
381 return *this;
382 }
383
384 base_uint&
386 {
387 // prefix operator
388 for (int i = WIDTH - 1; i >= 0; --i)
389 {
390 data_[i] = boost::endian::native_to_big(
391 boost::endian::big_to_native(data_[i]) + 1);
392 if (data_[i] != 0)
393 break;
394 }
395
396 return *this;
397 }
398
399 base_uint const
401 {
402 // postfix operator
403 base_uint const ret = *this;
404 ++(*this);
405
406 return ret;
407 }
408
409 base_uint&
411 {
412 for (int i = WIDTH - 1; i >= 0; --i)
413 {
414 auto prev = data_[i];
415 data_[i] = boost::endian::native_to_big(
416 boost::endian::big_to_native(data_[i]) - 1);
417
418 if (prev != 0)
419 break;
420 }
421
422 return *this;
423 }
424
425 base_uint const
427 {
428 // postfix operator
429 base_uint const ret = *this;
430 --(*this);
431
432 return ret;
433 }
434
436 next() const
437 {
438 auto ret = *this;
439 return ++ret;
440 }
441
443 prev() const
444 {
445 auto ret = *this;
446 return --ret;
447 }
448
449 base_uint&
451 {
452 std::uint64_t carry = 0;
453
454 for (int i = WIDTH; i--;)
455 {
456 std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
457 boost::endian::big_to_native(b.data_[i]);
458
459 data_[i] =
460 boost::endian::native_to_big(static_cast<std::uint32_t>(n));
461 carry = n >> 32;
462 }
463
464 return *this;
465 }
466
467 template <class Hasher>
468 friend void
469 hash_append(Hasher& h, base_uint const& a) noexcept
470 {
471 // Do not allow any endian transformations on this memory
472 h(a.data_.data(), sizeof(a.data_));
473 }
474
483 [[nodiscard]] constexpr bool
485 {
486 auto const result = parseFromStringView(sv);
487 if (!result)
488 return false;
489
490 data_ = *result;
491 return true;
492 }
493
494 [[nodiscard]] constexpr bool
495 parseHex(char const* str)
496 {
497 return parseHex(std::string_view{str});
498 }
499
500 [[nodiscard]] bool
502 {
503 return parseHex(std::string_view{str});
504 }
505
506 constexpr static std::size_t
508 {
509 return bytes;
510 }
511
514 {
515 data_.fill(0);
516 return *this;
517 }
518
519 // Deprecated.
520 bool
521 isZero() const
522 {
523 return *this == beast::zero;
524 }
525 bool
526 isNonZero() const
527 {
528 return *this != beast::zero;
529 }
530 void
532 {
533 *this = beast::zero;
534 }
535};
536
541
542template <std::size_t Bits, class Tag>
543[[nodiscard]] inline constexpr std::strong_ordering
545{
546 // This comparison might seem wrong on a casual inspection because it
547 // compares data internally stored as std::uint32_t byte-by-byte. But
548 // note that the underlying data is stored in big endian, even if the
549 // platform is little endian. This makes the comparison correct.
550 //
551 // FIXME: use std::lexicographical_compare_three_way once support is
552 // added to MacOS.
553
554 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
555
556 // a == b
557 if (ret.first == lhs.cend())
558 return std::strong_ordering::equivalent;
559
560 return (*ret.first > *ret.second) ? std::strong_ordering::greater
561 : std::strong_ordering::less;
562}
563
564template <std::size_t Bits, typename Tag>
565[[nodiscard]] inline constexpr bool
567{
568 return (lhs <=> rhs) == 0;
569}
570
571//------------------------------------------------------------------------------
572template <std::size_t Bits, class Tag>
573inline constexpr bool
575{
576 return a == base_uint<Bits, Tag>(b);
577}
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
594template <std::size_t Bits, class Tag>
595inline constexpr base_uint<Bits, Tag>
597{
598 return base_uint<Bits, Tag>(a) |= b;
599}
600
601template <std::size_t Bits, class Tag>
602inline constexpr base_uint<Bits, Tag>
604{
605 return base_uint<Bits, Tag>(a) += b;
606}
607
608//------------------------------------------------------------------------------
609template <std::size_t Bits, class Tag>
610inline std::string
612{
613 return strHex(a.cbegin(), a.cend());
614}
615
616template <std::size_t Bits, class Tag>
617inline std::string
619{
620 static_assert(
622 "For 4 bytes or less, use a native type");
623 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
624}
625
626template <std::size_t Bits, class Tag>
629{
630 return out << to_string(u);
631}
632
633template <>
634inline std::size_t
635extract(uint256 const& key)
636{
637 std::size_t result;
638 // Use memcpy to avoid unaligned UB
639 // (will optimize to equivalent code)
640 std::memcpy(&result, key.data(), sizeof(std::size_t));
641 return result;
642}
643
644#ifndef __INTELLISENSE__
645static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
646static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
647static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
648static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
649#endif
650
651} // namespace ripple
652
653namespace beast {
654
655template <std::size_t Bits, class Tag>
656struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
657 : public std::true_type
658{
659 explicit is_uniquely_represented() = default;
660};
661
662} // namespace beast
663
664#endif
T begin(T... args)
An immutable linear range of bytes.
Definition Slice.h:27
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:67
base_uint next() const
Definition base_uint.h:436
base_uint & operator^=(base_uint const &b)
Definition base_uint.h:358
constexpr bool parseHex(char const *str)
Definition base_uint.h:495
static std::size_t constexpr bytes
Definition base_uint.h:89
const_pointer data() const
Definition base_uint.h:111
bool operator!() const
Definition base_uint.h:325
iterator begin()
Definition base_uint.h:117
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition base_uint.h:307
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:234
static base_uint fromVoid(void const *data)
Definition base_uint.h:300
base_uint const operator--(int)
Definition base_uint.h:426
const_pointer const_iterator
Definition base_uint.h:100
const_iterator cbegin() const
Definition base_uint.h:137
base_uint & operator--()
Definition base_uint.h:410
bool parseHex(std::string const &str)
Definition base_uint.h:501
constexpr base_uint(std::string_view sv) noexcept(false)
Definition base_uint.h:264
static constexpr std::size_t size()
Definition base_uint.h:507
constexpr base_uint operator~() const
Definition base_uint.h:331
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:484
const_iterator end() const
Definition base_uint.h:132
bool isZero() const
Definition base_uint.h:521
const_iterator cend() const
Definition base_uint.h:142
base_uint(Container const &c)
Definition base_uint.h:274
base_uint & operator&=(base_uint const &b)
Definition base_uint.h:367
base_uint & operator+=(base_uint const &b)
Definition base_uint.h:450
constexpr int signum() const
Definition base_uint.h:315
base_uint & operator|=(base_uint const &b)
Definition base_uint.h:376
unsigned char value_type
Definition base_uint.h:94
constexpr base_uint()
Definition base_uint.h:248
value_type * pointer
Definition base_uint.h:95
base_uint prev() const
Definition base_uint.h:443
static constexpr std::size_t WIDTH
Definition base_uint.h:76
value_type const & const_reference
Definition base_uint.h:98
value_type const * const_pointer
Definition base_uint.h:97
value_type & reference
Definition base_uint.h:96
base_uint & operator=(std::uint64_t uHost)
Definition base_uint.h:342
constexpr Expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition base_uint.h:181
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:287
base_uint(std::uint64_t b)
Definition base_uint.h:256
bool isNonZero() const
Definition base_uint.h:526
const_iterator begin() const
Definition base_uint.h:127
iterator end()
Definition base_uint.h:122
base_uint(void const *data, VoidHelper)
Definition base_uint.h:168
constexpr base_uint(beast::Zero)
Definition base_uint.h:252
std::array< std::uint32_t, WIDTH > data_
Definition base_uint.h:81
base_uint const operator++(int)
Definition base_uint.h:400
base_uint & operator++()
Definition base_uint.h:385
friend void hash_append(Hasher &h, base_uint const &a) noexcept
Definition base_uint.h:469
base_uint< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:513
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)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string to_short_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:618
constexpr base_uint< Bits, Tag > operator|(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:596
constexpr std::strong_ordering operator<=>(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:544
base_uint< 256 > uint256
Definition base_uint.h:539
base_uint< 128 > uint128
Definition base_uint.h:537
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:628
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 strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
base_uint< 192 > uint192
Definition base_uint.h:540
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
constexpr base_uint< Bits, Tag > operator^(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:582
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:603
base_uint< 160 > uint160
Definition base_uint.h:538
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:566
std::size_t extract(uint256 const &key)
Definition base_uint.h:635
STL namespace.
T size(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:26
Construct from a raw pointer.
Definition base_uint.h:164