mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-26 14:05:51 +00:00
Remove legacy arbitrary precision integer support:
The CBigNum class is a wrapper around OpenSSL's BIGNUM implementation to make use simpler. Replacing the implementation with boost::multiprecision helps reduce the size of the codebase and improves performance (benchmarks show the new boost-based implementation is ~7x faster).
This commit is contained in:
committed by
Howard Hinnant
parent
1c3ee48146
commit
f081e80c28
@@ -2079,20 +2079,12 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\core\TimeKeeper.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\CAutoBN_CTX.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\CBigNum.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\csprng.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\ECIES.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\GenerateDeterministicKey.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\impl\CBigNum.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\impl\csprng.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
@@ -2137,10 +2129,6 @@
|
||||
</None>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\RFC1751.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\tests\CBigNum_test.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\tests\CKey.test.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
|
||||
@@ -2604,12 +2604,6 @@
|
||||
<ClInclude Include="..\..\src\ripple\core\TimeKeeper.h">
|
||||
<Filter>ripple\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\CAutoBN_CTX.h">
|
||||
<Filter>ripple\crypto</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\CBigNum.h">
|
||||
<Filter>ripple\crypto</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\crypto\csprng.h">
|
||||
<Filter>ripple\crypto</Filter>
|
||||
</ClInclude>
|
||||
@@ -2619,9 +2613,6 @@
|
||||
<ClInclude Include="..\..\src\ripple\crypto\GenerateDeterministicKey.h">
|
||||
<Filter>ripple\crypto</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\impl\CBigNum.cpp">
|
||||
<Filter>ripple\crypto\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\impl\csprng.cpp">
|
||||
<Filter>ripple\crypto\impl</Filter>
|
||||
</ClCompile>
|
||||
@@ -2664,9 +2655,6 @@
|
||||
<ClInclude Include="..\..\src\ripple\crypto\RFC1751.h">
|
||||
<Filter>ripple\crypto</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\tests\CBigNum_test.cpp">
|
||||
<Filter>ripple\crypto\tests</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\crypto\tests\CKey.test.cpp">
|
||||
<Filter>ripple\crypto\tests</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -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 <ripple/basics/contract.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class CAutoBN_CTX
|
||||
{
|
||||
protected:
|
||||
BN_CTX* pctx;
|
||||
|
||||
public:
|
||||
CAutoBN_CTX ()
|
||||
{
|
||||
pctx = BN_CTX_new ();
|
||||
|
||||
if (pctx == nullptr)
|
||||
Throw<std::runtime_error> ("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
|
||||
@@ -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 <ripple/basics/base_uint.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
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
|
||||
@@ -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 <BeastConfig.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <ripple/crypto/CAutoBN_CTX.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
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<std::runtime_error> ("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<std::runtime_error> ("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<unsigned long> (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<std::uint64_t> (getulong ());
|
||||
#else
|
||||
int len = BN_num_bytes (this);
|
||||
|
||||
if (len > 8)
|
||||
Throw<std::runtime_error> ("BN getuint64 overflow");
|
||||
|
||||
unsigned char buf[8];
|
||||
memset (buf, 0, sizeof (buf));
|
||||
BN_bn2bin (this, buf + 8 - len);
|
||||
return
|
||||
static_cast<std::uint64_t> (buf[0]) << 56 | static_cast<std::uint64_t> (buf[1]) << 48 |
|
||||
static_cast<std::uint64_t> (buf[2]) << 40 | static_cast<std::uint64_t> (buf[3]) << 32 |
|
||||
static_cast<std::uint64_t> (buf[4]) << 24 | static_cast<std::uint64_t> (buf[5]) << 16 |
|
||||
static_cast<std::uint64_t> (buf[6]) << 8 | static_cast<std::uint64_t> (buf[7]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CBigNum::setuint64 (std::uint64_t n)
|
||||
{
|
||||
#if (ULONG_MAX > UINT_MAX)
|
||||
setulong (static_cast<unsigned long> (n));
|
||||
#else
|
||||
unsigned char buf[8];
|
||||
buf[0] = static_cast<unsigned char> ((n >> 56) & 0xff);
|
||||
buf[1] = static_cast<unsigned char> ((n >> 48) & 0xff);
|
||||
buf[2] = static_cast<unsigned char> ((n >> 40) & 0xff);
|
||||
buf[3] = static_cast<unsigned char> ((n >> 32) & 0xff);
|
||||
buf[4] = static_cast<unsigned char> ((n >> 24) & 0xff);
|
||||
buf[5] = static_cast<unsigned char> ((n >> 16) & 0xff);
|
||||
buf[6] = static_cast<unsigned char> ((n >> 8) & 0xff);
|
||||
buf[7] = static_cast<unsigned char> ((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<std::runtime_error> ("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<std::runtime_error> ("CBigNum::operator+= : BN_add failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator-= (const CBigNum& b)
|
||||
{
|
||||
*this = *this - b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator*= (const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
|
||||
if (!BN_mul (this, this, &b, pctx))
|
||||
Throw<std::runtime_error> ("CBigNum::operator*= : BN_mul failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator/= (const CBigNum& b)
|
||||
{
|
||||
*this = *this / b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator%= (const CBigNum& b)
|
||||
{
|
||||
*this = *this % b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& CBigNum::operator<<= (unsigned int shift)
|
||||
{
|
||||
if (!BN_lshift (this, this, shift))
|
||||
Throw<std::runtime_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, this) > 0)
|
||||
{
|
||||
*this = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (! BN_rshift (this, this, shift))
|
||||
Throw<std::runtime_error> ("CBigNum:operator>>= : BN_rshift failed");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
CBigNum& CBigNum::operator++ ()
|
||||
{
|
||||
// prefix operator
|
||||
if (! BN_add (this, this, BN_value_one ()))
|
||||
Throw<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> (
|
||||
"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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<BN_ULONG>(-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
|
||||
|
||||
}
|
||||
@@ -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 <BeastConfig.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class CBigNum_test : public beast::unit_test::suite
|
||||
{
|
||||
private:
|
||||
// Generic test for constructing CBigNum from native types.
|
||||
template<typename T>
|
||||
void
|
||||
testNativeCtor()
|
||||
{
|
||||
static_assert (std::numeric_limits<T>::is_integer, "Requires int type");
|
||||
if (std::numeric_limits<T>::is_signed)
|
||||
{
|
||||
CBigNum const neg (static_cast<T>(std::numeric_limits<T>::min()));
|
||||
this->expect (neg == std::numeric_limits<T>::min());
|
||||
this->expect (neg < 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
CBigNum const naught (static_cast<T>(0));
|
||||
this->expect (naught == 0);
|
||||
}
|
||||
CBigNum const big (static_cast<T>(std::numeric_limits<T>::max()));
|
||||
this->expect (big == std::numeric_limits<T>::max());
|
||||
this->expect (big > 0);
|
||||
}
|
||||
|
||||
// Return pointer to start of array.
|
||||
template<typename T, std::size_t N>
|
||||
static auto
|
||||
array_cbegin(T (&a)[N]) -> T const*
|
||||
{
|
||||
return &a[0];
|
||||
}
|
||||
|
||||
// Return pointer to one past end of array.
|
||||
template<typename T, std::size_t N>
|
||||
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<unsigned char>(1));
|
||||
expect (big1 == 1);
|
||||
// Assignment.
|
||||
CBigNum bigA;
|
||||
bigA = big1;
|
||||
expect (bigA == big1);
|
||||
}
|
||||
{
|
||||
// Test constructing from native types.
|
||||
testNativeCtor<char>();
|
||||
testNativeCtor<unsigned char>();
|
||||
testNativeCtor<short>();
|
||||
testNativeCtor<unsigned short>();
|
||||
testNativeCtor<int>();
|
||||
testNativeCtor<unsigned int>();
|
||||
testNativeCtor<long>();
|
||||
// testNativeCtor<unsigned long>(); // unsigned long not supported
|
||||
testNativeCtor<long long>();
|
||||
testNativeCtor<unsigned long long>();
|
||||
}
|
||||
{
|
||||
// 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<void> 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<unsigned int>::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<int>::min());
|
||||
expect (neg.getint() == std::numeric_limits<int>::min());
|
||||
// Note that getint() limits at INT_MIN on negative overflow.
|
||||
--neg;
|
||||
expect (neg.getint() == std::numeric_limits<int>::min());
|
||||
|
||||
CBigNum pos (std::numeric_limits<int>::max());
|
||||
expect (pos.getint() == std::numeric_limits<int>::max());
|
||||
// Note that getint() limits at INT_MAX on positive overflow.
|
||||
++pos;
|
||||
expect (pos.getint() == std::numeric_limits<int>::max());
|
||||
}
|
||||
{
|
||||
// setint64().
|
||||
CBigNum big;
|
||||
big.setint64 (std::numeric_limits<std::int64_t>::min());
|
||||
expect (big.GetHex() == "-8000000000000000");
|
||||
--big;
|
||||
expect (big.GetHex() == "-8000000000000001");
|
||||
|
||||
big.setint64 (std::numeric_limits<std::int64_t>::max());
|
||||
expect (big.GetHex() == "7fffffffffffffff");
|
||||
++big;
|
||||
expect (big.GetHex() == "8000000000000000");
|
||||
}
|
||||
{
|
||||
// setuint64() and getuint64().
|
||||
CBigNum big;
|
||||
big.setuint64 (static_cast<std::uint64_t>(0));
|
||||
expect (big.getuint64() == 0);
|
||||
// Note that getuint64() drops the sign.
|
||||
--big;
|
||||
expect (big.getuint64() == 1);
|
||||
|
||||
big.setuint64 (std::numeric_limits<std::uint64_t>::max());
|
||||
expect (
|
||||
big.getuint64() == std::numeric_limits<std::uint64_t>::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<std::uint64_t>::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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
@@ -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<std::uint64_t>::max())
|
||||
{
|
||||
Throw<std::overflow_error> ("overflow: (" +
|
||||
std::to_string (multiplier) + " * " +
|
||||
std::to_string (multiplicand) + ") / " +
|
||||
std::to_string (divisor));
|
||||
}
|
||||
|
||||
return static_cast<uint64_t>(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<std::uint64_t>::max())
|
||||
{
|
||||
Throw<std::overflow_error> ("overflow: ((" +
|
||||
std::to_string (multiplier) + " * " +
|
||||
std::to_string (multiplicand) + ") + " +
|
||||
std::to_string (rounding) + ") / " +
|
||||
std::to_string (divisor));
|
||||
}
|
||||
|
||||
return static_cast<uint64_t>(ret);
|
||||
}
|
||||
|
||||
STAmount
|
||||
divide (STAmount const& num, STAmount const& den, Issue const& issue)
|
||||
{
|
||||
@@ -1013,21 +1065,13 @@ 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<std::runtime_error> ("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,
|
||||
// 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());
|
||||
}
|
||||
@@ -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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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<std::runtime_error> ("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)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/random.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
|
||||
@@ -404,24 +403,6 @@ public:
|
||||
{
|
||||
testcase ("arithmetic");
|
||||
|
||||
CBigNum b;
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
std::uint64_t r = rand_int<std::uint64_t>();
|
||||
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
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
|
||||
#include <ripple/crypto/impl/CBigNum.cpp>
|
||||
#include <ripple/crypto/impl/ec_key.cpp>
|
||||
#include <ripple/crypto/impl/ECDSAKey.cpp>
|
||||
#include <ripple/crypto/impl/ECIES.cpp>
|
||||
@@ -29,7 +28,6 @@
|
||||
#include <ripple/crypto/impl/csprng.cpp>
|
||||
#include <ripple/crypto/impl/RFC1751.cpp>
|
||||
|
||||
#include <ripple/crypto/tests/CBigNum_test.cpp>
|
||||
#include <ripple/crypto/tests/CKey.test.cpp>
|
||||
|
||||
#if DOXYGEN
|
||||
|
||||
Reference in New Issue
Block a user