Path: blob/main/crypto/libecc/src/curves/aff_pt_montgomery.c
34889 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#define AFF_PT_MONTGOMERY_MAGIC ((word_t)(0x7390a9bc43d94598ULL))1314/* Verify that an affine point has already been initialized.15*16* Returns 0 on success, -1 on error.17*/18int aff_pt_montgomery_check_initialized(aff_pt_montgomery_src_t in)19{20int ret;2122MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC)), ret, err);23ret = ec_montgomery_crv_check_initialized(in->crv);2425err:26return ret;27}2829/*30* Initialize pointed aff_pt_montgomery structure to make it usable by library31* function on given curve.32*33* Returns 0 on success, -1 on error.34*/35int aff_pt_montgomery_init(aff_pt_montgomery_t in, ec_montgomery_crv_src_t curve)36{37int ret;3839MUST_HAVE((in != NULL), ret, err);40ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err);4142ret = fp_init(&(in->u), curve->A.ctx); EG(ret, err);43ret = fp_init(&(in->v), curve->A.ctx); EG(ret, err);4445in->crv = curve;46in->magic = AFF_PT_MONTGOMERY_MAGIC;4748err:49return ret;50}5152/*53* Initialize pointed aff_pt_montgomery structure to make it usable by library54* function on given curve with explicit coordinates.55*56* Returns 0 on success, -1 on error.57*/58int aff_pt_montgomery_init_from_coords(aff_pt_montgomery_t in,59ec_montgomery_crv_src_t curve,60fp_src_t ucoord, fp_src_t vcoord)61{62int ret;6364ret = aff_pt_montgomery_init(in, curve); EG(ret, err);65ret = fp_copy(&(in->u), ucoord); EG(ret, err);66ret = fp_copy(&(in->v), vcoord);6768err:69return ret;70}7172/*73* Uninitialize pointed affine point to prevent further use (magic field74* in the structure is zeroized) and zeroize associated storage space.75* Note that the curve context pointed to by the point element (passed76* during init) is left untouched.77*78*/79void aff_pt_montgomery_uninit(aff_pt_montgomery_t in)80{81if ((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC) && (in->crv != NULL)) {82fp_uninit(&(in->u));83fp_uninit(&(in->v));8485in->crv = NULL;86in->magic = WORD(0);87}8889return;90}9192/*93* 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it94* verifies curve equation B*v^2 = u^3 + A*u^2 + u. It is set to 0 otherwise.95* 'on_curve' is not meaningful on error.96*97* Returns 0 on success, -1 on error.98*/99int is_on_montgomery_curve(fp_src_t u, fp_src_t v, ec_montgomery_crv_src_t curve, int *on_curve)100{101fp Bv2, u3, Au2, tmp;102int ret, cmp;103Bv2.magic = u3.magic = Au2.magic = tmp.magic = WORD(0);104105MUST_HAVE((on_curve != NULL), ret, err);106ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err);107108ret = fp_check_initialized(u); EG(ret, err);109ret = fp_check_initialized(v); EG(ret, err);110111MUST_HAVE((u->ctx == v->ctx), ret, err);112MUST_HAVE((u->ctx == curve->A.ctx), ret, err);113114ret = fp_init(&Bv2, v->ctx); EG(ret, err);115ret = fp_sqr(&Bv2, v); EG(ret, err);116ret = fp_mul(&Bv2, &(curve->B), &Bv2); EG(ret, err);117118ret = fp_init(&Au2, u->ctx); EG(ret, err);119ret = fp_sqr(&Au2, u); EG(ret, err);120ret = fp_copy(&u3, &Au2); EG(ret, err);121ret = fp_mul(&Au2, &(curve->A), &Au2); EG(ret, err);122123ret = fp_mul(&u3, &u3, u); EG(ret, err);124125ret = fp_init(&tmp, u->ctx); EG(ret, err);126ret = fp_add(&tmp, &u3, &Au2); EG(ret, err);127ret = fp_add(&tmp, &tmp, u); EG(ret, err);128129ret = fp_cmp(&tmp, &Bv2, &cmp); EG(ret, err);130131(*on_curve) = (!cmp);132133err:134fp_uninit(&Bv2);135fp_uninit(&u3);136fp_uninit(&Au2);137fp_uninit(&tmp);138139return ret;140}141142/* Checks if affine coordinates point is on a Montgomery curve. 'on_curve' is set to 1 if yes,143* 0 if no. 'on_curve' is not meaningful in case of error.144*145* Returns 0 on success, -1 on error.146*/147int aff_pt_montgomery_is_on_curve(aff_pt_montgomery_src_t pt, int *on_curve)148{149int ret;150151ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err);152153ret = is_on_montgomery_curve(&(pt->u), &(pt->v), pt->crv, on_curve);154155err:156return ret;157}158159/* Copy a Montgomery affine point in an output. The output is initialized properly.160*161* Returns 0 on success, -1 on error.162*/163int ec_montgomery_aff_copy(aff_pt_montgomery_t out, aff_pt_montgomery_src_t in)164{165int ret;166167ret = aff_pt_montgomery_check_initialized(in); EG(ret, err);168169ret = aff_pt_montgomery_init(out, in->crv); EG(ret, err);170ret = fp_copy(&(out->u), &(in->u)); EG(ret, err);171ret = fp_copy(&(out->v), &(in->v));172173err:174return ret;175}176177/*178* Compares two given affine points on a Montgomery curve, it returns 0 in input 'cmp' if179* they correspond or not 0 if not. 'cmp' is not meaningful on error.180*181* Returns 0 on success, -1 on error.182*/183int ec_montgomery_aff_cmp(aff_pt_montgomery_src_t in1, aff_pt_montgomery_src_t in2, int *cmp)184{185int ret, cmp1, cmp2;186187MUST_HAVE((cmp != NULL), ret, err);188ret = aff_pt_montgomery_check_initialized(in1); EG(ret, err);189ret = aff_pt_montgomery_check_initialized(in2); EG(ret, err);190MUST_HAVE((in1->crv == in2->crv), ret, err);191192ret = fp_cmp(&(in1->u), &(in2->u), &cmp1); EG(ret, err);193ret = fp_cmp(&(in1->v), &(in2->v), &cmp2); EG(ret, err);194195(*cmp) = (cmp1 | cmp2);196197err:198return ret;199}200201/*202* Import an Montgomery affine point from a buffer with the following layout; the 2203* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len204* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each205* coordinate is encoded in big endian. Size of buffer must exactly match206* 2 * p_len.207*208* Returns 0 on success, -1 on error.209*/210int aff_pt_montgomery_import_from_buf(aff_pt_montgomery_t pt,211const u8 *pt_buf,212u16 pt_buf_len, ec_montgomery_crv_src_t crv)213{214fp_ctx_src_t ctx;215u16 coord_len;216int ret, on_curve;217218ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err);219MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);220221ctx = crv->A.ctx;222coord_len = (u16)BYTECEIL(ctx->p_bitlen);223224MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);225226ret = fp_init_from_buf(&(pt->u), ctx, pt_buf, coord_len); EG(ret, err);227ret = fp_init_from_buf(&(pt->v), ctx, pt_buf + coord_len, coord_len); EG(ret, err);228229/* Set the curve */230pt->crv = crv;231232/* Mark the point as initialized */233pt->magic = AFF_PT_MONTGOMERY_MAGIC;234235/* Check that the point is indeed on the provided curve, uninitialize it236* if this is not the case.237*/238ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err);239if (!on_curve) {240aff_pt_montgomery_uninit(pt);241ret = -1;242}243244err:245return ret;246}247248249/* Export an Montgomery affine point to a buffer with the following layout; the 2250* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len251* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each252* coordinate is encoded in big endian. Size of buffer must exactly match253* 2 * p_len.254*255* Returns 0 on success, -1 on error.256*/257int aff_pt_montgomery_export_to_buf(aff_pt_montgomery_src_t pt, u8 *pt_buf, u32 pt_buf_len)258{259fp_ctx_src_t ctx;260u16 coord_len;261int ret, on_curve;262263ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err);264MUST_HAVE((pt_buf != NULL), ret, err);265266/* The point to be exported must be on the curve */267ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err);268MUST_HAVE(on_curve, ret, err);269270ctx = pt->crv->A.ctx;271coord_len = (u16)BYTECEIL(ctx->p_bitlen);272273MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);274275/* Export the three coordinates */276ret = fp_export_to_buf(pt_buf, coord_len, &(pt->u)); EG(ret, err);277ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->v));278279err:280return ret;281}282283/**** Mappings between curves *************/284/*285* Mapping curves from Montgomery to short Weiertstrass.286*287* M{A, B} is mapped to W{a, b} using the formula:288* a = (3-A^2)/(3*B^2)289* b = (2*A^3-9*A)/(27*B^3)290*291* Returns 0 on success, -1 on error.292*/293int curve_montgomery_to_shortw(ec_montgomery_crv_src_t montgomery_crv, ec_shortw_crv_t shortw_crv)294{295fp tmp, tmp2, a, b;296int ret;297tmp.magic = tmp2.magic = a.magic = b.magic = WORD(0);298299ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);300301ret = fp_init(&tmp, montgomery_crv->A.ctx); EG(ret, err);302ret = fp_init(&tmp2, montgomery_crv->A.ctx); EG(ret, err);303ret = fp_init(&a, montgomery_crv->A.ctx); EG(ret, err);304ret = fp_init(&b, montgomery_crv->A.ctx); EG(ret, err);305306/* Compute a */307ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err);308ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err);309/* 3*B^2 */310ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err);311/* (3*B^2)^-1 */312ret = fp_inv(&tmp, &tmp); EG(ret, err);313314/* (3-A^2) */315ret = fp_sqr(&tmp2, &(montgomery_crv->A)); EG(ret, err);316ret = fp_set_word_value(&a, WORD(3)); EG(ret, err);317ret = fp_sub(&tmp2, &a, &tmp2); EG(ret, err);318319ret = fp_mul(&a, &tmp2, &tmp); EG(ret, err);320321/* Compute b */322ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err);323ret = fp_mul(&tmp, &tmp, &(montgomery_crv->B)); EG(ret, err);324ret = fp_set_word_value(&tmp2, WORD(27)); EG(ret, err);325/* (27*B^3) */326ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err);327/* (27*B^3)^-1 */328ret = fp_inv(&tmp, &tmp); EG(ret, err);329330/* (2*A^3-9*A) */331ret = fp_set_word_value(&tmp2, WORD(2)); EG(ret, err);332ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);333ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);334ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);335336ret = fp_set_word_value(&b, WORD(9)); EG(ret, err);337ret = fp_mul(&b, &b, &(montgomery_crv->A)); EG(ret, err);338ret = fp_sub(&b, &tmp2, &b); EG(ret, err);339340ret = fp_mul(&b, &b, &tmp); EG(ret, err);341342/* Initialize our short Weiertstrass curve */343ret = ec_shortw_crv_init(shortw_crv, &a, &b, &(montgomery_crv->order));344345err:346fp_uninit(&a);347fp_uninit(&b);348fp_uninit(&tmp);349fp_uninit(&tmp2);350351return ret;352}353354/*355* Checks that a short Weiertstrass curve and Montgomery curve are compatible.356*357* Returns 0 on success, -1 on error.358*/359int curve_montgomery_shortw_check(ec_montgomery_crv_src_t montgomery_crv,360ec_shortw_crv_src_t shortw_crv)361{362int ret, cmp;363ec_shortw_crv check;364check.magic = WORD(0);365366ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);367ret = curve_montgomery_to_shortw(montgomery_crv, &check); EG(ret, err);368369/* Check elements */370MUST_HAVE((!fp_cmp(&(check.a), &(shortw_crv->a), &cmp)) && (!cmp), ret, err);371MUST_HAVE((!fp_cmp(&(check.b), &(shortw_crv->b), &cmp)) && (!cmp), ret, err);372MUST_HAVE((!nn_cmp(&(check.order), &(shortw_crv->order), &cmp)) && (!cmp), ret, err);373374err:375ec_shortw_crv_uninit(&check);376377return ret;378}379380/*381* Mapping curves from short Weiertstrass to Montgomery382*383* W{a, b} is mapped to M{A, B} using the formula:384* A = 3 * alpha / gamma385* B = 1 / gamma386* with gamma square root of c = a + 3 * alpha**2387*388* Returns 0 on success, -1 on error.389*/390int curve_shortw_to_montgomery(ec_shortw_crv_src_t shortw_crv,391ec_montgomery_crv_t montgomery_crv,392fp_src_t alpha, fp_src_t gamma)393{394int ret, cmp;395fp c, gamma_inv, A, tmp;396c.magic = gamma_inv.magic = A.magic = tmp.magic = WORD(0);397398ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);399ret = fp_check_initialized(alpha); EG(ret, err);400ret = fp_check_initialized(gamma); EG(ret, err);401MUST_HAVE((alpha->ctx == shortw_crv->a.ctx) && (gamma->ctx == shortw_crv->a.ctx), ret, err);402403ret = fp_init(&A, shortw_crv->a.ctx); EG(ret, err);404ret = fp_init(&gamma_inv, shortw_crv->a.ctx); EG(ret, err);405ret = fp_init(&c, shortw_crv->a.ctx); EG(ret, err);406ret = fp_init(&tmp, shortw_crv->a.ctx); EG(ret, err);407408/* Compute 1 / gamma */409ret = fp_inv(&gamma_inv, gamma); EG(ret, err);410411/* Compute A */412ret = fp_set_word_value(&A, WORD(3)); EG(ret, err);413ret = fp_mul(&A, &A, alpha); EG(ret, err);414ret = fp_mul(&A, &A, &gamma_inv); EG(ret, err);415416/* Sanity check on c */417ret = fp_set_word_value(&c, WORD(3)); EG(ret, err);418ret = fp_mul(&c, &c, alpha); EG(ret, err);419ret = fp_mul(&c, &c, alpha); EG(ret, err);420ret = fp_add(&c, &c, &(shortw_crv->a)); EG(ret, err);421ret = fp_sqr(&tmp, gamma); EG(ret, err);422/* gamma ** 2 must be equal to c */423MUST_HAVE((!fp_cmp(&c, &tmp, &cmp)) && (!cmp), ret, err);424425/* B is simply the inverse of gamma */426ret = ec_montgomery_crv_init(montgomery_crv, &A, &gamma_inv, &(shortw_crv->order));427428err:429fp_uninit(&A);430fp_uninit(&gamma_inv);431fp_uninit(&c);432fp_uninit(&tmp);433434return ret;435}436437/*438* Mapping points from Montgomery to short Weierstrass.439* Point M(u, v) is mapped to W(x, y) with the formula:440* - (x, y) = ((u/B)+(A/3B), v/B)441*442* Returns 0 on success, -1 on error.443*/444int aff_pt_montgomery_to_shortw(aff_pt_montgomery_src_t in_montgomery,445ec_shortw_crv_src_t shortw_crv, aff_pt_t out_shortw)446{447int ret, on_curve;448fp tmp, tmp2;449tmp.magic = tmp2.magic = WORD(0);450451ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);452453/* Check that our input point is on its curve */454MUST_HAVE((!aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve)) && on_curve, ret, err);455456ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err);457ret = fp_init(&tmp2, in_montgomery->crv->A.ctx); EG(ret, err);458459ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err);460ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err);461462ret = aff_pt_init(out_shortw, shortw_crv); EG(ret, err);463464ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err);465ret = fp_mul(&tmp, &tmp, &(in_montgomery->u)); EG(ret, err);466467ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err);468ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->B)); EG(ret, err);469ret = fp_inv(&tmp2, &tmp2); EG(ret, err);470ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->A)); EG(ret, err);471472ret = fp_add(&(out_shortw->x), &tmp, &tmp2); EG(ret, err);473474ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err);475ret = fp_mul(&(out_shortw->y), &tmp, &(in_montgomery->v)); EG(ret, err);476477/* Final check that the point is on the curve */478MUST_HAVE((!aff_pt_is_on_curve(out_shortw, &on_curve)) && on_curve, ret, err);479480err:481fp_uninit(&tmp);482fp_uninit(&tmp2);483484return ret;485}486487/*488* Mapping from short Weierstrass to Montgomery.489* Point W(x, y) is mapped to M(u, v) with the formula:490* - (u, v) = (((Bx)−(A/3), By)491*492* Returns 0 on success, -1 on error.493*/494int aff_pt_shortw_to_montgomery(aff_pt_src_t in_shortw,495ec_montgomery_crv_src_t montgomery_crv,496aff_pt_montgomery_t out_montgomery)497{498int ret, on_curve;499fp tmp, tmp2;500tmp.magic = tmp2.magic = WORD(0);501502ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);503504/* Check that our input point is on its curve */505MUST_HAVE((!aff_pt_is_on_curve(in_shortw, &on_curve)) && on_curve, ret, err);506507ret = fp_init(&tmp, in_shortw->crv->a.ctx); EG(ret, err);508ret = fp_init(&tmp2, in_shortw->crv->a.ctx); EG(ret, err);509510ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err);511512ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err);513514/* A/3 */515ret = fp_inv_word(&tmp, WORD(3)); EG(ret, err);516ret = fp_mul(&tmp, &tmp, &(montgomery_crv->A)); EG(ret, err);517518/* Bx */519ret = fp_mul(&tmp2, &(montgomery_crv->B), &(in_shortw->x)); EG(ret, err);520521/* u = (Bx) - (A/3) */522ret = fp_sub(&(out_montgomery->u), &tmp2, &tmp); EG(ret, err);523524/* v = By */525ret = fp_mul(&(out_montgomery->v), &(montgomery_crv->B), &(in_shortw->y)); EG(ret, err);526527/* Final check that the point is on the curve */528MUST_HAVE((!aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve)) && on_curve, ret, err);529530err:531fp_uninit(&tmp);532fp_uninit(&tmp2);533534return ret;535}536537538/*539* Recover the two possible v coordinates from one u on a given540* curve.541* The two outputs v1 and v2 are initialized in the function.542*543* The function returns -1 on error, 0 on success.544*545*/546int aff_pt_montgomery_v_from_u(fp_t v1, fp_t v2, fp_src_t u, ec_montgomery_crv_src_t crv)547{548int ret;549550/* Sanity checks */551ret = fp_check_initialized(u); EG(ret, err);552ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err);553MUST_HAVE((u->ctx == crv->A.ctx) && (u->ctx == crv->B.ctx), ret, err);554MUST_HAVE((v1 != NULL) && (v2 != NULL), ret, err);555/* Aliasing is not supported */556MUST_HAVE((v1 != v2) && (v1 != u), ret, err);557558/* Initialize v1 and v2 with context */559ret = fp_init(v1, u->ctx); EG(ret, err);560ret = fp_init(v2, u->ctx); EG(ret, err);561562/* v must satisfy the equation B v^2 = u^3 + A u^2 + u,563* so we compute square root for B^-1 * (u^3 + A u^2 + u)564*/565ret = fp_sqr(v2, u); EG(ret, err);566ret = fp_mul(v1, v2, u); EG(ret, err);567ret = fp_mul(v2, v2, &(crv->A)); EG(ret, err);568ret = fp_add(v1, v1, v2); EG(ret, err);569ret = fp_add(v1, v1, u); EG(ret, err);570ret = fp_inv(v2, &(crv->B)); EG(ret, err);571ret = fp_mul(v1, v1, v2); EG(ret, err);572573/* Choose any of the two square roots as the solution */574ret = fp_sqrt(v1, v2, v1);575576err:577return ret;578}579580581