/* Galois field arithmetic Copyright 2018 Ahmet Inan */ #pragma once #include namespace CODE { namespace GF { template struct Index; template struct Value { static const int Q = 1 << M, N = Q - 1; static_assert(M <= 8 * sizeof(TYPE), "TYPE not wide enough"); static_assert(Q == (POLY & ~N), "POLY not of degree Q"); TYPE v; Value() {} explicit Value(TYPE v) : v(v) { assert(v <= N); } explicit operator bool () const { return v; } explicit operator int () const { return v; } Value operator *= (Index a) { assert(a.i < a.modulus()); return *this = *this * a; } Value operator *= (Value a) { assert(a.v <= a.N); return *this = *this * a; } Value operator += (Value a) { assert(a.v <= a.N); return *this = *this + a; } static const Value zero() { return Value(0); } }; template struct Index { static const int Q = 1 << M, N = Q - 1; static_assert(M <= 8 * sizeof(TYPE), "TYPE not wide enough"); static_assert(Q == (POLY & ~N), "POLY not of degree Q"); TYPE i; Index() {} explicit Index(TYPE i) : i(i) { assert(i < modulus()); } explicit operator int () const { return i; } Index operator *= (Index a) { assert(a.i < a.modulus()); assert(i < modulus()); return *this = *this * a; } Index operator /= (Index a) { assert(a.i < a.modulus()); assert(i < modulus()); return *this = *this / a; } static const TYPE modulus() { return N; } }; template struct Tables { static const int Q = 1 << M, N = Q - 1; static_assert(M <= 8 * sizeof(TYPE), "TYPE not wide enough"); static_assert(Q == (POLY & ~N), "POLY not of degree Q"); static TYPE *LOG, *EXP; TYPE log_[Q], exp_[Q]; static TYPE next(TYPE a) { return a & (TYPE)(Q >> 1) ? (a << 1) ^ (TYPE)POLY : a << 1; } static TYPE log(TYPE a) { assert(LOG != nullptr); assert(a <= N); return LOG[a]; } static TYPE exp(TYPE a) { assert(EXP != nullptr); assert(a <= N); return EXP[a]; } Tables() { assert(LOG == nullptr); LOG = log_; assert(EXP == nullptr); EXP = exp_; log_[exp_[N] = 0] = N; TYPE a = 1; for (int i = 0; i < N; ++i, a = next(a)) { log_[exp_[i] = a] = i; assert(!i || a != 1); } assert(1 == a); } ~Tables() { assert(LOG != nullptr); LOG = nullptr; assert(EXP != nullptr); EXP = nullptr; } }; template TYPE *Tables::LOG; template TYPE *Tables::EXP; template Index index(Value a) { assert(a.v <= a.N); assert(a.v); return Index(Tables::log(a.v)); } template Value value(Index a) { assert(a.i < a.modulus()); return Value(Tables::exp(a.i)); } template bool operator == (Value a, Value b) { assert(a.v <= a.N); assert(b.v <= b.N); return a.v == b.v; } template bool operator != (Value a, Value b) { assert(a.v <= a.N); assert(b.v <= b.N); return a.v != b.v; } template Value operator + (Value a, Value b) { assert(a.v <= a.N); assert(b.v <= b.N); return Value(a.v ^ b.v); } template Index operator * (Index a, Index b) { assert(a.i < a.modulus()); assert(b.i < b.modulus()); TYPE tmp = a.i + b.i; return Index(a.modulus() - a.i <= b.i ? tmp - a.modulus() : tmp); } template Value operator * (Value a, Value b) { assert(a.v <= a.N); assert(b.v <= b.N); return (!a.v || !b.v) ? a.zero() : value(index(a) * index(b)); } template Value rcp(Value a) { assert(a.v <= a.N); assert(a.v); return value(Index(index(a).modulus() - index(a).i)); } template Index operator / (Index a, Index b) { assert(a.i < a.modulus()); assert(b.i < b.modulus()); TYPE tmp = a.i - b.i; return Index(a.i < b.i ? tmp + a.modulus() : tmp); } template Value operator / (Value a, Value b) { assert(a.v <= a.N); assert(b.v <= b.N); assert(b.v); return !a.v ? a.zero() : value(index(a) / index(b)); } template Value operator / (Index a, Value b) { assert(a.i < a.modulus()); assert(b.v <= b.N); assert(b.v); return value(a / index(b)); } template Value operator / (Value a, Index b) { assert(a.v <= a.N); assert(b.i < b.modulus()); return !a.v ? a.zero() : value(index(a) / b); } template Value operator * (Index a, Value b) { assert(a.i < a.modulus()); assert(b.v <= b.N); return !b.v ? b.zero() : value(a * index(b)); } template Value operator * (Value a, Index b) { assert(a.v <= a.N); assert(b.i < b.modulus()); return !a.v ? a.zero() : value(index(a) * b); } template Value fma(Index a, Index b, Value c) { assert(a.i < a.modulus()); assert(b.i < b.modulus()); assert(c.v <= c.N); return value(a * b) + c; } template Value fma(Index a, Value b, Value c) { assert(a.i < a.modulus()); assert(b.v <= b.N); assert(c.v <= c.N); return !b.v ? c : (value(a * index(b)) + c); } template Value fma(Value a, Index b, Value c) { assert(a.v <= a.N); assert(b.i < b.modulus()); assert(c.v <= c.N); return !a.v ? c : (value(index(a) * b) + c); } template Value fma(Value a, Value b, Value c) { assert(a.v <= a.N); assert(b.v <= b.N); assert(c.v <= c.N); return (!a.v || !b.v) ? c : (value(index(a) * index(b)) + c); } } template class GaloisField { public: static const int M = WIDTH, Q = 1 << M, N = Q - 1; static_assert(M <= 8 * sizeof(TYPE), "TYPE not wide enough"); static_assert(Q == (POLY & ~N), "POLY not of degree Q"); typedef TYPE value_type; typedef GF::Value ValueType; typedef GF::Index IndexType; private: GF::Tables Tables; }; }