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 const shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
216 {
217 if (auto const result = hexCharToUInt(*in++, shift, accum);
218 result != ParseResult::okay)
219 return Unexpected(result);
220 }
221 ret[i++] = accum;
222 }
223 return ret;
224 }
225
226 constexpr decltype(data_)
228 {
229 auto const result = parseFromStringView(sv);
230 if (!result)
231 {
232 if (result.error() == ParseResult::badLength)
233 Throw<std::invalid_argument>("invalid length for hex string");
234
235 Throw<std::range_error>("invalid hex character");
236 }
237 return *result;
238 }
239
240public:
241 constexpr base_uint() : data_{}
242 {
243 }
244
246 {
247 }
248
250 {
251 *this = b;
252 }
253
254 // This constructor is intended to be used at compile time since it might
255 // throw at runtime. Consider declaring this constructor consteval once
256 // we get to C++23.
257 explicit constexpr base_uint(std::string_view sv) noexcept(false)
259 {
260 }
261
262 template <
263 class Container,
264 class = std::enable_if_t<
267 explicit base_uint(Container const& c)
268 {
269 XRPL_ASSERT(
270 c.size() * sizeof(typename Container::value_type) == size(),
271 "xrpl::base_uint::base_uint(Container auto) : input size match");
272 std::memcpy(data_.data(), c.data(), size());
273 }
274
275 template <class Container>
279 base_uint&>
280 operator=(Container const& c)
281 {
282 XRPL_ASSERT(
283 c.size() * sizeof(typename Container::value_type) == size(),
284 "xrpl::base_uint::operator=(Container auto) : input size match");
285 std::memcpy(data_.data(), c.data(), size());
286 return *this;
287 }
288
289 /* Construct from a raw pointer.
290 The buffer pointed to by `data` must be at least Bits/8 bytes.
291 */
292 static base_uint
293 fromVoid(void const* data)
294 {
295 return base_uint(data, VoidHelper());
296 }
297
298 template <class T>
300 fromVoidChecked(T const& from)
301 {
302 if (from.size() != size())
303 return {};
304 return fromVoid(from.data());
305 }
306
307 constexpr int
308 signum() const
309 {
310 for (int i = 0; i < WIDTH; i++)
311 if (data_[i] != 0)
312 return 1;
313
314 return 0;
315 }
316
317 bool
318 operator!() const
319 {
320 return *this == beast::zero;
321 }
322
323 constexpr base_uint
324 operator~() const
325 {
326 base_uint ret;
327
328 for (int i = 0; i < WIDTH; i++)
329 ret.data_[i] = ~data_[i];
330
331 return ret;
332 }
333
334 base_uint&
336 {
337 *this = beast::zero;
338 // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
339 union
340 {
341 unsigned u[2];
342 std::uint64_t ul;
343 };
344 // NOLINTEND(cppcoreguidelines-pro-type-member-init)
345 // Put in least significant bits.
346 ul = boost::endian::native_to_big(uHost);
347 data_[WIDTH - 2] = u[0];
348 data_[WIDTH - 1] = u[1];
349 return *this;
350 }
351
352 base_uint&
354 {
355 for (int i = 0; i < WIDTH; i++)
356 data_[i] ^= b.data_[i];
357
358 return *this;
359 }
360
361 base_uint&
363 {
364 for (int i = 0; i < WIDTH; i++)
365 data_[i] &= b.data_[i];
366
367 return *this;
368 }
369
370 base_uint&
372 {
373 for (int i = 0; i < WIDTH; i++)
374 data_[i] |= b.data_[i];
375
376 return *this;
377 }
378
379 base_uint&
381 {
382 // prefix operator
383 for (int i = WIDTH - 1; i >= 0; --i)
384 {
385 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
386 if (data_[i] != 0)
387 break;
388 }
389
390 return *this;
391 }
392
393 base_uint const
395 {
396 // postfix operator
397 base_uint const ret = *this;
398 ++(*this);
399
400 return ret;
401 }
402
403 base_uint&
405 {
406 for (int i = WIDTH - 1; i >= 0; --i)
407 {
408 auto prev = data_[i];
409 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
410
411 if (prev != 0)
412 break;
413 }
414
415 return *this;
416 }
417
418 base_uint const
420 {
421 // postfix operator
422 base_uint const ret = *this;
423 --(*this);
424
425 return ret;
426 }
427
429 next() const
430 {
431 auto ret = *this;
432 return ++ret;
433 }
434
436 prev() const
437 {
438 auto ret = *this;
439 return --ret;
440 }
441
442 base_uint&
444 {
445 std::uint64_t carry = 0;
446
447 for (int i = WIDTH; i--;)
448 {
449 std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
450 boost::endian::big_to_native(b.data_[i]);
451
452 data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
453 carry = n >> 32;
454 }
455
456 return *this;
457 }
458
459 template <class Hasher>
460 friend void
461 hash_append(Hasher& h, base_uint const& a) noexcept
462 {
463 // Do not allow any endian transformations on this memory
464 h(a.data_.data(), sizeof(a.data_));
465 }
466
475 [[nodiscard]] constexpr bool
477 {
478 auto const result = parseFromStringView(sv);
479 if (!result)
480 return false;
481
482 data_ = *result;
483 return true;
484 }
485
486 [[nodiscard]] constexpr bool
487 parseHex(char const* str)
488 {
489 return parseHex(std::string_view{str});
490 }
491
492 [[nodiscard]] bool
494 {
495 return parseHex(std::string_view{str});
496 }
497
498 constexpr static std::size_t
500 {
501 return bytes;
502 }
503
506 {
507 data_.fill(0);
508 return *this;
509 }
510
511 // Deprecated.
512 bool
513 isZero() const
514 {
515 return *this == beast::zero;
516 }
517 bool
518 isNonZero() const
519 {
520 return *this != beast::zero;
521 }
522 void
524 {
525 *this = beast::zero;
526 }
527};
528
533
534template <std::size_t Bits, class Tag>
535[[nodiscard]] inline constexpr std::strong_ordering
537{
538 // This comparison might seem wrong on a casual inspection because it
539 // compares data internally stored as std::uint32_t byte-by-byte. But
540 // note that the underlying data is stored in big endian, even if the
541 // platform is little endian. This makes the comparison correct.
542 //
543 // FIXME: use std::lexicographical_compare_three_way once support is
544 // added to MacOS.
545
546 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
547
548 // a == b
549 if (ret.first == lhs.cend())
550 return std::strong_ordering::equivalent;
551
552 return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less;
553}
554
555template <std::size_t Bits, typename Tag>
556[[nodiscard]] inline constexpr bool
558{
559 return (lhs <=> rhs) == 0;
560}
561
562//------------------------------------------------------------------------------
563template <std::size_t Bits, class Tag>
564inline constexpr bool
566{
567 return a == base_uint<Bits, Tag>(b);
568}
569
570//------------------------------------------------------------------------------
571template <std::size_t Bits, class Tag>
572inline constexpr base_uint<Bits, Tag>
574{
575 return base_uint<Bits, Tag>(a) ^= b;
576}
577
578template <std::size_t Bits, class Tag>
579inline constexpr base_uint<Bits, Tag>
581{
582 return base_uint<Bits, Tag>(a) &= b;
583}
584
585template <std::size_t Bits, class Tag>
586inline constexpr base_uint<Bits, Tag>
588{
589 return base_uint<Bits, Tag>(a) |= b;
590}
591
592template <std::size_t Bits, class Tag>
593inline constexpr base_uint<Bits, Tag>
595{
596 return base_uint<Bits, Tag>(a) += b;
597}
598
599//------------------------------------------------------------------------------
600template <std::size_t Bits, class Tag>
601inline std::string
603{
604 return strHex(a.cbegin(), a.cend());
605}
606
607template <std::size_t Bits, class Tag>
608inline std::string
610{
611 static_assert(base_uint<Bits, Tag>::bytes > 4, "For 4 bytes or less, use a native type");
612 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
613}
614
615template <std::size_t Bits, class Tag>
618{
619 return out << to_string(u);
620}
621
622template <>
623inline std::size_t
624extract(uint256 const& key)
625{
626 std::size_t result = 0;
627 // Use memcpy to avoid unaligned UB
628 // (will optimize to equivalent code)
629 std::memcpy(&result, key.data(), sizeof(std::size_t));
630 return result;
631}
632
633#ifndef __INTELLISENSE__
634static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
635static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
636static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
637static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
638#endif
639
640} // namespace xrpl
641
642namespace beast {
643
644template <std::size_t Bits, class Tag>
645struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>> : public std::true_type
646{
647 explicit is_uniquely_represented() = default;
648};
649
650} // 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:249
static base_uint fromVoid(void const *data)
Definition base_uint.h:293
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:362
base_uint prev() const
Definition base_uint.h:436
base_uint & operator^=(base_uint const &b)
Definition base_uint.h:353
bool parseHex(std::string const &str)
Definition base_uint.h:493
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:227
base_uint & operator=(std::uint64_t uHost)
Definition base_uint.h:335
base_uint & operator++()
Definition base_uint.h:380
bool operator!() const
Definition base_uint.h:318
pointer iterator
Definition base_uint.h:94
base_uint & operator|=(base_uint const &b)
Definition base_uint.h:371
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:280
constexpr base_uint(std::string_view sv) noexcept(false)
Definition base_uint.h:257
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:476
iterator end()
Definition base_uint.h:117
base_uint next() const
Definition base_uint.h:429
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition base_uint.h:300
unsigned char value_type
Definition base_uint.h:89
bool isZero() const
Definition base_uint.h:513
base_uint & operator--()
Definition base_uint.h:404
const_pointer data() const
Definition base_uint.h:106
constexpr base_uint()
Definition base_uint.h:241
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:267
value_type const & const_reference
Definition base_uint.h:93
constexpr int signum() const
Definition base_uint.h:308
base_uint< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:505
base_uint & operator+=(base_uint const &b)
Definition base_uint.h:443
value_type & reference
Definition base_uint.h:91
constexpr bool parseHex(char const *str)
Definition base_uint.h:487
value_type const * const_pointer
Definition base_uint.h:92
constexpr base_uint operator~() const
Definition base_uint.h:324
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:245
base_uint const operator++(int)
Definition base_uint.h:394
base_uint const operator--(int)
Definition base_uint.h:419
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:499
bool isNonZero() const
Definition base_uint.h:518
friend void hash_append(Hasher &h, base_uint const &a) noexcept
Definition base_uint.h:461
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:624
base_uint< 192 > uint192
Definition base_uint.h:532
base_uint< 128 > uint128
Definition base_uint.h:529
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:594
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
constexpr base_uint< Bits, Tag > operator|(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:587
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:617
constexpr base_uint< Bits, Tag > operator^(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:573
constexpr base_uint< Bits, Tag > operator&(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:580
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:557
base_uint< 256 > uint256
Definition base_uint.h:531
constexpr std::strong_ordering operator<=>(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:536
base_uint< 160 > uint160
Definition base_uint.h:530
std::string to_short_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:609
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