aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2015-11-25 13:19:48 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2015-11-25 13:59:49 +0100
commit4ec3561eb3473638230ef780b41343bc6284b460 (patch)
treeb56e639d4133bbd1818fc9e97a354f124b993c38
parent2b2ddc558e1cddb5ff54fd2d9e375793021a908e (diff)
downloadbitcoin-4ec3561eb3473638230ef780b41343bc6284b460.tar.xz
Replace scriptnum_test's normative ScriptNum implementation
Compare against the scriptnum from Bitcoin Core 0.10 instead of OpenSSL. Closes #7086.
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/test/bignum.h180
-rw-r--r--src/test/scriptnum10.h183
-rw-r--r--src/test/scriptnum_tests.cpp41
4 files changed, 206 insertions, 200 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 2328d0b4cc..fafc1a2944 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -35,7 +35,7 @@ GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.r
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
- test/bignum.h \
+ test/scriptnum10.h \
test/addrman_tests.cpp \
test/alert_tests.cpp \
test/allocator_tests.cpp \
diff --git a/src/test/bignum.h b/src/test/bignum.h
deleted file mode 100644
index e7aeee9db6..0000000000
--- a/src/test/bignum.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_TEST_BIGNUM_H
-#define BITCOIN_TEST_BIGNUM_H
-
-#include <algorithm>
-#include <limits>
-#include <stdexcept>
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-#include <openssl/bn.h>
-
-class bignum_error : public std::runtime_error
-{
-public:
- explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
-};
-
-
-/** C++ wrapper for BIGNUM (OpenSSL bignum) */
-class CBigNum : public BIGNUM
-{
-public:
- CBigNum()
- {
- BN_init(this);
- }
-
- CBigNum(const CBigNum& b)
- {
- BN_init(this);
- if (!BN_copy(this, &b))
- {
- BN_clear_free(this);
- throw bignum_error("CBigNum::CBigNum(const CBigNum&): BN_copy failed");
- }
- }
-
- CBigNum& operator=(const CBigNum& b)
- {
- if (!BN_copy(this, &b))
- throw bignum_error("CBigNum::operator=: BN_copy failed");
- return (*this);
- }
-
- ~CBigNum()
- {
- BN_clear_free(this);
- }
-
- CBigNum(long long n) { BN_init(this); setint64(n); }
-
- explicit CBigNum(const std::vector<unsigned char>& vch)
- {
- BN_init(this);
- setvch(vch);
- }
-
- int getint() const
- {
- BN_ULONG n = BN_get_word(this);
- if (!BN_is_negative(this))
- return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
- else
- return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
- }
-
- void setint64(int64_t sn)
- {
- unsigned char pch[sizeof(sn) + 6];
- unsigned char* p = pch + 4;
- bool fNegative;
- uint64_t n;
-
- if (sn < (int64_t)0)
- {
- // Since the minimum signed integer cannot be represented as positive so long as its type is signed,
- // and it's not well-defined what happens if you make it unsigned before negating it,
- // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
- n = -(sn + 1);
- ++n;
- fNegative = true;
- } else {
- n = sn;
- fNegative = false;
- }
-
- bool fLeadingZeroes = true;
- for (int i = 0; i < 8; i++)
- {
- unsigned char c = (n >> 56) & 0xff;
- n <<= 8;
- if (fLeadingZeroes)
- {
- if (c == 0)
- continue;
- if (c & 0x80)
- *p++ = (fNegative ? 0x80 : 0);
- else if (fNegative)
- c |= 0x80;
- fLeadingZeroes = false;
- }
- *p++ = c;
- }
- unsigned int nSize = p - (pch + 4);
- pch[0] = (nSize >> 24) & 0xff;
- pch[1] = (nSize >> 16) & 0xff;
- pch[2] = (nSize >> 8) & 0xff;
- pch[3] = (nSize) & 0xff;
- BN_mpi2bn(pch, p - pch, this);
- }
-
- void setvch(const std::vector<unsigned char>& vch)
- {
- std::vector<unsigned char> vch2(vch.size() + 4);
- unsigned int nSize = vch.size();
- // BIGNUM's byte stream format expects 4 bytes of
- // big endian size data info at the front
- vch2[0] = (nSize >> 24) & 0xff;
- vch2[1] = (nSize >> 16) & 0xff;
- vch2[2] = (nSize >> 8) & 0xff;
- vch2[3] = (nSize >> 0) & 0xff;
- // swap data to big endian
- reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
- BN_mpi2bn(&vch2[0], vch2.size(), this);
- }
-
- std::vector<unsigned char> getvch() const
- {
- unsigned int nSize = BN_bn2mpi(this, NULL);
- if (nSize <= 4)
- return std::vector<unsigned char>();
- std::vector<unsigned char> vch(nSize);
- BN_bn2mpi(this, &vch[0]);
- vch.erase(vch.begin(), vch.begin() + 4);
- reverse(vch.begin(), vch.end());
- return vch;
- }
-
- friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
-};
-
-
-
-inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
-{
- CBigNum r;
- if (!BN_add(&r, &a, &b))
- throw bignum_error("CBigNum::operator+: BN_add failed");
- return r;
-}
-
-inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
-{
- CBigNum r;
- if (!BN_sub(&r, &a, &b))
- throw bignum_error("CBigNum::operator-: BN_sub failed");
- return r;
-}
-
-inline const CBigNum operator-(const CBigNum& a)
-{
- CBigNum r(a);
- BN_set_negative(&r, !BN_is_negative(&r));
- return r;
-}
-
-inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
-inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
-inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
-inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
-inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
-inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
-
-#endif // BITCOIN_TEST_BIGNUM_H
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
new file mode 100644
index 0000000000..00419746b7
--- /dev/null
+++ b/src/test/scriptnum10.h
@@ -0,0 +1,183 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_TEST_SCRIPTNUM10_H
+#define BITCOIN_TEST_SCRIPTNUM10_H
+
+#include <algorithm>
+#include <limits>
+#include <stdexcept>
+#include <stdint.h>
+#include <string>
+#include <vector>
+#include "assert.h"
+
+class scriptnum10_error : public std::runtime_error
+{
+public:
+ explicit scriptnum10_error(const std::string& str) : std::runtime_error(str) {}
+};
+
+class CScriptNum10
+{
+/**
+ * The ScriptNum implementation from Bitcoin Core 0.10.0, for cross-comparison.
+ */
+public:
+
+ explicit CScriptNum10(const int64_t& n)
+ {
+ m_value = n;
+ }
+
+ static const size_t nDefaultMaxNumSize = 4;
+
+ explicit CScriptNum10(const std::vector<unsigned char>& vch, bool fRequireMinimal,
+ const size_t nMaxNumSize = nDefaultMaxNumSize)
+ {
+ if (vch.size() > nMaxNumSize) {
+ throw scriptnum10_error("script number overflow");
+ }
+ if (fRequireMinimal && vch.size() > 0) {
+ // Check that the number is encoded with the minimum possible
+ // number of bytes.
+ //
+ // If the most-significant-byte - excluding the sign bit - is zero
+ // then we're not minimal. Note how this test also rejects the
+ // negative-zero encoding, 0x80.
+ if ((vch.back() & 0x7f) == 0) {
+ // One exception: if there's more than one byte and the most
+ // significant bit of the second-most-significant-byte is set
+ // it would conflict with the sign bit. An example of this case
+ // is +-255, which encode to 0xff00 and 0xff80 respectively.
+ // (big-endian).
+ if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
+ throw scriptnum10_error("non-minimally encoded script number");
+ }
+ }
+ }
+ m_value = set_vch(vch);
+ }
+
+ inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
+ inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
+ inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
+ inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
+ inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
+ inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
+
+ inline bool operator==(const CScriptNum10& rhs) const { return operator==(rhs.m_value); }
+ inline bool operator!=(const CScriptNum10& rhs) const { return operator!=(rhs.m_value); }
+ inline bool operator<=(const CScriptNum10& rhs) const { return operator<=(rhs.m_value); }
+ inline bool operator< (const CScriptNum10& rhs) const { return operator< (rhs.m_value); }
+ inline bool operator>=(const CScriptNum10& rhs) const { return operator>=(rhs.m_value); }
+ inline bool operator> (const CScriptNum10& rhs) const { return operator> (rhs.m_value); }
+
+ inline CScriptNum10 operator+( const int64_t& rhs) const { return CScriptNum10(m_value + rhs);}
+ inline CScriptNum10 operator-( const int64_t& rhs) const { return CScriptNum10(m_value - rhs);}
+ inline CScriptNum10 operator+( const CScriptNum10& rhs) const { return operator+(rhs.m_value); }
+ inline CScriptNum10 operator-( const CScriptNum10& rhs) const { return operator-(rhs.m_value); }
+
+ inline CScriptNum10& operator+=( const CScriptNum10& rhs) { return operator+=(rhs.m_value); }
+ inline CScriptNum10& operator-=( const CScriptNum10& rhs) { return operator-=(rhs.m_value); }
+
+ inline CScriptNum10 operator-() const
+ {
+ assert(m_value != std::numeric_limits<int64_t>::min());
+ return CScriptNum10(-m_value);
+ }
+
+ inline CScriptNum10& operator=( const int64_t& rhs)
+ {
+ m_value = rhs;
+ return *this;
+ }
+
+ inline CScriptNum10& operator+=( const int64_t& rhs)
+ {
+ assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
+ (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
+ m_value += rhs;
+ return *this;
+ }
+
+ inline CScriptNum10& operator-=( const int64_t& rhs)
+ {
+ assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
+ (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
+ m_value -= rhs;
+ return *this;
+ }
+
+ int getint() const
+ {
+ if (m_value > std::numeric_limits<int>::max())
+ return std::numeric_limits<int>::max();
+ else if (m_value < std::numeric_limits<int>::min())
+ return std::numeric_limits<int>::min();
+ return m_value;
+ }
+
+ std::vector<unsigned char> getvch() const
+ {
+ return serialize(m_value);
+ }
+
+ static std::vector<unsigned char> serialize(const int64_t& value)
+ {
+ if(value == 0)
+ return std::vector<unsigned char>();
+
+ std::vector<unsigned char> result;
+ const bool neg = value < 0;
+ uint64_t absvalue = neg ? -value : value;
+
+ while(absvalue)
+ {
+ result.push_back(absvalue & 0xff);
+ absvalue >>= 8;
+ }
+
+// - If the most significant byte is >= 0x80 and the value is positive, push a
+// new zero-byte to make the significant byte < 0x80 again.
+
+// - If the most significant byte is >= 0x80 and the value is negative, push a
+// new 0x80 byte that will be popped off when converting to an integral.
+
+// - If the most significant byte is < 0x80 and the value is negative, add
+// 0x80 to it, since it will be subtracted and interpreted as a negative when
+// converting to an integral.
+
+ if (result.back() & 0x80)
+ result.push_back(neg ? 0x80 : 0);
+ else if (neg)
+ result.back() |= 0x80;
+
+ return result;
+ }
+
+private:
+ static int64_t set_vch(const std::vector<unsigned char>& vch)
+ {
+ if (vch.empty())
+ return 0;
+
+ int64_t result = 0;
+ for (size_t i = 0; i != vch.size(); ++i)
+ result |= static_cast<int64_t>(vch[i]) << 8*i;
+
+ // If the input vector's most significant byte is 0x80, remove it from
+ // the result's msb and return a negative.
+ if (vch.back() & 0x80)
+ return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));
+
+ return result;
+ }
+
+ int64_t m_value;
+};
+
+
+#endif // BITCOIN_TEST_BIGNUM_H
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index d95724dbe1..2405ab3ffc 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bignum.h"
+#include "scriptnum10.h"
#include "script/script.h"
#include "test/test_bitcoin.h"
@@ -16,45 +16,48 @@ static const int64_t values[] = \
{ 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX };
static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000};
-static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum)
+static bool verify(const CScriptNum10& bignum, const CScriptNum& scriptnum)
{
return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint();
}
static void CheckCreateVch(const int64_t& num)
{
- CBigNum bignum(num);
+ CScriptNum10 bignum(num);
CScriptNum scriptnum(num);
BOOST_CHECK(verify(bignum, scriptnum));
- CBigNum bignum2(bignum.getvch());
+ std::vector<unsigned char> vch = bignum.getvch();
+
+ CScriptNum10 bignum2(bignum.getvch(), false);
+ vch = scriptnum.getvch();
CScriptNum scriptnum2(scriptnum.getvch(), false);
BOOST_CHECK(verify(bignum2, scriptnum2));
- CBigNum bignum3(scriptnum2.getvch());
+ CScriptNum10 bignum3(scriptnum2.getvch(), false);
CScriptNum scriptnum3(bignum2.getvch(), false);
BOOST_CHECK(verify(bignum3, scriptnum3));
}
static void CheckCreateInt(const int64_t& num)
{
- CBigNum bignum(num);
+ CScriptNum10 bignum(num);
CScriptNum scriptnum(num);
BOOST_CHECK(verify(bignum, scriptnum));
- BOOST_CHECK(verify(bignum.getint(), CScriptNum(scriptnum.getint())));
- BOOST_CHECK(verify(scriptnum.getint(), CScriptNum(bignum.getint())));
- BOOST_CHECK(verify(CBigNum(scriptnum.getint()).getint(), CScriptNum(CScriptNum(bignum.getint()).getint())));
+ BOOST_CHECK(verify(CScriptNum10(bignum.getint()), CScriptNum(scriptnum.getint())));
+ BOOST_CHECK(verify(CScriptNum10(scriptnum.getint()), CScriptNum(bignum.getint())));
+ BOOST_CHECK(verify(CScriptNum10(CScriptNum10(scriptnum.getint()).getint()), CScriptNum(CScriptNum(bignum.getint()).getint())));
}
static void CheckAdd(const int64_t& num1, const int64_t& num2)
{
- const CBigNum bignum1(num1);
- const CBigNum bignum2(num2);
+ const CScriptNum10 bignum1(num1);
+ const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
- CBigNum bignum3(num1);
- CBigNum bignum4(num1);
+ CScriptNum10 bignum3(num1);
+ CScriptNum10 bignum4(num1);
CScriptNum scriptnum3(num1);
CScriptNum scriptnum4(num1);
@@ -71,7 +74,7 @@ static void CheckAdd(const int64_t& num1, const int64_t& num2)
static void CheckNegate(const int64_t& num)
{
- const CBigNum bignum(num);
+ const CScriptNum10 bignum(num);
const CScriptNum scriptnum(num);
// -INT64_MIN is undefined
@@ -81,8 +84,8 @@ static void CheckNegate(const int64_t& num)
static void CheckSubtract(const int64_t& num1, const int64_t& num2)
{
- const CBigNum bignum1(num1);
- const CBigNum bignum2(num2);
+ const CScriptNum10 bignum1(num1);
+ const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
bool invalid = false;
@@ -107,8 +110,8 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2)
static void CheckCompare(const int64_t& num1, const int64_t& num2)
{
- const CBigNum bignum1(num1);
- const CBigNum bignum2(num2);
+ const CScriptNum10 bignum1(num1);
+ const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
@@ -149,7 +152,7 @@ static void RunCreate(const int64_t& num)
CheckCreateVch(num);
else
{
- BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum_error);
+ BOOST_CHECK_THROW (CheckCreateVch(num), scriptnum10_error);
}
}