uint256.h raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-present The Limenka developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #ifndef LIMENKA_UINT256_H
   7  #define LIMENKA_UINT256_H
   8  
   9  #include <crypto/common.h>
  10  #include <span.h>
  11  #include <util/strencodings.h>
  12  #include <util/string.h>
  13  
  14  #include <algorithm>
  15  #include <array>
  16  #include <cassert>
  17  #include <cstdint>
  18  #include <cstring>
  19  #include <optional>
  20  #include <string>
  21  #include <string_view>
  22  
  23  /** Template base class for fixed-sized opaque blobs. */
  24  template<unsigned int BITS>
  25  class base_blob
  26  {
  27  protected:
  28      static constexpr int WIDTH = BITS / 8;
  29      static_assert(BITS % 8 == 0, "base_blob currently only supports whole bytes.");
  30      std::array<uint8_t, WIDTH> m_data;
  31      static_assert(WIDTH == sizeof(m_data), "Sanity check");
  32  
  33  public:
  34      /* construct 0 value by default */
  35      constexpr base_blob() : m_data() {}
  36  
  37      /* constructor for constants between 1 and 255 */
  38      constexpr explicit base_blob(uint8_t v) : m_data{v} {}
  39  
  40      constexpr explicit base_blob(Span<const unsigned char> vch)
  41      {
  42          assert(vch.size() == WIDTH);
  43          std::copy(vch.begin(), vch.end(), m_data.begin());
  44      }
  45  
  46      consteval explicit base_blob(std::string_view hex_str);
  47  
  48      constexpr bool IsNull() const
  49      {
  50          return std::all_of(m_data.begin(), m_data.end(), [](uint8_t val) {
  51              return val == 0;
  52          });
  53      }
  54  
  55      constexpr void SetNull()
  56      {
  57          std::fill(m_data.begin(), m_data.end(), 0);
  58      }
  59  
  60      /** Lexicographic ordering
  61       * @note Does NOT match the ordering on the corresponding \ref
  62       *       base_uint::CompareTo, which starts comparing from the end.
  63       */
  64      constexpr int Compare(const base_blob& other) const { return std::memcmp(m_data.data(), other.m_data.data(), WIDTH); }
  65  
  66      friend constexpr bool operator==(const base_blob& a, const base_blob& b) { return a.Compare(b) == 0; }
  67      friend constexpr bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; }
  68      friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; }
  69  
  70      /** @name Hex representation
  71       *
  72       * The hex representation used by GetHex(), ToString(), FromHex() and
  73       * SetHexDeprecated() is unusual, since it shows bytes of the base_blob in
  74       * reverse order. For example, a 4-byte blob {0x12, 0x34, 0x56, 0x78} is
  75       * represented as "78563412" instead of the more typical "12345678"
  76       * representation that would be shown in a hex editor or used by typical
  77       * byte-array / hex conversion functions like python's bytes.hex() and
  78       * bytes.fromhex().
  79       *
  80       * The nice thing about the reverse-byte representation, even though it is
  81       * unusual, is that if a blob contains an arithmetic number in little endian
  82       * format (with least significant bytes first, and most significant bytes
  83       * last), the GetHex() output will match the way the number would normally
  84       * be written in base-16 (with most significant digits first and least
  85       * significant digits last).
  86       *
  87       * This means, for example, that ArithToUint256(num).GetHex() can be used to
  88       * display an arith_uint256 num value as a number, because
  89       * ArithToUint256() converts the number to a blob in little-endian format,
  90       * so the arith_uint256 class doesn't need to have its own number parsing
  91       * and formatting functions.
  92       *
  93       * @{*/
  94      std::string GetHex() const;
  95      /** Unlike FromHex this accepts any invalid input, thus it is fragile and deprecated!
  96       *
  97       * - Hex numbers that don't specify enough bytes to fill the internal array
  98       *   will be treated as setting the beginning of it, which corresponds to
  99       *   the least significant bytes when converted to base_uint.
 100       *
 101       * - Hex numbers specifying too many bytes will have the numerically most
 102       *   significant bytes (the beginning of the string) narrowed away.
 103       *
 104       * - An odd count of hex digits will result in the high bits of the leftmost
 105       *   byte being zero.
 106       *   "0x123" => {0x23, 0x1, 0x0, ..., 0x0}
 107       */
 108      void SetHexDeprecated(std::string_view str);
 109      std::string ToString() const;
 110      /**@}*/
 111  
 112      constexpr const unsigned char* data() const { return m_data.data(); }
 113      constexpr unsigned char* data() { return m_data.data(); }
 114  
 115      constexpr unsigned char* begin() { return m_data.data(); }
 116      constexpr unsigned char* end() { return m_data.data() + WIDTH; }
 117  
 118      constexpr const unsigned char* begin() const { return m_data.data(); }
 119      constexpr const unsigned char* end() const { return m_data.data() + WIDTH; }
 120  
 121      static constexpr unsigned int size() { return WIDTH; }
 122  
 123      constexpr uint64_t GetUint64(int pos) const { return ReadLE64(m_data.data() + pos * 8); }
 124  
 125      template<typename Stream>
 126      void Serialize(Stream& s) const
 127      {
 128          s << Span(m_data);
 129      }
 130  
 131      template<typename Stream>
 132      void Unserialize(Stream& s)
 133      {
 134          s.read(MakeWritableByteSpan(m_data));
 135      }
 136  };
 137  
 138  template <unsigned int BITS>
 139  consteval base_blob<BITS>::base_blob(std::string_view hex_str)
 140  {
 141      if (hex_str.length() != m_data.size() * 2) throw "Hex string must fit exactly";
 142      auto str_it = hex_str.rbegin();
 143      for (auto& elem : m_data) {
 144          auto lo = util::ConstevalHexDigit(*(str_it++));
 145          elem = (util::ConstevalHexDigit(*(str_it++)) << 4) | lo;
 146      }
 147  }
 148  
 149  namespace detail {
 150  /**
 151   * Writes the hex string (in reverse byte order) into a new uintN_t object
 152   * and only returns a value iff all of the checks pass:
 153   *   - Input length is uintN_t::size()*2
 154   *   - All characters are hex
 155   */
 156  template <class uintN_t>
 157  std::optional<uintN_t> FromHex(std::string_view str)
 158  {
 159      if (uintN_t::size() * 2 != str.size() || !IsHex(str)) return std::nullopt;
 160      uintN_t rv;
 161      rv.SetHexDeprecated(str);
 162      return rv;
 163  }
 164  /**
 165   * @brief Like FromHex(std::string_view str), but allows an "0x" prefix
 166   *        and pads the input with leading zeroes if it is shorter than
 167   *        the expected length of uintN_t::size()*2.
 168   *
 169   *        Designed to be used when dealing with user input.
 170   */
 171  template <class uintN_t>
 172  std::optional<uintN_t> FromUserHex(std::string_view input)
 173  {
 174      input = util::RemovePrefixView(input, "0x");
 175      constexpr auto expected_size{uintN_t::size() * 2};
 176      if (input.size() < expected_size) {
 177          auto padded = std::string(expected_size, '0');
 178          std::copy(input.begin(), input.end(), padded.begin() + expected_size - input.size());
 179          return FromHex<uintN_t>(padded);
 180      }
 181      return FromHex<uintN_t>(input);
 182  }
 183  } // namespace detail
 184  
 185  /** 160-bit opaque blob.
 186   * @note This type is called uint160 for historical reasons only. It is an opaque
 187   * blob of 160 bits and has no integer operations.
 188   */
 189  class uint160 : public base_blob<160> {
 190  public:
 191      static std::optional<uint160> FromHex(std::string_view str) { return detail::FromHex<uint160>(str); }
 192      constexpr uint160() = default;
 193      constexpr explicit uint160(Span<const unsigned char> vch) : base_blob<160>(vch) {}
 194  };
 195  
 196  /** 256-bit opaque blob.
 197   * @note This type is called uint256 for historical reasons only. It is an
 198   * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if
 199   * those are required.
 200   */
 201  class uint256 : public base_blob<256> {
 202  public:
 203      static std::optional<uint256> FromHex(std::string_view str) { return detail::FromHex<uint256>(str); }
 204      static std::optional<uint256> FromUserHex(std::string_view str) { return detail::FromUserHex<uint256>(str); }
 205      constexpr uint256() = default;
 206      consteval explicit uint256(std::string_view hex_str) : base_blob<256>(hex_str) {}
 207      constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {}
 208      constexpr explicit uint256(Span<const unsigned char> vch) : base_blob<256>(vch) {}
 209      static const uint256 ZERO;
 210      static const uint256 ONE;
 211  };
 212  
 213  #endif // LIMENKA_UINT256_H
 214