1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8*f0865ec9SKyle Evans * 9*f0865ec9SKyle Evans * Contributors: 10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12*f0865ec9SKyle Evans * 13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 15*f0865ec9SKyle Evans */ 16*f0865ec9SKyle Evans #include <libecc/curves/aff_pt.h> 17*f0865ec9SKyle Evans 18*f0865ec9SKyle Evans #define AFF_PT_MAGIC ((word_t)(0x4c82a9bcd0d9ffabULL)) 19*f0865ec9SKyle Evans 20*f0865ec9SKyle Evans /* 21*f0865ec9SKyle Evans * Verify that an affine point has already been initialized. Return 0 on 22*f0865ec9SKyle Evans * success, -1 otherwise. 23*f0865ec9SKyle Evans */ 24*f0865ec9SKyle Evans int aff_pt_check_initialized(aff_pt_src_t in) 25*f0865ec9SKyle Evans { 26*f0865ec9SKyle Evans int ret; 27*f0865ec9SKyle Evans 28*f0865ec9SKyle Evans MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_MAGIC)), ret, err); 29*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(in->crv); 30*f0865ec9SKyle Evans 31*f0865ec9SKyle Evans err: 32*f0865ec9SKyle Evans return ret; 33*f0865ec9SKyle Evans } 34*f0865ec9SKyle Evans 35*f0865ec9SKyle Evans /* 36*f0865ec9SKyle Evans * Initialize pointed aff_pt structure to make it usable by library 37*f0865ec9SKyle Evans * function on given curve. Return 0 on success, -1 on error. 38*f0865ec9SKyle Evans */ 39*f0865ec9SKyle Evans int aff_pt_init(aff_pt_t in, ec_shortw_crv_src_t curve) 40*f0865ec9SKyle Evans { 41*f0865ec9SKyle Evans int ret; 42*f0865ec9SKyle Evans 43*f0865ec9SKyle Evans MUST_HAVE((in != NULL), ret, err); 44*f0865ec9SKyle Evans MUST_HAVE((curve != NULL), ret, err); 45*f0865ec9SKyle Evans 46*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(curve); EG(ret, err); 47*f0865ec9SKyle Evans ret = fp_init(&(in->x), curve->a.ctx); EG(ret, err); 48*f0865ec9SKyle Evans ret = fp_init(&(in->y), curve->a.ctx); EG(ret, err); 49*f0865ec9SKyle Evans 50*f0865ec9SKyle Evans in->crv = curve; 51*f0865ec9SKyle Evans in->magic = AFF_PT_MAGIC; 52*f0865ec9SKyle Evans 53*f0865ec9SKyle Evans err: 54*f0865ec9SKyle Evans return ret; 55*f0865ec9SKyle Evans } 56*f0865ec9SKyle Evans 57*f0865ec9SKyle Evans /* 58*f0865ec9SKyle Evans * Initialize given point 'in' on given curve 'curve' and set its coordinates to 59*f0865ec9SKyle Evans * 'xcoord' and 'ycoord'. Return 0 on success, -1 on error. 60*f0865ec9SKyle Evans */ 61*f0865ec9SKyle Evans int aff_pt_init_from_coords(aff_pt_t in, 62*f0865ec9SKyle Evans ec_shortw_crv_src_t curve, 63*f0865ec9SKyle Evans fp_src_t xcoord, fp_src_t ycoord) 64*f0865ec9SKyle Evans { 65*f0865ec9SKyle Evans int ret; 66*f0865ec9SKyle Evans 67*f0865ec9SKyle Evans ret = aff_pt_init(in, curve); EG(ret, err); 68*f0865ec9SKyle Evans ret = fp_copy(&(in->x), xcoord); EG(ret, err); 69*f0865ec9SKyle Evans ret = fp_copy(&(in->y), ycoord); 70*f0865ec9SKyle Evans 71*f0865ec9SKyle Evans err: 72*f0865ec9SKyle Evans return ret; 73*f0865ec9SKyle Evans } 74*f0865ec9SKyle Evans 75*f0865ec9SKyle Evans /* 76*f0865ec9SKyle Evans * Uninitialize pointed affine point 'in' to prevent further use (magic field 77*f0865ec9SKyle Evans * in the structure is zeroized) and zeroize associated storage space. Note 78*f0865ec9SKyle Evans * that the curve context pointed to by the point element (passed during init) 79*f0865ec9SKyle Evans * is left untouched. 80*f0865ec9SKyle Evans */ 81*f0865ec9SKyle Evans void aff_pt_uninit(aff_pt_t in) 82*f0865ec9SKyle Evans { 83*f0865ec9SKyle Evans if((in != NULL) && (in->magic == AFF_PT_MAGIC) && (in->crv != NULL)){ 84*f0865ec9SKyle Evans in->crv = NULL; 85*f0865ec9SKyle Evans in->magic = WORD(0); 86*f0865ec9SKyle Evans 87*f0865ec9SKyle Evans fp_uninit(&(in->x)); 88*f0865ec9SKyle Evans fp_uninit(&(in->y)); 89*f0865ec9SKyle Evans } 90*f0865ec9SKyle Evans 91*f0865ec9SKyle Evans return; 92*f0865ec9SKyle Evans } 93*f0865ec9SKyle Evans 94*f0865ec9SKyle Evans /* 95*f0865ec9SKyle Evans * Recover the two possible y coordinates from one x on a given 96*f0865ec9SKyle Evans * curve. 97*f0865ec9SKyle Evans * The two outputs y1 and y2 are initialized in the function. 98*f0865ec9SKyle Evans * 99*f0865ec9SKyle Evans * The function returns -1 on error, 0 on success. 100*f0865ec9SKyle Evans * 101*f0865ec9SKyle Evans */ 102*f0865ec9SKyle Evans int aff_pt_y_from_x(fp_t y1, fp_t y2, fp_src_t x, ec_shortw_crv_src_t curve) 103*f0865ec9SKyle Evans { 104*f0865ec9SKyle Evans int ret; 105*f0865ec9SKyle Evans 106*f0865ec9SKyle Evans MUST_HAVE((y1 != NULL) && (y2 != NULL), ret, err); 107*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(curve); EG(ret, err); 108*f0865ec9SKyle Evans ret = fp_check_initialized(x); EG(ret, err); 109*f0865ec9SKyle Evans /* Aliasing is not supported */ 110*f0865ec9SKyle Evans MUST_HAVE((y1 != y2) && (y1 != x), ret, err); 111*f0865ec9SKyle Evans 112*f0865ec9SKyle Evans 113*f0865ec9SKyle Evans /* Initialize our elements */ 114*f0865ec9SKyle Evans ret = fp_copy(y1, x); EG(ret, err); 115*f0865ec9SKyle Evans ret = fp_copy(y2, x); EG(ret, err); 116*f0865ec9SKyle Evans 117*f0865ec9SKyle Evans /* Compute x^3 + ax + b */ 118*f0865ec9SKyle Evans ret = fp_sqr(y1, y1); EG(ret, err); 119*f0865ec9SKyle Evans ret = fp_mul(y1, y1, x); EG(ret, err); 120*f0865ec9SKyle Evans ret = fp_mul(y2, y2, &(curve->a)); EG(ret, err); 121*f0865ec9SKyle Evans ret = fp_add(y1, y1, y2); EG(ret, err); 122*f0865ec9SKyle Evans ret = fp_add(y1, y1, &(curve->b)); EG(ret, err); 123*f0865ec9SKyle Evans 124*f0865ec9SKyle Evans /* Now compute the two possible square roots 125*f0865ec9SKyle Evans * realizing y^2 = x^3 + ax + b 126*f0865ec9SKyle Evans */ 127*f0865ec9SKyle Evans ret = fp_sqrt(y1, y2, y1); 128*f0865ec9SKyle Evans 129*f0865ec9SKyle Evans err: 130*f0865ec9SKyle Evans return ret; 131*f0865ec9SKyle Evans } 132*f0865ec9SKyle Evans 133*f0865ec9SKyle Evans /* 134*f0865ec9SKyle Evans * Check if given point of coordinate ('x', 'y') is on given curve 'curve' (i.e. 135*f0865ec9SKyle Evans * if it verifies curve equation y^2 = x^3 + ax + b). On success, the verdict is 136*f0865ec9SKyle Evans * given using 'on_curve' out parameter (1 if on curve, 0 if not). On error, 137*f0865ec9SKyle Evans * the function returns -1 and 'on_curve' is left unmodified. 138*f0865ec9SKyle Evans */ 139*f0865ec9SKyle Evans int is_on_shortw_curve(fp_src_t x, fp_src_t y, ec_shortw_crv_src_t curve, int *on_curve) 140*f0865ec9SKyle Evans { 141*f0865ec9SKyle Evans fp tmp1, tmp2; 142*f0865ec9SKyle Evans int ret, cmp; 143*f0865ec9SKyle Evans tmp1.magic = tmp2.magic = WORD(0); 144*f0865ec9SKyle Evans 145*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(curve); EG(ret, err); 146*f0865ec9SKyle Evans ret = fp_check_initialized(x); EG(ret, err); 147*f0865ec9SKyle Evans ret = fp_check_initialized(y); EG(ret, err); 148*f0865ec9SKyle Evans MUST_HAVE((on_curve != NULL), ret, err); 149*f0865ec9SKyle Evans 150*f0865ec9SKyle Evans MUST_HAVE((x->ctx == y->ctx), ret, err); 151*f0865ec9SKyle Evans MUST_HAVE((x->ctx == curve->a.ctx), ret, err); 152*f0865ec9SKyle Evans 153*f0865ec9SKyle Evans /* Note: to optimize local variables, we instead check that 154*f0865ec9SKyle Evans * (y^2 - b) = (x^2 + a) * x 155*f0865ec9SKyle Evans */ 156*f0865ec9SKyle Evans 157*f0865ec9SKyle Evans /* Compute y^2 - b */ 158*f0865ec9SKyle Evans ret = fp_init(&tmp1, x->ctx); EG(ret, err); 159*f0865ec9SKyle Evans ret = fp_sqr(&tmp1, y); EG(ret, err); 160*f0865ec9SKyle Evans ret = fp_sub(&tmp1, &tmp1, &(curve->b)); EG(ret, err); 161*f0865ec9SKyle Evans 162*f0865ec9SKyle Evans /* Compute (x^2 + a) * x */ 163*f0865ec9SKyle Evans ret = fp_init(&tmp2, x->ctx); EG(ret, err); 164*f0865ec9SKyle Evans ret = fp_sqr(&tmp2, x); EG(ret, err); 165*f0865ec9SKyle Evans ret = fp_add(&tmp2, &tmp2, &(curve->a)); EG(ret, err); 166*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, x); EG(ret, err); 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans /* Now check*/ 169*f0865ec9SKyle Evans ret = fp_cmp(&tmp1, &tmp2, &cmp); EG(ret, err); 170*f0865ec9SKyle Evans 171*f0865ec9SKyle Evans (*on_curve) = (!cmp); 172*f0865ec9SKyle Evans 173*f0865ec9SKyle Evans err: 174*f0865ec9SKyle Evans fp_uninit(&tmp1); 175*f0865ec9SKyle Evans fp_uninit(&tmp2); 176*f0865ec9SKyle Evans 177*f0865ec9SKyle Evans return ret; 178*f0865ec9SKyle Evans } 179*f0865ec9SKyle Evans 180*f0865ec9SKyle Evans /* 181*f0865ec9SKyle Evans * Same as previous but using an affine point instead of pair of coordinates 182*f0865ec9SKyle Evans * and a curve 183*f0865ec9SKyle Evans */ 184*f0865ec9SKyle Evans int aff_pt_is_on_curve(aff_pt_src_t pt, int *on_curve) 185*f0865ec9SKyle Evans { 186*f0865ec9SKyle Evans int ret; 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans MUST_HAVE((on_curve != NULL), ret, err); 189*f0865ec9SKyle Evans ret = aff_pt_check_initialized(pt); EG(ret, err); 190*f0865ec9SKyle Evans ret = is_on_shortw_curve(&(pt->x), &(pt->y), pt->crv, on_curve); 191*f0865ec9SKyle Evans 192*f0865ec9SKyle Evans err: 193*f0865ec9SKyle Evans return ret; 194*f0865ec9SKyle Evans } 195*f0865ec9SKyle Evans 196*f0865ec9SKyle Evans /* 197*f0865ec9SKyle Evans * Copy 'in' affine point into 'out'. 'out' is initialized by the function. 198*f0865ec9SKyle Evans * 0 is returned on success, -1 on error. 199*f0865ec9SKyle Evans */ 200*f0865ec9SKyle Evans int ec_shortw_aff_copy(aff_pt_t out, aff_pt_src_t in) 201*f0865ec9SKyle Evans { 202*f0865ec9SKyle Evans int ret; 203*f0865ec9SKyle Evans 204*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in); EG(ret, err); 205*f0865ec9SKyle Evans ret = aff_pt_init(out, in->crv); EG(ret, err); 206*f0865ec9SKyle Evans ret = fp_copy(&(out->x), &(in->x)); EG(ret, err); 207*f0865ec9SKyle Evans ret = fp_copy(&(out->y), &(in->y)); 208*f0865ec9SKyle Evans 209*f0865ec9SKyle Evans err: 210*f0865ec9SKyle Evans return ret; 211*f0865ec9SKyle Evans } 212*f0865ec9SKyle Evans 213*f0865ec9SKyle Evans /* 214*f0865ec9SKyle Evans * Compare affine points 'in1' and 'in2'. On success, 0 is returned and 215*f0865ec9SKyle Evans * comparison value is given using 'cmp' (0 if equal, a non-zero value 216*f0865ec9SKyle Evans * if they are different). -1 is returned on error. 217*f0865ec9SKyle Evans */ 218*f0865ec9SKyle Evans int ec_shortw_aff_cmp(aff_pt_src_t in1, aff_pt_src_t in2, int *cmp) 219*f0865ec9SKyle Evans { 220*f0865ec9SKyle Evans int ret, cmp_x, cmp_y; 221*f0865ec9SKyle Evans 222*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 223*f0865ec9SKyle Evans 224*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in1); EG(ret, err); 225*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in2); EG(ret, err); 226*f0865ec9SKyle Evans 227*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 228*f0865ec9SKyle Evans 229*f0865ec9SKyle Evans ret = fp_cmp(&(in1->x), &(in2->x), &cmp_x); EG(ret, err); 230*f0865ec9SKyle Evans ret = fp_cmp(&(in1->y), &(in2->y), &cmp_y); EG(ret, err); 231*f0865ec9SKyle Evans 232*f0865ec9SKyle Evans (*cmp) = (cmp_x | cmp_y); 233*f0865ec9SKyle Evans 234*f0865ec9SKyle Evans err: 235*f0865ec9SKyle Evans return ret; 236*f0865ec9SKyle Evans } 237*f0865ec9SKyle Evans 238*f0865ec9SKyle Evans /* 239*f0865ec9SKyle Evans * Check if given affine points 'in1' and 'in2' on the same curve are equal 240*f0865ec9SKyle Evans * or opposite. On success, 0 is returned and 'aff_is_eq_or_opp' contains: 241*f0865ec9SKyle Evans * - 1 if points are equal or opposite 242*f0865ec9SKyle Evans * - 0 if not 243*f0865ec9SKyle Evans * The function returns -1 on error, in which case 'aff_is_eq_or_opp' 244*f0865ec9SKyle Evans * is left untouched. 245*f0865ec9SKyle Evans */ 246*f0865ec9SKyle Evans int ec_shortw_aff_eq_or_opp(aff_pt_src_t in1, aff_pt_src_t in2, 247*f0865ec9SKyle Evans int *aff_is_eq_or_opp) 248*f0865ec9SKyle Evans { 249*f0865ec9SKyle Evans int ret, cmp, eq_or_opp; 250*f0865ec9SKyle Evans 251*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in1); EG(ret, err); 252*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in2); EG(ret, err); 253*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 254*f0865ec9SKyle Evans MUST_HAVE((aff_is_eq_or_opp != NULL), ret, err); 255*f0865ec9SKyle Evans 256*f0865ec9SKyle Evans ret = fp_cmp(&(in1->x), &(in2->x), &cmp); EG(ret, err); 257*f0865ec9SKyle Evans ret = fp_eq_or_opp(&(in1->y), &(in2->y), &eq_or_opp); EG(ret, err); 258*f0865ec9SKyle Evans 259*f0865ec9SKyle Evans (*aff_is_eq_or_opp) = ((cmp == 0) & eq_or_opp); 260*f0865ec9SKyle Evans 261*f0865ec9SKyle Evans err: 262*f0865ec9SKyle Evans return ret; 263*f0865ec9SKyle Evans } 264*f0865ec9SKyle Evans 265*f0865ec9SKyle Evans /* 266*f0865ec9SKyle Evans * Import an affine point from a buffer with the following layout; the 2 267*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 268*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 269*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 270*f0865ec9SKyle Evans * 2 * p_len. The function returns 0 on success, -1 on error. 271*f0865ec9SKyle Evans */ 272*f0865ec9SKyle Evans int aff_pt_import_from_buf(aff_pt_t pt, 273*f0865ec9SKyle Evans const u8 *pt_buf, 274*f0865ec9SKyle Evans u16 pt_buf_len, ec_shortw_crv_src_t crv) 275*f0865ec9SKyle Evans { 276*f0865ec9SKyle Evans fp_ctx_src_t ctx; 277*f0865ec9SKyle Evans u16 coord_len; 278*f0865ec9SKyle Evans int ret, on_curve; 279*f0865ec9SKyle Evans 280*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 281*f0865ec9SKyle Evans MUST_HAVE((pt != NULL), ret, err); 282*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(crv); EG(ret, err); 283*f0865ec9SKyle Evans 284*f0865ec9SKyle Evans ctx = crv->a.ctx; 285*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 286*f0865ec9SKyle Evans 287*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 288*f0865ec9SKyle Evans 289*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->x), ctx, pt_buf, coord_len); EG(ret, err); 290*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->y), ctx, pt_buf + coord_len, coord_len); EG(ret, err); 291*f0865ec9SKyle Evans 292*f0865ec9SKyle Evans /* Set the curve */ 293*f0865ec9SKyle Evans pt->crv = crv; 294*f0865ec9SKyle Evans 295*f0865ec9SKyle Evans /* Mark the point as initialized */ 296*f0865ec9SKyle Evans pt->magic = AFF_PT_MAGIC; 297*f0865ec9SKyle Evans 298*f0865ec9SKyle Evans /* 299*f0865ec9SKyle Evans * Check that the point is indeed on provided curve, uninitialize it 300*f0865ec9SKyle Evans * if this is not the case. 301*f0865ec9SKyle Evans */ 302*f0865ec9SKyle Evans ret = aff_pt_is_on_curve(pt, &on_curve); EG(ret, err); 303*f0865ec9SKyle Evans 304*f0865ec9SKyle Evans if (!on_curve) { 305*f0865ec9SKyle Evans aff_pt_uninit(pt); 306*f0865ec9SKyle Evans ret = -1; 307*f0865ec9SKyle Evans } else { 308*f0865ec9SKyle Evans ret = 0; 309*f0865ec9SKyle Evans } 310*f0865ec9SKyle Evans 311*f0865ec9SKyle Evans err: 312*f0865ec9SKyle Evans PTR_NULLIFY(ctx); 313*f0865ec9SKyle Evans 314*f0865ec9SKyle Evans return ret; 315*f0865ec9SKyle Evans } 316*f0865ec9SKyle Evans 317*f0865ec9SKyle Evans 318*f0865ec9SKyle Evans /* 319*f0865ec9SKyle Evans * Export an affine point 'pt' to a buffer with the following layout; the 2 320*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 321*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 322*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 323*f0865ec9SKyle Evans * 2 * p_len. 324*f0865ec9SKyle Evans */ 325*f0865ec9SKyle Evans int aff_pt_export_to_buf(aff_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len) 326*f0865ec9SKyle Evans { 327*f0865ec9SKyle Evans u16 coord_len; 328*f0865ec9SKyle Evans int ret, on_curve; 329*f0865ec9SKyle Evans 330*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 331*f0865ec9SKyle Evans 332*f0865ec9SKyle Evans /* The point to be exported must be on the curve */ 333*f0865ec9SKyle Evans ret = aff_pt_is_on_curve(pt, &on_curve); EG(ret, err); 334*f0865ec9SKyle Evans MUST_HAVE((on_curve), ret, err); 335*f0865ec9SKyle Evans 336*f0865ec9SKyle Evans /* buffer size must match 2 * p_len */ 337*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(pt->crv->a.ctx->p_bitlen); 338*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 339*f0865ec9SKyle Evans 340*f0865ec9SKyle Evans /* Export the two coordinates */ 341*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf, coord_len, &(pt->x)); EG(ret, err); 342*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->y)); 343*f0865ec9SKyle Evans 344*f0865ec9SKyle Evans err: 345*f0865ec9SKyle Evans return ret; 346*f0865ec9SKyle Evans } 347