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<>>
51{
52};
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 <>
66{
67};
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>
638{
639 return out << to_string(u);
640}
641
642template <>
643inline std::size_t
644extract(uint256 const& key)
645{
646 std::size_t result;
647 // Use memcpy to avoid unaligned UB
648 // (will optimize to equivalent code)
649 std::memcpy(&result, key.data(), sizeof(std::size_t));
650 return result;
651}
652
653#ifndef __INTELLISENSE__
654static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
655static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
656static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
657static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
658#endif
659
660} // namespace ripple
661
662namespace beast {
663
664template <std::size_t Bits, class Tag>
665struct is_uniquely_represented<ripple::base_uint<Bits, Tag>>
666 : public std::true_type
667{
668 explicit is_uniquely_represented() = default;
669};
670
671} // namespace beast
672
673#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
pointer data()
Definition: base_uint.h:125
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
pointer iterator
Definition: base_uint.h:118
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.
Definition: hardened_hash.h:93
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
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:637
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:644
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