mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add support for multiprecision integer arithmetic and binary data encoding
This commit is contained in:
@@ -323,7 +323,9 @@
|
|||||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h" />
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h" />
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_crypto\beast_crypto.h" />
|
<ClInclude Include="..\..\modules\beast_crypto\beast_crypto.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_crypto\math\BinaryEncoding.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedInteger.h" />
|
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedInteger.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedIntegerCalc.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_db\beast_db.h" />
|
<ClInclude Include="..\..\modules\beast_db\beast_db.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_db\keyvalue\beast_KeyvaDB.h" />
|
<ClInclude Include="..\..\modules\beast_db\keyvalue\beast_KeyvaDB.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_extras\beast_extras.h" />
|
<ClInclude Include="..\..\modules\beast_extras\beast_extras.h" />
|
||||||
@@ -1265,6 +1267,12 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\modules\beast_crypto\beast_crypto.cpp" />
|
<ClCompile Include="..\..\modules\beast_crypto\beast_crypto.cpp" />
|
||||||
|
<ClCompile Include="..\..\modules\beast_crypto\math\BinaryEncoding.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\modules\beast_crypto\math\UnsignedInteger.cpp">
|
<ClCompile Include="..\..\modules\beast_crypto\math\UnsignedInteger.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
|||||||
@@ -1028,6 +1028,12 @@
|
|||||||
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedInteger.h">
|
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedInteger.h">
|
||||||
<Filter>beast_crypto\math</Filter>
|
<Filter>beast_crypto\math</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedIntegerCalc.h">
|
||||||
|
<Filter>beast_crypto\math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_crypto\math\BinaryEncoding.h">
|
||||||
|
<Filter>beast_crypto\math</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||||
@@ -1552,6 +1558,9 @@
|
|||||||
<ClCompile Include="..\..\modules\beast_crypto\math\UnsignedInteger.cpp">
|
<ClCompile Include="..\..\modules\beast_crypto\math\UnsignedInteger.cpp">
|
||||||
<Filter>beast_crypto\math</Filter>
|
<Filter>beast_crypto\math</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_crypto\math\BinaryEncoding.cpp">
|
||||||
|
<Filter>beast_crypto\math</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="..\..\TODO.txt" />
|
<Text Include="..\..\TODO.txt" />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
namespace beast
|
namespace beast
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#include "math/BinaryEncoding.cpp"
|
||||||
#include "math/UnsignedInteger.cpp"
|
#include "math/UnsignedInteger.cpp"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,9 @@
|
|||||||
namespace beast
|
namespace beast
|
||||||
{
|
{
|
||||||
|
|
||||||
|
# include "math/UnsignedIntegerCalc.h"
|
||||||
#include "math/UnsignedInteger.h"
|
#include "math/UnsignedInteger.h"
|
||||||
|
#include "math/BinaryEncoding.h"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
395
modules/beast_crypto/math/BinaryEncoding.cpp
Normal file
395
modules/beast_crypto/math/BinaryEncoding.cpp
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/** Generic algorithms for base encoding and decoding. */
|
||||||
|
class BinaryEncoding
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Concept: Conversion
|
||||||
|
|
||||||
|
X denotes a Conversion class, a is a value of type X,
|
||||||
|
i is an integral type.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
Expression Type Notes/Contracts
|
||||||
|
------------- ----------- ------------------
|
||||||
|
X a;
|
||||||
|
X::radix size_type constexpr
|
||||||
|
a.map (i) char maps base numeral to a char
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Encode the unsigned integer into a string using the specified conversion. */
|
||||||
|
template <typename Conversion, std::size_t Bytes>
|
||||||
|
static std::string encode (UnsignedInteger <Bytes> v, Conversion c = Conversion ())
|
||||||
|
{
|
||||||
|
// bi is destroyed in this process
|
||||||
|
typename UnsignedInteger <Bytes>::CalcType bi (v.toCalcType ());
|
||||||
|
std::size_t const radix (Conversion::radix);
|
||||||
|
std::string s;
|
||||||
|
s.reserve (bi.size() * 3); // guess
|
||||||
|
while (bi.isNotZero ())
|
||||||
|
{
|
||||||
|
std::size_t const m (bi % radix);
|
||||||
|
bi /= radix;
|
||||||
|
s.push_back (c.map (m));
|
||||||
|
}
|
||||||
|
std::reverse (s.begin(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decode the string into an unsigned integer.
|
||||||
|
The size must match exactly
|
||||||
|
@return `true` on success.
|
||||||
|
*/
|
||||||
|
template <typename Conversion, std::size_t Bytes>
|
||||||
|
static bool decode (UnsignedInteger <Bytes>& rv,
|
||||||
|
std::string const& s, Conversion c = Conversion ())
|
||||||
|
{
|
||||||
|
typename UnsignedInteger <Bytes>::CalcType bi (rv.toCalcType (false));
|
||||||
|
std::size_t const radix (Conversion::radix);
|
||||||
|
bi.clear ();
|
||||||
|
for (std::string::const_iterator iter (s.begin()); iter != s.end(); ++iter)
|
||||||
|
{
|
||||||
|
int const v (c.invert (*iter));
|
||||||
|
if (v == -1)
|
||||||
|
return false;
|
||||||
|
bi *= radix;
|
||||||
|
bi += v;
|
||||||
|
}
|
||||||
|
bi.toCanonical();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Some common code
|
||||||
|
template <class Conversion>
|
||||||
|
class BaseConversion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char map (std::size_t i) const
|
||||||
|
{
|
||||||
|
return Conversion::alphabet () [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int invert (char c) const
|
||||||
|
{
|
||||||
|
return Conversion::inverse_alphabet () [c];
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector <int> const& inverse_alphabet ()
|
||||||
|
{
|
||||||
|
static std::vector <int> t (invert (Conversion::alphabet(), Conversion::radix));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build the inverse mapping table from characters to digits. */
|
||||||
|
static std::vector <int> invert (std::string const& alphabet, std::size_t radix)
|
||||||
|
{
|
||||||
|
std::vector <int> table (256, -1);
|
||||||
|
for (std::size_t i (0); i < radix; ++i)
|
||||||
|
table [alphabet [i]] = i;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Foolproof hexadecimal encoding and decoding facility.
|
||||||
|
This is to check the correctness of the more complex converters.
|
||||||
|
*/
|
||||||
|
class HexEncoding
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <std::size_t Bytes>
|
||||||
|
static std::string encode (UnsignedInteger <Bytes> const& v)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
uint8 const* src (v.cbegin()-1);
|
||||||
|
char const* const tab (alphabet().c_str());
|
||||||
|
s.reserve (Bytes * 2);
|
||||||
|
for (std::size_t bytes (v.sizeInBytes);bytes--;)
|
||||||
|
{
|
||||||
|
uint8 const v (*++src);
|
||||||
|
s.push_back (tab [v>>4]);
|
||||||
|
s.push_back (tab [v&0x0f]);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Bytes>
|
||||||
|
static bool decode (UnsignedInteger <Bytes>& rv,
|
||||||
|
std::string const& s)
|
||||||
|
{
|
||||||
|
// can't have an odd size
|
||||||
|
if (s.size() & 1)
|
||||||
|
return false;
|
||||||
|
uint8* dest (rv.begin()-1);
|
||||||
|
int const* const tab (&inverse_alphabet().front());
|
||||||
|
for (std::string::const_iterator iter (s.begin()); iter != s.end();)
|
||||||
|
{
|
||||||
|
int const n1 (tab [*iter++]);
|
||||||
|
if (n1 == -1)
|
||||||
|
return false;
|
||||||
|
int const n2 (tab [*iter++]);
|
||||||
|
if (n2 == -1)
|
||||||
|
return false;
|
||||||
|
*++dest = ((uint8)((n1<<4)|n2));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string const& alphabet ()
|
||||||
|
{
|
||||||
|
static std::string s ("0123456789ABCDEF");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector <int> const& inverse_alphabet ()
|
||||||
|
{
|
||||||
|
static std::vector <int> s (invert (alphabet(), 16));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build the inverse mapping table from characters to digits. */
|
||||||
|
static std::vector <int> invert (std::string const& alphabet, std::size_t radix)
|
||||||
|
{
|
||||||
|
std::vector <int> table (256, -1);
|
||||||
|
for (std::size_t i (0); i < radix; ++i)
|
||||||
|
table [alphabet [i]] = i;
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Base58 conversion used by Bitcoin. */
|
||||||
|
class BitcoinBase58Conversion : public BaseConversion <BitcoinBase58Conversion>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::size_t const radix = 58;
|
||||||
|
|
||||||
|
char const* name () const
|
||||||
|
{
|
||||||
|
return "BitcoinBase58";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string const& alphabet ()
|
||||||
|
{
|
||||||
|
static std::string s (
|
||||||
|
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||||
|
);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Base58 conversion used by Ripple. */
|
||||||
|
class RippleBase58Conversion : public BaseConversion <RippleBase58Conversion>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::size_t const radix = 58;
|
||||||
|
|
||||||
|
char const* name () const
|
||||||
|
{
|
||||||
|
return "RippleBase58";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string const& alphabet ()
|
||||||
|
{
|
||||||
|
static std::string s (
|
||||||
|
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
|
||||||
|
);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Base64Conversion : public BaseConversion <Base64Conversion>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::size_t const radix = 64;
|
||||||
|
|
||||||
|
char const* name () const
|
||||||
|
{
|
||||||
|
return "Base64";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string const& alphabet ()
|
||||||
|
{
|
||||||
|
static std::string s (
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Base16Conversion : public BaseConversion <Base16Conversion>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::size_t const radix = 16;
|
||||||
|
|
||||||
|
char const* name () const
|
||||||
|
{
|
||||||
|
return "Hex";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string const& alphabet ()
|
||||||
|
{
|
||||||
|
static std::string s (
|
||||||
|
"0123456789ABCDEF"
|
||||||
|
);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class BinaryEncodingTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// This is a baseline for the other tests
|
||||||
|
template <std::size_t Bytes>
|
||||||
|
void testBase16 ()
|
||||||
|
{
|
||||||
|
beginTestCase ("base16");
|
||||||
|
for (int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
typedef UnsignedInteger <Bytes> UInt;
|
||||||
|
UInt v0;
|
||||||
|
random().fillBitsRandomly (v0.begin(), UInt::sizeInBytes);
|
||||||
|
std::string const good (HexEncoding::encode (v0));
|
||||||
|
|
||||||
|
UInt v1;
|
||||||
|
bool const success (HexEncoding::decode (v1, good));
|
||||||
|
if (expect (success))
|
||||||
|
{
|
||||||
|
expect (v0 == v1);
|
||||||
|
|
||||||
|
Base16Conversion c;
|
||||||
|
std::string const check (BinaryEncoding::encode (v0, c));
|
||||||
|
if (! expect (good == check))
|
||||||
|
logMessage (String ("expected ") + good + " but got " + check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Bytes>
|
||||||
|
void testBase64Bytes (
|
||||||
|
std::string const& vin, std::string const& vout,
|
||||||
|
Base64Conversion c = Base64Conversion ())
|
||||||
|
{
|
||||||
|
typedef UnsignedInteger <Bytes> UInt;
|
||||||
|
UInt v1 (vin.c_str());
|
||||||
|
std::string const s1 (BinaryEncoding::encode (v1, c));
|
||||||
|
logMessage (vout + " to " + s1);
|
||||||
|
expect (vout == s1);
|
||||||
|
|
||||||
|
UInt v2;
|
||||||
|
bool const success (BinaryEncoding::decode (v2, vout, c));
|
||||||
|
if (expect (success))
|
||||||
|
{
|
||||||
|
std::string const s2 (BinaryEncoding::encode (v2, c));
|
||||||
|
logMessage (vin + " to " + s2);
|
||||||
|
//expect (vin == v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBase64 ()
|
||||||
|
{
|
||||||
|
beginTestCase ("Base64");
|
||||||
|
|
||||||
|
// input (uint)
|
||||||
|
std::string const vin [] = {
|
||||||
|
"","f","fo","foo","foob","fooba","foobar"
|
||||||
|
};
|
||||||
|
|
||||||
|
// output (encoded string)
|
||||||
|
std::string const vout [] = {
|
||||||
|
"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"
|
||||||
|
};
|
||||||
|
|
||||||
|
//testBase64Bytes <0> (vin [0], vout [0]);
|
||||||
|
testBase64Bytes <1> (vin [1], vout [1]);
|
||||||
|
testBase64Bytes <2> (vin [2], vout [2]);
|
||||||
|
testBase64Bytes <3> (vin [3], vout [3]);
|
||||||
|
testBase64Bytes <4> (vin [4], vout [4]);
|
||||||
|
testBase64Bytes <5> (vin [5], vout [5]);
|
||||||
|
testBase64Bytes <6> (vin [6], vout [6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Conversion, std::size_t Bytes>
|
||||||
|
void testEncode (Conversion c = Conversion())
|
||||||
|
{
|
||||||
|
typedef UnsignedInteger <Bytes> UInt;
|
||||||
|
|
||||||
|
beginTestCase (String (c.name()) + " <" + String::fromNumber (Bytes) + ">");
|
||||||
|
|
||||||
|
for (int i = 0; i < 50; ++i)
|
||||||
|
{
|
||||||
|
UInt v1;
|
||||||
|
random().fillBitsRandomly (v1.begin(), UInt::sizeInBytes);
|
||||||
|
std::string const s1 (BinaryEncoding::encode (v1, c));
|
||||||
|
|
||||||
|
UInt v2;
|
||||||
|
bool success (BinaryEncoding::decode (v2, s1, c));
|
||||||
|
if (expect (success))
|
||||||
|
expect (v1 == v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest ()
|
||||||
|
{
|
||||||
|
testBase16 <10> ();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
testEncode <Base16Conversion, 1> ();
|
||||||
|
testEncode <Base16Conversion, 2> ();
|
||||||
|
testEncode <Base16Conversion, 3> ();
|
||||||
|
testEncode <Base16Conversion, 4> ();
|
||||||
|
testEncode <Base16Conversion, 5> ();
|
||||||
|
testEncode <Base16Conversion, 6> ();
|
||||||
|
testEncode <Base16Conversion, 7> ();
|
||||||
|
testEncode <Base16Conversion, 8> ();
|
||||||
|
testEncode <Base16Conversion, 9> ();
|
||||||
|
testEncode <Base16Conversion, 10> ();
|
||||||
|
|
||||||
|
testBase64 ();
|
||||||
|
testEncode <Base64Conversion, 20> ();
|
||||||
|
testEncode <Base64Conversion, 33> ();
|
||||||
|
testEncode <RippleBase58Conversion, 20> ();
|
||||||
|
testEncode <RippleBase58Conversion, 33> ();
|
||||||
|
testEncode <BitcoinBase58Conversion, 20> ();
|
||||||
|
testEncode <BitcoinBase58Conversion, 33> ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryEncodingTests () : UnitTest ("BinaryEncoding", "beast", runManual)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static BinaryEncodingTests BinaryEncodingTests;
|
||||||
24
modules/beast_crypto/math/BinaryEncoding.h
Normal file
24
modules/beast_crypto/math/BinaryEncoding.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_CRYPTO_BINARYENCODING_H_INCLUDED
|
||||||
|
#define BEAST_CRYPTO_BINARYENCODING_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -17,6 +17,327 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* Copyright (c) 2013 the authors listed at the following URL, and/or
|
||||||
|
the authors of referenced articles or incorporated external code:
|
||||||
|
http://en.literateprograms.org/Arbitrary-precision_integer_arithmetic_(C)?action=history&offset=20100923155004
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Retrieved from: http://en.literateprograms.org/Arbitrary-precision_integer_arithmetic_(C)?oldid=16902
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace multiprecsion
|
||||||
|
{
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef unsigned short component_t;
|
||||||
|
typedef unsigned long double_component_t;
|
||||||
|
|
||||||
|
#define MAX_COMPONENT ((component_t)(-1))
|
||||||
|
#define COMPONENT_BITS (sizeof(component_t)*CHAR_BIT)
|
||||||
|
|
||||||
|
#define LOG_2_10 3.3219280948873623478703194294894
|
||||||
|
|
||||||
|
#define MIN(x,y) ((x)<(y) ? (x) : (y))
|
||||||
|
#define MAX(x,y) ((x)>(y) ? (x) : (y))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
component_t* c; /* least-significant word first */
|
||||||
|
int num_components;
|
||||||
|
} integer;
|
||||||
|
|
||||||
|
|
||||||
|
integer create_integer(int components);
|
||||||
|
void free_integer(integer i);
|
||||||
|
void set_zero_integer(integer i);
|
||||||
|
void copy_integer(integer source, integer target);
|
||||||
|
void add_integer(integer left, integer right, integer result);
|
||||||
|
void subtract_integer(integer left, integer right, integer result);
|
||||||
|
void multiply_small_integer(integer left, component_t right, integer result);
|
||||||
|
void multiply_integer(integer left, integer right, integer result);
|
||||||
|
int compare_integers(integer left, integer right);
|
||||||
|
void shift_left_one_integer(integer arg);
|
||||||
|
void shift_right_one_integer(integer arg);
|
||||||
|
component_t mod_small_integer(integer left, component_t right);
|
||||||
|
void mod_integer(integer left, integer right, integer result);
|
||||||
|
void divide_small_integer(integer left, component_t right, integer result);
|
||||||
|
integer string_to_integer(char* s);
|
||||||
|
char* integer_to_string(integer x);
|
||||||
|
int is_zero_integer(integer x);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
integer create_integer(int components) {
|
||||||
|
integer result;
|
||||||
|
result.num_components = components;
|
||||||
|
result.c = (component_t*)malloc(sizeof(component_t)*components);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void free_integer(integer i) {
|
||||||
|
free(i.c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_zero_integer(integer i) {
|
||||||
|
memset(i.c, 0, sizeof(component_t)*i.num_components);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int is_zero_integer(integer x) {
|
||||||
|
int i;
|
||||||
|
for(i=0; i < x.num_components; i++) {
|
||||||
|
if (x.c[i] != 0) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_integer(integer source, integer target) {
|
||||||
|
memmove(target.c, source.c,
|
||||||
|
sizeof(component_t)*MIN(source.num_components, target.num_components));
|
||||||
|
if (target.num_components > source.num_components) {
|
||||||
|
memset(target.c + source.num_components, 0,
|
||||||
|
sizeof(component_t)*(target.num_components - source.num_components));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_integer(integer left, integer right, integer result) {
|
||||||
|
double_component_t carry = 0;
|
||||||
|
int i;
|
||||||
|
for(i=0; i<left.num_components || i<right.num_components || carry != 0; i++) {
|
||||||
|
double_component_t partial_sum = carry;
|
||||||
|
carry = 0;
|
||||||
|
if (i < left.num_components) partial_sum += left.c[i];
|
||||||
|
if (i < right.num_components) partial_sum += right.c[i];
|
||||||
|
if (partial_sum > MAX_COMPONENT) {
|
||||||
|
partial_sum &= MAX_COMPONENT;
|
||||||
|
carry = 1;
|
||||||
|
}
|
||||||
|
result.c[i] = (component_t)partial_sum;
|
||||||
|
}
|
||||||
|
for ( ; i < result.num_components; i++) { result.c[i] = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void subtract_integer(integer left, integer right, integer result) {
|
||||||
|
int borrow = 0;
|
||||||
|
int i;
|
||||||
|
for(i=0; i<left.num_components; i++) {
|
||||||
|
double_component_t lhs = left.c[i];
|
||||||
|
double_component_t rhs = (i < right.num_components) ? right.c[i] : 0;
|
||||||
|
if (borrow) {
|
||||||
|
if (lhs <= rhs) {
|
||||||
|
/* leave borrow set to 1 */
|
||||||
|
lhs += (MAX_COMPONENT + 1) - 1;
|
||||||
|
} else {
|
||||||
|
borrow = 0;
|
||||||
|
lhs--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lhs < rhs) {
|
||||||
|
borrow = 1;
|
||||||
|
lhs += MAX_COMPONENT + 1;
|
||||||
|
}
|
||||||
|
result.c[i] = lhs - rhs;
|
||||||
|
}
|
||||||
|
for ( ; i < result.num_components; i++) { result.c[i] = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void multiply_small_integer(integer left, component_t right, integer result) {
|
||||||
|
double_component_t carry = 0;
|
||||||
|
int i;
|
||||||
|
for(i=0; i<left.num_components || carry != 0; i++) {
|
||||||
|
double_component_t partial_sum = carry;
|
||||||
|
carry = 0;
|
||||||
|
if (i < left.num_components) partial_sum += left.c[i]*right;
|
||||||
|
carry = partial_sum >> COMPONENT_BITS;
|
||||||
|
result.c[i] = (component_t)(partial_sum & MAX_COMPONENT);
|
||||||
|
}
|
||||||
|
for ( ; i < result.num_components; i++) { result.c[i] = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void multiply_integer(integer left, integer right, integer result) {
|
||||||
|
int i, lidx, ridx;
|
||||||
|
double_component_t carry = 0;
|
||||||
|
int max_size_no_carry;
|
||||||
|
int left_max_component = left.num_components - 1;
|
||||||
|
int right_max_component = right.num_components - 1;
|
||||||
|
while(left.c[left_max_component] == 0) left_max_component--;
|
||||||
|
while(right.c[right_max_component] == 0) right_max_component--;
|
||||||
|
max_size_no_carry = left_max_component + right_max_component;
|
||||||
|
for(i=0; i <= max_size_no_carry || carry != 0; i++) {
|
||||||
|
double_component_t partial_sum = carry;
|
||||||
|
carry = 0;
|
||||||
|
lidx = MIN(i, left_max_component);
|
||||||
|
ridx = i - lidx;
|
||||||
|
while(lidx >= 0 && ridx <= right_max_component) {
|
||||||
|
partial_sum += ((double_component_t)left.c[lidx])*right.c[ridx];
|
||||||
|
carry += partial_sum >> COMPONENT_BITS;
|
||||||
|
partial_sum &= MAX_COMPONENT;
|
||||||
|
lidx--; ridx++;
|
||||||
|
}
|
||||||
|
result.c[i] = partial_sum;
|
||||||
|
}
|
||||||
|
for ( ; i < result.num_components; i++) { result.c[i] = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int compare_integers(integer left, integer right) {
|
||||||
|
int i = MAX(left.num_components - 1, right.num_components - 1);
|
||||||
|
for ( ; i >= 0; i--) {
|
||||||
|
component_t left_comp =
|
||||||
|
(i < left.num_components) ? left.c[i] : 0;
|
||||||
|
component_t right_comp =
|
||||||
|
(i < right.num_components) ? right.c[i] : 0;
|
||||||
|
if (left_comp < right_comp)
|
||||||
|
return -1;
|
||||||
|
else if (left_comp > right_comp)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shift_left_one_integer(integer arg) {
|
||||||
|
int i;
|
||||||
|
arg.c[arg.num_components - 1] <<= 1;
|
||||||
|
for (i = arg.num_components - 2; i >= 0; i--) {
|
||||||
|
arg.c[i + 1] |= arg.c[i] >> (COMPONENT_BITS - 1);
|
||||||
|
arg.c[i] <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void shift_right_one_integer(integer arg) {
|
||||||
|
int i;
|
||||||
|
arg.c[0] >>= 1;
|
||||||
|
for (i = 1; i < arg.num_components; i++) {
|
||||||
|
arg.c[i - 1] |= (arg.c[i] & 1) << (COMPONENT_BITS - 1);
|
||||||
|
arg.c[i] >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component_t mod_small_integer(integer left, component_t right) {
|
||||||
|
double_component_t mod_two_power = 1;
|
||||||
|
double_component_t result = 0;
|
||||||
|
int i, bit;
|
||||||
|
for(i=0; i<left.num_components; i++) {
|
||||||
|
for(bit=0; bit<COMPONENT_BITS; bit++) {
|
||||||
|
if ((left.c[i] & (1 << bit)) != 0) {
|
||||||
|
result += mod_two_power;
|
||||||
|
if (result >= right) {
|
||||||
|
result -= right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod_two_power <<= 1;
|
||||||
|
if (mod_two_power >= right) {
|
||||||
|
mod_two_power -= right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (component_t)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mod_integer(integer left, integer right, integer result) {
|
||||||
|
integer mod_two_power = create_integer(right.num_components + 1);
|
||||||
|
int i, bit;
|
||||||
|
set_zero_integer(result);
|
||||||
|
set_zero_integer(mod_two_power);
|
||||||
|
mod_two_power.c[0] = 1;
|
||||||
|
for(i=0; i<left.num_components; i++) {
|
||||||
|
for(bit=0; bit<COMPONENT_BITS; bit++) {
|
||||||
|
if ((left.c[i] & (1 << bit)) != 0) {
|
||||||
|
add_integer(result, mod_two_power, result);
|
||||||
|
if (compare_integers(result, right) >= 0) {
|
||||||
|
subtract_integer(result, right, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shift_left_one_integer(mod_two_power);
|
||||||
|
if (compare_integers(mod_two_power, right) >= 0) {
|
||||||
|
subtract_integer(mod_two_power, right, mod_two_power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_integer(mod_two_power);
|
||||||
|
}
|
||||||
|
|
||||||
|
void divide_small_integer(integer left, component_t right, integer result) {
|
||||||
|
double_component_t dividend = 0;
|
||||||
|
int i;
|
||||||
|
for (i = left.num_components - 1; i >= 0; i--) {
|
||||||
|
dividend |= left.c[i];
|
||||||
|
result.c[i] = dividend/right;
|
||||||
|
dividend = (dividend % right) << COMPONENT_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
integer string_to_integer(char* s) {
|
||||||
|
integer result = create_integer((int)ceil(LOG_2_10*strlen(s)/COMPONENT_BITS));
|
||||||
|
set_zero_integer(result);
|
||||||
|
integer digit = create_integer(1);
|
||||||
|
int i;
|
||||||
|
for (i = 0; s[i] != '\0'; i++) {
|
||||||
|
multiply_small_integer(result, 10, result);
|
||||||
|
digit.c[0] = s[i] - '0';
|
||||||
|
add_integer(result, digit, result);
|
||||||
|
}
|
||||||
|
free_integer(digit);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* integer_to_string(integer x) {
|
||||||
|
int i, result_len;
|
||||||
|
char* result =
|
||||||
|
(char*)malloc((int)ceil(COMPONENT_BITS*x.num_components/LOG_2_10) + 2);
|
||||||
|
integer ten = create_integer(1);
|
||||||
|
ten.c[0] = 10;
|
||||||
|
|
||||||
|
if (is_zero_integer(x)) {
|
||||||
|
strcpy(result, "0");
|
||||||
|
} else {
|
||||||
|
for (i = 0; !is_zero_integer(x); i++) {
|
||||||
|
result[i] = (char)mod_small_integer(x, 10) + '0';
|
||||||
|
divide_small_integer(x, 10, x);
|
||||||
|
}
|
||||||
|
result[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
result_len = strlen(result);
|
||||||
|
for(i=0; i < result_len/2; i++) {
|
||||||
|
char temp = result[i];
|
||||||
|
result[i] = result[result_len - i - 1];
|
||||||
|
result[result_len - i - 1] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_integer(ten);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class UnsignedIntegerTests : public UnitTest
|
class UnsignedIntegerTests : public UnitTest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -27,21 +348,21 @@ public:
|
|||||||
template <unsigned int Bytes>
|
template <unsigned int Bytes>
|
||||||
void runTest ()
|
void runTest ()
|
||||||
{
|
{
|
||||||
|
typedef UnsignedInteger <Bytes> UInt;
|
||||||
|
|
||||||
String s;
|
String s;
|
||||||
|
|
||||||
s << "Bytes=" << String(Bytes);
|
s << "Bytes=" << String(Bytes);
|
||||||
|
|
||||||
beginTestCase (s);
|
beginTestCase (s);
|
||||||
|
|
||||||
UnsignedInteger <Bytes> zero;
|
UInt zero;
|
||||||
zero.fill (0);
|
zero.fill (0);
|
||||||
expect (zero.isZero (), "should be zero");
|
expect (zero.isZero (), "should be zero");
|
||||||
expect (! zero.isNotZero (), "sould not be non-zero");
|
expect (! zero.isNotZero (), "sould not be non-zero");
|
||||||
|
|
||||||
UnsignedInteger <Bytes> one;
|
UInt one (UInt::createFromInteger (1U));
|
||||||
one.clear ();
|
expect (one == UInt::createFromInteger (1U), "should be equal");
|
||||||
one [Bytes - 1] = 1;
|
|
||||||
expect (one == UnsignedInteger <Bytes>::createFromInteger (1U), "should be equal");
|
|
||||||
|
|
||||||
expect (! one.isZero (), "should not be zero");
|
expect (! one.isZero (), "should not be zero");
|
||||||
expect (one.isNotZero (), "sould be non-zero");
|
expect (one.isNotZero (), "sould be non-zero");
|
||||||
@@ -54,23 +375,13 @@ public:
|
|||||||
expect (zero == zero, "should be equal");
|
expect (zero == zero, "should be equal");
|
||||||
expect (zero != one, "should not be equal");
|
expect (zero != one, "should not be equal");
|
||||||
|
|
||||||
expect ((zero | zero) == zero, "should be zero");
|
expect (zero == UInt::createFromInteger (0U), "should be zero");
|
||||||
expect ((zero | one) != zero, "should not be zero");
|
expect (one == UInt::createFromInteger (1U), "should be one");
|
||||||
expect ((one | one) != zero, "should not be zero");
|
expect (one != UInt::createFromInteger (2U), "should not be two");
|
||||||
|
|
||||||
expect ((one & zero) == zero, "should be zero");
|
UInt largest = UInt::createFilled (0xff);
|
||||||
expect ((one & one) == one, "should be one");
|
|
||||||
expect ((zero & zero) == zero, "should be zero");
|
|
||||||
|
|
||||||
expect (zero == UnsignedInteger <Bytes>::createFromInteger (0U), "should be zero");
|
|
||||||
expect (one == UnsignedInteger <Bytes>::createFromInteger (1U), "should be one");
|
|
||||||
expect (one != UnsignedInteger <Bytes>::createFromInteger (2U), "should not be two");
|
|
||||||
|
|
||||||
UnsignedInteger <Bytes> largest = UnsignedInteger <Bytes>::createFilled (0xff);
|
|
||||||
|
|
||||||
expect (largest > zero && largest > one, "should be greater");
|
expect (largest > zero && largest > one, "should be greater");
|
||||||
expect (~largest == zero, "should be zero");
|
|
||||||
expect (~one < largest, "should be less");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void runTest()
|
void runTest()
|
||||||
|
|||||||
@@ -17,15 +17,18 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_UNSIGNEDINTEGER_H_INCLUDED
|
#ifndef BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED
|
||||||
#define BEAST_UNSIGNEDINTEGER_H_INCLUDED
|
#define BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED
|
||||||
|
|
||||||
/** Represents a set of bits of fixed size.
|
/** Represents a set of bits of fixed size.
|
||||||
Integer representations are stored in network / big endian byte order.
|
|
||||||
@note The number of bits represented can only be a multiple of 8.
|
The data is stored in "canonical" format which is network (big endian)
|
||||||
@tparam Bytes The number of bytes of storage.
|
byte order, most significant byte first.
|
||||||
|
|
||||||
|
In this implementation the pointer to the beginning of the canonical format
|
||||||
|
may not be aligned.
|
||||||
*/
|
*/
|
||||||
template <size_t Bytes>
|
template <std::size_t Bytes>
|
||||||
class UnsignedInteger : public SafeBool <UnsignedInteger <Bytes> >
|
class UnsignedInteger : public SafeBool <UnsignedInteger <Bytes> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -36,10 +39,16 @@ public:
|
|||||||
sizeInBytes = Bytes
|
sizeInBytes = Bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The underlying integer type we use when converting to calculation format.
|
||||||
|
typedef uint32 IntCalcType;
|
||||||
|
|
||||||
|
// The type of object resulting from a conversion to calculation format.
|
||||||
|
typedef UnsignedIntegerCalc <IntCalcType> CalcType;
|
||||||
|
|
||||||
// Standard container compatibility
|
// Standard container compatibility
|
||||||
typedef uint8 value_type;
|
typedef uint8 ValueType;
|
||||||
typedef value_type* iterator;
|
typedef ValueType* iterator;
|
||||||
typedef value_type const* const_iterator;
|
typedef ValueType const* const_iterator;
|
||||||
|
|
||||||
/** Hardened hash function for use with HashMap.
|
/** Hardened hash function for use with HashMap.
|
||||||
The seed is used to make the hash unpredictable. This prevents
|
The seed is used to make the hash unpredictable. This prevents
|
||||||
@@ -61,14 +70,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Generates a simple hash from an UnsignedInteger. */
|
/** Generates a simple hash from an UnsignedInteger. */
|
||||||
HashValue generateHash (UnsignedInteger <Bytes> const& key) const noexcept
|
HashValue generateHash (UnsignedInteger const& key) const
|
||||||
{
|
{
|
||||||
HashValue hash;
|
HashValue hash;
|
||||||
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashValue operator() (UnsignedInteger <Bytes> const& key) const noexcept
|
HashValue operator() (UnsignedInteger const& key) const
|
||||||
{
|
{
|
||||||
HashValue hash;
|
HashValue hash;
|
||||||
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
||||||
@@ -84,12 +93,12 @@ public:
|
|||||||
/** Construct the object.
|
/** Construct the object.
|
||||||
The values are uninitialized.
|
The values are uninitialized.
|
||||||
*/
|
*/
|
||||||
UnsignedInteger () noexcept
|
UnsignedInteger ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a copy. */
|
/** Construct a copy. */
|
||||||
UnsignedInteger (UnsignedInteger <Bytes> const& other) noexcept
|
UnsignedInteger (UnsignedInteger const& other)
|
||||||
{
|
{
|
||||||
this->operator= (other);
|
this->operator= (other);
|
||||||
}
|
}
|
||||||
@@ -101,37 +110,31 @@ public:
|
|||||||
/** @{ */
|
/** @{ */
|
||||||
explicit UnsignedInteger (void const* buf)
|
explicit UnsignedInteger (void const* buf)
|
||||||
{
|
{
|
||||||
|
m_values [0] = 0; // clear any pad bytes
|
||||||
std::memcpy (begin(), buf, Bytes);
|
std::memcpy (begin(), buf, Bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
explicit UnsignedInteger (T const* buf)
|
explicit UnsignedInteger (T const* buf)
|
||||||
{
|
{
|
||||||
|
m_values [0] = 0; // clear any pad bytes
|
||||||
std::memcpy (begin(), buf, Bytes);
|
std::memcpy (begin(), buf, Bytes);
|
||||||
}
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/** Construct from a sequence. */
|
/** Assign from another UnsignedInteger. */
|
||||||
template <class ForwardIterator>
|
UnsignedInteger& operator= (UnsignedInteger const& other)
|
||||||
UnsignedInteger (ForwardIterator start, ForwardIterator finish)
|
|
||||||
{
|
{
|
||||||
bassert (std::distance (start, finish) == Bytes);
|
// Perform an aligned, all inclusive copy that includes padding.
|
||||||
std::copy (start, finish, begin());
|
std::copy (other.m_values, other.m_values + CalcCount, m_values);
|
||||||
}
|
|
||||||
|
|
||||||
/** Assign from another value. */
|
|
||||||
UnsignedInteger <Bytes>& operator= (UnsignedInteger const& other) noexcept
|
|
||||||
{
|
|
||||||
std::memcpy (begin(), other.begin(), Bytes);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create from an integer type.
|
/** Create from an integer type.
|
||||||
|
|
||||||
@invariant IntegerType must be an unsigned integer type.
|
@invariant IntegerType must be an unsigned integer type.
|
||||||
*/
|
*/
|
||||||
template <class IntegerType>
|
template <class IntegerType>
|
||||||
static UnsignedInteger <Bytes> createFromInteger (IntegerType value)
|
static UnsignedInteger createFromInteger (IntegerType value)
|
||||||
{
|
{
|
||||||
static_bassert (Bytes >= sizeof (IntegerType));
|
static_bassert (Bytes >= sizeof (IntegerType));
|
||||||
UnsignedInteger <Bytes> result;
|
UnsignedInteger <Bytes> result;
|
||||||
@@ -143,31 +146,39 @@ public:
|
|||||||
|
|
||||||
/** Construct with a filled value.
|
/** Construct with a filled value.
|
||||||
*/
|
*/
|
||||||
static UnsignedInteger <Bytes> createFilled (value_type value)
|
static UnsignedInteger createFilled (ValueType value)
|
||||||
{
|
{
|
||||||
UnsignedInteger <Bytes> result;
|
UnsignedInteger result;
|
||||||
result.fill (value);
|
result.fill (value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fill with a particular byte value. */
|
/** Fill with a particular byte value. */
|
||||||
void fill (value_type value) noexcept
|
void fill (ValueType value)
|
||||||
{
|
{
|
||||||
std::fill (begin(), end(), value);
|
IntCalcType c;
|
||||||
|
memset (&c, value, sizeof (c));
|
||||||
|
std::fill (m_values, m_values + CalcCount, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clear the contents to zero. */
|
/** Clear the contents to zero. */
|
||||||
void clear () noexcept
|
void clear ()
|
||||||
{
|
{
|
||||||
fill (0);
|
std::fill (m_values, m_values + CalcCount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert to calculation format. */
|
||||||
|
CalcType toCalcType (bool convert = true)
|
||||||
|
{
|
||||||
|
return CalcType::fromCanonical (m_values, Bytes, convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Determine if all bits are zero. */
|
/** Determine if all bits are zero. */
|
||||||
bool isZero () const noexcept
|
bool isZero () const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Bytes; ++i)
|
for (int i = 0; i < Bytes; ++i)
|
||||||
{
|
{
|
||||||
if (m_byte [i] != 0)
|
if (m_values [i] != 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +186,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Determine if any bit is non-zero. */
|
/** Determine if any bit is non-zero. */
|
||||||
bool isNotZero () const noexcept
|
bool isNotZero () const
|
||||||
{
|
{
|
||||||
return ! isZero ();
|
return ! isZero ();
|
||||||
}
|
}
|
||||||
@@ -184,198 +195,107 @@ public:
|
|||||||
@return `true` if any bit is non-zero.
|
@return `true` if any bit is non-zero.
|
||||||
@see SafeBool
|
@see SafeBool
|
||||||
*/
|
*/
|
||||||
bool asBoolean () const noexcept
|
bool asBoolean () const
|
||||||
{
|
{
|
||||||
return isNotZero ();
|
return isNotZero ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Access a particular byte. */
|
|
||||||
value_type& getByte (int byteIndex) noexcept
|
|
||||||
{
|
|
||||||
bassert (byteIndex >= 0 && byteIndex < Bytes);
|
|
||||||
|
|
||||||
return m_byte [byteIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Access a particular byte as `const`. */
|
|
||||||
value_type getByte (int byteIndex) const noexcept
|
|
||||||
{
|
|
||||||
bassert (byteIndex >= 0 && byteIndex < Bytes);
|
|
||||||
|
|
||||||
return m_byte [byteIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Access a particular byte. */
|
|
||||||
value_type& operator[] (int byteIndex) noexcept
|
|
||||||
{
|
|
||||||
return getByte (byteIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Access a particular byte as `const`. */
|
|
||||||
value_type const operator[] (int byteIndex) const noexcept
|
|
||||||
{
|
|
||||||
return getByte (byteIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get an iterator to the beginning. */
|
/** Get an iterator to the beginning. */
|
||||||
iterator begin () noexcept
|
iterator begin ()
|
||||||
{
|
{
|
||||||
return &m_byte [0];
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get an iterator to past-the-end. */
|
/** Get an iterator to past-the-end. */
|
||||||
iterator end () noexcept
|
iterator end ()
|
||||||
{
|
{
|
||||||
return &m_byte [Bytes];
|
return get()+Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a const iterator to the beginning. */
|
/** Get a const iterator to the beginning. */
|
||||||
const_iterator begin () const noexcept
|
const_iterator begin () const
|
||||||
{
|
{
|
||||||
return &m_byte [0];
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a const iterator to past-the-end. */
|
/** Get a const iterator to past-the-end. */
|
||||||
const_iterator end () const noexcept
|
const_iterator end () const
|
||||||
{
|
{
|
||||||
return &m_byte [Bytes];
|
return get()+Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a const iterator to the beginning. */
|
/** Get a const iterator to the beginning. */
|
||||||
const_iterator cbegin () const noexcept
|
const_iterator cbegin () const
|
||||||
{
|
{
|
||||||
return &m_byte [0];
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a const iterator to past-the-end. */
|
/** Get a const iterator to past-the-end. */
|
||||||
const_iterator cend () const noexcept
|
const_iterator cend () const
|
||||||
{
|
{
|
||||||
return &m_byte [Bytes];
|
return get()+Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compare two objects. */
|
/** Compare two objects of equal size.
|
||||||
int compare (UnsignedInteger <Bytes> const& other) const noexcept
|
The comparison is performed using a numeric lexicographical comparison.
|
||||||
|
*/
|
||||||
|
int compare (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return memcmp (cbegin (), other.cbegin (), Bytes);
|
return memcmp (cbegin (), other.cbegin (), Bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Determine equality. */
|
/** Determine equality. */
|
||||||
bool operator== (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator== (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) == 0;
|
return compare (other) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Determine inequality. */
|
/** Determine inequality. */
|
||||||
bool operator!= (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator!= (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) != 0;
|
return compare (other) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ordered comparison. */
|
/** Ordered comparison. */
|
||||||
bool operator< (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator< (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) < 0;
|
return compare (other) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ordered comparison. */
|
/** Ordered comparison. */
|
||||||
bool operator<= (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator<= (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) <= 0;
|
return compare (other) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ordered comparison. */
|
/** Ordered comparison. */
|
||||||
bool operator> (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator> (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) > 0;
|
return compare (other) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Ordered comparison. */
|
/** Ordered comparison. */
|
||||||
bool operator>= (UnsignedInteger <Bytes> const& other) const noexcept
|
bool operator>= (UnsignedInteger const& other) const
|
||||||
{
|
{
|
||||||
return compare (other) >= 0;
|
return compare (other) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Perform bitwise logical-not. */
|
|
||||||
UnsignedInteger <Bytes> operator~ () const noexcept
|
|
||||||
{
|
|
||||||
UnsignedInteger <Bytes> result;
|
|
||||||
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
result [i] = ~getByte (i);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-or. */
|
|
||||||
UnsignedInteger <Bytes>& operator|= (UnsignedInteger <Bytes> const& rhs) noexcept
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
getByte (i) |= rhs [i];
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-or. */
|
|
||||||
UnsignedInteger <Bytes> operator| (UnsignedInteger <Bytes> const& rhs) const noexcept
|
|
||||||
{
|
|
||||||
UnsignedInteger <Bytes> result;
|
|
||||||
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
result [i] = getByte (i) | rhs [i];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-and. */
|
|
||||||
UnsignedInteger <Bytes>& operator&= (UnsignedInteger <Bytes> const& rhs) noexcept
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
getByte (i) &= rhs [i];
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-and. */
|
|
||||||
UnsignedInteger <Bytes> operator& (UnsignedInteger <Bytes> const& rhs) const noexcept
|
|
||||||
{
|
|
||||||
UnsignedInteger <Bytes> result;
|
|
||||||
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
result [i] = getByte (i) & rhs [i];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-xor. */
|
|
||||||
UnsignedInteger <Bytes>& operator^= (UnsignedInteger <Bytes> const& rhs) noexcept
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
getByte (i) ^= rhs [i];
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform bitwise logical-xor. */
|
|
||||||
UnsignedInteger <Bytes> operator^ (UnsignedInteger <Bytes> const& rhs) const noexcept
|
|
||||||
{
|
|
||||||
UnsignedInteger <Bytes> result;
|
|
||||||
|
|
||||||
for (int i = 0; i < Bytes; ++i)
|
|
||||||
result [i] = getByte (i) ^ rhs [i];
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VFALCO TODO:
|
|
||||||
//
|
|
||||||
// increment, decrement, add, subtract
|
|
||||||
// negate
|
|
||||||
// other stuff that makes sense from base_uint <>
|
|
||||||
// missing stuff that built-in integers do
|
|
||||||
//
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type m_byte [Bytes];
|
static std::size_t const CalcCount = (Bytes + sizeof (IntCalcType) - 1) / sizeof (IntCalcType);
|
||||||
|
|
||||||
|
ValueType* get ()
|
||||||
|
{
|
||||||
|
return (reinterpret_cast <ValueType*> (&m_values [0])) +
|
||||||
|
((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType const* get () const
|
||||||
|
{
|
||||||
|
return (reinterpret_cast <ValueType const*> (&m_values [0])) +
|
||||||
|
((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntCalcType m_values [CalcCount];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
428
modules/beast_crypto/math/UnsignedIntegerCalc.h
Normal file
428
modules/beast_crypto/math/UnsignedIntegerCalc.h
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_CRYPTO_UNSIGNEDINTEGERCALC_H_INCLUDED
|
||||||
|
#define BEAST_CRYPTO_UNSIGNEDINTEGERCALC_H_INCLUDED
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename UInt>
|
||||||
|
struct DoubleWidthUInt;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DoubleWidthUInt <uint16>
|
||||||
|
{
|
||||||
|
typedef uint32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct DoubleWidthUInt <uint32>
|
||||||
|
{
|
||||||
|
typedef uint64 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Multiprecision unsigned integer suitable for calculations.
|
||||||
|
|
||||||
|
The data is stored in "calculation" format, which means it can be
|
||||||
|
readily used for performing calculations, but no raw access to the
|
||||||
|
bytes are provided. To transmit a serialized unsigned integer or
|
||||||
|
perform base encodings, it must be converted back into UnsignedInteger.
|
||||||
|
The number is represented as a series of native UInt unsigned integer
|
||||||
|
types, in order of increasing significance.
|
||||||
|
|
||||||
|
This is a lightweight object, storage and ownership of the underlying
|
||||||
|
data buffer is an external responsibility. The makes the class cheap to
|
||||||
|
copy and pass by value.
|
||||||
|
|
||||||
|
A consequence of this ownership model is that arithmetics operators
|
||||||
|
which return results by value cannot be included in the interface.
|
||||||
|
*/
|
||||||
|
template <typename UInt>
|
||||||
|
class UnsignedIntegerCalc : public SafeBool <UnsignedIntegerCalc <UInt> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef typename detail::DoubleWidthUInt <UInt>::type UIntBig;
|
||||||
|
|
||||||
|
typedef std::size_t size_type;
|
||||||
|
|
||||||
|
static UInt const maxUInt = ((UInt)(-1));
|
||||||
|
static size_type const numBits = (sizeof(UInt)*8);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Construct an empty integer / zero bits. */
|
||||||
|
UnsignedIntegerCalc ()
|
||||||
|
: m_size (0)
|
||||||
|
, m_values (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct a reference to an existing buffer. */
|
||||||
|
UnsignedIntegerCalc (UnsignedIntegerCalc const& other)
|
||||||
|
: m_size (other.m_size)
|
||||||
|
, m_values (other.m_values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Construct from an existing array of values.
|
||||||
|
The existing data must already be in the "calculation" format.
|
||||||
|
*/
|
||||||
|
UnsignedIntegerCalc (size_type count, UInt* values)
|
||||||
|
: m_size (count)
|
||||||
|
, m_values (values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert to calculation format from canonical format.
|
||||||
|
This overwrites the callers memory without transferring ownership.
|
||||||
|
Canonical format is defined as a big endian byte oriented
|
||||||
|
multiprecision integer format. The buffer should point to the
|
||||||
|
beginning of the storage area and not the beginning of the canonical
|
||||||
|
data. Bytes is the desired canonical bytes.
|
||||||
|
*/
|
||||||
|
static UnsignedIntegerCalc fromCanonical (
|
||||||
|
void* buffer, size_type const bytes, bool swizzle = true)
|
||||||
|
{
|
||||||
|
UInt* const values (reinterpret_cast <UInt*> (buffer));
|
||||||
|
size_type const count ((bytes + sizeof (UInt) - 1) / sizeof (UInt));
|
||||||
|
if (swizzle)
|
||||||
|
{
|
||||||
|
// Zero fill the possibly uninitialized pad bytes
|
||||||
|
memset (buffer, 0,
|
||||||
|
((sizeof(UInt)-(bytes&(sizeof(UInt)-1)))&(sizeof(UInt)-1)));
|
||||||
|
// Swap and swizzle
|
||||||
|
UInt* lo (values);
|
||||||
|
UInt* hi (values + count - 1);
|
||||||
|
while (lo < hi)
|
||||||
|
{
|
||||||
|
std::swap (*lo, *hi);
|
||||||
|
*lo++ = fromNetworkByteOrder <UInt> (*lo);
|
||||||
|
*hi-- = fromNetworkByteOrder <UInt> (*hi);
|
||||||
|
}
|
||||||
|
if (lo == hi)
|
||||||
|
*lo = fromNetworkByteOrder <UInt> (*lo);
|
||||||
|
}
|
||||||
|
return UnsignedIntegerCalc (count, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert the buffer back into canonical format.
|
||||||
|
Since ownership was never transferred, the caller's data is
|
||||||
|
restored to its original format. Typically this will be done
|
||||||
|
as the last step of a series of operations.
|
||||||
|
*/
|
||||||
|
void toCanonical ()
|
||||||
|
{
|
||||||
|
// Swap and swizzle
|
||||||
|
UInt* lo (m_values);
|
||||||
|
UInt* hi (m_values + m_size - 1);
|
||||||
|
while (lo < hi)
|
||||||
|
{
|
||||||
|
std::swap (*lo, *hi);
|
||||||
|
*lo++ = toNetworkByteOrder <UInt> (*lo);
|
||||||
|
*hi-- = toNetworkByteOrder <UInt> (*hi);
|
||||||
|
}
|
||||||
|
if (lo == hi)
|
||||||
|
*lo = toNetworkByteOrder <UInt> (*lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assign a value from another integer.
|
||||||
|
@note This does not transfer the reference to the buffer, it
|
||||||
|
copies the values from one buffer to the other.
|
||||||
|
*/
|
||||||
|
UnsignedIntegerCalc& operator= (UnsignedIntegerCalc const& other)
|
||||||
|
{
|
||||||
|
bassert (other.size() <= size());
|
||||||
|
size_type n (size());
|
||||||
|
UInt* dest (m_values + size());
|
||||||
|
for (; n-- > other.size();)
|
||||||
|
*--dest = 0;
|
||||||
|
UInt const* rhs (other.m_values + n);
|
||||||
|
for (; n--;)
|
||||||
|
*--dest = *--rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if this represents the number zero. */
|
||||||
|
bool isZero () const
|
||||||
|
{
|
||||||
|
for (size_type n (size()); n--;)
|
||||||
|
if (m_values [n] != 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if this represents any number other than zero. */
|
||||||
|
bool isNotZero () const
|
||||||
|
{
|
||||||
|
return ! isZero ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Safe conversion to `bool`, `true` means a non-zero value. */
|
||||||
|
bool asBoolean () const
|
||||||
|
{
|
||||||
|
return isNotZero ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns `true` if the buffer has 0 values. */
|
||||||
|
bool empty () const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the size of the buffer, in values. */
|
||||||
|
size_type size () const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Safe array indexing to arbitrary positions.
|
||||||
|
If the index is out of range, zero is returned.
|
||||||
|
*/
|
||||||
|
UInt operator[] (size_type n) const
|
||||||
|
{
|
||||||
|
if (n >= 0 && n < size())
|
||||||
|
return m_values [n];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Universal comparison.
|
||||||
|
The comparison is performed numerically.
|
||||||
|
The return values have the same meaning as memcmp().
|
||||||
|
*/
|
||||||
|
int compare (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
if (size() == 0)
|
||||||
|
{
|
||||||
|
if (other.size() == 0)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (other.size() == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_type n (std::max (size(), other.size())); n--;)
|
||||||
|
{
|
||||||
|
UInt lhs ((*this)[n]);
|
||||||
|
UInt rhs (other[n]);
|
||||||
|
if (lhs < rhs)
|
||||||
|
return -1;
|
||||||
|
else if (lhs > rhs)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determine equality. */
|
||||||
|
bool operator== (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determine inequality. */
|
||||||
|
bool operator!= (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ordered comparison. */
|
||||||
|
bool operator< (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ordered comparison. */
|
||||||
|
bool operator<= (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ordered comparison. */
|
||||||
|
bool operator> (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ordered comparison. */
|
||||||
|
bool operator>= (UnsignedIntegerCalc const& other) const
|
||||||
|
{
|
||||||
|
return compare (other) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Assign zero. */
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
UInt* dest (m_values - 1);
|
||||||
|
for (size_type n (size()); n--;)
|
||||||
|
*++dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform bitwise logical-not. */
|
||||||
|
/*
|
||||||
|
UnsignedIntegerCalc& not ()
|
||||||
|
{
|
||||||
|
unaryAssign (Not());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Perform bitwise logical-or. */
|
||||||
|
UnsignedIntegerCalc& operator|= (UnsignedIntegerCalc const& rhs)
|
||||||
|
{
|
||||||
|
binaryAssign (rhs, Or());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform bitwise logical-and. */
|
||||||
|
UnsignedIntegerCalc& operator&= (UnsignedIntegerCalc const& rhs)
|
||||||
|
{
|
||||||
|
binaryAssign (rhs, And());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform bitwise logical-xor. */
|
||||||
|
UnsignedIntegerCalc& operator^= (UnsignedIntegerCalc const& rhs)
|
||||||
|
{
|
||||||
|
binaryAssign (rhs, Xor());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform addition. */
|
||||||
|
UnsignedIntegerCalc& operator+= (UnsignedIntegerCalc const& v)
|
||||||
|
{
|
||||||
|
UIntBig carry (0);
|
||||||
|
UInt* lhs (m_values);
|
||||||
|
UInt const* rhs (v.m_values - 1);
|
||||||
|
for (size_type n (0); n<size() || n<v.size(); ++n)
|
||||||
|
{
|
||||||
|
UIntBig part (carry);
|
||||||
|
carry = 0;
|
||||||
|
if (n < size())
|
||||||
|
part += *lhs;
|
||||||
|
if (n < v.size())
|
||||||
|
part += *++rhs;
|
||||||
|
if (part > maxUInt)
|
||||||
|
{
|
||||||
|
part &= maxUInt;
|
||||||
|
carry = 1;
|
||||||
|
}
|
||||||
|
*lhs++ = UInt (part);
|
||||||
|
}
|
||||||
|
bassert (carry == 0) // overflow
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform small addition. */
|
||||||
|
UnsignedIntegerCalc& operator+= (UInt rhs)
|
||||||
|
{
|
||||||
|
UnsignedIntegerCalc const v (1, &rhs);
|
||||||
|
return operator+= (v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform small multiply. */
|
||||||
|
UnsignedIntegerCalc& operator*= (UInt rhs)
|
||||||
|
{
|
||||||
|
UIntBig carry (0);
|
||||||
|
UInt* lhs (m_values - 1);
|
||||||
|
for (size_type n (size()); n--;)
|
||||||
|
{
|
||||||
|
UIntBig part (carry);
|
||||||
|
carry = 0;
|
||||||
|
part += (*++lhs) * UIntBig(rhs);
|
||||||
|
carry = part >> numBits;
|
||||||
|
*lhs = UInt (part & maxUInt);
|
||||||
|
}
|
||||||
|
bassert (carry == 0); // overflow
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Small division. */
|
||||||
|
UnsignedIntegerCalc operator/= (UInt rhs)
|
||||||
|
{
|
||||||
|
UIntBig dividend (0);
|
||||||
|
UInt* lhs (m_values+size());
|
||||||
|
for (size_type n (size()); n--;)
|
||||||
|
{
|
||||||
|
dividend |= *--lhs;
|
||||||
|
*lhs = UInt (dividend / rhs);
|
||||||
|
dividend = (dividend % rhs) << numBits;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Small modulus. */
|
||||||
|
UInt operator% (UInt rhs) const
|
||||||
|
{
|
||||||
|
UIntBig modsq = 1;
|
||||||
|
UIntBig result = 0;
|
||||||
|
UInt const* lhs (m_values);
|
||||||
|
for (size_type n (size()); n--; ++lhs)
|
||||||
|
{
|
||||||
|
for (int bit (0); bit < numBits; ++bit)
|
||||||
|
{
|
||||||
|
if (((*lhs) & (1 << bit)) != 0)
|
||||||
|
{
|
||||||
|
result += modsq;
|
||||||
|
if (result >= rhs)
|
||||||
|
result -= rhs;
|
||||||
|
}
|
||||||
|
modsq <<= 1;
|
||||||
|
if (modsq >= rhs)
|
||||||
|
modsq -= rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UInt (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Not { void operator() (UInt& rv) const { rv = ~rv; } };
|
||||||
|
struct Or { void operator() (UInt& lhs, UInt rhs) const { lhs |= rhs; } };
|
||||||
|
struct And { void operator() (UInt& lhs, UInt rhs) const { lhs &= rhs; } };
|
||||||
|
struct Xor { void operator() (UInt& lhs, UInt rhs) const { lhs ^= rhs; } };
|
||||||
|
|
||||||
|
template <class Operator>
|
||||||
|
void unaryAssign (Operator op = Operator())
|
||||||
|
{
|
||||||
|
UInt* dest (m_values-1);
|
||||||
|
for (size_type n (size()); n--;)
|
||||||
|
op (*++dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Operator>
|
||||||
|
void binaryAssign (UnsignedIntegerCalc const& other, Operator op = Operator ())
|
||||||
|
{
|
||||||
|
UInt* dest (m_values + size());
|
||||||
|
size_type n (size());
|
||||||
|
for (; n-- > other.size();)
|
||||||
|
*--dest = 0;
|
||||||
|
UInt const* rhs (other.m_values + n);
|
||||||
|
for (UInt const* rhs (other.m_values + n); n--;)
|
||||||
|
op (*--dest, *--rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type m_size;
|
||||||
|
UInt* m_values;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user