mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-16 17:15:51 +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\zutil.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\UnsignedIntegerCalc.h" />
|
||||
<ClInclude Include="..\..\modules\beast_db\beast_db.h" />
|
||||
<ClInclude Include="..\..\modules\beast_db\keyvalue\beast_KeyvaDB.h" />
|
||||
<ClInclude Include="..\..\modules\beast_extras\beast_extras.h" />
|
||||
@@ -1265,6 +1267,12 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<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">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -1028,6 +1028,12 @@
|
||||
<ClInclude Include="..\..\modules\beast_crypto\math\UnsignedInteger.h">
|
||||
<Filter>beast_crypto\math</Filter>
|
||||
</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>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||
@@ -1552,6 +1558,9 @@
|
||||
<ClCompile Include="..\..\modules\beast_crypto\math\UnsignedInteger.cpp">
|
||||
<Filter>beast_crypto\math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_crypto\math\BinaryEncoding.cpp">
|
||||
<Filter>beast_crypto\math</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\..\TODO.txt" />
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
namespace beast
|
||||
{
|
||||
|
||||
#include "math/BinaryEncoding.cpp"
|
||||
#include "math/UnsignedInteger.cpp"
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,9 @@
|
||||
namespace beast
|
||||
{
|
||||
|
||||
# include "math/UnsignedIntegerCalc.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
|
||||
{
|
||||
public:
|
||||
@@ -27,21 +348,21 @@ public:
|
||||
template <unsigned int Bytes>
|
||||
void runTest ()
|
||||
{
|
||||
typedef UnsignedInteger <Bytes> UInt;
|
||||
|
||||
String s;
|
||||
|
||||
s << "Bytes=" << String(Bytes);
|
||||
|
||||
beginTestCase (s);
|
||||
|
||||
UnsignedInteger <Bytes> zero;
|
||||
UInt zero;
|
||||
zero.fill (0);
|
||||
expect (zero.isZero (), "should be zero");
|
||||
expect (! zero.isNotZero (), "sould not be non-zero");
|
||||
|
||||
UnsignedInteger <Bytes> one;
|
||||
one.clear ();
|
||||
one [Bytes - 1] = 1;
|
||||
expect (one == UnsignedInteger <Bytes>::createFromInteger (1U), "should be equal");
|
||||
UInt one (UInt::createFromInteger (1U));
|
||||
expect (one == UInt::createFromInteger (1U), "should be equal");
|
||||
|
||||
expect (! one.isZero (), "should not be zero");
|
||||
expect (one.isNotZero (), "sould be non-zero");
|
||||
@@ -54,23 +375,13 @@ public:
|
||||
expect (zero == zero, "should be equal");
|
||||
expect (zero != one, "should not be equal");
|
||||
|
||||
expect ((zero | zero) == zero, "should be zero");
|
||||
expect ((zero | one) != zero, "should not be zero");
|
||||
expect ((one | one) != zero, "should not be zero");
|
||||
expect (zero == UInt::createFromInteger (0U), "should be zero");
|
||||
expect (one == UInt::createFromInteger (1U), "should be one");
|
||||
expect (one != UInt::createFromInteger (2U), "should not be two");
|
||||
|
||||
expect ((one & zero) == zero, "should be zero");
|
||||
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);
|
||||
UInt largest = UInt::createFilled (0xff);
|
||||
|
||||
expect (largest > zero && largest > one, "should be greater");
|
||||
expect (~largest == zero, "should be zero");
|
||||
expect (~one < largest, "should be less");
|
||||
}
|
||||
|
||||
void runTest()
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_UNSIGNEDINTEGER_H_INCLUDED
|
||||
#define BEAST_UNSIGNEDINTEGER_H_INCLUDED
|
||||
#ifndef BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED
|
||||
#define BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED
|
||||
|
||||
/** 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.
|
||||
@tparam Bytes The number of bytes of storage.
|
||||
|
||||
The data is stored in "canonical" format which is network (big endian)
|
||||
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> >
|
||||
{
|
||||
public:
|
||||
@@ -36,10 +39,16 @@ public:
|
||||
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
|
||||
typedef uint8 value_type;
|
||||
typedef value_type* iterator;
|
||||
typedef value_type const* const_iterator;
|
||||
typedef uint8 ValueType;
|
||||
typedef ValueType* iterator;
|
||||
typedef ValueType const* const_iterator;
|
||||
|
||||
/** Hardened hash function for use with HashMap.
|
||||
The seed is used to make the hash unpredictable. This prevents
|
||||
@@ -61,14 +70,14 @@ public:
|
||||
}
|
||||
|
||||
/** Generates a simple hash from an UnsignedInteger. */
|
||||
HashValue generateHash (UnsignedInteger <Bytes> const& key) const noexcept
|
||||
HashValue generateHash (UnsignedInteger const& key) const
|
||||
{
|
||||
HashValue hash;
|
||||
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
HashValue operator() (UnsignedInteger <Bytes> const& key) const noexcept
|
||||
HashValue operator() (UnsignedInteger const& key) const
|
||||
{
|
||||
HashValue hash;
|
||||
Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash);
|
||||
@@ -84,12 +93,12 @@ public:
|
||||
/** Construct the object.
|
||||
The values are uninitialized.
|
||||
*/
|
||||
UnsignedInteger () noexcept
|
||||
UnsignedInteger ()
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct a copy. */
|
||||
UnsignedInteger (UnsignedInteger <Bytes> const& other) noexcept
|
||||
UnsignedInteger (UnsignedInteger const& other)
|
||||
{
|
||||
this->operator= (other);
|
||||
}
|
||||
@@ -101,37 +110,31 @@ public:
|
||||
/** @{ */
|
||||
explicit UnsignedInteger (void const* buf)
|
||||
{
|
||||
m_values [0] = 0; // clear any pad bytes
|
||||
std::memcpy (begin(), buf, Bytes);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
explicit UnsignedInteger (T const* buf)
|
||||
{
|
||||
m_values [0] = 0; // clear any pad bytes
|
||||
std::memcpy (begin(), buf, Bytes);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Construct from a sequence. */
|
||||
template <class ForwardIterator>
|
||||
UnsignedInteger (ForwardIterator start, ForwardIterator finish)
|
||||
/** Assign from another UnsignedInteger. */
|
||||
UnsignedInteger& operator= (UnsignedInteger const& other)
|
||||
{
|
||||
bassert (std::distance (start, finish) == Bytes);
|
||||
std::copy (start, finish, begin());
|
||||
}
|
||||
|
||||
/** Assign from another value. */
|
||||
UnsignedInteger <Bytes>& operator= (UnsignedInteger const& other) noexcept
|
||||
{
|
||||
std::memcpy (begin(), other.begin(), Bytes);
|
||||
// Perform an aligned, all inclusive copy that includes padding.
|
||||
std::copy (other.m_values, other.m_values + CalcCount, m_values);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Create from an integer type.
|
||||
|
||||
@invariant IntegerType must be an unsigned integer type.
|
||||
*/
|
||||
template <class IntegerType>
|
||||
static UnsignedInteger <Bytes> createFromInteger (IntegerType value)
|
||||
static UnsignedInteger createFromInteger (IntegerType value)
|
||||
{
|
||||
static_bassert (Bytes >= sizeof (IntegerType));
|
||||
UnsignedInteger <Bytes> result;
|
||||
@@ -143,31 +146,39 @@ public:
|
||||
|
||||
/** 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);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
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. */
|
||||
bool isZero () const noexcept
|
||||
bool isZero () const
|
||||
{
|
||||
for (int i = 0; i < Bytes; ++i)
|
||||
{
|
||||
if (m_byte [i] != 0)
|
||||
if (m_values [i] != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -175,7 +186,7 @@ public:
|
||||
}
|
||||
|
||||
/** Determine if any bit is non-zero. */
|
||||
bool isNotZero () const noexcept
|
||||
bool isNotZero () const
|
||||
{
|
||||
return ! isZero ();
|
||||
}
|
||||
@@ -184,198 +195,107 @@ public:
|
||||
@return `true` if any bit is non-zero.
|
||||
@see SafeBool
|
||||
*/
|
||||
bool asBoolean () const noexcept
|
||||
bool asBoolean () const
|
||||
{
|
||||
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. */
|
||||
iterator begin () noexcept
|
||||
iterator begin ()
|
||||
{
|
||||
return &m_byte [0];
|
||||
return get();
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
const_iterator begin () const noexcept
|
||||
const_iterator begin () const
|
||||
{
|
||||
return &m_byte [0];
|
||||
return get();
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
const_iterator cbegin () const noexcept
|
||||
const_iterator cbegin () const
|
||||
{
|
||||
return &m_byte [0];
|
||||
return get();
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
int compare (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
/** Compare two objects of equal size.
|
||||
The comparison is performed using a numeric lexicographical comparison.
|
||||
*/
|
||||
int compare (UnsignedInteger const& other) const
|
||||
{
|
||||
return memcmp (cbegin (), other.cbegin (), Bytes);
|
||||
}
|
||||
|
||||
/** Determine equality. */
|
||||
bool operator== (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator== (UnsignedInteger const& other) const
|
||||
{
|
||||
return compare (other) == 0;
|
||||
}
|
||||
|
||||
/** Determine inequality. */
|
||||
bool operator!= (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator!= (UnsignedInteger const& other) const
|
||||
{
|
||||
return compare (other) != 0;
|
||||
}
|
||||
|
||||
/** Ordered comparison. */
|
||||
bool operator< (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator< (UnsignedInteger const& other) const
|
||||
{
|
||||
return compare (other) < 0;
|
||||
}
|
||||
|
||||
/** Ordered comparison. */
|
||||
bool operator<= (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator<= (UnsignedInteger const& other) const
|
||||
{
|
||||
return compare (other) <= 0;
|
||||
}
|
||||
|
||||
/** Ordered comparison. */
|
||||
bool operator> (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator> (UnsignedInteger const& other) const
|
||||
{
|
||||
return compare (other) > 0;
|
||||
}
|
||||
|
||||
/** Ordered comparison. */
|
||||
bool operator>= (UnsignedInteger <Bytes> const& other) const noexcept
|
||||
bool operator>= (UnsignedInteger const& other) const
|
||||
{
|
||||
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:
|
||||
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
|
||||
|
||||
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