Path: blob/main/crypto/libecc/src/curves/aff_pt.c
105211 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/aff_pt.h>1617#define AFF_PT_MAGIC ((word_t)(0x4c82a9bcd0d9ffabULL))1819/*20* Verify that an affine point has already been initialized. Return 0 on21* success, -1 otherwise.22*/23int aff_pt_check_initialized(aff_pt_src_t in)24{25int ret;2627MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_MAGIC)), ret, err);28ret = ec_shortw_crv_check_initialized(in->crv);2930err:31return ret;32}3334/*35* Initialize pointed aff_pt structure to make it usable by library36* function on given curve. Return 0 on success, -1 on error.37*/38int aff_pt_init(aff_pt_t in, ec_shortw_crv_src_t curve)39{40int ret;4142MUST_HAVE((in != NULL), ret, err);43MUST_HAVE((curve != NULL), ret, err);4445ret = ec_shortw_crv_check_initialized(curve); EG(ret, err);46ret = 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_MAGIC;5152err:53return ret;54}5556/*57* Initialize given point 'in' on given curve 'curve' and set its coordinates to58* 'xcoord' and 'ycoord'. Return 0 on success, -1 on error.59*/60int aff_pt_init_from_coords(aff_pt_t in,61ec_shortw_crv_src_t curve,62fp_src_t xcoord, fp_src_t ycoord)63{64int ret;6566ret = aff_pt_init(in, curve); EG(ret, err);67ret = fp_copy(&(in->x), xcoord); EG(ret, err);68ret = fp_copy(&(in->y), ycoord);6970err:71return ret;72}7374/*75* Uninitialize pointed affine point 'in' to prevent further use (magic field76* in the structure is zeroized) and zeroize associated storage space. Note77* that the curve context pointed to by the point element (passed during init)78* is left untouched.79*/80void aff_pt_uninit(aff_pt_t in)81{82if((in != NULL) && (in->magic == AFF_PT_MAGIC) && (in->crv != NULL)){83in->crv = NULL;84in->magic = WORD(0);8586fp_uninit(&(in->x));87fp_uninit(&(in->y));88}8990return;91}9293/*94* Recover the two possible y coordinates from one x on a given95* curve.96* The two outputs y1 and y2 are initialized in the function.97*98* The function returns -1 on error, 0 on success.99*100*/101int aff_pt_y_from_x(fp_t y1, fp_t y2, fp_src_t x, ec_shortw_crv_src_t curve)102{103int ret;104105MUST_HAVE((y1 != NULL) && (y2 != NULL), ret, err);106ret = ec_shortw_crv_check_initialized(curve); EG(ret, err);107ret = fp_check_initialized(x); EG(ret, err);108/* Aliasing is not supported */109MUST_HAVE((y1 != y2) && (y1 != x), ret, err);110111112/* Initialize our elements */113ret = fp_copy(y1, x); EG(ret, err);114ret = fp_copy(y2, x); EG(ret, err);115116/* Compute x^3 + ax + b */117ret = fp_sqr(y1, y1); EG(ret, err);118ret = fp_mul(y1, y1, x); EG(ret, err);119ret = fp_mul(y2, y2, &(curve->a)); EG(ret, err);120ret = fp_add(y1, y1, y2); EG(ret, err);121ret = fp_add(y1, y1, &(curve->b)); EG(ret, err);122123/* Now compute the two possible square roots124* realizing y^2 = x^3 + ax + b125*/126ret = fp_sqrt(y1, y2, y1);127128err:129return ret;130}131132/*133* Check if given point of coordinate ('x', 'y') is on given curve 'curve' (i.e.134* if it verifies curve equation y^2 = x^3 + ax + b). On success, the verdict is135* given using 'on_curve' out parameter (1 if on curve, 0 if not). On error,136* the function returns -1 and 'on_curve' is left unmodified.137*/138int is_on_shortw_curve(fp_src_t x, fp_src_t y, ec_shortw_crv_src_t curve, int *on_curve)139{140fp tmp1, tmp2;141int ret, cmp;142tmp1.magic = tmp2.magic = WORD(0);143144ret = ec_shortw_crv_check_initialized(curve); EG(ret, err);145ret = fp_check_initialized(x); EG(ret, err);146ret = fp_check_initialized(y); EG(ret, err);147MUST_HAVE((on_curve != NULL), ret, err);148149MUST_HAVE((x->ctx == y->ctx), ret, err);150MUST_HAVE((x->ctx == curve->a.ctx), ret, err);151152/* Note: to optimize local variables, we instead check that153* (y^2 - b) = (x^2 + a) * x154*/155156/* Compute y^2 - b */157ret = fp_init(&tmp1, x->ctx); EG(ret, err);158ret = fp_sqr(&tmp1, y); EG(ret, err);159ret = fp_sub(&tmp1, &tmp1, &(curve->b)); EG(ret, err);160161/* Compute (x^2 + a) * x */162ret = fp_init(&tmp2, x->ctx); EG(ret, err);163ret = fp_sqr(&tmp2, x); EG(ret, err);164ret = fp_add(&tmp2, &tmp2, &(curve->a)); EG(ret, err);165ret = fp_mul(&tmp2, &tmp2, x); EG(ret, err);166167/* Now check*/168ret = fp_cmp(&tmp1, &tmp2, &cmp); EG(ret, err);169170(*on_curve) = (!cmp);171172err:173fp_uninit(&tmp1);174fp_uninit(&tmp2);175176return ret;177}178179/*180* Same as previous but using an affine point instead of pair of coordinates181* and a curve182*/183int aff_pt_is_on_curve(aff_pt_src_t pt, int *on_curve)184{185int ret;186187MUST_HAVE((on_curve != NULL), ret, err);188ret = aff_pt_check_initialized(pt); EG(ret, err);189ret = is_on_shortw_curve(&(pt->x), &(pt->y), pt->crv, on_curve);190191err:192return ret;193}194195/*196* Copy 'in' affine point into 'out'. 'out' is initialized by the function.197* 0 is returned on success, -1 on error.198*/199int ec_shortw_aff_copy(aff_pt_t out, aff_pt_src_t in)200{201int ret;202203ret = aff_pt_check_initialized(in); EG(ret, err);204ret = aff_pt_init(out, in->crv); EG(ret, err);205ret = fp_copy(&(out->x), &(in->x)); EG(ret, err);206ret = fp_copy(&(out->y), &(in->y));207208err:209return ret;210}211212/*213* Compare affine points 'in1' and 'in2'. On success, 0 is returned and214* comparison value is given using 'cmp' (0 if equal, a non-zero value215* if they are different). -1 is returned on error.216*/217int ec_shortw_aff_cmp(aff_pt_src_t in1, aff_pt_src_t in2, int *cmp)218{219int ret, cmp_x, cmp_y;220221MUST_HAVE((cmp != NULL), ret, err);222223ret = aff_pt_check_initialized(in1); EG(ret, err);224ret = aff_pt_check_initialized(in2); EG(ret, err);225226MUST_HAVE((in1->crv == in2->crv), ret, err);227228ret = fp_cmp(&(in1->x), &(in2->x), &cmp_x); EG(ret, err);229ret = fp_cmp(&(in1->y), &(in2->y), &cmp_y); EG(ret, err);230231(*cmp) = (cmp_x | cmp_y);232233err:234return ret;235}236237/*238* Check if given affine points 'in1' and 'in2' on the same curve are equal239* or opposite. On success, 0 is returned and 'aff_is_eq_or_opp' contains:240* - 1 if points are equal or opposite241* - 0 if not242* The function returns -1 on error, in which case 'aff_is_eq_or_opp'243* is left untouched.244*/245int ec_shortw_aff_eq_or_opp(aff_pt_src_t in1, aff_pt_src_t in2,246int *aff_is_eq_or_opp)247{248int ret, cmp, eq_or_opp;249250ret = aff_pt_check_initialized(in1); EG(ret, err);251ret = aff_pt_check_initialized(in2); EG(ret, err);252MUST_HAVE((in1->crv == in2->crv), ret, err);253MUST_HAVE((aff_is_eq_or_opp != NULL), ret, err);254255ret = fp_cmp(&(in1->x), &(in2->x), &cmp); EG(ret, err);256ret = fp_eq_or_opp(&(in1->y), &(in2->y), &eq_or_opp); EG(ret, err);257258(*aff_is_eq_or_opp) = ((cmp == 0) & eq_or_opp);259260err:261return ret;262}263264/*265* Import an affine point from a buffer with the following layout; the 2266* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len267* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each268* coordinate is encoded in big endian. Size of buffer must exactly match269* 2 * p_len. The function returns 0 on success, -1 on error.270*/271int aff_pt_import_from_buf(aff_pt_t pt,272const u8 *pt_buf,273u16 pt_buf_len, ec_shortw_crv_src_t crv)274{275fp_ctx_src_t ctx;276u16 coord_len;277int ret, on_curve;278279MUST_HAVE((pt_buf != NULL), ret, err);280MUST_HAVE((pt != NULL), ret, err);281ret = ec_shortw_crv_check_initialized(crv); EG(ret, err);282283ctx = crv->a.ctx;284coord_len = (u16)BYTECEIL(ctx->p_bitlen);285286MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);287288ret = fp_init_from_buf(&(pt->x), ctx, pt_buf, coord_len); EG(ret, err);289ret = fp_init_from_buf(&(pt->y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);290291/* Set the curve */292pt->crv = crv;293294/* Mark the point as initialized */295pt->magic = AFF_PT_MAGIC;296297/*298* Check that the point is indeed on provided curve, uninitialize it299* if this is not the case.300*/301ret = aff_pt_is_on_curve(pt, &on_curve); EG(ret, err);302303if (!on_curve) {304aff_pt_uninit(pt);305ret = -1;306} else {307ret = 0;308}309310err:311PTR_NULLIFY(ctx);312313return ret;314}315316317/*318* Export an affine point 'pt' to a buffer with the following layout; the 2319* coordinates (elements of Fp) are each encoded on p_len bytes, where p_len320* is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each321* coordinate is encoded in big endian. Size of buffer must exactly match322* 2 * p_len.323*/324int aff_pt_export_to_buf(aff_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len)325{326u16 coord_len;327int ret, on_curve;328329MUST_HAVE((pt_buf != NULL), ret, err);330331/* The point to be exported must be on the curve */332ret = aff_pt_is_on_curve(pt, &on_curve); EG(ret, err);333MUST_HAVE((on_curve), ret, err);334335/* buffer size must match 2 * p_len */336coord_len = (u16)BYTECEIL(pt->crv->a.ctx->p_bitlen);337MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);338339/* Export the two coordinates */340ret = fp_export_to_buf(pt_buf, coord_len, &(pt->x)); EG(ret, err);341ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->y));342343err:344return ret;345}346347348