#include <libecc/curves/ec_shortw.h>
#include <libecc/curves/prj_pt.h>
#include <libecc/nn/nn_logical.h>
#include <libecc/nn/nn_add.h>
#include <libecc/nn/nn_rand.h>
#include <libecc/fp/fp_add.h>
#include <libecc/fp/fp_mul.h>
#include <libecc/fp/fp_montgomery.h>
#include <libecc/fp/fp_rand.h>
#define PRJ_PT_MAGIC ((word_t)(0xe1cd70babb1d5afeULL))
int prj_pt_check_initialized(prj_pt_src_t in)
{
int ret;
MUST_HAVE(((in != NULL) && (in->magic == PRJ_PT_MAGIC)), ret, err);
ret = ec_shortw_crv_check_initialized(in->crv);
err:
return ret;
}
int prj_pt_init(prj_pt_t in, ec_shortw_crv_src_t curve)
{
int ret;
ret = ec_shortw_crv_check_initialized(curve); EG(ret, err);
MUST_HAVE((in != NULL), ret, err);
ret = fp_init(&(in->X), curve->a.ctx); EG(ret, err);
ret = fp_init(&(in->Y), curve->a.ctx); EG(ret, err);
ret = fp_init(&(in->Z), curve->a.ctx); EG(ret, err);
in->crv = curve;
in->magic = PRJ_PT_MAGIC;
err:
return ret;
}
int prj_pt_init_from_coords(prj_pt_t in,
ec_shortw_crv_src_t curve,
fp_src_t xcoord, fp_src_t ycoord, fp_src_t zcoord)
{
int ret;
ret = prj_pt_init(in, curve); EG(ret, err);
ret = fp_copy(&(in->X), xcoord); EG(ret, err);
ret = fp_copy(&(in->Y), ycoord); EG(ret, err);
ret = fp_copy(&(in->Z), zcoord);
err:
return ret;
}
void prj_pt_uninit(prj_pt_t in)
{
if((in != NULL) && (in->magic == PRJ_PT_MAGIC) && (in->crv != NULL)){
in->crv = NULL;
in->magic = WORD(0);
fp_uninit(&(in->X));
fp_uninit(&(in->Y));
fp_uninit(&(in->Z));
}
return;
}
int prj_pt_iszero(prj_pt_src_t in, int *iszero)
{
int ret;
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = fp_iszero(&(in->Z), iszero);
err:
return ret;
}
int prj_pt_zero(prj_pt_t out)
{
int ret;
ret = prj_pt_check_initialized(out); EG(ret, err);
ret = fp_zero(&(out->X)); EG(ret, err);
ret = fp_one(&(out->Y)); EG(ret, err);
ret = fp_zero(&(out->Z));
err:
return ret;
}
int prj_pt_is_on_curve(prj_pt_src_t in, int *on_curve)
{
int ret, cmp;
fp X, Y, Z;
X.magic = Y.magic = Z.magic = WORD(0);
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = ec_shortw_crv_check_initialized(in->crv); EG(ret, err);
MUST_HAVE((on_curve != NULL), ret, err);
ret = fp_init(&X, in->X.ctx); EG(ret, err);
ret = fp_init(&Y, in->X.ctx); EG(ret, err);
ret = fp_init(&Z, in->X.ctx); EG(ret, err);
ret = fp_sqr(&X, &(in->X)); EG(ret, err);
ret = fp_mul(&X, &X, &(in->X)); EG(ret, err);
ret = fp_mul(&Z, &(in->X), &(in->crv->a)); EG(ret, err);
ret = fp_mul(&Y, &(in->crv->b), &(in->Z)); EG(ret, err);
ret = fp_add(&Z, &Z, &Y); EG(ret, err);
ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err);
ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err);
ret = fp_add(&X, &X, &Z); EG(ret, err);
ret = fp_sqr(&Y, &(in->Y)); EG(ret, err);
ret = fp_mul(&Y, &Y, &(in->Z)); EG(ret, err);
ret = fp_cmp(&X, &Y, &cmp); EG(ret, err);
(*on_curve) = (!cmp);
err:
fp_uninit(&X);
fp_uninit(&Y);
fp_uninit(&Z);
return ret;
}
int prj_pt_copy(prj_pt_t out, prj_pt_src_t in)
{
int ret;
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_copy(&(out->X), &(in->X)); EG(ret, err);
ret = fp_copy(&(out->Y), &(in->Y)); EG(ret, err);
ret = fp_copy(&(out->Z), &(in->Z));
err:
return ret;
}
int prj_pt_to_aff(aff_pt_t out, prj_pt_src_t in)
{
int ret, iszero;
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = prj_pt_iszero(in, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = aff_pt_init(out, in->crv); EG(ret, err);
ret = fp_inv(&(out->x), &(in->Z)); EG(ret, err);
ret = fp_mul(&(out->y), &(in->Y), &(out->x)); EG(ret, err);
ret = fp_mul(&(out->x), &(in->X), &(out->x));
err:
return ret;
}
int prj_pt_unique(prj_pt_t out, prj_pt_src_t in)
{
int ret, iszero;
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = prj_pt_iszero(in, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
if(out == in){
fp tmp;
tmp.magic = WORD(0);
ret = fp_init(&tmp, (in->Z).ctx); EG(ret, err);
ret = fp_inv(&tmp, &(in->Z)); EG(ret, err1);
ret = fp_mul(&(out->Y), &(in->Y), &tmp); EG(ret, err1);
ret = fp_mul(&(out->X), &(in->X), &tmp); EG(ret, err1);
ret = fp_one(&(out->Z)); EG(ret, err1);
err1:
fp_uninit(&tmp); EG(ret, err);
}
else{
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_inv(&(out->X), &(in->Z)); EG(ret, err);
ret = fp_mul(&(out->Y), &(in->Y), &(out->X)); EG(ret, err);
ret = fp_mul(&(out->X), &(in->X), &(out->X)); EG(ret, err);
ret = fp_one(&(out->Z)); EG(ret, err);
}
err:
return ret;
}
int ec_shortw_aff_to_prj(prj_pt_t out, aff_pt_src_t in)
{
int ret, on_curve;
ret = aff_pt_check_initialized(in); EG(ret, err);
ret = aff_pt_is_on_curve(in, &on_curve); EG(ret, err);
MUST_HAVE(on_curve, ret, err);
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_copy(&(out->X), &(in->x)); EG(ret, err);
ret = fp_copy(&(out->Y), &(in->y)); EG(ret, err);
ret = nn_one(&(out->Z).fp_val);
err:
return ret;
}
int prj_pt_cmp(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp)
{
fp X1, X2, Y1, Y2;
int ret, x_cmp, y_cmp;
X1.magic = X2.magic = Y1.magic = Y2.magic = WORD(0);
MUST_HAVE((cmp != NULL), ret, err);
ret = prj_pt_check_initialized(in1); EG(ret, err);
ret = prj_pt_check_initialized(in2); EG(ret, err);
MUST_HAVE((in1->crv == in2->crv), ret, err);
ret = fp_init(&X1, (in1->X).ctx); EG(ret, err);
ret = fp_init(&X2, (in2->X).ctx); EG(ret, err);
ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err);
ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err);
ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);
ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);
ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);
ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);
ret = fp_cmp(&X1, &X2, &x_cmp); EG(ret, err);
ret = fp_cmp(&Y1, &Y2, &y_cmp);
if (!ret) {
(*cmp) = (x_cmp | y_cmp);
}
err:
fp_uninit(&Y2);
fp_uninit(&Y1);
fp_uninit(&X2);
fp_uninit(&X1);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_eq_or_opp_X(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp)
{
int ret;
fp X1, X2;
X1.magic = X2.magic = WORD(0);
ret = fp_init(&X1, (in1->X).ctx); EG(ret, err);
ret = fp_init(&X2, (in2->X).ctx); EG(ret, err);
ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);
ret = fp_cmp(&X1, &X2, cmp);
err:
fp_uninit(&X1);
fp_uninit(&X2);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_eq_or_opp_Y(prj_pt_src_t in1, prj_pt_src_t in2, int *eq_or_opp)
{
int ret;
fp Y1, Y2;
Y1.magic = Y2.magic = WORD(0);
ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err);
ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err);
ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);
ret = fp_eq_or_opp(&Y1, &Y2, eq_or_opp);
err:
fp_uninit(&Y1);
fp_uninit(&Y2);
return ret;
}
int prj_pt_eq_or_opp(prj_pt_src_t in1, prj_pt_src_t in2, int *eq_or_opp)
{
int ret, cmp, _eq_or_opp;
ret = prj_pt_check_initialized(in1); EG(ret, err);
ret = prj_pt_check_initialized(in2); EG(ret, err);
MUST_HAVE((in1->crv == in2->crv), ret, err);
MUST_HAVE((eq_or_opp != NULL), ret, err);
ret = _prj_pt_eq_or_opp_X(in1, in2, &cmp); EG(ret, err);
ret = _prj_pt_eq_or_opp_Y(in1, in2, &_eq_or_opp);
if (!ret) {
(*eq_or_opp) = ((cmp == 0) & _eq_or_opp);
}
err:
return ret;
}
int prj_pt_neg(prj_pt_t out, prj_pt_src_t in)
{
int ret;
ret = prj_pt_check_initialized(in); EG(ret, err);
if (out != in) {
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = prj_pt_copy(out, in); EG(ret, err);
}
ret = fp_neg(&(out->Y), &(out->Y));
err:
return ret;
}
int prj_pt_import_from_buf(prj_pt_t pt,
const u8 *pt_buf,
u16 pt_buf_len, ec_shortw_crv_src_t crv)
{
int on_curve, ret;
fp_ctx_src_t ctx;
u16 coord_len;
ret = ec_shortw_crv_check_initialized(crv); EG(ret, err);
MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);
ctx = crv->a.ctx;
coord_len = (u16)BYTECEIL(ctx->p_bitlen);
MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err);
ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err);
ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);
ret = fp_init_from_buf(&(pt->Z), ctx, pt_buf + (2 * coord_len), coord_len); EG(ret, err);
pt->crv = crv;
pt->magic = PRJ_PT_MAGIC;
ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);
if (!on_curve){
prj_pt_uninit(pt);
ret = -1;
}
err:
PTR_NULLIFY(ctx);
return ret;
}
int prj_pt_import_from_aff_buf(prj_pt_t pt,
const u8 *pt_buf,
u16 pt_buf_len, ec_shortw_crv_src_t crv)
{
int ret, on_curve;
fp_ctx_src_t ctx;
u16 coord_len;
ret = ec_shortw_crv_check_initialized(crv); EG(ret, err);
MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);
ctx = crv->a.ctx;
coord_len = (u16)BYTECEIL(ctx->p_bitlen);
MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);
ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err);
ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);
ret = fp_init(&(pt->Z), ctx); EG(ret, err);
ret = fp_one(&(pt->Z)); EG(ret, err);
pt->crv = crv;
pt->magic = PRJ_PT_MAGIC;
ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);
if (!on_curve){
prj_pt_uninit(pt);
ret = -1;
}
err:
PTR_NULLIFY(ctx);
return ret;
}
int prj_pt_export_to_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len)
{
fp_ctx_src_t ctx;
u16 coord_len;
int ret, on_curve;
ret = prj_pt_check_initialized(pt); EG(ret, err);
MUST_HAVE((pt_buf != NULL), ret, err);
ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);
MUST_HAVE((on_curve), ret, err);
ctx = pt->crv->a.ctx;
coord_len = (u16)BYTECEIL(ctx->p_bitlen);
MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err);
ret = fp_export_to_buf(pt_buf, coord_len, &(pt->X)); EG(ret, err);
ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->Y)); EG(ret, err);
ret = fp_export_to_buf(pt_buf + (2 * coord_len), coord_len, &(pt->Z));
err:
PTR_NULLIFY(ctx);
return ret;
}
int prj_pt_export_to_aff_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len)
{
int ret, on_curve;
aff_pt tmp_aff;
tmp_aff.magic = WORD(0);
ret = prj_pt_check_initialized(pt); EG(ret, err);
MUST_HAVE((pt_buf != NULL), ret, err);
ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);
MUST_HAVE((on_curve), ret, err);
ret = prj_pt_to_aff(&tmp_aff, pt); EG(ret, err);
ret = aff_pt_export_to_buf(&tmp_aff, pt_buf, pt_buf_len);
err:
aff_pt_uninit(&tmp_aff);
return ret;
}
#ifdef NO_USE_COMPLETE_FORMULAS
ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_no_cf(prj_pt_t out, prj_pt_src_t in)
{
fp XX, ZZ, w, s, ss, sss, R, RR, B, h;
int ret;
XX.magic = ZZ.magic = w.magic = s.magic = WORD(0);
ss.magic = sss.magic = R.magic = WORD(0);
RR.magic = B.magic = h.magic = WORD(0);
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_init(&XX, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&ZZ, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&w, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&s, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&ss, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&sss, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&R, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&RR, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&B, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&h, out->crv->a.ctx); EG(ret, err);
ret = fp_sqr_monty(&XX, &(in->X)); EG(ret, err);
ret = fp_sqr_monty(&ZZ, &(in->Z)); EG(ret, err);
ret = fp_mul_monty(&w, &(in->crv->a_monty), &ZZ); EG(ret, err);
ret = fp_add_monty(&w, &w, &XX); EG(ret, err);
ret = fp_add_monty(&w, &w, &XX); EG(ret, err);
ret = fp_add_monty(&w, &w, &XX); EG(ret, err);
ret = fp_mul_monty(&s, &(in->Y), &(in->Z)); EG(ret, err);
ret = fp_add_monty(&s, &s, &s); EG(ret, err);
ret = fp_sqr_monty(&ss, &s); EG(ret, err);
ret = fp_mul_monty(&sss, &s, &ss); EG(ret, err);
ret = fp_mul_monty(&R, &(in->Y), &s); EG(ret, err);
ret = fp_sqr_monty(&RR, &R); EG(ret, err);
ret = fp_add_monty(&R, &R, &(in->X)); EG(ret, err);
ret = fp_sqr_monty(&B, &R); EG(ret, err);
ret = fp_sub_monty(&B, &B, &XX); EG(ret, err);
ret = fp_sub_monty(&B, &B, &RR); EG(ret, err);
ret = fp_sqr_monty(&h, &w); EG(ret, err);
ret = fp_sub_monty(&h, &h, &B); EG(ret, err);
ret = fp_sub_monty(&h, &h, &B); EG(ret, err);
ret = fp_mul_monty(&(out->X), &h, &s); EG(ret, err);
ret = fp_sub_monty(&B, &B, &h); EG(ret, err);
ret = fp_mul_monty(&(out->Y), &w, &B); EG(ret, err);
ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err);
ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err);
ret = fp_copy(&(out->Z), &sss);
err:
fp_uninit(&XX);
fp_uninit(&ZZ);
fp_uninit(&w);
fp_uninit(&s);
fp_uninit(&ss);
fp_uninit(&sss);
fp_uninit(&R);
fp_uninit(&RR);
fp_uninit(&B);
fp_uninit(&h);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int ___prj_pt_add_monty_no_cf(prj_pt_t out,
prj_pt_src_t in1,
prj_pt_src_t in2)
{
fp Y1Z2, X1Z2, Z1Z2, u, uu, v, vv, vvv, R, A;
int ret;
Y1Z2.magic = X1Z2.magic = Z1Z2.magic = u.magic = uu.magic = v.magic = WORD(0);
vv.magic = vvv.magic = R.magic = A.magic = WORD(0);
ret = prj_pt_init(out, in1->crv); EG(ret, err);
ret = fp_init(&Y1Z2, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&X1Z2, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&Z1Z2, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&u, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&uu, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&v, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&vv, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&vvv, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&R, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&A, out->crv->a.ctx); EG(ret, err);
ret = fp_mul_monty(&Y1Z2, &(in1->Y), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&X1Z2, &(in1->X), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&Z1Z2, &(in1->Z), &(in2->Z)); EG(ret, err);
ret = fp_mul_monty(&u, &(in2->Y), &(in1->Z)); EG(ret, err);
ret = fp_sub_monty(&u, &u, &Y1Z2); EG(ret, err);
ret = fp_sqr_monty(&uu, &u); EG(ret, err);
ret = fp_mul_monty(&v, &(in2->X), &(in1->Z)); EG(ret, err);
ret = fp_sub_monty(&v, &v, &X1Z2); EG(ret, err);
ret = fp_sqr_monty(&vv, &v); EG(ret, err);
ret = fp_mul_monty(&vvv, &v, &vv); EG(ret, err);
ret = fp_mul_monty(&R, &vv, &X1Z2); EG(ret, err);
ret = fp_mul_monty(&A, &uu, &Z1Z2); EG(ret, err);
ret = fp_sub_monty(&A, &A, &vvv); EG(ret, err);
ret = fp_sub_monty(&A, &A, &R); EG(ret, err);
ret = fp_sub_monty(&A, &A, &R); EG(ret, err);
ret = fp_mul_monty(&(out->X), &v, &A); EG(ret, err);
ret = fp_sub_monty(&R, &R, &A); EG(ret, err);
ret = fp_mul_monty(&(out->Y), &u, &R); EG(ret, err);
ret = fp_mul_monty(&R, &vvv, &Y1Z2); EG(ret, err);
ret = fp_sub_monty(&(out->Y), &(out->Y), &R); EG(ret, err);
ret = fp_mul_monty(&(out->Z), &vvv, &Z1Z2);
err:
fp_uninit(&Y1Z2);
fp_uninit(&X1Z2);
fp_uninit(&Z1Z2);
fp_uninit(&u);
fp_uninit(&uu);
fp_uninit(&v);
fp_uninit(&vv);
fp_uninit(&vvv);
fp_uninit(&R);
fp_uninit(&A);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_add_monty_no_cf(prj_pt_t out, prj_pt_src_t in1, prj_pt_src_t in2)
{
int ret, iszero, eq_or_opp, cmp;
ret = prj_pt_check_initialized(in1); EG(ret, err);
ret = prj_pt_check_initialized(in2); EG(ret, err);
MUST_HAVE((in1->crv == in2->crv), ret, err);
ret = prj_pt_iszero(in1, &iszero); EG(ret, err);
if (iszero) {
ret = prj_pt_init(out, in2->crv); EG(ret, err);
ret = prj_pt_copy(out, in2); EG(ret, err);
} else {
ret = prj_pt_iszero(in2, &iszero); EG(ret, err);
if (iszero) {
ret = prj_pt_init(out, in1->crv); EG(ret, err);
ret = prj_pt_copy(out, in1); EG(ret, err);
} else {
ret = prj_pt_eq_or_opp(in1, in2, &eq_or_opp); EG(ret, err);
if (eq_or_opp) {
ret = prj_pt_cmp(in1, in2, &cmp); EG(ret, err);
if (cmp == 0) {
ret = __prj_pt_dbl_monty_no_cf(out, in1); EG(ret, err);
} else {
ret = prj_pt_init(out, in1->crv); EG(ret, err);
ret = prj_pt_zero(out); EG(ret, err);
}
} else {
ret = ___prj_pt_add_monty_no_cf(out, in1, in2); EG(ret, err);
}
}
}
err:
return ret;
}
#else
ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_cf(prj_pt_t out, prj_pt_src_t in)
{
fp t0, t1, t2, t3;
int ret;
t0.magic = t1.magic = t2.magic = t3.magic = WORD(0);
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err);
ret = fp_mul_monty(&t0, &in->X, &in->X); EG(ret, err);
ret = fp_mul_monty(&t1, &in->Y, &in->Y); EG(ret, err);
ret = fp_mul_monty(&t2, &in->Z, &in->Z); EG(ret, err);
ret = fp_mul_monty(&t3, &in->X, &in->Y); EG(ret, err);
ret = fp_add_monty(&t3, &t3, &t3); EG(ret, err);
ret = fp_mul_monty(&out->Z, &in->X, &in->Z); EG(ret, err);
ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err);
ret = fp_mul_monty(&out->X, &in->crv->a_monty, &out->Z); EG(ret, err);
ret = fp_mul_monty(&out->Y, &in->crv->b3_monty, &t2); EG(ret, err);
ret = fp_add_monty(&out->Y, &out->X, &out->Y); EG(ret, err);
ret = fp_sub_monty(&out->X, &t1, &out->Y); EG(ret, err);
ret = fp_add_monty(&out->Y, &t1, &out->Y); EG(ret, err);
ret = fp_mul_monty(&out->Y, &out->X, &out->Y); EG(ret, err);
ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err);
ret = fp_mul_monty(&out->Z, &in->crv->b3_monty, &out->Z); EG(ret, err);
ret = fp_mul_monty(&t2, &in->crv->a_monty, &t2); EG(ret, err);
ret = fp_sub_monty(&t3, &t0, &t2); EG(ret, err);
ret = fp_mul_monty(&t3, &in->crv->a_monty, &t3); EG(ret, err);
ret = fp_add_monty(&t3, &t3, &out->Z); EG(ret, err);
ret = fp_add_monty(&out->Z, &t0, &t0); EG(ret, err);
ret = fp_add_monty(&t0, &out->Z, &t0); EG(ret, err);
ret = fp_add_monty(&t0, &t0, &t2); EG(ret, err);
ret = fp_mul_monty(&t0, &t0, &t3); EG(ret, err);
ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err);
ret = fp_mul_monty(&t2, &in->Y, &in->Z); EG(ret, err);
ret = fp_add_monty(&t2, &t2, &t2); EG(ret, err);
ret = fp_mul_monty(&t0, &t2, &t3); EG(ret, err);
ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err);
ret = fp_mul_monty(&out->Z, &t2, &t1); EG(ret, err);
ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err);
ret = fp_add_monty(&out->Z, &out->Z, &out->Z);
err:
fp_uninit(&t0);
fp_uninit(&t1);
fp_uninit(&t2);
fp_uninit(&t3);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_add_monty_cf(prj_pt_t out,
prj_pt_src_t in1,
prj_pt_src_t in2)
{
int cmp1, cmp2;
fp t0, t1, t2, t3, t4, t5;
int ret;
t0.magic = t1.magic = t2.magic = WORD(0);
t3.magic = t4.magic = t5.magic = WORD(0);
ret = prj_pt_init(out, in1->crv); EG(ret, err);
ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t4, out->crv->a.ctx); EG(ret, err);
ret = fp_init(&t5, out->crv->a.ctx); EG(ret, err);
ret = fp_mul_monty(&t0, &in1->X, &in2->X); EG(ret, err);
ret = fp_mul_monty(&t1, &in1->Y, &in2->Y); EG(ret, err);
ret = fp_mul_monty(&t2, &in1->Z, &in2->Z); EG(ret, err);
ret = fp_add_monty(&t3, &in1->X, &in1->Y); EG(ret, err);
ret = fp_add_monty(&t4, &in2->X, &in2->Y); EG(ret, err);
ret = fp_mul_monty(&t3, &t3, &t4); EG(ret, err);
ret = fp_add_monty(&t4, &t0, &t1); EG(ret, err);
ret = fp_sub_monty(&t3, &t3, &t4); EG(ret, err);
ret = fp_add_monty(&t4, &in1->X, &in1->Z); EG(ret, err);
ret = fp_add_monty(&t5, &in2->X, &in2->Z); EG(ret, err);
ret = fp_mul_monty(&t4, &t4, &t5); EG(ret, err);
ret = fp_add_monty(&t5, &t0, &t2); EG(ret, err);
ret = fp_sub_monty(&t4, &t4, &t5); EG(ret, err);
ret = fp_add_monty(&t5, &in1->Y, &in1->Z); EG(ret, err);
ret = fp_add_monty(&out->X, &in2->Y, &in2->Z); EG(ret, err);
ret = fp_mul_monty(&t5, &t5, &out->X); EG(ret, err);
ret = fp_add_monty(&out->X, &t1, &t2); EG(ret, err);
ret = fp_sub_monty(&t5, &t5, &out->X); EG(ret, err);
ret = fp_mul_monty(&out->Z, &in1->crv->a_monty, &t4); EG(ret, err);
ret = fp_mul_monty(&out->X, &in1->crv->b3_monty, &t2); EG(ret, err);
ret = fp_add_monty(&out->Z, &out->X, &out->Z); EG(ret, err);
ret = fp_sub_monty(&out->X, &t1, &out->Z); EG(ret, err);
ret = fp_add_monty(&out->Z, &t1, &out->Z); EG(ret, err);
ret = fp_mul_monty(&out->Y, &out->X, &out->Z); EG(ret, err);
ret = fp_add_monty(&t1, &t0, &t0); EG(ret, err);
ret = fp_add_monty(&t1, &t1, &t0); EG(ret, err);
ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err);
ret = fp_mul_monty(&t4, &in1->crv->b3_monty, &t4); EG(ret, err);
ret = fp_add_monty(&t1, &t1, &t2); EG(ret, err);
ret = fp_sub_monty(&t2, &t0, &t2); EG(ret, err);
ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err);
ret = fp_add_monty(&t4, &t4, &t2); EG(ret, err);
ret = fp_mul_monty(&t0, &t1, &t4); EG(ret, err);
ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err);
ret = fp_mul_monty(&t0, &t5, &t4); EG(ret, err);
ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err);
ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err);
ret = fp_mul_monty(&t0, &t3, &t1); EG(ret, err);
ret = fp_mul_monty(&out->Z, &t5, &out->Z); EG(ret, err);
ret = fp_add_monty(&out->Z, &out->Z, &t0);
ret = fp_iszero(&(out->Z), &cmp1); EG(ret, err);
ret = fp_iszero(&(out->Y), &cmp2); EG(ret, err);
MUST_HAVE(!((cmp1) && (cmp2)), ret, err);
err:
fp_uninit(&t0);
fp_uninit(&t1);
fp_uninit(&t2);
fp_uninit(&t3);
fp_uninit(&t4);
fp_uninit(&t5);
return ret;
}
#endif
static int _prj_pt_dbl_monty(prj_pt_t out, prj_pt_src_t in)
{
int ret;
#ifdef NO_USE_COMPLETE_FORMULAS
int iszero;
ret = prj_pt_iszero(in, &iszero); EG(ret, err);
if (iszero) {
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = prj_pt_zero(out);
} else {
ret = __prj_pt_dbl_monty_no_cf(out, in);
}
#else
ret = __prj_pt_dbl_monty_cf(out, in); EG(ret, err);
#endif
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_dbl_monty_aliased(prj_pt_t val)
{
prj_pt out_cpy;
int ret;
out_cpy.magic = WORD(0);
ret = _prj_pt_dbl_monty(&out_cpy, val); EG(ret, err);
ret = prj_pt_copy(val, &out_cpy);
err:
prj_pt_uninit(&out_cpy);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET int prj_pt_dbl(prj_pt_t out, prj_pt_src_t in)
{
int ret;
ret = prj_pt_check_initialized(in); EG(ret, err);
if (out == in) {
ret = _prj_pt_dbl_monty_aliased(out);
} else {
ret = _prj_pt_dbl_monty(out, in);
}
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_add_monty(prj_pt_t out,
prj_pt_src_t in1,
prj_pt_src_t in2)
{
#ifndef NO_USE_COMPLETE_FORMULAS
return __prj_pt_add_monty_cf(out, in1, in2);
#else
return __prj_pt_add_monty_no_cf(out, in1, in2);
#endif
}
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_add_monty_aliased(prj_pt_t out,
prj_pt_src_t in1,
prj_pt_src_t in2)
{
int ret;
prj_pt out_cpy;
out_cpy.magic = WORD(0);
ret = _prj_pt_add_monty(&out_cpy, in1, in2); EG(ret, err);
ret = prj_pt_copy(out, &out_cpy); EG(ret, err);
err:
prj_pt_uninit(&out_cpy);
return ret;
}
int prj_pt_add(prj_pt_t out, prj_pt_src_t in1, prj_pt_src_t in2)
{
int ret;
ret = prj_pt_check_initialized(in1); EG(ret, err);
ret = prj_pt_check_initialized(in2); EG(ret, err);
MUST_HAVE((in1->crv == in2->crv), ret, err);
if ((out == in1) || (out == in2)) {
ret = _prj_pt_add_monty_aliased(out, in1, in2);
} else {
ret = _prj_pt_add_monty(out, in1, in2);
}
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int _blind_projective_point(prj_pt_t out, prj_pt_src_t in)
{
int ret;
MUST_HAVE((in != out), ret, err);
ret = prj_pt_init(out, in->crv); EG(ret, err);
ret = fp_get_random(&(out->Z), in->X.ctx); EG(ret, err);
ret = fp_mul_monty(&(out->X), &(in->X), &(out->Z)); EG(ret, err);
ret = fp_mul_monty(&(out->Y), &(in->Y), &(out->Z)); EG(ret, err);
ret = fp_mul_monty(&(out->Z), &(in->Z), &(out->Z));
err:
return ret;
}
#if defined(USE_SMALL_STACK) && defined(USE_MONTY_LADDER)
#error "Small stack is only compatible with USE_DOUBLE_ADD_ALWAYS while USE_MONTY_LADDER has been explicitly asked!"
#endif
#if defined(USE_SMALL_STACK)
#ifndef USE_DOUBLE_ADD_ALWAYS
#define USE_DOUBLE_ADD_ALWAYS
#endif
#endif
#if !defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_MONTY_LADDER)
#define USE_MONTY_LADDER
#endif
#if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_MONTY_LADDER)
#error "You can either choose USE_DOUBLE_ADD_ALWAYS or USE_MONTY_LADDER, not both!"
#endif
#if defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_SMALL_STACK)
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_dbl_add_always(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
prj_pt T[3];
bitcnt_t mlen;
u8 mbit, rbit;
nn r;
nn m_msb_fixed;
nn_src_t curve_order;
nn curve_order_square;
int ret, ret_ops, cmp;
r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0);
T[0].magic = T[1].magic = T[2].magic = WORD(0);
curve_order = &(in->crv->order);
ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err);
ret = nn_cmp(m, curve_order, &cmp); EG(ret, err);
if (cmp < 0){
bitcnt_t msb_bit_len, order_bitlen;
ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);
ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err);
ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,
&m_msb_fixed, curve_order); EG(ret, err);
} else {
ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err);
if (cmp < 0) {
bitcnt_t msb_bit_len, curve_order_square_bitlen;
ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);
ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err);
ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),
&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err);
} else {
ret = nn_copy(&m_msb_fixed, m); EG(ret, err);
}
}
ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);
MUST_HAVE(mlen != 0, ret, err);
mlen--;
ret_ops = 0;
ret = nn_get_random_len(&r, m_msb_fixed.wlen * WORD_BYTES); EG(ret, err);
ret = nn_getbit(&r, mlen, &rbit); EG(ret, err);
ret = prj_pt_init(&T[0], in->crv); EG(ret, err);
ret = prj_pt_init(&T[1], in->crv); EG(ret, err);
ret = _blind_projective_point(&T[2], in); EG(ret, err);
ret = prj_pt_copy(&T[rbit], &T[2]); EG(ret, err);
while (mlen > 0) {
u8 rbit_next;
--mlen;
ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err);
ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err);
#ifndef NO_USE_COMPLETE_FORMULAS
ret_ops |= prj_pt_add(&T[rbit], &T[rbit], &T[rbit]);
#else
ret_ops |= prj_pt_dbl(&T[rbit], &T[rbit]);
#endif
ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[2]);
ret = nn_copy(&(T[rbit_next].X.fp_val), &(T[mbit ^ rbit].X.fp_val)); EG(ret, err);
ret = nn_copy(&(T[rbit_next].Y.fp_val), &(T[mbit ^ rbit].Y.fp_val)); EG(ret, err);
ret = nn_copy(&(T[rbit_next].Z.fp_val), &(T[mbit ^ rbit].Z.fp_val)); EG(ret, err);
rbit = rbit_next;
}
ret = prj_pt_copy(out, &T[rbit]); EG(ret, err);
ret |= ret_ops;
err:
prj_pt_uninit(&T[0]);
prj_pt_uninit(&T[1]);
prj_pt_uninit(&T[2]);
nn_uninit(&r);
nn_uninit(&m_msb_fixed);
nn_uninit(&curve_order_square);
PTR_NULLIFY(curve_order);
return ret;
}
#endif
#if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_SMALL_STACK)
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_dbl_add_always(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
int ret, ret_ops;
ret_ops = 0;
ret = _blind_projective_point(out, in); EG(ret, err);
{
bitcnt_t mlen;
u8 mbit;
nn m_msb_fixed;
nn_src_t curve_order;
int cmp;
m_msb_fixed.magic = WORD(0);
{
nn curve_order_square;
curve_order_square.magic = WORD(0);
curve_order = &(in->crv->order);
ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err1);
ret = nn_cmp(m, curve_order, &cmp); EG(ret, err1);
if (cmp < 0){
bitcnt_t msb_bit_len, order_bitlen;
ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err1);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1);
ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err1);
ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,
&m_msb_fixed, curve_order); EG(ret, err1);
} else {
ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err1);
if (cmp < 0) {
bitcnt_t msb_bit_len, curve_order_square_bitlen;
ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err1);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1);
ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err1);
ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),
&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err1);
} else {
ret = nn_copy(&m_msb_fixed, m); EG(ret, err1);
}
}
err1:
nn_uninit(&curve_order_square); EG(ret, err);
}
ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);
MUST_HAVE((mlen != 0), ret, err);
mlen--;
{
prj_pt dbl;
dbl.magic = WORD(0);
ret = prj_pt_init(&dbl, in->crv); EG(ret, err2);
while (mlen > 0) {
--mlen;
ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err2);
#ifndef NO_USE_COMPLETE_FORMULAS
ret_ops |= prj_pt_add(&dbl, out, out);
#else
ret_ops |= prj_pt_dbl(&dbl, out);
#endif
ret_ops |= prj_pt_add(out, &dbl, in);
ret = nn_cnd_swap(!mbit, &(out->X.fp_val), &(dbl.X.fp_val)); EG(ret, err2);
ret = nn_cnd_swap(!mbit, &(out->Y.fp_val), &(dbl.Y.fp_val)); EG(ret, err2);
ret = nn_cnd_swap(!mbit, &(out->Z.fp_val), &(dbl.Z.fp_val)); EG(ret, err2);
}
err2:
prj_pt_uninit(&dbl); EG(ret, err);
}
err:
nn_uninit(&m_msb_fixed);
PTR_NULLIFY(curve_order);
}
ret |= ret_ops;
return ret;
}
#endif
#ifdef USE_MONTY_LADDER
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_ladder(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
prj_pt T[3];
bitcnt_t mlen;
u8 mbit, rbit;
nn r;
nn m_msb_fixed;
nn_src_t curve_order;
nn curve_order_square;
int ret, ret_ops, cmp;
r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0);
T[0].magic = T[1].magic = T[2].magic = WORD(0);
curve_order = &(in->crv->order);
ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err);
ret = nn_cmp(m, curve_order, &cmp); EG(ret, err);
if (cmp < 0) {
bitcnt_t msb_bit_len, order_bitlen;
ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);
ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err);
ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,
&m_msb_fixed, curve_order); EG(ret, err);
} else {
ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err);
if (cmp < 0) {
bitcnt_t msb_bit_len, curve_order_square_bitlen;
ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err);
ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);
ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err);
ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),
&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err);
} else {
ret = nn_copy(&m_msb_fixed, m); EG(ret, err);
}
}
ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);
MUST_HAVE((mlen != 0), ret, err);
mlen--;
ret_ops = 0;
ret = nn_get_random_len(&r, (u16)(m_msb_fixed.wlen * WORD_BYTES)); EG(ret, err);
ret = nn_getbit(&r, mlen, &rbit); EG(ret, err);
ret = prj_pt_init(&T[0], in->crv); EG(ret, err);
ret = prj_pt_init(&T[1], in->crv); EG(ret, err);
ret = prj_pt_init(&T[2], in->crv); EG(ret, err);
ret = _blind_projective_point(&T[rbit], in); EG(ret, err);
#ifndef NO_USE_COMPLETE_FORMULAS
ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[rbit]);
#else
ret_ops |= prj_pt_dbl(&T[1-rbit], &T[rbit]);
#endif
while (mlen > 0) {
u8 rbit_next;
--mlen;
ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err);
ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err);
#ifndef NO_USE_COMPLETE_FORMULAS
ret_ops |= prj_pt_add(&T[2], &T[mbit ^ rbit], &T[mbit ^ rbit]);
#else
ret_ops |= prj_pt_dbl(&T[2], &T[mbit ^ rbit]);
#endif
ret_ops |= prj_pt_add(&T[1], &T[0], &T[1]);
ret = nn_copy(&(T[0].X.fp_val), &(T[2-(mbit ^ rbit_next)].X.fp_val)); EG(ret, err);
ret = nn_copy(&(T[0].Y.fp_val), &(T[2-(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err);
ret = nn_copy(&(T[0].Z.fp_val), &(T[2-(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err);
ret = nn_copy(&(T[1].X.fp_val), &(T[1+(mbit ^ rbit_next)].X.fp_val)); EG(ret, err);
ret = nn_copy(&(T[1].Y.fp_val), &(T[1+(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err);
ret = nn_copy(&(T[1].Z.fp_val), &(T[1+(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err);
rbit = rbit_next;
}
ret = prj_pt_copy(out, &T[rbit]); EG(ret, err);
ret |= ret_ops;
err:
prj_pt_uninit(&T[0]);
prj_pt_uninit(&T[1]);
prj_pt_uninit(&T[2]);
nn_uninit(&r);
nn_uninit(&m_msb_fixed);
nn_uninit(&curve_order_square);
PTR_NULLIFY(curve_order);
return ret;
}
#endif
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty(prj_pt_t out, nn_src_t m, prj_pt_src_t in){
#if defined(USE_DOUBLE_ADD_ALWAYS)
return _prj_pt_mul_ltr_monty_dbl_add_always(out, m, in);
#elif defined(USE_MONTY_LADDER)
return _prj_pt_mul_ltr_monty_ladder(out, m, in);
#else
#error "Error: neither Double and Add Always nor Montgomery Ladder has been selected!"
#endif
}
ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_aliased(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
prj_pt out_cpy;
int ret;
out_cpy.magic = WORD(0);
ret = prj_pt_init(&out_cpy, in->crv); EG(ret, err);
ret = _prj_pt_mul_ltr_monty(&out_cpy, m, in); EG(ret, err);
ret = prj_pt_copy(out, &out_cpy);
err:
prj_pt_uninit(&out_cpy);
return ret;
}
int prj_pt_mul(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
int ret, on_curve;
ret = prj_pt_check_initialized(in); EG(ret, err);
ret = nn_check_initialized(m); EG(ret, err);
MUST_HAVE((!prj_pt_is_on_curve(in, &on_curve)) && on_curve, ret, err);
if (out == in) {
ret = _prj_pt_mul_ltr_monty_aliased(out, m, in); EG(ret, err);
} else {
ret = _prj_pt_mul_ltr_monty(out, m, in); EG(ret, err);
}
MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err);
err:
return ret;
}
int prj_pt_mul_blind(prj_pt_t out, nn_src_t m, prj_pt_src_t in)
{
nn b;
nn_src_t q;
int ret;
b.magic = WORD(0);
ret = prj_pt_check_initialized(in); EG(ret, err);
q = &(in->crv->order);
ret = nn_init(&b, 0); EG(ret, err);
ret = nn_get_random_mod(&b, q); EG(ret, err);
ret = nn_mul(&b, &b, q); EG(ret, err);
ret = nn_add(&b, &b, m); EG(ret, err);
ret = prj_pt_mul(out, &b, in);
err:
nn_uninit(&b);
PTR_NULLIFY(q);
return ret;
}
static int __prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in)
{
u8 expbit;
bitcnt_t explen;
int ret, iszero, on_curve;
ret = prj_pt_check_initialized(public_in); EG(ret, err);
ret = nn_check_initialized(scalar); EG(ret, err);
MUST_HAVE((out != public_in), ret, err);
MUST_HAVE((!prj_pt_is_on_curve(public_in, &on_curve)) && on_curve, ret, err);
ret = nn_iszero(scalar, &iszero); EG(ret, err);
if(iszero){
ret = prj_pt_zero(out); EG(ret, err);
goto err;
}
ret = nn_bitlen(scalar, &explen); EG(ret, err);
MUST_HAVE((explen > 0), ret, err);
explen = (bitcnt_t)(explen - 1);
ret = prj_pt_copy(out, public_in); EG(ret, err);
while (explen > 0) {
explen = (bitcnt_t)(explen - 1);
ret = nn_getbit(scalar, explen, &expbit); EG(ret, err);
ret = prj_pt_dbl(out, out); EG(ret, err);
if(expbit){
ret = prj_pt_add(out, out, public_in); EG(ret, err);
}
}
MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err);
err:
VAR_ZEROIFY(expbit);
VAR_ZEROIFY(explen);
return ret;
}
int _prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in)
{
int ret;
if(out == public_in){
prj_pt A;
A.magic = WORD(0);
ret = prj_pt_copy(&A, public_in); EG(ret, err1);
ret = __prj_pt_unprotected_mult(out, scalar, &A);
err1:
prj_pt_uninit(&A);
goto err;
}
else{
ret = __prj_pt_unprotected_mult(out, scalar, public_in);
}
err:
return ret;
}
int check_prj_pt_order(prj_pt_src_t in_shortw, nn_src_t in_isorder, prj_pt_sensitivity s, int *check)
{
int ret, iszero;
prj_pt res;
res.magic = WORD(0);
ret = prj_pt_check_initialized(in_shortw); EG(ret, err);
ret = nn_check_initialized(in_isorder); EG(ret, err);
MUST_HAVE((check != NULL), ret, err);
if(s == PUBLIC_PT){
ret = _prj_pt_unprotected_mult(&res, in_isorder, in_shortw); EG(ret, err);
}
else{
ret = prj_pt_mul_blind(&res, in_isorder, in_shortw); EG(ret, err);
}
ret = prj_pt_iszero(&res, &iszero); EG(ret, err);
(*check) = iszero;
err:
prj_pt_uninit(&res);
return ret;
}
int aff_pt_edwards_to_prj_pt_shortw(aff_pt_edwards_src_t in_edwards,
ec_shortw_crv_src_t shortw_crv,
prj_pt_t out_shortw,
fp_src_t alpha_edwards)
{
int ret, iszero, cmp;
aff_pt out_shortw_aff;
fp one;
out_shortw_aff.magic = one.magic = WORD(0);
ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err);
ret = curve_edwards_shortw_check(in_edwards->crv, shortw_crv, alpha_edwards); EG(ret, err);
ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err);
ret = fp_init(&one, in_edwards->x.ctx); EG(ret, err);
ret = fp_one(&one); EG(ret, err);
ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);
ret = fp_cmp(&(in_edwards->y), &one, &cmp); EG(ret, err);
if(iszero && (cmp == 0)){
ret = prj_pt_zero(out_shortw); EG(ret, err);
ret = 0;
goto err;
}
ret = aff_pt_edwards_to_shortw(in_edwards, shortw_crv, &out_shortw_aff, alpha_edwards); EG(ret, err);
ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff);
err:
fp_uninit(&one);
aff_pt_uninit(&out_shortw_aff);
return ret;
}
int prj_pt_shortw_to_aff_pt_edwards(prj_pt_src_t in_shortw,
ec_edwards_crv_src_t edwards_crv,
aff_pt_edwards_t out_edwards,
fp_src_t alpha_edwards)
{
int ret, iszero;
aff_pt in_shortw_aff;
in_shortw_aff.magic = WORD(0);
ret = prj_pt_check_initialized(in_shortw); EG(ret, err);
ret = curve_edwards_shortw_check(edwards_crv, in_shortw->crv, alpha_edwards); EG(ret, err);
ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err);
ret = prj_pt_iszero(in_shortw, &iszero); EG(ret, err);
if(iszero){
fp zero, one;
zero.magic = one.magic = WORD(0);
ret = fp_init(&zero, in_shortw->X.ctx); EG(ret, err1);
ret = fp_init(&one, in_shortw->X.ctx); EG(ret, err1);
ret = fp_zero(&zero); EG(ret, err1);
ret = fp_one(&one); EG(ret, err1);
ret = aff_pt_edwards_init_from_coords(out_edwards, edwards_crv, &zero, &one);
err1:
fp_uninit(&zero);
fp_uninit(&one);
goto err;
}
ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err);
ret = aff_pt_shortw_to_edwards(&in_shortw_aff, edwards_crv, out_edwards, alpha_edwards);
err:
aff_pt_uninit(&in_shortw_aff);
return ret;
}
int aff_pt_montgomery_to_prj_pt_shortw(aff_pt_montgomery_src_t in_montgomery,
ec_shortw_crv_src_t shortw_crv,
prj_pt_t out_shortw)
{
int ret;
aff_pt out_shortw_aff;
out_shortw_aff.magic = WORD(0);
ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err);
ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err);
ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err);
ret = aff_pt_montgomery_to_shortw(in_montgomery, shortw_crv, &out_shortw_aff); EG(ret, err);
ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff);
err:
aff_pt_uninit(&out_shortw_aff);
return ret;
}
int prj_pt_shortw_to_aff_pt_montgomery(prj_pt_src_t in_shortw, ec_montgomery_crv_src_t montgomery_crv, aff_pt_montgomery_t out_montgomery)
{
int ret;
aff_pt in_shortw_aff;
in_shortw_aff.magic = WORD(0);
ret = prj_pt_check_initialized(in_shortw); EG(ret, err);
ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err);
ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err);
ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err);
ret = aff_pt_shortw_to_montgomery(&in_shortw_aff, montgomery_crv, out_montgomery);
err:
aff_pt_uninit(&in_shortw_aff);
return ret;
}