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
37#include <boost/endian/conversion.hpp>
38#include <boost/functional/hash.hpp>
39
40#include <algorithm>
41#include <array>
42#include <cstring>
43#include <type_traits>
44
45namespace ripple {
46
47namespace detail {
48
49template <class Container, class = std::void_t<>>
53
54template <class Container>
56 Container,
57 std::void_t<
58 decltype(std::declval<Container const>().size()),
59 decltype(std::declval<Container const>().data()),
60 typename Container::value_type>> : std::true_type
61{
62};
63
64template <>
68
69} // namespace detail
70
84template <std::size_t Bits, class Tag = void>
86{
87 static_assert(
88 (Bits % 32) == 0,
89 "The length of a base_uint in bits must be a multiple of 32.");
90
91 static_assert(
92 Bits >= 64,
93 "The length of a base_uint in bits must be at least 64.");
94
95 static constexpr std::size_t WIDTH = Bits / 32;
96
97 // This is really big-endian in byte order.
98 // We sometimes use std::uint32_t for speed.
99
101
102public:
103 //--------------------------------------------------------------------------
104 //
105 // STL Container Interface
106 //
107
108 static std::size_t constexpr bytes = Bits / 8;
109 static_assert(sizeof(data_) == bytes, "");
110
113 using value_type = unsigned char;
116 using const_pointer = value_type const*;
122 using tag_type = Tag;
123
124 pointer
126 {
127 return reinterpret_cast<pointer>(data_.data());
128 }
130 data() const
131 {
132 return reinterpret_cast<const_pointer>(data_.data());
133 }
134
137 {
138 return data();
139 }
142 {
143 return data() + bytes;
144 }
146 begin() const
147 {
148 return data();
149 }
151 end() const
152 {
153 return data() + bytes;
154 }
156 cbegin() const
157 {
158 return data();
159 }
161 cend() const
162 {
163 return data() + bytes;
164 }
165
171
172 //--------------------------------------------------------------------------
173
174private:
181 // NIKB TODO Remove the need for this constructor.
183 {
184 explicit VoidHelper() = default;
185 };
186
187 explicit base_uint(void const* data, VoidHelper)
188 {
189 memcpy(data_.data(), data, bytes);
190 }
191
192 // Helper function to initialize a base_uint from a std::string_view.
193 enum class ParseResult {
194 okay,
195 badLength,
196 badChar,
197 };
198
199 constexpr Expected<decltype(data_), ParseResult>
201 {
202 // Local lambda that converts a single hex char to four bits and
203 // ORs those bits into a uint32_t.
204 auto hexCharToUInt = [](char c,
205 std::uint32_t shift,
206 std::uint32_t& accum) -> ParseResult {
207 std::uint32_t nibble = 0xFFu;
208 if (c < '0' || c > 'f')
210
211 if (c >= 'a')
212 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
213 else if (c >= 'A')
214 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
215 else if (c <= '9')
216 nibble = static_cast<std::uint32_t>(c - '0');
217
218 if (nibble > 0xFu)
220
221 accum |= (nibble << shift);
222
223 return ParseResult::okay;
224 };
225
226 decltype(data_) ret{};
227
228 if (sv == "0")
229 {
230 return ret;
231 }
232
233 if (sv.size() != size() * 2)
235
236 std::size_t i = 0u;
237 auto in = sv.begin();
238 while (in != sv.end())
239 {
240 std::uint32_t accum = {};
241 for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
242 {
243 if (auto const result = hexCharToUInt(*in++, shift, accum);
244 result != ParseResult::okay)
245 return Unexpected(result);
246 }
247 ret[i++] = accum;
248 }
249 return ret;
250 }
251
252 constexpr decltype(data_)
254 {
255 auto const result = parseFromStringView(sv);
256 if (!result)
257 {
258 if (result.error() == ParseResult::badLength)
259 Throw<std::invalid_argument>("invalid length for hex string");
260
261 Throw<std::range_error>("invalid hex character");
262 }
263 return *result;
264 }
265
266public:
267 constexpr base_uint() : data_{}
268 {
269 }
270
272 {
273 }
274
276 {
277 *this = b;
278 }
279
280 // This constructor is intended to be used at compile time since it might
281 // throw at runtime. Consider declaring this constructor consteval once
282 // we get to C++23.
283 explicit constexpr base_uint(std::string_view sv) noexcept(false)
285 {
286 }
287
288 template <
289 class Container,
290 class = std::enable_if_t<
293 explicit base_uint(Container const& c)
294 {
295 XRPL_ASSERT(
296 c.size() * sizeof(typename Container::value_type) == size(),
297 "ripple::base_uint::base_uint(Container auto) : input size match");
298 std::memcpy(data_.data(), c.data(), size());
299 }
300
301 template <class Container>
305 base_uint&>
306 operator=(Container const& c)
307 {
308 XRPL_ASSERT(
309 c.size() * sizeof(typename Container::value_type) == size(),
310 "ripple::base_uint::operator=(Container auto) : input size match");
311 std::memcpy(data_.data(), c.data(), size());
312 return *this;
313 }
314
315 /* Construct from a raw pointer.
316 The buffer pointed to by `data` must be at least Bits/8 bytes.
317 */
318 static base_uint
319 fromVoid(void const* data)
320 {
321 return base_uint(data, VoidHelper());
322 }
323
324 template <class T>
326 fromVoidChecked(T const& from)
327 {
328 if (from.size() != size())
329 return {};
330 return fromVoid(from.data());
331 }
332
333 constexpr int
334 signum() const
335 {
336 for (int i = 0; i < WIDTH; i++)
337 if (data_[i] != 0)
338 return 1;
339
340 return 0;
341 }
342
343 bool
344 operator!() const
345 {
346 return *this == beast::zero;
347 }
348
349 constexpr base_uint
350 operator~() const
351 {
352 base_uint ret;
353
354 for (int i = 0; i < WIDTH; i++)
355 ret.data_[i] = ~data_[i];
356
357 return ret;
358 }
359
360 base_uint&
362 {
363 *this = beast::zero;
364 union
365 {
366 unsigned u[2];
367 std::uint64_t ul;
368 };
369 // Put in least significant bits.
370 ul = boost::endian::native_to_big(uHost);
371 data_[WIDTH - 2] = u[0];
372 data_[WIDTH - 1] = u[1];
373 return *this;
374 }
375
376 base_uint&
378 {
379 for (int i = 0; i < WIDTH; i++)
380 data_[i] ^= b.data_[i];
381
382 return *this;
383 }
384
385 base_uint&
387 {
388 for (int i = 0; i < WIDTH; i++)
389 data_[i] &= b.data_[i];
390
391 return *this;
392 }
393
394 base_uint&
396 {
397 for (int i = 0; i < WIDTH; i++)
398 data_[i] |= b.data_[i];
399
400 return *this;
401 }
402
403 base_uint&
405 {
406 // prefix operator
407 for (int i = WIDTH - 1; i >= 0; --i)
408 {
409 data_[i] = boost::endian::native_to_big(
410 boost::endian::big_to_native(data_[i]) + 1);
411 if (data_[i] != 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
428 base_uint&
430 {
431 for (int i = WIDTH - 1; i >= 0; --i)
432 {
433 auto prev = data_[i];
434 data_[i] = boost::endian::native_to_big(
435 boost::endian::big_to_native(data_[i]) - 1);
436
437 if (prev != 0)
438 break;
439 }
440
441 return *this;
442 }
443
444 base_uint const
446 {
447 // postfix operator
448 base_uint const ret = *this;
449 --(*this);
450
451 return ret;
452 }
453
455 next() const
456 {
457 auto ret = *this;
458 return ++ret;
459 }
460
462 prev() const
463 {
464 auto ret = *this;
465 return --ret;
466 }
467
468 base_uint&
470 {
471 std::uint64_t carry = 0;
472
473 for (int i = WIDTH; i--;)
474 {
475 std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
476 boost::endian::big_to_native(b.data_[i]);
477
478 data_[i] =
479 boost::endian::native_to_big(static_cast<std::uint32_t>(n));
480 carry = n >> 32;
481 }
482
483 return *this;
484 }
485
486 template <class Hasher>
487 friend void
488 hash_append(Hasher& h, base_uint const& a) noexcept
489 {
490 // Do not allow any endian transformations on this memory
491 h(a.data_.data(), sizeof(a.data_));
492 }
493
502 [[nodiscard]] constexpr bool
504 {
505 auto const result = parseFromStringView(sv);
506 if (!result)
507 return false;
508
509 data_ = *result;
510 return true;
511 }
512
513 [[nodiscard]] constexpr bool
514 parseHex(char const* str)
515 {
516 return parseHex(std::string_view{str});
517 }
518
519 [[nodiscard]] bool
521 {
522 return parseHex(std::string_view{str});
523 }
524
525 constexpr static std::size_t
527 {
528 return bytes;
529 }
530
533 {
534 data_.fill(0);
535 return *this;
536 }
537
538 // Deprecated.
539 bool
540 isZero() const
541 {
542 return *this == beast::zero;
543 }
544 bool
545 isNonZero() const
546 {
547 return *this != beast::zero;
548 }
549 void
551 {
552 *this = beast::zero;
553 }
554};
555
560
561template <std::size_t Bits, class Tag>
562[[nodiscard]] inline constexpr std::strong_ordering
564{
565 // This comparison might seem wrong on a casual inspection because it
566 // compares data internally stored as std::uint32_t byte-by-byte. But
567 // note that the underlying data is stored in big endian, even if the
568 // plaform is little endian. This makes the comparison correct.
569 //
570 // FIXME: use std::lexicographical_compare_three_way once support is
571 // added to MacOS.
572
573 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
574
575 // a == b
576 if (ret.first == lhs.cend())
577 return std::strong_ordering::equivalent;
578
579 return (*ret.first > *ret.second) ? std::strong_ordering::greater
580 : std::strong_ordering::less;
581}
582
583template <std::size_t Bits, typename Tag>
584[[nodiscard]] inline constexpr bool
586{
587 return (lhs <=> rhs) == 0;
588}
589
590//------------------------------------------------------------------------------
591template <std::size_t Bits, class Tag>
592inline constexpr bool
594{
595 return a == base_uint<Bits, Tag>(b);
596}
597
598//------------------------------------------------------------------------------
599template <std::size_t Bits, class Tag>
600inline constexpr base_uint<Bits, Tag>
602{
603 return base_uint<Bits, Tag>(a) ^= b;
604}
605
606template <std::size_t Bits, class Tag>
607inline constexpr base_uint<Bits, Tag>
609{
610 return base_uint<Bits, Tag>(a) &= b;
611}
612
613template <std::size_t Bits, class Tag>
614inline constexpr base_uint<Bits, Tag>
616{
617 return base_uint<Bits, Tag>(a) |= b;
618}
619
620template <std::size_t Bits, class Tag>
621inline constexpr base_uint<Bits, Tag>
623{
624 return base_uint<Bits, Tag>(a) += b;
625}
626
627//------------------------------------------------------------------------------
628template <std::size_t Bits, class Tag>
629inline std::string
631{
632 return strHex(a.cbegin(), a.cend());
633}
634
635template <std::size_t Bits, class Tag>
636inline std::string
638{
639 static_assert(
641 "For 4 bytes or less, use a native type");
642 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
643}
644
645template <std::size_t Bits, class Tag>
648{
649 return out << to_string(u);
650}
651
652template <>
653inline std::size_t
654extract(uint256 const& key)
655{
656 std::size_t result;
657 // Use memcpy to avoid unaligned UB
658 // (will optimize to equivalent code)
659 std::memcpy(&result, key.data(), sizeof(std::size_t));
660 return result;
661}
662
663#ifndef __INTELLISENSE__
664static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
665static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
666static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
667static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
668#endif
669
670} // namespace ripple
671
672namespace beast {
673
674template <std::size_t Bits, class Tag>
675struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
676 : public std::true_type
677{
678 explicit is_uniquely_represented() = default;
679};
680
681} // namespace beast
682
683#endif
T begin(T... args)
An immutable linear range of bytes.
Definition Slice.h:46
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:86
base_uint next() const
Definition base_uint.h:455
base_uint & operator^=(base_uint const &b)
Definition base_uint.h:377
constexpr bool parseHex(char const *str)
Definition base_uint.h:514
static std::size_t constexpr bytes
Definition base_uint.h:108
const_pointer data() const
Definition base_uint.h:130
bool operator!() const
Definition base_uint.h:344
iterator begin()
Definition base_uint.h:136
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition base_uint.h:326
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:253
static base_uint fromVoid(void const *data)
Definition base_uint.h:319
base_uint const operator--(int)
Definition base_uint.h:445
const_pointer const_iterator
Definition base_uint.h:119
const_iterator cbegin() const
Definition base_uint.h:156
base_uint & operator--()
Definition base_uint.h:429
bool parseHex(std::string const &str)
Definition base_uint.h:520
constexpr base_uint(std::string_view sv) noexcept(false)
Definition base_uint.h:283
static constexpr std::size_t size()
Definition base_uint.h:526
constexpr base_uint operator~() const
Definition base_uint.h:350
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
const_iterator end() const
Definition base_uint.h:151
bool isZero() const
Definition base_uint.h:540
const_iterator cend() const
Definition base_uint.h:161
base_uint(Container const &c)
Definition base_uint.h:293
base_uint & operator&=(base_uint const &b)
Definition base_uint.h:386
base_uint & operator+=(base_uint const &b)
Definition base_uint.h:469
constexpr int signum() const
Definition base_uint.h:334
base_uint & operator|=(base_uint const &b)
Definition base_uint.h:395
unsigned char value_type
Definition base_uint.h:113
constexpr base_uint()
Definition base_uint.h:267
value_type * pointer
Definition base_uint.h:114
base_uint prev() const
Definition base_uint.h:462
static constexpr std::size_t WIDTH
Definition base_uint.h:95
value_type const & const_reference
Definition base_uint.h:117
value_type const * const_pointer
Definition base_uint.h:116
value_type & reference
Definition base_uint.h:115
base_uint & operator=(std::uint64_t uHost)
Definition base_uint.h:361
constexpr Expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition base_uint.h:200
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:306
base_uint(std::uint64_t b)
Definition base_uint.h:275
bool isNonZero() const
Definition base_uint.h:545
const_iterator begin() const
Definition base_uint.h:146
iterator end()
Definition base_uint.h:141
base_uint(void const *data, VoidHelper)
Definition base_uint.h:187
constexpr base_uint(beast::Zero)
Definition base_uint.h:271
std::array< std::uint32_t, WIDTH > data_
Definition base_uint.h:100
base_uint const operator++(int)
Definition base_uint.h:419
base_uint & operator++()
Definition base_uint.h:404
friend void hash_append(Hasher &h, base_uint const &a) noexcept
Definition base_uint.h:488
base_uint< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:532
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:25
std::string to_short_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:637
constexpr base_uint< Bits, Tag > operator|(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:615
constexpr std::strong_ordering operator<=>(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:563
base_uint< 256 > uint256
Definition base_uint.h:558
base_uint< 128 > uint128
Definition base_uint.h:556
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:647
constexpr base_uint< Bits, Tag > operator&(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:608
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:30
base_uint< 192 > uint192
Definition base_uint.h:559
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:630
constexpr base_uint< Bits, Tag > operator^(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:601
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition base_uint.h:622
base_uint< 160 > uint160
Definition base_uint.h:557
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
Definition base_uint.h:585
std::size_t extract(uint256 const &key)
Definition base_uint.h:654
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:183