#include <libecc/fp/fp_sqrt.h>
#include <libecc/nn/nn_add.h>
#include <libecc/nn/nn_logical.h>
ATTRIBUTE_WARN_UNUSED_RET static int legendre(fp_src_t a)
{
int ret, iszero, cmp;
fp pow;
fp one;
nn exp;
pow.magic = one.magic = WORD(0);
exp.magic = WORD(0);
ret = fp_check_initialized(a); EG(ret, err);
ret = fp_init(&pow, a->ctx); EG(ret, err);
ret = fp_init(&one, a->ctx); EG(ret, err);
ret = nn_init(&exp, 0); EG(ret, err);
ret = fp_init(&pow, a->ctx); EG(ret, err);
ret = fp_init(&one, a->ctx); EG(ret, err);
ret = nn_init(&exp, 0); EG(ret, err);
ret = fp_one(&one); EG(ret, err);
ret = nn_dec(&exp, &(a->ctx->p)); EG(ret, err);
ret = nn_rshift(&exp, &exp, 1); EG(ret, err);
ret = fp_pow(&pow, a, &exp); EG(ret, err);
ret = fp_iszero(&pow, &iszero); EG(ret, err);
ret = fp_cmp(&pow, &one, &cmp); EG(ret, err);
if (iszero) {
ret = 0;
} else if (cmp == 0) {
ret = 1;
} else {
ret = -1;
}
err:
fp_uninit(&pow);
fp_uninit(&one);
nn_uninit(&exp);
return ret;
}
int fp_sqrt(fp_t sqrt1, fp_t sqrt2, fp_src_t n)
{
int ret, iszero, cmp, isodd;
nn q, s, one_nn, two_nn, m, i, tmp_nn;
fp z, t, b, r, c, one_fp, tmp_fp, __n;
fp_t _n = &__n;
q.magic = s.magic = one_nn.magic = two_nn.magic = m.magic = WORD(0);
i.magic = tmp_nn.magic = z.magic = t.magic = b.magic = WORD(0);
r.magic = c.magic = one_fp.magic = tmp_fp.magic = __n.magic = WORD(0);
ret = nn_init(&q, 0); EG(ret, err);
ret = nn_init(&s, 0); EG(ret, err);
ret = nn_init(&tmp_nn, 0); EG(ret, err);
ret = nn_init(&one_nn, 0); EG(ret, err);
ret = nn_init(&two_nn, 0); EG(ret, err);
ret = nn_init(&m, 0); EG(ret, err);
ret = nn_init(&i, 0); EG(ret, err);
ret = fp_init(&z, n->ctx); EG(ret, err);
ret = fp_init(&t, n->ctx); EG(ret, err);
ret = fp_init(&b, n->ctx); EG(ret, err);
ret = fp_init(&r, n->ctx); EG(ret, err);
ret = fp_init(&c, n->ctx); EG(ret, err);
ret = fp_init(&one_fp, n->ctx); EG(ret, err);
ret = fp_init(&tmp_fp, n->ctx); EG(ret, err);
ret = fp_copy(_n, n); EG(ret, err);
ret = fp_init(sqrt1, _n->ctx); EG(ret, err);
ret = fp_init(sqrt2, _n->ctx); EG(ret, err);
ret = nn_one(&one_nn); EG(ret, err);
ret = nn_set_word_value(&two_nn, WORD(2)); EG(ret, err);
ret = nn_cmp(&(_n->ctx->p), &two_nn, &cmp); EG(ret, err);
if (cmp == 0) {
ret = fp_copy(sqrt1, _n); EG(ret, err);
ret = fp_copy(sqrt2, _n); EG(ret, err);
ret = 0;
goto err;
}
ret = fp_iszero(_n, &iszero); EG(ret, err);
if (iszero) {
ret = fp_zero(sqrt1); EG(ret, err);
ret = fp_zero(sqrt2); EG(ret, err);
ret = 0;
goto err;
}
if (legendre(_n) != 1) {
ret = -1;
goto err;
}
ret = nn_zero(&s); EG(ret, err);
ret = nn_copy(&q, &(_n->ctx->p)); EG(ret, err);
ret = nn_dec(&q, &q); EG(ret, err);
while (1) {
ret = nn_divrem(&tmp_nn, &i, &q, &two_nn); EG(ret, err);
ret = nn_inc(&s, &s); EG(ret, err);
ret = nn_copy(&q, &tmp_nn); EG(ret, err);
ret = nn_isodd(&q, &isodd); EG(ret, err);
if (isodd) {
break;
}
}
ret = nn_cmp(&s, &one_nn, &cmp); EG(ret, err);
if (cmp == 0) {
ret = nn_inc(&tmp_nn, &(_n->ctx->p)); EG(ret, err);
ret = nn_rshift(&tmp_nn, &tmp_nn, 2); EG(ret, err);
ret = fp_pow(sqrt1, _n, &tmp_nn); EG(ret, err);
ret = fp_neg(sqrt2, sqrt1); EG(ret, err);
ret = 0;
goto err;
}
ret = fp_zero(&z); EG(ret, err);
while (legendre(&z) != -1) {
ret = fp_inc(&z, &z); EG(ret, err);
}
ret = fp_pow(&c, &z, &q); EG(ret, err);
ret = nn_inc(&tmp_nn, &q); EG(ret, err);
ret = nn_rshift(&tmp_nn, &tmp_nn, 1); EG(ret, err);
ret = fp_pow(&r, _n, &tmp_nn); EG(ret, err);
ret = fp_pow(&t, _n, &q); EG(ret, err);
ret = nn_copy(&m, &s); EG(ret, err);
ret = fp_one(&one_fp); EG(ret, err);
while (1) {
ret = fp_cmp(&t, &one_fp, &cmp); EG(ret, err);
if (cmp == 0) {
ret = fp_copy(sqrt1, &r); EG(ret, err);
ret = fp_neg(sqrt2, sqrt1); EG(ret, err);
ret = 0;
goto err;
}
ret = nn_one(&i); EG(ret, err);
ret = fp_copy(&tmp_fp, &t); EG(ret, err);
while (1) {
ret = fp_sqr(&tmp_fp, &tmp_fp); EG(ret, err);
ret = fp_cmp(&tmp_fp, &one_fp, &cmp); EG(ret, err);
if (cmp == 0) {
break;
}
ret = nn_inc(&i, &i); EG(ret, err);
ret = nn_cmp(&i, &m, &cmp); EG(ret, err);
if (cmp == 0) {
ret = -2;
goto err;
}
}
ret = nn_sub(&tmp_nn, &m, &i); EG(ret, err);
ret = nn_dec(&tmp_nn, &tmp_nn); EG(ret, err);
ret = fp_copy(&b, &c); EG(ret, err);
ret = nn_iszero(&tmp_nn, &iszero); EG(ret, err);
while (!iszero) {
ret = fp_sqr(&b, &b); EG(ret, err);
ret = nn_dec(&tmp_nn, &tmp_nn); EG(ret, err);
ret = nn_iszero(&tmp_nn, &iszero); EG(ret, err);
}
ret = fp_mul(&r, &r, &b); EG(ret, err);
ret = fp_sqr(&c, &b); EG(ret, err);
ret = fp_mul(&t, &t, &c); EG(ret, err);
ret = nn_copy(&m, &i); EG(ret, err);
}
err:
nn_uninit(&q);
nn_uninit(&s);
nn_uninit(&tmp_nn);
nn_uninit(&one_nn);
nn_uninit(&two_nn);
nn_uninit(&m);
nn_uninit(&i);
fp_uninit(&z);
fp_uninit(&t);
fp_uninit(&b);
fp_uninit(&r);
fp_uninit(&c);
fp_uninit(&one_fp);
fp_uninit(&tmp_fp);
fp_uninit(&__n);
PTR_NULLIFY(_n);
return ret;
}