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