#include "bee2/core/mem.h"
#include "bee2/core/util.h"
#include "bee2/math/ecp.h"
#include "bee2/math/gfp.h"
#include "bee2/math/pri.h"
#include "bee2/math/ww.h"
#include "bee2/math/zm.h"
#include "bee2/math/zz.h"
#define ecpSeemsOnA(a, ec)\
(zmIsIn(ecX(a), (ec)->f) && zmIsIn(ecY(a, (ec)->f->n), (ec)->f))
#define ecpSeemsOn3(a, ec)\
(ecpSeemsOnA(a, ec) && zmIsIn(ecZ(a, (ec)->f->n), (ec)->f))
static bool_t ecpFromAJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOnA(a, ec));
ASSERT(a == b || wwIsDisjoint2(a, 2 * n, b, 3 * n));
qrCopy(ecX(b), ecX(a), ec->f);
qrCopy(ecY(b, n), ecY(a, n), ec->f);
qrSetUnity(ecZ(b, n), ec->f);
return TRUE;
}
static bool_t ecpToAJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
stack = t2 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(a == b || wwIsDisjoint2(a, 3 * n, b, 2 * n));
if (qrIsZero(ecZ(a, n), ec->f))
return FALSE;
qrInv(t1, ecZ(a, n), ec->f, stack);
qrSqr(t2, t1, ec->f, stack);
qrMul(ecX(b), ecX(a), t2, ec->f, stack);
qrMul(t2, t1, t2, ec->f, stack);
qrMul(ecY(b, n), ecY(a, n), t2, ec->f, stack);
return TRUE;
}
static size_t ecpToAJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(2 * n) + f_deep;
}
static void ecpNegJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
qrCopy(ecX(b), ecX(a), ec->f);
zmNeg(ecY(b, n), ecY(a, n), ec->f);
qrCopy(ecZ(b, n), ecZ(a, n), ec->f);
}
static void ecpDblJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
stack = t2 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
if (qrIsZero(ecZ(a, n), ec->f) || qrIsZero(ecY(a, n), ec->f))
{
qrSetZero(ecZ(b, n), ec->f);
return;
}
qrSqr(t1, ecZ(a, n), ec->f, stack);
qrMul(ecZ(b, n), ecY(a, n), ecZ(a, n), ec->f, stack);
gfpDouble(ecZ(b, n), ecZ(b, n), ec->f);
qrSqr(t1, t1, ec->f, stack);
qrMul(t1, ec->A, t1, ec->f, stack);
qrSqr(t2, ecX(a), ec->f, stack);
zmAdd(t1, t1, t2, ec->f);
gfpDouble(t2, t2, ec->f);
zmAdd(t1, t1, t2, ec->f);
gfpDouble(ecY(b, n), ecY(a, n), ec->f);
qrSqr(ecY(b, n), ecY(b, n), ec->f, stack);
qrSqr(t2, ecY(b, n), ec->f, stack);
gfpHalf(t2, t2, ec->f);
qrMul(ecY(b, n), ecY(b, n), ecX(a), ec->f, stack);
qrSqr(ecX(b), t1, ec->f, stack);
zmSub(ecX(b), ecX(b), ecY(b, n), ec->f);
zmSub(ecX(b), ecX(b), ecY(b, n), ec->f);
zmSub(ecY(b, n), ecY(b, n), ecX(b), ec->f);
qrMul(ecY(b, n), ecY(b, n), t1, ec->f, stack);
zmSub(ecY(b, n), ecY(b, n), t2, ec->f);
}
static size_t ecpDblJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(2 * n) + f_deep;
}
static void ecpDblJA3(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
stack = t2 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
if (qrIsZero(ecZ(a, n), ec->f) || qrIsZero(ecY(a, n), ec->f))
{
qrSetZero(ecZ(b, n), ec->f);
return;
}
qrSqr(t1, ecZ(a, n), ec->f, stack);
qrMul(ecZ(b, n), ecY(a, n), ecZ(a, n), ec->f, stack);
gfpDouble(ecZ(b, n), ecZ(b, n), ec->f);
zmSub(t2, ecX(a), t1, ec->f);
zmAdd(t1, ecX(a), t1, ec->f);
qrMul(t2, t1, t2, ec->f, stack);
gfpDouble(t1, t2, ec->f);
zmAdd(t1, t1, t2, ec->f);
gfpDouble(ecY(b, n), ecY(a, n), ec->f);
qrSqr(ecY(b, n), ecY(b, n), ec->f, stack);
qrSqr(t2, ecY(b, n), ec->f, stack);
gfpHalf(t2, t2, ec->f);
qrMul(ecY(b, n), ecY(b, n), ecX(a), ec->f, stack);
qrSqr(ecX(b), t1, ec->f, stack);
zmSub(ecX(b), ecX(b), ecY(b, n), ec->f);
zmSub(ecX(b), ecX(b), ecY(b, n), ec->f);
zmSub(ecY(b, n), ecY(b, n), ecX(b), ec->f);
qrMul(ecY(b, n), ecY(b, n), t1, ec->f, stack);
zmSub(ecY(b, n), ecY(b, n), t2, ec->f);
}
static size_t ecpDblJA3_deep(size_t n, size_t f_deep)
{
return O_OF_W(2 * n) + f_deep;
}
static void ecpDblAJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
word* t4 = t3 + n;
stack = t4 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOnA(a, ec));
ASSERT(a == b || wwIsDisjoint2(a, 2 * n, b, 3 * n));
if (qrIsZero(ecY(a, n), ec->f))
{
qrSetZero(ecZ(b, n), ec->f);
return;
}
qrSqr(t1, ecX(a), ec->f, stack);
qrSqr(t2, ecY(a, n), ec->f, stack);
qrSqr(t3, t2, ec->f, stack);
zmAdd(t2, t2, ecX(a), ec->f);
qrSqr(t2, t2, ec->f, stack);
zmSub(t2, t2, t1, ec->f);
zmSub(t2, t2, t3, ec->f);
gfpDouble(t2, t2, ec->f);
gfpDouble(t4, t1, ec->f);
zmAdd(t4, t4, t1, ec->f);
zmAdd(t4, t4, ec->A, ec->f);
gfpDouble(t1, t2, ec->f);
qrSqr(ecX(b), t4, ec->f, stack);
zmSub(ecX(b), ecX(b), t1, ec->f);
gfpDouble(ecZ(b, n), ecY(a, n), ec->f);
zmSub(t2, t2, ecX(b), ec->f);
qrMul(ecY(b, n), t4, t2, ec->f, stack);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
zmSub(ecY(b, n), ecY(b, n), t3, ec->f);
}
static size_t ecpDblAJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(4 * n) + f_deep;
}
static void ecpAddJ(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
word* t4 = t3 + n;
stack = t4 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(ecpSeemsOn3(b, ec));
ASSERT(wwIsSameOrDisjoint(a, c, 3 * n));
ASSERT(wwIsSameOrDisjoint(b, c, 3 * n));
if (qrIsZero(ecZ(a, n), ec->f))
{
wwCopy(c, b, 3 * n);
return;
}
if (qrIsZero(ecZ(b, n), ec->f))
{
wwCopy(c, a, 3 * n);
return;
}
qrSqr(t1, ecZ(a, n), ec->f, stack);
qrSqr(t2, ecZ(b, n), ec->f, stack);
qrMul(t3, ecZ(b, n), t2, ec->f, stack);
qrMul(t3, ecY(a, n), t3, ec->f, stack);
qrMul(t4, ecZ(a, n), t1, ec->f, stack);
qrMul(t4, ecY(b, n), t4, ec->f, stack);
zmAdd(ecZ(c, n), ecZ(a, n), ecZ(b, n), ec->f);
qrSqr(ecZ(c, n), ecZ(c, n), ec->f, stack);
zmSub(ecZ(c, n), ecZ(c, n), t1, ec->f);
zmSub(ecZ(c, n), ecZ(c, n), t2, ec->f);
qrMul(t1, ecX(b), t1, ec->f, stack);
qrMul(t2, ecX(a), t2, ec->f, stack);
zmSub(t1, t1, t2, ec->f);
if (qrIsZero(t1, ec->f))
{
if (qrCmp(t3, t4, ec->f) == 0)
ecpDblJ(c, c == a ? b : a, ec, stack);
else
qrSetZero(ecZ(c, n), ec->f);
return;
}
qrMul(ecZ(c, n), ecZ(c, n), t1, ec->f, stack);
zmSub(t4, t4, t3, ec->f);
gfpDouble(t4, t4, ec->f);
gfpDouble(ecY(c, n), t1, ec->f);
qrSqr(ecY(c, n), ecY(c, n), ec->f, stack);
qrMul(t1, t1, ecY(c, n), ec->f, stack);
qrMul(ecY(c, n), t2, ecY(c, n), ec->f, stack);
gfpDouble(t2, ecY(c, n), ec->f);
qrSqr(ecX(c), t4, ec->f, stack);
zmSub(ecX(c), ecX(c), t1, ec->f);
zmSub(ecX(c), ecX(c), t2, ec->f);
zmSub(ecY(c, n), ecY(c, n), ecX(c), ec->f);
qrMul(ecY(c, n), t4, ecY(c, n), ec->f, stack);
gfpDouble(t3, t3, ec->f);
qrMul(t3, t3, t1, ec->f, stack);
zmSub(ecY(c, n), ecY(c, n), t3, ec->f);
}
static size_t ecpAddJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(4 * n) +
utilMax(2,
f_deep,
ecpDblJ_deep(n, f_deep));
}
static void ecpAddAJ(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
word* t4 = t3 + n;
stack = t4 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(ecpSeemsOnA(b, ec));
ASSERT(wwIsSameOrDisjoint(a, c, 3 * n));
ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n));
if (qrIsZero(ecZ(a, n), ec->f))
{
qrCopy(ecX(c), ecX(b), ec->f);
qrCopy(ecY(c, n), ecY(b, n), ec->f);
qrSetUnity(ecZ(c, n), ec->f);
return;
}
qrSqr(t1, ecZ(a, n), ec->f, stack);
qrMul(t2, t1, ecZ(a, n), ec->f, stack);
qrMul(t1, t1, ecX(b), ec->f, stack);
qrMul(t2, t2, ecY(b, n), ec->f, stack);
zmSub(t1, t1, ecX(a), ec->f);
zmSub(t2, t2, ecY(a, n), ec->f);
if (qrIsZero(t1, ec->f))
{
if (qrIsZero(t2, ec->f))
ecpDblAJ(c, b, ec, stack);
else
qrSetZero(ecZ(c, n), ec->f);
return;
}
qrMul(ecZ(c, n), t1, ecZ(a, n), ec->f, stack);
qrSqr(t3, t1, ec->f, stack);
qrMul(t4, t1, t3, ec->f, stack);
qrMul(t3, t3, ecX(a), ec->f, stack);
gfpDouble(t1, t3, ec->f);
qrSqr(ecX(c), t2, ec->f, stack);
zmSub(ecX(c), ecX(c), t1, ec->f);
zmSub(ecX(c), ecX(c), t4, ec->f);
zmSub(t3, t3, ecX(c), ec->f);
qrMul(t3, t3, t2, ec->f, stack);
qrMul(t4, t4, ecY(a, n), ec->f, stack);
zmSub(ecY(c, n), t3, t4, ec->f);
}
static size_t ecpAddAJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(4 * n) +
utilMax(2,
f_deep,
ecpDblAJ_deep(n, f_deep));
}
static void ecpSubJ(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t = (word*)stack;
stack = t + 3 * n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(ecpSeemsOn3(b, ec));
ASSERT(wwIsSameOrDisjoint(a, c, 3 * n));
ASSERT(wwIsSameOrDisjoint(b, c, 3 * n));
qrCopy(ecX(t), ecX(b), ec->f);
zmNeg(ecY(t, n), ecY(b, n), ec->f);
qrCopy(ecZ(t, n), ecZ(b, n), ec->f);
ecpAddJ(c, a, t, ec, stack);
}
static size_t ecpSubJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(3 * n) + ecpAddJ_deep(n, f_deep);
}
static void ecpSubAJ(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t = (word*)stack;
stack = t + 2 * n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(ecpSeemsOnA(b, ec));
ASSERT(wwIsSameOrDisjoint(a, c, 3 * n));
ASSERT(b == c || wwIsDisjoint2(b, 2 * n, c, 3 * n));
qrCopy(ecX(t), ecX(b), ec->f);
zmNeg(ecY(t, n), ecY(b, n), ec->f);
ecpAddAJ(c, a, t, ec, stack);
}
static size_t ecpSubAJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(2 * n) + ecpAddAJ_deep(n, f_deep);
}
static void ecpTplJ(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t0 = (word*)stack;
word* t1 = t0 + n;
word* t2 = t1 + n;
word* t3 = t2 + n;
word* t4 = t3 + n;
word* t5 = t4 + n;
word* t6 = t5 + n;
word* t7 = t6 + n;
stack = t7 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
qrSqr(t0, ecX(a), ec->f, stack);
qrSqr(t1, ecY(a, n), ec->f, stack);
qrSqr(t2, ecZ(a, n), ec->f, stack);
qrSqr(t3, t1, ec->f, stack);
qrSqr(t4, t2, ec->f, stack);
qrMul(t4, t4, ec->A, ec->f, stack);
gfpDouble(t5, t0, ec->f);
zmAdd(t5, t0, t5, ec->f);
zmAdd(t4, t4, t5, ec->f);
qrSqr(t5, t4, ec->f, stack);
zmAdd(t6, ecX(a), t1, ec->f);
qrSqr(t6, t6, ec->f, stack);
zmSub(t6, t6, t0, ec->f);
zmSub(t6, t6, t3, ec->f);
gfpDouble(t7, t6, ec->f);
zmAdd(t6, t6, t7, ec->f);
gfpDouble(t6, t6, ec->f);
zmSub(t6, t6, t5, ec->f);
qrSqr(t7, t6, ec->f, stack);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
zmAdd(ecZ(b, n), ecZ(a, n), t6, ec->f);
qrSqr(ecZ(b, n), ecZ(b, n), ec->f, stack);
zmSub(ecZ(b, n), ecZ(b, n), t2, ec->f);
zmSub(ecZ(b, n), ecZ(b, n), t7, ec->f);
zmAdd(t2, t4, t6, ec->f);
qrSqr(t2, t2, ec->f, stack);
zmSub(t2, t2, t5, ec->f);
zmSub(t2, t2, t7, ec->f);
zmSub(t2, t2, t3, ec->f);
zmSub(t3, t3, t2, ec->f);
qrMul(t3, t2, t3, ec->f, stack);
qrMul(t6, t6, t7, ec->f, stack);
zmSub(t3, t3, t6, ec->f);
qrMul(ecY(b, n), ecY(a, n), t3, ec->f, stack);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
qrMul(t1, t1, t2, ec->f, stack);
gfpDouble(t1, t1, ec->f);
gfpDouble(t1, t1, ec->f);
qrMul(ecX(b), ecX(a), t7, ec->f, stack);
zmSub(ecX(b), ecX(b), t1, ec->f);
gfpDouble(ecX(b), ecX(b), ec->f);
gfpDouble(ecX(b), ecX(b), ec->f);
}
static size_t ecpTplJ_deep(size_t n, size_t f_deep)
{
return O_OF_W(8 * n) + f_deep;
}
static void ecpTplJA3(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
word* t4 = t3 + n;
word* t5 = t4 + n;
word* t6 = t5 + n;
word* t7 = t6 + n;
stack = t7 + n;
ASSERT(ecIsOperable(ec) && ec->d == 3);
ASSERT(ecpSeemsOn3(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
qrSqr(t1, ecY(a, n), ec->f, stack);
qrSqr(t2, ecZ(a, n), ec->f, stack);
qrSqr(t3, t1, ec->f, stack);
zmSub(t4, ecX(a), t2, ec->f);
zmAdd(t5, ecX(a), t2, ec->f);
qrMul(t4, t4, t5, ec->f, stack);
gfpDouble(t5, t4, ec->f);
zmAdd(t4, t4, t5, ec->f);
qrSqr(t5, t4, ec->f, stack);
qrMul(t6, ecX(a), t1, ec->f, stack);
gfpDouble(t7, t6, ec->f);
zmAdd(t6, t6, t7, ec->f);
gfpDouble(t6, t6, ec->f);
gfpDouble(t6, t6, ec->f);
zmSub(t6, t6, t5, ec->f);
qrSqr(t7, t6, ec->f, stack);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
gfpDouble(t3, t3, ec->f);
zmAdd(ecZ(b, n), ecZ(a, n), t6, ec->f);
qrSqr(ecZ(b, n), ecZ(b, n), ec->f, stack);
zmSub(ecZ(b, n), ecZ(b, n), t2, ec->f);
zmSub(ecZ(b, n), ecZ(b, n), t7, ec->f);
zmAdd(t2, t4, t6, ec->f);
qrSqr(t2, t2, ec->f, stack);
zmSub(t2, t2, t5, ec->f);
zmSub(t2, t2, t7, ec->f);
zmSub(t2, t2, t3, ec->f);
zmSub(t3, t3, t2, ec->f);
qrMul(t3, t2, t3, ec->f, stack);
qrMul(t6, t6, t7, ec->f, stack);
zmSub(t3, t3, t6, ec->f);
qrMul(ecY(b, n), ecY(a, n), t3, ec->f, stack);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
gfpDouble(ecY(b, n), ecY(b, n), ec->f);
qrMul(t1, t1, t2, ec->f, stack);
gfpDouble(t1, t1, ec->f);
gfpDouble(t1, t1, ec->f);
qrMul(ecX(b), ecX(a), t7, ec->f, stack);
zmSub(ecX(b), ecX(b), t1, ec->f);
gfpDouble(ecX(b), ecX(b), ec->f);
gfpDouble(ecX(b), ecX(b), ec->f);
}
static size_t ecpTplJA3_deep(size_t n, size_t f_deep)
{
return O_OF_W(7 * n) + f_deep;
}
bool_t ecpCreateJ(ec_o* ec, const qr_o* f, const octet A[], const octet B[],
void* stack)
{
register bool_t bA3;
word* t;
ASSERT(memIsValid(ec, sizeof(ec_o)));
ASSERT(gfpIsOperable(f));
ASSERT(memIsValid(A, f->no));
ASSERT(memIsValid(B, f->no));
if (wwCmpW(f->mod, f->n, 3) <= 0)
return FALSE;
memSetZero(ec, sizeof(ec_o));
ec->d = 3;
ec->f = f;
ec->A = (word*)ec->descr;
ec->B = ec->A + f->n;
if (!qrFrom(ec->A, A, ec->f, stack) || !qrFrom(ec->B, B, ec->f, stack))
return FALSE;
t = (word*)stack;
gfpDouble(t, f->unity, f);
zmAdd(t, t, f->unity, f);
zmNeg(t, t, f);
bA3 = qrCmp(t, ec->A, f) == 0;
ec->base = ec->B + f->n;
ec->order = ec->base + 2 * f->n;
ec->froma = ecpFromAJ;
ec->toa = ecpToAJ;
ec->neg = ecpNegJ;
ec->add = ecpAddJ;
ec->adda = ecpAddAJ;
ec->sub = ecpSubJ;
ec->suba = ecpSubAJ;
ec->dbl = bA3 ? ecpDblJA3 : ecpDblJ;
ec->dbla = ecpDblAJ;
ec->tpl = bA3 ? ecpTplJA3 : ecpTplJ;
ec->deep = utilMax(8,
ecpToAJ_deep(f->n, f->deep),
ecpAddJ_deep(f->n, f->deep),
ecpAddAJ_deep(f->n, f->deep),
ecpSubJ_deep(f->n, f->deep),
ecpSubAJ_deep(f->n, f->deep),
bA3 ? ecpDblJA3_deep(f->n, f->deep) : ecpDblJ_deep(f->n, f->deep),
ecpDblAJ_deep(f->n, f->deep),
bA3 ? ecpTplJA3_deep(f->n, f->deep) : ecpTplJ_deep(f->n, f->deep));
ec->hdr.keep = sizeof(ec_o) + O_OF_W(5 * f->n + 1);
ec->hdr.p_count = 6;
ec->hdr.o_count = 1;
CLEAN(bA3);
return TRUE;
}
size_t ecpCreateJ_keep(size_t n)
{
return sizeof(ec_o) + O_OF_W(5 * n + 1);
}
size_t ecpCreateJ_deep(size_t n, size_t f_deep)
{
return utilMax(11,
O_OF_W(n),
ecpToAJ_deep(n, f_deep),
ecpAddJ_deep(n, f_deep),
ecpAddAJ_deep(n, f_deep),
ecpSubJ_deep(n, f_deep),
ecpSubAJ_deep(n, f_deep),
ecpDblJ_deep(n, f_deep),
ecpDblJA3_deep(n, f_deep),
ecpDblAJ_deep(n, f_deep),
ecpTplJ_deep(n, f_deep),
ecpTplJA3_deep(n, f_deep));
}
bool_t ecpIsValid(const ec_o* ec, void* stack)
{
size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
stack = t3 + n;
if (!ecIsOperable2(ec) ||
!gfpIsValid(ec->f, stack) ||
wwCmpW(ec->f->mod, ec->f->n, 3) <= 0 ||
ec->deep < ec->f->deep ||
!zmIsIn(ec->A, ec->f) ||
!zmIsIn(ec->B, ec->f))
return FALSE;
qrSqr(t1, ec->A, ec->f, stack);
qrMul(t1, t1, ec->A, ec->f, stack);
gfpDouble(t1, t1, ec->f);
gfpDouble(t1, t1, ec->f);
qrSqr(t2, ec->B, ec->f, stack);
gfpDouble(t3, t2, ec->f);
zmAdd(t2, t2, t3, ec->f);
gfpDouble(t3, t2, ec->f);
zmAdd(t2, t2, t3, ec->f);
gfpDouble(t3, t2, ec->f);
zmAdd(t2, t2, t3, ec->f);
zmAdd(t1, t1, t2, ec->f);
return !qrIsZero(t1, ec->f);
}
size_t ecpIsValid_deep(size_t n, size_t f_deep)
{
return O_OF_W(3 * n) +
utilMax(2,
f_deep,
gfpIsValid_deep(n));
}
bool_t ecpSeemsValidGroup(const ec_o* ec, void* stack)
{
size_t n = ec->f->n;
int cmp;
word w;
word* t1 = (word*)stack;
word* t2 = t1 + n + 1;
word* t3 = t2 + n + 2;
stack = t3 + 2 * n;
ASSERT(ecIsOperable(ec));
if (!ecIsOperableGroup(ec) ||
!ecpIsOnA(ec->base, ec, stack))
return FALSE;
t1[n + 1] = zzMulW(t1, ec->order, n + 1, ec->cofactor);
if (zzSubW2(t1, n + 2, 1))
return FALSE;
if (wwCmp2(t1, n + 2, ec->f->mod, n) >= 0)
zzSubW2(t1 + n, 2, zzSub2(t1, ec->f->mod, n));
else
zzSub(t1, ec->f->mod, t1, n);
n = wwWordSize(t1, n + 2);
if (n > ec->f->n)
return FALSE;
zzSqr(t2, t1, n, stack);
w = wwGetBits(t2, 0, 2);
wwShLo(t2, 2 * n, 2);
cmp = wwCmp2(t2, 2 * n, ec->f->mod, ec->f->n);
if (cmp > 0 || cmp == 0 && w != 0)
return FALSE;
return TRUE;
}
size_t ecpSeemsValidGroup_deep(size_t n, size_t f_deep)
{
return O_OF_W(4 * n + 3) +
utilMax(2,
ecpIsOnA_deep(n, f_deep),
zzSqr_deep(n));
}
bool_t ecpIsSafeGroup(const ec_o* ec, size_t mov_threshold, void* stack)
{
size_t n1 = ec->f->n + 1;
word* t1 = (word*)stack;
word* t2 = t1 + n1;
stack = t2 + n1;
ASSERT(ecIsOperable(ec));
ASSERT(ecIsOperableGroup(ec));
n1 = wwWordSize(ec->order, n1);
if (!priIsPrime(ec->order, n1, stack))
return FALSE;
if (wwCmp2(ec->f->mod, ec->f->n, ec->order, n1) == 0)
return FALSE;
if (mov_threshold)
{
zzMod(t1, ec->f->mod, ec->f->n, ec->order, n1, stack);
wwCopy(t2, t1, n1);
if (wwCmpW(t2, n1, 1) == 0)
return FALSE;
while (--mov_threshold)
{
zzMulMod(t2, t2, t1, ec->order, n1, stack);
if (wwCmpW(t2, n1, 1) == 0)
return FALSE;
}
}
return TRUE;
}
size_t ecpIsSafeGroup_deep(size_t n)
{
const size_t n1 = n + 1;
return O_OF_W(2 * n1) +
utilMax(3,
priIsPrime_deep(n1),
zzMod_deep(n, n1),
zzMulMod_deep(n1));
}
bool_t ecpIsOnA(const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
stack = t2 + n;
ASSERT(ecIsOperable(ec));
if (!zmIsIn(ecX(a), ec->f) || !zmIsIn(ecY(a, n), ec->f))
return FALSE;
qrSqr(t1, ecX(a), ec->f, stack);
zmAdd(t1, t1, ec->A, ec->f);
qrMul(t1, t1, ecX(a), ec->f, stack);
zmAdd(t1, t1, ec->B, ec->f);
qrSqr(t2, ecY(a, n), ec->f, stack);
return qrCmp(t1, t2, ec->f) == 0;
}
size_t ecpIsOnA_deep(size_t n, size_t f_deep)
{
return O_OF_W(2 * n) + f_deep;
}
void ecpNegA(word b[], const word a[], const ec_o* ec)
{
const size_t n = ec->f->n;
ASSERT(ecIsOperable(ec));
ASSERT(ecpSeemsOnA(a, ec));
ASSERT(wwIsSameOrDisjoint(a, b, 3 * n));
qrCopy(ecX(b), ecX(a), ec->f);
zmNeg(ecY(b, n), ecY(a, n), ec->f);
}
bool_t ecpAddAA(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
stack = t3 + n;
ASSERT(ecIsOperable(ec));
ASSERT(ecpSeemsOnA(a, ec));
ASSERT(ecpSeemsOnA(b, ec));
if (qrCmp(ecX(a), ecX(b), ec->f) != 0)
{
zmSub(t1, ecX(a), ecX(b), ec->f);
zmSub(t2, ecY(a, n), ecY(b, n), ec->f);
}
else
{
if (qrCmp(ecY(a, n), ecY(b, n), ec->f) != 0 ||
qrIsZero(ecY(b, n), ec->f))
return FALSE;
qrSqr(t1, ecX(a), ec->f, stack);
gfpDouble(t2, t1, ec->f);
zmAdd(t2, t2, t1, ec->f);
zmAdd(t2, t2, ec->A, ec->f);
gfpDouble(t1, ecY(a, n), ec->f);
}
qrDiv(t2, t2, t1, ec->f, stack);
qrSqr(t1, t2, ec->f, stack);
zmSub(t1, t1, ecX(a), ec->f);
zmSub(t1, t1, ecX(b), ec->f);
zmSub(t3, ecX(a), t1, ec->f);
qrMul(t2, t2, t3, ec->f, stack);
zmSub(t2, t2, ecY(a, n), ec->f);
qrCopy(ecX(c), t1, ec->f);
qrCopy(ecY(c, n), t2, ec->f);
return TRUE;
}
size_t ecpAddAA_deep(size_t n, size_t f_deep)
{
return O_OF_W(3 * n) + f_deep;
}
bool_t ecpSubAA(word c[], const word a[], const word b[], const ec_o* ec,
void* stack)
{
const size_t n = ec->f->n;
word* t1 = (word*)stack;
word* t2 = t1 + n;
word* t3 = t2 + n;
stack = t3 + n;
ASSERT(ecIsOperable(ec));
ASSERT(ecpSeemsOnA(a, ec));
ASSERT(ecpSeemsOnA(b, ec));
if (qrCmp(ecX(a), ecX(b), ec->f) != 0)
{
zmSub(t1, ecX(a), ecX(b), ec->f);
zmAdd(t2, ecY(a, n), ecY(b, n), ec->f);
}
else
{
if (qrCmp(ecY(a, n), ecY(b, n), ec->f) == 0)
return FALSE;
qrSqr(t1, ecX(a), ec->f, stack);
gfpDouble(t2, t1, ec->f);
zmAdd(t2, t2, t1, ec->f);
zmAdd(t2, t2, ec->A, ec->f);
gfpDouble(t1, ecY(a, n), ec->f);
}
qrDiv(t2, t2, t1, ec->f, stack);
qrSqr(t1, t2, ec->f, stack);
zmSub(t1, t1, ecX(a), ec->f);
zmSub(t1, t1, ecX(b), ec->f);
zmSub(t3, ecX(a), t1, ec->f);
qrMul(t2, t2, t3, ec->f, stack);
zmSub(t2, t2, ecY(a, n), ec->f);
qrCopy(ecX(c), t1, ec->f);
qrCopy(ecY(c, n), t2, ec->f);
return TRUE;
}
size_t ecpSubAA_deep(size_t n, size_t f_deep)
{
return O_OF_W(3 * n) + f_deep;
}
void ecpSWU(word b[], const word a[], const ec_o* ec, void* stack)
{
const size_t n = ec->f->n;
register size_t mask;
word* t = (word*)stack;
word* x1 = t + n;
word* x2 = x1 + n;
word* y = x2 + n;
word* s = y + n;
stack = s + n;
ASSERT(ecIsOperable(ec));
ASSERT(zmIsIn(a, ec->f));
ASSERT(wwGetBits(ec->f->mod, 0, 2) == 3);
ASSERT(!qrIsZero(ec->A, ec->f) && !qrIsZero(ec->B, ec->f));
qrSqr(t, a, ec->f, stack);
zmNeg(t, t, ec->f);
wwCopy(s, ec->f->mod, n);
zzSubW2(s, n, 2);
qrSqr(x2, t, ec->f, stack);
qrAdd(x2, x2, t, ec->f);
qrMul(x1, x2, ec->A, ec->f, stack);
qrPower(x1, x1, s, n, ec->f, stack);
qrAddUnity(x2, x2, ec->f);
qrMul(x1, x1, x2, ec->f, stack);
qrMul(x1, x1, ec->B, ec->f, stack);
zmNeg(x1, x1, ec->f);
qrSqr(x2, x1, ec->f, stack);
qrMul(x2, x2, x1, ec->f, stack);
qrMul(y, x1, ec->A, ec->f, stack);
qrAdd(y, y, x2, ec->f);
qrAdd(y, y, ec->B, ec->f);
qrMul(x2, x1, t, ec->f, stack);
wwCopy(t, ec->f->mod, n);
wwShLo(t, n, 2);
zzSub(s, s, t, n);
qrPower(t, y, s, n, ec->f, stack);
qrSqr(s, a, ec->f, stack);
qrMul(s, s, a, ec->f, stack);
qrMul(s, s, y, ec->f, stack);
qrSqr(b, t, ec->f, stack);
qrMul(b, b, y, ec->f, stack);
mask = qrIsUnity(b, ec->f) - SIZE_1;
qrCopy(ecX(b), x1 + (mask & n), ec->f);
qrMul(ecY(b, n), t, y + (mask & n), ec->f, stack);
CLEAN(mask);
}
size_t ecpSWU_deep(size_t n, size_t f_deep)
{
return O_OF_W(5 * n) +
utilMax(2,
f_deep,
qrPower_deep(n, n, f_deep));
}