#include "bee2/core/util.h"
#include "bee2/math/pp.h"
#include "bee2/math/ww.h"
void ppMulMod(word c[], const word a[], const word b[], const word mod[],
size_t n, void* stack)
{
word* prod = (word*)stack;
stack = prod + 2 * n;
ASSERT(wwCmp(a, mod, n) < 0 && wwCmp(b, mod, n) < 0);
ASSERT(n > 0 && mod[n - 1] != 0);
ASSERT(wwIsValid(c, n));
ppMul(prod, a, n, b, n, stack);
ppMod(c, prod, 2 * n, mod, n, stack);
}
size_t ppMulMod_deep(size_t n)
{
return O_OF_W(2 * n) +
utilMax(2,
ppMul_deep(n, n),
ppMod_deep(2 * n, n));
}
void ppSqrMod(word b[], const word a[], const word mod[], size_t n,
void* stack)
{
word* sqr = (word*)stack;
stack = sqr + 2 * n;
ASSERT(wwCmp(a, mod, n) < 0);
ASSERT(n > 0 && mod[n - 1] != 0);
ASSERT(wwIsValid(b, n));
ppSqr(sqr, a, n, stack);
ppMod(b, sqr, 2 * n, mod, n, stack);
}
size_t ppSqrMod_deep(size_t n)
{
return O_OF_W(2 * n) +
utilMax(2,
ppSqr_deep(n),
ppMod_deep(2 * n, n));
}
void ppDivMod(word b[], const word divident[], const word a[],
const word mod[], size_t n, void* stack)
{
size_t nu, nv;
word* u = (word*)stack;
word* v = u + n;
word* da0 = v + n;
word* da = da0 + n;
ASSERT(wwCmp(a, mod, n) < 0);
ASSERT(wwCmp(divident, mod, n) < 0);
ASSERT(n > 0 && mod[n - 1] != 0 && wwTestBit(mod, 0));
ASSERT(wwIsValid(b, n));
wwCopy(da0, divident, n);
wwSetZero(da, n);
wwCopy(u, a, n);
nu = wwWordSize(u, n);
wwCopy(v, mod, n);
nv = n;
while (!wwIsZero(u, nu))
{
for (; wwTestBit(u, 0) == 0; wwShLo(u, nu, 1))
if (wwTestBit(da0, 0) == 0)
wwShLo(da0, n, 1);
else
wwXor2(da0, mod, n), wwShLo(da0, n, 1);
for (; wwTestBit(v, 0) == 0; wwShLo(v, nv, 1))
if (wwTestBit(da, 0) == 0)
wwShLo(da, n, 1);
else
wwXor2(da, mod, n), wwShLo(da, n, 1);
nu = wwWordSize(u, nu);
nv = wwWordSize(v, nv);
if (wwCmp2(u, nu, v, nv) >= 0)
{
wwXor2(u, v, nv);
wwXor2(da0, da, n);
}
else
{
wwXor2(v, u, nu);
wwXor2(da, da0, n);
}
}
EXPECT(wwIsW(v, nv, 1));
if (wwIsW(v, nv, 1))
wwCopy(b, da, n);
else
wwSetZero(b, n);
}
size_t ppDivMod_deep(size_t n)
{
return O_OF_W(4 * n);
}
void ppInvMod(word b[], const word a[], const word mod[], size_t n,
void* stack)
{
word* divident = (word*)stack;
stack = divident + n;
wwSetW(divident, n, 1);
ppDivMod(b, divident, a, mod, n, stack);
}
size_t ppInvMod_deep(size_t n)
{
return O_OF_W(n) + ppDivMod_deep(n);
}