#include "bee2/core/util.h"
#include "bee2/math/qr.h"
#include "bee2/math/ww.h"
bool_t qrIsOperable(const qr_o* r)
{
return objIsOperable(r) &&
objKeep(r) >= sizeof(qr_o) &&
objPCount(r) == 3 &&
objOCount(r) == 0 &&
r->n > 0 && r->no > 0 &&
wwIsValid(r->unity, r->n) &&
r->from != 0 &&
r->to != 0 &&
r->add != 0 &&
r->sub != 0 &&
r->neg != 0 &&
r->mul != 0 &&
r->sqr != 0 &&
r->inv != 0 &&
r->div != 0;
}
static size_t qrCalcSlideWidth(size_t m)
{
m = B_OF_W(m);
if (m <= 79)
return 3;
if (m <= 239)
return 4;
if (m <= 671)
return 5;
if (m <= 1791)
return 6;
return 7;
}
void qrPower(word c[], const word a[], const word b[], size_t m,
const qr_o* r, void* stack)
{
const size_t w = qrCalcSlideWidth(m);
const size_t powers_count = SIZE_1 << (w - 1);
register word slide;
register size_t slide_size;
size_t pos;
word* power;
word* powers;
ASSERT(qrIsOperable(r));
ASSERT(wwIsValid(a, r->n));
ASSERT(wwIsValid(b, m));
ASSERT(wwIsValid(c, r->n));
power = (word*)stack;
powers = power + r->n;
stack = powers + r->n * powers_count;
if (wwIsZero(b, m))
{
wwCopy(c, r->unity, r->n);
return;
}
ASSERT(w > 0);
if (w == 1)
wwCopy(powers, a, r->n);
else
{
size_t i;
qrSqr(powers, a, r, stack);
qrMul(powers + r->n, a, powers, r, stack);
for (i = 2; i < powers_count; ++i)
qrMul(powers + r->n * i, powers + r->n * i - r->n, powers, r,
stack);
wwCopy(powers, a, r->n);
}
pos = wwBitSize(b, m) - 1;
ASSERT(pos != SIZE_MAX);
slide_size = MIN2(pos + 1, w);
slide = wwGetBits(b, pos - slide_size + 1, slide_size);
while (slide % 2 == 0)
slide >>= 1, slide_size--;
wwCopy(power, powers + r->n * (slide / 2), r->n);
pos -= slide_size;
while (pos != SIZE_MAX)
if (!wwTestBit(b, pos))
{
qrSqr(power, power, r, stack);
--pos;
}
else
{
slide_size = MIN2(pos + 1, w);
slide = wwGetBits(b, pos - slide_size + 1, slide_size);
while (slide % 2 == 0)
slide >>= 1, slide_size--;
pos -= slide_size;
while (slide_size--)
qrSqr(power, power, r, stack);
qrMul(power, power, powers + r->n * (slide / 2), r, stack);
}
CLEAN2(slide_size, slide);
wwCopy(c, power, r->n);
}
size_t qrPower_deep(size_t n, size_t m, size_t r_deep)
{
const size_t powers_count = SIZE_1 << (qrCalcSlideWidth(m) - 1);
return O_OF_W(n + n * powers_count) + r_deep;
}