Path: blob/main/crypto/libecc/src/curves/prj_pt.c
105911 views
/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/curves/ec_shortw.h>16#include <libecc/curves/prj_pt.h>17#include <libecc/nn/nn_logical.h>18#include <libecc/nn/nn_add.h>19#include <libecc/nn/nn_rand.h>20#include <libecc/fp/fp_add.h>21#include <libecc/fp/fp_mul.h>22#include <libecc/fp/fp_montgomery.h>23#include <libecc/fp/fp_rand.h>2425#define PRJ_PT_MAGIC ((word_t)(0xe1cd70babb1d5afeULL))2627/*28* Check given projective point has been correctly initialized (using29* prj_pt_init()). Returns 0 on success, -1 on error.30*/31int prj_pt_check_initialized(prj_pt_src_t in)32{33int ret;3435MUST_HAVE(((in != NULL) && (in->magic == PRJ_PT_MAGIC)), ret, err);36ret = ec_shortw_crv_check_initialized(in->crv);3738err:39return ret;40}4142/*43* Initialize the projective point structure on given curve as the point at44* infinity. The function returns 0 on success, -1 on error.45*/46int prj_pt_init(prj_pt_t in, ec_shortw_crv_src_t curve)47{48int ret;4950ret = ec_shortw_crv_check_initialized(curve); EG(ret, err);5152MUST_HAVE((in != NULL), ret, err);5354ret = fp_init(&(in->X), curve->a.ctx); EG(ret, err);55ret = fp_init(&(in->Y), curve->a.ctx); EG(ret, err);56ret = fp_init(&(in->Z), curve->a.ctx); EG(ret, err);57in->crv = curve;58in->magic = PRJ_PT_MAGIC;5960err:61return ret;62}6364/*65* Initialize the projective point structure on given curve using given66* coordinates. The function returns 0 on success, -1 on error.67*/68int prj_pt_init_from_coords(prj_pt_t in,69ec_shortw_crv_src_t curve,70fp_src_t xcoord, fp_src_t ycoord, fp_src_t zcoord)71{72int ret;7374ret = prj_pt_init(in, curve); EG(ret, err);75ret = fp_copy(&(in->X), xcoord); EG(ret, err);76ret = fp_copy(&(in->Y), ycoord); EG(ret, err);77ret = fp_copy(&(in->Z), zcoord);7879err:80return ret;81}8283/*84* Uninit given projective point structure. The function returns 0 on success,85* -1 on error. This is an error if passed point has not already been86* initialized first.87*/88void prj_pt_uninit(prj_pt_t in)89{90if((in != NULL) && (in->magic == PRJ_PT_MAGIC) && (in->crv != NULL)){91in->crv = NULL;92in->magic = WORD(0);9394fp_uninit(&(in->X));95fp_uninit(&(in->Y));96fp_uninit(&(in->Z));97}9899return;100}101102/*103* Checks if projective point is the point at infinity (last coordinate is 0).104* In that case, 'iszero' out parameter is set to 1. It is set to 0 if the105* point is not the point at infinity. The function returns 0 on success, -1 on106* error. On error, 'iszero' is not meaningful.107*/108int prj_pt_iszero(prj_pt_src_t in, int *iszero)109{110int ret;111112ret = prj_pt_check_initialized(in); EG(ret, err);113ret = fp_iszero(&(in->Z), iszero);114115err:116return ret;117}118119/*120* Set given projective point 'out' to the point at infinity. The functions121* returns 0 on success, -1 on error.122*/123int prj_pt_zero(prj_pt_t out)124{125int ret;126127ret = prj_pt_check_initialized(out); EG(ret, err);128129ret = fp_zero(&(out->X)); EG(ret, err);130ret = fp_one(&(out->Y)); EG(ret, err);131ret = fp_zero(&(out->Z));132133err:134return ret;135}136137/*138* Check if a projective point is indeed on its curve. The function sets139* 'on_curve' out parameter to 1 if the point is on the curve, 0 if not.140* The function returns 0 on success, -1 on error. 'on_curve' is not141* meaningful on error.142*/143int prj_pt_is_on_curve(prj_pt_src_t in, int *on_curve)144{145int ret, cmp;146147/* In order to check that we are on the curve, we148* use the projective formula of the curve:149*150* Y**2 * Z = X**3 + a * X * Z**2 + b * Z**3151*152*/153fp X, Y, Z;154X.magic = Y.magic = Z.magic = WORD(0);155156ret = prj_pt_check_initialized(in); EG(ret, err);157ret = ec_shortw_crv_check_initialized(in->crv); EG(ret, err);158MUST_HAVE((on_curve != NULL), ret, err);159160ret = fp_init(&X, in->X.ctx); EG(ret, err);161ret = fp_init(&Y, in->X.ctx); EG(ret, err);162ret = fp_init(&Z, in->X.ctx); EG(ret, err);163164/* Compute X**3 + a * X * Z**2 + b * Z**3 on one side */165ret = fp_sqr(&X, &(in->X)); EG(ret, err);166ret = fp_mul(&X, &X, &(in->X)); EG(ret, err);167ret = fp_mul(&Z, &(in->X), &(in->crv->a)); EG(ret, err);168ret = fp_mul(&Y, &(in->crv->b), &(in->Z)); EG(ret, err);169ret = fp_add(&Z, &Z, &Y); EG(ret, err);170ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err);171ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err);172ret = fp_add(&X, &X, &Z); EG(ret, err);173174/* Compute Y**2 * Z on the other side */175ret = fp_sqr(&Y, &(in->Y)); EG(ret, err);176ret = fp_mul(&Y, &Y, &(in->Z)); EG(ret, err);177178/* Compare the two values */179ret = fp_cmp(&X, &Y, &cmp); EG(ret, err);180181(*on_curve) = (!cmp);182183err:184fp_uninit(&X);185fp_uninit(&Y);186fp_uninit(&Z);187188return ret;189}190191/*192* The function copies 'in' projective point to 'out'. 'out' is initialized by193* the function. The function returns 0 on sucess, -1 on error.194*/195int prj_pt_copy(prj_pt_t out, prj_pt_src_t in)196{197int ret;198199ret = prj_pt_check_initialized(in); EG(ret, err);200201ret = prj_pt_init(out, in->crv); EG(ret, err);202203ret = fp_copy(&(out->X), &(in->X)); EG(ret, err);204ret = fp_copy(&(out->Y), &(in->Y)); EG(ret, err);205ret = fp_copy(&(out->Z), &(in->Z));206207err:208return ret;209}210211/*212* Convert given projective point 'in' to affine representation in 'out'. 'out'213* is initialized by the function. The function returns 0 on success, -1 on214* error. Passing the point at infinty to the function is considered as an215* error.216*/217int prj_pt_to_aff(aff_pt_t out, prj_pt_src_t in)218{219int ret, iszero;220221ret = prj_pt_check_initialized(in); EG(ret, err);222223ret = prj_pt_iszero(in, &iszero); EG(ret, err);224MUST_HAVE((!iszero), ret, err);225226ret = aff_pt_init(out, in->crv); EG(ret, err);227228ret = fp_inv(&(out->x), &(in->Z)); EG(ret, err);229ret = fp_mul(&(out->y), &(in->Y), &(out->x)); EG(ret, err);230ret = fp_mul(&(out->x), &(in->X), &(out->x));231232err:233return ret;234}235236/*237* Get the unique Z = 1 projective point representation ("equivalent" to affine238* point). The function returns 0 on success, -1 on error.239*/240int prj_pt_unique(prj_pt_t out, prj_pt_src_t in)241{242int ret, iszero;243244ret = prj_pt_check_initialized(in); EG(ret, err);245ret = prj_pt_iszero(in, &iszero); EG(ret, err);246MUST_HAVE((!iszero), ret, err);247248if(out == in){249/* Aliasing case */250fp tmp;251tmp.magic = WORD(0);252253ret = fp_init(&tmp, (in->Z).ctx); EG(ret, err);254ret = fp_inv(&tmp, &(in->Z)); EG(ret, err1);255ret = fp_mul(&(out->Y), &(in->Y), &tmp); EG(ret, err1);256ret = fp_mul(&(out->X), &(in->X), &tmp); EG(ret, err1);257ret = fp_one(&(out->Z)); EG(ret, err1);258err1:259fp_uninit(&tmp); EG(ret, err);260}261else{262ret = prj_pt_init(out, in->crv); EG(ret, err);263ret = fp_inv(&(out->X), &(in->Z)); EG(ret, err);264ret = fp_mul(&(out->Y), &(in->Y), &(out->X)); EG(ret, err);265ret = fp_mul(&(out->X), &(in->X), &(out->X)); EG(ret, err);266ret = fp_one(&(out->Z)); EG(ret, err);267}268269270err:271return ret;272}273274/*275* Converts affine point 'in' to projective representation in 'out'. 'out' is276* initialized by the function. The function returns 0 on success, -1 on error.277*/278int ec_shortw_aff_to_prj(prj_pt_t out, aff_pt_src_t in)279{280int ret, on_curve;281282ret = aff_pt_check_initialized(in); EG(ret, err);283284/* The input affine point must be on the curve */285ret = aff_pt_is_on_curve(in, &on_curve); EG(ret, err);286MUST_HAVE(on_curve, ret, err);287288ret = prj_pt_init(out, in->crv); EG(ret, err);289ret = fp_copy(&(out->X), &(in->x)); EG(ret, err);290ret = fp_copy(&(out->Y), &(in->y)); EG(ret, err);291ret = nn_one(&(out->Z).fp_val); /* Z = 1 */292293err:294return ret;295}296297/*298* Compare projective points 'in1' and 'in2'. On success, 'cmp' is set to299* the result of the comparison (0 if in1 == in2, !0 if in1 != in2). The300* function returns 0 on success, -1 on error.301*/302int prj_pt_cmp(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp)303{304fp X1, X2, Y1, Y2;305int ret, x_cmp, y_cmp;306X1.magic = X2.magic = Y1.magic = Y2.magic = WORD(0);307308MUST_HAVE((cmp != NULL), ret, err);309ret = prj_pt_check_initialized(in1); EG(ret, err);310ret = prj_pt_check_initialized(in2); EG(ret, err);311312MUST_HAVE((in1->crv == in2->crv), ret, err);313314ret = fp_init(&X1, (in1->X).ctx); EG(ret, err);315ret = fp_init(&X2, (in2->X).ctx); EG(ret, err);316ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err);317ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err);318319/*320* Montgomery multiplication is used as it is faster than321* usual multiplication and the spurious multiplicative322* factor does not matter.323*/324ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);325ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);326ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);327ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);328329ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);330ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);331ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);332ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);333ret = fp_cmp(&X1, &X2, &x_cmp); EG(ret, err);334ret = fp_cmp(&Y1, &Y2, &y_cmp);335336if (!ret) {337(*cmp) = (x_cmp | y_cmp);338}339340err:341fp_uninit(&Y2);342fp_uninit(&Y1);343fp_uninit(&X2);344fp_uninit(&X1);345346return ret;347}348349/*350* NOTE: this internal functions assumes that upper layer have checked that in1 and in2351* are initialized, and that cmp is not NULL.352*/353ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_eq_or_opp_X(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp)354{355int ret;356fp X1, X2;357X1.magic = X2.magic = WORD(0);358359/*360* Montgomery multiplication is used as it is faster than361* usual multiplication and the spurious multiplicative362* factor does not matter.363*/364ret = fp_init(&X1, (in1->X).ctx); EG(ret, err);365ret = fp_init(&X2, (in2->X).ctx); EG(ret, err);366ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err);367ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err);368ret = fp_cmp(&X1, &X2, cmp);369370err:371fp_uninit(&X1);372fp_uninit(&X2);373374return ret;375}376377/*378* NOTE: this internal functions assumes that upper layer have checked that in1 and in2379* are initialized, and that eq_or_opp is not NULL.380*/381ATTRIBUTE_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)382{383int ret;384fp Y1, Y2;385Y1.magic = Y2.magic = WORD(0);386387/*388* Montgomery multiplication is used as it is faster than389* usual multiplication and the spurious multiplicative390* factor does not matter.391*/392ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err);393ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err);394ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err);395ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err);396ret = fp_eq_or_opp(&Y1, &Y2, eq_or_opp);397398err:399fp_uninit(&Y1);400fp_uninit(&Y2);401402return ret;403}404405/*406* The functions tests if given projective points 'in1' and 'in2' are equal or407* opposite. On success, the result of the comparison is given via 'eq_or_opp'408* out parameter (1 if equal or opposite, 0 otherwise). The function returns409* 0 on succes, -1 on error.410*/411int prj_pt_eq_or_opp(prj_pt_src_t in1, prj_pt_src_t in2, int *eq_or_opp)412{413int ret, cmp, _eq_or_opp;414415ret = prj_pt_check_initialized(in1); EG(ret, err);416ret = prj_pt_check_initialized(in2); EG(ret, err);417MUST_HAVE((in1->crv == in2->crv), ret, err);418MUST_HAVE((eq_or_opp != NULL), ret, err);419420ret = _prj_pt_eq_or_opp_X(in1, in2, &cmp); EG(ret, err);421ret = _prj_pt_eq_or_opp_Y(in1, in2, &_eq_or_opp);422423if (!ret) {424(*eq_or_opp) = ((cmp == 0) & _eq_or_opp);425}426427err:428return ret;429}430431/* Compute the opposite of a projective point. Supports aliasing.432* Returns 0 on success, -1 on failure.433*/434int prj_pt_neg(prj_pt_t out, prj_pt_src_t in)435{436int ret;437438ret = prj_pt_check_initialized(in); EG(ret, err);439440if (out != in) { /* Copy point if not aliased */441ret = prj_pt_init(out, in->crv); EG(ret, err);442ret = prj_pt_copy(out, in); EG(ret, err);443}444445/* Then, negate Y */446ret = fp_neg(&(out->Y), &(out->Y));447448err:449return ret;450}451452/*453* Import a projective point from a buffer with the following layout; the 3454* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len455* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each456* coordinate is encoded in big endian. Size of buffer must exactly match457* 3 * p_len. The projective point is initialized by the function.458*459* The function returns 0 on success, -1 on error.460*/461int prj_pt_import_from_buf(prj_pt_t pt,462const u8 *pt_buf,463u16 pt_buf_len, ec_shortw_crv_src_t crv)464{465int on_curve, ret;466fp_ctx_src_t ctx;467u16 coord_len;468469ret = ec_shortw_crv_check_initialized(crv); EG(ret, err);470MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);471472ctx = crv->a.ctx;473coord_len = (u16)BYTECEIL(ctx->p_bitlen);474MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err);475476ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err);477ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);478ret = fp_init_from_buf(&(pt->Z), ctx, pt_buf + (2 * coord_len), coord_len); EG(ret, err);479480/* Set the curve */481pt->crv = crv;482483/* Mark the point as initialized */484pt->magic = PRJ_PT_MAGIC;485486/* Check that the point is indeed on the provided curve, uninitialize it487* if this is not the case.488*/489ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);490if (!on_curve){491prj_pt_uninit(pt);492ret = -1;493}494495err:496PTR_NULLIFY(ctx);497498return ret;499}500501/*502* Import a projective point from an affine point buffer with the following layout; the 2503* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len504* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each505* coordinate is encoded in big endian. Size of buffer must exactly match506* 2 * p_len. The projective point is initialized by the function.507*508* The function returns 0 on success, -1 on error.509*/510int prj_pt_import_from_aff_buf(prj_pt_t pt,511const u8 *pt_buf,512u16 pt_buf_len, ec_shortw_crv_src_t crv)513{514int ret, on_curve;515fp_ctx_src_t ctx;516u16 coord_len;517518ret = ec_shortw_crv_check_initialized(crv); EG(ret, err);519MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);520521ctx = crv->a.ctx;522coord_len = (u16)BYTECEIL(ctx->p_bitlen);523MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);524525ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err);526ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);527/* Z coordinate is set to 1 */528ret = fp_init(&(pt->Z), ctx); EG(ret, err);529ret = fp_one(&(pt->Z)); EG(ret, err);530531/* Set the curve */532pt->crv = crv;533534/* Mark the point as initialized */535pt->magic = PRJ_PT_MAGIC;536537/* Check that the point is indeed on the provided curve, uninitialize it538* if this is not the case.539*/540ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);541if (!on_curve){542prj_pt_uninit(pt);543ret = -1;544}545546err:547PTR_NULLIFY(ctx);548549return ret;550}551552553/* Export a projective point to a buffer with the following layout; the 3554* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len555* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each556* coordinate is encoded in big endian. Size of buffer must exactly match557* 3 * p_len.558*559* The function returns 0 on success, -1 on error.560*/561int prj_pt_export_to_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len)562{563fp_ctx_src_t ctx;564u16 coord_len;565int ret, on_curve;566567ret = prj_pt_check_initialized(pt); EG(ret, err);568569MUST_HAVE((pt_buf != NULL), ret, err);570571/* The point to be exported must be on the curve */572ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);573MUST_HAVE((on_curve), ret, err);574575ctx = pt->crv->a.ctx;576coord_len = (u16)BYTECEIL(ctx->p_bitlen);577MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err);578579/* Export the three coordinates */580ret = fp_export_to_buf(pt_buf, coord_len, &(pt->X)); EG(ret, err);581ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->Y)); EG(ret, err);582ret = fp_export_to_buf(pt_buf + (2 * coord_len), coord_len, &(pt->Z));583584err:585PTR_NULLIFY(ctx);586587return ret;588}589590/*591* Export a projective point to an affine point buffer with the following592* layout; the 2 coordinates (elements of Fp) are each encoded on p_len bytes,593* where p_len is the size of p in bytes (e.g. 66 for a prime p of 521 bits).594* Each coordinate is encoded in big endian. Size of buffer must exactly match595* 2 * p_len.596*597* The function returns 0 on success, -1 on error.598*/599int prj_pt_export_to_aff_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len)600{601int ret, on_curve;602aff_pt tmp_aff;603tmp_aff.magic = WORD(0);604605ret = prj_pt_check_initialized(pt); EG(ret, err);606607MUST_HAVE((pt_buf != NULL), ret, err);608609/* The point to be exported must be on the curve */610ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err);611MUST_HAVE((on_curve), ret, err);612613/* Move to the affine unique representation */614ret = prj_pt_to_aff(&tmp_aff, pt); EG(ret, err);615616/* Export the affine point to the buffer */617ret = aff_pt_export_to_buf(&tmp_aff, pt_buf, pt_buf_len);618619err:620aff_pt_uninit(&tmp_aff);621622return ret;623}624625626#ifdef NO_USE_COMPLETE_FORMULAS627628/*629* The function is an internal one: no check is performed on parameters,630* this MUST be done by the caller:631*632* - in is initialized633* - in and out must not be aliased634*635* The function will initialize 'out'. The function returns 0 on success, -1636* on error.637*/638ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_no_cf(prj_pt_t out, prj_pt_src_t in)639{640fp XX, ZZ, w, s, ss, sss, R, RR, B, h;641int ret;642XX.magic = ZZ.magic = w.magic = s.magic = WORD(0);643ss.magic = sss.magic = R.magic = WORD(0);644RR.magic = B.magic = h.magic = WORD(0);645646ret = prj_pt_init(out, in->crv); EG(ret, err);647648ret = fp_init(&XX, out->crv->a.ctx); EG(ret, err);649ret = fp_init(&ZZ, out->crv->a.ctx); EG(ret, err);650ret = fp_init(&w, out->crv->a.ctx); EG(ret, err);651ret = fp_init(&s, out->crv->a.ctx); EG(ret, err);652ret = fp_init(&ss, out->crv->a.ctx); EG(ret, err);653ret = fp_init(&sss, out->crv->a.ctx); EG(ret, err);654ret = fp_init(&R, out->crv->a.ctx); EG(ret, err);655ret = fp_init(&RR, out->crv->a.ctx); EG(ret, err);656ret = fp_init(&B, out->crv->a.ctx); EG(ret, err);657ret = fp_init(&h, out->crv->a.ctx); EG(ret, err);658659/* XX = X1² */660ret = fp_sqr_monty(&XX, &(in->X)); EG(ret, err);661662/* ZZ = Z1² */663ret = fp_sqr_monty(&ZZ, &(in->Z)); EG(ret, err);664665/* w = a*ZZ+3*XX */666ret = fp_mul_monty(&w, &(in->crv->a_monty), &ZZ); EG(ret, err);667ret = fp_add_monty(&w, &w, &XX); EG(ret, err);668ret = fp_add_monty(&w, &w, &XX); EG(ret, err);669ret = fp_add_monty(&w, &w, &XX); EG(ret, err);670671/* s = 2*Y1*Z1 */672ret = fp_mul_monty(&s, &(in->Y), &(in->Z)); EG(ret, err);673ret = fp_add_monty(&s, &s, &s); EG(ret, err);674675/* ss = s² */676ret = fp_sqr_monty(&ss, &s); EG(ret, err);677678/* sss = s*ss */679ret = fp_mul_monty(&sss, &s, &ss); EG(ret, err);680681/* R = Y1*s */682ret = fp_mul_monty(&R, &(in->Y), &s); EG(ret, err);683684/* RR = R² */685ret = fp_sqr_monty(&RR, &R); EG(ret, err);686687/* B = (X1+R)²-XX-RR */688ret = fp_add_monty(&R, &R, &(in->X)); EG(ret, err);689ret = fp_sqr_monty(&B, &R); EG(ret, err);690ret = fp_sub_monty(&B, &B, &XX); EG(ret, err);691ret = fp_sub_monty(&B, &B, &RR); EG(ret, err);692693/* h = w²-2*B */694ret = fp_sqr_monty(&h, &w); EG(ret, err);695ret = fp_sub_monty(&h, &h, &B); EG(ret, err);696ret = fp_sub_monty(&h, &h, &B); EG(ret, err);697698/* X3 = h*s */699ret = fp_mul_monty(&(out->X), &h, &s); EG(ret, err);700701/* Y3 = w*(B-h)-2*RR */702ret = fp_sub_monty(&B, &B, &h); EG(ret, err);703ret = fp_mul_monty(&(out->Y), &w, &B); EG(ret, err);704ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err);705ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err);706707/* Z3 = sss */708ret = fp_copy(&(out->Z), &sss);709710err:711fp_uninit(&XX);712fp_uninit(&ZZ);713fp_uninit(&w);714fp_uninit(&s);715fp_uninit(&ss);716fp_uninit(&sss);717fp_uninit(&R);718fp_uninit(&RR);719fp_uninit(&B);720fp_uninit(&h);721722return ret;723}724725/*726* The function is an internal one: no check is performed on parameters,727* this MUST be done by the caller:728*729* - in1 and in2 are initialized730* - in1 and in2 are on the same curve731* - in1/in2 and out must not be aliased732* - in1 and in2 must not be equal, opposite or have identical value733*734* The function will initialize 'out'. The function returns 0 on success, -1735* on error.736*/737ATTRIBUTE_WARN_UNUSED_RET static int ___prj_pt_add_monty_no_cf(prj_pt_t out,738prj_pt_src_t in1,739prj_pt_src_t in2)740{741fp Y1Z2, X1Z2, Z1Z2, u, uu, v, vv, vvv, R, A;742int ret;743Y1Z2.magic = X1Z2.magic = Z1Z2.magic = u.magic = uu.magic = v.magic = WORD(0);744vv.magic = vvv.magic = R.magic = A.magic = WORD(0);745746ret = prj_pt_init(out, in1->crv); EG(ret, err);747748ret = fp_init(&Y1Z2, out->crv->a.ctx); EG(ret, err);749ret = fp_init(&X1Z2, out->crv->a.ctx); EG(ret, err);750ret = fp_init(&Z1Z2, out->crv->a.ctx); EG(ret, err);751ret = fp_init(&u, out->crv->a.ctx); EG(ret, err);752ret = fp_init(&uu, out->crv->a.ctx); EG(ret, err);753ret = fp_init(&v, out->crv->a.ctx); EG(ret, err);754ret = fp_init(&vv, out->crv->a.ctx); EG(ret, err);755ret = fp_init(&vvv, out->crv->a.ctx); EG(ret, err);756ret = fp_init(&R, out->crv->a.ctx); EG(ret, err);757ret = fp_init(&A, out->crv->a.ctx); EG(ret, err);758759/* Y1Z2 = Y1*Z2 */760ret = fp_mul_monty(&Y1Z2, &(in1->Y), &(in2->Z)); EG(ret, err);761762/* X1Z2 = X1*Z2 */763ret = fp_mul_monty(&X1Z2, &(in1->X), &(in2->Z)); EG(ret, err);764765/* Z1Z2 = Z1*Z2 */766ret = fp_mul_monty(&Z1Z2, &(in1->Z), &(in2->Z)); EG(ret, err);767768/* u = Y2*Z1-Y1Z2 */769ret = fp_mul_monty(&u, &(in2->Y), &(in1->Z)); EG(ret, err);770ret = fp_sub_monty(&u, &u, &Y1Z2); EG(ret, err);771772/* uu = u² */773ret = fp_sqr_monty(&uu, &u); EG(ret, err);774775/* v = X2*Z1-X1Z2 */776ret = fp_mul_monty(&v, &(in2->X), &(in1->Z)); EG(ret, err);777ret = fp_sub_monty(&v, &v, &X1Z2); EG(ret, err);778779/* vv = v² */780ret = fp_sqr_monty(&vv, &v); EG(ret, err);781782/* vvv = v*vv */783ret = fp_mul_monty(&vvv, &v, &vv); EG(ret, err);784785/* R = vv*X1Z2 */786ret = fp_mul_monty(&R, &vv, &X1Z2); EG(ret, err);787788/* A = uu*Z1Z2-vvv-2*R */789ret = fp_mul_monty(&A, &uu, &Z1Z2); EG(ret, err);790ret = fp_sub_monty(&A, &A, &vvv); EG(ret, err);791ret = fp_sub_monty(&A, &A, &R); EG(ret, err);792ret = fp_sub_monty(&A, &A, &R); EG(ret, err);793794/* X3 = v*A */795ret = fp_mul_monty(&(out->X), &v, &A); EG(ret, err);796797/* Y3 = u*(R-A)-vvv*Y1Z2 */798ret = fp_sub_monty(&R, &R, &A); EG(ret, err);799ret = fp_mul_monty(&(out->Y), &u, &R); EG(ret, err);800ret = fp_mul_monty(&R, &vvv, &Y1Z2); EG(ret, err);801ret = fp_sub_monty(&(out->Y), &(out->Y), &R); EG(ret, err);802803/* Z3 = vvv*Z1Z2 */804ret = fp_mul_monty(&(out->Z), &vvv, &Z1Z2);805806err:807fp_uninit(&Y1Z2);808fp_uninit(&X1Z2);809fp_uninit(&Z1Z2);810fp_uninit(&u);811fp_uninit(&uu);812fp_uninit(&v);813fp_uninit(&vv);814fp_uninit(&vvv);815fp_uninit(&R);816fp_uninit(&A);817818return ret;819}820821/*822* Public version of the addition w/o complete formulas to handle the case823* where the inputs are zero or opposite. Returns 0 on success, -1 on error.824*/825ATTRIBUTE_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)826{827int ret, iszero, eq_or_opp, cmp;828829ret = prj_pt_check_initialized(in1); EG(ret, err);830ret = prj_pt_check_initialized(in2); EG(ret, err);831MUST_HAVE((in1->crv == in2->crv), ret, err);832833ret = prj_pt_iszero(in1, &iszero); EG(ret, err);834if (iszero) {835/* in1 at infinity, output in2 in all cases */836ret = prj_pt_init(out, in2->crv); EG(ret, err);837ret = prj_pt_copy(out, in2); EG(ret, err);838} else {839/* in1 not at infinity, output in2 */840ret = prj_pt_iszero(in2, &iszero); EG(ret, err);841if (iszero) {842/* in2 at infinity, output in1 */843ret = prj_pt_init(out, in1->crv); EG(ret, err);844ret = prj_pt_copy(out, in1); EG(ret, err);845} else {846/* enither in1, nor in2 at infinity */847848/*849* The following test which guarantees in1 and in2 are not850* equal or opposite needs to be rewritten because it851* has a *HUGE* impact on perf (ec_self_tests run on852* all test vectors takes 24 times as long with this853* enabled). The same exists in non monty version.854*/855ret = prj_pt_eq_or_opp(in1, in2, &eq_or_opp); EG(ret, err);856if (eq_or_opp) {857/* in1 and in2 are either equal or opposite */858ret = prj_pt_cmp(in1, in2, &cmp); EG(ret, err);859if (cmp == 0) {860/* in1 == in2 => doubling w/o cf */861ret = __prj_pt_dbl_monty_no_cf(out, in1); EG(ret, err);862} else {863/* in1 == -in2 => output zero (point at infinity) */864ret = prj_pt_init(out, in1->crv); EG(ret, err);865ret = prj_pt_zero(out); EG(ret, err);866}867} else {868/*869* in1 and in2 are neither 0, nor equal or870* opposite. Use the basic monty addition871* implementation w/o complete formulas.872*/873ret = ___prj_pt_add_monty_no_cf(out, in1, in2); EG(ret, err);874}875}876}877878err:879return ret;880}881882883#else /* NO_USE_COMPLETE_FORMULAS */884885886/*887* If NO_USE_COMPLETE_FORMULAS flag is not defined addition formulas from Algorithm 3888* of https://joostrenes.nl/publications/complete.pdf are used, otherwise889* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl890*/891ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_cf(prj_pt_t out, prj_pt_src_t in)892{893fp t0, t1, t2, t3;894int ret;895t0.magic = t1.magic = t2.magic = t3.magic = WORD(0);896897ret = prj_pt_init(out, in->crv); EG(ret, err);898899ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err);900ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err);901ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err);902ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err);903904ret = fp_mul_monty(&t0, &in->X, &in->X); EG(ret, err);905ret = fp_mul_monty(&t1, &in->Y, &in->Y); EG(ret, err);906ret = fp_mul_monty(&t2, &in->Z, &in->Z); EG(ret, err);907ret = fp_mul_monty(&t3, &in->X, &in->Y); EG(ret, err);908ret = fp_add_monty(&t3, &t3, &t3); EG(ret, err);909910ret = fp_mul_monty(&out->Z, &in->X, &in->Z); EG(ret, err);911ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err);912ret = fp_mul_monty(&out->X, &in->crv->a_monty, &out->Z); EG(ret, err);913ret = fp_mul_monty(&out->Y, &in->crv->b3_monty, &t2); EG(ret, err);914ret = fp_add_monty(&out->Y, &out->X, &out->Y); EG(ret, err);915916ret = fp_sub_monty(&out->X, &t1, &out->Y); EG(ret, err);917ret = fp_add_monty(&out->Y, &t1, &out->Y); EG(ret, err);918ret = fp_mul_monty(&out->Y, &out->X, &out->Y); EG(ret, err);919ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err);920ret = fp_mul_monty(&out->Z, &in->crv->b3_monty, &out->Z); EG(ret, err);921922ret = fp_mul_monty(&t2, &in->crv->a_monty, &t2); EG(ret, err);923ret = fp_sub_monty(&t3, &t0, &t2); EG(ret, err);924ret = fp_mul_monty(&t3, &in->crv->a_monty, &t3); EG(ret, err);925ret = fp_add_monty(&t3, &t3, &out->Z); EG(ret, err);926ret = fp_add_monty(&out->Z, &t0, &t0); EG(ret, err);927928ret = fp_add_monty(&t0, &out->Z, &t0); EG(ret, err);929ret = fp_add_monty(&t0, &t0, &t2); EG(ret, err);930ret = fp_mul_monty(&t0, &t0, &t3); EG(ret, err);931ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err);932ret = fp_mul_monty(&t2, &in->Y, &in->Z); EG(ret, err);933934ret = fp_add_monty(&t2, &t2, &t2); EG(ret, err);935ret = fp_mul_monty(&t0, &t2, &t3); EG(ret, err);936ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err);937ret = fp_mul_monty(&out->Z, &t2, &t1); EG(ret, err);938ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err);939940ret = fp_add_monty(&out->Z, &out->Z, &out->Z);941942err:943fp_uninit(&t0);944fp_uninit(&t1);945fp_uninit(&t2);946fp_uninit(&t3);947948return ret;949}950951/*952* If NO_USE_COMPLETE_FORMULAS flag is not defined addition formulas from Algorithm 1953* of https://joostrenes.nl/publications/complete.pdf are used, otherwise954* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2955*/956957/*958* The function is an internal one: no check is performed on parameters,959* this MUST be done by the caller:960*961* - in1 and in2 are initialized962* - in1 and in2 are on the same curve963* - in1/in2 and out must not be aliased964* - in1 and in2 must not be an "exceptional" pair, i.e. (in1-in2) is not a point965* of order exactly 2966*967* The function will initialize 'out'. The function returns 0 on success, -1968* on error.969*/970ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_add_monty_cf(prj_pt_t out,971prj_pt_src_t in1,972prj_pt_src_t in2)973{974int cmp1, cmp2;975fp t0, t1, t2, t3, t4, t5;976int ret;977t0.magic = t1.magic = t2.magic = WORD(0);978t3.magic = t4.magic = t5.magic = WORD(0);979980ret = prj_pt_init(out, in1->crv); EG(ret, err);981982ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err);983ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err);984ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err);985ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err);986ret = fp_init(&t4, out->crv->a.ctx); EG(ret, err);987ret = fp_init(&t5, out->crv->a.ctx); EG(ret, err);988989ret = fp_mul_monty(&t0, &in1->X, &in2->X); EG(ret, err);990ret = fp_mul_monty(&t1, &in1->Y, &in2->Y); EG(ret, err);991ret = fp_mul_monty(&t2, &in1->Z, &in2->Z); EG(ret, err);992ret = fp_add_monty(&t3, &in1->X, &in1->Y); EG(ret, err);993ret = fp_add_monty(&t4, &in2->X, &in2->Y); EG(ret, err);994995ret = fp_mul_monty(&t3, &t3, &t4); EG(ret, err);996ret = fp_add_monty(&t4, &t0, &t1); EG(ret, err);997ret = fp_sub_monty(&t3, &t3, &t4); EG(ret, err);998ret = fp_add_monty(&t4, &in1->X, &in1->Z); EG(ret, err);999ret = fp_add_monty(&t5, &in2->X, &in2->Z); EG(ret, err);10001001ret = fp_mul_monty(&t4, &t4, &t5); EG(ret, err);1002ret = fp_add_monty(&t5, &t0, &t2); EG(ret, err);1003ret = fp_sub_monty(&t4, &t4, &t5); EG(ret, err);1004ret = fp_add_monty(&t5, &in1->Y, &in1->Z); EG(ret, err);1005ret = fp_add_monty(&out->X, &in2->Y, &in2->Z); EG(ret, err);10061007ret = fp_mul_monty(&t5, &t5, &out->X); EG(ret, err);1008ret = fp_add_monty(&out->X, &t1, &t2); EG(ret, err);1009ret = fp_sub_monty(&t5, &t5, &out->X); EG(ret, err);1010ret = fp_mul_monty(&out->Z, &in1->crv->a_monty, &t4); EG(ret, err);1011ret = fp_mul_monty(&out->X, &in1->crv->b3_monty, &t2); EG(ret, err);10121013ret = fp_add_monty(&out->Z, &out->X, &out->Z); EG(ret, err);1014ret = fp_sub_monty(&out->X, &t1, &out->Z); EG(ret, err);1015ret = fp_add_monty(&out->Z, &t1, &out->Z); EG(ret, err);1016ret = fp_mul_monty(&out->Y, &out->X, &out->Z); EG(ret, err);1017ret = fp_add_monty(&t1, &t0, &t0); EG(ret, err);10181019ret = fp_add_monty(&t1, &t1, &t0); EG(ret, err);1020ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err);1021ret = fp_mul_monty(&t4, &in1->crv->b3_monty, &t4); EG(ret, err);1022ret = fp_add_monty(&t1, &t1, &t2); EG(ret, err);1023ret = fp_sub_monty(&t2, &t0, &t2); EG(ret, err);10241025ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err);1026ret = fp_add_monty(&t4, &t4, &t2); EG(ret, err);1027ret = fp_mul_monty(&t0, &t1, &t4); EG(ret, err);1028ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err);1029ret = fp_mul_monty(&t0, &t5, &t4); EG(ret, err);10301031ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err);1032ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err);1033ret = fp_mul_monty(&t0, &t3, &t1); EG(ret, err);1034ret = fp_mul_monty(&out->Z, &t5, &out->Z); EG(ret, err);1035ret = fp_add_monty(&out->Z, &out->Z, &t0);10361037/* Check for "exceptional" pairs of input points with1038* checking if Y = Z = 0 as output (see the Bosma-Lenstra1039* article "Complete Systems of Two Addition Laws for1040* Elliptic Curves"). This should only happen on composite1041* order curves (i.e. not on prime order curves).1042*1043* In this case, we raise an error as the result is1044* not sound. This should not happen in our nominal1045* cases with regular signature and protocols, and if1046* it happens this usually means that bad points have1047* been injected.1048*1049* NOTE: if for some reasons you need to deal with1050* all the possible pairs of points including these1051* exceptional pairs of inputs with an order 2 difference,1052* you should fallback to the incomplete formulas using the1053* COMPLETE=0 compilation toggle. Beware that in this1054* case, the library will be more sensitive to1055* side-channel attacks.1056*/1057ret = fp_iszero(&(out->Z), &cmp1); EG(ret, err);1058ret = fp_iszero(&(out->Y), &cmp2); EG(ret, err);1059MUST_HAVE(!((cmp1) && (cmp2)), ret, err);10601061err:1062fp_uninit(&t0);1063fp_uninit(&t1);1064fp_uninit(&t2);1065fp_uninit(&t3);1066fp_uninit(&t4);1067fp_uninit(&t5);10681069return ret;1070}1071#endif /* NO_USE_COMPLETE_FORMULAS */10721073/*1074* Internal function:1075*1076* - not supporting aliasing,1077* - requiring caller to check in parameter is initialized1078*1079* Based on library configuration, the function either use complete formulas1080* or not.1081*/1082static int _prj_pt_dbl_monty(prj_pt_t out, prj_pt_src_t in)1083{1084int ret;10851086#ifdef NO_USE_COMPLETE_FORMULAS1087int iszero;1088ret = prj_pt_iszero(in, &iszero); EG(ret, err);1089if (iszero) {1090ret = prj_pt_init(out, in->crv); EG(ret, err);1091ret = prj_pt_zero(out);1092} else {1093ret = __prj_pt_dbl_monty_no_cf(out, in);1094}1095#else1096ret = __prj_pt_dbl_monty_cf(out, in); EG(ret, err);1097#endif10981099err:1100return ret;1101}11021103/*1104* Internal version that peform in place doubling of given val,1105* by using a temporary copy. Sanity checks on parameters must1106* be done by caller.1107*/1108ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_dbl_monty_aliased(prj_pt_t val)1109{1110prj_pt out_cpy;1111int ret;1112out_cpy.magic = WORD(0);11131114ret = _prj_pt_dbl_monty(&out_cpy, val); EG(ret, err);1115ret = prj_pt_copy(val, &out_cpy);11161117err:1118prj_pt_uninit(&out_cpy);11191120return ret;1121}11221123/*1124* Public function for projective point doubling. The function handles the init1125* check of 'in' parameter which must be guaranteed for internal functions.1126* 'out' parameter need not be initialized and can be aliased with 'in'1127* parameter.1128*1129* The function returns 0 on success, -1 on error.1130*/1131ATTRIBUTE_WARN_UNUSED_RET int prj_pt_dbl(prj_pt_t out, prj_pt_src_t in)1132{1133int ret;11341135ret = prj_pt_check_initialized(in); EG(ret, err);11361137if (out == in) {1138ret = _prj_pt_dbl_monty_aliased(out);1139} else {1140ret = _prj_pt_dbl_monty(out, in);1141}11421143err:1144return ret;1145}11461147/*1148* Internal function:1149*1150* - not supporting aliasing,1151* - requiring caller to check in1 and in2 parameter1152*1153* Based on library configuration, the function either use complete formulas1154* or not.1155*/1156ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_add_monty(prj_pt_t out,1157prj_pt_src_t in1,1158prj_pt_src_t in2)1159{1160#ifndef NO_USE_COMPLETE_FORMULAS1161return __prj_pt_add_monty_cf(out, in1, in2);1162#else1163return __prj_pt_add_monty_no_cf(out, in1, in2);1164#endif1165}11661167/*1168* The function is an internal one that specifically handles aliasing. No check1169* is performed on parameters, this MUST be done by the caller:1170*1171* - in1 and in2 are initialized1172* - in1 and in2 are on the same curve1173*1174* The function will initialize 'out'. The function returns 0 on success, -11175* on error.1176*/1177ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_add_monty_aliased(prj_pt_t out,1178prj_pt_src_t in1,1179prj_pt_src_t in2)1180{1181int ret;1182prj_pt out_cpy;1183out_cpy.magic = WORD(0);11841185ret = _prj_pt_add_monty(&out_cpy, in1, in2); EG(ret, err);1186ret = prj_pt_copy(out, &out_cpy); EG(ret, err);11871188err:1189prj_pt_uninit(&out_cpy);11901191return ret;1192}11931194/*1195* Public function for projective point addition. The function handles the1196* init checks of 'in1' and 'in2' parameters, along with the check they1197* use the same curve. This must be guaranteed for internal functions.1198* 'out' parameter need not be initialized and can be aliased with either1199* 'in1' or 'in2' parameter.1200*1201* The function returns 0 on success, -1 on error.1202*/1203int prj_pt_add(prj_pt_t out, prj_pt_src_t in1, prj_pt_src_t in2)1204{1205int ret;12061207ret = prj_pt_check_initialized(in1); EG(ret, err);1208ret = prj_pt_check_initialized(in2); EG(ret, err);1209MUST_HAVE((in1->crv == in2->crv), ret, err);12101211if ((out == in1) || (out == in2)) {1212ret = _prj_pt_add_monty_aliased(out, in1, in2);1213} else {1214ret = _prj_pt_add_monty(out, in1, in2);1215}12161217err:1218return ret;1219}12201221/*******************************************************************************/1222/****** Scalar multiplication algorithms ***************************************/1223/***********/1224/*1225* The description below summarizes the following algorithms.1226*1227* Double-and-Add-Always and Montgomery Ladder masked using Itoh et al. anti-ADPA1228* (Address-bit DPA) countermeasure.1229* See "A Practical Countermeasure against Address-Bit Differential Power Analysis"1230* by Itoh, Izu and Takenaka for more information.1231*1232* NOTE: these masked variants of the Double-and-Add-Always and Montgomery Ladder algorithms1233* are used by default as Itoh et al. countermeasure has a very small impact on performance1234* and is inherently more robust againt DPA. The only case where we use another variant is1235* for devices with low memory as Itoh requires many temporary variables that consume many1236* temporary stack space.1237*1238* NOTE: the algorithms inherently depend on the MSB of the1239* scalar. In order to avoid leaking this MSB and fall into HNP (Hidden Number1240* Problem) issues, we use the trick described in https://eprint.iacr.org/2011/232.pdf1241* to have the MSB always set. However, since the scalar m might be less or bigger than1242* the order q of the curve, we distinguish three situations:1243* - The scalar m is < q (the order), in this case we compute:1244* -1245* | m' = m + (2 * q) if [log(k + q)] == [log(q)],1246* | m' = m + q otherwise.1247* -1248* - The scalar m is >= q and < q**2, in this case we compute:1249* -1250* | m' = m + (2 * (q**2)) if [log(k + (q**2))] == [log(q**2)],1251* | m' = m + (q**2) otherwise.1252* -1253* - The scalar m is >= (q**2), in this case m == m'1254*1255* => We only deal with 0 <= m < (q**2) using the countermeasure. When m >= (q**2),1256* we stick with m' = m, accepting MSB issues (not much can be done in this case1257* anyways). In the two first cases, Double-and-Add-Always and Montgomery Ladder are1258* performed in constant time wrt the size of the scalar m.1259*/1260/***********/1261/*1262* Internal point blinding function: as it is internal, in is supposed to be initialized and1263* aliasing is NOT supported.1264*/1265ATTRIBUTE_WARN_UNUSED_RET static int _blind_projective_point(prj_pt_t out, prj_pt_src_t in)1266{1267int ret;12681269/* Random for projective coordinates masking */1270/* NOTE: to limit stack usage, we reuse out->Z as a temporary1271* variable. This does not work if in == out, hence the check.1272*/1273MUST_HAVE((in != out), ret, err);12741275ret = prj_pt_init(out, in->crv); EG(ret, err);12761277/* Get a random value l in Fp */1278ret = fp_get_random(&(out->Z), in->X.ctx); EG(ret, err);12791280/*1281* Blind the point with projective coordinates1282* (X, Y, Z) => (l*X, l*Y, l*Z)1283*/1284ret = fp_mul_monty(&(out->X), &(in->X), &(out->Z)); EG(ret, err);1285ret = fp_mul_monty(&(out->Y), &(in->Y), &(out->Z)); EG(ret, err);1286ret = fp_mul_monty(&(out->Z), &(in->Z), &(out->Z));12871288err:1289return ret;1290}12911292/* If nothing is specified regarding the scalar multiplication algorithm, we use1293* the Montgomery Ladder. For the specific case of small stack devices, we release1294* some pressure on the stack by explicitly using double and always WITHOUT the Itoh1295* et al. countermeasure against A-DPA as it is quite consuming.1296*/1297#if defined(USE_SMALL_STACK) && defined(USE_MONTY_LADDER)1298#error "Small stack is only compatible with USE_DOUBLE_ADD_ALWAYS while USE_MONTY_LADDER has been explicitly asked!"1299#endif13001301#if defined(USE_SMALL_STACK)1302#ifndef USE_DOUBLE_ADD_ALWAYS1303#define USE_DOUBLE_ADD_ALWAYS1304#endif1305#endif13061307#if !defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_MONTY_LADDER)1308#define USE_MONTY_LADDER1309#endif13101311#if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_MONTY_LADDER)1312#error "You can either choose USE_DOUBLE_ADD_ALWAYS or USE_MONTY_LADDER, not both!"1313#endif13141315#if defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_SMALL_STACK)1316ATTRIBUTE_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)1317{1318/* We use Itoh et al. notations here for T and the random r */1319prj_pt T[3];1320bitcnt_t mlen;1321u8 mbit, rbit;1322/* Random for masking the Double and Add Always algorithm */1323nn r;1324/* The new scalar we will use with MSB fixed to 1 (noted m' above).1325* This helps dealing with constant time.1326*/1327nn m_msb_fixed;1328nn_src_t curve_order;1329nn curve_order_square;1330int ret, ret_ops, cmp;1331r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0);1332T[0].magic = T[1].magic = T[2].magic = WORD(0);13331334/* Compute m' from m depending on the rule described above */1335curve_order = &(in->crv->order);1336/* First compute q**2 */1337ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err);1338/* Then compute m' depending on m size */1339ret = nn_cmp(m, curve_order, &cmp); EG(ret, err);1340if (cmp < 0){1341bitcnt_t msb_bit_len, order_bitlen;13421343/* Case where m < q */1344ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err);1345ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);1346ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err);1347ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,1348&m_msb_fixed, curve_order); EG(ret, err);1349} else {1350ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err);1351if (cmp < 0) {1352bitcnt_t msb_bit_len, curve_order_square_bitlen;13531354/* Case where m >= q and m < (q**2) */1355ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err);1356ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);1357ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err);1358ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),1359&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err);1360} else {1361/* Case where m >= (q**2) */1362ret = nn_copy(&m_msb_fixed, m); EG(ret, err);1363}1364}1365ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);1366MUST_HAVE(mlen != 0, ret, err);1367mlen--;13681369/* Hide possible internal failures for double and add1370* operations and perform the operation in constant time.1371*/1372ret_ops = 0;13731374/* Get a random r with the same size of m_msb_fixed */1375ret = nn_get_random_len(&r, m_msb_fixed.wlen * WORD_BYTES); EG(ret, err);13761377ret = nn_getbit(&r, mlen, &rbit); EG(ret, err);13781379/* Initialize points */1380ret = prj_pt_init(&T[0], in->crv); EG(ret, err);1381ret = prj_pt_init(&T[1], in->crv); EG(ret, err);13821383/*1384* T[2] = R(P)1385* Blind the point with projective coordinates1386* (X, Y, Z) => (l*X, l*Y, l*Z)1387*/1388ret = _blind_projective_point(&T[2], in); EG(ret, err);13891390/* T[r[n-1]] = T[2] */1391ret = prj_pt_copy(&T[rbit], &T[2]); EG(ret, err);13921393/* Main loop of Double and Add Always */1394while (mlen > 0) {1395u8 rbit_next;1396--mlen;1397/* rbit is r[i+1], and rbit_next is r[i] */1398ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err);13991400/* mbit is m[i] */1401ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err);14021403/* Double: T[r[i+1]] = ECDBL(T[r[i+1]]) */1404#ifndef NO_USE_COMPLETE_FORMULAS1405/*1406* NOTE: in case of complete formulas, we use the1407* addition for doubling, incurring a small performance hit1408* for better SCA resistance.1409*/1410ret_ops |= prj_pt_add(&T[rbit], &T[rbit], &T[rbit]);1411#else1412ret_ops |= prj_pt_dbl(&T[rbit], &T[rbit]);1413#endif1414/* Add: T[1-r[i+1]] = ECADD(T[r[i+1]],T[2]) */1415ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[2]);14161417/*1418* T[r[i]] = T[d[i] ^ r[i+1]]1419* NOTE: we use the low level nn_copy function here to avoid1420* any possible leakage on operands with prj_pt_copy1421*/1422ret = nn_copy(&(T[rbit_next].X.fp_val), &(T[mbit ^ rbit].X.fp_val)); EG(ret, err);1423ret = nn_copy(&(T[rbit_next].Y.fp_val), &(T[mbit ^ rbit].Y.fp_val)); EG(ret, err);1424ret = nn_copy(&(T[rbit_next].Z.fp_val), &(T[mbit ^ rbit].Z.fp_val)); EG(ret, err);14251426/* Update rbit */1427rbit = rbit_next;1428}1429/* Output: T[r[0]] */1430ret = prj_pt_copy(out, &T[rbit]); EG(ret, err);14311432/* Take into consideration our double and add errors */1433ret |= ret_ops;14341435err:1436prj_pt_uninit(&T[0]);1437prj_pt_uninit(&T[1]);1438prj_pt_uninit(&T[2]);1439nn_uninit(&r);1440nn_uninit(&m_msb_fixed);1441nn_uninit(&curve_order_square);14421443PTR_NULLIFY(curve_order);14441445return ret;1446}1447#endif14481449#if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_SMALL_STACK)1450/* NOTE: in small stack case where we compile for low memory devices, we do not use Itoh et al. countermeasure1451* as it requires too much temporary space on the stack.1452*/1453ATTRIBUTE_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)1454{1455int ret, ret_ops;14561457/* Hide possible internal failures for double and add1458* operations and perform the operation in constant time.1459*/1460ret_ops = 0;14611462/* Blind the input point projective coordinates */1463ret = _blind_projective_point(out, in); EG(ret, err);14641465/*******************/1466{1467bitcnt_t mlen;1468u8 mbit;1469/* The new scalar we will use with MSB fixed to 1 (noted m' above).1470* This helps dealing with constant time.1471*/1472nn m_msb_fixed;1473nn_src_t curve_order;1474int cmp;1475m_msb_fixed.magic = WORD(0);14761477{1478nn curve_order_square;1479curve_order_square.magic = WORD(0);14801481/* Compute m' from m depending on the rule described above */1482curve_order = &(in->crv->order);1483/* First compute q**2 */1484ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err1);1485/* Then compute m' depending on m size */1486ret = nn_cmp(m, curve_order, &cmp); EG(ret, err1);1487if (cmp < 0){1488bitcnt_t msb_bit_len, order_bitlen;14891490/* Case where m < q */1491ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err1);1492ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1);1493ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err1);1494ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,1495&m_msb_fixed, curve_order); EG(ret, err1);1496} else {1497ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err1);1498if (cmp < 0) {1499bitcnt_t msb_bit_len, curve_order_square_bitlen;15001501/* Case where m >= q and m < (q**2) */1502ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err1);1503ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1);1504ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err1);1505ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),1506&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err1);1507} else {1508/* Case where m >= (q**2) */1509ret = nn_copy(&m_msb_fixed, m); EG(ret, err1);1510}1511}1512err1:1513nn_uninit(&curve_order_square); EG(ret, err);1514}15151516ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);1517MUST_HAVE((mlen != 0), ret, err);1518mlen--;15191520{1521prj_pt dbl;1522dbl.magic = WORD(0);15231524/* Initialize temporary point */1525ret = prj_pt_init(&dbl, in->crv); EG(ret, err2);15261527/* Main loop of Double and Add Always */1528while (mlen > 0) {1529--mlen;1530/* mbit is m[i] */1531ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err2);15321533#ifndef NO_USE_COMPLETE_FORMULAS1534/*1535* NOTE: in case of complete formulas, we use the1536* addition for doubling, incurring a small performance hit1537* for better SCA resistance.1538*/1539ret_ops |= prj_pt_add(&dbl, out, out);1540#else1541ret_ops |= prj_pt_dbl(&dbl, out);1542#endif1543ret_ops |= prj_pt_add(out, &dbl, in);1544/* Swap */1545ret = nn_cnd_swap(!mbit, &(out->X.fp_val), &(dbl.X.fp_val)); EG(ret, err2);1546ret = nn_cnd_swap(!mbit, &(out->Y.fp_val), &(dbl.Y.fp_val)); EG(ret, err2);1547ret = nn_cnd_swap(!mbit, &(out->Z.fp_val), &(dbl.Z.fp_val)); EG(ret, err2);1548}1549err2:1550prj_pt_uninit(&dbl); EG(ret, err);1551}15521553err:1554nn_uninit(&m_msb_fixed);15551556PTR_NULLIFY(curve_order);1557}15581559/* Take into consideration our double and add errors */1560ret |= ret_ops;15611562return ret;1563}1564#endif156515661567#ifdef USE_MONTY_LADDER1568ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_ladder(prj_pt_t out, nn_src_t m, prj_pt_src_t in)1569{1570/* We use Itoh et al. notations here for T and the random r */1571prj_pt T[3];1572bitcnt_t mlen;1573u8 mbit, rbit;1574/* Random for masking the Montgomery Ladder algorithm */1575nn r;1576/* The new scalar we will use with MSB fixed to 1 (noted m' above).1577* This helps dealing with constant time.1578*/1579nn m_msb_fixed;1580nn_src_t curve_order;1581nn curve_order_square;1582int ret, ret_ops, cmp;1583r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0);1584T[0].magic = T[1].magic = T[2].magic = WORD(0);15851586/* Compute m' from m depending on the rule described above */1587curve_order = &(in->crv->order);15881589/* First compute q**2 */1590ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err);15911592/* Then compute m' depending on m size */1593ret = nn_cmp(m, curve_order, &cmp); EG(ret, err);1594if (cmp < 0) {1595bitcnt_t msb_bit_len, order_bitlen;15961597/* Case where m < q */1598ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err);1599ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);1600ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err);1601ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed,1602&m_msb_fixed, curve_order); EG(ret, err);1603} else {1604ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err);1605if (cmp < 0) {1606bitcnt_t msb_bit_len, curve_order_square_bitlen;16071608/* Case where m >= q and m < (q**2) */1609ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err);1610ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err);1611ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err);1612ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen),1613&m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err);1614} else {1615/* Case where m >= (q**2) */1616ret = nn_copy(&m_msb_fixed, m); EG(ret, err);1617}1618}16191620ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err);1621MUST_HAVE((mlen != 0), ret, err);1622mlen--;16231624/* Hide possible internal failures for double and add1625* operations and perform the operation in constant time.1626*/1627ret_ops = 0;16281629/* Get a random r with the same size of m_msb_fixed */1630ret = nn_get_random_len(&r, (u16)(m_msb_fixed.wlen * WORD_BYTES)); EG(ret, err);16311632ret = nn_getbit(&r, mlen, &rbit); EG(ret, err);16331634/* Initialize points */1635ret = prj_pt_init(&T[0], in->crv); EG(ret, err);1636ret = prj_pt_init(&T[1], in->crv); EG(ret, err);1637ret = prj_pt_init(&T[2], in->crv); EG(ret, err);16381639/* Initialize T[r[n-1]] to input point */1640/*1641* Blind the point with projective coordinates1642* (X, Y, Z) => (l*X, l*Y, l*Z)1643*/1644ret = _blind_projective_point(&T[rbit], in); EG(ret, err);16451646/* Initialize T[1-r[n-1]] with ECDBL(T[r[n-1]])) */1647#ifndef NO_USE_COMPLETE_FORMULAS1648/*1649* NOTE: in case of complete formulas, we use the1650* addition for doubling, incurring a small performance hit1651* for better SCA resistance.1652*/1653ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[rbit]);1654#else1655ret_ops |= prj_pt_dbl(&T[1-rbit], &T[rbit]);1656#endif16571658/* Main loop of the Montgomery Ladder */1659while (mlen > 0) {1660u8 rbit_next;1661--mlen;1662/* rbit is r[i+1], and rbit_next is r[i] */1663ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err);16641665/* mbit is m[i] */1666ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err);1667/* Double: T[2] = ECDBL(T[d[i] ^ r[i+1]]) */16681669#ifndef NO_USE_COMPLETE_FORMULAS1670/* NOTE: in case of complete formulas, we use the1671* addition for doubling, incurring a small performance hit1672* for better SCA resistance.1673*/1674ret_ops |= prj_pt_add(&T[2], &T[mbit ^ rbit], &T[mbit ^ rbit]);1675#else1676ret_ops |= prj_pt_dbl(&T[2], &T[mbit ^ rbit]);1677#endif16781679/* Add: T[1] = ECADD(T[0],T[1]) */1680ret_ops |= prj_pt_add(&T[1], &T[0], &T[1]);16811682/* T[0] = T[2-(d[i] ^ r[i])] */1683/*1684* NOTE: we use the low level nn_copy function here to avoid1685* any possible leakage on operands with prj_pt_copy1686*/1687ret = nn_copy(&(T[0].X.fp_val), &(T[2-(mbit ^ rbit_next)].X.fp_val)); EG(ret, err);1688ret = nn_copy(&(T[0].Y.fp_val), &(T[2-(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err);1689ret = nn_copy(&(T[0].Z.fp_val), &(T[2-(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err);16901691/* T[1] = T[1+(d[i] ^ r[i])] */1692/* NOTE: we use the low level nn_copy function here to avoid1693* any possible leakage on operands with prj_pt_copy1694*/1695ret = nn_copy(&(T[1].X.fp_val), &(T[1+(mbit ^ rbit_next)].X.fp_val)); EG(ret, err);1696ret = nn_copy(&(T[1].Y.fp_val), &(T[1+(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err);1697ret = nn_copy(&(T[1].Z.fp_val), &(T[1+(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err);16981699/* Update rbit */1700rbit = rbit_next;1701}1702/* Output: T[r[0]] */1703ret = prj_pt_copy(out, &T[rbit]); EG(ret, err);17041705/* Take into consideration our double and add errors */1706ret |= ret_ops;17071708err:1709prj_pt_uninit(&T[0]);1710prj_pt_uninit(&T[1]);1711prj_pt_uninit(&T[2]);1712nn_uninit(&r);1713nn_uninit(&m_msb_fixed);1714nn_uninit(&curve_order_square);17151716PTR_NULLIFY(curve_order);17171718return ret;1719}1720#endif17211722/* Main projective scalar multiplication function.1723* Depending on the preprocessing options, we use either the1724* Double and Add Always algorithm, or the Montgomery Ladder one.1725*/1726ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty(prj_pt_t out, nn_src_t m, prj_pt_src_t in){1727#if defined(USE_DOUBLE_ADD_ALWAYS)1728return _prj_pt_mul_ltr_monty_dbl_add_always(out, m, in);1729#elif defined(USE_MONTY_LADDER)1730return _prj_pt_mul_ltr_monty_ladder(out, m, in);1731#else1732#error "Error: neither Double and Add Always nor Montgomery Ladder has been selected!"1733#endif1734}17351736/* version with 'm' passed via 'out'. */1737ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_aliased(prj_pt_t out, nn_src_t m, prj_pt_src_t in)1738{1739prj_pt out_cpy;1740int ret;1741out_cpy.magic = WORD(0);17421743ret = prj_pt_init(&out_cpy, in->crv); EG(ret, err);1744ret = _prj_pt_mul_ltr_monty(&out_cpy, m, in); EG(ret, err);1745ret = prj_pt_copy(out, &out_cpy);17461747err:1748prj_pt_uninit(&out_cpy);1749return ret;1750}17511752/* Aliased version. This is the public main interface of our1753* scalar multiplication algorithm. Checks that the input point1754* and that the output point are on the curve are performed here1755* (before and after calling the core algorithm, albeit Double and1756* Add Always or Montgomery Ladder).1757*/1758int prj_pt_mul(prj_pt_t out, nn_src_t m, prj_pt_src_t in)1759{1760int ret, on_curve;17611762ret = prj_pt_check_initialized(in); EG(ret, err);1763ret = nn_check_initialized(m); EG(ret, err);17641765/* Check that the input is on the curve */1766MUST_HAVE((!prj_pt_is_on_curve(in, &on_curve)) && on_curve, ret, err);17671768if (out == in) {1769ret = _prj_pt_mul_ltr_monty_aliased(out, m, in); EG(ret, err);1770} else {1771ret = _prj_pt_mul_ltr_monty(out, m, in); EG(ret, err);1772}17731774/* Check that the output is on the curve */1775MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err);17761777err:1778return ret;1779}17801781int prj_pt_mul_blind(prj_pt_t out, nn_src_t m, prj_pt_src_t in)1782{1783/* Blind the scalar m with (b*q) where q is the curve order.1784* NOTE: the curve order and the "generator" order are1785* usually the same (i.e. cofactor = 1) for the classical1786* prime fields curves. However some exceptions exist1787* (e.g. Wei25519 and Wei448), and in this case it is1788* curcial to use the curve order for a generic blinding1789* working on any point on the curve.1790*/1791nn b;1792nn_src_t q;1793int ret;1794b.magic = WORD(0);17951796ret = prj_pt_check_initialized(in); EG(ret, err);17971798q = &(in->crv->order);17991800ret = nn_init(&b, 0); EG(ret, err);18011802ret = nn_get_random_mod(&b, q); EG(ret, err);18031804ret = nn_mul(&b, &b, q); EG(ret, err);1805ret = nn_add(&b, &b, m); EG(ret, err);18061807/* NOTE: point blinding is performed in the lower functions */1808/* NOTE: check that input and output points are on the curve are1809* performed in the lower functions.1810*/18111812/* Perform the scalar multiplication */1813ret = prj_pt_mul(out, &b, in);18141815err:1816nn_uninit(&b);18171818PTR_NULLIFY(q);18191820return ret;1821}18221823/* Naive double and add scalar multiplication.1824*1825* This scalar multiplication is used on public values and is optimized with no1826* countermeasures, and it is usually faster as scalar can be small with few bits1827* to process (e.g. cofactors, etc.).1828*1829* out is initialized by the function.1830*1831* XXX: WARNING: this function must only be used on public points!1832*1833*/1834static int __prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in)1835{1836u8 expbit;1837bitcnt_t explen;1838int ret, iszero, on_curve;18391840ret = prj_pt_check_initialized(public_in); EG(ret, err);1841ret = nn_check_initialized(scalar); EG(ret, err);18421843/* This function does not support aliasing */1844MUST_HAVE((out != public_in), ret, err);18451846/* Check that the input is on the curve */1847MUST_HAVE((!prj_pt_is_on_curve(public_in, &on_curve)) && on_curve, ret, err);18481849ret = nn_iszero(scalar, &iszero); EG(ret, err);1850/* Multiplication by zero is the point at infinity */1851if(iszero){1852ret = prj_pt_zero(out); EG(ret, err);1853goto err;1854}18551856ret = nn_bitlen(scalar, &explen); EG(ret, err);1857/* Sanity check */1858MUST_HAVE((explen > 0), ret, err);1859explen = (bitcnt_t)(explen - 1);1860ret = prj_pt_copy(out, public_in); EG(ret, err);18611862while (explen > 0) {1863explen = (bitcnt_t)(explen - 1);1864ret = nn_getbit(scalar, explen, &expbit); EG(ret, err);1865ret = prj_pt_dbl(out, out); EG(ret, err);1866if(expbit){1867ret = prj_pt_add(out, out, public_in); EG(ret, err);1868}1869}18701871/* Check that the output is on the curve */1872MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err);18731874err:1875VAR_ZEROIFY(expbit);1876VAR_ZEROIFY(explen);18771878return ret;1879}18801881/* Aliased version of __prj_pt_unprotected_mult */1882int _prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in)1883{1884int ret;18851886if(out == public_in){1887prj_pt A;1888A.magic = WORD(0);18891890ret = prj_pt_copy(&A, public_in); EG(ret, err1);1891ret = __prj_pt_unprotected_mult(out, scalar, &A);1892err1:1893prj_pt_uninit(&A);1894goto err;1895}1896else{1897ret = __prj_pt_unprotected_mult(out, scalar, public_in);1898}1899err:1900return ret;1901}1902/*1903* Check if an integer is (a multiple of) a projective point order.1904*1905* The function returns 0 on success, -1 on error. The value check is set to 1 if the projective1906* point has order in_isorder, 0 otherwise. The value is meaningless on error.1907*/1908int check_prj_pt_order(prj_pt_src_t in_shortw, nn_src_t in_isorder, prj_pt_sensitivity s, int *check)1909{1910int ret, iszero;1911prj_pt res;1912res.magic = WORD(0);19131914/* First sanity checks */1915ret = prj_pt_check_initialized(in_shortw); EG(ret, err);1916ret = nn_check_initialized(in_isorder); EG(ret, err);1917MUST_HAVE((check != NULL), ret, err);19181919/* Then, perform the scalar multiplication */1920if(s == PUBLIC_PT){1921/* If this is a public point, we can use the naive scalar multiplication */1922ret = _prj_pt_unprotected_mult(&res, in_isorder, in_shortw); EG(ret, err);1923}1924else{1925/* If the point is private, it is sensitive and we proceed with the secure1926* scalar blind multiplication.1927*/1928ret = prj_pt_mul_blind(&res, in_isorder, in_shortw); EG(ret, err);1929}19301931/* Check if we have the point at infinity */1932ret = prj_pt_iszero(&res, &iszero); EG(ret, err);1933(*check) = iszero;19341935err:1936prj_pt_uninit(&res);19371938return ret;1939}19401941/*****************************************************************************/19421943/*1944* Map points from Edwards to short Weierstrass projective points through Montgomery (composition mapping).1945* Point at infinity (0, 1) -> (0, 1, 0) is treated as an exception, which is trivially not constant time.1946* This is OK since our mapping functions should be used at the non sensitive input and output1947* interfaces.1948*1949* The function returns 0 on success, -1 on error.1950*/1951int aff_pt_edwards_to_prj_pt_shortw(aff_pt_edwards_src_t in_edwards,1952ec_shortw_crv_src_t shortw_crv,1953prj_pt_t out_shortw,1954fp_src_t alpha_edwards)1955{1956int ret, iszero, cmp;1957aff_pt out_shortw_aff;1958fp one;1959out_shortw_aff.magic = one.magic = WORD(0);19601961/* Check the curves compatibility */1962ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err);1963ret = curve_edwards_shortw_check(in_edwards->crv, shortw_crv, alpha_edwards); EG(ret, err);19641965/* Initialize output point with curve */1966ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err);19671968ret = fp_init(&one, in_edwards->x.ctx); EG(ret, err);1969ret = fp_one(&one); EG(ret, err);19701971/* Check if we are the point at infinity1972* This check induces a non consant time exception, but the current function must be called on1973* public data anyways.1974*/1975ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);1976ret = fp_cmp(&(in_edwards->y), &one, &cmp); EG(ret, err);1977if(iszero && (cmp == 0)){1978ret = prj_pt_zero(out_shortw); EG(ret, err);1979ret = 0;1980goto err;1981}19821983/* Use the affine mapping */1984ret = aff_pt_edwards_to_shortw(in_edwards, shortw_crv, &out_shortw_aff, alpha_edwards); EG(ret, err);1985/* And then map the short Weierstrass affine to projective coordinates */1986ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff);19871988err:1989fp_uninit(&one);1990aff_pt_uninit(&out_shortw_aff);19911992return ret;1993}19941995/*1996* Map points from short Weierstrass projective points to Edwards through Montgomery (composition mapping).1997* Point at infinity with Z=0 (in projective coordinates) -> (0, 1) is treated as an exception, which is trivially not constant time.1998* This is OK since our mapping functions should be used at the non sensitive input and output1999* interfaces.2000*2001* The function returns 0 on success, -1 on error.2002*/2003int prj_pt_shortw_to_aff_pt_edwards(prj_pt_src_t in_shortw,2004ec_edwards_crv_src_t edwards_crv,2005aff_pt_edwards_t out_edwards,2006fp_src_t alpha_edwards)2007{2008int ret, iszero;2009aff_pt in_shortw_aff;2010in_shortw_aff.magic = WORD(0);20112012/* Check the curves compatibility */2013ret = prj_pt_check_initialized(in_shortw); EG(ret, err);2014ret = curve_edwards_shortw_check(edwards_crv, in_shortw->crv, alpha_edwards); EG(ret, err);20152016/* Initialize output point with curve */2017ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err);20182019/* Check if we are the point at infinity2020* This check induces a non consant time exception, but the current function must be called on2021* public data anyways.2022*/2023ret = prj_pt_iszero(in_shortw, &iszero); EG(ret, err);2024if(iszero){2025fp zero, one;2026zero.magic = one.magic = WORD(0);20272028ret = fp_init(&zero, in_shortw->X.ctx); EG(ret, err1);2029ret = fp_init(&one, in_shortw->X.ctx); EG(ret, err1);20302031ret = fp_zero(&zero); EG(ret, err1);2032ret = fp_one(&one); EG(ret, err1);20332034ret = aff_pt_edwards_init_from_coords(out_edwards, edwards_crv, &zero, &one);20352036err1:2037fp_uninit(&zero);2038fp_uninit(&one);20392040goto err;2041}20422043/* Map projective to affine on the short Weierstrass */2044ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err);2045/* Use the affine mapping */2046ret = aff_pt_shortw_to_edwards(&in_shortw_aff, edwards_crv, out_edwards, alpha_edwards);20472048err:2049aff_pt_uninit(&in_shortw_aff);20502051return ret;2052}20532054/*2055* Map points from Montgomery to short Weierstrass projective points.2056*2057* The function returns 0 on success, -1 on error.2058*/2059int aff_pt_montgomery_to_prj_pt_shortw(aff_pt_montgomery_src_t in_montgomery,2060ec_shortw_crv_src_t shortw_crv,2061prj_pt_t out_shortw)2062{2063int ret;2064aff_pt out_shortw_aff;2065out_shortw_aff.magic = WORD(0);20662067/* Check the curves compatibility */2068ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err);2069ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err);20702071/* Initialize output point with curve */2072ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err);20732074/* Use the affine mapping */2075ret = aff_pt_montgomery_to_shortw(in_montgomery, shortw_crv, &out_shortw_aff); EG(ret, err);2076/* And then map the short Weierstrass affine to projective coordinates */2077ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff);20782079err:2080aff_pt_uninit(&out_shortw_aff);20812082return ret;2083}20842085/*2086* Map points from short Weierstrass projective points to Montgomery.2087*2088* The function returns 0 on success, -1 on error.2089*/2090int 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)2091{2092int ret;2093aff_pt in_shortw_aff;2094in_shortw_aff.magic = WORD(0);20952096/* Check the curves compatibility */2097ret = prj_pt_check_initialized(in_shortw); EG(ret, err);2098ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err);20992100/* Initialize output point with curve */2101ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err);21022103/* Map projective to affine on the short Weierstrass */2104ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err);2105/* Use the affine mapping */2106ret = aff_pt_shortw_to_montgomery(&in_shortw_aff, montgomery_crv, out_montgomery);21072108err:2109aff_pt_uninit(&in_shortw_aff);21102111return ret;2112}211321142115