From 6e96e0a767a4cfd8e9292f6151a628f0d94e54ea Mon Sep 17 00:00:00 2001 From: fallenoak Date: Mon, 30 Jan 2023 00:10:52 -0600 Subject: [PATCH] feat(big): add SBigMul --- storm/Big.cpp | 4 ++ storm/Big.hpp | 2 + storm/big/BigBuffer.cpp | 12 +++++ storm/big/BigBuffer.hpp | 1 + storm/big/BigData.cpp | 4 ++ storm/big/BigData.hpp | 1 + storm/big/BigStack.cpp | 29 ++++++++++++ storm/big/BigStack.hpp | 4 ++ storm/big/Ops.cpp | 20 +++++++++ storm/big/Ops.hpp | 3 ++ test/Big.cpp | 99 +++++++++++++++++++++++++++++++++++++++++ 11 files changed, 179 insertions(+) create mode 100644 storm/big/BigStack.cpp diff --git a/storm/Big.cpp b/storm/Big.cpp index 5b28cfe..142c861 100644 --- a/storm/Big.cpp +++ b/storm/Big.cpp @@ -24,6 +24,10 @@ void SBigNew(BigData** num) { *num = new (m) BigData(); } +void SBigMul(BigData* a, BigData* b, BigData* c) { + Mul(a->Primary(), b->Primary(), c->Primary(), a->Stack()); +} + void SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes) { auto& output = num->Output(); ToBinary(output, num->Primary()); diff --git a/storm/Big.hpp b/storm/Big.hpp index a12566b..e73070d 100644 --- a/storm/Big.hpp +++ b/storm/Big.hpp @@ -12,6 +12,8 @@ void SBigFromBinary(BigData* num, const void* data, uint32_t bytes); void SBigFromUnsigned(BigData* num, uint32_t val); +void SBigMul(BigData* a, BigData* b, BigData* c); + void SBigNew(BigData** num); void SBigToBinaryBuffer(BigData* num, uint8_t* data, uint32_t maxBytes, uint32_t* bytes); diff --git a/storm/big/BigBuffer.cpp b/storm/big/BigBuffer.cpp index 4bafa49..71200fb 100644 --- a/storm/big/BigBuffer.cpp +++ b/storm/big/BigBuffer.cpp @@ -32,3 +32,15 @@ int32_t BigBuffer::IsUsed(uint32_t index) const { void BigBuffer::SetCount(uint32_t count) { this->m_data.SetCount(this->m_offset + count); } + +void BigBuffer::Trim() const { + while (this->Count()) { + auto& data = const_cast&>(this->m_data); + + if (*data.Top()) { + break; + } + + data.SetCount(data.Count() - 1); + } +} diff --git a/storm/big/BigBuffer.hpp b/storm/big/BigBuffer.hpp index 0266996..fac408d 100644 --- a/storm/big/BigBuffer.hpp +++ b/storm/big/BigBuffer.hpp @@ -18,6 +18,7 @@ class BigBuffer { void GrowToFit(uint32_t index); int32_t IsUsed(uint32_t index) const; void SetCount(uint32_t count); + void Trim() const; }; #endif diff --git a/storm/big/BigData.cpp b/storm/big/BigData.cpp index ad19de5..a6c43e9 100644 --- a/storm/big/BigData.cpp +++ b/storm/big/BigData.cpp @@ -7,3 +7,7 @@ TSGrowableArray& BigData::Output() const { BigBuffer& BigData::Primary() { return this->m_primary; } + +BigStack& BigData::Stack() const { + return const_cast(this->m_stack); +} diff --git a/storm/big/BigData.hpp b/storm/big/BigData.hpp index baae677..3d9c4fb 100644 --- a/storm/big/BigData.hpp +++ b/storm/big/BigData.hpp @@ -15,6 +15,7 @@ class BigData { // Member functions TSGrowableArray& Output() const; BigBuffer& Primary(); + BigStack& Stack() const; }; #endif diff --git a/storm/big/BigStack.cpp b/storm/big/BigStack.cpp new file mode 100644 index 0000000..c2707f8 --- /dev/null +++ b/storm/big/BigStack.cpp @@ -0,0 +1,29 @@ +#include "storm/big/BigStack.hpp" + +BigBuffer& BigStack::Alloc(uint32_t* count) { + STORM_ASSERT(this->m_used < SIZE); + + if (count) { + (*count)++; + } + + auto& buffer = this->m_buffer[this->m_used]; + this->m_used++; + + return buffer; +} + +void BigStack::Free(uint32_t count) { + this->m_used -= count; +} + +BigBuffer& BigStack::MakeDistinct(BigBuffer& orig, int32_t required) { + return required ? this->Alloc(nullptr) : orig; +} + +void BigStack::UnmakeDistinct(BigBuffer& orig, BigBuffer& distinct) { + if (&orig != &distinct) { + orig = distinct; + this->Free(1); + } +} diff --git a/storm/big/BigStack.hpp b/storm/big/BigStack.hpp index 2192911..21ae82b 100644 --- a/storm/big/BigStack.hpp +++ b/storm/big/BigStack.hpp @@ -14,6 +14,10 @@ class BigStack { uint32_t m_used = 0; // Member functions + BigBuffer& Alloc(uint32_t* count); + void Free(uint32_t count); + BigBuffer& MakeDistinct(BigBuffer& orig, int32_t required); + void UnmakeDistinct(BigBuffer& orig, BigBuffer& distinct); }; #endif diff --git a/storm/big/Ops.cpp b/storm/big/Ops.cpp index f6411ee..9567fcc 100644 --- a/storm/big/Ops.cpp +++ b/storm/big/Ops.cpp @@ -62,6 +62,26 @@ void Mul(BigBuffer& a, const BigBuffer& b, uint64_t c) { a.SetCount(i); } +void Mul(BigBuffer& a, const BigBuffer& b, const BigBuffer& c, BigStack& stack) { + auto& aa = stack.MakeDistinct(a, &a == &b || &a == &c); + aa.Clear(); + + uint32_t i = 0; + for (i = 0; b.IsUsed(i); i++) { + uint64_t carry = 0; + + uint32_t j = 0; + for (j = 0; c.IsUsed(j); j++) { + carry += aa[i + j] + b[i] * static_cast(c[j]); + aa[i + j] = ExtractLowPart(carry); + } + + aa[i + j] = ExtractLowPart(carry); + } + + stack.UnmakeDistinct(a, aa); +} + void ToBinaryAppend(TSGrowableArray& output, const BigBuffer& buffer) { for (uint32_t i = 0; i < buffer.Count() * 4; i++) { auto byte = buffer[i / 4] >> (8 * (i & 3)); diff --git a/storm/big/Ops.hpp b/storm/big/Ops.hpp index 30f1f4b..d8f39a5 100644 --- a/storm/big/Ops.hpp +++ b/storm/big/Ops.hpp @@ -2,6 +2,7 @@ #define STORM_BIG_OPS_HPP #include "storm/big/BigBuffer.hpp" +#include "storm/big/BigStack.hpp" #include void Add(BigBuffer& a, const BigBuffer& b, const BigBuffer& c); @@ -18,6 +19,8 @@ uint64_t MakeLarge(uint32_t low, uint32_t high); void Mul(BigBuffer& a, const BigBuffer& b, uint64_t c); +void Mul(BigBuffer& a, const BigBuffer& b, const BigBuffer& c, BigStack& stack); + void ToBinary(TSGrowableArray& output, const BigBuffer& buffer); #endif diff --git a/test/Big.cpp b/test/Big.cpp index 9d354a8..86776c2 100644 --- a/test/Big.cpp +++ b/test/Big.cpp @@ -270,6 +270,105 @@ TEST_CASE("SBigFromUnsigned", "[big]") { } } +TEST_CASE("SBigMul", "[big]") { + SECTION("multiplies 0 and 1") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + SBigFromUnsigned(b, 0); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 1); + + SBigMul(a, b, c); + + a->Primary().Trim(); + + CHECK(a->Primary().Count() == 0); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + } + + SECTION("multiplies 2 and 4") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + SBigFromUnsigned(b, 2); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 4); + + SBigMul(a, b, c); + + a->Primary().Trim(); + + CHECK(a->Primary().Count() == 1); + CHECK(a->Primary()[0] == 8); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + } + + SECTION("multiplies 0xFFFFFFFF and 0x100") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + SBigFromUnsigned(b, 0xFFFFFFFF); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 0x100); + + SBigMul(a, b, c); + + a->Primary().Trim(); + + CHECK(a->Primary().Count() == 2); + CHECK(a->Primary()[0] == 0xFFFFFF00); + CHECK(a->Primary()[1] == 0xFF); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + } + + SECTION("multiplies 0xFFFFFF and 0x11223344") { + BigData* a; + SBigNew(&a); + + BigData* b; + SBigNew(&b); + SBigFromUnsigned(b, 0xFFFFFF); + + BigData* c; + SBigNew(&c); + SBigFromUnsigned(c, 0x11223344); + + SBigMul(a, b, c); + + a->Primary().Trim(); + + CHECK(a->Primary().Count() == 2); + CHECK(a->Primary()[0] == 0x32DDCCBC); + CHECK(a->Primary()[1] == 0x112233); + + SBigDel(a); + SBigDel(b); + SBigDel(c); + } +} + TEST_CASE("SBigToBinaryBuffer", "[big]") { SECTION("returns expected buffer for bigdata representing 0") { BigData* num;