//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2012, 2013 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED #define RIPPLE_BASICS_BASE_UINT_H_INCLUDED #include #include #include #include #include #include #include #include using beast::zero; using beast::Zero; namespace ripple { // This class stores its values internally in big-endian form template class base_uint { static_assert ((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32."); static_assert (Bits >= 64, "The length of a base_uint in bits must be at least 64."); protected: enum { WIDTH = Bits / 32 }; // This is really big-endian in byte order. // We sometimes use std::uint32_t for speed. // NIKB TODO: migrate to std::array std::uint32_t pn[WIDTH]; public: //-------------------------------------------------------------------------- // // STL Container Interface // static std::size_t const bytes = Bits / 8; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using value_type = unsigned char; using pointer = value_type*; using reference = value_type&; using const_pointer = value_type const*; using const_reference = value_type const&; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using tag_type = Tag; pointer data() { return reinterpret_cast(pn); } const_pointer data() const { return reinterpret_cast(pn); } iterator begin() { return data(); } iterator end() { return data()+bytes; } const_iterator begin() const { return data(); } const_iterator end() const { return data()+bytes; } const_iterator cbegin() const { return data(); } const_iterator cend() const { return data()+bytes; } /** Value hashing function. The seed prevents crafted inputs from causing degenarate parent containers. */ using hasher = hardened_hash <>; /** Container equality testing function. */ class key_equal { public: bool operator() (base_uint const& lhs, base_uint const& rhs) const { return lhs == rhs; } }; //-------------------------------------------------------------------------- private: /** Construct from a raw pointer. The buffer pointed to by `data` must be at least Bits/8 bytes. @note the structure is used to disambiguate this from the std::uint64_t constructor: something like base_uint(0) is ambiguous. */ // NIKB TODO Remove the need for this constructor. struct VoidHelper {}; explicit base_uint (void const* data, VoidHelper) { memcpy (&pn [0], data, bytes); } public: base_uint() { *this = beast::zero; } base_uint(beast::Zero) { *this = beast::zero; } explicit base_uint (Blob const& vch) { assert (vch.size () == size ()); if (vch.size () == size ()) memcpy (pn, &vch[0], size ()); else *this = beast::zero; } explicit base_uint (std::uint64_t b) { *this = b; } base_uint (base_uint const& other) = default; template void copyFrom (base_uint const& other) { memcpy (&pn [0], other.data(), bytes); } /* Construct from a raw pointer. The buffer pointed to by `data` must be at least Bits/8 bytes. */ static base_uint fromVoid (void const* data) { return base_uint (data, VoidHelper ()); } int signum() const { for (int i = 0; i < WIDTH; i++) if (pn[i] != 0) return 1; return 0; } bool operator! () const { return *this == beast::zero; } const base_uint operator~ () const { base_uint ret; for (int i = 0; i < WIDTH; i++) ret.pn[i] = ~pn[i]; return ret; } base_uint& operator= (const base_uint& b) { for (int i = 0; i < WIDTH; i++) pn[i] = b.pn[i]; return *this; } base_uint& operator= (std::uint64_t uHost) { *this = beast::zero; union { unsigned u[2]; std::uint64_t ul; }; // Put in least significant bits. ul = htobe64 (uHost); pn[WIDTH-2] = u[0]; pn[WIDTH-1] = u[1]; return *this; } base_uint& operator^= (const base_uint& b) { for (int i = 0; i < WIDTH; i++) pn[i] ^= b.pn[i]; return *this; } base_uint& operator&= (const base_uint& b) { for (int i = 0; i < WIDTH; i++) pn[i] &= b.pn[i]; return *this; } base_uint& operator|= (const base_uint& b) { for (int i = 0; i < WIDTH; i++) pn[i] |= b.pn[i]; return *this; } // be32toh and htobe32 are macros that somehow cause shadowing // warnings in this header file, so we hide them... static uint32_t bigendToHost (uint32_t x) { return be32toh(x); } static uint32_t hostToBigend (uint32_t x) { return htobe32(x); } base_uint& operator++ () { // prefix operator for (int i = WIDTH - 1; i >= 0; --i) { pn[i] = hostToBigend (bigendToHost (pn[i]) + 1); if (pn[i] != 0) break; } return *this; } const base_uint operator++ (int) { // postfix operator const base_uint ret = *this; ++ (*this); return ret; } base_uint& operator-- () { for (int i = WIDTH - 1; i >= 0; --i) { auto prev = pn[i]; pn[i] = hostToBigend (bigendToHost (pn[i]) - 1); if (prev != 0) break; } return *this; } const base_uint operator-- (int) { // postfix operator const base_uint ret = *this; -- (*this); return ret; } base_uint& operator+= (const base_uint& b) { std::uint64_t carry = 0; for (int i = WIDTH; i--;) { std::uint64_t n = carry + bigendToHost (pn[i]) + bigendToHost (b.pn[i]); pn[i] = hostToBigend (n & 0xffffffff); carry = n >> 32; } return *this; } template > friend void hash_append( Hasher& h, base_uint const& a) noexcept { // Do not allow any endian transformations on this memory h(a.pn, sizeof(a.pn)); } /** Parse a hex string into a base_uint The string must contain exactly bytes * 2 hex characters and must not have any leading or trailing whitespace. */ bool SetHexExact (const char* psz) { unsigned char* pOut = begin (); assert(sizeof(pn) == bytes); for (int i = 0; i < sizeof (pn); ++i) { auto hi = charUnHex(*psz++); if (hi == -1) return false; auto lo = charUnHex (*psz++); if (lo == -1) return false; *pOut++ = (hi << 4) | lo; } // We've consumed exactly as many bytes as we needed at this point // so we should be at the end of the string. return (*psz == 0); } /** Parse a hex string into a base_uint The input can be: - shorter than the full hex representation by not including leading zeroes. - longer than the full hex representation in which case leading bytes are discarded. When finished parsing, the string must be fully consumed with only a null terminator remaining. When bStrict is false, the parsing is done in non-strict mode, and, if present, leading whitespace and the 0x prefix will be skipped. */ bool SetHex (const char* psz, bool bStrict = false) { // skip leading spaces if (!bStrict) while (isspace (*psz)) psz++; // skip 0x if (!bStrict && psz[0] == '0' && tolower (psz[1]) == 'x') psz += 2; const unsigned char* pEnd = reinterpret_cast (psz); const unsigned char* pBegin = pEnd; // Find end. while (charUnHex(*pEnd) != -1) pEnd++; // Take only last digits of over long string. if ((unsigned int) (pEnd - pBegin) > 2 * size ()) pBegin = pEnd - 2 * size (); unsigned char* pOut = end () - ((pEnd - pBegin + 1) / 2); *this = beast::zero; if ((pEnd - pBegin) & 1) *pOut++ = charUnHex(*pBegin++); while (pBegin != pEnd) { auto cHigh = charUnHex(*pBegin++); auto cLow = pBegin == pEnd ? 0 : charUnHex(*pBegin++); if (cHigh == -1 || cLow == -1) return false; *pOut++ = (cHigh << 4) | cLow; } return !*pEnd; } bool SetHex (std::string const& str, bool bStrict = false) { return SetHex (str.c_str (), bStrict); } bool SetHexExact (std::string const& str) { return SetHexExact (str.c_str ()); } constexpr static std::size_t size () { return bytes; } base_uint& operator=(Zero) { memset (&pn[0], 0, sizeof (pn)); return *this; } // Deprecated. bool isZero () const { return *this == beast::zero; } bool isNonZero () const { return *this != beast::zero; } void zero () { *this = beast::zero; } }; using uint128 = base_uint<128>; using uint160 = base_uint<160>; using uint256 = base_uint<256>; template inline int compare ( base_uint const& a, base_uint const& b) { auto ret = std::mismatch (a.cbegin (), a.cend (), b.cbegin ()); if (ret.first == a.cend ()) return 0; // a > b if (*ret.first > *ret.second) return 1; // a < b return -1; } template inline bool operator< ( base_uint const& a, base_uint const& b) { return compare (a, b) < 0; } template inline bool operator<= ( base_uint const& a, base_uint const& b) { return compare (a, b) <= 0; } template inline bool operator> ( base_uint const& a, base_uint const& b) { return compare (a, b) > 0; } template inline bool operator>= ( base_uint const& a, base_uint const& b) { return compare (a, b) >= 0; } template inline bool operator== ( base_uint const& a, base_uint const& b) { return compare (a, b) == 0; } template inline bool operator!= ( base_uint const& a, base_uint const& b) { return compare (a, b) != 0; } //------------------------------------------------------------------------------ template inline bool operator== (base_uint const& a, std::uint64_t b) { return a == base_uint(b); } template inline bool operator!= (base_uint const& a, std::uint64_t b) { return !(a == b); } //------------------------------------------------------------------------------ template inline const base_uint operator^ ( base_uint const& a, base_uint const& b) { return base_uint (a) ^= b; } template inline const base_uint operator& ( base_uint const& a, base_uint const& b) { return base_uint (a) &= b; } template inline const base_uint operator| ( base_uint const& a, base_uint const& b) { return base_uint (a) |= b; } template inline const base_uint operator+ ( base_uint const& a, base_uint const& b) { return base_uint (a) += b; } //------------------------------------------------------------------------------ template inline std::string to_string (base_uint const& a) { return strHex (a.begin (), a.size ()); } // Function templates that return a base_uint given text in hexadecimal. // Invoke like: // auto i = from_hex_text("AAAAA"); template auto from_hex_text (char const* text) -> std::enable_if_t< std::is_same>::value, T> { T ret; ret.SetHex (text); return ret; } template auto from_hex_text (std::string const& text) -> std::enable_if_t< std::is_same>::value, T> { T ret; ret.SetHex (text); return ret; } template inline std::ostream& operator<< ( std::ostream& out, base_uint const& u) { return out << to_string (u); } static_assert(sizeof(uint128) == 128/8, "There should be no padding bytes"); static_assert(sizeof(uint160) == 160/8, "There should be no padding bytes"); static_assert(sizeof(uint256) == 256/8, "There should be no padding bytes"); } // rippled namespace beast { template struct is_uniquely_represented> : public std::true_type {}; } // beast #endif