scriptnum10.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-present The Bitcoin Core 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 BITCOIN_TEST_SCRIPTNUM10_H 7 #define BITCOIN_TEST_SCRIPTNUM10_H 8 9 #include <cassert> 10 #include <cstdint> 11 #include <limits> 12 #include <stdexcept> 13 #include <string> 14 #include <vector> 15 16 class scriptnum10_error : public std::runtime_error 17 { 18 public: 19 explicit scriptnum10_error(const std::string& str) : std::runtime_error(str) {} 20 }; 21 22 class CScriptNum10 23 { 24 /** 25 * The ScriptNum implementation from Bitcoin Core 0.10.0, for cross-comparison. 26 */ 27 public: 28 29 explicit CScriptNum10(const int64_t& n) 30 { 31 m_value = n; 32 } 33 34 static const size_t nDefaultMaxNumSize = 4; 35 36 explicit CScriptNum10(const std::vector<unsigned char>& vch, bool fRequireMinimal, 37 const size_t nMaxNumSize = nDefaultMaxNumSize) 38 { 39 if (vch.size() > nMaxNumSize) { 40 throw scriptnum10_error("script number overflow"); 41 } 42 if (fRequireMinimal && vch.size() > 0) { 43 // Check that the number is encoded with the minimum possible 44 // number of bytes. 45 // 46 // If the most-significant-byte - excluding the sign bit - is zero 47 // then we're not minimal. Note how this test also rejects the 48 // negative-zero encoding, 0x80. 49 if ((vch.back() & 0x7f) == 0) { 50 // One exception: if there's more than one byte and the most 51 // significant bit of the second-most-significant-byte is set 52 // it would conflict with the sign bit. An example of this case 53 // is +-255, which encode to 0xff00 and 0xff80 respectively. 54 // (big-endian). 55 if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) { 56 throw scriptnum10_error("non-minimally encoded script number"); 57 } 58 } 59 } 60 m_value = set_vch(vch); 61 } 62 63 inline bool operator==(const int64_t& rhs) const { return m_value == rhs; } 64 inline auto operator<=>(const int64_t& rhs) const { return m_value <=> rhs; } 65 66 inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); } 67 inline auto operator<=>(const CScriptNum10& rhs) const { return operator<=>(rhs.m_value); } 68 69 inline CScriptNum10 operator+( const int64_t& rhs) const { return CScriptNum10(m_value + rhs);} 70 inline CScriptNum10 operator-( const int64_t& rhs) const { return CScriptNum10(m_value - rhs);} 71 inline CScriptNum10 operator+( const CScriptNum10& rhs) const { return operator+(rhs.m_value); } 72 inline CScriptNum10 operator-( const CScriptNum10& rhs) const { return operator-(rhs.m_value); } 73 74 inline CScriptNum10& operator+=( const CScriptNum10& rhs) { return operator+=(rhs.m_value); } 75 inline CScriptNum10& operator-=( const CScriptNum10& rhs) { return operator-=(rhs.m_value); } 76 77 inline CScriptNum10 operator-() const 78 { 79 assert(m_value != std::numeric_limits<int64_t>::min()); 80 return CScriptNum10(-m_value); 81 } 82 83 inline CScriptNum10& operator=( const int64_t& rhs) 84 { 85 m_value = rhs; 86 return *this; 87 } 88 89 inline CScriptNum10& operator+=( const int64_t& rhs) 90 { 91 assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || 92 (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)); 93 m_value += rhs; 94 return *this; 95 } 96 97 inline CScriptNum10& operator-=( const int64_t& rhs) 98 { 99 assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || 100 (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)); 101 m_value -= rhs; 102 return *this; 103 } 104 105 int getint() const 106 { 107 if (m_value > std::numeric_limits<int>::max()) 108 return std::numeric_limits<int>::max(); 109 else if (m_value < std::numeric_limits<int>::min()) 110 return std::numeric_limits<int>::min(); 111 return m_value; 112 } 113 114 std::vector<unsigned char> getvch() const 115 { 116 return serialize(m_value); 117 } 118 119 static std::vector<unsigned char> serialize(const int64_t& value) 120 { 121 if(value == 0) 122 return std::vector<unsigned char>(); 123 124 std::vector<unsigned char> result; 125 const bool neg = value < 0; 126 uint64_t absvalue = neg ? -value : value; 127 128 while(absvalue) 129 { 130 result.push_back(absvalue & 0xff); 131 absvalue >>= 8; 132 } 133 134 // - If the most significant byte is >= 0x80 and the value is positive, push a 135 // new zero-byte to make the significant byte < 0x80 again. 136 137 // - If the most significant byte is >= 0x80 and the value is negative, push a 138 // new 0x80 byte that will be popped off when converting to an integral. 139 140 // - If the most significant byte is < 0x80 and the value is negative, add 141 // 0x80 to it, since it will be subtracted and interpreted as a negative when 142 // converting to an integral. 143 144 if (result.back() & 0x80) 145 result.push_back(neg ? 0x80 : 0); 146 else if (neg) 147 result.back() |= 0x80; 148 149 return result; 150 } 151 152 private: 153 static int64_t set_vch(const std::vector<unsigned char>& vch) 154 { 155 if (vch.empty()) 156 return 0; 157 158 int64_t result = 0; 159 for (size_t i = 0; i != vch.size(); ++i) 160 result |= static_cast<int64_t>(vch[i]) << 8*i; 161 162 // If the input vector's most significant byte is 0x80, remove it from 163 // the result's msb and return a negative. 164 if (vch.back() & 0x80) 165 return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); 166 167 return result; 168 } 169 170 int64_t m_value; 171 }; 172 173 174 #endif // BITCOIN_TEST_SCRIPTNUM10_H