rippled
Loading...
Searching...
No Matches
base_uint.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20// Copyright (c) 2009-2010 Satoshi Nakamoto
21// Copyright (c) 2011 The Bitcoin developers
22// Distributed under the MIT/X11 software license, see the accompanying
23// file license.txt or http://www.opensource.org/licenses/mit-license.php.
24
25#ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED
26#define RIPPLE_BASICS_BASE_UINT_H_INCLUDED
27
28#include <xrpl/basics/Expected.h>
29#include <xrpl/basics/Slice.h>
30#include <xrpl/basics/contract.h>
31#include <xrpl/basics/hardened_hash.h>
32#include <xrpl/basics/partitioned_unordered_map.h>
33#include <xrpl/basics/strHex.h>
34#include <xrpl/beast/utility/Zero.h>
35#include <xrpl/beast/utility/instrumentation.h>
36#include <boost/endian/conversion.hpp>
37#include <boost/functional/hash.hpp>
38#include <algorithm>
39#include <array>
40#include <cstring>
41#include <functional>
42#include <type_traits>
43
44namespace ripple {
45
46namespace detail {
47
48template <class Container, class = std::void_t<>>
50{
51};
52
53template <class Container>
55 Container,
56 std::void_t<
57 decltype(std::declval<Container const>().size()),
58 decltype(std::declval<Container const>().data()),
59 typename Container::value_type>> : std::true_type
60{
61};
62
63template <>
65{
66};
67
68} // namespace detail
69
83template <std::size_t Bits, class Tag = void>
85{
86 static_assert(
87 (Bits % 32) == 0,
88 "The length of a base_uint in bits must be a multiple of 32.");
89
90 static_assert(
91 Bits >= 64,
92 "The length of a base_uint in bits must be at least 64.");
93
94 static constexpr std::size_t WIDTH = Bits / 32;
95
96 // This is really big-endian in byte order.
97 // We sometimes use std::uint32_t for speed.
98
100
101public:
102 //--------------------------------------------------------------------------
103 //
104 // STL Container Interface
105 //
106
107 static std::size_t constexpr bytes = Bits / 8;
108 static_assert(sizeof(data_) == bytes, "");
109
112 using value_type = unsigned char;
115 using const_pointer = value_type const*;
121 using tag_type = Tag;
122
123 pointer
125 {
126 return reinterpret_cast<pointer>(data_.data());
127 }
129 data() const
130 {
131 return reinterpret_cast<const_pointer>(data_.data());
132 }
133
136 {
137 return data();
138 }
141 {
142 return data() + bytes;
143 }
145 begin() const
146 {
147 return data();
148 }
150 end() const
151 {
152 return data() + bytes;
153 }
155 cbegin() const
156 {
157 return data();
158 }
160 cend() const
161 {
162 return data() + bytes;
163 }
164
170
171 //--------------------------------------------------------------------------
172
173private:
180 // NIKB TODO Remove the need for this constructor.
182 {
183 explicit VoidHelper() = default;
184 };
185
186 explicit base_uint(void const* data, VoidHelper)
187 {
188 memcpy(data_.data(), data, bytes);
189 }
190
191 // Helper function to initialize a base_uint from a std::string_view.
192 enum class ParseResult {
193 okay,
194 badLength,
195 badChar,
196 };
197
198 constexpr Expected<decltype(data_), ParseResult>
200 {
201 // Local lambda that converts a single hex char to four bits and
202 // ORs those bits into a uint32_t.
203 auto hexCharToUInt = [](char c,
204 std::uint32_t shift,
205 std::uint32_t& accum) -> ParseResult {
206 std::uint32_t nibble = 0xFFu;
207 if (c < '0' || c > 'f')
209
210 if (c >= 'a')
211 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
212 else if (c >= 'A')
213 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
214 else if (c <= '9')
215 nibble = static_cast<std::uint32_t>(c - '0');
216
217 if (nibble > 0xFu)
219
220 accum |= (nibble << shift);
221
222 return ParseResult::okay;
223 };
224
225 decltype(data_) ret{};
226
227 if (sv == "0")
228 {
229 return ret;
230 }
231
232 if (sv.size() != size() * 2)
234
235 std::size_t i = 0u;
236 auto in = sv.begin();
237 while (in != sv.end())
238 {
239 std::uint32_t accum = {};
240 for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
241 {
242 if (auto const result = hexCharToUInt(*in++, shift, accum);
243 result != ParseResult::okay)
244 return Unexpected(result);
245 }
246 ret[i++] = accum;
247 }
248 return ret;
249 }
250
251 constexpr decltype(data_)
253 {
254 auto const result = parseFromStringView(sv);
255 if (!result)
256 {
257 if (result.error() == ParseResult::badLength)
258 Throw<std::invalid_argument>("invalid length for hex string");
259
260 Throw<std::range_error>("invalid hex character");
261 }
262 return *result;
263 }
264
265public:
266 constexpr base_uint() : data_{}
267 {
268 }
269
271 {
272 }
273
275 {
276 *this = b;
277 }
278
279 // This constructor is intended to be used at compile time since it might
280 // throw at runtime. Consider declaring this constructor consteval once
281 // we get to C++23.
282 explicit constexpr base_uint(std::string_view sv) noexcept(false)
284 {
285 }
286
287 template <
288 class Container,
289 class = std::enable_if_t<
292 explicit base_uint(Container const& c)
293 {
294 XRPL_ASSERT(
295 c.size() * sizeof(typename Container::value_type) == size(),
296 "ripple::base_uint::base_uint(Container auto) : input size match");
297 std::memcpy(data_.data(), c.data(), size());
298 }
299
300 template <class Container>
304 base_uint&>
305 operator=(Container const& c)
306 {
307 XRPL_ASSERT(
308 c.size() * sizeof(typename Container::value_type) == size(),
309 "ripple::base_uint::operator=(Container auto) : input size match");
310 std::memcpy(data_.data(), c.data(), size());
311 return *this;
312 }
313
314 /* Construct from a raw pointer.
315 The buffer pointed to by `data` must be at least Bits/8 bytes.
316 */
317 static base_uint
318 fromVoid(void const* data)
319 {
320 return base_uint(data, VoidHelper());
321 }
322
323 template <class T>
325 fromVoidChecked(T const& from)
326 {
327 if (from.size() != size())
328 return {};
329 return fromVoid(from.data());
330 }
331
332 constexpr int
333 signum() const
334 {
335 for (int i = 0; i < WIDTH; i++)
336 if (data_[i] != 0)
337 return 1;
338
339 return 0;
340 }
341
342 bool
343 operator!() const
344 {
345 return *this == beast::zero;
346 }
347
348 constexpr base_uint
349 operator~() const
350 {
351 base_uint ret;
352
353 for (int i = 0; i < WIDTH; i++)
354 ret.data_[i] = ~data_[i];
355
356 return ret;
357 }
358
359 base_uint&
361 {
362 *this = beast::zero;
363 union
364 {
365 unsigned u[2];
366 std::uint64_t ul;
367 };
368 // Put in least significant bits.
369 ul = boost::endian::native_to_big(uHost);
370 data_[WIDTH - 2] = u[0];
371 data_[WIDTH - 1] = u[1];
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 for (int i = 0; i < WIDTH; i++)
388 data_[i] &= b.data_[i];
389
390 return *this;
391 }
392
393 base_uint&
395 {
396 for (int i = 0; i < WIDTH; i++)
397 data_[i] |= b.data_[i];
398
399 return *this;
400 }
401
402 base_uint&
404 {
405 // prefix operator
406 for (int i = WIDTH - 1; i >= 0; --i)
407 {
408 data_[i] = boost::endian::native_to_big(
409 boost::endian::big_to_native(data_[i]) + 1);
410 if (data_[i] != 0)
411 break;
412 }
413
414 return *this;
415 }
416
417 const base_uint
419 {
420 // postfix operator
421 const base_uint ret = *this;
422 ++(*this);
423
424 return ret;
425 }
426
427 base_uint&
429 {
430 for (int i = WIDTH - 1; i >= 0; --i)
431 {
432 auto prev = data_[i];
433 data_[i] = boost::endian::native_to_big(
434 boost::endian::big_to_native(data_[i]) - 1);
435
436 if (prev != 0)
437 break;
438 }
439
440 return *this;
441 }
442
443 const base_uint
445 {
446 // postfix operator
447 const base_uint ret = *this;
448 --(*this);
449
450 return ret;
451 }
452
454 next() const
455 {
456 auto ret = *this;
457 return ++ret;
458 }
459
461 prev() const
462 {
463 auto ret = *this;
464 return --ret;
465 }
466
467 base_uint&
469 {
470 std::uint64_t carry = 0;
471
472 for (int i = WIDTH; i--;)
473 {
474 std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
475 boost::endian::big_to_native(b.data_[i]);
476
477 data_[i] =
478 boost::endian::native_to_big(static_cast<std::uint32_t>(n));
479 carry = n >> 32;
480 }
481
482 return *this;
483 }
484
485 template <class Hasher>
486 friend void
487 hash_append(Hasher& h, base_uint const& a) noexcept
488 {
489 // Do not allow any endian transformations on this memory
490 h(a.data_.data(), sizeof(a.data_));
491 }
492
501 [[nodiscard]] constexpr bool
503 {
504 auto const result = parseFromStringView(sv);
505 if (!result)
506 return false;
507
508 data_ = *result;
509 return true;
510 }
511
512 [[nodiscard]] constexpr bool
513 parseHex(const char* str)
514 {
515 return parseHex(std::string_view{str});
516 }
517
518 [[nodiscard]] bool
520 {
521 return parseHex(std::string_view{str});
522 }
523
524 constexpr static std::size_t
526 {
527 return bytes;
528 }
529
532 {
533 data_.fill(0);
534 return *this;
535 }
536
537 // Deprecated.
538 bool
539 isZero() const
540 {
541 return *this == beast::zero;
542 }
543 bool
544 isNonZero() const
545 {
546 return *this != beast::zero;
547 }
548 void
550 {
551 *this = beast::zero;
552 }
553};
554
559
560template <std::size_t Bits, class Tag>
561[[nodiscard]] inline constexpr std::strong_ordering
563{
564 // This comparison might seem wrong on a casual inspection because it
565 // compares data internally stored as std::uint32_t byte-by-byte. But
566 // note that the underlying data is stored in big endian, even if the
567 // plaform is little endian. This makes the comparison correct.
568 //
569 // FIXME: use std::lexicographical_compare_three_way once support is
570 // added to MacOS.
571
572 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
573
574 // a == b
575 if (ret.first == lhs.cend())
576 return std::strong_ordering::equivalent;
577
578 return (*ret.first > *ret.second) ? std::strong_ordering::greater
579 : std::strong_ordering::less;
580}
581
582template <std::size_t Bits, typename Tag>
583[[nodiscard]] inline constexpr bool
585{
586 return (lhs <=> rhs) == 0;
587}
588
589//------------------------------------------------------------------------------
590template <std::size_t Bits, class Tag>
591inline constexpr bool
593{
594 return a == base_uint<Bits, Tag>(b);
595}
596
597//------------------------------------------------------------------------------
598template <std::size_t Bits, class Tag>
599inline constexpr base_uint<Bits, Tag>
601{
602 return base_uint<Bits, Tag>(a) ^= b;
603}
604
605template <std::size_t Bits, class Tag>
606inline constexpr base_uint<Bits, Tag>
608{
609 return base_uint<Bits, Tag>(a) &= b;
610}
611
612template <std::size_t Bits, class Tag>
613inline constexpr base_uint<Bits, Tag>
615{
616 return base_uint<Bits, Tag>(a) |= b;
617}
618
619template <std::size_t Bits, class Tag>
620inline constexpr base_uint<Bits, Tag>
622{
623 return base_uint<Bits, Tag>(a) += b;
624}
625
626//------------------------------------------------------------------------------
627template <std::size_t Bits, class Tag>
628inline std::string
630{
631 return strHex(a.cbegin(), a.cend());
632}
633
634template <std::size_t Bits, class Tag>
637{
638 return out << to_string(u);
639}
640
641template <>
642inline std::size_t
643extract(uint256 const& key)
644{
645 std::size_t result;
646 // Use memcpy to avoid unaligned UB
647 // (will optimize to equivalent code)
648 std::memcpy(&result, key.data(), sizeof(std::size_t));
649 return result;
650}
651
652#ifndef __INTELLISENSE__
653static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
654static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
655static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
656static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
657#endif
658
659} // namespace ripple
660
661namespace beast {
662
663template <std::size_t Bits, class Tag>
664struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
665 : public std::true_type
666{
667 explicit is_uniquely_represented() = default;
668};
669
670} // namespace beast
671
672#endif
T begin(T... args)
An immutable linear range of bytes.
Definition: Slice.h:45
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:85
base_uint next() const
Definition: base_uint.h:454
static std::size_t constexpr bytes
Definition: base_uint.h:107
base_uint & operator+=(const base_uint &b)
Definition: base_uint.h:468
const_pointer data() const
Definition: base_uint.h:129
bool operator!() const
Definition: base_uint.h:343
iterator begin()
Definition: base_uint.h:135
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition: base_uint.h:325
const base_uint operator--(int)
Definition: base_uint.h:444
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition: base_uint.h:252
static base_uint fromVoid(void const *data)
Definition: base_uint.h:318
const_pointer const_iterator
Definition: base_uint.h:118
const base_uint operator++(int)
Definition: base_uint.h:418
const_iterator cbegin() const
Definition: base_uint.h:155
pointer data()
Definition: base_uint.h:124
base_uint & operator|=(const base_uint &b)
Definition: base_uint.h:394
base_uint & operator--()
Definition: base_uint.h:428
bool parseHex(std::string const &str)
Definition: base_uint.h:519
constexpr base_uint(std::string_view sv) noexcept(false)
Definition: base_uint.h:282
static constexpr std::size_t size()
Definition: base_uint.h:525
constexpr base_uint operator~() const
Definition: base_uint.h:349
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:502
const_iterator end() const
Definition: base_uint.h:150
bool isZero() const
Definition: base_uint.h:539
const_iterator cend() const
Definition: base_uint.h:160
base_uint(Container const &c)
Definition: base_uint.h:292
constexpr bool parseHex(const char *str)
Definition: base_uint.h:513
constexpr int signum() const
Definition: base_uint.h:333
base_uint & operator^=(const base_uint &b)
Definition: base_uint.h:376
unsigned char value_type
Definition: base_uint.h:112
constexpr base_uint()
Definition: base_uint.h:266
base_uint & operator&=(const base_uint &b)
Definition: base_uint.h:385
value_type * pointer
Definition: base_uint.h:113
base_uint prev() const
Definition: base_uint.h:461
static constexpr std::size_t WIDTH
Definition: base_uint.h:94
value_type const & const_reference
Definition: base_uint.h:116
value_type const * const_pointer
Definition: base_uint.h:115
value_type & reference
Definition: base_uint.h:114
base_uint & operator=(std::uint64_t uHost)
Definition: base_uint.h:360
constexpr Expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition: base_uint.h:199
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:305
base_uint(std::uint64_t b)
Definition: base_uint.h:274
bool isNonZero() const
Definition: base_uint.h:544
const_iterator begin() const
Definition: base_uint.h:145
iterator end()
Definition: base_uint.h:140
base_uint(void const *data, VoidHelper)
Definition: base_uint.h:186
constexpr base_uint(beast::Zero)
Definition: base_uint.h:270
std::array< std::uint32_t, WIDTH > data_
Definition: base_uint.h:99
base_uint & operator++()
Definition: base_uint.h:403
pointer iterator
Definition: base_uint.h:117
friend void hash_append(Hasher &h, base_uint const &a) noexcept
Definition: base_uint.h:487
base_uint< Bits, Tag > & operator=(beast::Zero)
Definition: base_uint.h:531
Seed functor once per construction.
Definition: hardened_hash.h:97
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:26
constexpr base_uint< Bits, Tag > operator|(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:614
constexpr std::strong_ordering operator<=>(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition: base_uint.h:562
base_uint< 256 > uint256
Definition: base_uint.h:557
base_uint< 128 > uint128
Definition: base_uint.h:555
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition: base_uint.h:636
constexpr base_uint< Bits, Tag > operator&(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:607
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
base_uint< 192 > uint192
Definition: base_uint.h:558
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
constexpr base_uint< Bits, Tag > operator^(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:600
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:621
base_uint< 160 > uint160
Definition: base_uint.h:556
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition: base_uint.h:584
std::size_t extract(uint256 const &key)
Definition: base_uint.h:643
STL namespace.
T size(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition: Zero.h:43
Construct from a raw pointer.
Definition: base_uint.h:182