diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | includes/BigInt.h | 80 | ||||
-rw-r--r-- | src/BigInt.cc | 378 | ||||
-rw-r--r-- | tests/test-BigInt.cc | 20 |
4 files changed, 481 insertions, 4 deletions
@@ -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."); +} |