summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--includes/BigInt.h80
-rw-r--r--src/BigInt.cc378
-rw-r--r--tests/test-BigInt.cc20
4 files changed, 481 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index ab2c6bd..c155c10 100644
--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,8 @@ Async.cc \
BString.cc \
Main.cc \
Printer.cc \
+BigInt.cc \
+BRegex.cc \
\
Handle.cc \
Input.cc \
@@ -63,13 +65,9 @@ HttpServer.cc \
SimpleMustache.cc \
\
BLua.cc \
-\
LuaHandle.cc \
-\
LuaTask.cc \
\
-BRegex.cc \
-\
lcrypt.c \
ifeq ($(SYSTEM),MINGW32)
@@ -101,6 +99,7 @@ event.c \
TEST_SOURCES = \
test-Sanity.cc \
+test-BigInt.cc \
test-String.cc \
test-Tasks.cc \
test-Threads.cc \
diff --git a/includes/BigInt.h b/includes/BigInt.h
new file mode 100644
index 0000000..a74df6e
--- /dev/null
+++ b/includes/BigInt.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <stdint.h>
+#include <Exceptions.h>
+#include <BString.h>
+
+namespace Balau {
+
+class BigInt {
+ public:
+ BigInt() throw(GeneralException);
+ BigInt(const BigInt &) throw (GeneralException);
+ BigInt(BigInt &&);
+ ~BigInt();
+
+ BigInt & operator=(const BigInt &) throw (GeneralException);
+
+ void set(uint64_t) throw (GeneralException);
+ void set(int64_t);
+ void set(uint32_t) throw (GeneralException);
+ void set(int32_t);
+ void set(double) throw (GeneralException);
+ void set(const String &, int radix = 10) throw (GeneralException);
+ void set2expt(int i) throw (GeneralException);
+
+ BigInt operator+(unsigned int) const throw (GeneralException);
+ BigInt operator+(const BigInt &) const throw (GeneralException);
+ BigInt operator-(unsigned int) const throw (GeneralException);
+ BigInt operator-(const BigInt &) const throw (GeneralException);
+ BigInt operator*(unsigned int) const throw (GeneralException);
+ BigInt operator*(const BigInt &) const throw (GeneralException);
+ BigInt operator/(const BigInt &) const throw (GeneralException);
+ BigInt operator%(const BigInt &) const throw (GeneralException);
+ BigInt operator<<(unsigned int) const throw (GeneralException);
+ BigInt operator>>(unsigned int) const;
+
+ BigInt & operator+=(unsigned int) throw (GeneralException);
+ BigInt & operator+=(const BigInt &) throw (GeneralException);
+ BigInt & operator-=(unsigned int) throw (GeneralException);
+ BigInt & operator-=(const BigInt &) throw (GeneralException);
+ BigInt & operator*=(unsigned int) throw (GeneralException);
+ BigInt & operator*=(const BigInt &) throw (GeneralException);
+ BigInt & operator/=(const BigInt &) throw (GeneralException);
+ BigInt & operator%=(const BigInt &) throw (GeneralException);
+ BigInt & operator<<=(unsigned int) throw (GeneralException);
+ BigInt & operator>>=(unsigned int);
+
+ BigInt operator-() const throw (GeneralException);
+
+ BigInt & operator++();
+ BigInt operator++(int);
+ BigInt & operator--();
+ BigInt operator--(int);
+
+ enum comp_t { LT, GT, EQ };
+ comp_t comp(const BigInt &) const throw (GeneralException);
+
+ BigInt & neg() throw (GeneralException);
+
+ BigInt sqrt() const throw (GeneralException);
+ BigInt & do_sqrt() throw (GeneralException);
+
+ BigInt gcd(const BigInt &) const throw (GeneralException);
+ BigInt lcm(const BigInt &) const throw (GeneralException);
+
+ bool operator==(const BigInt &) const;
+ bool operator!=(const BigInt &) const;
+ bool operator<=(const BigInt &) const;
+ bool operator>=(const BigInt &) const;
+ bool operator<(const BigInt &) const;
+ bool operator>(const BigInt &) const;
+
+ String toString(int radix = 10) const;
+ char * makeString(int radix = 10) const;
+
+ private:
+ void * m_bi = NULL;
+};
+
+};
diff --git a/src/BigInt.cc b/src/BigInt.cc
new file mode 100644
index 0000000..7a30e7e
--- /dev/null
+++ b/src/BigInt.cc
@@ -0,0 +1,378 @@
+#include <malloc.h>
+#include <math.h>
+#include "tomcrypt.h"
+#include "BigInt.h"
+#include "Main.h"
+
+namespace {
+
+class InitMP : public Balau::AtStart {
+ public:
+ InitMP() : AtStart(0) { }
+ void doStart() {
+ ltc_mp = ltm_desc;
+ m_initialized = true;
+ static Balau::BigInt s2p32;
+ IAssert(!m_2p32, "doStart should only be called once.");
+ s2p32.set2expt(32);
+ m_2p32 = &s2p32;
+ }
+ const Balau::BigInt & get2p32() {
+ return *m_2p32;
+ }
+ bool initialized() { return m_initialized; }
+ private:
+ Balau::BigInt * m_2p32 = NULL;
+ bool m_initialized = false;
+};
+
+static InitMP s_MP;
+
+};
+
+Balau::BigInt::BigInt() throw (GeneralException) {
+ AAssert(s_MP.initialized(), "You can't statically declare a BigInt.");
+ if (mp_init(&m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_init");
+}
+
+Balau::BigInt::BigInt(const BigInt & v) throw (GeneralException) {
+ AAssert(s_MP.initialized(), "You can't statically declare a BigInt.");
+ if (mp_init_copy(&m_bi, v.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_init_copy");
+}
+
+Balau::BigInt::BigInt(BigInt && v) {
+ m_bi = v.m_bi;
+ v.m_bi = NULL;
+}
+
+Balau::BigInt::~BigInt() {
+ if (!m_bi)
+ return;
+ mp_clear(m_bi);
+ m_bi = NULL;
+}
+
+Balau::BigInt & Balau::BigInt::operator=(const BigInt & v) throw (GeneralException) {
+ if (&v == this)
+ return *this;
+
+ if (mp_copy(v.m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_init_copy");
+}
+
+void Balau::BigInt::set(uint64_t v) throw (GeneralException) {
+ uint32_t low = v & 0xffffffff;
+ uint32_t high = v >> 32;
+ if (high == 0) {
+ if (mp_set_int(m_bi, low) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_set_init");
+ } else {
+ if (mp_set_int(m_bi, high) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_set_init");
+ operator*=(s_MP.get2p32());
+ operator+=(low);
+ }
+}
+
+void Balau::BigInt::set(int64_t v) {
+ if (v >= 0) {
+ set((uint64_t) v);
+ } else {
+ v = -v;
+ set((uint64_t) v);
+ neg();
+ }
+}
+
+void Balau::BigInt::set(uint32_t v) throw (GeneralException) {
+ if (mp_set_int(m_bi, v) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_set_init");
+}
+
+void Balau::BigInt::set(int32_t v) {
+ if (v >= 0) {
+ set((uint32_t) v);
+ } else {
+ v = -v;
+ set((uint32_t) v);
+ neg();
+ }
+}
+
+void Balau::BigInt::set(double v) throw (GeneralException) {
+ double f, i;
+ f = modf(v, &i);
+ AAssert(f == 0.0, "Can't set a BigInt with a double that has a fractional value");
+
+ int e;
+
+ f = frexp(v, &e);
+ if (mp_set_int(m_bi, 0) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_set_init");
+
+ for (e -= 1.0; e > 0.0; e -= 1.0) {
+ f *= 2.0;
+ if (f >= 1.0) {
+ operator+=(1);
+ f -= 1.0;
+ }
+ operator*=(2);
+ }
+}
+
+void Balau::BigInt::set(const String & v, int radix) throw (GeneralException) {
+ if (mp_read_radix(m_bi, v.to_charp(), radix) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_read_radix");
+}
+
+void Balau::BigInt::set2expt(int i) throw (GeneralException) {
+ if (mp_2expt(m_bi, i) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_2expt");
+}
+
+Balau::BigInt Balau::BigInt::operator+(unsigned int i) const throw (GeneralException) {
+ BigInt r;
+ if (mp_add_d(m_bi, i, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_add_d");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator+(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_add(m_bi, a.m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_add");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator-(unsigned int i) const throw (GeneralException) {
+ BigInt r;
+ if (mp_sub_d(m_bi, i, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sub_d");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator-(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_sub(m_bi, a.m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sub");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator*(unsigned int i) const throw (GeneralException) {
+ BigInt r;
+ if (mp_mul_d(m_bi, i, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_mul_d");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator*(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_mul(m_bi, a.m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_mul");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator/(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_div(m_bi, a.m_bi, r.m_bi, NULL) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator%(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_div(m_bi, a.m_bi, NULL, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::operator<<(unsigned int a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_mul_d(m_bi, 1 << a, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return *this;
+}
+
+Balau::BigInt Balau::BigInt::operator>>(unsigned int a) const {
+ BigInt s;
+ s.set2expt(a);
+ return operator/(s);
+}
+
+Balau::BigInt & Balau::BigInt::operator+=(unsigned int i) throw (GeneralException) {
+ if (mp_add_d(m_bi, i, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_add_d");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator+=(const BigInt & a) throw (GeneralException) {
+ if (mp_add(m_bi, a.m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_add");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator-=(unsigned int i) throw (GeneralException) {
+ if (mp_sub_d(m_bi, i, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sub_d");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator-=(const BigInt & a) throw (GeneralException) {
+ if (mp_sub(m_bi, a.m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sub");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator*=(unsigned int i) throw (GeneralException) {
+ if (mp_mul_d(m_bi, i, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_mul_d");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator*=(const BigInt & a) throw (GeneralException) {
+ if (mp_mul(m_bi, a.m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_mul");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator/=(const BigInt & a) throw (GeneralException) {
+ if (mp_div(m_bi, a.m_bi, m_bi, NULL) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator%=(const BigInt & a) throw (GeneralException) {
+ if (mp_div(m_bi, a.m_bi, NULL, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator<<=(unsigned int a) throw (GeneralException) {
+ if (mp_mul_d(m_bi, 1 << a, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_div");
+ return *this;
+}
+
+Balau::BigInt & Balau::BigInt::operator>>=(unsigned int a) {
+ BigInt s;
+ s.set2expt(a);
+ return operator/=(s);
+}
+
+Balau::BigInt Balau::BigInt::operator-() const throw (GeneralException) {
+ BigInt r(*this);
+ r.neg();
+ return r;
+}
+
+Balau::BigInt & Balau::BigInt::operator++() {
+ operator+=(1);
+ return *this;
+}
+
+Balau::BigInt Balau::BigInt::operator++(int) {
+ BigInt r(*this);
+ operator+=(1);
+ return r;
+}
+
+Balau::BigInt & Balau::BigInt::operator--() {
+ operator-=(1);
+ return *this;
+}
+
+Balau::BigInt Balau::BigInt::operator--(int) {
+ BigInt r(*this);
+ operator-=(1);
+ return r;
+}
+
+Balau::BigInt & Balau::BigInt::neg() throw (GeneralException) {
+ if (mp_neg(m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_neg");
+}
+
+Balau::BigInt Balau::BigInt::sqrt() const throw (GeneralException) {
+ BigInt r;
+ if (mp_sqr(m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sqr");
+ return r;
+}
+
+Balau::BigInt & Balau::BigInt::do_sqrt() throw (GeneralException) {
+ if (mp_sqr(m_bi, m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_sqr");
+ return *this;
+}
+
+Balau::BigInt Balau::BigInt::gcd(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_gcd(m_bi, a.m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_gcd");
+ return r;
+}
+
+Balau::BigInt Balau::BigInt::lcm(const BigInt & a) const throw (GeneralException) {
+ BigInt r;
+ if (mp_lcm(m_bi, a.m_bi, r.m_bi) != CRYPT_OK)
+ throw GeneralException("Error while calling mp_lcm");
+ return r;
+}
+
+Balau::BigInt::comp_t Balau::BigInt::comp(const BigInt & a) const throw (GeneralException) {
+ int r = mp_cmp(m_bi, a.m_bi);
+ switch (r) {
+ case LTC_MP_LT:
+ return LT;
+ case LTC_MP_GT:
+ return GT;
+ case LTC_MP_EQ:
+ return EQ;
+ default:
+ throw GeneralException("Unknown result from mp_cmp");
+ }
+}
+
+bool Balau::BigInt::operator==(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r == EQ;
+}
+
+bool Balau::BigInt::operator!=(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r != EQ;
+}
+
+bool Balau::BigInt::operator<=(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r == LT || r == EQ;
+}
+
+bool Balau::BigInt::operator>=(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r == GT || r == EQ;
+}
+
+bool Balau::BigInt::operator<(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r == LT;
+}
+
+bool Balau::BigInt::operator>(const BigInt & a) const {
+ comp_t r = comp(a);
+ return r == GT;
+}
+
+Balau::String Balau::BigInt::toString(int radix) const {
+ char * out = (char *) alloca(mp_count_bits(m_bi) / (radix >= 10 ? 3 : 1) + 3);
+ mp_toradix(m_bi, out, radix);
+ return String(out);
+}
+
+char * Balau::BigInt::makeString(int radix) const {
+ char * out = (char *) malloc(mp_count_bits(m_bi) / (radix >= 10 ? 3 : 1) + 3);
+ mp_toradix(m_bi, out, radix);
+ return out;
+}
diff --git a/tests/test-BigInt.cc b/tests/test-BigInt.cc
new file mode 100644
index 0000000..df69e64
--- /dev/null
+++ b/tests/test-BigInt.cc
@@ -0,0 +1,20 @@
+#include <Main.h>
+#include <BigInt.h>
+
+using namespace Balau;
+
+void MainTask::Do() {
+ Printer::log(M_STATUS, "Test::BigInt running.");
+
+ {
+ BigInt a, b;
+ uint64_t t = 10000000000000000000;
+ String s = "10000000000000000000";
+ a.set(t);
+ b.set(s);
+ TAssert(a == b);
+ TAssert(a.toString() == s);
+ }
+
+ Printer::log(M_STATUS, "Test::BigInt passed.");
+}