From d91ad90bde254bdc6f69cd9557cbe486f6b1398f Mon Sep 17 00:00:00 2001 From: warrows Date: Thu, 11 Oct 2018 13:41:48 +0200 Subject: [PATCH] [Refactor] Refactor bignum header file into several files --- configure.ac | 3 + src/Makefile.am | 9 +- src/libzerocoin/bignum.cpp | 63 ++ src/libzerocoin/bignum.h | 1103 ++++------------------------ src/libzerocoin/bignum_gmp.cpp | 341 +++++++++ src/libzerocoin/bignum_openssl.cpp | 508 +++++++++++++ 6 files changed, 1046 insertions(+), 981 deletions(-) create mode 100644 src/libzerocoin/bignum.cpp create mode 100644 src/libzerocoin/bignum_gmp.cpp create mode 100644 src/libzerocoin/bignum_openssl.cpp diff --git a/configure.ac b/configure.ac index 2d060774cba8f5..c7c23e9982b5fe 100644 --- a/configure.ac +++ b/configure.ac @@ -1310,6 +1310,9 @@ openssl) ;; esac +AM_CONDITIONAL([USE_NUM_GMP], [test "x$set_bignum" = "xgmp"]) +AM_CONDITIONAL([USE_NUM_OPENSSL], [test "x$set_bignum" = "xopenssl"]) + AC_MSG_CHECKING([whether to build test_pivx]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) diff --git a/src/Makefile.am b/src/Makefile.am index 1662436b656250..c24a77ba38639c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -324,9 +324,9 @@ crypto_libbitcoin_crypto_a_SOURCES = \ libzerocoin_libbitcoin_zerocoin_a_CPPFLAGS = $(AM_CPPFLAGS) $(BOOST_CPPFLAGS) libzerocoin_libbitcoin_zerocoin_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ + libzerocoin/bignum.h \ libzerocoin/Accumulator.h \ libzerocoin/AccumulatorProofOfKnowledge.h \ - libzerocoin/bignum.h \ libzerocoin/Coin.h \ libzerocoin/CoinSpend.h \ libzerocoin/Commitment.h \ @@ -336,6 +336,7 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ libzerocoin/SerialNumberSignatureOfKnowledge.h \ libzerocoin/SpendType.h \ libzerocoin/ZerocoinDefines.h \ + libzerocoin/bignum.cpp \ libzerocoin/Accumulator.cpp \ libzerocoin/AccumulatorProofOfKnowledge.cpp \ libzerocoin/Coin.cpp \ @@ -345,6 +346,12 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ libzerocoin/ParamGeneration.cpp \ libzerocoin/Params.cpp \ libzerocoin/SerialNumberSignatureOfKnowledge.cpp +if USE_NUM_GMP + libzerocoin_libbitcoin_zerocoin_a_SOURCES += libzerocoin/bignum_gmp.cpp +endif +if USE_NUM_OPENSSL + libzerocoin_libbitcoin_zerocoin_a_SOURCES += libzerocoin/bignum_openssl.cpp +endif # common: shared between pivxd, and pivx-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) diff --git a/src/libzerocoin/bignum.cpp b/src/libzerocoin/bignum.cpp new file mode 100644 index 00000000000000..6b19ea1bd41611 --- /dev/null +++ b/src/libzerocoin/bignum.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-2019 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +#if defined(USE_NUM_GMP) +#include "bignum_gmp.cpp" +#endif + +#if defined(USE_NUM_OPENSSL) +#include "bignum_openssl.cpp" +#endif + +std::string CBigNum::GetHex() const +{ + return ToString(16); +} + +std::string CBigNum::GetDec() const +{ + return ToString(10); +} + +CBigNum CBigNum::pow(const int e) const +{ + return this->pow(CBigNum(e)); +} + +void CBigNum::SetHex(const std::string& str) +{ + SetHexBool(str); +} + +CBigNum& CBigNum::operator/=(const CBigNum& b) +{ + *this = *this / b; + return *this; +} + +CBigNum& CBigNum::operator%=(const CBigNum& b) +{ + *this = *this % b; + 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/libzerocoin/bignum.h b/src/libzerocoin/bignum.h index 47ddb5c18e6e82..98be5aac0eec3f 100755 --- a/src/libzerocoin/bignum.h +++ b/src/libzerocoin/bignum.h @@ -1,8 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2017-2018 The PIVX developers +// Copyright (c) 2017-2019 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_BIGNUM_H #define BITCOIN_BIGNUM_H @@ -10,15 +11,16 @@ #include "config/pivx-config.h" #endif -#include -#include -#include -#if defined(USE_NUM_GMP) -#include -#endif #if defined(USE_NUM_OPENSSL) #include #endif +#if defined(USE_NUM_GMP) +#include +#endif + +#include +#include +#include #include "serialize.h" #include "uint256.h" @@ -32,368 +34,69 @@ class bignum_error : public std::runtime_error explicit bignum_error(const std::string& str) : std::runtime_error(str) {} }; -#if defined(USE_NUM_OPENSSL) - - -/** RAII encapsulated BN_CTX (OpenSSL bignum context) */ -class CAutoBN_CTX -{ -protected: - BN_CTX* pctx; - 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); - } - - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } - bool operator!() { return (pctx == NULL); } -}; - -/** C++ wrapper for BIGNUM (OpenSSL bignum) */ +/** C++ wrapper for BIGNUM */ class CBigNum { +#if defined(USE_NUM_OPENSSL) BIGNUM* bn; +#endif +#if defined(USE_NUM_GMP) + mpz_t bn; +#endif public: - CBigNum() - { - bn = BN_new(); - } - - CBigNum(const CBigNum& b) - { - bn = BN_new(); - if (!BN_copy(bn, b.bn)) - { - BN_clear_free(bn); - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); - } - } - - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(bn, b.bn)) - throw bignum_error("CBigNum::operator= : BN_copy failed"); - return (*this); - } - - ~CBigNum() - { - BN_clear_free(bn); - } + CBigNum(); + CBigNum(const CBigNum& b); + CBigNum& operator=(const CBigNum& b); + ~CBigNum(); //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(short n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long long n) { bn = BN_new(); setint64(n); } - CBigNum(unsigned char n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned short n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned int n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned long n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned long long 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); - } + CBigNum(signed char n); + CBigNum(short n); + CBigNum(int n); + CBigNum(long n); + CBigNum(long long n); + CBigNum(unsigned char n); + CBigNum(unsigned short n); + CBigNum(unsigned int n); + CBigNum(unsigned long n); + CBigNum(unsigned long long n); + explicit CBigNum(uint256 n); + explicit CBigNum(const std::vector& vch); /** Generates a cryptographically secure random number between zero and range exclusive * i.e. 0 < returned number < range * @param range The upper bound on the number. * @return */ - static CBigNum randBignum(const CBigNum& range) { - CBigNum ret; - if(!BN_rand_range(ret.bn, range.bn)){ - throw bignum_error("CBigNum:rand element : BN_rand_range failed"); - } - return ret; - } + static CBigNum randBignum(const CBigNum& range); /** Generates a cryptographically secure random k-bit number * @param k The bit length of the number. * @return */ - static CBigNum RandKBitBigum(const uint32_t k){ - CBigNum ret; - if(!BN_rand(ret.bn, k, -1, 0)){ - throw bignum_error("CBigNum:rand element : BN_rand failed"); - } - return ret; - } + static CBigNum RandKBitBigum(const uint32_t k); /**Returns the size in bits of the underlying bignum. * * @return the size */ - int bitSize() const{ - return BN_num_bits(bn); - } - - void setulong(unsigned long n) - { - if (!BN_set_word(bn, n)) - throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); - } - - unsigned long getulong() const - { - return BN_get_word(bn); - } - - unsigned int getuint() const - { - return BN_get_word(bn); - } - - int getint() const - { - unsigned long n = BN_get_word(bn); - if (!BN_is_negative(bn)) - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); - else - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::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, bn); - } - - void setuint64(uint64_t n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - 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++ = 0; - 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, bn); - } - - void setuint256(uint256 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - 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 >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, bn); - } - - uint256 getuint256() const - { - if(bitSize() > 256){ - throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); - } - 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 (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setvch(const std::vector& vch) - { - std::vector 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(), 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); - reverse(vch.begin(), vch.end()); - return vch; - } - - void SetDec(const std::string& str) - { - BN_dec2bn(&bn, str.c_str()); - } - - void SetHex(const std::string& str) - { - SetHexBool(str); - } - - bool SetHexBool(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[(unsigned char)*psz++]; - *this += n; - } - if (fNegative) - *this = 0 - *this; - - return true; - } - - - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - CBigNum locBn = *this; - std::string str; - BN_set_negative(locBn.bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(locBn.bn, bn0.bn) == 0) - return "0"; - while (BN_cmp(locBn.bn, bn0.bn) > 0) - { - if (!BN_div(dv.bn, rem.bn, locBn.bn, bnBase.bn, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - locBn = dv; - unsigned int c = rem.getulong(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(bn)) - str += "-"; - reverse(str.begin(), str.end()); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - std::string GetDec() const - { - return ToString(10); - } + int bitSize() const; + void setulong(unsigned long n); + unsigned long getulong() const; + unsigned int getuint() const; + int getint() const; + void setint64(int64_t sn); + void setuint64(uint64_t n); + void setuint256(uint256 n); + uint256 getuint256() const; + void setvch(const std::vector& vch); + std::vector getvch() const; + void SetDec(const std::string& str); + void SetHex(const std::string& str); + bool SetHexBool(const std::string& str); + std::string ToString(int nBase=10) const; + std::string GetHex() const; + std::string GetDec() const; unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const { @@ -419,71 +122,36 @@ class CBigNum * @param e the exponent as an int * @return */ - CBigNum pow(const int e) const { - return this->pow(CBigNum(e)); - } + CBigNum pow(const int e) const ; /** * exponentiation this^e * @param e the exponent * @return */ - CBigNum pow(const CBigNum& e) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_exp(ret.bn, bn, e.bn, pctx)) - throw bignum_error("CBigNum::pow : BN_exp failed"); - return ret; - } + CBigNum pow(const CBigNum& e) const; /** * modular multiplication: (this * b) mod m * @param b operand * @param m modulus */ - CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_mod_mul(ret.bn, bn, b.bn, m.bn, pctx)) - throw bignum_error("CBigNum::mul_mod : BN_mod_mul failed"); - - return ret; - } + CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const; /** * modular exponentiation: this^e mod n * @param e exponent * @param m modulus */ - CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if( e < 0){ - // g^-x = (g^-1)^x - CBigNum inv = this->inverse(m); - CBigNum posE = e * -1; - if (!BN_mod_exp(ret.bn, inv.bn, posE.bn, m.bn, pctx)) - throw bignum_error("CBigNum::pow_mod: BN_mod_exp failed on negative exponent"); - }else - if (!BN_mod_exp(ret.bn, bn, e.bn, m.bn, pctx)) - throw bignum_error("CBigNum::pow_mod : BN_mod_exp failed"); + CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const; - return ret; - } - - /** + /** * Calculates the inverse of this element mod m. * i.e. i such this*i = 1 mod m * @param m the modu * @return the inverse */ - CBigNum inverse(const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_mod_inverse(ret.bn, bn, m.bn, pctx)) - throw bignum_error("CBigNum::inverse*= :BN_mod_inverse"); - return ret; - } + CBigNum inverse(const CBigNum& m) const; /** * Generates a random (safe) prime of numBits bits @@ -491,144 +159,41 @@ class CBigNum * @param safe true for a safe prime * @return the prime */ - static CBigNum generatePrime(const unsigned int numBits, bool safe = false) { - CBigNum ret; - if(!BN_generate_prime_ex(ret.bn, numBits, (safe == true), NULL, NULL, NULL)) - throw bignum_error("CBigNum::generatePrime*= :BN_generate_prime_ex"); - return ret; - } + static CBigNum generatePrime(const unsigned int numBits, bool safe = false); /** * Calculates the greatest common divisor (GCD) of two numbers. * @param m the second element * @return the GCD */ - CBigNum gcd( const CBigNum& b) const{ - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_gcd(ret.bn, bn, b.bn, pctx)) - throw bignum_error("CBigNum::gcd*= :BN_gcd"); - return ret; - } + CBigNum gcd( const CBigNum& b) const; - /** + /** * Miller-Rabin primality test on this element * @param checks: optional, the number of Miller-Rabin tests to run * default causes error rate of 2^-80. * @return true if prime */ - bool isPrime(const int checks=BN_prime_checks) const { - CAutoBN_CTX pctx; - int ret = BN_is_prime_ex(bn, checks, pctx, NULL); - if(ret < 0){ - throw bignum_error("CBigNum::isPrime :BN_is_prime"); - } - return ret; - } - - bool isOne() const { - return BN_is_one(bn); - } - - - - bool operator!() const - { - return BN_is_zero(bn); - } - - 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) - { - if (!BN_sub(bn, bn, b.bn)) - throw bignum_error("CBigNum::operator-= : BN_sub failed"); - 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) - { - bn = 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"); - bn = r.bn; - return *this; - } +#if defined(USE_NUM_OPENSSL) + bool isPrime(const int checks=BN_prime_checks) const; +#endif +#if defined(USE_NUM_GMP) + bool isPrime(const int checks=15) const; +#endif - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } + bool isOne() const; + bool operator!() const; + 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); @@ -645,562 +210,140 @@ class CBigNum friend inline bool operator>(const CBigNum& a, const CBigNum& b); }; -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +#if defined(USE_NUM_OPENSSL) +class CAutoBN_CTX { +protected: + BN_CTX* pctx; + 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); + } + + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } +}; + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) { CBigNum r; if (!BN_add(r.bn, a.bn, b.bn)) throw bignum_error("CBigNum::operator+ : BN_add failed"); return r; } - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) { CBigNum r; if (!BN_sub(r.bn, a.bn, b.bn)) throw bignum_error("CBigNum::operator- : BN_sub failed"); return r; } - -inline const CBigNum operator-(const CBigNum& a) -{ +inline const CBigNum operator-(const CBigNum& a) { CBigNum r(a); BN_set_negative(r.bn, !BN_is_negative(r.bn)); return r; } - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_mul(r.bn, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator* : BN_mul failed"); return r; } - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_div(r.bn, NULL, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator/ : BN_div failed"); return r; } - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_nnmod(r.bn, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator% : BN_div failed"); return r; } - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) { CBigNum r; if (!BN_lshift(r.bn, a.bn, shift)) throw bignum_error("CBigNum:operator<< : BN_lshift failed"); return r; } - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) { CBigNum r = a; r >>= shift; return r; } - inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); } inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); } inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); } inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); } inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); } inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); } -inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } - #endif -#if defined(USE_NUM_GMP) -/** C++ wrapper for BIGNUM (Gmp bignum) */ -class CBigNum -{ - mpz_t bn; -public: - CBigNum() - { - mpz_init(bn); - } - CBigNum(const CBigNum& b) - { - mpz_init(bn); - mpz_set(bn, b.bn); - } - - CBigNum& operator=(const CBigNum& b) - { - mpz_set(bn, b.bn); - return (*this); - } - - ~CBigNum() - { - mpz_clear(bn); - } - - //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(short n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(int n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(long n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(long long n) { mpz_init(bn); mpz_set_si(bn, n); } - CBigNum(unsigned char n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned short n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned int n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned long n) { mpz_init(bn); mpz_set_ui(bn, n); } - - explicit CBigNum(uint256 n) { mpz_init(bn); setuint256(n); } - - explicit CBigNum(const std::vector& vch) - { - mpz_init(bn); - setvch(vch); - } - - /** Generates a cryptographically secure random number between zero and range exclusive - * i.e. 0 < returned number < range - * @param range The upper bound on the number. - * @return - */ - static CBigNum randBignum(const CBigNum& range) { - size_t size = (mpz_sizeinbase (range.bn, 2) + CHAR_BIT-1) / CHAR_BIT; - std::vector buf(size); - - RandAddSeed(); - GetRandBytes(buf.data(), size); - - CBigNum ret(buf); - if (ret < 0) - mpz_neg(ret.bn, ret.bn); - return ret; - } - - /** Generates a cryptographically secure random k-bit number - * @param k The bit length of the number. - * @return - */ - static CBigNum RandKBitBigum(const uint32_t k){ - std::vector buf((k+7)/8); - - RandAddSeed(); - GetRandBytes(buf.data(), (k+7)/8); - - CBigNum ret(buf); - if (ret < 0) - mpz_neg(ret.bn, ret.bn); - return ret; - } - - /**Returns the size in bits of the underlying bignum. - * - * @return the size - */ - int bitSize() const{ - return mpz_sizeinbase(bn, 2); - } - - void setulong(unsigned long n) - { - mpz_set_ui(bn, n); - } - - unsigned long getulong() const - { - return mpz_get_ui(bn); - } - - unsigned int getuint() const - { - return mpz_get_ui(bn); - } - - int getint() const - { - unsigned long n = getulong(); - if (mpz_cmp(bn, CBigNum(0).bn) >= 0) { - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); - } else { - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); - } - } - - void setuint256(uint256 n) - { - mpz_import(bn, n.size(), -1, 1, 0, 0, (unsigned char*)&n); - } - - uint256 getuint256() const - { - if(bitSize() > 256){ - throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); - } - uint256 n = 0; - mpz_export((unsigned char*)&n, NULL, -1, 1, 0, 0, bn); - return n; - } - - void setvch(const std::vector& vch) - { - std::vector vch2 = vch; - unsigned char sign = 0; - if (vch2.size() > 0) { - sign = vch2[vch2.size()-1] & 0x80; - vch2[vch2.size()-1] = vch2[vch2.size()-1] & 0x7f; - mpz_import(bn, vch2.size(), -1, 1, 0, 0, &vch2[0]); - if (sign) - mpz_neg(bn, bn); - } - else { - mpz_set_si(bn, 0); - } - } - - std::vector getvch() const - { - if (mpz_cmp(bn, CBigNum(0).bn) == 0) { - return std::vector(0); - } - size_t size = (mpz_sizeinbase (bn, 2) + CHAR_BIT-1) / CHAR_BIT; - if (size <= 0) - return std::vector(); - std::vector v(size + 1); - mpz_export(&v[0], &size, -1, 1, 0, 0, bn); - if (v[v.size()-2] & 0x80) { - if (mpz_sgn(bn)<0) { - v[v.size()-1] = 0x80; - } else { - v[v.size()-1] = 0x00; - } - } else { - v.pop_back(); - if (mpz_sgn(bn)<0) { - v[v.size()-1] |= 0x80; - } - } - return v; - } - - void SetDec(const std::string& str) - { - const char* psz = str.c_str(); - mpz_set_str(bn, psz, 10); - } - - void SetHex(const std::string& str) - { - SetHexBool(str); - } - - bool SetHexBool(const std::string& str) - { - const char* psz = str.c_str(); - int ret = 1 + mpz_set_str(bn, psz, 16); - return (bool) ret; - } - - std::string ToString(int nBase=10) const - { - char* c_str = mpz_get_str(NULL, nBase, bn); - std::string str(c_str); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - std::string GetDec() const - { - return ToString(10); - } - - unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const - { - return ::GetSerializeSize(getvch(), nType, nVersion); - } - - template - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const - { - ::Serialize(s, getvch(), nType, nVersion); - } - - template - void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) - { - std::vector vch; - ::Unserialize(s, vch, nType, nVersion); - setvch(vch); - } - - /** - * exponentiation with an int. this^e - * @param e the exponent as an int - * @return - */ - CBigNum pow(const int e) const { - return this->pow(CBigNum(e)); - } - - /** - * exponentiation this^e - * @param e the exponent - * @return - */ - CBigNum pow(const CBigNum& e) const { - CBigNum ret; - long unsigned int ei = mpz_get_ui (e.bn); - mpz_pow_ui(ret.bn, bn, ei); - return ret; - } - - /** - * modular multiplication: (this * b) mod m - * @param b operand - * @param m modulus - */ - CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const { - CBigNum ret; - mpz_mul (ret.bn, bn, b.bn); - mpz_mod (ret.bn, ret.bn, m.bn); - return ret; - } - - /** - * modular exponentiation: this^e mod n - * @param e exponent - * @param m modulus - */ - CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const { - CBigNum ret; - if (e > CBigNum(0) && mpz_odd_p(m.bn)) - mpz_powm_sec (ret.bn, bn, e.bn, m.bn); - else - mpz_powm (ret.bn, bn, e.bn, m.bn); - return ret; - } - - /** - * Calculates the inverse of this element mod m. - * i.e. i such this*i = 1 mod m - * @param m the modu - * @return the inverse - */ - CBigNum inverse(const CBigNum& m) const { - CBigNum ret; - mpz_invert(ret.bn, bn, m.bn); - return ret; - } - - /** - * Generates a random (safe) prime of numBits bits - * @param numBits the number of bits - * @param safe true for a safe prime - * @return the prime - */ - static CBigNum generatePrime(const unsigned int numBits, bool safe = false) { - CBigNum rand = RandKBitBigum(numBits); - CBigNum prime; - mpz_nextprime(prime.bn, rand.bn); - return prime; - } - - /** - * Calculates the greatest common divisor (GCD) of two numbers. - * @param m the second element - * @return the GCD - */ - CBigNum gcd( const CBigNum& b) const{ - CBigNum ret; - mpz_gcd(ret.bn, bn, b.bn); - return ret; - } - - /** - * Miller-Rabin primality test on this element - * @param checks: optional, the number of Miller-Rabin tests to run - * default causes error rate of 2^-80. - * @return true if prime - */ - bool isPrime(const int checks=15) const { - int ret = mpz_probab_prime_p(bn, checks); - return ret; - } - - bool isOne() const - { - return mpz_cmp(bn, CBigNum(1).bn) == 0; - } - - bool operator!() const - { - return mpz_cmp(bn, CBigNum(0).bn) == 0; - } - - CBigNum& operator+=(const CBigNum& b) - { - mpz_add(bn, bn, b.bn); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - mpz_sub(bn, bn, b.bn); - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - mpz_mul(bn, bn, b.bn); - 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) - { - mpz_mul_2exp(bn, bn, shift); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - mpz_div_2exp(bn, bn, shift); - return *this; - } - - - CBigNum& operator++() - { - // prefix operator - mpz_add(bn, bn, CBigNum(1).bn); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - mpz_sub(bn, bn, CBigNum(1).bn); - return *this; - } - - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } - - friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator*(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator<<(const CBigNum& a, unsigned int shift); - friend inline const CBigNum operator-(const CBigNum& a); - friend inline bool operator==(const CBigNum& a, const CBigNum& b); - friend inline bool operator!=(const CBigNum& a, const CBigNum& b); - friend inline bool operator<=(const CBigNum& a, const CBigNum& b); - friend inline bool operator>=(const CBigNum& a, const CBigNum& b); - friend inline bool operator<(const CBigNum& a, const CBigNum& b); - friend inline bool operator>(const CBigNum& a, const CBigNum& b); -}; - -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) -{ +#if defined(USE_NUM_GMP) +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_add(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_sub(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator-(const CBigNum& a) -{ +inline const CBigNum operator-(const CBigNum& a) { CBigNum r; mpz_neg(r.bn, a.bn); return r; } - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_mul(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_tdiv_q(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_mmod(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) { CBigNum r; mpz_mul_2exp(r.bn, a.bn, shift); return r; } - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) { CBigNum r = a; r >>= shift; return r; } - inline bool operator==(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) == 0); } inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) != 0); } inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) <= 0); } inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) >= 0); } inline bool operator<(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) < 0); } inline bool operator>(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) > 0); } -inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } #endif -typedef CBigNum Bignum; - +inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } +typedef CBigNum Bignum; #endif diff --git a/src/libzerocoin/bignum_gmp.cpp b/src/libzerocoin/bignum_gmp.cpp new file mode 100644 index 00000000000000..395c916925674f --- /dev/null +++ b/src/libzerocoin/bignum_gmp.cpp @@ -0,0 +1,341 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-201 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +/** C++ wrapper for BIGNUM (Gmp bignum) */ +CBigNum::CBigNum() +{ + mpz_init(bn); +} + +CBigNum::CBigNum(const CBigNum& b) +{ + mpz_init(bn); + mpz_set(bn, b.bn); +} + +CBigNum& CBigNum::operator=(const CBigNum& b) +{ + mpz_set(bn, b.bn); + return (*this); +} + +CBigNum::~CBigNum() +{ + mpz_clear(bn); +} + +//CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. +CBigNum::CBigNum(signed char n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(short n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(int n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(long n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(long long n) { mpz_init(bn); mpz_set_si(bn, n); } +CBigNum::CBigNum(unsigned char n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned short n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned int n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned long n) { mpz_init(bn); mpz_set_ui(bn, n); } + +CBigNum::CBigNum(uint256 n) { mpz_init(bn); setuint256(n); } + +CBigNum::CBigNum(const std::vector& vch) +{ + mpz_init(bn); + setvch(vch); +} + +/** Generates a cryptographically secure random number between zero and range exclusive +* i.e. 0 < returned number < range +* @param range The upper bound on the number. +* @return +*/ +CBigNum CBigNum::randBignum(const CBigNum& range) +{ + size_t size = (mpz_sizeinbase (range.bn, 2) + CHAR_BIT-1) / CHAR_BIT; + std::vector buf(size); + + RandAddSeed(); + GetRandBytes(buf.data(), size); + + CBigNum ret(buf); + if (ret < 0) + mpz_neg(ret.bn, ret.bn); + return ret; +} + +/** Generates a cryptographically secure random k-bit number +* @param k The bit length of the number. +* @return +*/ +CBigNum CBigNum::RandKBitBigum(const uint32_t k) +{ + std::vector buf((k+7)/8); + + RandAddSeed(); + GetRandBytes(buf.data(), (k+7)/8); + + CBigNum ret(buf); + if (ret < 0) + mpz_neg(ret.bn, ret.bn); + return ret; +} + +/**Returns the size in bits of the underlying bignum. + * + * @return the size + */ +int CBigNum::bitSize() const +{ + return mpz_sizeinbase(bn, 2); +} + +void CBigNum::setulong(unsigned long n) +{ + mpz_set_ui(bn, n); +} + +unsigned long CBigNum::getulong() const +{ + return mpz_get_ui(bn); +} + +unsigned int CBigNum::getuint() const +{ + return mpz_get_ui(bn); +} + +int CBigNum::getint() const +{ + unsigned long n = getulong(); + if (mpz_cmp(bn, CBigNum(0).bn) >= 0) { + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); + } else { + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); + } +} + +void CBigNum::setuint256(uint256 n) +{ + mpz_import(bn, n.size(), -1, 1, 0, 0, (unsigned char*)&n); +} + +uint256 CBigNum::getuint256() const +{ + if(bitSize() > 256) { + throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); + } + uint256 n = uint256(0); + mpz_export((unsigned char*)&n, NULL, -1, 1, 0, 0, bn); + return n; +} + +void CBigNum::setvch(const std::vector& vch) +{ + std::vector vch2 = vch; + unsigned char sign = 0; + if (vch2.size() > 0) { + sign = vch2[vch2.size()-1] & 0x80; + vch2[vch2.size()-1] = vch2[vch2.size()-1] & 0x7f; + mpz_import(bn, vch2.size(), -1, 1, 0, 0, &vch2[0]); + if (sign) + mpz_neg(bn, bn); + } + else { + mpz_set_si(bn, 0); + } +} + +std::vector CBigNum::getvch() const +{ + if (mpz_cmp(bn, CBigNum(0).bn) == 0) { + return std::vector(0); + } + size_t size = (mpz_sizeinbase (bn, 2) + CHAR_BIT-1) / CHAR_BIT; + if (size <= 0) + return std::vector(); + std::vector v(size + 1); + mpz_export(&v[0], &size, -1, 1, 0, 0, bn); + if (v[v.size()-2] & 0x80) { + if (mpz_sgn(bn)<0) { + v[v.size()-1] = 0x80; + } else { + v[v.size()-1] = 0x00; + } + } else { + v.pop_back(); + if (mpz_sgn(bn)<0) { + v[v.size()-1] |= 0x80; + } + } + return v; +} + +void CBigNum::SetDec(const std::string& str) +{ + const char* psz = str.c_str(); + mpz_set_str(bn, psz, 10); +} + +bool CBigNum::SetHexBool(const std::string& str) +{ + const char* psz = str.c_str(); + int ret = 1 + mpz_set_str(bn, psz, 16); + return (bool) ret; +} + +std::string CBigNum::ToString(int nBase) const +{ + char* c_str = mpz_get_str(NULL, nBase, bn); + std::string str(c_str); + return str; +} + +/** + * exponentiation this^e + * @param e the exponent + * @return + */ +CBigNum CBigNum::pow(const CBigNum& e) const +{ + CBigNum ret; + long unsigned int ei = mpz_get_ui (e.bn); + mpz_pow_ui(ret.bn, bn, ei); + return ret; +} + +/** + * modular multiplication: (this * b) mod m + * @param b operand + * @param m modulus + */ +CBigNum CBigNum::mul_mod(const CBigNum& b, const CBigNum& m) const +{ + CBigNum ret; + mpz_mul (ret.bn, bn, b.bn); + mpz_mod (ret.bn, ret.bn, m.bn); + return ret; +} + +/** + * modular exponentiation: this^e mod n + * @param e exponent + * @param m modulus + */ +CBigNum CBigNum::pow_mod(const CBigNum& e, const CBigNum& m) const +{ + CBigNum ret; + if (e > CBigNum(0) && mpz_odd_p(m.bn)) + mpz_powm_sec (ret.bn, bn, e.bn, m.bn); + else + mpz_powm (ret.bn, bn, e.bn, m.bn); + return ret; +} + +/** +* Calculates the inverse of this element mod m. +* i.e. i such this*i = 1 mod m +* @param m the modu +* @return the inverse +*/ +CBigNum CBigNum::inverse(const CBigNum& m) const +{ + CBigNum ret; + mpz_invert(ret.bn, bn, m.bn); + return ret; +} + +/** + * Generates a random (safe) prime of numBits bits + * @param numBits the number of bits + * @param safe true for a safe prime + * @return the prime + */ +CBigNum CBigNum::generatePrime(const unsigned int numBits, bool safe) +{ + CBigNum rand = RandKBitBigum(numBits); + CBigNum prime; + mpz_nextprime(prime.bn, rand.bn); + return prime; +} + +/** + * Calculates the greatest common divisor (GCD) of two numbers. + * @param m the second element + * @return the GCD + */ +CBigNum CBigNum::gcd( const CBigNum& b) const +{ + CBigNum ret; + mpz_gcd(ret.bn, bn, b.bn); + return ret; +} + +/** +* Miller-Rabin primality test on this element +* @param checks: optional, the number of Miller-Rabin tests to run +* default causes error rate of 2^-80. +* @return true if prime +*/ +bool CBigNum::isPrime(const int checks) const +{ + int ret = mpz_probab_prime_p(bn, checks); + return ret; +} + +bool CBigNum::isOne() const +{ + return mpz_cmp(bn, CBigNum(1).bn) == 0; +} + +bool CBigNum::operator!() const +{ + return mpz_cmp(bn, CBigNum(0).bn) == 0; +} + +CBigNum& CBigNum::operator+=(const CBigNum& b) +{ + mpz_add(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator-=(const CBigNum& b) +{ + mpz_sub(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator*=(const CBigNum& b) +{ + mpz_mul(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator<<=(unsigned int shift) +{ + mpz_mul_2exp(bn, bn, shift); + return *this; +} + +CBigNum& CBigNum::operator>>=(unsigned int shift) +{ + mpz_div_2exp(bn, bn, shift); + return *this; +} + +CBigNum& CBigNum::operator++() +{ + // prefix operator + mpz_add(bn, bn, CBigNum(1).bn); + return *this; +} + +CBigNum& CBigNum::operator--() +{ + // prefix operator + mpz_sub(bn, bn, CBigNum(1).bn); + return *this; +} diff --git a/src/libzerocoin/bignum_openssl.cpp b/src/libzerocoin/bignum_openssl.cpp new file mode 100644 index 00000000000000..8e692433d14d91 --- /dev/null +++ b/src/libzerocoin/bignum_openssl.cpp @@ -0,0 +1,508 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-2019 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +CBigNum::CBigNum() +{ + bn = BN_new(); +} + +CBigNum::CBigNum(const CBigNum& b) +{ + bn = BN_new(); + if (!BN_copy(bn, b.bn)) + { + BN_clear_free(bn); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } +} + +CBigNum& CBigNum::operator=(const CBigNum& b) +{ + if (!BN_copy(bn, b.bn)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); +} + +CBigNum::~CBigNum() +{ + BN_clear_free(bn); +} + +//CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. +CBigNum::CBigNum(signed char n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(short n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(int n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(long n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(long long n) { bn = BN_new(); setint64(n); } +CBigNum::CBigNum(unsigned char n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned short n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned int n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned long n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned long long n) { bn = BN_new(); setuint64(n); } +CBigNum::CBigNum(uint256 n) { bn = BN_new(); setuint256(n); } + +CBigNum::CBigNum(const std::vector& vch) +{ + bn = BN_new(); + setvch(vch); +} + +/** Generates a cryptographically secure random number between zero and range exclusive +* i.e. 0 < returned number < range +* @param range The upper bound on the number. +* @return +*/ +CBigNum CBigNum::randBignum(const CBigNum& range) +{ + CBigNum ret; + if(!BN_rand_range(ret.bn, range.bn)){ + throw bignum_error("CBigNum:rand element : BN_rand_range failed"); + } + return ret; +} + +/** Generates a cryptographically secure random k-bit number +* @param k The bit length of the number. +* @return +*/ +CBigNum CBigNum::RandKBitBigum(const uint32_t k) +{ + CBigNum ret; + if(!BN_rand(ret.bn, k, -1, 0)){ + throw bignum_error("CBigNum:rand element : BN_rand failed"); + } + return ret; +} + +/**Returns the size in bits of the underlying bignum. + * + * @return the size + */ +int CBigNum::bitSize() const +{ + return BN_num_bits(bn); +} + +void CBigNum::setulong(unsigned long n) +{ + if (!BN_set_word(bn, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); +} + +unsigned long CBigNum::getulong() const +{ + return BN_get_word(bn); +} + +unsigned int CBigNum::getuint() const +{ + return BN_get_word(bn); +} + +int CBigNum::getint() const +{ + unsigned long n = BN_get_word(bn); + if (!BN_is_negative(bn)) + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); + else + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); +} + +void CBigNum::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, bn); +} + +void CBigNum::setuint64(uint64_t n) +{ + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + 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++ = 0; + 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, bn); +} + +void CBigNum::setuint256(uint256 n) +{ + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + unsigned char* pbegin = (unsigned char*)&n; + unsigned char* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + unsigned char c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + 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 >> 0) & 0xff; + BN_mpi2bn(pch, p - pch, bn); +} + +uint256 CBigNum::getuint256() const +{ + if(bitSize() > 256) { + throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); + } + 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 (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; +} + +void CBigNum::setvch(const std::vector& vch) +{ + std::vector 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(), bn); +} + +std::vector CBigNum::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); + reverse(vch.begin(), vch.end()); + return vch; +} + +void CBigNum::SetDec(const std::string& str) +{ + BN_dec2bn(&bn, str.c_str()); +} + +bool CBigNum::SetHexBool(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[(unsigned char)*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + + return true; +} + + +std::string CBigNum::ToString(int nBase) const +{ + CAutoBN_CTX pctx; + CBigNum bnBase = nBase; + CBigNum bn0 = 0; + CBigNum locBn = *this; + std::string str; + BN_set_negative(locBn.bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(locBn.bn, bn0.bn) == 0) + return "0"; + while (BN_cmp(locBn.bn, bn0.bn) > 0) + { + if (!BN_div(dv.bn, rem.bn, locBn.bn, bnBase.bn, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + locBn = dv; + unsigned int c = rem.getulong(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(bn)) + str += "-"; + reverse(str.begin(), str.end()); + return str; +} + +/** + * exponentiation this^e + * @param e the exponent + * @return + */ +CBigNum CBigNum::pow(const CBigNum& e) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_exp(ret.bn, bn, e.bn, pctx)) + throw bignum_error("CBigNum::pow : BN_exp failed"); + return ret; +} + +/** + * modular multiplication: (this * b) mod m + * @param b operand + * @param m modulus + */ +CBigNum CBigNum::mul_mod(const CBigNum& b, const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_mod_mul(ret.bn, bn, b.bn, m.bn, pctx)) + throw bignum_error("CBigNum::mul_mod : BN_mod_mul failed"); + + return ret; +} + +/** + * modular exponentiation: this^e mod n + * @param e exponent + * @param m modulus + */ +CBigNum CBigNum::pow_mod(const CBigNum& e, const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if( e < 0){ + // g^-x = (g^-1)^x + CBigNum inv = this->inverse(m); + CBigNum posE = e * -1; + if (!BN_mod_exp(ret.bn, inv.bn, posE.bn, m.bn, pctx)) + throw bignum_error("CBigNum::pow_mod: BN_mod_exp failed on negative exponent"); + }else + if (!BN_mod_exp(ret.bn, bn, e.bn, m.bn, pctx)) + throw bignum_error("CBigNum::pow_mod : BN_mod_exp failed"); + + return ret; +} + +/** +* Calculates the inverse of this element mod m. +* i.e. i such this*i = 1 mod m +* @param m the modu +* @return the inverse +*/ +CBigNum CBigNum::inverse(const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_mod_inverse(ret.bn, bn, m.bn, pctx)) + throw bignum_error("CBigNum::inverse*= :BN_mod_inverse"); + return ret; +} + +/** + * Generates a random (safe) prime of numBits bits + * @param numBits the number of bits + * @param safe true for a safe prime + * @return the prime + */ +CBigNum CBigNum::generatePrime(const unsigned int numBits, bool safe) +{ + CBigNum ret; + if(!BN_generate_prime_ex(ret.bn, numBits, (safe == true), NULL, NULL, NULL)) + throw bignum_error("CBigNum::generatePrime*= :BN_generate_prime_ex"); + return ret; +} + +/** + * Calculates the greatest common divisor (GCD) of two numbers. + * @param m the second element + * @return the GCD + */ +CBigNum CBigNum::gcd( const CBigNum& b) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_gcd(ret.bn, bn, b.bn, pctx)) + throw bignum_error("CBigNum::gcd*= :BN_gcd"); + return ret; +} + +/** +* Miller-Rabin primality test on this element +* @param checks: optional, the number of Miller-Rabin tests to run +* default causes error rate of 2^-80. +* @return true if prime +*/ +bool CBigNum::isPrime(const int checks) const +{ + CAutoBN_CTX pctx; + int ret = BN_is_prime_ex(bn, checks, pctx, NULL); + if(ret < 0){ + throw bignum_error("CBigNum::isPrime :BN_is_prime"); + } + return ret; +} + +bool CBigNum::isOne() const +{ + return BN_is_one(bn); +} + +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) +{ + if (!BN_sub(bn, bn, b.bn)) + throw bignum_error("CBigNum::operator-= : BN_sub failed"); + 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<<=(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) + { + bn = 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"); + bn = r.bn; + return *this; +}