Path: blob/main/crypto/libecc/src/curves/aff_pt_edwards.c
34878 views
/*1* Copyright (C) 2021 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6*7* This software is licensed under a dual BSD and GPL v2 license.8* See LICENSE file at the root folder of the project.9*/10#include <libecc/curves/aff_pt.h>1112/* NOTE: Edwards here implies Twisted Edwards curves13* (these in fact include/extend basic form Edwards curves).14*/1516#define AFF_PT_EDWARDS_MAGIC ((word_t)(0x8390a9bc43d9ffabULL))1718/* Verify that an affine point has already been initialized19*20* Returns 0 on success, -1 on error.21*/22int aff_pt_edwards_check_initialized(aff_pt_edwards_src_t in)23{24int ret;2526MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC)), ret, err);27ret = ec_edwards_crv_check_initialized(in->crv);2829err:30return ret;31}3233/*34* Initialize pointed aff_pt_edwards structure to make it usable by library35* function on given curve.36*37* Returns 0 on success, -1 on error.38*/39int aff_pt_edwards_init(aff_pt_edwards_t in, ec_edwards_crv_src_t curve)40{41int ret;4243MUST_HAVE((in != NULL), ret, err);44ret = ec_edwards_crv_check_initialized(curve); EG(ret, err);4546ret = fp_init(&(in->x), curve->a.ctx); EG(ret, err);47ret = fp_init(&(in->y), curve->a.ctx); EG(ret, err);4849in->crv = curve;50in->magic = AFF_PT_EDWARDS_MAGIC;5152err:53return ret;54}5556/*57* Initialize pointed aff_pt_edwards structure to make it usable by library58* function on given curve with explicit coordinates.59*60* Returns 0 on success, -1 on error.61*/62int aff_pt_edwards_init_from_coords(aff_pt_edwards_t in,63ec_edwards_crv_src_t curve,64fp_src_t xcoord, fp_src_t ycoord)65{66int ret;6768ret = aff_pt_edwards_init(in, curve); EG(ret, err);69ret = fp_copy(&(in->x), xcoord); EG(ret, err);70ret = fp_copy(&(in->y), ycoord);7172err:73return ret;74}7576/*77* Uninitialize pointed affine point to prevent further use (magic field78* in the structure is zeroized) and zeroize associated storage space.79* Note that the curve context pointed to by the point element (passed80* during init) is left untouched.81*82*/83void aff_pt_edwards_uninit(aff_pt_edwards_t in)84{85if ((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC) && (in->crv != NULL)) {86fp_uninit(&(in->x));87fp_uninit(&(in->y));8889in->crv = NULL;90in->magic = WORD(0);91}9293return;94}9596/*97* 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it98* verifies curve equation a*x^2 + y^2 = 1 + d*x^2*y^2. It is set to 0 otherwise.99* 'on_curve' is not meaningful on error.100*101* Returns 0 on success, -1 on error.102*/103int is_on_edwards_curve(fp_src_t x, fp_src_t y,104ec_edwards_crv_src_t curve,105int *on_curve)106{107fp x2, y2, tmp1, tmp2;108int ret, cmp;109x2.magic = y2.magic = tmp1.magic = tmp2.magic = WORD(0);110111MUST_HAVE((on_curve != NULL), ret, err);112ret = ec_edwards_crv_check_initialized(curve); EG(ret, err);113114ret = fp_check_initialized(x); EG(ret, err);115ret = fp_check_initialized(y); EG(ret, err);116117MUST_HAVE((x->ctx == y->ctx), ret, err);118MUST_HAVE((x->ctx == curve->a.ctx), ret, err);119120ret = fp_init(&x2, x->ctx); EG(ret, err);121ret = fp_sqr(&x2, x); EG(ret, err);122ret = fp_init(&y2, x->ctx); EG(ret, err);123ret = fp_sqr(&y2, y); EG(ret, err);124125ret = fp_init(&tmp1, x->ctx); EG(ret, err);126ret = fp_init(&tmp2, x->ctx); EG(ret, err);127128ret = fp_mul(&tmp1, &x2, &y2); EG(ret, err);129ret = fp_mul(&tmp1, &tmp1, &(curve->d)); EG(ret, err);130ret = fp_inc(&tmp1, &tmp1); EG(ret, err);131132ret = fp_mul(&tmp2, &x2, &(curve->a)); EG(ret, err);133ret = fp_add(&tmp2, &tmp2, &y2); EG(ret, err);134135ret = fp_cmp(&tmp1, &tmp2, &cmp);136137if (!ret) {138(*on_curve) = (!cmp);139}140141err:142fp_uninit(&x2);143fp_uninit(&y2);144fp_uninit(&tmp1);145fp_uninit(&tmp2);146147return ret;148}149150/*151* Checks if affine coordinates point is on an Edwards curve. 'on_curve' is set152* to 1 if yes, 0 if no. 'on_curve' is not meaningful in case of error.153*154* Returns 0 on success, -1 on error.155*/156int aff_pt_edwards_is_on_curve(aff_pt_edwards_src_t pt, int *on_curve)157{158int ret;159160ret = aff_pt_edwards_check_initialized(pt); EG(ret, err);161162ret = is_on_edwards_curve(&(pt->x), &(pt->y), pt->crv, on_curve);163164err:165return ret;166}167168/*169* Copy an Edwards affine point in an output. The output is initialized properly.170*171* Returns 0 on success, -1 on error.172*/173int ec_edwards_aff_copy(aff_pt_edwards_t out, aff_pt_edwards_src_t in)174{175int ret;176177ret = aff_pt_edwards_check_initialized(in); EG(ret, err);178ret = aff_pt_edwards_init(out, in->crv); EG(ret, err);179180ret = fp_copy(&(out->x), &(in->x)); EG(ret, err);181ret = fp_copy(&(out->y), &(in->y));182183err:184return ret;185}186187/*188* Compares two given affine points on an Edwards curve, it returns 0 in input189* 'cmp' if they correspond or not 0 if not. 'cmp' is not meaningful on error.190*191* Returns 0 on success, -1 on error.192*/193int ec_edwards_aff_cmp(aff_pt_edwards_src_t in1, aff_pt_edwards_src_t in2,194int *cmp)195{196int ret, cmp1, cmp2;197198MUST_HAVE((cmp != NULL), ret, err);199ret = aff_pt_edwards_check_initialized(in1); EG(ret, err);200ret = aff_pt_edwards_check_initialized(in2); EG(ret, err);201202MUST_HAVE((in1->crv == in2->crv), ret, err);203204ret = fp_cmp(&(in1->x), &(in2->x), &cmp1); EG(ret, err);205ret = fp_cmp(&(in1->y), &(in2->y), &cmp2);206207if (!ret) {208(*cmp) = (cmp1 | cmp2);209}210211err:212return ret;213}214215/*216* Import an Edwards affine point from a buffer with the following layout; the 2217* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len218* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each219* coordinate is encoded in big endian. Size of buffer must exactly match220* 2 * p_len.221*222* Returns 0 on success, -1 on error.223*/224int aff_pt_edwards_import_from_buf(aff_pt_edwards_t pt,225const u8 *pt_buf,226u16 pt_buf_len, ec_edwards_crv_src_t crv)227{228fp_ctx_src_t ctx;229u16 coord_len;230int ret, on_curve;231232ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);233MUST_HAVE(((pt_buf != NULL) && (pt != NULL)), ret, err);234235ctx = crv->a.ctx;236coord_len = (u16)BYTECEIL(ctx->p_bitlen);237238MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);239240ret = fp_init_from_buf(&(pt->x), ctx, pt_buf, coord_len); EG(ret, err);241ret = fp_init_from_buf(&(pt->y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);242243/* Set the curve */244pt->crv = crv;245246/* Mark the point as initialized */247pt->magic = AFF_PT_EDWARDS_MAGIC;248249/* Check that the point is indeed on the provided curve, uninitialize it250* if this is not the case.251*/252ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err);253if (!on_curve) {254aff_pt_edwards_uninit(pt);255ret = -1;256}257258err:259return ret;260}261262263/* Export an Edwards affine point to a buffer with the following layout; the 2264* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len265* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each266* coordinate is encoded in big endian. Size of buffer must exactly match267* 2 * p_len.268*269* Returns 0 on success, -1 on error.270*/271int aff_pt_edwards_export_to_buf(aff_pt_edwards_src_t pt,272u8 *pt_buf, u32 pt_buf_len)273{274fp_ctx_src_t ctx;275u16 coord_len;276int ret, on_curve;277278ret = aff_pt_edwards_check_initialized(pt); EG(ret, err);279MUST_HAVE((pt_buf != NULL), ret, err);280281/* The point to be exported must be on the curve */282ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err);283MUST_HAVE(on_curve, ret, err);284285ctx = pt->crv->a.ctx;286coord_len = (u16)BYTECEIL(ctx->p_bitlen);287288MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);289290/* Export the three coordinates */291ret = fp_export_to_buf(pt_buf, coord_len, &(pt->x)); EG(ret, err);292ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->y));293294err:295return ret;296}297298/*299* Mapping curves from twisted Edwards to Montgomery.300*301* E{a, d} is mapped to M{A, B} using the formula:302* A = 2(a+d)/(a-d)303* B = 4/((a-d) * alpha^2)304*305* Returns 0 on success, -1 on error.306*/307int curve_edwards_to_montgomery(ec_edwards_crv_src_t edwards_crv,308ec_montgomery_crv_t montgomery_crv,309fp_src_t alpha_edwards)310{311fp tmp1, tmp2, A, B;312int ret;313tmp1.magic = tmp2.magic = A.magic = B.magic = WORD(0);314315ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err);316ret = fp_check_initialized(alpha_edwards); EG(ret, err);317MUST_HAVE((edwards_crv->a.ctx == alpha_edwards->ctx), ret, err);318319ret = fp_init(&tmp1, edwards_crv->a.ctx); EG(ret, err);320ret = fp_init(&tmp2, edwards_crv->a.ctx); EG(ret, err);321ret = fp_init(&A, edwards_crv->a.ctx); EG(ret, err);322ret = fp_init(&B, edwards_crv->a.ctx); EG(ret, err);323324325/* Compute Z = (alpha ^ 2) et T = 2 / ((a-d) * Z)326* and then:327* A = 2(a+d)/(a-d) = Z * (a + d) * T328* B = 4/((a-d) * alpha^2) = 2 * T329*/330ret = fp_sqr(&tmp1, alpha_edwards); EG(ret, err);331ret = fp_sub(&tmp2, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err);332ret = fp_mul(&tmp2, &tmp2, &tmp1); EG(ret, err);333ret = fp_inv(&tmp2, &tmp2); EG(ret, err);334ret = fp_set_word_value(&B, WORD(2)); EG(ret, err);335ret = fp_mul(&tmp2, &tmp2, &B); EG(ret, err);336337ret = fp_add(&A, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err);338ret = fp_mul(&A, &A, &tmp1); EG(ret, err);339ret = fp_mul(&A, &A, &tmp2); EG(ret, err);340ret = fp_mul(&B, &B, &tmp2); EG(ret, err);341342/* Initialize our Montgomery curve */343ret = ec_montgomery_crv_init(montgomery_crv, &A, &B, &(edwards_crv->order));344345err:346fp_uninit(&tmp1);347fp_uninit(&tmp2);348fp_uninit(&A);349fp_uninit(&B);350351return ret;352}353354/*355* Checks that an Edwards curve and Montgomery curve are compatible.356*357* Returns 0 on success, -1 on error.358*/359int curve_edwards_montgomery_check(ec_edwards_crv_src_t e_crv,360ec_montgomery_crv_src_t m_crv,361fp_src_t alpha_edwards)362{363int ret, cmp;364ec_montgomery_crv check;365check.magic = WORD(0);366367ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err);368ret = curve_edwards_to_montgomery(e_crv, &check, alpha_edwards); EG(ret, err);369370/* Check elements */371MUST_HAVE((!fp_cmp(&(check.A), &(m_crv->A), &cmp)) && (!cmp), ret, err);372MUST_HAVE((!fp_cmp(&(check.B), &(m_crv->B), &cmp)) && (!cmp), ret, err);373MUST_HAVE((!nn_cmp(&(check.order), &(m_crv->order), &cmp)) && (!cmp), ret, err);374375err:376ec_montgomery_crv_uninit(&check);377378return ret;379}380381/*382* Mapping curves from Montgomery to twisted Edwards.383*384* M{A, B} is mapped to E{a, d} using the formula:385* a = (A+2)/(B * alpha^2)386* d = (A-2)/(B * alpha^2)387*388* Or the inverse (switch a and d roles).389*390* Returns 0 on success, -1 on error.391*/392int curve_montgomery_to_edwards(ec_montgomery_crv_src_t m_crv,393ec_edwards_crv_t e_crv,394fp_src_t alpha_edwards)395{396int ret, cmp;397fp tmp, tmp2, a, d;398tmp.magic = tmp2.magic = a.magic = d.magic = WORD(0);399400ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err);401ret = fp_check_initialized(alpha_edwards); EG(ret, err);402MUST_HAVE((m_crv->A.ctx == alpha_edwards->ctx), ret, err);403404ret = fp_init(&tmp, m_crv->A.ctx); EG(ret, err);405ret = fp_init(&tmp2, m_crv->A.ctx); EG(ret, err);406ret = fp_init(&a, m_crv->A.ctx); EG(ret, err);407ret = fp_init(&d, m_crv->A.ctx); EG(ret, err);408409ret = fp_set_word_value(&tmp, WORD(2)); EG(ret, err);410ret = fp_mul(&tmp2, &(m_crv->B), alpha_edwards); EG(ret, err);411ret = fp_mul(&tmp2, &tmp2, alpha_edwards); EG(ret, err);412ret = fp_inv(&tmp2, &tmp2); EG(ret, err);413414/* a = (A+2)/(B * alpha^2) */415ret = fp_add(&a, &(m_crv->A), &tmp); EG(ret, err);416ret = fp_mul(&a, &a, &tmp2); EG(ret, err);417418/* d = (A-2)/(B * alpha^2) */419ret = fp_sub(&d, &(m_crv->A), &tmp); EG(ret, err);420ret = fp_mul(&d, &d, &tmp2); EG(ret, err);421422/* Initialize our Edwards curve */423/* Check if we have to inverse a and d */424ret = fp_one(&tmp); EG(ret, err);425ret = fp_cmp(&d, &tmp, &cmp); EG(ret, err);426if (cmp == 0) {427ret = ec_edwards_crv_init(e_crv, &d, &a, &(m_crv->order));428} else {429ret = ec_edwards_crv_init(e_crv, &a, &d, &(m_crv->order));430}431432err:433fp_uninit(&tmp);434fp_uninit(&tmp2);435fp_uninit(&a);436fp_uninit(&d);437438return ret;439}440441/*442* Mapping curve from Edwards to short Weierstrass.443*444* Returns 0 on success, -1 on error.445*/446int curve_edwards_to_shortw(ec_edwards_crv_src_t edwards_crv,447ec_shortw_crv_t shortw_crv,448fp_src_t alpha_edwards)449{450int ret;451ec_montgomery_crv montgomery_crv;452montgomery_crv.magic = WORD(0);453454ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err);455ret = curve_montgomery_to_shortw(&montgomery_crv, shortw_crv);456457err:458ec_montgomery_crv_uninit(&montgomery_crv);459460return ret;461}462463/* Checking if an Edwards curve and short Weierstrass curve are compliant (through Montgomery mapping).464*465* Returns 0 on success, -1 on error.466*/467int curve_edwards_shortw_check(ec_edwards_crv_src_t edwards_crv,468ec_shortw_crv_src_t shortw_crv,469fp_src_t alpha_edwards)470{471int ret;472ec_montgomery_crv montgomery_crv;473montgomery_crv.magic = WORD(0);474475ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err);476477ret = curve_montgomery_shortw_check(&montgomery_crv, shortw_crv);478479err:480ec_montgomery_crv_uninit(&montgomery_crv);481482return ret;483}484485/*486* Mapping curve from short Weierstrass to Edwards.487*488* Returns 0 on success, -1 on error.489*/490int curve_shortw_to_edwards(ec_shortw_crv_src_t shortw_crv,491ec_edwards_crv_t edwards_crv,492fp_src_t alpha_montgomery,493fp_src_t gamma_montgomery,494fp_src_t alpha_edwards)495{496int ret;497ec_montgomery_crv montgomery_crv;498montgomery_crv.magic = WORD(0);499500ret = curve_shortw_to_montgomery(shortw_crv, &montgomery_crv, alpha_montgomery, gamma_montgomery); EG(ret, err);501502ret = curve_montgomery_to_edwards(&montgomery_crv, edwards_crv, alpha_edwards);503504err:505ec_montgomery_crv_uninit(&montgomery_crv);506507return ret;508}509510/*511* Mapping points from twisted Edwards to Montgomery.512* Point E(x, y) is mapped to M(u, v) with the formula:513* - (0, 1) mapped to the point at infinity (not possible in our affine coordinates)514* - (0, -1) mapped to (0, 0)515* - (u, v) mapped to ((1+y)/(1-y), alpha * (1+y)/((1-y)x))516*517* Returns 0 on success, -1 on error.518*/519int aff_pt_edwards_to_montgomery(aff_pt_edwards_src_t in_edwards,520ec_montgomery_crv_src_t montgomery_crv,521aff_pt_montgomery_t out_montgomery,522fp_src_t alpha_edwards)523{524/* NOTE: we attempt to perform the (0, -1) -> (0, 0) mapping in constant time.525* Hence the weird table selection.526*/527int ret, iszero, on_curve, cmp;528fp tmp, tmp2, x, y;529fp tab_x[2];530fp_src_t tab_x_t[2] = { &tab_x[0], &tab_x[1] };531fp tab_y[2];532fp_src_t tab_y_t[2] = { &tab_y[0], &tab_y[1] };533u8 idx = 0;534tmp.magic = tmp2.magic = x.magic = y.magic = WORD(0);535tab_x[0].magic = tab_x[1].magic = WORD(0);536tab_y[0].magic = tab_y[1].magic = WORD(0);537538ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);539540/* Check input point is on its curve */541ret = aff_pt_edwards_is_on_curve(in_edwards, &on_curve); EG(ret, err);542MUST_HAVE(on_curve, ret, err);543544ret = curve_edwards_montgomery_check(in_edwards->crv, montgomery_crv, alpha_edwards); EG(ret, err);545546ret = fp_init(&tmp, in_edwards->crv->a.ctx); EG(ret, err);547ret = fp_init(&tmp2, in_edwards->crv->a.ctx); EG(ret, err);548ret = fp_init(&x, in_edwards->crv->a.ctx); EG(ret, err);549ret = fp_init(&y, in_edwards->crv->a.ctx); EG(ret, err);550ret = fp_init(&tab_x[0], in_edwards->crv->a.ctx); EG(ret, err);551ret = fp_init(&tab_x[1], in_edwards->crv->a.ctx); EG(ret, err);552ret = fp_init(&tab_y[0], in_edwards->crv->a.ctx); EG(ret, err);553ret = fp_init(&tab_y[1], in_edwards->crv->a.ctx); EG(ret, err);554555ret = fp_one(&tmp); EG(ret, err);556/* We do not handle point at infinity in affine coordinates */557ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);558ret = fp_cmp(&(in_edwards->y), &tmp, &cmp); EG(ret, err);559MUST_HAVE(!(iszero && (cmp == 0)), ret, err);560/* Map (0, -1) to (0, 0) */561ret = fp_zero(&tmp2); EG(ret, err);562ret = fp_sub(&tmp2, &tmp2, &tmp); EG(ret, err);563/* Copy 1 as x as dummy value */564ret = fp_one(&tab_x[0]); EG(ret, err);565ret = fp_copy(&tab_x[1], &(in_edwards->x)); EG(ret, err);566/* Copy -1 as y to produce (0, 0) */567ret = fp_copy(&tab_y[0], &tmp2); EG(ret, err);568ret = fp_copy(&tab_y[1], &(in_edwards->y)); EG(ret, err);569570ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);571ret = fp_cmp(&(in_edwards->y), &tmp2, &cmp); EG(ret, err);572idx = !(iszero && cmp);573ret = fp_tabselect(&x, idx, tab_x_t, 2); EG(ret, err);574ret = fp_tabselect(&y, idx, tab_y_t, 2); EG(ret, err);575576ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err);577/* Compute general case */578ret = fp_copy(&tmp2, &tmp); EG(ret, err);579/* Put 1/(1-y) in tmp */580ret = fp_sub(&tmp, &tmp, &y); EG(ret, err);581ret = fp_inv(&tmp, &tmp); EG(ret, err);582/* Put (1+y) in tmp2 */583ret = fp_add(&tmp2, &tmp2, &y); EG(ret, err);584/* u = (1+y) / (1-y) */585ret = fp_mul(&(out_montgomery->u), &tmp, &tmp2); EG(ret, err);586/* v = alpha_edwards * (1+y)/((1-y)x) */587ret = fp_inv(&(out_montgomery->v), &x); EG(ret, err);588ret = fp_mul(&(out_montgomery->v), &(out_montgomery->v), alpha_edwards); EG(ret, err);589ret = fp_mul(&(out_montgomery->v), &(out_montgomery->u), &(out_montgomery->v)); EG(ret, err);590591/* Final check that the point is on the curve */592ret = aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve); EG(ret, err);593if (!on_curve) {594ret = -1;595}596597err:598fp_uninit(&tmp);599fp_uninit(&tmp2);600fp_uninit(&x);601fp_uninit(&y);602fp_uninit(&tab_x[0]);603fp_uninit(&tab_x[1]);604fp_uninit(&tab_y[0]);605fp_uninit(&tab_y[1]);606607return ret;608}609610/*611* Mapping points from Montgomery to twisted Edwards.612* Point M(u, v) is mapped to E(x, y) with the formula:613* - Point at infinity mapped to (0, 1) (not possible in our affine coordinates)614* - (0, 0) mapped to (0, -1)615* - (x, y) mapped to (alpha * (u/v), (u-1)/(u+1))616*617* Returns 0 on success, -1 on error.618*/619int aff_pt_montgomery_to_edwards(aff_pt_montgomery_src_t in_montgomery,620ec_edwards_crv_src_t edwards_crv,621aff_pt_edwards_t out_edwards,622fp_src_t alpha)623{624/* NOTE: we attempt to perform the (0, 0) -> (0, -1) mapping in constant time.625* Hence the weird table selection.626*/627int ret, iszero1, iszero2, on_curve;628fp tmp, u, v;629fp tab_u[2];630fp_src_t tab_u_t[2] = { &tab_u[0], &tab_u[1] };631fp tab_v[2];632fp_src_t tab_v_t[2] = { &tab_v[0], &tab_v[1] };633u8 idx = 0;634tmp.magic = u.magic = v.magic = 0;635tab_u[0].magic = tab_u[1].magic = WORD(0);636tab_v[0].magic = tab_v[1].magic = WORD(0);637638ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err);639640/* Check input point is on its curve */641ret = aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve); EG(ret, err);642MUST_HAVE(on_curve, ret, err);643644ret = curve_edwards_montgomery_check(edwards_crv, in_montgomery->crv, alpha); EG(ret, err);645646ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err);647ret = fp_init(&u, in_montgomery->crv->A.ctx); EG(ret, err);648ret = fp_init(&v, in_montgomery->crv->A.ctx); EG(ret, err);649ret = fp_init(&tab_u[0], in_montgomery->crv->A.ctx); EG(ret, err);650ret = fp_init(&tab_u[1], in_montgomery->crv->A.ctx); EG(ret, err);651ret = fp_init(&tab_v[0], in_montgomery->crv->A.ctx); EG(ret, err);652ret = fp_init(&tab_v[1], in_montgomery->crv->A.ctx); EG(ret, err);653654ret = fp_one(&tmp); EG(ret, err);655/* Map (0, 0) to (0, -1) */656/* Copy 0 as u as dummy value */657ret = fp_zero(&tab_u[0]); EG(ret, err);658ret = fp_copy(&tab_u[1], &(in_montgomery->u)); EG(ret, err);659/* Copy 1 as v dummy value to produce (0, -1) */660ret = fp_copy(&tab_v[0], &tmp); EG(ret, err);661ret = fp_copy(&tab_v[1], &(in_montgomery->v)); EG(ret, err);662663ret = fp_iszero(&(in_montgomery->u), &iszero1); EG(ret, err);664ret = fp_iszero(&(in_montgomery->v), &iszero2); EG(ret, err);665idx = (iszero1 && iszero2) ? 0 : 1;666ret = fp_tabselect(&u, idx, tab_u_t, 2); EG(ret, err);667ret = fp_tabselect(&v, idx, tab_v_t, 2); EG(ret, err);668669ret = aff_pt_edwards_init(out_edwards, edwards_crv); EG(ret, err);670/* x = alpha * (u / v) */671ret = fp_inv(&(out_edwards->x), &v); EG(ret, err);672ret = fp_mul(&(out_edwards->x), &(out_edwards->x), alpha); EG(ret, err);673ret = fp_mul(&(out_edwards->x), &(out_edwards->x), &u); EG(ret, err);674/* y = (u-1)/(u+1) */675ret = fp_add(&(out_edwards->y), &u, &tmp); EG(ret, err);676ret = fp_inv(&(out_edwards->y), &(out_edwards->y)); EG(ret, err);677ret = fp_sub(&tmp, &u, &tmp); EG(ret, err);678ret = fp_mul(&(out_edwards->y), &(out_edwards->y), &tmp); EG(ret, err);679680/* Final check that the point is on the curve */681ret = aff_pt_edwards_is_on_curve(out_edwards, &on_curve); EG(ret, err);682if (!on_curve) {683ret = -1;684}685686err:687fp_uninit(&tmp);688fp_uninit(&u);689fp_uninit(&v);690fp_uninit(&tab_u[0]);691fp_uninit(&tab_u[1]);692fp_uninit(&tab_v[0]);693fp_uninit(&tab_v[1]);694695return ret;696}697698699/*700* Map points from Edwards to short Weierstrass through Montgomery (composition mapping).701*702* Returns 0 on success, -1 on error.703*/704int aff_pt_edwards_to_shortw(aff_pt_edwards_src_t in_edwards,705ec_shortw_crv_src_t shortw_crv,706aff_pt_t out_shortw, fp_src_t alpha_edwards)707{708int ret;709aff_pt_montgomery inter_montgomery;710ec_montgomery_crv inter_montgomery_crv;711inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0);712713/* First, map from Edwards to Montgomery */714ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err);715ret = curve_edwards_to_montgomery(in_edwards->crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err);716ret = aff_pt_edwards_to_montgomery(in_edwards, &inter_montgomery_crv, &inter_montgomery, alpha_edwards); EG(ret, err);717718/* Then map from Montgomery to short Weierstrass */719ret = aff_pt_montgomery_to_shortw(&inter_montgomery, shortw_crv, out_shortw);720721err:722aff_pt_montgomery_uninit(&inter_montgomery);723ec_montgomery_crv_uninit(&inter_montgomery_crv);724725return ret;726}727728/*729* Map points from projective short Weierstrass to Edwards through Montgomery (composition mapping).730*731* Returns 0 on success, -1 on error.732*/733int aff_pt_shortw_to_edwards(aff_pt_src_t in_shortw,734ec_edwards_crv_src_t edwards_crv,735aff_pt_edwards_t out_edwards,736fp_src_t alpha_edwards)737{738int ret;739aff_pt_montgomery inter_montgomery;740ec_montgomery_crv inter_montgomery_crv;741inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0);742743/* First, map from short Weierstrass to Montgomery */744ret = curve_edwards_to_montgomery(edwards_crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err);745ret = aff_pt_shortw_to_montgomery(in_shortw, &inter_montgomery_crv, &inter_montgomery); EG(ret, err);746747/* Then map from Montgomery to Edwards */748ret = aff_pt_montgomery_to_edwards(&inter_montgomery, edwards_crv, out_edwards, alpha_edwards);749750err:751aff_pt_montgomery_uninit(&inter_montgomery);752ec_montgomery_crv_uninit(&inter_montgomery_crv);753754return ret;755}756757/*758* Recover the two possible y coordinates from one x on a given759* curve.760* The two outputs y1 and y2 are initialized in the function.761*762* The function returns -1 on error, 0 on success.763*764*/765int aff_pt_edwards_y_from_x(fp_t y1, fp_t y2, fp_src_t x, ec_edwards_crv_src_t crv)766{767int ret;768fp tmp;769tmp.magic = WORD(0);770771/* Sanity checks */772ret = fp_check_initialized(x); EG(ret, err);773ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);774MUST_HAVE((x->ctx == crv->a.ctx) && (x->ctx == crv->d.ctx), ret, err);775MUST_HAVE((y1 != NULL) && (y2 != NULL), ret, err);776/* Aliasing is not supported */777MUST_HAVE((y1 != y2) && (y1 != x), ret, err);778779ret = fp_init(y1, x->ctx); EG(ret, err);780ret = fp_init(y2, x->ctx); EG(ret, err);781ret = fp_init(&tmp, x->ctx); EG(ret, err);782783/* In order to find our two possible y, we have to find the square784* roots of (1 - a x**2) / (1 - d * x**2).785*/786ret = fp_one(&tmp); EG(ret, err);787/* (1 - a x**2) */788ret = fp_mul(y1, x, &(crv->a)); EG(ret, err);789ret = fp_mul(y1, y1, x); EG(ret, err);790ret = fp_sub(y1, &tmp, y1); EG(ret, err);791/* 1 / (1 - d * x**2) */792ret = fp_mul(y2, x, &(crv->d)); EG(ret, err);793ret = fp_mul(y2, y2, x); EG(ret, err);794ret = fp_sub(y2, &tmp, y2); EG(ret, err);795ret = fp_inv(y2, y2); EG(ret, err);796797ret = fp_mul(&tmp, y1, y2); EG(ret, err);798799ret = fp_sqrt(y1, y2, &tmp);800801err:802fp_uninit(&tmp);803804return ret;805}806807/*808* Recover the two possible x coordinates from one y on a given809* curve.810* The two outputs x1 and x2 are initialized in the function.811*812* The function returns -1 on error, 0 on success.813*814*/815int aff_pt_edwards_x_from_y(fp_t x1, fp_t x2, fp_src_t y, ec_edwards_crv_src_t crv)816{817int ret;818fp tmp;819tmp.magic = WORD(0);820821/* Sanity checks */822ret = fp_check_initialized(y); EG(ret, err);823ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);824MUST_HAVE((y->ctx == crv->a.ctx) && (y->ctx == crv->d.ctx), ret, err);825MUST_HAVE((x1 != NULL) && (x2 != NULL), ret, err);826/* Aliasing is not supported */827MUST_HAVE((x1 != x2) && (x1 != y), ret, err);828829ret = fp_init(x1, y->ctx); EG(ret, err);830ret = fp_init(x2, y->ctx); EG(ret, err);831ret = fp_init(&tmp, y->ctx); EG(ret, err);832833/* In order to find our two possible y, we have to find the square834* roots of (1 - y**2) / (a - d * y**2).835*/836ret = fp_one(&tmp); EG(ret, err);837/* (1 - y**2) */838ret = fp_mul(x1, y, y); EG(ret, err);839ret = fp_sub(x1, &tmp, x1); EG(ret, err);840/* 1 / (a - d * x**2) */841ret = fp_mul(x2, y, &(crv->d)); EG(ret, err);842ret = fp_mul(x2, x2, y); EG(ret, err);843ret = fp_sub(x2, &(crv->a), x2); EG(ret, err);844ret = fp_inv(x2, x2); EG(ret, err);845846ret = fp_mul(&tmp, x1, x2); EG(ret, err);847848ret = fp_sqrt(x1, x2, &tmp);849850err:851fp_uninit(&tmp);852853return ret;854}855856857