From: svost Date: Sun, 30 Jan 2022 09:02:05 +0000 (+0300) Subject: Split bignum.h to .h and .cpp files X-Git-Tag: nvc-v0.5.10~14 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=6118a2ab33fbe0162b38e0511c30fcf8885d83d1 Split bignum.h to .h and .cpp files --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 94e65fb..7210f2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingfilterproxy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingtablemodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/bignum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/kernelrecord.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/alert.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/version.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 366fcd6..b21af95 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,6 +85,7 @@ set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/addrman.cpp ${CMAKE_CURRENT_SOURCE_DIR}/alert.cpp ${CMAKE_CURRENT_SOURCE_DIR}/base58.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bignum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinrpc.cpp ${CMAKE_CURRENT_SOURCE_DIR}/checkpoints.cpp ${CMAKE_CURRENT_SOURCE_DIR}/crypter.cpp diff --git a/src/bignum.cpp b/src/bignum.cpp new file mode 100644 index 0000000..ad79919 --- /dev/null +++ b/src/bignum.cpp @@ -0,0 +1,438 @@ +#include "bignum.h" + + +CAutoBN_CTX::CAutoBN_CTX() { + pctx = BN_CTX_new(); + if (pctx == nullptr) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); +} + +CAutoBN_CTX::~CAutoBN_CTX() { + if (pctx != nullptr) + BN_CTX_free(pctx); +} + +CBigNum::CBigNum() { + bn = BN_new(); +} + +CBigNum::CBigNum(const CBigNum &b) { + BIGNUM *dup = BN_dup(b.bn); + if (!dup) { + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_dup failed"); + } + bn = dup; +} + +CBigNum &CBigNum::operator=(const CBigNum &b) { + BIGNUM *dup = BN_dup(b.bn); + if (!dup) { + throw bignum_error("CBigNum::operator= : BN_dup failed"); + } + bn = dup; + return (*this); +} + +CBigNum::CBigNum(const BIGNUM *bnp) { + BIGNUM *dup = BN_dup(bnp); + if (!dup) { + throw bignum_error("CBigNum::CBigNum(const BIGNUM*) : BN_dup failed"); + } + bn = dup; +} + +CBigNum::~CBigNum() { + BN_clear_free(bn); +} + +void CBigNum::setuint32(uint32_t n) { + if (!BN_set_word(bn, n)) + throw bignum_error("CBigNum conversion from uint32_t : BN_set_word failed"); +} + +uint32_t CBigNum::getuint32() const { + return BN_get_word(bn); +} + +int32_t CBigNum::getint32() const { + uint64_t n = BN_get_word(bn); + if (!BN_is_negative(bn)) + return (n > (uint64_t)std::numeric_limits::max() ? std::numeric_limits::max() : (int32_t)n); + else + return (n > (uint64_t)std::numeric_limits::max() ? std::numeric_limits::min() : -(int32_t)n); +} + +void CBigNum::setint64(int64_t sn) { + uint8_t pch[sizeof(sn) + 6]; + uint8_t* 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++) + { + uint8_t 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; + } + uint32_t nSize = (uint32_t) (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, (int)(p - pch), bn); +} + +uint64_t CBigNum::getuint64() { + size_t nSize = BN_bn2mpi(bn, nullptr); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint64_t n = 0; + for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((uint8_t*)&n)[i] = vch[j]; + return n; +} + +void CBigNum::setuint64(uint64_t n) { + // Use BN_set_word if word size is sufficient for uint64_t + if (check(sizeof(n) <= sizeof(BN_ULONG))) + { + if (!BN_set_word(bn, (BN_ULONG)n)) + throw bignum_error("CBigNum conversion from uint64_t : BN_set_word failed"); + return; + } + + uint8_t pch[sizeof(n) + 6]; + uint8_t* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + uint8_t c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + uint32_t nSize = (uint32_t) (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, (int)(p - pch), bn); +} + +void CBigNum::setuint160(uint160 n) { + uint8_t pch[sizeof(n) + 6]; + uint8_t* p = pch + 4; + bool fLeadingZeroes = true; + uint8_t* pbegin = (uint8_t*)&n; + uint8_t* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + uint8_t c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + uint32_t nSize = (uint32_t) (p - (pch + 4)); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, (int) (p - pch), bn); +} + +uint160 CBigNum::getuint160() const { + unsigned int nSize = BN_bn2mpi(bn, nullptr); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint160 n = 0; + for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((uint8_t*)&n)[i] = vch[j]; + return n; +} + +void CBigNum::setuint256(uint256 n) { + uint8_t pch[sizeof(n) + 6]; + uint8_t* p = pch + 4; + bool fLeadingZeroes = true; + uint8_t* pbegin = (uint8_t*)&n; + uint8_t* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + uint8_t c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + uint32_t nSize = (uint32_t) (p - (pch + 4)); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, (int) (p - pch), bn); +} + +uint256 CBigNum::getuint256() const { + unsigned int nSize = BN_bn2mpi(bn, nullptr); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint256 n = 0; + for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((uint8_t*)&n)[i] = vch[j]; + return n; +} + +void CBigNum::setBytes(const std::vector &vchBytes) { + BN_bin2bn(&vchBytes[0], (int) vchBytes.size(), bn); +} + +std::vector CBigNum::getBytes() const { + int nBytes = BN_num_bytes(bn); + + std::vector vchBytes(nBytes); + + int n = BN_bn2bin(bn, &vchBytes[0]); + if (n != nBytes) { + throw bignum_error("CBigNum::getBytes : BN_bn2bin failed"); + } + + return vchBytes; +} + +void CBigNum::setvch(const std::vector &vch) { + std::vector vch2(vch.size() + 4); + uint32_t nSize = (uint32_t) 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 + std::reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], (int) vch2.size(), bn); +} + +std::vector CBigNum::getvch() const { + unsigned int nSize = BN_bn2mpi(bn, nullptr); + if (nSize <= 4) + return {}; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + std::reverse(vch.begin(), vch.end()); + return vch; +} + +CBigNum &CBigNum::SetCompact(uint32_t nCompact) { + uint32_t nSize = nCompact >> 24; + std::vector vch(4 + nSize); + vch[3] = nSize; + if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; + if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; + if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; + BN_mpi2bn(&vch[0], (int) vch.size(), bn); + return *this; +} + +uint32_t CBigNum::GetCompact() const { + uint32_t nSize = BN_bn2mpi(bn, nullptr); + std::vector vch(nSize); + nSize -= 4; + BN_bn2mpi(bn, &vch[0]); + uint32_t nCompact = nSize << 24; + if (nSize >= 1) nCompact |= (vch[4] << 16); + if (nSize >= 2) nCompact |= (vch[5] << 8); + if (nSize >= 3) nCompact |= (vch[6] << 0); + return nCompact; +} + +void CBigNum::SetHex(const std::string &str) { + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to bignum + static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[(uint8_t)*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; +} + +std::string CBigNum::ToString(int nBase) const { + CAutoBN_CTX pctx; + CBigNum bnBase = nBase; + CBigNum bn0 = 0; + std::string str; + CBigNum bn = *this; + BN_set_negative(bn.bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(bn.bn, bn0.bn) == 0) + return "0"; + while (BN_cmp(bn.bn, bn0.bn) > 0) + { + if (!BN_div(dv.bn, rem.bn, bn.bn, bnBase.bn, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + bn = dv; + uint32_t c = rem.getuint32(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(bn.bn)) + str += "-"; + std::reverse(str.begin(), str.end()); + return str; +} + +bool CBigNum::operator!() const { + return BN_is_zero(bn); +} + +CBigNum &CBigNum::operator+=(const CBigNum &b) { + if (!BN_add(bn, bn, b.bn)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; +} + +CBigNum &CBigNum::operator-=(const CBigNum &b) { + *this = *this - b; + return *this; +} + +CBigNum &CBigNum::operator*=(const CBigNum &b) { + CAutoBN_CTX pctx; + if (!BN_mul(bn, bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; +} + +CBigNum &CBigNum::operator/=(const CBigNum &b) { + *this = *this / b; + return *this; +} + +CBigNum &CBigNum::operator%=(const CBigNum &b) { + *this = *this % b; + return *this; +} + +CBigNum &CBigNum::operator<<=(unsigned int shift) { + if (!BN_lshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; +} + +CBigNum &CBigNum::operator>>=(unsigned int shift) { + // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number + // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL + CBigNum a = 1; + a <<= shift; + if (BN_cmp(a.bn, bn) > 0) + { + *this = 0; + return *this; + } + + if (!BN_rshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; +} + +CBigNum &CBigNum::operator++() { + // prefix operator + if (!BN_add(bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; +} + +CBigNum &CBigNum::operator--() { + // prefix operator + CBigNum r; + if (!BN_sub(r.bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + return *this; +} + +const CBigNum CBigNum::operator--(int) { + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; +} + +const CBigNum CBigNum::operator++(int) { + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; +} diff --git a/src/bignum.h b/src/bignum.h index a9611c7..8c6b588 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -31,18 +31,8 @@ protected: BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } public: - CAutoBN_CTX() - { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); - } - - ~CAutoBN_CTX() - { - if (pctx != NULL) - BN_CTX_free(pctx); - } + CAutoBN_CTX(); + ~CAutoBN_CTX(); operator BN_CTX*() { return pctx; } BN_CTX& operator*() { return *pctx; } @@ -57,45 +47,12 @@ class CBigNum private: BIGNUM* bn; public: - CBigNum() - { - bn = BN_new(); - } + CBigNum(); + CBigNum(const CBigNum& b); + CBigNum& operator=(const CBigNum& b); + CBigNum(const BIGNUM *bnp); - CBigNum(const CBigNum& b) - { - BIGNUM *dup = BN_dup(b.bn); - if (!dup) - { - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_dup failed"); - } - bn = dup; - } - - CBigNum& operator=(const CBigNum& b) - { - BIGNUM *dup = BN_dup(b.bn); - if (!dup) - { - throw bignum_error("CBigNum::operator= : BN_dup failed"); - } - bn = dup; - return (*this); - } - - CBigNum(const BIGNUM *bnp) { - BIGNUM *dup = BN_dup(bnp); - if (!dup) - { - throw bignum_error("CBigNum::CBigNum(const BIGNUM*) : BN_dup failed"); - } - bn = dup; - } - - ~CBigNum() - { - BN_clear_free(bn); - } + ~CBigNum(); CBigNum(bool n) { bn = BN_new(); setuint32(n); } @@ -110,349 +67,32 @@ public: CBigNum(uint64_t n) { bn = BN_new(); setuint64(n); } explicit CBigNum(uint256 n) { bn = BN_new(); setuint256(n); } - explicit CBigNum(const std::vector& vch) - { - bn = BN_new(); - setvch(vch); - } - - void setuint32(uint32_t n) - { - if (!BN_set_word(bn, n)) - throw bignum_error("CBigNum conversion from uint32_t : BN_set_word failed"); - } + explicit CBigNum(const std::vector& vch) { bn = BN_new(); setvch(vch); } - uint32_t getuint32() const - { - return BN_get_word(bn); - } - - int32_t getint32() const - { - uint64_t n = BN_get_word(bn); - if (!BN_is_negative(bn)) - return (n > (uint64_t)std::numeric_limits::max() ? std::numeric_limits::max() : (int32_t)n); - else - return (n > (uint64_t)std::numeric_limits::max() ? std::numeric_limits::min() : -(int32_t)n); - } - - void setint64(int64_t sn) - { - uint8_t pch[sizeof(sn) + 6]; - uint8_t* 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++) - { - uint8_t 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; - } - uint32_t nSize = (uint32_t) (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, (int)(p - pch), bn); - } - - uint64_t getuint64() - { - size_t nSize = BN_bn2mpi(bn, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint64_t n = 0; - for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((uint8_t*)&n)[i] = vch[j]; - return n; - } + void setuint32(uint32_t n); + uint32_t getuint32() const; + int32_t getint32() const; + void setint64(int64_t sn); + uint64_t getuint64(); //supress msvc C4127: conditional expression is constant inline bool check(bool value) {return value;} - void setuint64(uint64_t n) - { - // Use BN_set_word if word size is sufficient for uint64_t - if (check(sizeof(n) <= sizeof(BN_ULONG))) - { - if (!BN_set_word(bn, (BN_ULONG)n)) - throw bignum_error("CBigNum conversion from uint64_t : BN_set_word failed"); - return; - } - - uint8_t pch[sizeof(n) + 6]; - uint8_t* p = pch + 4; - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - uint8_t c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - uint32_t nSize = (uint32_t) (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, (int)(p - pch), bn); - } - - void setuint160(uint160 n) - { - uint8_t pch[sizeof(n) + 6]; - uint8_t* p = pch + 4; - bool fLeadingZeroes = true; - uint8_t* pbegin = (uint8_t*)&n; - uint8_t* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - uint8_t c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - uint32_t nSize = (uint32_t) (p - (pch + 4)); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, (int) (p - pch), bn); - } - - uint160 getuint160() const - { - unsigned int nSize = BN_bn2mpi(bn, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint160 n = 0; - for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((uint8_t*)&n)[i] = vch[j]; - return n; - } - - void setuint256(uint256 n) - { - uint8_t pch[sizeof(n) + 6]; - uint8_t* p = pch + 4; - bool fLeadingZeroes = true; - uint8_t* pbegin = (uint8_t*)&n; - uint8_t* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - uint8_t c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - uint32_t nSize = (uint32_t) (p - (pch + 4)); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, (int) (p - pch), bn); - } - - uint256 getuint256() const - { - unsigned int nSize = BN_bn2mpi(bn, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint256 n = 0; - for (size_t i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((uint8_t*)&n)[i] = vch[j]; - return n; - } - - void setBytes(const std::vector& vchBytes) - { - BN_bin2bn(&vchBytes[0], (int) vchBytes.size(), bn); - } - - std::vector getBytes() const - { - int nBytes = BN_num_bytes(bn); - - std::vector vchBytes(nBytes); - - int n = BN_bn2bin(bn, &vchBytes[0]); - if (n != nBytes) { - throw bignum_error("CBigNum::getBytes : BN_bn2bin failed"); - } - - return vchBytes; - } - - void setvch(const std::vector& vch) - { - std::vector vch2(vch.size() + 4); - uint32_t nSize = (uint32_t) 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 - std::reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], (int) vch2.size(), bn); - } - - std::vector getvch() const - { - unsigned int nSize = BN_bn2mpi(bn, NULL); - if (nSize <= 4) - return std::vector(); - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - std::reverse(vch.begin(), vch.end()); - return vch; - } - - CBigNum& SetCompact(uint32_t nCompact) - { - uint32_t nSize = nCompact >> 24; - std::vector vch(4 + nSize); - vch[3] = nSize; - if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; - if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; - if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; - BN_mpi2bn(&vch[0], (int) vch.size(), bn); - return *this; - } - - uint32_t GetCompact() const - { - uint32_t nSize = BN_bn2mpi(bn, NULL); - std::vector vch(nSize); - nSize -= 4; - BN_bn2mpi(bn, &vch[0]); - uint32_t nCompact = nSize << 24; - if (nSize >= 1) nCompact |= (vch[4] << 16); - if (nSize >= 2) nCompact |= (vch[5] << 8); - if (nSize >= 3) nCompact |= (vch[6] << 0); - return nCompact; - } - - void SetHex(const std::string& str) - { - // skip 0x - const char* psz = str.c_str(); - while (isspace(*psz)) - psz++; - bool fNegative = false; - if (*psz == '-') - { - fNegative = true; - psz++; - } - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - while (isspace(*psz)) - psz++; - - // hex string to bignum - static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; - *this = 0; - while (isxdigit(*psz)) - { - *this <<= 4; - int n = phexdigit[(uint8_t)*psz++]; - *this += n; - } - if (fNegative) - *this = 0 - *this; - } - - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - std::string str; - CBigNum bn = *this; - BN_set_negative(bn.bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(bn.bn, bn0.bn) == 0) - return "0"; - while (BN_cmp(bn.bn, bn0.bn) > 0) - { - if (!BN_div(dv.bn, rem.bn, bn.bn, bnBase.bn, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - bn = dv; - uint32_t c = rem.getuint32(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(bn.bn)) - str += "-"; - std::reverse(str.begin(), str.end()); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - BIGNUM* get() const { - return BN_dup(bn); - } + void setuint64(uint64_t n); + void setuint160(uint160 n); + uint160 getuint160() const; + void setuint256(uint256 n); + uint256 getuint256() const; + void setBytes(const std::vector& vchBytes); + std::vector getBytes() const; + void setvch(const std::vector& vch); + std::vector getvch() const; + CBigNum& SetCompact(uint32_t nCompact); + uint32_t GetCompact() const; + void SetHex(const std::string& str); + std::string ToString(int nBase=10) const; + std::string GetHex() const { return ToString(16); } + BIGNUM* get() const { return BN_dup(bn); } unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const { @@ -473,101 +113,19 @@ public: setvch(vch); } - bool operator!() const - { - return BN_is_zero(bn); - } + bool operator!() const; - CBigNum& operator+=(const CBigNum& b) - { - if (!BN_add(bn, bn, b.bn)) - throw bignum_error("CBigNum::operator+= : BN_add failed"); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - *this = *this - b; - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - CAutoBN_CTX pctx; - if (!BN_mul(bn, bn, b.bn, pctx)) - throw bignum_error("CBigNum::operator*= : BN_mul failed"); - return *this; - } - - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } - - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } - - CBigNum& operator<<=(unsigned int shift) - { - if (!BN_lshift(bn, bn, shift)) - throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL - CBigNum a = 1; - a <<= shift; - if (BN_cmp(a.bn, bn) > 0) - { - *this = 0; - return *this; - } - - if (!BN_rshift(bn, bn, shift)) - throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); - return *this; - } - - CBigNum& operator++() - { - // prefix operator - if (!BN_add(bn, bn, BN_value_one())) - throw bignum_error("CBigNum::operator++ : BN_add failed"); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - CBigNum r; - if (!BN_sub(r.bn, bn, BN_value_one())) - throw bignum_error("CBigNum::operator-- : BN_sub failed"); - *this = r; - return *this; - } - - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } + CBigNum& operator+=(const CBigNum& b); + CBigNum& operator-=(const CBigNum& b); + CBigNum& operator*=(const CBigNum& b); + CBigNum& operator/=(const CBigNum& b); + CBigNum& operator%=(const CBigNum& b); + CBigNum& operator<<=(unsigned int shift); + CBigNum& operator>>=(unsigned int shift); + CBigNum& operator++(); + const CBigNum operator++(int); + CBigNum& operator--(); + const CBigNum operator--(int); friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);