diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj index e1aaf544cc..70a2c5b51f 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj +++ b/Builds/VisualStudio2015/RippleD.vcxproj @@ -2079,20 +2079,12 @@ - - - - - - True - True - True True @@ -2137,10 +2129,6 @@ - - True - True - True True diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters index 20e2439c7f..472d40ac00 100644 --- a/Builds/VisualStudio2015/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters @@ -2604,12 +2604,6 @@ ripple\core - - ripple\crypto - - - ripple\crypto - ripple\crypto @@ -2619,9 +2613,6 @@ ripple\crypto - - ripple\crypto\impl - ripple\crypto\impl @@ -2664,9 +2655,6 @@ ripple\crypto - - ripple\crypto\tests - ripple\crypto\tests diff --git a/src/ripple/crypto/CAutoBN_CTX.h b/src/ripple/crypto/CAutoBN_CTX.h deleted file mode 100644 index 7db906c81f..0000000000 --- a/src/ripple/crypto/CAutoBN_CTX.h +++ /dev/null @@ -1,80 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#ifndef RIPPLE_CRYPTO_CAUTOBN_CTX_H_INCLUDED -#define RIPPLE_CRYPTO_CAUTOBN_CTX_H_INCLUDED - -#include - -#include - -#include -#include - -namespace ripple { - -class CAutoBN_CTX -{ -protected: - BN_CTX* pctx; - -public: - CAutoBN_CTX () - { - pctx = BN_CTX_new (); - - if (pctx == nullptr) - Throw ("CAutoBN_CTX : BN_CTX_new() returned nullptr"); - } - - ~CAutoBN_CTX () - { - if (pctx != nullptr) - BN_CTX_free (pctx); - } - - CAutoBN_CTX (CAutoBN_CTX const&) = delete; - CAutoBN_CTX& operator= (CAutoBN_CTX const&) = delete; - - operator BN_CTX* () - { - return pctx; - } - BN_CTX& operator* () - { - return *pctx; - } - BN_CTX** operator& () - { - return &pctx; - } - bool operator! () - { - return (pctx == nullptr); - } -}; - -} - -#endif diff --git a/src/ripple/crypto/CBigNum.h b/src/ripple/crypto/CBigNum.h deleted file mode 100644 index 213bfb9ae1..0000000000 --- a/src/ripple/crypto/CBigNum.h +++ /dev/null @@ -1,119 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#ifndef RIPPLE_CRYPTO_CBIGNUM_H_INCLUDED -#define RIPPLE_CRYPTO_CBIGNUM_H_INCLUDED - -#include -#include - -namespace ripple { - -// VFALCO TODO figure out a way to remove the dependency on openssl in the -// header. Maybe rewrite this to use cryptopp. - -class CBigNum : public BIGNUM -{ -public: - CBigNum (); - CBigNum (const CBigNum& b); - CBigNum& operator= (const CBigNum& b); - CBigNum (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 long n); - explicit CBigNum (uint256 n); - explicit CBigNum (Blob const& vch); - explicit CBigNum (BIGNUM const* b); - CBigNum (unsigned char const* begin, unsigned char const* end); - ~CBigNum (); - - void setuint (unsigned int n); - unsigned int getuint () const; - int getint () const; - void setint64 (std::int64_t n); - std::uint64_t getuint64 () const; - void setuint64 (std::uint64_t n); - void setuint256 (uint256 const& n); - uint256 getuint256 (); - void setvch (unsigned char const* begin, unsigned char const* end); - void setvch (Blob const& vch); - Blob getvch () const; - CBigNum& SetCompact (unsigned int nCompact); - unsigned int GetCompact () const; - void SetHex (std::string const& str); - std::string ToString (int nBase = 10) const; - std::string GetHex () 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++ (); - CBigNum& operator-- (); - const CBigNum operator++ (int); - const CBigNum operator-- (int); - -private: - // private because the size of an unsigned long varies by platform - - void setulong (unsigned long n); - unsigned long getulong () const; -}; - -const CBigNum operator+ (const CBigNum& a, const CBigNum& b); -const CBigNum operator- (const CBigNum& a, const CBigNum& b); -const CBigNum operator- (const CBigNum& a); -const CBigNum operator* (const CBigNum& a, const CBigNum& b); -const CBigNum operator/ (const CBigNum& a, const CBigNum& b); -const CBigNum operator% (const CBigNum& a, const CBigNum& b); -const CBigNum operator<< (const CBigNum& a, unsigned int shift); -const CBigNum operator>> (const CBigNum& a, unsigned int shift); - -bool operator== (const CBigNum& a, const CBigNum& b); -bool operator!= (const CBigNum& a, const CBigNum& b); -bool operator<= (const CBigNum& a, const CBigNum& b); -bool operator>= (const CBigNum& a, const CBigNum& b); -bool operator< (const CBigNum& a, const CBigNum& b); -bool operator> (const CBigNum& a, const CBigNum& b); - -//------------------------------------------------------------------------------ - -// Only STAmount uses these (January 2016). -int BN_add_word64 (BIGNUM* a, std::uint64_t w); -int BN_sub_word64 (BIGNUM* a, std::uint64_t w); -int BN_mul_word64 (BIGNUM* a, std::uint64_t w); -int BN_div_word64 (BIGNUM* a, std::uint64_t w); - -} - -#endif diff --git a/src/ripple/crypto/impl/CBigNum.cpp b/src/ripple/crypto/impl/CBigNum.cpp deleted file mode 100644 index 44aa8fed2f..0000000000 --- a/src/ripple/crypto/impl/CBigNum.cpp +++ /dev/null @@ -1,689 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -CBigNum::CBigNum () -{ - BN_init (this); -} - -CBigNum::CBigNum (const CBigNum& b) -: CBigNum (&b) -{ } - -CBigNum& CBigNum::operator= (const CBigNum& b) -{ - if (!BN_copy (this, &b)) - Throw ("CBigNum::operator= : BN_copy failed"); - - return (*this); -} - -CBigNum::~CBigNum () -{ - BN_clear_free (this); -} - -CBigNum::CBigNum (char n) -{ - BN_init (this); - - if (n >= 0) setulong (n); - else setint64 (n); -} -CBigNum::CBigNum (short n) -{ - BN_init (this); - - if (n >= 0) setulong (n); - else setint64 (n); -} -CBigNum::CBigNum (int n) -{ - BN_init (this); - - if (n >= 0) setulong (n); - else setint64 (n); -} -CBigNum::CBigNum (long n) -{ - BN_init (this); - - if (n >= 0) setulong (n); - else setint64 (n); -} -CBigNum::CBigNum (long long n) -{ - BN_init (this); - setint64 (n); -} -CBigNum::CBigNum (unsigned char n) -{ - BN_init (this); - setulong (n); -} -CBigNum::CBigNum (unsigned short n) -{ - BN_init (this); - setulong (n); -} -CBigNum::CBigNum (unsigned int n) -{ - BN_init (this); - setulong (n); -} -CBigNum::CBigNum (unsigned long long n) -{ - BN_init (this); - setuint64 (n); -} -CBigNum::CBigNum (uint256 n) -{ - BN_init (this); - setuint256 (n); -} - -CBigNum::CBigNum (Blob const& vch) -{ - BN_init (this); - setvch (&vch.front(), &vch.back()+1); -} - -CBigNum::CBigNum (BIGNUM const* b) -{ - BN_init (this); - - if (!BN_copy (this, b)) - { - BN_clear_free (this); - Throw ("CBigNum::CBigNum(BIGNUM const* b) : BN_copy failed"); - } -} - -CBigNum::CBigNum (unsigned char const* begin, unsigned char const* end) -{ - BN_init (this); - setvch (begin, end); -} - -void CBigNum::setuint (unsigned int n) -{ - setulong (static_cast (n)); -} - -unsigned int CBigNum::getuint () const -{ - return BN_get_word (this); -} - -int CBigNum::getint () const -{ - unsigned long n = BN_get_word (this); - - if (!BN_is_negative (this)) - return (n > INT_MAX ? INT_MAX : n); - else - return (n > INT_MAX ? INT_MIN : - (int)n); -} - -void CBigNum::setint64 (std::int64_t n) -{ - unsigned char pch[sizeof (n) + 6]; - unsigned char* p = pch + 4; - bool fNegative = false; - - if (n < (std::int64_t)0) - { - n = -n; - fNegative = true; - } - - bool fLeadingZeroes = true; - - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - - if (fLeadingZeroes) - { - if (c == 0) - continue; - - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - - fLeadingZeroes = false; - } - - *p++ = c; - } - - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn (pch, p - pch, this); -} - -std::uint64_t CBigNum::getuint64 () const -{ -#if (ULONG_MAX > UINT_MAX) - return static_cast (getulong ()); -#else - int len = BN_num_bytes (this); - - if (len > 8) - Throw ("BN getuint64 overflow"); - - unsigned char buf[8]; - memset (buf, 0, sizeof (buf)); - BN_bn2bin (this, buf + 8 - len); - return - static_cast (buf[0]) << 56 | static_cast (buf[1]) << 48 | - static_cast (buf[2]) << 40 | static_cast (buf[3]) << 32 | - static_cast (buf[4]) << 24 | static_cast (buf[5]) << 16 | - static_cast (buf[6]) << 8 | static_cast (buf[7]); -#endif -} - -void CBigNum::setuint64 (std::uint64_t n) -{ -#if (ULONG_MAX > UINT_MAX) - setulong (static_cast (n)); -#else - unsigned char buf[8]; - buf[0] = static_cast ((n >> 56) & 0xff); - buf[1] = static_cast ((n >> 48) & 0xff); - buf[2] = static_cast ((n >> 40) & 0xff); - buf[3] = static_cast ((n >> 32) & 0xff); - buf[4] = static_cast ((n >> 24) & 0xff); - buf[5] = static_cast ((n >> 16) & 0xff); - buf[6] = static_cast ((n >> 8) & 0xff); - buf[7] = static_cast ((n) & 0xff); - BN_bin2bn (buf, 8, this); -#endif -} - -void CBigNum::setuint256 (uint256 const& n) -{ - BN_bin2bn (n.begin (), n.size (), this); -} - -uint256 CBigNum::getuint256 () -{ - uint256 ret; - unsigned int size = BN_num_bytes (this); - - if (size > ret.size ()) - return ret; - - BN_bn2bin (this, ret.begin () + (ret.size () - BN_num_bytes (this))); - return ret; -} - -void CBigNum::setvch (unsigned char const* begin, unsigned char const* end) -{ - std::size_t const size (std::distance (begin, end)); - Blob vch2 (size + 4); - unsigned int nSize (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 (begin, end, vch2.begin() + 4); - BN_mpi2bn (&vch2[0], vch2.size (), this); -} - -void CBigNum::setvch (Blob const& vch) -{ - setvch (&vch.front(), &vch.back()+1); -} - -Blob CBigNum::getvch () const -{ - unsigned int nSize = BN_bn2mpi (this, nullptr); - - if (nSize < 4) - return Blob (); - - Blob vch (nSize); - BN_bn2mpi (this, &vch[0]); - vch.erase (vch.begin (), vch.begin () + 4); - reverse (vch.begin (), vch.end ()); - return vch; -} - -CBigNum& CBigNum::SetCompact (unsigned int nCompact) -{ - unsigned int nSize = nCompact >> 24; - Blob 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], vch.size (), this); - return *this; -} - -unsigned int CBigNum::GetCompact () const -{ - unsigned int nSize = BN_bn2mpi (this, nullptr); - Blob vch (nSize); - nSize -= 4; - BN_bn2mpi (this, &vch[0]); - unsigned int 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 (std::string const& 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 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[ (int) * 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, false); - CBigNum dv; - CBigNum rem; - - if (BN_cmp (&bn, &bn0) == 0) - return "0"; - - while (BN_cmp (&bn, &bn0) > 0) - { - if (!BN_div (&dv, &rem, &bn, &bnBase, pctx)) - Throw ("CBigNum::ToString() : BN_div failed"); - - bn = dv; - unsigned int c = rem.getuint (); - str += "0123456789abcdef"[c]; - } - - if (BN_is_negative (this)) - str += "-"; - - reverse (str.begin (), str.end ()); - return str; -} - -std::string CBigNum::GetHex () const -{ - return ToString (16); -} - -bool CBigNum::operator! () const -{ - return BN_is_zero (this); -} - -CBigNum& CBigNum::operator+= (const CBigNum& b) -{ - if (!BN_add (this, this, &b)) - Throw ("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 (this, this, &b, pctx)) - Throw ("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 (this, this, shift)) - Throw ("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, this) > 0) - { - *this = 0; - return *this; - } - - if (! BN_rshift (this, this, shift)) - Throw ("CBigNum:operator>>= : BN_rshift failed"); - - return *this; -} - - -CBigNum& CBigNum::operator++ () -{ - // prefix operator - if (! BN_add (this, this, BN_value_one ())) - Throw ("CBigNum::operator++ : BN_add failed"); - - return *this; -} - -const CBigNum CBigNum::operator++ (int) -{ - // postfix operator - const CBigNum ret = *this; - ++ (*this); - return ret; -} - -CBigNum& CBigNum::operator-- () -{ - // prefix operator - CBigNum r; - - if (! BN_sub (&r, this, BN_value_one ())) - Throw ("CBigNum::operator-- : BN_sub failed"); - - *this = r; - return *this; -} - -const CBigNum CBigNum::operator-- (int) -{ - // postfix operator - const CBigNum ret = *this; - -- (*this); - return ret; -} - -void CBigNum::setulong (unsigned long n) -{ - if (! BN_set_word (this, n)) - Throw ( - "CBigNum conversion from unsigned long : BN_set_word failed"); -} - -unsigned long CBigNum::getulong () const -{ - return BN_get_word (this); -} - -const CBigNum operator+ (const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - - if (! BN_add (&r, &a, &b)) - Throw ("CBigNum::operator+ : BN_add failed"); - - return r; -} - -const CBigNum operator- (const CBigNum& a, const CBigNum& b) -{ - CBigNum r; - - if (! BN_sub (&r, &a, &b)) - Throw ("CBigNum::operator- : BN_sub failed"); - - return r; -} - -const CBigNum operator- (const CBigNum& a) -{ - CBigNum r (a); - BN_set_negative (&r, !BN_is_negative (&r)); - return r; -} - -const CBigNum operator* (const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - - if (! BN_mul (&r, &a, &b, pctx)) - Throw ("CBigNum::operator* : BN_mul failed"); - - return r; -} - -const CBigNum operator/ (const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - - if (! BN_div (&r, nullptr, &a, &b, pctx)) - Throw ("CBigNum::operator/ : BN_div failed"); - - return r; -} - -const CBigNum operator% (const CBigNum& a, const CBigNum& b) -{ - CAutoBN_CTX pctx; - CBigNum r; - - if (! BN_mod (&r, &a, &b, pctx)) - Throw ("CBigNum::operator% : BN_div failed"); - - return r; -} - -const CBigNum operator<< (const CBigNum& a, unsigned int shift) -{ - CBigNum r; - - if (! BN_lshift (&r, &a, shift)) - Throw ("CBigNum:operator<< : BN_lshift failed"); - - return r; -} - -const CBigNum operator>> (const CBigNum& a, unsigned int shift) -{ - CBigNum r = a; - r >>= shift; - return r; -} - -bool operator== (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) == 0); -} - -bool operator!= (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) != 0); -} - -bool operator<= (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) <= 0); -} - -bool operator>= (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) >= 0); -} - -bool operator< (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) < 0); -} - -bool operator> (const CBigNum& a, const CBigNum& b) -{ - return (BN_cmp (&a, &b) > 0); -} - -#if (ULONG_MAX > UINT_MAX) - -int BN_add_word64 (BIGNUM* bn, std::uint64_t word) -{ - return BN_add_word (bn, word); -} - -int BN_sub_word64 (BIGNUM* bn, std::uint64_t word) -{ - return BN_sub_word (bn, word); -} - -int BN_mul_word64 (BIGNUM* bn, std::uint64_t word) -{ - return BN_mul_word (bn, word); -} - -// This function returns 1 on success like the three preceding functions. -// In contrast, BN_div_word returns ( BN_ULONG )-1 on error. -int BN_div_word64 (BIGNUM* bn, std::uint64_t word) -{ - BN_ULONG const remainder {BN_div_word (bn, word)}; - return remainder == static_cast(-1) ? 0 : 1; -} - -#else - -int BN_add_word64 (BIGNUM* a, std::uint64_t w) -{ - CBigNum bn (w); - return BN_add (a, a, &bn); -} - -int BN_sub_word64 (BIGNUM* a, std::uint64_t w) -{ - CBigNum bn (w); - return BN_sub (a, a, &bn); -} - -int BN_mul_word64 (BIGNUM* a, std::uint64_t w) -{ - CBigNum bn (w); - CAutoBN_CTX ctx; - return BN_mul (a, a, &bn, ctx); -} - -int BN_div_word64 (BIGNUM* a, std::uint64_t w) -{ - CBigNum bn (w); - CBigNum temp (a); // Copy a. Destination may not be the same as dividend. - CAutoBN_CTX ctx; - return BN_div (a, nullptr, &temp, &bn, ctx); -} - -#endif - -} diff --git a/src/ripple/crypto/tests/CBigNum_test.cpp b/src/ripple/crypto/tests/CBigNum_test.cpp deleted file mode 100644 index a573312866..0000000000 --- a/src/ripple/crypto/tests/CBigNum_test.cpp +++ /dev/null @@ -1,580 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2016 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include - -namespace ripple { - -class CBigNum_test : public beast::unit_test::suite -{ -private: - // Generic test for constructing CBigNum from native types. - template - void - testNativeCtor() - { - static_assert (std::numeric_limits::is_integer, "Requires int type"); - if (std::numeric_limits::is_signed) - { - CBigNum const neg (static_cast(std::numeric_limits::min())); - this->expect (neg == std::numeric_limits::min()); - this->expect (neg < 0); - } - else - { - CBigNum const naught (static_cast(0)); - this->expect (naught == 0); - } - CBigNum const big (static_cast(std::numeric_limits::max())); - this->expect (big == std::numeric_limits::max()); - this->expect (big > 0); - } - - // Return pointer to start of array. - template - static auto - array_cbegin(T (&a)[N]) -> T const* - { - return &a[0]; - } - - // Return pointer to one past end of array. - template - static auto - array_cend(T (&a)[N]) -> T const* - { - return &a[N]; - } - -public: - void - run () - { - { - // Default constructor. - CBigNum const big0; - expect (big0 == 0); - // Construct from unsigned char. - CBigNum const big1 (static_cast(1)); - expect (big1 == 1); - // Assignment. - CBigNum bigA; - bigA = big1; - expect (bigA == big1); - } - { - // Test constructing from native types. - testNativeCtor(); - testNativeCtor(); - testNativeCtor(); - testNativeCtor(); - testNativeCtor(); - testNativeCtor(); - testNativeCtor(); -// testNativeCtor(); // unsigned long not supported - testNativeCtor(); - testNativeCtor(); - } - { - // Construction from uint256. - uint256 const naught256 (0); - uint256 big256 = naught256; - --big256; - CBigNum naught (naught256); - expect (naught == 0); - CBigNum big (big256); - expect (big.GetHex() == "ffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - } - { - // Construction from Blob. - Blob const naughtBlob (67, 0); - Blob const bigBlob (40, 255); - CBigNum const naught (naughtBlob); - expect (naught == 0); - CBigNum big (bigBlob); - expect (big.GetHex() == "-7fffffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - } - { - // Construction from BIGNUM*. - BIGNUM b; - BN_init (&b); - // Scope guard to free b when we leave scope. - std::shared_ptr guard (nullptr, [&b] (void*) - { - BN_clear_free (&b); - }); - expect (BN_set_word (&b, 0x123456789ABCDF0ull) == 1); - CBigNum big (&b); - --big; - expect (BN_cmp (&big, &b) == -1); - ++big; - expect (BN_cmp (&big, &b) == 0); - ++big; - expect (BN_cmp (&big, &b) == 1); - } - { - // Construction from unsigned char*. - static unsigned char const a[] {0x0,0xF, - 0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0}; - CBigNum big (array_cbegin(a), array_cend(a)); - expect (big.GetHex() == "102030405060708090a0b0c0d0e0f00"); - } - { - // setuint() and getuint(). - CBigNum big; - expect (big.getuint() == 0); - --big; - // Note that getuint() does not throw an exception on underflow. - expect (big.getuint() == 1); - - unsigned int const biggest_uint = - std::numeric_limits::max(); - big.setuint (biggest_uint); - expect (big.getuint() == biggest_uint); - // Note that getuint() does not throw an exception on overflow. - ++big; - expect (big.getuint() == 0); - } - { - // getint(). - CBigNum neg (std::numeric_limits::min()); - expect (neg.getint() == std::numeric_limits::min()); - // Note that getint() limits at INT_MIN on negative overflow. - --neg; - expect (neg.getint() == std::numeric_limits::min()); - - CBigNum pos (std::numeric_limits::max()); - expect (pos.getint() == std::numeric_limits::max()); - // Note that getint() limits at INT_MAX on positive overflow. - ++pos; - expect (pos.getint() == std::numeric_limits::max()); - } - { - // setint64(). - CBigNum big; - big.setint64 (std::numeric_limits::min()); - expect (big.GetHex() == "-8000000000000000"); - --big; - expect (big.GetHex() == "-8000000000000001"); - - big.setint64 (std::numeric_limits::max()); - expect (big.GetHex() == "7fffffffffffffff"); - ++big; - expect (big.GetHex() == "8000000000000000"); - } - { - // setuint64() and getuint64(). - CBigNum big; - big.setuint64 (static_cast(0)); - expect (big.getuint64() == 0); - // Note that getuint64() drops the sign. - --big; - expect (big.getuint64() == 1); - - big.setuint64 (std::numeric_limits::max()); - expect ( - big.getuint64() == std::numeric_limits::max()); - // Note that one some platforms getuint() throws on positive - // overflow and on other platforms it does not. Hence the macro. - ++big; -#if (ULONG_MAX > UINT_MAX) - expect ( - big.getuint64() == std::numeric_limits::max()); -#else - bool overflowException = false; - try - { - big.getuint64(); - } - catch (std::runtime_error const&) - { - overflowException = true; - } - expect (overflowException); -#endif - } - { - // setuint256() and getuint256(). - uint256 const naught256 (Blob (32, 0)); - uint256 const max256 (Blob (32, 0xFF)); - - CBigNum big; - big.setuint256(max256); - expect (big.GetHex() == "ffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffff"); - expect (big.getuint256() == max256); - - // Note that getuint256() returns zero on overflow. - ++big; - expect (big.GetHex() == "1000000000000000" - "0000000000000000000000000000000000000000000000000"); - expect (big.getuint256() == naught256); - - --big; - expect (big.getuint256() == max256); - - big.setuint256(naught256); - expect (big == 0); - expect (big.getuint256() == naught256); - --big; - expect (big == -1); - ++big; - expect (big.getuint256() == naught256); - } - { - // setvch() and getvch(). - CBigNum big; - expect (big.getvch().size() == 0); - - // Small values. - static unsigned char const one[] {1,0}; - big.setvch(array_cbegin(one), array_cend(one)); - expect (big == 1); - --big; - expect (big.getvch().size() == 0); - --big; - Blob smallBlob = big.getvch(); - expect (smallBlob.size() == 1); - expect (smallBlob[0] ==0x81); - smallBlob[0] = 0xff; - expect (big == -1); - big.setvch(smallBlob); - expect (big == -127); - expect (big.getvch().size() == 1); - - // Big values - static unsigned char const large[80] { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, - }; - static unsigned char const larger[81] { - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00 - }; - - big.setvch (array_cbegin(large), array_cend(large)); - CBigNum bigger; - bigger.setvch(array_cbegin(larger), array_cend(larger)); - expect (big > 0); - expect (big < bigger); - - Blob bigBlob = big.getvch(); - expect (bigBlob.size() == 80); - expect (bigBlob.back() == 0x7f); - - ++big; - expect (big == bigger); - bigBlob = big.getvch(); - expect (bigBlob.size() == 81); - expect (std::equal(array_cbegin(larger), array_cend(larger), - bigBlob.begin(), bigBlob.end())); - - bigBlob[0] = 1; - bigger.setvch(bigBlob); - expect (big < bigger); - ++big; - expect (big == bigger); - } - { - // GetCompact() and SetCompact(). - CBigNum big (0); - expect (big.GetCompact() == 0); - big.SetCompact (0x1010000); - expect (big == 1); - big.SetCompact (0x1810000); - expect (big == -1); - - // Positive values. - big.SetCompact (0x2010000); - expect (big.GetCompact() == 0x2010000); - ++big; - expect (big.GetCompact() == 0x2010100); - - big.SetCompact (0x3010000); - expect (big.GetCompact() == 0x3010000); - ++big; - expect (big.GetCompact() == 0x3010001); - - { - big.SetCompact (0x4010000); - expect (big.getuint64() == 0x1000000); - unsigned int const compact = big.GetCompact(); - ++big; - expect (compact == big.GetCompact()); - } - big.SetCompact (0xFF7FFFFF); - --big; - expect (big.GetCompact() == 0xFF7FFFFE); - expect (big.GetHex() == - "7ffffefffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffff"); - - // Negative values. - big.SetCompact (0x2810000); - expect (big.GetCompact() == 0x2810000); - --big; - expect (big.GetCompact() == 0x2810100); - - big.SetCompact (0x3810000); - expect (big.GetCompact() == 0x3810000); - --big; - expect (big.GetCompact() == 0x3810001); - - { - big.SetCompact (0x4810000); - expect (big.getint() == -16777216); - unsigned int const compact = big.GetCompact(); - --big; - expect (compact == big.GetCompact()); - } - big.SetCompact (0xFFFFFFFF); - ++big; - expect (big.GetCompact() == 0xFFFFFFFE); - expect (big.GetHex() == - "-7ffffefffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffff" - "fffffffffffffff"); - } - { - // SetHex() and GetHex(). - CBigNum big (1); - expect (big != 0); - big.SetHex (" "); - expect (big == 0); - big.SetHex (" -0x 1"); - expect (big == -1); - big.SetHex (" -0"); - expect (big.GetHex() == "0"); - big.SetHex ("Feeble"); - expect (big.GetHex () == "feeb"); - } - { - // ToString(). - CBigNum big; - expect (big.ToString (0) == "0"); - - // Trying to use base 0 throws an exception. - ++big; - { - bool badDivisor = false; - try - { - big.ToString (0); - } - catch (std::runtime_error const&) - { - badDivisor = true; - } - expect (badDivisor); - } - ++big; - expect (big.ToString (2) == "10"); - expect (big.ToString (10) == "2"); - } - { - // Member math operators. - CBigNum big; - expect (!big); - --big; - expect (! (!big)); - big += 2; - expect (big == 1); - big -= 3; - expect (big == -2); - big *= -1; - expect (big == 2); - big /= 2; - expect (big == 1); - big = 8; - big %= 5; - expect (big == 3); - ++big; - expect (big == 4); - --big; - expect (big == 3); - { - CBigNum const preIncr = big++; - expect (preIncr == 3); - expect (big == 4); - } - { - CBigNum const preDecr = big--; - expect (preDecr == 4); - expect (big == 3); - } - big.setuint64 (0x80); - big >>= 1; - expect (big == 0x40); - big <<= 2; - expect (big == 0x100); - big >>= 9; - expect (big == 0); - } - { - // Non-member math operators. - CBigNum a (5); - CBigNum b (3); - CBigNum c = a + b; - expect (c == 8); - c = c * a; - expect (c == 40); - c = c - b; - expect (c == 37); - a = c / b; - expect (a == 12); - a = c % b; - expect (a == 1); - a = -c; - expect (a == -37); - b = a << 1; - expect (b == -74); - a = c >> 2; - expect (a == 9); - // All right shifts of negative numbers yield zero. - a = (b >> 1); - expect (a == 0); - } - { - // Test non-member comparison operators. - auto comparison_test = [this] (int center) - { - CBigNum delta (1); - CBigNum lo (center); - lo -= delta; - CBigNum const ref (center); - CBigNum const mid (center); - CBigNum hi (center); - hi += delta; - - this->expect ( (lo < ref)); - this->expect (!(mid < ref)); - this->expect (!(hi < ref)); - - this->expect ( (lo <= ref)); - this->expect ( (mid <= ref)); - this->expect (!(hi <= ref)); - - this->expect (!(lo > ref)); - this->expect (!(mid > ref)); - this->expect ( (hi > ref)); - - this->expect (!(lo >= ref)); - this->expect ( (mid >= ref)); - this->expect ( (hi >= ref)); - - this->expect (!(lo == ref)); - this->expect ( (mid == ref)); - this->expect (!(hi == ref)); - - this->expect ( (lo != ref)); - this->expect (!(mid != ref)); - this->expect ( (hi != ref)); - }; - - comparison_test (537); - comparison_test (0); - comparison_test (-2058); - } - { - // BN math functions defined in CBigNum.h. - CBigNum a; - expect (BN_is_zero (&a)); - expect (BN_add_word64 (&a, 0xF000000000000000ull) == 1); - expect (BN_add_word64 (&a, 0x0FFFFFFFFFFFFFFFull) == 1); - - CBigNum b; - expect (BN_set_word (&b, 0xFFFFFFFFFFFFFFFFull) == 1); - expect (BN_cmp (&a, &b) == 0); - - expect (BN_sub_word64 (&a, 0xFF00000000000000ull) == 1); - expect (BN_set_word (&b, 0x00FFFFFFFFFFFFFFull) == 1); - expect (BN_cmp (&a, &b) == 0); - - expect (BN_mul_word64 (&a, 0x10) == 1); - expect (BN_set_word (&b, 0x0FFFFFFFFFFFFFF0ull) == 1); - expect (BN_cmp (&a, &b) == 0); - - expect (BN_div_word64 (&a, 0x10) == 1); - expect (BN_set_word (&b, 0x00FFFFFFFFFFFFFFull) == 1); - expect (BN_cmp (&a, &b) == 0); - - expect (BN_div_word64 (&a, 0x200) == 1); - expect (BN_set_word (&b, 0x00007FFFFFFFFFFFull) == 1); - expect (BN_cmp (&a, &b) == 0); - - a *= -1; - expect (a < 0); - expect (BN_div_word64 (&a, 0x400) == 1); - expect (BN_set_word (&b, 0x0000001FFFFFFFFFull) == 1); - b *= -1; - expect (a == b); - - // Divide by 0 should return an error. - expect (BN_div_word64 (&a, 0) != 1); - } - } -}; - -BEAST_DEFINE_TESTSUITE(CBigNum,ripple_data,ripple); - -} // ripple diff --git a/src/ripple/protocol/STAmount.h b/src/ripple/protocol/STAmount.h index c9ddc5d606..4338316f64 100644 --- a/src/ripple/protocol/STAmount.h +++ b/src/ripple/protocol/STAmount.h @@ -171,8 +171,6 @@ public: STAmount zeroed() const { - // TODO(tom): what does this next comment mean here? - // See https://ripplelabs.atlassian.net/browse/WC-1847?jql= return STAmount (mIssue); } diff --git a/src/ripple/protocol/impl/STAmount.cpp b/src/ripple/protocol/impl/STAmount.cpp index 106b571b0d..906075dd9e 100644 --- a/src/ripple/protocol/impl/STAmount.cpp +++ b/src/ripple/protocol/impl/STAmount.cpp @@ -22,13 +22,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -980,6 +980,58 @@ operator- (STAmount const& value) // Arithmetic // //------------------------------------------------------------------------------ + +// Calculate (a * b) / c when all three values are 64-bit +// without loss of precision: +static +std::uint64_t +muldiv( + std::uint64_t multiplier, + std::uint64_t multiplicand, + std::uint64_t divisor) +{ + boost::multiprecision::uint128_t ret; + + boost::multiprecision::multiply(ret, multiplier, multiplicand); + ret /= divisor; + + if (ret > std::numeric_limits::max()) + { + Throw ("overflow: (" + + std::to_string (multiplier) + " * " + + std::to_string (multiplicand) + ") / " + + std::to_string (divisor)); + } + + return static_cast(ret); +} + +static +std::uint64_t +muldiv_round( + std::uint64_t multiplier, + std::uint64_t multiplicand, + std::uint64_t divisor, + std::uint64_t rounding) +{ + boost::multiprecision::uint128_t ret; + + boost::multiprecision::multiply(ret, multiplier, multiplicand); + ret += rounding; + ret /= divisor; + + if (ret > std::numeric_limits::max()) + { + Throw ("overflow: ((" + + std::to_string (multiplier) + " * " + + std::to_string (multiplicand) + ") + " + + std::to_string (rounding) + ") / " + + std::to_string (divisor)); + } + + return static_cast(ret); +} + STAmount divide (STAmount const& num, STAmount const& den, Issue const& issue) { @@ -1013,23 +1065,15 @@ divide (STAmount const& num, STAmount const& den, Issue const& issue) } } - // Compute (numerator * 10^17) / denominator - CBigNum v; - - if ((BN_add_word64 (&v, numVal) != 1) || - (BN_mul_word64 (&v, tenTo17) != 1) || - (BN_div_word64 (&v, denVal) != 1)) - { - Throw ("internal bn error"); - } - - // 10^16 <= quotient <= 10^18 - assert (BN_num_bytes (&v) <= 64); - - // TODO(tom): where do 5 and 17 come from? - return STAmount (issue, v.getuint64 () + 5, - numOffset - denOffset - 17, - num.negative() != den.negative()); + // We divide the two mantissas (each is between 10^15 + // and 10^16). To maintain precision, we multiply the + // numerator by 10^17 (the product is in the range of + // 10^32 to 10^33) followed by a division, so the result + // is in the range of 10^16 to 10^15. + return STAmount (issue, + muldiv(numVal, tenTo17, denVal) + 5, + numOffset - denOffset - 17, + num.negative() != den.negative()); } STAmount @@ -1077,32 +1121,20 @@ multiply (STAmount const& v1, STAmount const& v2, Issue const& issue) } } - // Compute (numerator * denominator) / 10^14 with rounding - // 10^16 <= result <= 10^18 - CBigNum v; - - if ((BN_add_word64 (&v, value1) != 1) || - (BN_mul_word64 (&v, value2) != 1) || - (BN_div_word64 (&v, tenTo14) != 1)) - { - Throw ("internal bn error"); - } - - // 10^16 <= product <= 10^18 - assert (BN_num_bytes (&v) <= 64); - - // TODO(tom): where do 7 and 14 come from? - return STAmount (issue, v.getuint64 () + 7, - offset1 + offset2 + 14, v1.negative() != v2.negative()); + // We multiply the two mantissas (each is between 10^15 + // and 10^16), so their product is in the 10^30 to 10^32 + // range. Dividing their product by 10^14 maintains the + // precision, by scaling the result to 10^16 to 10^18. + return STAmount (issue, + muldiv(value1, value2, tenTo14) + 7, + offset1 + offset2 + 14, + v1.negative() != v2.negative()); } static void -canonicalizeRound (bool native, std::uint64_t& value, int& offset, bool roundUp) +canonicalizeRound (bool native, std::uint64_t& value, int& offset) { - if (!roundUp) // canonicalize already rounds down - return; - if (native) { if (offset < 0) @@ -1142,7 +1174,9 @@ mulRound (STAmount const& v1, STAmount const& v2, Issue const& issue, if (v1 == zero || v2 == zero) return {issue}; - if (v1.native() && v2.native() && isXRP (issue)) + bool const xrp = isXRP (issue); + + if (v1.native() && v2.native() && xrp) { std::uint64_t minV = (getSNValue (v1) < getSNValue (v2)) ? getSNValue (v1) : getSNValue (v2); @@ -1179,32 +1213,29 @@ mulRound (STAmount const& v1, STAmount const& v2, Issue const& issue, } } - bool resultNegative = v1.negative() != v2.negative(); - // Compute (numerator * denominator) / 10^14 with rounding - // 10^16 <= result <= 10^18 - CBigNum v; + bool const resultNegative = v1.negative() != v2.negative(); - if ((BN_add_word64 (&v, value1) != 1) || (BN_mul_word64 (&v, value2) != 1)) - Throw ("internal bn error"); + // We multiply the two mantissas (each is between 10^15 + // and 10^16), so their product is in the 10^30 to 10^32 + // range. Dividing their product by 10^14 maintains the + // precision, by scaling the result to 10^16 to 10^18. + // + // If the we're rounding up, we want to round up away + // from zero, and if we're rounding down, truncation + // is implicit. + std::uint64_t amount = muldiv_round ( + value1, value2, tenTo14, + (resultNegative != roundUp) ? tenTo14m1 : 0); - if (resultNegative != roundUp) // rounding down is automatic when we divide - BN_add_word64 (&v, tenTo14m1); - - if (BN_div_word64 (&v, tenTo14) != 1) - Throw ("internal bn error"); - - // 10^16 <= product <= 10^18 - assert (BN_num_bytes (&v) <= 64); - - std::uint64_t amount = v.getuint64 (); int offset = offset1 + offset2 + 14; - canonicalizeRound ( - isXRP (issue), amount, offset, resultNegative != roundUp); + if (resultNegative != roundUp) + canonicalizeRound (xrp, amount, offset); STAmount result (issue, amount, offset, resultNegative); + // Control when bugfixes that require switchover dates are enabled if (roundUp && !resultNegative && !result && *stAmountCalcSwitchover) { - if (isXRP(issue) && *stAmountCalcSwitchover2) + if (xrp && *stAmountCalcSwitchover2) { // return the smallest value above zero amount = 1; @@ -1235,40 +1266,43 @@ divRound (STAmount const& num, STAmount const& den, int numOffset = num.exponent(), denOffset = den.exponent(); if (num.native()) + { while (numVal < STAmount::cMinValue) { - // Need to bring into range numVal *= 10; --numOffset; } + } if (den.native()) + { while (denVal < STAmount::cMinValue) { denVal *= 10; --denOffset; } + } - bool resultNegative = num.negative() != den.negative(); - // Compute (numerator * 10^17) / denominator - CBigNum v; + bool const resultNegative = + (num.negative() != den.negative()); - if ((BN_add_word64 (&v, numVal) != 1) || (BN_mul_word64 (&v, tenTo17) != 1)) - Throw ("internal bn error"); + // We divide the two mantissas (each is between 10^15 + // and 10^16). To maintain precision, we multiply the + // numerator by 10^17 (the product is in the range of + // 10^32 to 10^33) followed by a division, so the result + // is in the range of 10^16 to 10^15. + // + // We round away from zero if we're rounding up or + // truncate if we're rounding down. + std::uint64_t amount = muldiv_round ( + numVal, tenTo17, denVal, + (resultNegative != roundUp) ? denVal - 1 : 0); - if (resultNegative != roundUp) // Rounding down is automatic when we divide - BN_add_word64 (&v, denVal - 1); - - if (BN_div_word64 (&v, denVal) != 1) - Throw ("internal bn error"); - - // 10^16 <= quotient <= 10^18 - assert (BN_num_bytes (&v) <= 64); - - std::uint64_t amount = v.getuint64 (); int offset = numOffset - denOffset - 17; - canonicalizeRound ( - isXRP (issue), amount, offset, resultNegative != roundUp); + + if (resultNegative != roundUp) + canonicalizeRound (isXRP (issue), amount, offset); + STAmount result (issue, amount, offset, resultNegative); // Control when bugfixes that require switchover dates are enabled if (roundUp && !resultNegative && !result && *stAmountCalcSwitchover) diff --git a/src/ripple/protocol/tests/STAmount.test.cpp b/src/ripple/protocol/tests/STAmount.test.cpp index 3ec27429c5..a7ed160739 100644 --- a/src/ripple/protocol/tests/STAmount.test.cpp +++ b/src/ripple/protocol/tests/STAmount.test.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -404,24 +403,6 @@ public: { testcase ("arithmetic"); - CBigNum b; - - for (int i = 0; i < 16; ++i) - { - std::uint64_t r = rand_int(); - b.setuint64 (r); - - if (b.getuint64 () != r) - { - log << r << " != " << b.getuint64 () << " " << b.ToString (16); - fail ("setull64/getull64 failure"); - } - else - { - pass (); - } - } - // Test currency multiplication and division operations such as // convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded diff --git a/src/ripple/unity/crypto.cpp b/src/ripple/unity/crypto.cpp index 906f46f380..928a6e8fb2 100644 --- a/src/ripple/unity/crypto.cpp +++ b/src/ripple/unity/crypto.cpp @@ -19,7 +19,6 @@ #include -#include #include #include #include @@ -29,7 +28,6 @@ #include #include -#include #include #if DOXYGEN