#include <bee2/core/mem.h>
#include <bee2/core/prng.h>
#include <bee2/core/util.h>
#include <bee2/math/pp.h>
#include <bee2/core/u16.h>
#include <bee2/math/ww.h>
static u16 exps16Mul(u16 a, u16 b, u16 poly)
{
size_t i;
u16 c;
for (c = 0, i = 0; i < 16; ++i)
{
c ^= (a & 1) ? b : 0;
a >>= 1;
b = (b << 1) ^ ((b & 0x8000) ? poly : 0);
}
return c;
}
static void exps16Create(u16 s[65536], u16 poly, u16 alpha)
{
size_t pos;
ASSERT(memIsValid(s, 65536 * 2));
s[0] = 0, s[1] = alpha;
for (pos = 2; pos < 65536; ++pos)
s[pos] = exps16Mul(s[pos - 1], alpha, poly);
}
static bool_t ppTestExps16()
{
enum {n = W_OF_B(17)};
const u16 poly = 0x002B;
const u16 alpha = 0x0003;
word mod[n];
word a[n];
word t[n];
u16 s1[65536];
u16 s2[65536];
octet stack[1024];
size_t pos;
if (sizeof(stack) < utilMax(2,
ppIsIrred_deep(n),
ppMulMod_deep(n)))
return FALSE;
u16To(mod, 2, &poly);
wwFrom(mod, mod, 2);
wwSetBit(mod, 16, TRUE);
if (!ppIsIrred(mod, n, stack))
return FALSE;
u16To(a, 2, &alpha);
wwFrom(a, a, 2);
wwCopy(t, a, n);
s1[0] = 0;
for (pos = 1; pos < 65536; ++pos)
{
wwTo(s1 + pos, 2, t);
u16From(s1 + pos, s1 + pos, 2);
ppMulMod(t, t, a, mod, n, stack);
if (wwEq(t, a, n) && pos < 65535)
return FALSE;
}
exps16Create(s2, poly, alpha);
if (!memEq(s1, s2, sizeof(s1)))
return FALSE;
return TRUE;
}
static bool_t ppTestRed()
{
enum { n = W_OF_B(571) };
const pp_trinom_st kb233 = { 233, 74 };
const pp_pentanom_st kb283 = { 283, 12, 7, 5 };
const pp_trinom_st kb409 = { 409, 87 };
const pp_pentanom_st kb571 = { 571, 10, 5, 2 };
size_t reps = 500;
word a[2 * n];
word t[2 * n];
word t1[2 * n];
word mod[n];
octet combo_state[32];
octet stack[2048];
if (sizeof(combo_state) < prngCOMBO_keep() ||
sizeof(stack) < utilMax(1,
ppRed_deep(n)))
return FALSE;
prngCOMBOStart(combo_state, utilNonce32());
while (reps--)
{
size_t m;
prngCOMBOStepR(a, 2 * O_OF_W(n), combo_state);
ASSERT(W_OF_B(233) == W_OF_B(234));
m = W_OF_B(233);
wwCopy(t, a, 2 * m);
wwCopy(t1, a, 2 * m);
wwSetZero(mod, m);
wwSetBit(mod, kb233.m, TRUE);
wwSetBit(mod, kb233.k, TRUE);
wwSetBit(mod, 0, TRUE);
ppRed(t, mod, m, stack);
ppRedTrinomial(t1, &kb233);
if (!wwEq(t, t1, m))
return FALSE;
ASSERT(W_OF_B(283) == W_OF_B(284));
m = W_OF_B(283);
wwCopy(t, a, 2 * m);
wwCopy(t1, a, 2 * m);
wwSetZero(mod, m);
wwSetBit(mod, kb283.m, TRUE);
wwSetBit(mod, kb283.k, TRUE);
wwSetBit(mod, kb283.l, TRUE);
wwSetBit(mod, kb283.l1, TRUE);
wwSetBit(mod, 0, TRUE);
ppRed(t, mod, m, stack);
ppRedPentanomial(t1, &kb283);
if (!wwEq(t, t1, m))
return FALSE;
ASSERT(W_OF_B(409) == W_OF_B(410));
m = W_OF_B(409);
wwCopy(t, a, 2 * m);
wwCopy(t1, a, 2 * m);
wwSetZero(mod, m);
wwSetBit(mod, kb409.m, TRUE);
wwSetBit(mod, kb409.k, TRUE);
wwSetBit(mod, 0, TRUE);
ppRed(t, mod, m, stack);
ppRedTrinomial(t1, &kb409);
if (!wwEq(t, t1, m))
return FALSE;
ASSERT(W_OF_B(571) == W_OF_B(572));
m = W_OF_B(571);
wwCopy(t, a, 2 * m);
wwCopy(t1, a, 2 * m);
wwSetZero(mod, m);
wwSetBit(mod, kb571.m, TRUE);
wwSetBit(mod, kb571.k, TRUE);
wwSetBit(mod, kb571.l, TRUE);
wwSetBit(mod, kb571.l1, TRUE);
wwSetBit(mod, 0, TRUE);
ppRed(t, mod, m, stack);
ppRedPentanomial(t1, &kb571);
if (!wwEq(t, t1, m))
return FALSE;
}
return TRUE;
}
bool_t ppTest()
{
return ppTestExps16() &&
ppTestRed();
}