diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj
index eb2aac8ed..99a33dcd2 100644
--- a/Builds/VisualStudio2012/beast.vcxproj
+++ b/Builds/VisualStudio2012/beast.vcxproj
@@ -323,7 +323,9 @@
+
+
@@ -1265,6 +1267,12 @@
true
+
+ true
+ true
+ true
+ true
+
true
true
diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters
index db6326b29..8e6eaabfb 100644
--- a/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -1028,6 +1028,12 @@
beast_crypto\math
+
+ beast_crypto\math
+
+
+ beast_crypto\math
+
@@ -1552,6 +1558,9 @@
beast_crypto\math
+
+ beast_crypto\math
+
diff --git a/modules/beast_crypto/beast_crypto.cpp b/modules/beast_crypto/beast_crypto.cpp
index 072c02ddb..f5ef3ad86 100644
--- a/modules/beast_crypto/beast_crypto.cpp
+++ b/modules/beast_crypto/beast_crypto.cpp
@@ -24,6 +24,7 @@
namespace beast
{
+#include "math/BinaryEncoding.cpp"
#include "math/UnsignedInteger.cpp"
}
diff --git a/modules/beast_crypto/beast_crypto.h b/modules/beast_crypto/beast_crypto.h
index 4556a5fac..4e9039bbc 100644
--- a/modules/beast_crypto/beast_crypto.h
+++ b/modules/beast_crypto/beast_crypto.h
@@ -44,7 +44,9 @@
namespace beast
{
+# include "math/UnsignedIntegerCalc.h"
#include "math/UnsignedInteger.h"
+#include "math/BinaryEncoding.h"
}
diff --git a/modules/beast_crypto/math/BinaryEncoding.cpp b/modules/beast_crypto/math/BinaryEncoding.cpp
new file mode 100644
index 000000000..c67e4396c
--- /dev/null
+++ b/modules/beast_crypto/math/BinaryEncoding.cpp
@@ -0,0 +1,395 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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
+ static std::string encode (UnsignedInteger v, Conversion c = Conversion ())
+ {
+ // bi is destroyed in this process
+ typename UnsignedInteger ::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
+ static bool decode (UnsignedInteger & rv,
+ std::string const& s, Conversion c = Conversion ())
+ {
+ typename UnsignedInteger ::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 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 const& inverse_alphabet ()
+ {
+ static std::vector t (invert (Conversion::alphabet(), Conversion::radix));
+ return t;
+ }
+
+ /** Build the inverse mapping table from characters to digits. */
+ static std::vector invert (std::string const& alphabet, std::size_t radix)
+ {
+ std::vector 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
+ static std::string encode (UnsignedInteger 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
+ static bool decode (UnsignedInteger & 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 const& inverse_alphabet ()
+ {
+ static std::vector s (invert (alphabet(), 16));
+ return s;
+ }
+
+ /** Build the inverse mapping table from characters to digits. */
+ static std::vector invert (std::string const& alphabet, std::size_t radix)
+ {
+ std::vector 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
+{
+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
+{
+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
+{
+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
+{
+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
+ void testBase16 ()
+ {
+ beginTestCase ("base16");
+ for (int i = 0; i < 50; ++i)
+ {
+ typedef UnsignedInteger 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
+ void testBase64Bytes (
+ std::string const& vin, std::string const& vout,
+ Base64Conversion c = Base64Conversion ())
+ {
+ typedef UnsignedInteger 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
+ void testEncode (Conversion c = Conversion())
+ {
+ typedef UnsignedInteger 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 ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+
+ testBase64 ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+ testEncode ();
+#endif
+ }
+
+ BinaryEncodingTests () : UnitTest ("BinaryEncoding", "beast", runManual)
+ {
+ }
+};
+
+static BinaryEncodingTests BinaryEncodingTests;
diff --git a/modules/beast_crypto/math/BinaryEncoding.h b/modules/beast_crypto/math/BinaryEncoding.h
new file mode 100644
index 000000000..d93691e4a
--- /dev/null
+++ b/modules/beast_crypto/math/BinaryEncoding.h
@@ -0,0 +1,24 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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
diff --git a/modules/beast_crypto/math/UnsignedInteger.cpp b/modules/beast_crypto/math/UnsignedInteger.cpp
index 2315d4344..40b079d06 100644
--- a/modules/beast_crypto/math/UnsignedInteger.cpp
+++ b/modules/beast_crypto/math/UnsignedInteger.cpp
@@ -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 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> 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= 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= 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
void runTest ()
{
+ typedef UnsignedInteger UInt;
+
String s;
s << "Bytes=" << String(Bytes);
beginTestCase (s);
- UnsignedInteger zero;
+ UInt zero;
zero.fill (0);
expect (zero.isZero (), "should be zero");
expect (! zero.isNotZero (), "sould not be non-zero");
- UnsignedInteger one;
- one.clear ();
- one [Bytes - 1] = 1;
- expect (one == UnsignedInteger ::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 ::createFromInteger (0U), "should be zero");
- expect (one == UnsignedInteger ::createFromInteger (1U), "should be one");
- expect (one != UnsignedInteger ::createFromInteger (2U), "should not be two");
-
- UnsignedInteger largest = UnsignedInteger ::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()
diff --git a/modules/beast_crypto/math/UnsignedInteger.h b/modules/beast_crypto/math/UnsignedInteger.h
index 72ab8ed0f..04f32a720 100644
--- a/modules/beast_crypto/math/UnsignedInteger.h
+++ b/modules/beast_crypto/math/UnsignedInteger.h
@@ -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
+template
class UnsignedInteger : public SafeBool >
{
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 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 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 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 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
explicit UnsignedInteger (T const* buf)
{
+ m_values [0] = 0; // clear any pad bytes
std::memcpy (begin(), buf, Bytes);
}
/** @} */
- /** Construct from a sequence. */
- template
- 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 & 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
- static UnsignedInteger createFromInteger (IntegerType value)
+ static UnsignedInteger createFromInteger (IntegerType value)
{
static_bassert (Bytes >= sizeof (IntegerType));
UnsignedInteger result;
@@ -143,31 +146,39 @@ public:
/** Construct with a filled value.
*/
- static UnsignedInteger createFilled (value_type value)
+ static UnsignedInteger createFilled (ValueType value)
{
- UnsignedInteger 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 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 const& other) const noexcept
+ bool operator== (UnsignedInteger const& other) const
{
return compare (other) == 0;
}
/** Determine inequality. */
- bool operator!= (UnsignedInteger const& other) const noexcept
+ bool operator!= (UnsignedInteger const& other) const
{
return compare (other) != 0;
}
/** Ordered comparison. */
- bool operator< (UnsignedInteger const& other) const noexcept
+ bool operator< (UnsignedInteger const& other) const
{
return compare (other) < 0;
}
/** Ordered comparison. */
- bool operator<= (UnsignedInteger const& other) const noexcept
+ bool operator<= (UnsignedInteger const& other) const
{
return compare (other) <= 0;
}
/** Ordered comparison. */
- bool operator> (UnsignedInteger const& other) const noexcept
+ bool operator> (UnsignedInteger const& other) const
{
return compare (other) > 0;
}
/** Ordered comparison. */
- bool operator>= (UnsignedInteger const& other) const noexcept
+ bool operator>= (UnsignedInteger const& other) const
{
return compare (other) >= 0;
}
- /** Perform bitwise logical-not. */
- UnsignedInteger operator~ () const noexcept
- {
- UnsignedInteger result;
-
- for (int i = 0; i < Bytes; ++i)
- result [i] = ~getByte (i);
-
- return result;
- }
-
- /** Perform bitwise logical-or. */
- UnsignedInteger & operator|= (UnsignedInteger const& rhs) noexcept
- {
- for (int i = 0; i < Bytes; ++i)
- getByte (i) |= rhs [i];
-
- return *this;
- }
-
- /** Perform bitwise logical-or. */
- UnsignedInteger operator| (UnsignedInteger const& rhs) const noexcept
- {
- UnsignedInteger result;
-
- for (int i = 0; i < Bytes; ++i)
- result [i] = getByte (i) | rhs [i];
-
- return result;
- }
-
- /** Perform bitwise logical-and. */
- UnsignedInteger & operator&= (UnsignedInteger const& rhs) noexcept
- {
- for (int i = 0; i < Bytes; ++i)
- getByte (i) &= rhs [i];
-
- return *this;
- }
-
- /** Perform bitwise logical-and. */
- UnsignedInteger operator& (UnsignedInteger const& rhs) const noexcept
- {
- UnsignedInteger result;
-
- for (int i = 0; i < Bytes; ++i)
- result [i] = getByte (i) & rhs [i];
-
- return result;
- }
-
- /** Perform bitwise logical-xor. */
- UnsignedInteger & operator^= (UnsignedInteger const& rhs) noexcept
- {
- for (int i = 0; i < Bytes; ++i)
- getByte (i) ^= rhs [i];
-
- return *this;
- }
-
- /** Perform bitwise logical-xor. */
- UnsignedInteger operator^ (UnsignedInteger const& rhs) const noexcept
- {
- UnsignedInteger 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 (&m_values [0])) +
+ ((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1));
+ }
+
+ ValueType const* get () const
+ {
+ return (reinterpret_cast (&m_values [0])) +
+ ((sizeof(IntCalcType)-(Bytes&(sizeof(IntCalcType)-1)))&(sizeof(IntCalcType)-1));
+ }
+
+ IntCalcType m_values [CalcCount];
};
#endif
diff --git a/modules/beast_crypto/math/UnsignedIntegerCalc.h b/modules/beast_crypto/math/UnsignedIntegerCalc.h
new file mode 100644
index 000000000..74afd7cb8
--- /dev/null
+++ b/modules/beast_crypto/math/UnsignedIntegerCalc.h
@@ -0,0 +1,428 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ 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
+struct DoubleWidthUInt;
+
+template <>
+struct DoubleWidthUInt
+{
+ typedef uint32 type;
+};
+
+template <>
+struct DoubleWidthUInt
+{
+ 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
+class UnsignedIntegerCalc : public SafeBool >
+{
+public:
+ typedef typename detail::DoubleWidthUInt ::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 (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 (*lo);
+ *hi-- = fromNetworkByteOrder (*hi);
+ }
+ if (lo == hi)
+ *lo = fromNetworkByteOrder (*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 (*lo);
+ *hi-- = toNetworkByteOrder (*hi);
+ }
+ if (lo == hi)
+ *lo = toNetworkByteOrder (*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 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
+ void unaryAssign (Operator op = Operator())
+ {
+ UInt* dest (m_values-1);
+ for (size_type n (size()); n--;)
+ op (*++dest);
+ }
+
+ template
+ 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