1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-2020 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 <assert.h> 10 #include <limits> 11 #include <stdexcept> 12 #include <stdint.h> 13 #include <string> 14 #include <vector> 15 16 class scriptnum10_error : public std::runtime_error 17 { 18 public: scriptnum10_error(const std::string & str)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 CScriptNum10(const int64_t & n)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 bool operator!=(const int64_t& rhs) const { return m_value != rhs; } 65 inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; } 66 inline bool operator< (const int64_t& rhs) const { return m_value < rhs; } 67 inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; } 68 inline bool operator> (const int64_t& rhs) const { return m_value > rhs; } 69 70 inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); } 71 inline bool operator!=(const CScriptNum10& rhs) const { return operator!=(rhs.m_value); } 72 inline bool operator<=(const CScriptNum10& rhs) const { return operator<=(rhs.m_value); } 73 inline bool operator< (const CScriptNum10& rhs) const { return operator< (rhs.m_value); } 74 inline bool operator>=(const CScriptNum10& rhs) const { return operator>=(rhs.m_value); } 75 inline bool operator> (const CScriptNum10& rhs) const { return operator> (rhs.m_value); } 76 77 inline CScriptNum10 operator+( const int64_t& rhs) const { return CScriptNum10(m_value + rhs);} 78 inline CScriptNum10 operator-( const int64_t& rhs) const { return CScriptNum10(m_value - rhs);} 79 inline CScriptNum10 operator+( const CScriptNum10& rhs) const { return operator+(rhs.m_value); } 80 inline CScriptNum10 operator-( const CScriptNum10& rhs) const { return operator-(rhs.m_value); } 81 82 inline CScriptNum10& operator+=( const CScriptNum10& rhs) { return operator+=(rhs.m_value); } 83 inline CScriptNum10& operator-=( const CScriptNum10& rhs) { return operator-=(rhs.m_value); } 84 85 inline CScriptNum10 operator-() const 86 { 87 assert(m_value != std::numeric_limits<int64_t>::min()); 88 return CScriptNum10(-m_value); 89 } 90 91 inline CScriptNum10& operator=( const int64_t& rhs) 92 { 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>::max() - rhs) || 100 (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)); 101 m_value += rhs; 102 return *this; 103 } 104 105 inline CScriptNum10& operator-=( const int64_t& rhs) 106 { 107 assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || 108 (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)); 109 m_value -= rhs; 110 return *this; 111 } 112 getint()113 int getint() const 114 { 115 if (m_value > std::numeric_limits<int>::max()) 116 return std::numeric_limits<int>::max(); 117 else if (m_value < std::numeric_limits<int>::min()) 118 return std::numeric_limits<int>::min(); 119 return m_value; 120 } 121 getvch()122 std::vector<unsigned char> getvch() const 123 { 124 return serialize(m_value); 125 } 126 serialize(const int64_t & value)127 static std::vector<unsigned char> serialize(const int64_t& value) 128 { 129 if(value == 0) 130 return std::vector<unsigned char>(); 131 132 std::vector<unsigned char> result; 133 const bool neg = value < 0; 134 uint64_t absvalue = neg ? -value : value; 135 136 while(absvalue) 137 { 138 result.push_back(absvalue & 0xff); 139 absvalue >>= 8; 140 } 141 142 // - If the most significant byte is >= 0x80 and the value is positive, push a 143 // new zero-byte to make the significant byte < 0x80 again. 144 145 // - If the most significant byte is >= 0x80 and the value is negative, push a 146 // new 0x80 byte that will be popped off when converting to an integral. 147 148 // - If the most significant byte is < 0x80 and the value is negative, add 149 // 0x80 to it, since it will be subtracted and interpreted as a negative when 150 // converting to an integral. 151 152 if (result.back() & 0x80) 153 result.push_back(neg ? 0x80 : 0); 154 else if (neg) 155 result.back() |= 0x80; 156 157 return result; 158 } 159 160 private: set_vch(const std::vector<unsigned char> & vch)161 static int64_t set_vch(const std::vector<unsigned char>& vch) 162 { 163 if (vch.empty()) 164 return 0; 165 166 int64_t result = 0; 167 for (size_t i = 0; i != vch.size(); ++i) 168 result |= static_cast<int64_t>(vch[i]) << 8*i; 169 170 // If the input vector's most significant byte is 0x80, remove it from 171 // the result's msb and return a negative. 172 if (vch.back() & 0x80) 173 return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); 174 175 return result; 176 } 177 178 int64_t m_value; 179 }; 180 181 182 #endif // BITCOIN_TEST_BIGNUM_H 183