From 341fb538a8101fcf5affb637b129870984056378 Mon Sep 17 00:00:00 2001
From: GabrielTofvesson <gabriel.tofvesson@gmail.com>
Date: Thu, 1 Mar 2018 01:14:51 +0100
Subject: [PATCH] Started properly implementing galois 'n stuff

---
 XMath/Galois.cpp            | 203 +++++++++++++++++++++++++-----------
 XMath/Galois.h              |  40 +++----
 XMath/XMath.vcxproj         |   1 +
 XMath/XMath.vcxproj.filters |   3 +
 4 files changed, 171 insertions(+), 76 deletions(-)

diff --git a/XMath/Galois.cpp b/XMath/Galois.cpp
index a08d72f..5fb053c 100644
--- a/XMath/Galois.cpp
+++ b/XMath/Galois.cpp
@@ -1,4 +1,7 @@
+#define GALOIS_API
+
 #include "Galois.h"
+#include <string.h>
 
 namespace CryptoCPP{
 	namespace Math{
@@ -7,6 +10,18 @@ namespace CryptoCPP{
 			return (size_t)d + (d > (size_t)d ? 1 : 0);
 		}
 
+		size_t block_count(size_t bin_block_size, size_t bufs)
+		{
+			return (bufs * 8) / bin_block_size;
+		}
+
+		void* do_copy(void* v, size_t size)
+		{
+			char * c = new char[size];
+			memcpy(c, v, size);
+			return c;
+		}
+
 		GALOIS_API Galois::Galois(
 				size_t characteristic,
 				size_t exponent,
@@ -24,7 +39,7 @@ namespace CryptoCPP{
 			data = value;
 		}
 
-		GALOIS_API Galois::Galois(Galois & copy) :
+		GALOIS_API Galois::Galois(const Galois & copy) :
 			characteristic(copy.characteristic),
 			exponent(copy.exponent),
 			irreducible(new size_t[copy.irreducible_size]),
@@ -44,127 +59,199 @@ namespace CryptoCPP{
 		}
 
 		GALOIS_API Galois * Galois::add(const Galois * value) const
-		{ 
-			Galois * result = new Galois(*this);
-			result->iadd(value);
-			return result;
+		{
+			bool imSmaller = value->data_size > data_size;
+			size_t state_size = imSmaller ? value->data_size : data_size;
+			size_t * state = new size_t[state_size];
+			memset(state, 0, state_size * sizeof(size_t));
+			memcpy(state, imSmaller ? value->data : data, state_size * sizeof(size_t));
+
+			iadd(imSmaller ? data : value->data, imSmaller ? data_size : value->data_size, binary_block_size, state, state_size, characteristic);
+			
+			return new Galois(characteristic, exponent, (size_t *)do_copy(irreducible, irreducible_size * sizeof(size_t)), irreducible_size, state);
 		}
 
 		GALOIS_API Galois * Galois::sub(const Galois * value) const
-		{ 
-			Galois * result = new Galois(*this);
-			result->isub(value);
-			return result;
+		{
+			bool imSmaller = value->data_size > data_size;
+			size_t state_size = imSmaller ? value->data_size : data_size;
+			size_t * state = new size_t[state_size];
+			memset(state, 0, state_size * sizeof(size_t));
+			memcpy(state, data, data_size * sizeof(size_t));
+
+			isub(value->data, value->data_size, binary_block_size, state, state_size, characteristic);
+
+			return new Galois(characteristic, exponent, (size_t *)do_copy(irreducible, irreducible_size * sizeof(size_t)), irreducible_size, state);
 		}
 
 		GALOIS_API Galois * Galois::mul(const Galois * value) const
-		{ 
-			Galois * result = new Galois(*this);
-			result->imul(value);
-			return result;
-		}
-
-		GALOIS_API Galois * Galois::inv(const Galois * value) const
-		{ 
-			Galois * result = new Galois(*this);
-			result->iinv(value);
-			return result;	
-		}
-
-		GALOIS_API void Galois::iadd(const Galois * value)
 		{
-			size_t min = data_size < value->data_size ? data_size : value->data_size;
-			for(size_t t = 0; t<min; ++t)
+			bool nb1, nb2;
+			size_t
+				h1 = high_factor(data, data_size, binary_block_size, &nb1),
+				h2 = high_factor(value->data, value->data_size, value->binary_block_size, &nb2);
+
+			// If one of the values is 0, return a zero-Galois
+			if (nb1 || nb2) return new Galois(characteristic, exponent, (size_t *)do_copy(irreducible, irreducible_size * sizeof(size_t)), irreducible_size, (size_t*)memset(new size_t[1], 0, sizeof(size_t)));
+
+			// The product of two values with the same base is represented as the sum of their exponents
+			size_t * state = new size_t[h1 + h2];
+			memset(state, 0, (h1 + h2) * sizeof(size_t));
+
+			imul(value->data, value->data_size, binary_block_size, state, h1 + h2, characteristic, h1, h2);
+
+			return new Galois(characteristic, exponent, (size_t *)do_copy(irreducible, irreducible_size * sizeof(size_t)), irreducible_size, state);
+		}
+
+		GALOIS_API Galois * Galois::inv() const
+		{
+
+		}
+
+		// These internal functions assume that an adequate state size has been chose
+		GALOIS_API void Galois::iadd(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic)
+		{
+				for (size_t t = block_count(bin_size, data_size); t > 0; --t)
+					set_value(
+						t - 1,
+						(
+							get_value(t-1, bin_size, state) +
+							get_value(t - 1, bin_size, data)
+						) % characteristic,
+						bin_size,
+						characteristic, 
+						state
+					);
+		}
+
+		GALOIS_API void Galois::isub(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic)
+		{
+			for (size_t t = block_count(bin_size, data_size); t > 0; --t)
+				set_value(
+					t - 1,
+					(
+						characteristic +
+						get_value(t - 1, bin_size, state) -
+						get_value(t - 1, bin_size, data)
+						) % characteristic,
+					bin_size,
+					characteristic,
+					state
+				);
+		}
+
+		GALOIS_API void Galois::imul(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic, size_t high1, size_t high2)
+		{
+			size_t * temp = new size_t[high1 + high2];
+			memset(temp, 0, (high1 + high2) * sizeof(size_t));
+
+			size_t data_blocks = block_count(bin_size, data_size);
+
+			for (size_t t = block_count(bin_size, state_size); t > 0; --t)
 			{
-				size_t block = (get_value(t) + value->get_value(t)) % characteristic;
-				set_value(t, block);
+				memcpy(temp, data, data_size * sizeof(size_t));
+				ilsh(temp, data_size + (t*bin_size), t);
+
+				for (size_t tblk = 0; tblk < data_blocks; ++tblk) // Multiply each element
+					set_value(tblk, get_value(tblk, bin_size, data) * get_value(t - 1, bin_size, state), bin_size, characteristic, temp);
+
+				// Add shifted and multiplied value to state
+				iadd(state, data_size + (t*bin_size), bin_size, state, state_size, characteristic);
 			}
 		}
 
-		GALOIS_API void Galois::isub(const Galois * value)
+		GALOIS_API void Galois::iinv(size_t * state, size_t state_size)
 		{
 			
 		}
 
-		GALOIS_API void Galois::imul(const Galois * value)
+		GALOIS_API void Galois::ilsh(size_t * state, size_t state_size, size_t bin_size, size_t characteristic, size_t shiftc)
 		{
-			
+			for (size_t t = block_count(bin_size, state_size); t > shiftc; --t)
+				set_value(t - 1, get_value(t - 1 - shiftc, bin_size, state), bin_size, characteristic, state);
+			for (size_t t = shiftc; t > 0; --t)
+				set_value(t - 1, 0, bin_size, characteristic, state);
 		}
 
-		GALOIS_API void Galois::iinv(cosnt Galois * value)
-		{
-			
-		}
-
-		GALOIS_API size_t Galois::_mask(size_t bits, bool side) const
+		GALOIS_API size_t Galois::_mask(size_t bits, bool side)
 		{
 			size_t result = 0;
 			for(size_t t = 0; t<bits; ++t) result = side?(result<<1)|1:(result>>1)|high_bit;
 			return result;
 		}
 
-		GALOIS_API size_t Galois::get_value(size_t index) const
+		GALOIS_API size_t Galois::get_value(size_t index, size_t block_size, size_t * from)
 		{
 			// Compute block/sub-block indexing
-			size_t upper_bit_size = ((binary_block_size*index)%(8*sizeof(size_t)))%binary_block_size;
-			size_t upper_block_index = (index*binary_block_size)/8;
-			size_t lower_block_index = ((index - upper_bit_size)*binary_block_size)/8;
+			size_t upper_bit_size = ((block_size*index)%(8*sizeof(size_t)))% block_size;
+			size_t upper_block_index = (index*block_size)/8;
+			size_t lower_block_index = ((index - upper_bit_size)*block_size)/8;
 			
 			// Boundary disparity check
 			if(upper_block_index!=lower_block_index)
 			{
 				// Get block values
-				size_t upper_block = data[upper_block_index] & _mask(upper_bit_size, true);
-				size_t lower_block = data[lower_block_index] & _mask(binary_block_size-upper_bit_size, false);
+				size_t upper_block = from[upper_block_index] & _mask(upper_bit_size, true);
+				size_t lower_block = from[lower_block_index] & _mask(block_size -upper_bit_size, false);
 
 				// Do alignment
-				size_t block = (upper_block << (binary_block_size - upper_bit_size)) | (lower_block >> ((sizeof(size_t)*8)-upper_bit_size));
+				size_t block = (upper_block << (block_size - upper_bit_size)) | (lower_block >> ((sizeof(size_t)*8)-upper_bit_size));
 			
 				return block;
 			}
 			else
 			{
 				// Passed: no boundary disparity
-				size_t shift = (binary_block_size * index) % (8 * sizeof(size_t));
-				size_t block_index = (binary_block_size * index) / (8 * sizeof(size_t));
+				size_t shift = (block_size * index) % (8 * sizeof(size_t));
+				size_t block_index = (block_size * index) / (8 * sizeof(size_t));
 
 				// Get and mask
-				return data[block_index] >> shift & _mask(binary_block_size, true);
+				return from[block_index] >> shift & _mask(block_size, true);
 			}
 		}
 
-		GALOIS_API void Galois::set_value(size_t index, size_t value)
+		GALOIS_API void Galois::set_value(size_t index, size_t value, size_t block_size, size_t characteristic, size_t * to)
 		{
 			value = value % characteristic;
 			
 			// Compute block/sub-block indexing
-			size_t upper_bit_size = ((binary_block_size*index)%(8*sizeof(size_t)))%binary_block_size;
-			size_t upper_block_index = (index*binary_block_size)/8;
-			size_t lower_block_index = ((index - upper_bit_size)*binary_block_size)/8;
+			size_t upper_bit_size = ((block_size*index)%(8*sizeof(size_t)))%block_size;
+			size_t upper_block_index = (index*block_size)/8;
+			size_t lower_block_index = ((index - upper_bit_size)*block_size)/8;
 			
 			// Boundary disparity check
 			if(upper_block_index!=lower_block_index)
 			{
 				// Mask bits
-				data[upper_block_index] &= ~_mask(upper_bit_size, false);
-				data[lower_block_index] &= ~_mask(binary_block_size-upper_bit_size, true);
+				to[upper_block_index] &= ~_mask(upper_bit_size, false);
+				to[lower_block_index] &= ~_mask(block_size -upper_bit_size, true);
 
 				// Get block values
-				data[upper_block_index] = value >> (binary_block_size - upper_bit_size);
-				data[lower_block_index] = (value & _mask(binary_block_size-upper_bit_size, false)) << ((8 * sizeof(size_t)) - (binary_block_size - upper_bit_size));
+				to[upper_block_index] = value >> (block_size - upper_bit_size);
+				to[lower_block_index] = (value & _mask(block_size -upper_bit_size, false)) << ((8 * sizeof(size_t)) - (block_size - upper_bit_size));
 			}
 			else
 			{
 				// Passed: no boundary disparity
-				size_t shift = (binary_block_size * index) % (8 * sizeof(size_t));
-				size_t block_index = (binary_block_size * index) / (8 * sizeof(size_t));
+				size_t shift = (block_size * index) % (8 * sizeof(size_t));
+				size_t block_index = (block_size * index) / (8 * sizeof(size_t));
 
 				// Mask bits
-				data[block_index] &= ~_mask(binary_block_size, false) << shift;
+				to[block_index] &= ~_mask(block_size, false) << shift;
 
 				// Apply shift
-				data[block_index] = value << shift;
+				to[block_index] = value << shift;
 			}
 		}
+
+		GALOIS_API size_t Galois::high_factor(size_t * state, size_t state_size, size_t bin_size, bool * noBits)
+		{
+			*noBits = false;
+			for (size_t t = block_count(bin_size, state_size); t > 0; --t)
+				if (get_value(t - 1, bin_size, state))
+					return t - 1;
+			*noBits = true;
+			return 0;
+		}
 	}
 }
diff --git a/XMath/Galois.h b/XMath/Galois.h
index 8adfe2d..a1bac41 100644
--- a/XMath/Galois.h
+++ b/XMath/Galois.h
@@ -25,12 +25,12 @@ namespace CryptoCPP {
 		{
 		public:
 			GALOIS_API Galois(
-					size_t characteristic,
-					size_t exponent,
-					size_t * irreducible,
-					size_t irreducible_size,
-					size_t * value
-					);
+				size_t characteristic,
+				size_t exponent,
+				size_t * irreducible,
+				size_t irreducible_size,
+				size_t * value
+				);
 			GALOIS_API ~Galois();
 
 			// Addition
@@ -43,31 +43,35 @@ namespace CryptoCPP {
 			GALOIS_API Galois * mul(const Galois * value) const;
 
 			// Inverse multiplication
-			GALOIS_API Galois * inv(const Galois * value) const;
+			GALOIS_API Galois * inv() const;
 
 
 		protected:
 			static const size_t high_bit = 1 << ((sizeof(size_t)*8)-1);
 			// GF parameters
-			const size_t characteristic, exponent, irreducible;
+			size_t characteristic, exponent, *irreducible, irreducible_size;
 			// Effective storage params
-			const size_t binary_block_size, data_size;
+			size_t binary_block_size, data_size;
 			// Value of this GF object
-			const size_t * data;
+			size_t * data;
 
 
 			// Reduce the value of this galois to fit characteristic
 			GALOIS_API void reduce();
 
-			// Self-mutable operations
-			GALOIS_API void iadd(const Galois * value);
-			GALOIS_API void isub(const Galois * value);
-			GALOIS_API void imul(const Galois * value);
-			GALOIS_API void iinv(const Galois * value);
 
-			GALOIS_API size_t _mask(size_t bits, bool side) const;
-			GALOIS_API size_t get_value(size_t idx) const;
-			GALOIS_API void set_value(size_t idx, size_t value);
+			// Logic
+			GALOIS_API static void iadd(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic);	// Addition
+			GALOIS_API static void isub(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic);	// Subtraction
+			GALOIS_API static void imul(size_t * data, size_t data_size, size_t bin_size, size_t * state, size_t state_size, size_t characteristic, size_t high1, size_t high2);	// Multiplication
+			GALOIS_API static void iinv(size_t * state, size_t state_size);							// Multiplicative inverse
+			GALOIS_API static void ilsh(size_t * state, size_t state_size, size_t bin_size, size_t characteristic, size_t shiftc);			// Left shift
+
+			// Data management. Don't look at these unless you want a headache
+			GALOIS_API static size_t _mask(size_t bits, bool side);
+			GALOIS_API static size_t get_value(size_t idx, size_t block_size, size_t * from);
+			GALOIS_API static void set_value(size_t idx, size_t value, size_t block_size, size_t characteristic, size_t * to);
+			GALOIS_API static size_t high_factor(size_t * state, size_t state_size, size_t bin_size, bool * noBits);
 		};
 	}
 }
diff --git a/XMath/XMath.vcxproj b/XMath/XMath.vcxproj
index 03c7612..bc65f77 100644
--- a/XMath/XMath.vcxproj
+++ b/XMath/XMath.vcxproj
@@ -122,6 +122,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="BigInteger.cpp" />
+    <ClCompile Include="Galois.cpp" />
     <ClCompile Include="Matrix.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/XMath/XMath.vcxproj.filters b/XMath/XMath.vcxproj.filters
index f72a80e..c80218e 100644
--- a/XMath/XMath.vcxproj.filters
+++ b/XMath/XMath.vcxproj.filters
@@ -21,6 +21,9 @@
     <ClCompile Include="Matrix.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Galois.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="BigInteger.h">