From eb2cbd754d0ed02ab1c3f0889b6ee1776abd5082 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 19 Apr 2014 23:02:47 +0200 Subject: [PATCH 1/5] Deduplicate shared code between uint160 and uint256 --- src/uint256.h | 306 +++++++++++--------------------------------------- 1 file changed, 65 insertions(+), 241 deletions(-) diff --git a/src/uint256.h b/src/uint256.h index ba903bc8f..a3f783587 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,17 +19,56 @@ inline signed char HexDigit(char c) return p_util_hexdigit[(unsigned char)c]; } -/** Base class without constructors for uint256 and uint160. - * This makes the compiler let you use it in a union. - */ +/** Template base class for unsigned big integers. */ template class base_uint { -protected: +private: enum { WIDTH=BITS/32 }; uint32_t pn[WIDTH]; public: + base_uint() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + + base_uint(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + base_uint& operator=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + base_uint(uint64_t b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + explicit base_uint(const std::string& str) + { + SetHex(str); + } + + explicit base_uint(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) { + memcpy(pn, &vch[0], sizeof(pn)); + } else { + *this = 0; + } + } + bool operator!() const { for (int i = 0; i < WIDTH; i++) @@ -292,7 +331,13 @@ public: return (!(a == b)); } - + friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } + friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } + friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } + friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } + friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } + friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } + friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } std::string GetHex() const { @@ -373,263 +418,42 @@ public: return pn[0] | (uint64_t)pn[1] << 32; } -// unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const unsigned int GetSerializeSize(int nType, int nVersion) const { return sizeof(pn); } template -// void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const void Serialize(Stream& s, int nType, int nVersion) const { s.write((char*)pn, sizeof(pn)); } template -// void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) void Unserialize(Stream& s, int nType, int nVersion) { s.read((char*)pn, sizeof(pn)); } - - - friend class uint160; - friend class uint256; }; -typedef base_uint<160> base_uint160; -typedef base_uint<256> base_uint256; - - - -// -// uint160 and uint256 could be implemented as templates, but to keep -// compile errors and debugging cleaner, they're copy and pasted. -// - - - -////////////////////////////////////////////////////////////////////////////// -// -// uint160 -// - -/** 160-bit unsigned integer */ -class uint160 : public base_uint160 -{ +/** 160-bit unsigned big integer. */ +class uint160 : public base_uint<160> { public: - typedef base_uint160 basetype; - - uint160() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint160(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint160& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint160(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint160& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint160(const std::string& str) - { - SetHex(str); - } - - explicit uint160(const std::vector& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } + uint160() {} + uint160(const base_uint<160>& b) : base_uint<160>(b) {} + uint160(uint64_t b) : base_uint<160>(b) {} + explicit uint160(const std::string& str) : base_uint<160>(str) {} + explicit uint160(const std::vector& vch) : base_uint<160>(vch) {} }; -inline bool operator==(const uint160& a, uint64_t b) { return (base_uint160)a == b; } -inline bool operator!=(const uint160& a, uint64_t b) { return (base_uint160)a != b; } -inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } -inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } -inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } -inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } - -inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } -inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } -inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } -inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } -inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } - -inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } - -inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } - -inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } -inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } -inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } -inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } -inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } -inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } - - - -////////////////////////////////////////////////////////////////////////////// -// -// uint256 -// - -/** 256-bit unsigned integer */ -class uint256 : public base_uint256 -{ +/** 256-bit unsigned big integer. */ +class uint256 : public base_uint<256> { public: - typedef base_uint256 basetype; - - uint256() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - uint256(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - uint256& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - uint256(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - uint256& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - explicit uint256(const std::string& str) - { - SetHex(str); - } - - explicit uint256(const std::vector& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - *this = 0; - } + uint256() {} + uint256(const base_uint<256>& b) : base_uint<256>(b) {} + uint256(uint64_t b) : base_uint<256>(b) {} + explicit uint256(const std::string& str) : base_uint<256>(str) {} + explicit uint256(const std::vector& vch) : base_uint<256>(vch) {} }; -inline bool operator==(const uint256& a, uint64_t b) { return (base_uint256)a == b; } -inline bool operator!=(const uint256& a, uint64_t b) { return (base_uint256)a != b; } -inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } -inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } -inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } -inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } - -inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } -inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } -inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } -inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } -inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } - -inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } - -inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } - -inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } -inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } -inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } -inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } -inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } -inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } -inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } -inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } -inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } -inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } -inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } - #endif From 4d480c8a3fe3c58eeb083ea544c6f9e991606692 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 19 Apr 2014 23:25:44 +0200 Subject: [PATCH 2/5] Exception instead of assigning 0 in case of wrong vector length --- src/test/uint256_tests.cpp | 10 +++++----- src/uint256.h | 15 ++++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 815babf10..8e4b63c8b 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -160,11 +160,11 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality tmpS = ~R2S; BOOST_CHECK(tmpS == ~R2S); tmpS = ~MaxS; BOOST_CHECK(tmpS == ~MaxS); - // Wrong length must give 0 - BOOST_CHECK(uint256(std::vector(OneArray,OneArray+31)) == 0); - BOOST_CHECK(uint256(std::vector(OneArray,OneArray+20)) == 0); - BOOST_CHECK(uint160(std::vector(OneArray,OneArray+32)) == 0); - BOOST_CHECK(uint160(std::vector(OneArray,OneArray+19)) == 0); + // Wrong length must throw exception. + BOOST_CHECK_THROW(uint256(std::vector(OneArray,OneArray+31)), uint_error); + BOOST_CHECK_THROW(uint256(std::vector(OneArray,OneArray+20)), uint_error); + BOOST_CHECK_THROW(uint160(std::vector(OneArray,OneArray+32)), uint_error); + BOOST_CHECK_THROW(uint160(std::vector(OneArray,OneArray+19)), uint_error); } void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) diff --git a/src/uint256.h b/src/uint256.h index a3f783587..b6365bb36 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_UINT256_H #define BITCOIN_UINT256_H +#include +#include #include #include #include @@ -19,6 +21,11 @@ inline signed char HexDigit(char c) return p_util_hexdigit[(unsigned char)c]; } +class uint_error : public std::runtime_error { +public: + explicit uint_error(const std::string& str) : std::runtime_error(str) {} +}; + /** Template base class for unsigned big integers. */ template class base_uint @@ -62,11 +69,9 @@ public: explicit base_uint(const std::vector& vch) { - if (vch.size() == sizeof(pn)) { - memcpy(pn, &vch[0], sizeof(pn)); - } else { - *this = 0; - } + if (vch.size() != sizeof(pn)) + throw uint_error("Converting vector of wrong size to base_uint"); + memcpy(pn, &vch[0], sizeof(pn)); } bool operator!() const From a7031507e647da0723bf289dadba10ef1a50f278 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 20 Apr 2014 01:03:19 +0200 Subject: [PATCH 3/5] Add multiplication and division to uint160/uint256 --- src/test/uint256_tests.cpp | 71 ++++++++++++++++++++++++++++++++++++++ src/uint256.h | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 8e4b63c8b..226d737de 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -482,6 +482,77 @@ BOOST_AUTO_TEST_CASE( plusMinus ) } +BOOST_AUTO_TEST_CASE( multiply ) +{ + BOOST_CHECK((R1L * R1L).ToString() == "62a38c0486f01e45879d7910a7761bf30d5237e9873f9bff3642a732c4d84f10"); + BOOST_CHECK((R1L * R2L).ToString() == "de37805e9986996cfba76ff6ba51c008df851987d9dd323f0e5de07760529c40"); + BOOST_CHECK((R1L * ZeroL) == ZeroL); + BOOST_CHECK((R1L * OneL) == R1L); + BOOST_CHECK((R1L * MaxL) == -R1L); + BOOST_CHECK((R2L * R1L) == (R1L * R2L)); + BOOST_CHECK((R2L * R2L).ToString() == "ac8c010096767d3cae5005dec28bb2b45a1d85ab7996ccd3e102a650f74ff100"); + BOOST_CHECK((R2L * ZeroL) == ZeroL); + BOOST_CHECK((R2L * OneL) == R2L); + BOOST_CHECK((R2L * MaxL) == -R2L); + + BOOST_CHECK((R1S * R1S).ToString() == "a7761bf30d5237e9873f9bff3642a732c4d84f10"); + BOOST_CHECK((R1S * R2S).ToString() == "ba51c008df851987d9dd323f0e5de07760529c40"); + BOOST_CHECK((R1S * ZeroS) == ZeroS); + BOOST_CHECK((R1S * OneS) == R1S); + BOOST_CHECK((R1S * MaxS) == -R1S); + BOOST_CHECK((R2S * R1S) == (R1S * R2S)); + BOOST_CHECK((R2S * R2S).ToString() == "c28bb2b45a1d85ab7996ccd3e102a650f74ff100"); + BOOST_CHECK((R2S * ZeroS) == ZeroS); + BOOST_CHECK((R2S * OneS) == R2S); + BOOST_CHECK((R2S * MaxS) == -R2S); + + BOOST_CHECK(MaxL * MaxL == OneL); + BOOST_CHECK(MaxS * MaxS == OneS); + + BOOST_CHECK((R1L * 0) == 0); + BOOST_CHECK((R1L * 1) == R1L); + BOOST_CHECK((R1L * 3).ToString() == "7759b1c0ed14047f961ad09b20ff83687876a0181a367b813634046f91def7d4"); + BOOST_CHECK((R2L * 0x87654321UL).ToString() == "23f7816e30c4ae2017257b7a0fa64d60402f5234d46e746b61c960d09a26d070"); + BOOST_CHECK((R1S * 0) == 0); + BOOST_CHECK((R1S * 1) == R1S); + BOOST_CHECK((R1S * 7).ToString() == "f7a987f3c3bf758d927f202d7e795faeff084244"); + BOOST_CHECK((R2S * 0xFFFFFFFFUL).ToString() == "1c6f6c930353e17f7d6127213bb18d2883e2cd90"); +} + +BOOST_AUTO_TEST_CASE( divide ) +{ + uint256 D1L("AD7133AC1977FA2B7"); + uint256 D2L("ECD751716"); + BOOST_CHECK((R1L / D1L).ToString() == "00000000000000000b8ac01106981635d9ed112290f8895545a7654dde28fb3a"); + BOOST_CHECK((R1L / D2L).ToString() == "000000000873ce8efec5b67150bad3aa8c5fcb70e947586153bf2cec7c37c57a"); + BOOST_CHECK(R1L / OneL == R1L); + BOOST_CHECK(R1L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R1L == 2); + BOOST_CHECK_THROW(R1L / ZeroL, uint_error); + BOOST_CHECK((R2L / D1L).ToString() == "000000000000000013e1665895a1cc981de6d93670105a6b3ec3b73141b3a3c5"); + BOOST_CHECK((R2L / D2L).ToString() == "000000000e8f0abe753bb0afe2e9437ee85d280be60882cf0bd1aaf7fa3cc2c4"); + BOOST_CHECK(R2L / OneL == R2L); + BOOST_CHECK(R2L / MaxL == ZeroL); + BOOST_CHECK(MaxL / R2L == 1); + BOOST_CHECK_THROW(R2L / ZeroL, uint_error); + + uint160 D1S("D3C5EDCDEA54EB92679F0A4B4"); + uint160 D2S("13037"); + BOOST_CHECK((R1S / D1S).ToString() == "0000000000000000000000000db9af3beade6c02"); + BOOST_CHECK((R1S / D2S).ToString() == "000098dfb6cc40ca592bf74366794f298ada205c"); + BOOST_CHECK(R1S / OneS == R1S); + BOOST_CHECK(R1S / MaxS == ZeroS); + BOOST_CHECK(MaxS / R1S == 1); + BOOST_CHECK_THROW(R1S / ZeroS, uint_error); + BOOST_CHECK((R2S / D1S).ToString() == "0000000000000000000000000c5608e781182047"); + BOOST_CHECK((R2S / D2S).ToString() == "00008966751b7187c3c67c1fda5cea7db2c1c069"); + BOOST_CHECK(R2S / OneS == R2S); + BOOST_CHECK(R2S / MaxS == ZeroS); + BOOST_CHECK(MaxS / R2S == 1); + BOOST_CHECK_THROW(R2S / ZeroS, uint_error); +} + + bool almostEqual(double d1, double d2) { return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits::epsilon(); diff --git a/src/uint256.h b/src/uint256.h index b6365bb36..7b17694eb 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -222,6 +222,57 @@ public: return *this; } + base_uint& operator*=(uint32_t b32) + { + uint64_t carry = 0; + for (int i = 0; i < WIDTH; i++) + { + uint64_t n = carry + (uint64_t)b32 * pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; + } + + base_uint& operator*=(const base_uint& b) + { + base_uint a = *this; + *this = 0; + for (int j = 0; j < WIDTH; j++) { + uint64_t carry = 0; + for (int i = 0; i + j < WIDTH; i++) { + uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; + pn[i + j] = n & 0xffffffff; + carry = n >> 32; + } + } + return *this; + } + + base_uint& operator/=(const base_uint& b) + { + base_uint div = b; // make a copy, so we can shift. + base_uint num = *this; // make a copy, so we can subtract. + *this = 0; // the quotient. + int num_bits = num.bits(); + int div_bits = div.bits(); + if (div_bits == 0) + throw uint_error("Division by zero"); + if (div_bits > num_bits) // the result is certainly 0. + return *this; + int shift = num_bits - div_bits; + div <<= shift; // shift so that div and nun align. + while (shift >= 0) { + if (num >= div) { + num -= div; + pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. + } + div >>= 1; // shift back. + shift--; + } + // num now contains the remainder of the division. + return *this; + } base_uint& operator++() { @@ -338,11 +389,14 @@ public: friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } + friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } + friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } + friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } std::string GetHex() const { @@ -417,6 +471,22 @@ public: return sizeof(pn); } + // Returns the position of the highest bit set plus one, or zero if the + // value is zero. + unsigned int bits() const + { + for (int pos = WIDTH-1; pos >= 0; pos--) { + if (pn[pos]) { + for (int bits = 31; bits > 0; bits--) { + if (pn[pos] & 1<= 2); From df9eb5e14fa8072bc8a82b59e712c2ba36f13f4c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 20 Apr 2014 03:19:20 +0200 Subject: [PATCH 4/5] Move {Get,Set}Compact from bignum to uint256 --- src/bignum.h | 65 ------------------- src/chainparams.cpp | 4 +- src/chainparams.h | 4 +- src/main.cpp | 43 +++++++------ src/main.h | 17 +++-- src/miner.cpp | 6 +- src/rpcmining.cpp | 4 +- src/test/DoS_tests.cpp | 4 +- src/test/bignum_tests.cpp | 88 ------------------------- src/test/uint256_tests.cpp | 129 +++++++++++++++++++++++++++++++++++++ src/txdb.cpp | 6 -- src/txdb.h | 2 - src/uint256.h | 70 ++++++++++++++++++++ 13 files changed, 243 insertions(+), 199 deletions(-) diff --git a/src/bignum.h b/src/bignum.h index 0259338b3..6b77462d8 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -269,71 +269,6 @@ public: return vch; } - // The "compact" format is a representation of a whole - // number N using an unsigned 32bit number similar to a - // floating point format. - // The most significant 8 bits are the unsigned exponent of base 256. - // This exponent can be thought of as "number of bytes of N". - // The lower 23 bits are the mantissa. - // Bit number 24 (0x800000) represents the sign of N. - // N = (-1^sign) * mantissa * 256^(exponent-3) - // - // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). - // MPI uses the most significant bit of the first byte as sign. - // Thus 0x1234560000 is compact (0x05123456) - // and 0xc0de000000 is compact (0x0600c0de) - // (0x05c0de00) would be -0x40de000000 - // - // Bitcoin only uses this "compact" format for encoding difficulty - // targets, which are unsigned 256bit quantities. Thus, all the - // complexities of the sign bit and using base 256 are probably an - // implementation accident. - // - // This implementation directly uses shifts instead of going - // through an intermediate MPI representation. - CBigNum& SetCompact(unsigned int nCompact) - { - unsigned int nSize = nCompact >> 24; - bool fNegative =(nCompact & 0x00800000) != 0; - unsigned int nWord = nCompact & 0x007fffff; - if (nSize <= 3) - { - nWord >>= 8*(3-nSize); - BN_set_word(this, nWord); - } - else - { - BN_set_word(this, nWord); - BN_lshift(this, this, 8*(nSize-3)); - } - BN_set_negative(this, fNegative); - return *this; - } - - unsigned int GetCompact() const - { - unsigned int nSize = BN_num_bytes(this); - unsigned int nCompact = 0; - if (nSize <= 3) - nCompact = BN_get_word(this) << 8*(3-nSize); - else - { - CBigNum bn; - BN_rshift(&bn, this, 8*(nSize-3)); - nCompact = BN_get_word(&bn); - } - // The 0x00800000 bit denotes the sign. - // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. - if (nCompact & 0x00800000) - { - nCompact >>= 8; - nSize++; - } - nCompact |= nSize << 24; - nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); - return nCompact; - } - void SetHex(const std::string& str) { // skip 0x diff --git a/src/chainparams.cpp b/src/chainparams.cpp index eb56800b9..f5cf846a0 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -110,7 +110,7 @@ public: vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 8333; nRPCPort = 8332; - bnProofOfWorkLimit = CBigNum(~uint256(0) >> 32); + bnProofOfWorkLimit = ~uint256(0) >> 32; nSubsidyHalvingInterval = 210000; // Build the genesis block. Note that the output of the genesis coinbase cannot @@ -233,7 +233,7 @@ public: pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; nSubsidyHalvingInterval = 150; - bnProofOfWorkLimit = CBigNum(~uint256(0) >> 1); + bnProofOfWorkLimit = ~uint256(0) >> 1; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; genesis.nNonce = 2; diff --git a/src/chainparams.h b/src/chainparams.h index 542afeaf9..f3f24efd9 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -56,7 +56,7 @@ public: const MessageStartChars& MessageStart() const { return pchMessageStart; } const vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - const CBigNum& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } + const uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } virtual const CBlock& GenesisBlock() const = 0; virtual bool RequireRPCPassword() const { return true; } @@ -75,7 +75,7 @@ protected: vector vAlertPubKey; int nDefaultPort; int nRPCPort; - CBigNum bnProofOfWorkLimit; + uint256 bnProofOfWorkLimit; int nSubsidyHalvingInterval; string strDataDir; vector vSeeds; diff --git a/src/main.cpp b/src/main.cpp index a0f4f40cb..6a7bb9206 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1209,13 +1209,13 @@ static const int64_t nInterval = nTargetTimespan / nTargetSpacing; // unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) { - const CBigNum &bnLimit = Params().ProofOfWorkLimit(); + const uint256 &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after nTargetSpacing*2 time between blocks: if (TestNet() && nTime > nTargetSpacing*2) return bnLimit.GetCompact(); - CBigNum bnResult; + uint256 bnResult; bnResult.SetCompact(nBase); while (nTime > 0 && bnResult < bnLimit) { @@ -1274,8 +1274,10 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead nActualTimespan = nTargetTimespan*4; // Retarget - CBigNum bnNew; + uint256 bnNew; + uint256 bnOld; bnNew.SetCompact(pindexLast->nBits); + bnOld = bnNew; bnNew *= nActualTimespan; bnNew /= nTargetTimespan; @@ -1285,23 +1287,25 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan); - LogPrintf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString()); - LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString()); + LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); + LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); return bnNew.GetCompact(); } bool CheckProofOfWork(uint256 hash, unsigned int nBits) { - CBigNum bnTarget; - bnTarget.SetCompact(nBits); + bool fNegative; + bool fOverflow; + uint256 bnTarget; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range - if (bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit()) + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) return error("CheckProofOfWork() : nBits below minimum work"); // Check proof of work matches claimed amount - if (hash > bnTarget.getuint256()) + if (hash > bnTarget) return error("CheckProofOfWork() : hash doesn't match nBits"); return true; @@ -1346,7 +1350,7 @@ void CheckForkWarningConditions() if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) pindexBestForkTip = NULL; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6).getuint256())) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (chainActive.Tip()->GetBlockWork() * 6))) { if (!fLargeWorkForkFound) { @@ -1402,7 +1406,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // We define it this way because it allows us to only store the highest fork tip (+ base) which meets // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() && + pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7) && chainActive.Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; @@ -1436,10 +1440,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew) if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) { pindexBestInvalid = pindexNew; - // The current code doesn't actually read the BestInvalidWork entry in - // the block database anymore, as it is derived from the flags in block - // index entry. We only write it for backward compatibility. - pblocktree->WriteBestInvalidWork(CBigNum(pindexBestInvalid->nChainWork)); uiInterface.NotifyBlocksChanged(); } LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", @@ -2182,7 +2182,7 @@ CBlockIndex* AddToBlockIndex(CBlockHeader& block) pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork(); pindexNew->RaiseValidity(BLOCK_VALID_TREE); return pindexNew; @@ -2359,11 +2359,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"), REJECT_CHECKPOINT, "time-too-old"); } - CBigNum bnNewBlock; - bnNewBlock.SetCompact(block.nBits); - CBigNum bnRequired; + bool fOverflow = false; + uint256 bnNewBlock; + bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow); + uint256 bnRequired; bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (bnNewBlock > bnRequired) + if (fOverflow || bnNewBlock > bnRequired) { return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), REJECT_INVALID, "bad-diffbits"); @@ -2934,7 +2935,7 @@ bool static LoadBlockIndexDB() BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256(); + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) setBlockIndexValid.insert(pindex); diff --git a/src/main.h b/src/main.h index c69e0d2a3..796a3031c 100644 --- a/src/main.h +++ b/src/main.h @@ -10,7 +10,6 @@ #include "bitcoin-config.h" #endif -#include "bignum.h" #include "chainparams.h" #include "coins.h" #include "core.h" @@ -816,13 +815,19 @@ public: return (int64_t)nTime; } - CBigNum GetBlockWork() const + uint256 GetBlockWork() const { - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - if (bnTarget <= 0) + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) return 0; - return (CBigNum(1)<<256) / (bnTarget+1); + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; } bool CheckIndex() const diff --git a/src/miner.cpp b/src/miner.cpp index 01fc56601..50be4fad4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -466,7 +466,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); if (hash > hashTarget) return false; @@ -552,7 +552,7 @@ void static BitcoinMiner(CWallet *pwallet) // Search // int64_t nStart = GetTime(); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); uint256 hashbuf[2]; uint256& hash = *alignup<16>(hashbuf); while (true) @@ -636,7 +636,7 @@ void static BitcoinMiner(CWallet *pwallet) { // Changing pblock->nTime can change work required on testnet: nBlockBits = ByteReverse(pblock->nBits); - hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + hashTarget.SetCompact(pblock->nBits); } } } } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 070cf1cb2..cb903b585 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -363,7 +363,7 @@ Value getwork(const Array& params, bool fHelp) char phash1[64]; FormatHashBuffers(pblock, pmidstate, pdata, phash1); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); Object result; result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated @@ -559,7 +559,7 @@ Value getblocktemplate(const Array& params, bool fHelp) Object aux; aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hashTarget = uint256().SetCompact(pblock->nBits); static Array aMutable; if (aMutable.empty()) diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index d86cc7a29..897fb87e4 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -106,9 +106,9 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, return CheckNBits(nbits2, time2, nbits1, time1); int64_t deltaTime = time2-time1; - CBigNum required; + uint256 required; required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - CBigNum have; + uint256 have; have.SetCompact(nbits2); return (have <= required); } diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp index d5ee8c977..01967c768 100644 --- a/src/test/bignum_tests.cpp +++ b/src/test/bignum_tests.cpp @@ -125,94 +125,6 @@ BOOST_AUTO_TEST_CASE(bignum_setint64) } -BOOST_AUTO_TEST_CASE(bignum_SetCompact) -{ - CBigNum num; - num.SetCompact(0); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x00123456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01003456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x02000056); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x03000000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x04000000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x00923456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01803456); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x02800056); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x03800000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x04800000); - BOOST_CHECK_EQUAL(num.GetHex(), "0"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0U); - - num.SetCompact(0x01123456); - BOOST_CHECK_EQUAL(num.GetHex(), "12"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); - - // Make sure that we don't generate compacts with the 0x00800000 bit set - num = 0x80; - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); - - num.SetCompact(0x01fedcba); - BOOST_CHECK_EQUAL(num.GetHex(), "-7e"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000U); - - num.SetCompact(0x02123456); - BOOST_CHECK_EQUAL(num.GetHex(), "1234"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); - - num.SetCompact(0x03123456); - BOOST_CHECK_EQUAL(num.GetHex(), "123456"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); - - num.SetCompact(0x04123456); - BOOST_CHECK_EQUAL(num.GetHex(), "12345600"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); - - num.SetCompact(0x04923456); - BOOST_CHECK_EQUAL(num.GetHex(), "-12345600"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456U); - - num.SetCompact(0x05009234); - BOOST_CHECK_EQUAL(num.GetHex(), "92340000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); - - num.SetCompact(0x20123456); - BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); - - num.SetCompact(0xff123456); - BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456U); -} - BOOST_AUTO_TEST_CASE(bignum_SetHex) { std::string hexStr = "deecf97fd890808b9cc0f1b6a3e7a60b400f52710e6ad075b1340755bfa58cc9"; diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 226d737de..4b1a2ae58 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -675,6 +675,135 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G } } +BOOST_AUTO_TEST_CASE(bignum_SetCompact) +{ + uint256 num; + bool fNegative; + bool fOverflow; + num.SetCompact(0, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01003456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02000056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04000000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x00923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01803456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02800056, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04800000, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x01123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000000012"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + // Make sure that we don't generate compacts with the 0x00800000 bit set + num = 0x80; + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000U); + + num.SetCompact(0x01fedcba, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "000000000000000000000000000000000000000000000000000000000000007e"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x01fe0000U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x02123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000001234"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x03123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000000123456"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x04923456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000012345600"); + BOOST_CHECK_EQUAL(num.GetCompact(true), 0x04923456U); + BOOST_CHECK_EQUAL(fNegative, true); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x05009234, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "0000000000000000000000000000000000000000000000000000000092340000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0x20123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000"); + BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456U); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, false); + + num.SetCompact(0xff123456, &fNegative, &fOverflow); + BOOST_CHECK_EQUAL(fNegative, false); + BOOST_CHECK_EQUAL(fOverflow, true); +} + + BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% coverage { // ~R1L give a base_uint<256> diff --git a/src/txdb.cpp b/src/txdb.cpp index cb92922a3..4eab8525a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -73,12 +73,6 @@ bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); } -bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork) -{ - // Obsolete; only written for backward compatibility. - return Write('I', bnBestInvalidWork); -} - bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) { return Write(make_pair('f', nFile), info); } diff --git a/src/txdb.h b/src/txdb.h index 5eb5731db..7257b0dd2 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -14,7 +14,6 @@ #include #include -class CBigNum; class CCoins; class uint256; @@ -52,7 +51,6 @@ private: void operator=(const CBlockTreeDB&); public: bool WriteBlockIndex(const CDiskBlockIndex& blockindex); - bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork); bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo); bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo); bool ReadLastBlockFile(int &nFile); diff --git a/src/uint256.h b/src/uint256.h index 7b17694eb..10c6657c7 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -529,6 +529,76 @@ public: uint256(uint64_t b) : base_uint<256>(b) {} explicit uint256(const std::string& str) : base_uint<256>(str) {} explicit uint256(const std::vector& vch) : base_uint<256>(vch) {} + + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + // + // This implementation directly uses shifts instead of going + // through an intermediate MPI representation. + uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL) + { + int nSize = nCompact >> 24; + uint32_t nWord = nCompact & 0x007fffff; + if (nSize <= 3) + { + nWord >>= 8*(3-nSize); + *this = nWord; + } + else + { + *this = nWord; + *this <<= 8*(nSize-3); + } + if (pfNegative) + *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; + if (pfOverflow) + *pfOverflow = nWord != 0 && ((nSize > 34) || + (nWord > 0xff && nSize > 33) || + (nWord > 0xffff && nSize > 32)); + return *this; + } + + uint32_t GetCompact(bool fNegative = false) const + { + int nSize = (bits() + 7) / 8; + uint32_t nCompact = 0; + if (nSize <= 3) + nCompact = GetLow64() << 8*(3-nSize); + else + { + uint256 bn = *this >> 8*(nSize-3); + nCompact = bn.GetLow64(); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) + { + nCompact >>= 8; + nSize++; + } + assert((nCompact & ~0x007fffff) == 0); + assert(nSize < 256); + nCompact |= nSize << 24; + nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); + return nCompact; + } }; #endif From 397668ea63e148a92f68e9fae578595585616770 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 21 Apr 2014 08:28:43 +0200 Subject: [PATCH 5/5] Deduplicate uint* comparison operator logic --- src/uint256.h | 93 ++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 71 deletions(-) diff --git a/src/uint256.h b/src/uint256.h index 10c6657c7..1acedd14b 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -308,85 +308,28 @@ public: return ret; } + int CompareTo(const base_uint& b) const { + for (int i = base_uint::WIDTH-1; i >= 0; i--) { + if (pn[i] < b.pn[i]) + return -1; + if (pn[i] > b.pn[i]) + return 1; + } + return 0; + } - friend inline bool operator<(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) + bool EqualTo(uint64_t b) const { + for (int i = base_uint::WIDTH-1; i >= 2; i--) { + if (pn[i]) return false; } - return false; - } - - friend inline bool operator<=(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] < b.pn[i]) - return true; - else if (a.pn[i] > b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator>(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return false; - } - - friend inline bool operator>=(const base_uint& a, const base_uint& b) - { - for (int i = base_uint::WIDTH-1; i >= 0; i--) - { - if (a.pn[i] > b.pn[i]) - return true; - else if (a.pn[i] < b.pn[i]) - return false; - } - return true; - } - - friend inline bool operator==(const base_uint& a, const base_uint& b) - { - for (int i = 0; i < base_uint::WIDTH; i++) - if (a.pn[i] != b.pn[i]) - return false; - return true; - } - - friend inline bool operator==(const base_uint& a, uint64_t b) - { - if (a.pn[0] != (unsigned int)b) + if (pn[1] != (b >> 32)) return false; - if (a.pn[1] != (unsigned int)(b >> 32)) + if (pn[0] != (b & 0xfffffffful)) return false; - for (int i = 2; i < base_uint::WIDTH; i++) - if (a.pn[i] != 0) - return false; return true; } - friend inline bool operator!=(const base_uint& a, const base_uint& b) - { - return (!(a == b)); - } - - friend inline bool operator!=(const base_uint& a, uint64_t b) - { - return (!(a == b)); - } - friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } @@ -397,6 +340,14 @@ public: friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } + friend inline bool operator==(const base_uint& a, const base_uint& b) { return a.CompareTo(b) == 0; } + friend inline bool operator!=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) != 0; } + friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } + friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } + friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } + friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } + friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } + friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } std::string GetHex() const {