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/ec_shortw.h> 17*f0865ec9SKyle Evans #include <libecc/curves/prj_pt.h> 18*f0865ec9SKyle Evans #include <libecc/nn/nn_logical.h> 19*f0865ec9SKyle Evans #include <libecc/nn/nn_add.h> 20*f0865ec9SKyle Evans #include <libecc/nn/nn_rand.h> 21*f0865ec9SKyle Evans #include <libecc/fp/fp_add.h> 22*f0865ec9SKyle Evans #include <libecc/fp/fp_mul.h> 23*f0865ec9SKyle Evans #include <libecc/fp/fp_montgomery.h> 24*f0865ec9SKyle Evans #include <libecc/fp/fp_rand.h> 25*f0865ec9SKyle Evans 26*f0865ec9SKyle Evans #define PRJ_PT_MAGIC ((word_t)(0xe1cd70babb1d5afeULL)) 27*f0865ec9SKyle Evans 28*f0865ec9SKyle Evans /* 29*f0865ec9SKyle Evans * Check given projective point has been correctly initialized (using 30*f0865ec9SKyle Evans * prj_pt_init()). Returns 0 on success, -1 on error. 31*f0865ec9SKyle Evans */ 32*f0865ec9SKyle Evans int prj_pt_check_initialized(prj_pt_src_t in) 33*f0865ec9SKyle Evans { 34*f0865ec9SKyle Evans int ret; 35*f0865ec9SKyle Evans 36*f0865ec9SKyle Evans MUST_HAVE(((in != NULL) && (in->magic == PRJ_PT_MAGIC)), ret, err); 37*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(in->crv); 38*f0865ec9SKyle Evans 39*f0865ec9SKyle Evans err: 40*f0865ec9SKyle Evans return ret; 41*f0865ec9SKyle Evans } 42*f0865ec9SKyle Evans 43*f0865ec9SKyle Evans /* 44*f0865ec9SKyle Evans * Initialize the projective point structure on given curve as the point at 45*f0865ec9SKyle Evans * infinity. The function returns 0 on success, -1 on error. 46*f0865ec9SKyle Evans */ 47*f0865ec9SKyle Evans int prj_pt_init(prj_pt_t in, ec_shortw_crv_src_t curve) 48*f0865ec9SKyle Evans { 49*f0865ec9SKyle Evans int ret; 50*f0865ec9SKyle Evans 51*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(curve); EG(ret, err); 52*f0865ec9SKyle Evans 53*f0865ec9SKyle Evans MUST_HAVE((in != NULL), ret, err); 54*f0865ec9SKyle Evans 55*f0865ec9SKyle Evans ret = fp_init(&(in->X), curve->a.ctx); EG(ret, err); 56*f0865ec9SKyle Evans ret = fp_init(&(in->Y), curve->a.ctx); EG(ret, err); 57*f0865ec9SKyle Evans ret = fp_init(&(in->Z), curve->a.ctx); EG(ret, err); 58*f0865ec9SKyle Evans in->crv = curve; 59*f0865ec9SKyle Evans in->magic = PRJ_PT_MAGIC; 60*f0865ec9SKyle Evans 61*f0865ec9SKyle Evans err: 62*f0865ec9SKyle Evans return ret; 63*f0865ec9SKyle Evans } 64*f0865ec9SKyle Evans 65*f0865ec9SKyle Evans /* 66*f0865ec9SKyle Evans * Initialize the projective point structure on given curve using given 67*f0865ec9SKyle Evans * coordinates. The function returns 0 on success, -1 on error. 68*f0865ec9SKyle Evans */ 69*f0865ec9SKyle Evans int prj_pt_init_from_coords(prj_pt_t in, 70*f0865ec9SKyle Evans ec_shortw_crv_src_t curve, 71*f0865ec9SKyle Evans fp_src_t xcoord, fp_src_t ycoord, fp_src_t zcoord) 72*f0865ec9SKyle Evans { 73*f0865ec9SKyle Evans int ret; 74*f0865ec9SKyle Evans 75*f0865ec9SKyle Evans ret = prj_pt_init(in, curve); EG(ret, err); 76*f0865ec9SKyle Evans ret = fp_copy(&(in->X), xcoord); EG(ret, err); 77*f0865ec9SKyle Evans ret = fp_copy(&(in->Y), ycoord); EG(ret, err); 78*f0865ec9SKyle Evans ret = fp_copy(&(in->Z), zcoord); 79*f0865ec9SKyle Evans 80*f0865ec9SKyle Evans err: 81*f0865ec9SKyle Evans return ret; 82*f0865ec9SKyle Evans } 83*f0865ec9SKyle Evans 84*f0865ec9SKyle Evans /* 85*f0865ec9SKyle Evans * Uninit given projective point structure. The function returns 0 on success, 86*f0865ec9SKyle Evans * -1 on error. This is an error if passed point has not already been 87*f0865ec9SKyle Evans * initialized first. 88*f0865ec9SKyle Evans */ 89*f0865ec9SKyle Evans void prj_pt_uninit(prj_pt_t in) 90*f0865ec9SKyle Evans { 91*f0865ec9SKyle Evans if((in != NULL) && (in->magic == PRJ_PT_MAGIC) && (in->crv != NULL)){ 92*f0865ec9SKyle Evans in->crv = NULL; 93*f0865ec9SKyle Evans in->magic = WORD(0); 94*f0865ec9SKyle Evans 95*f0865ec9SKyle Evans fp_uninit(&(in->X)); 96*f0865ec9SKyle Evans fp_uninit(&(in->Y)); 97*f0865ec9SKyle Evans fp_uninit(&(in->Z)); 98*f0865ec9SKyle Evans } 99*f0865ec9SKyle Evans 100*f0865ec9SKyle Evans return; 101*f0865ec9SKyle Evans } 102*f0865ec9SKyle Evans 103*f0865ec9SKyle Evans /* 104*f0865ec9SKyle Evans * Checks if projective point is the point at infinity (last coordinate is 0). 105*f0865ec9SKyle Evans * In that case, 'iszero' out parameter is set to 1. It is set to 0 if the 106*f0865ec9SKyle Evans * point is not the point at infinity. The function returns 0 on success, -1 on 107*f0865ec9SKyle Evans * error. On error, 'iszero' is not meaningful. 108*f0865ec9SKyle Evans */ 109*f0865ec9SKyle Evans int prj_pt_iszero(prj_pt_src_t in, int *iszero) 110*f0865ec9SKyle Evans { 111*f0865ec9SKyle Evans int ret; 112*f0865ec9SKyle Evans 113*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 114*f0865ec9SKyle Evans ret = fp_iszero(&(in->Z), iszero); 115*f0865ec9SKyle Evans 116*f0865ec9SKyle Evans err: 117*f0865ec9SKyle Evans return ret; 118*f0865ec9SKyle Evans } 119*f0865ec9SKyle Evans 120*f0865ec9SKyle Evans /* 121*f0865ec9SKyle Evans * Set given projective point 'out' to the point at infinity. The functions 122*f0865ec9SKyle Evans * returns 0 on success, -1 on error. 123*f0865ec9SKyle Evans */ 124*f0865ec9SKyle Evans int prj_pt_zero(prj_pt_t out) 125*f0865ec9SKyle Evans { 126*f0865ec9SKyle Evans int ret; 127*f0865ec9SKyle Evans 128*f0865ec9SKyle Evans ret = prj_pt_check_initialized(out); EG(ret, err); 129*f0865ec9SKyle Evans 130*f0865ec9SKyle Evans ret = fp_zero(&(out->X)); EG(ret, err); 131*f0865ec9SKyle Evans ret = fp_one(&(out->Y)); EG(ret, err); 132*f0865ec9SKyle Evans ret = fp_zero(&(out->Z)); 133*f0865ec9SKyle Evans 134*f0865ec9SKyle Evans err: 135*f0865ec9SKyle Evans return ret; 136*f0865ec9SKyle Evans } 137*f0865ec9SKyle Evans 138*f0865ec9SKyle Evans /* 139*f0865ec9SKyle Evans * Check if a projective point is indeed on its curve. The function sets 140*f0865ec9SKyle Evans * 'on_curve' out parameter to 1 if the point is on the curve, 0 if not. 141*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 'on_curve' is not 142*f0865ec9SKyle Evans * meaningful on error. 143*f0865ec9SKyle Evans */ 144*f0865ec9SKyle Evans int prj_pt_is_on_curve(prj_pt_src_t in, int *on_curve) 145*f0865ec9SKyle Evans { 146*f0865ec9SKyle Evans int ret, cmp; 147*f0865ec9SKyle Evans 148*f0865ec9SKyle Evans /* In order to check that we are on the curve, we 149*f0865ec9SKyle Evans * use the projective formula of the curve: 150*f0865ec9SKyle Evans * 151*f0865ec9SKyle Evans * Y**2 * Z = X**3 + a * X * Z**2 + b * Z**3 152*f0865ec9SKyle Evans * 153*f0865ec9SKyle Evans */ 154*f0865ec9SKyle Evans fp X, Y, Z; 155*f0865ec9SKyle Evans X.magic = Y.magic = Z.magic = WORD(0); 156*f0865ec9SKyle Evans 157*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 158*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(in->crv); EG(ret, err); 159*f0865ec9SKyle Evans MUST_HAVE((on_curve != NULL), ret, err); 160*f0865ec9SKyle Evans 161*f0865ec9SKyle Evans ret = fp_init(&X, in->X.ctx); EG(ret, err); 162*f0865ec9SKyle Evans ret = fp_init(&Y, in->X.ctx); EG(ret, err); 163*f0865ec9SKyle Evans ret = fp_init(&Z, in->X.ctx); EG(ret, err); 164*f0865ec9SKyle Evans 165*f0865ec9SKyle Evans /* Compute X**3 + a * X * Z**2 + b * Z**3 on one side */ 166*f0865ec9SKyle Evans ret = fp_sqr(&X, &(in->X)); EG(ret, err); 167*f0865ec9SKyle Evans ret = fp_mul(&X, &X, &(in->X)); EG(ret, err); 168*f0865ec9SKyle Evans ret = fp_mul(&Z, &(in->X), &(in->crv->a)); EG(ret, err); 169*f0865ec9SKyle Evans ret = fp_mul(&Y, &(in->crv->b), &(in->Z)); EG(ret, err); 170*f0865ec9SKyle Evans ret = fp_add(&Z, &Z, &Y); EG(ret, err); 171*f0865ec9SKyle Evans ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err); 172*f0865ec9SKyle Evans ret = fp_mul(&Z, &Z, &(in->Z)); EG(ret, err); 173*f0865ec9SKyle Evans ret = fp_add(&X, &X, &Z); EG(ret, err); 174*f0865ec9SKyle Evans 175*f0865ec9SKyle Evans /* Compute Y**2 * Z on the other side */ 176*f0865ec9SKyle Evans ret = fp_sqr(&Y, &(in->Y)); EG(ret, err); 177*f0865ec9SKyle Evans ret = fp_mul(&Y, &Y, &(in->Z)); EG(ret, err); 178*f0865ec9SKyle Evans 179*f0865ec9SKyle Evans /* Compare the two values */ 180*f0865ec9SKyle Evans ret = fp_cmp(&X, &Y, &cmp); EG(ret, err); 181*f0865ec9SKyle Evans 182*f0865ec9SKyle Evans (*on_curve) = (!cmp); 183*f0865ec9SKyle Evans 184*f0865ec9SKyle Evans err: 185*f0865ec9SKyle Evans fp_uninit(&X); 186*f0865ec9SKyle Evans fp_uninit(&Y); 187*f0865ec9SKyle Evans fp_uninit(&Z); 188*f0865ec9SKyle Evans 189*f0865ec9SKyle Evans return ret; 190*f0865ec9SKyle Evans } 191*f0865ec9SKyle Evans 192*f0865ec9SKyle Evans /* 193*f0865ec9SKyle Evans * The function copies 'in' projective point to 'out'. 'out' is initialized by 194*f0865ec9SKyle Evans * the function. The function returns 0 on sucess, -1 on error. 195*f0865ec9SKyle Evans */ 196*f0865ec9SKyle Evans int prj_pt_copy(prj_pt_t out, prj_pt_src_t in) 197*f0865ec9SKyle Evans { 198*f0865ec9SKyle Evans int ret; 199*f0865ec9SKyle Evans 200*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 201*f0865ec9SKyle Evans 202*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 203*f0865ec9SKyle Evans 204*f0865ec9SKyle Evans ret = fp_copy(&(out->X), &(in->X)); EG(ret, err); 205*f0865ec9SKyle Evans ret = fp_copy(&(out->Y), &(in->Y)); EG(ret, err); 206*f0865ec9SKyle Evans ret = fp_copy(&(out->Z), &(in->Z)); 207*f0865ec9SKyle Evans 208*f0865ec9SKyle Evans err: 209*f0865ec9SKyle Evans return ret; 210*f0865ec9SKyle Evans } 211*f0865ec9SKyle Evans 212*f0865ec9SKyle Evans /* 213*f0865ec9SKyle Evans * Convert given projective point 'in' to affine representation in 'out'. 'out' 214*f0865ec9SKyle Evans * is initialized by the function. The function returns 0 on success, -1 on 215*f0865ec9SKyle Evans * error. Passing the point at infinty to the function is considered as an 216*f0865ec9SKyle Evans * error. 217*f0865ec9SKyle Evans */ 218*f0865ec9SKyle Evans int prj_pt_to_aff(aff_pt_t out, prj_pt_src_t in) 219*f0865ec9SKyle Evans { 220*f0865ec9SKyle Evans int ret, iszero; 221*f0865ec9SKyle Evans 222*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 223*f0865ec9SKyle Evans 224*f0865ec9SKyle Evans ret = prj_pt_iszero(in, &iszero); EG(ret, err); 225*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err); 226*f0865ec9SKyle Evans 227*f0865ec9SKyle Evans ret = aff_pt_init(out, in->crv); EG(ret, err); 228*f0865ec9SKyle Evans 229*f0865ec9SKyle Evans ret = fp_inv(&(out->x), &(in->Z)); EG(ret, err); 230*f0865ec9SKyle Evans ret = fp_mul(&(out->y), &(in->Y), &(out->x)); EG(ret, err); 231*f0865ec9SKyle Evans ret = fp_mul(&(out->x), &(in->X), &(out->x)); 232*f0865ec9SKyle Evans 233*f0865ec9SKyle Evans err: 234*f0865ec9SKyle Evans return ret; 235*f0865ec9SKyle Evans } 236*f0865ec9SKyle Evans 237*f0865ec9SKyle Evans /* 238*f0865ec9SKyle Evans * Get the unique Z = 1 projective point representation ("equivalent" to affine 239*f0865ec9SKyle Evans * point). The function returns 0 on success, -1 on error. 240*f0865ec9SKyle Evans */ 241*f0865ec9SKyle Evans int prj_pt_unique(prj_pt_t out, prj_pt_src_t in) 242*f0865ec9SKyle Evans { 243*f0865ec9SKyle Evans int ret, iszero; 244*f0865ec9SKyle Evans 245*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 246*f0865ec9SKyle Evans ret = prj_pt_iszero(in, &iszero); EG(ret, err); 247*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err); 248*f0865ec9SKyle Evans 249*f0865ec9SKyle Evans if(out == in){ 250*f0865ec9SKyle Evans /* Aliasing case */ 251*f0865ec9SKyle Evans fp tmp; 252*f0865ec9SKyle Evans tmp.magic = WORD(0); 253*f0865ec9SKyle Evans 254*f0865ec9SKyle Evans ret = fp_init(&tmp, (in->Z).ctx); EG(ret, err); 255*f0865ec9SKyle Evans ret = fp_inv(&tmp, &(in->Z)); EG(ret, err1); 256*f0865ec9SKyle Evans ret = fp_mul(&(out->Y), &(in->Y), &tmp); EG(ret, err1); 257*f0865ec9SKyle Evans ret = fp_mul(&(out->X), &(in->X), &tmp); EG(ret, err1); 258*f0865ec9SKyle Evans ret = fp_one(&(out->Z)); EG(ret, err1); 259*f0865ec9SKyle Evans err1: 260*f0865ec9SKyle Evans fp_uninit(&tmp); EG(ret, err); 261*f0865ec9SKyle Evans } 262*f0865ec9SKyle Evans else{ 263*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 264*f0865ec9SKyle Evans ret = fp_inv(&(out->X), &(in->Z)); EG(ret, err); 265*f0865ec9SKyle Evans ret = fp_mul(&(out->Y), &(in->Y), &(out->X)); EG(ret, err); 266*f0865ec9SKyle Evans ret = fp_mul(&(out->X), &(in->X), &(out->X)); EG(ret, err); 267*f0865ec9SKyle Evans ret = fp_one(&(out->Z)); EG(ret, err); 268*f0865ec9SKyle Evans } 269*f0865ec9SKyle Evans 270*f0865ec9SKyle Evans 271*f0865ec9SKyle Evans err: 272*f0865ec9SKyle Evans return ret; 273*f0865ec9SKyle Evans } 274*f0865ec9SKyle Evans 275*f0865ec9SKyle Evans /* 276*f0865ec9SKyle Evans * Converts affine point 'in' to projective representation in 'out'. 'out' is 277*f0865ec9SKyle Evans * initialized by the function. The function returns 0 on success, -1 on error. 278*f0865ec9SKyle Evans */ 279*f0865ec9SKyle Evans int ec_shortw_aff_to_prj(prj_pt_t out, aff_pt_src_t in) 280*f0865ec9SKyle Evans { 281*f0865ec9SKyle Evans int ret, on_curve; 282*f0865ec9SKyle Evans 283*f0865ec9SKyle Evans ret = aff_pt_check_initialized(in); EG(ret, err); 284*f0865ec9SKyle Evans 285*f0865ec9SKyle Evans /* The input affine point must be on the curve */ 286*f0865ec9SKyle Evans ret = aff_pt_is_on_curve(in, &on_curve); EG(ret, err); 287*f0865ec9SKyle Evans MUST_HAVE(on_curve, ret, err); 288*f0865ec9SKyle Evans 289*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 290*f0865ec9SKyle Evans ret = fp_copy(&(out->X), &(in->x)); EG(ret, err); 291*f0865ec9SKyle Evans ret = fp_copy(&(out->Y), &(in->y)); EG(ret, err); 292*f0865ec9SKyle Evans ret = nn_one(&(out->Z).fp_val); /* Z = 1 */ 293*f0865ec9SKyle Evans 294*f0865ec9SKyle Evans err: 295*f0865ec9SKyle Evans return ret; 296*f0865ec9SKyle Evans } 297*f0865ec9SKyle Evans 298*f0865ec9SKyle Evans /* 299*f0865ec9SKyle Evans * Compare projective points 'in1' and 'in2'. On success, 'cmp' is set to 300*f0865ec9SKyle Evans * the result of the comparison (0 if in1 == in2, !0 if in1 != in2). The 301*f0865ec9SKyle Evans * function returns 0 on success, -1 on error. 302*f0865ec9SKyle Evans */ 303*f0865ec9SKyle Evans int prj_pt_cmp(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp) 304*f0865ec9SKyle Evans { 305*f0865ec9SKyle Evans fp X1, X2, Y1, Y2; 306*f0865ec9SKyle Evans int ret, x_cmp, y_cmp; 307*f0865ec9SKyle Evans X1.magic = X2.magic = Y1.magic = Y2.magic = WORD(0); 308*f0865ec9SKyle Evans 309*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 310*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in1); EG(ret, err); 311*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in2); EG(ret, err); 312*f0865ec9SKyle Evans 313*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 314*f0865ec9SKyle Evans 315*f0865ec9SKyle Evans ret = fp_init(&X1, (in1->X).ctx); EG(ret, err); 316*f0865ec9SKyle Evans ret = fp_init(&X2, (in2->X).ctx); EG(ret, err); 317*f0865ec9SKyle Evans ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err); 318*f0865ec9SKyle Evans ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err); 319*f0865ec9SKyle Evans 320*f0865ec9SKyle Evans /* 321*f0865ec9SKyle Evans * Montgomery multiplication is used as it is faster than 322*f0865ec9SKyle Evans * usual multiplication and the spurious multiplicative 323*f0865ec9SKyle Evans * factor does not matter. 324*f0865ec9SKyle Evans */ 325*f0865ec9SKyle Evans ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err); 326*f0865ec9SKyle Evans ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err); 327*f0865ec9SKyle Evans ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err); 328*f0865ec9SKyle Evans ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err); 329*f0865ec9SKyle Evans 330*f0865ec9SKyle Evans ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err); 331*f0865ec9SKyle Evans ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err); 332*f0865ec9SKyle Evans ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err); 333*f0865ec9SKyle Evans ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err); 334*f0865ec9SKyle Evans ret = fp_cmp(&X1, &X2, &x_cmp); EG(ret, err); 335*f0865ec9SKyle Evans ret = fp_cmp(&Y1, &Y2, &y_cmp); 336*f0865ec9SKyle Evans 337*f0865ec9SKyle Evans if (!ret) { 338*f0865ec9SKyle Evans (*cmp) = (x_cmp | y_cmp); 339*f0865ec9SKyle Evans } 340*f0865ec9SKyle Evans 341*f0865ec9SKyle Evans err: 342*f0865ec9SKyle Evans fp_uninit(&Y2); 343*f0865ec9SKyle Evans fp_uninit(&Y1); 344*f0865ec9SKyle Evans fp_uninit(&X2); 345*f0865ec9SKyle Evans fp_uninit(&X1); 346*f0865ec9SKyle Evans 347*f0865ec9SKyle Evans return ret; 348*f0865ec9SKyle Evans } 349*f0865ec9SKyle Evans 350*f0865ec9SKyle Evans /* 351*f0865ec9SKyle Evans * NOTE: this internal functions assumes that upper layer have checked that in1 and in2 352*f0865ec9SKyle Evans * are initialized, and that cmp is not NULL. 353*f0865ec9SKyle Evans */ 354*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_eq_or_opp_X(prj_pt_src_t in1, prj_pt_src_t in2, int *cmp) 355*f0865ec9SKyle Evans { 356*f0865ec9SKyle Evans int ret; 357*f0865ec9SKyle Evans fp X1, X2; 358*f0865ec9SKyle Evans X1.magic = X2.magic = WORD(0); 359*f0865ec9SKyle Evans 360*f0865ec9SKyle Evans /* 361*f0865ec9SKyle Evans * Montgomery multiplication is used as it is faster than 362*f0865ec9SKyle Evans * usual multiplication and the spurious multiplicative 363*f0865ec9SKyle Evans * factor does not matter. 364*f0865ec9SKyle Evans */ 365*f0865ec9SKyle Evans ret = fp_init(&X1, (in1->X).ctx); EG(ret, err); 366*f0865ec9SKyle Evans ret = fp_init(&X2, (in2->X).ctx); EG(ret, err); 367*f0865ec9SKyle Evans ret = fp_mul_monty(&X1, &(in1->X), &(in2->Z)); EG(ret, err); 368*f0865ec9SKyle Evans ret = fp_mul_monty(&X2, &(in2->X), &(in1->Z)); EG(ret, err); 369*f0865ec9SKyle Evans ret = fp_cmp(&X1, &X2, cmp); 370*f0865ec9SKyle Evans 371*f0865ec9SKyle Evans err: 372*f0865ec9SKyle Evans fp_uninit(&X1); 373*f0865ec9SKyle Evans fp_uninit(&X2); 374*f0865ec9SKyle Evans 375*f0865ec9SKyle Evans return ret; 376*f0865ec9SKyle Evans } 377*f0865ec9SKyle Evans 378*f0865ec9SKyle Evans /* 379*f0865ec9SKyle Evans * NOTE: this internal functions assumes that upper layer have checked that in1 and in2 380*f0865ec9SKyle Evans * are initialized, and that eq_or_opp is not NULL. 381*f0865ec9SKyle Evans */ 382*f0865ec9SKyle Evans ATTRIBUTE_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) 383*f0865ec9SKyle Evans { 384*f0865ec9SKyle Evans int ret; 385*f0865ec9SKyle Evans fp Y1, Y2; 386*f0865ec9SKyle Evans Y1.magic = Y2.magic = WORD(0); 387*f0865ec9SKyle Evans 388*f0865ec9SKyle Evans /* 389*f0865ec9SKyle Evans * Montgomery multiplication is used as it is faster than 390*f0865ec9SKyle Evans * usual multiplication and the spurious multiplicative 391*f0865ec9SKyle Evans * factor does not matter. 392*f0865ec9SKyle Evans */ 393*f0865ec9SKyle Evans ret = fp_init(&Y1, (in1->Y).ctx); EG(ret, err); 394*f0865ec9SKyle Evans ret = fp_init(&Y2, (in2->Y).ctx); EG(ret, err); 395*f0865ec9SKyle Evans ret = fp_mul_monty(&Y1, &(in1->Y), &(in2->Z)); EG(ret, err); 396*f0865ec9SKyle Evans ret = fp_mul_monty(&Y2, &(in2->Y), &(in1->Z)); EG(ret, err); 397*f0865ec9SKyle Evans ret = fp_eq_or_opp(&Y1, &Y2, eq_or_opp); 398*f0865ec9SKyle Evans 399*f0865ec9SKyle Evans err: 400*f0865ec9SKyle Evans fp_uninit(&Y1); 401*f0865ec9SKyle Evans fp_uninit(&Y2); 402*f0865ec9SKyle Evans 403*f0865ec9SKyle Evans return ret; 404*f0865ec9SKyle Evans } 405*f0865ec9SKyle Evans 406*f0865ec9SKyle Evans /* 407*f0865ec9SKyle Evans * The functions tests if given projective points 'in1' and 'in2' are equal or 408*f0865ec9SKyle Evans * opposite. On success, the result of the comparison is given via 'eq_or_opp' 409*f0865ec9SKyle Evans * out parameter (1 if equal or opposite, 0 otherwise). The function returns 410*f0865ec9SKyle Evans * 0 on succes, -1 on error. 411*f0865ec9SKyle Evans */ 412*f0865ec9SKyle Evans int prj_pt_eq_or_opp(prj_pt_src_t in1, prj_pt_src_t in2, int *eq_or_opp) 413*f0865ec9SKyle Evans { 414*f0865ec9SKyle Evans int ret, cmp, _eq_or_opp; 415*f0865ec9SKyle Evans 416*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in1); EG(ret, err); 417*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in2); EG(ret, err); 418*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 419*f0865ec9SKyle Evans MUST_HAVE((eq_or_opp != NULL), ret, err); 420*f0865ec9SKyle Evans 421*f0865ec9SKyle Evans ret = _prj_pt_eq_or_opp_X(in1, in2, &cmp); EG(ret, err); 422*f0865ec9SKyle Evans ret = _prj_pt_eq_or_opp_Y(in1, in2, &_eq_or_opp); 423*f0865ec9SKyle Evans 424*f0865ec9SKyle Evans if (!ret) { 425*f0865ec9SKyle Evans (*eq_or_opp) = ((cmp == 0) & _eq_or_opp); 426*f0865ec9SKyle Evans } 427*f0865ec9SKyle Evans 428*f0865ec9SKyle Evans err: 429*f0865ec9SKyle Evans return ret; 430*f0865ec9SKyle Evans } 431*f0865ec9SKyle Evans 432*f0865ec9SKyle Evans /* Compute the opposite of a projective point. Supports aliasing. 433*f0865ec9SKyle Evans * Returns 0 on success, -1 on failure. 434*f0865ec9SKyle Evans */ 435*f0865ec9SKyle Evans int prj_pt_neg(prj_pt_t out, prj_pt_src_t in) 436*f0865ec9SKyle Evans { 437*f0865ec9SKyle Evans int ret; 438*f0865ec9SKyle Evans 439*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 440*f0865ec9SKyle Evans 441*f0865ec9SKyle Evans if (out != in) { /* Copy point if not aliased */ 442*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 443*f0865ec9SKyle Evans ret = prj_pt_copy(out, in); EG(ret, err); 444*f0865ec9SKyle Evans } 445*f0865ec9SKyle Evans 446*f0865ec9SKyle Evans /* Then, negate Y */ 447*f0865ec9SKyle Evans ret = fp_neg(&(out->Y), &(out->Y)); 448*f0865ec9SKyle Evans 449*f0865ec9SKyle Evans err: 450*f0865ec9SKyle Evans return ret; 451*f0865ec9SKyle Evans } 452*f0865ec9SKyle Evans 453*f0865ec9SKyle Evans /* 454*f0865ec9SKyle Evans * Import a projective point from a buffer with the following layout; the 3 455*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 456*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 457*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 458*f0865ec9SKyle Evans * 3 * p_len. The projective point is initialized by the function. 459*f0865ec9SKyle Evans * 460*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 461*f0865ec9SKyle Evans */ 462*f0865ec9SKyle Evans int prj_pt_import_from_buf(prj_pt_t pt, 463*f0865ec9SKyle Evans const u8 *pt_buf, 464*f0865ec9SKyle Evans u16 pt_buf_len, ec_shortw_crv_src_t crv) 465*f0865ec9SKyle Evans { 466*f0865ec9SKyle Evans int on_curve, ret; 467*f0865ec9SKyle Evans fp_ctx_src_t ctx; 468*f0865ec9SKyle Evans u16 coord_len; 469*f0865ec9SKyle Evans 470*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(crv); EG(ret, err); 471*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err); 472*f0865ec9SKyle Evans 473*f0865ec9SKyle Evans ctx = crv->a.ctx; 474*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 475*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err); 476*f0865ec9SKyle Evans 477*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err); 478*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err); 479*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->Z), ctx, pt_buf + (2 * coord_len), coord_len); EG(ret, err); 480*f0865ec9SKyle Evans 481*f0865ec9SKyle Evans /* Set the curve */ 482*f0865ec9SKyle Evans pt->crv = crv; 483*f0865ec9SKyle Evans 484*f0865ec9SKyle Evans /* Mark the point as initialized */ 485*f0865ec9SKyle Evans pt->magic = PRJ_PT_MAGIC; 486*f0865ec9SKyle Evans 487*f0865ec9SKyle Evans /* Check that the point is indeed on the provided curve, uninitialize it 488*f0865ec9SKyle Evans * if this is not the case. 489*f0865ec9SKyle Evans */ 490*f0865ec9SKyle Evans ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err); 491*f0865ec9SKyle Evans if (!on_curve){ 492*f0865ec9SKyle Evans prj_pt_uninit(pt); 493*f0865ec9SKyle Evans ret = -1; 494*f0865ec9SKyle Evans } 495*f0865ec9SKyle Evans 496*f0865ec9SKyle Evans err: 497*f0865ec9SKyle Evans PTR_NULLIFY(ctx); 498*f0865ec9SKyle Evans 499*f0865ec9SKyle Evans return ret; 500*f0865ec9SKyle Evans } 501*f0865ec9SKyle Evans 502*f0865ec9SKyle Evans /* 503*f0865ec9SKyle Evans * Import a projective point from an affine point buffer with the following layout; the 2 504*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 505*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 506*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 507*f0865ec9SKyle Evans * 2 * p_len. The projective point is initialized by the function. 508*f0865ec9SKyle Evans * 509*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 510*f0865ec9SKyle Evans */ 511*f0865ec9SKyle Evans int prj_pt_import_from_aff_buf(prj_pt_t pt, 512*f0865ec9SKyle Evans const u8 *pt_buf, 513*f0865ec9SKyle Evans u16 pt_buf_len, ec_shortw_crv_src_t crv) 514*f0865ec9SKyle Evans { 515*f0865ec9SKyle Evans int ret, on_curve; 516*f0865ec9SKyle Evans fp_ctx_src_t ctx; 517*f0865ec9SKyle Evans u16 coord_len; 518*f0865ec9SKyle Evans 519*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(crv); EG(ret, err); 520*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err); 521*f0865ec9SKyle Evans 522*f0865ec9SKyle Evans ctx = crv->a.ctx; 523*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 524*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 525*f0865ec9SKyle Evans 526*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->X), ctx, pt_buf, coord_len); EG(ret, err); 527*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->Y), ctx, pt_buf + coord_len, coord_len); EG(ret, err); 528*f0865ec9SKyle Evans /* Z coordinate is set to 1 */ 529*f0865ec9SKyle Evans ret = fp_init(&(pt->Z), ctx); EG(ret, err); 530*f0865ec9SKyle Evans ret = fp_one(&(pt->Z)); EG(ret, err); 531*f0865ec9SKyle Evans 532*f0865ec9SKyle Evans /* Set the curve */ 533*f0865ec9SKyle Evans pt->crv = crv; 534*f0865ec9SKyle Evans 535*f0865ec9SKyle Evans /* Mark the point as initialized */ 536*f0865ec9SKyle Evans pt->magic = PRJ_PT_MAGIC; 537*f0865ec9SKyle Evans 538*f0865ec9SKyle Evans /* Check that the point is indeed on the provided curve, uninitialize it 539*f0865ec9SKyle Evans * if this is not the case. 540*f0865ec9SKyle Evans */ 541*f0865ec9SKyle Evans ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err); 542*f0865ec9SKyle Evans if (!on_curve){ 543*f0865ec9SKyle Evans prj_pt_uninit(pt); 544*f0865ec9SKyle Evans ret = -1; 545*f0865ec9SKyle Evans } 546*f0865ec9SKyle Evans 547*f0865ec9SKyle Evans err: 548*f0865ec9SKyle Evans PTR_NULLIFY(ctx); 549*f0865ec9SKyle Evans 550*f0865ec9SKyle Evans return ret; 551*f0865ec9SKyle Evans } 552*f0865ec9SKyle Evans 553*f0865ec9SKyle Evans 554*f0865ec9SKyle Evans /* Export a projective point to a buffer with the following layout; the 3 555*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 556*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 557*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 558*f0865ec9SKyle Evans * 3 * p_len. 559*f0865ec9SKyle Evans * 560*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 561*f0865ec9SKyle Evans */ 562*f0865ec9SKyle Evans int prj_pt_export_to_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len) 563*f0865ec9SKyle Evans { 564*f0865ec9SKyle Evans fp_ctx_src_t ctx; 565*f0865ec9SKyle Evans u16 coord_len; 566*f0865ec9SKyle Evans int ret, on_curve; 567*f0865ec9SKyle Evans 568*f0865ec9SKyle Evans ret = prj_pt_check_initialized(pt); EG(ret, err); 569*f0865ec9SKyle Evans 570*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 571*f0865ec9SKyle Evans 572*f0865ec9SKyle Evans /* The point to be exported must be on the curve */ 573*f0865ec9SKyle Evans ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err); 574*f0865ec9SKyle Evans MUST_HAVE((on_curve), ret, err); 575*f0865ec9SKyle Evans 576*f0865ec9SKyle Evans ctx = pt->crv->a.ctx; 577*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 578*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (3 * coord_len)), ret, err); 579*f0865ec9SKyle Evans 580*f0865ec9SKyle Evans /* Export the three coordinates */ 581*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf, coord_len, &(pt->X)); EG(ret, err); 582*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->Y)); EG(ret, err); 583*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf + (2 * coord_len), coord_len, &(pt->Z)); 584*f0865ec9SKyle Evans 585*f0865ec9SKyle Evans err: 586*f0865ec9SKyle Evans PTR_NULLIFY(ctx); 587*f0865ec9SKyle Evans 588*f0865ec9SKyle Evans return ret; 589*f0865ec9SKyle Evans } 590*f0865ec9SKyle Evans 591*f0865ec9SKyle Evans /* 592*f0865ec9SKyle Evans * Export a projective point to an affine point buffer with the following 593*f0865ec9SKyle Evans * layout; the 2 coordinates (elements of Fp) are each encoded on p_len bytes, 594*f0865ec9SKyle Evans * where p_len is the size of p in bytes (e.g. 66 for a prime p of 521 bits). 595*f0865ec9SKyle Evans * Each coordinate is encoded in big endian. Size of buffer must exactly match 596*f0865ec9SKyle Evans * 2 * p_len. 597*f0865ec9SKyle Evans * 598*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 599*f0865ec9SKyle Evans */ 600*f0865ec9SKyle Evans int prj_pt_export_to_aff_buf(prj_pt_src_t pt, u8 *pt_buf, u32 pt_buf_len) 601*f0865ec9SKyle Evans { 602*f0865ec9SKyle Evans int ret, on_curve; 603*f0865ec9SKyle Evans aff_pt tmp_aff; 604*f0865ec9SKyle Evans tmp_aff.magic = WORD(0); 605*f0865ec9SKyle Evans 606*f0865ec9SKyle Evans ret = prj_pt_check_initialized(pt); EG(ret, err); 607*f0865ec9SKyle Evans 608*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 609*f0865ec9SKyle Evans 610*f0865ec9SKyle Evans /* The point to be exported must be on the curve */ 611*f0865ec9SKyle Evans ret = prj_pt_is_on_curve(pt, &on_curve); EG(ret, err); 612*f0865ec9SKyle Evans MUST_HAVE((on_curve), ret, err); 613*f0865ec9SKyle Evans 614*f0865ec9SKyle Evans /* Move to the affine unique representation */ 615*f0865ec9SKyle Evans ret = prj_pt_to_aff(&tmp_aff, pt); EG(ret, err); 616*f0865ec9SKyle Evans 617*f0865ec9SKyle Evans /* Export the affine point to the buffer */ 618*f0865ec9SKyle Evans ret = aff_pt_export_to_buf(&tmp_aff, pt_buf, pt_buf_len); 619*f0865ec9SKyle Evans 620*f0865ec9SKyle Evans err: 621*f0865ec9SKyle Evans aff_pt_uninit(&tmp_aff); 622*f0865ec9SKyle Evans 623*f0865ec9SKyle Evans return ret; 624*f0865ec9SKyle Evans } 625*f0865ec9SKyle Evans 626*f0865ec9SKyle Evans 627*f0865ec9SKyle Evans #ifdef NO_USE_COMPLETE_FORMULAS 628*f0865ec9SKyle Evans 629*f0865ec9SKyle Evans /* 630*f0865ec9SKyle Evans * The function is an internal one: no check is performed on parameters, 631*f0865ec9SKyle Evans * this MUST be done by the caller: 632*f0865ec9SKyle Evans * 633*f0865ec9SKyle Evans * - in is initialized 634*f0865ec9SKyle Evans * - in and out must not be aliased 635*f0865ec9SKyle Evans * 636*f0865ec9SKyle Evans * The function will initialize 'out'. The function returns 0 on success, -1 637*f0865ec9SKyle Evans * on error. 638*f0865ec9SKyle Evans */ 639*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_no_cf(prj_pt_t out, prj_pt_src_t in) 640*f0865ec9SKyle Evans { 641*f0865ec9SKyle Evans fp XX, ZZ, w, s, ss, sss, R, RR, B, h; 642*f0865ec9SKyle Evans int ret; 643*f0865ec9SKyle Evans XX.magic = ZZ.magic = w.magic = s.magic = WORD(0); 644*f0865ec9SKyle Evans ss.magic = sss.magic = R.magic = WORD(0); 645*f0865ec9SKyle Evans RR.magic = B.magic = h.magic = WORD(0); 646*f0865ec9SKyle Evans 647*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 648*f0865ec9SKyle Evans 649*f0865ec9SKyle Evans ret = fp_init(&XX, out->crv->a.ctx); EG(ret, err); 650*f0865ec9SKyle Evans ret = fp_init(&ZZ, out->crv->a.ctx); EG(ret, err); 651*f0865ec9SKyle Evans ret = fp_init(&w, out->crv->a.ctx); EG(ret, err); 652*f0865ec9SKyle Evans ret = fp_init(&s, out->crv->a.ctx); EG(ret, err); 653*f0865ec9SKyle Evans ret = fp_init(&ss, out->crv->a.ctx); EG(ret, err); 654*f0865ec9SKyle Evans ret = fp_init(&sss, out->crv->a.ctx); EG(ret, err); 655*f0865ec9SKyle Evans ret = fp_init(&R, out->crv->a.ctx); EG(ret, err); 656*f0865ec9SKyle Evans ret = fp_init(&RR, out->crv->a.ctx); EG(ret, err); 657*f0865ec9SKyle Evans ret = fp_init(&B, out->crv->a.ctx); EG(ret, err); 658*f0865ec9SKyle Evans ret = fp_init(&h, out->crv->a.ctx); EG(ret, err); 659*f0865ec9SKyle Evans 660*f0865ec9SKyle Evans /* XX = X1² */ 661*f0865ec9SKyle Evans ret = fp_sqr_monty(&XX, &(in->X)); EG(ret, err); 662*f0865ec9SKyle Evans 663*f0865ec9SKyle Evans /* ZZ = Z1² */ 664*f0865ec9SKyle Evans ret = fp_sqr_monty(&ZZ, &(in->Z)); EG(ret, err); 665*f0865ec9SKyle Evans 666*f0865ec9SKyle Evans /* w = a*ZZ+3*XX */ 667*f0865ec9SKyle Evans ret = fp_mul_monty(&w, &(in->crv->a_monty), &ZZ); EG(ret, err); 668*f0865ec9SKyle Evans ret = fp_add_monty(&w, &w, &XX); EG(ret, err); 669*f0865ec9SKyle Evans ret = fp_add_monty(&w, &w, &XX); EG(ret, err); 670*f0865ec9SKyle Evans ret = fp_add_monty(&w, &w, &XX); EG(ret, err); 671*f0865ec9SKyle Evans 672*f0865ec9SKyle Evans /* s = 2*Y1*Z1 */ 673*f0865ec9SKyle Evans ret = fp_mul_monty(&s, &(in->Y), &(in->Z)); EG(ret, err); 674*f0865ec9SKyle Evans ret = fp_add_monty(&s, &s, &s); EG(ret, err); 675*f0865ec9SKyle Evans 676*f0865ec9SKyle Evans /* ss = s² */ 677*f0865ec9SKyle Evans ret = fp_sqr_monty(&ss, &s); EG(ret, err); 678*f0865ec9SKyle Evans 679*f0865ec9SKyle Evans /* sss = s*ss */ 680*f0865ec9SKyle Evans ret = fp_mul_monty(&sss, &s, &ss); EG(ret, err); 681*f0865ec9SKyle Evans 682*f0865ec9SKyle Evans /* R = Y1*s */ 683*f0865ec9SKyle Evans ret = fp_mul_monty(&R, &(in->Y), &s); EG(ret, err); 684*f0865ec9SKyle Evans 685*f0865ec9SKyle Evans /* RR = R² */ 686*f0865ec9SKyle Evans ret = fp_sqr_monty(&RR, &R); EG(ret, err); 687*f0865ec9SKyle Evans 688*f0865ec9SKyle Evans /* B = (X1+R)²-XX-RR */ 689*f0865ec9SKyle Evans ret = fp_add_monty(&R, &R, &(in->X)); EG(ret, err); 690*f0865ec9SKyle Evans ret = fp_sqr_monty(&B, &R); EG(ret, err); 691*f0865ec9SKyle Evans ret = fp_sub_monty(&B, &B, &XX); EG(ret, err); 692*f0865ec9SKyle Evans ret = fp_sub_monty(&B, &B, &RR); EG(ret, err); 693*f0865ec9SKyle Evans 694*f0865ec9SKyle Evans /* h = w²-2*B */ 695*f0865ec9SKyle Evans ret = fp_sqr_monty(&h, &w); EG(ret, err); 696*f0865ec9SKyle Evans ret = fp_sub_monty(&h, &h, &B); EG(ret, err); 697*f0865ec9SKyle Evans ret = fp_sub_monty(&h, &h, &B); EG(ret, err); 698*f0865ec9SKyle Evans 699*f0865ec9SKyle Evans /* X3 = h*s */ 700*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->X), &h, &s); EG(ret, err); 701*f0865ec9SKyle Evans 702*f0865ec9SKyle Evans /* Y3 = w*(B-h)-2*RR */ 703*f0865ec9SKyle Evans ret = fp_sub_monty(&B, &B, &h); EG(ret, err); 704*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->Y), &w, &B); EG(ret, err); 705*f0865ec9SKyle Evans ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err); 706*f0865ec9SKyle Evans ret = fp_sub_monty(&(out->Y), &(out->Y), &RR); EG(ret, err); 707*f0865ec9SKyle Evans 708*f0865ec9SKyle Evans /* Z3 = sss */ 709*f0865ec9SKyle Evans ret = fp_copy(&(out->Z), &sss); 710*f0865ec9SKyle Evans 711*f0865ec9SKyle Evans err: 712*f0865ec9SKyle Evans fp_uninit(&XX); 713*f0865ec9SKyle Evans fp_uninit(&ZZ); 714*f0865ec9SKyle Evans fp_uninit(&w); 715*f0865ec9SKyle Evans fp_uninit(&s); 716*f0865ec9SKyle Evans fp_uninit(&ss); 717*f0865ec9SKyle Evans fp_uninit(&sss); 718*f0865ec9SKyle Evans fp_uninit(&R); 719*f0865ec9SKyle Evans fp_uninit(&RR); 720*f0865ec9SKyle Evans fp_uninit(&B); 721*f0865ec9SKyle Evans fp_uninit(&h); 722*f0865ec9SKyle Evans 723*f0865ec9SKyle Evans return ret; 724*f0865ec9SKyle Evans } 725*f0865ec9SKyle Evans 726*f0865ec9SKyle Evans /* 727*f0865ec9SKyle Evans * The function is an internal one: no check is performed on parameters, 728*f0865ec9SKyle Evans * this MUST be done by the caller: 729*f0865ec9SKyle Evans * 730*f0865ec9SKyle Evans * - in1 and in2 are initialized 731*f0865ec9SKyle Evans * - in1 and in2 are on the same curve 732*f0865ec9SKyle Evans * - in1/in2 and out must not be aliased 733*f0865ec9SKyle Evans * - in1 and in2 must not be equal, opposite or have identical value 734*f0865ec9SKyle Evans * 735*f0865ec9SKyle Evans * The function will initialize 'out'. The function returns 0 on success, -1 736*f0865ec9SKyle Evans * on error. 737*f0865ec9SKyle Evans */ 738*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int ___prj_pt_add_monty_no_cf(prj_pt_t out, 739*f0865ec9SKyle Evans prj_pt_src_t in1, 740*f0865ec9SKyle Evans prj_pt_src_t in2) 741*f0865ec9SKyle Evans { 742*f0865ec9SKyle Evans fp Y1Z2, X1Z2, Z1Z2, u, uu, v, vv, vvv, R, A; 743*f0865ec9SKyle Evans int ret; 744*f0865ec9SKyle Evans Y1Z2.magic = X1Z2.magic = Z1Z2.magic = u.magic = uu.magic = v.magic = WORD(0); 745*f0865ec9SKyle Evans vv.magic = vvv.magic = R.magic = A.magic = WORD(0); 746*f0865ec9SKyle Evans 747*f0865ec9SKyle Evans ret = prj_pt_init(out, in1->crv); EG(ret, err); 748*f0865ec9SKyle Evans 749*f0865ec9SKyle Evans ret = fp_init(&Y1Z2, out->crv->a.ctx); EG(ret, err); 750*f0865ec9SKyle Evans ret = fp_init(&X1Z2, out->crv->a.ctx); EG(ret, err); 751*f0865ec9SKyle Evans ret = fp_init(&Z1Z2, out->crv->a.ctx); EG(ret, err); 752*f0865ec9SKyle Evans ret = fp_init(&u, out->crv->a.ctx); EG(ret, err); 753*f0865ec9SKyle Evans ret = fp_init(&uu, out->crv->a.ctx); EG(ret, err); 754*f0865ec9SKyle Evans ret = fp_init(&v, out->crv->a.ctx); EG(ret, err); 755*f0865ec9SKyle Evans ret = fp_init(&vv, out->crv->a.ctx); EG(ret, err); 756*f0865ec9SKyle Evans ret = fp_init(&vvv, out->crv->a.ctx); EG(ret, err); 757*f0865ec9SKyle Evans ret = fp_init(&R, out->crv->a.ctx); EG(ret, err); 758*f0865ec9SKyle Evans ret = fp_init(&A, out->crv->a.ctx); EG(ret, err); 759*f0865ec9SKyle Evans 760*f0865ec9SKyle Evans /* Y1Z2 = Y1*Z2 */ 761*f0865ec9SKyle Evans ret = fp_mul_monty(&Y1Z2, &(in1->Y), &(in2->Z)); EG(ret, err); 762*f0865ec9SKyle Evans 763*f0865ec9SKyle Evans /* X1Z2 = X1*Z2 */ 764*f0865ec9SKyle Evans ret = fp_mul_monty(&X1Z2, &(in1->X), &(in2->Z)); EG(ret, err); 765*f0865ec9SKyle Evans 766*f0865ec9SKyle Evans /* Z1Z2 = Z1*Z2 */ 767*f0865ec9SKyle Evans ret = fp_mul_monty(&Z1Z2, &(in1->Z), &(in2->Z)); EG(ret, err); 768*f0865ec9SKyle Evans 769*f0865ec9SKyle Evans /* u = Y2*Z1-Y1Z2 */ 770*f0865ec9SKyle Evans ret = fp_mul_monty(&u, &(in2->Y), &(in1->Z)); EG(ret, err); 771*f0865ec9SKyle Evans ret = fp_sub_monty(&u, &u, &Y1Z2); EG(ret, err); 772*f0865ec9SKyle Evans 773*f0865ec9SKyle Evans /* uu = u² */ 774*f0865ec9SKyle Evans ret = fp_sqr_monty(&uu, &u); EG(ret, err); 775*f0865ec9SKyle Evans 776*f0865ec9SKyle Evans /* v = X2*Z1-X1Z2 */ 777*f0865ec9SKyle Evans ret = fp_mul_monty(&v, &(in2->X), &(in1->Z)); EG(ret, err); 778*f0865ec9SKyle Evans ret = fp_sub_monty(&v, &v, &X1Z2); EG(ret, err); 779*f0865ec9SKyle Evans 780*f0865ec9SKyle Evans /* vv = v² */ 781*f0865ec9SKyle Evans ret = fp_sqr_monty(&vv, &v); EG(ret, err); 782*f0865ec9SKyle Evans 783*f0865ec9SKyle Evans /* vvv = v*vv */ 784*f0865ec9SKyle Evans ret = fp_mul_monty(&vvv, &v, &vv); EG(ret, err); 785*f0865ec9SKyle Evans 786*f0865ec9SKyle Evans /* R = vv*X1Z2 */ 787*f0865ec9SKyle Evans ret = fp_mul_monty(&R, &vv, &X1Z2); EG(ret, err); 788*f0865ec9SKyle Evans 789*f0865ec9SKyle Evans /* A = uu*Z1Z2-vvv-2*R */ 790*f0865ec9SKyle Evans ret = fp_mul_monty(&A, &uu, &Z1Z2); EG(ret, err); 791*f0865ec9SKyle Evans ret = fp_sub_monty(&A, &A, &vvv); EG(ret, err); 792*f0865ec9SKyle Evans ret = fp_sub_monty(&A, &A, &R); EG(ret, err); 793*f0865ec9SKyle Evans ret = fp_sub_monty(&A, &A, &R); EG(ret, err); 794*f0865ec9SKyle Evans 795*f0865ec9SKyle Evans /* X3 = v*A */ 796*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->X), &v, &A); EG(ret, err); 797*f0865ec9SKyle Evans 798*f0865ec9SKyle Evans /* Y3 = u*(R-A)-vvv*Y1Z2 */ 799*f0865ec9SKyle Evans ret = fp_sub_monty(&R, &R, &A); EG(ret, err); 800*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->Y), &u, &R); EG(ret, err); 801*f0865ec9SKyle Evans ret = fp_mul_monty(&R, &vvv, &Y1Z2); EG(ret, err); 802*f0865ec9SKyle Evans ret = fp_sub_monty(&(out->Y), &(out->Y), &R); EG(ret, err); 803*f0865ec9SKyle Evans 804*f0865ec9SKyle Evans /* Z3 = vvv*Z1Z2 */ 805*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->Z), &vvv, &Z1Z2); 806*f0865ec9SKyle Evans 807*f0865ec9SKyle Evans err: 808*f0865ec9SKyle Evans fp_uninit(&Y1Z2); 809*f0865ec9SKyle Evans fp_uninit(&X1Z2); 810*f0865ec9SKyle Evans fp_uninit(&Z1Z2); 811*f0865ec9SKyle Evans fp_uninit(&u); 812*f0865ec9SKyle Evans fp_uninit(&uu); 813*f0865ec9SKyle Evans fp_uninit(&v); 814*f0865ec9SKyle Evans fp_uninit(&vv); 815*f0865ec9SKyle Evans fp_uninit(&vvv); 816*f0865ec9SKyle Evans fp_uninit(&R); 817*f0865ec9SKyle Evans fp_uninit(&A); 818*f0865ec9SKyle Evans 819*f0865ec9SKyle Evans return ret; 820*f0865ec9SKyle Evans } 821*f0865ec9SKyle Evans 822*f0865ec9SKyle Evans /* 823*f0865ec9SKyle Evans * Public version of the addition w/o complete formulas to handle the case 824*f0865ec9SKyle Evans * where the inputs are zero or opposite. Returns 0 on success, -1 on error. 825*f0865ec9SKyle Evans */ 826*f0865ec9SKyle Evans ATTRIBUTE_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) 827*f0865ec9SKyle Evans { 828*f0865ec9SKyle Evans int ret, iszero, eq_or_opp, cmp; 829*f0865ec9SKyle Evans 830*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in1); EG(ret, err); 831*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in2); EG(ret, err); 832*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 833*f0865ec9SKyle Evans 834*f0865ec9SKyle Evans ret = prj_pt_iszero(in1, &iszero); EG(ret, err); 835*f0865ec9SKyle Evans if (iszero) { 836*f0865ec9SKyle Evans /* in1 at infinity, output in2 in all cases */ 837*f0865ec9SKyle Evans ret = prj_pt_init(out, in2->crv); EG(ret, err); 838*f0865ec9SKyle Evans ret = prj_pt_copy(out, in2); EG(ret, err); 839*f0865ec9SKyle Evans } else { 840*f0865ec9SKyle Evans /* in1 not at infinity, output in2 */ 841*f0865ec9SKyle Evans ret = prj_pt_iszero(in2, &iszero); EG(ret, err); 842*f0865ec9SKyle Evans if (iszero) { 843*f0865ec9SKyle Evans /* in2 at infinity, output in1 */ 844*f0865ec9SKyle Evans ret = prj_pt_init(out, in1->crv); EG(ret, err); 845*f0865ec9SKyle Evans ret = prj_pt_copy(out, in1); EG(ret, err); 846*f0865ec9SKyle Evans } else { 847*f0865ec9SKyle Evans /* enither in1, nor in2 at infinity */ 848*f0865ec9SKyle Evans 849*f0865ec9SKyle Evans /* 850*f0865ec9SKyle Evans * The following test which guarantees in1 and in2 are not 851*f0865ec9SKyle Evans * equal or opposite needs to be rewritten because it 852*f0865ec9SKyle Evans * has a *HUGE* impact on perf (ec_self_tests run on 853*f0865ec9SKyle Evans * all test vectors takes 24 times as long with this 854*f0865ec9SKyle Evans * enabled). The same exists in non monty version. 855*f0865ec9SKyle Evans */ 856*f0865ec9SKyle Evans ret = prj_pt_eq_or_opp(in1, in2, &eq_or_opp); EG(ret, err); 857*f0865ec9SKyle Evans if (eq_or_opp) { 858*f0865ec9SKyle Evans /* in1 and in2 are either equal or opposite */ 859*f0865ec9SKyle Evans ret = prj_pt_cmp(in1, in2, &cmp); EG(ret, err); 860*f0865ec9SKyle Evans if (cmp == 0) { 861*f0865ec9SKyle Evans /* in1 == in2 => doubling w/o cf */ 862*f0865ec9SKyle Evans ret = __prj_pt_dbl_monty_no_cf(out, in1); EG(ret, err); 863*f0865ec9SKyle Evans } else { 864*f0865ec9SKyle Evans /* in1 == -in2 => output zero (point at infinity) */ 865*f0865ec9SKyle Evans ret = prj_pt_init(out, in1->crv); EG(ret, err); 866*f0865ec9SKyle Evans ret = prj_pt_zero(out); EG(ret, err); 867*f0865ec9SKyle Evans } 868*f0865ec9SKyle Evans } else { 869*f0865ec9SKyle Evans /* 870*f0865ec9SKyle Evans * in1 and in2 are neither 0, nor equal or 871*f0865ec9SKyle Evans * opposite. Use the basic monty addition 872*f0865ec9SKyle Evans * implementation w/o complete formulas. 873*f0865ec9SKyle Evans */ 874*f0865ec9SKyle Evans ret = ___prj_pt_add_monty_no_cf(out, in1, in2); EG(ret, err); 875*f0865ec9SKyle Evans } 876*f0865ec9SKyle Evans } 877*f0865ec9SKyle Evans } 878*f0865ec9SKyle Evans 879*f0865ec9SKyle Evans err: 880*f0865ec9SKyle Evans return ret; 881*f0865ec9SKyle Evans } 882*f0865ec9SKyle Evans 883*f0865ec9SKyle Evans 884*f0865ec9SKyle Evans #else /* NO_USE_COMPLETE_FORMULAS */ 885*f0865ec9SKyle Evans 886*f0865ec9SKyle Evans 887*f0865ec9SKyle Evans /* 888*f0865ec9SKyle Evans * If NO_USE_COMPLETE_FORMULAS flag is not defined addition formulas from Algorithm 3 889*f0865ec9SKyle Evans * of https://joostrenes.nl/publications/complete.pdf are used, otherwise 890*f0865ec9SKyle Evans * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl 891*f0865ec9SKyle Evans */ 892*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_dbl_monty_cf(prj_pt_t out, prj_pt_src_t in) 893*f0865ec9SKyle Evans { 894*f0865ec9SKyle Evans fp t0, t1, t2, t3; 895*f0865ec9SKyle Evans int ret; 896*f0865ec9SKyle Evans t0.magic = t1.magic = t2.magic = t3.magic = WORD(0); 897*f0865ec9SKyle Evans 898*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 899*f0865ec9SKyle Evans 900*f0865ec9SKyle Evans ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err); 901*f0865ec9SKyle Evans ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err); 902*f0865ec9SKyle Evans ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err); 903*f0865ec9SKyle Evans ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err); 904*f0865ec9SKyle Evans 905*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &in->X, &in->X); EG(ret, err); 906*f0865ec9SKyle Evans ret = fp_mul_monty(&t1, &in->Y, &in->Y); EG(ret, err); 907*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in->Z, &in->Z); EG(ret, err); 908*f0865ec9SKyle Evans ret = fp_mul_monty(&t3, &in->X, &in->Y); EG(ret, err); 909*f0865ec9SKyle Evans ret = fp_add_monty(&t3, &t3, &t3); EG(ret, err); 910*f0865ec9SKyle Evans 911*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Z, &in->X, &in->Z); EG(ret, err); 912*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err); 913*f0865ec9SKyle Evans ret = fp_mul_monty(&out->X, &in->crv->a_monty, &out->Z); EG(ret, err); 914*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Y, &in->crv->b3_monty, &t2); EG(ret, err); 915*f0865ec9SKyle Evans ret = fp_add_monty(&out->Y, &out->X, &out->Y); EG(ret, err); 916*f0865ec9SKyle Evans 917*f0865ec9SKyle Evans ret = fp_sub_monty(&out->X, &t1, &out->Y); EG(ret, err); 918*f0865ec9SKyle Evans ret = fp_add_monty(&out->Y, &t1, &out->Y); EG(ret, err); 919*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Y, &out->X, &out->Y); EG(ret, err); 920*f0865ec9SKyle Evans ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err); 921*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Z, &in->crv->b3_monty, &out->Z); EG(ret, err); 922*f0865ec9SKyle Evans 923*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in->crv->a_monty, &t2); EG(ret, err); 924*f0865ec9SKyle Evans ret = fp_sub_monty(&t3, &t0, &t2); EG(ret, err); 925*f0865ec9SKyle Evans ret = fp_mul_monty(&t3, &in->crv->a_monty, &t3); EG(ret, err); 926*f0865ec9SKyle Evans ret = fp_add_monty(&t3, &t3, &out->Z); EG(ret, err); 927*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &t0, &t0); EG(ret, err); 928*f0865ec9SKyle Evans 929*f0865ec9SKyle Evans ret = fp_add_monty(&t0, &out->Z, &t0); EG(ret, err); 930*f0865ec9SKyle Evans ret = fp_add_monty(&t0, &t0, &t2); EG(ret, err); 931*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &t0, &t3); EG(ret, err); 932*f0865ec9SKyle Evans ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err); 933*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in->Y, &in->Z); EG(ret, err); 934*f0865ec9SKyle Evans 935*f0865ec9SKyle Evans ret = fp_add_monty(&t2, &t2, &t2); EG(ret, err); 936*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &t2, &t3); EG(ret, err); 937*f0865ec9SKyle Evans ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err); 938*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Z, &t2, &t1); EG(ret, err); 939*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &out->Z, &out->Z); EG(ret, err); 940*f0865ec9SKyle Evans 941*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &out->Z, &out->Z); 942*f0865ec9SKyle Evans 943*f0865ec9SKyle Evans err: 944*f0865ec9SKyle Evans fp_uninit(&t0); 945*f0865ec9SKyle Evans fp_uninit(&t1); 946*f0865ec9SKyle Evans fp_uninit(&t2); 947*f0865ec9SKyle Evans fp_uninit(&t3); 948*f0865ec9SKyle Evans 949*f0865ec9SKyle Evans return ret; 950*f0865ec9SKyle Evans } 951*f0865ec9SKyle Evans 952*f0865ec9SKyle Evans /* 953*f0865ec9SKyle Evans * If NO_USE_COMPLETE_FORMULAS flag is not defined addition formulas from Algorithm 1 954*f0865ec9SKyle Evans * of https://joostrenes.nl/publications/complete.pdf are used, otherwise 955*f0865ec9SKyle Evans * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 956*f0865ec9SKyle Evans */ 957*f0865ec9SKyle Evans 958*f0865ec9SKyle Evans /* 959*f0865ec9SKyle Evans * The function is an internal one: no check is performed on parameters, 960*f0865ec9SKyle Evans * this MUST be done by the caller: 961*f0865ec9SKyle Evans * 962*f0865ec9SKyle Evans * - in1 and in2 are initialized 963*f0865ec9SKyle Evans * - in1 and in2 are on the same curve 964*f0865ec9SKyle Evans * - in1/in2 and out must not be aliased 965*f0865ec9SKyle Evans * - in1 and in2 must not be an "exceptional" pair, i.e. (in1-in2) is not a point 966*f0865ec9SKyle Evans * of order exactly 2 967*f0865ec9SKyle Evans * 968*f0865ec9SKyle Evans * The function will initialize 'out'. The function returns 0 on success, -1 969*f0865ec9SKyle Evans * on error. 970*f0865ec9SKyle Evans */ 971*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int __prj_pt_add_monty_cf(prj_pt_t out, 972*f0865ec9SKyle Evans prj_pt_src_t in1, 973*f0865ec9SKyle Evans prj_pt_src_t in2) 974*f0865ec9SKyle Evans { 975*f0865ec9SKyle Evans int cmp1, cmp2; 976*f0865ec9SKyle Evans fp t0, t1, t2, t3, t4, t5; 977*f0865ec9SKyle Evans int ret; 978*f0865ec9SKyle Evans t0.magic = t1.magic = t2.magic = WORD(0); 979*f0865ec9SKyle Evans t3.magic = t4.magic = t5.magic = WORD(0); 980*f0865ec9SKyle Evans 981*f0865ec9SKyle Evans ret = prj_pt_init(out, in1->crv); EG(ret, err); 982*f0865ec9SKyle Evans 983*f0865ec9SKyle Evans ret = fp_init(&t0, out->crv->a.ctx); EG(ret, err); 984*f0865ec9SKyle Evans ret = fp_init(&t1, out->crv->a.ctx); EG(ret, err); 985*f0865ec9SKyle Evans ret = fp_init(&t2, out->crv->a.ctx); EG(ret, err); 986*f0865ec9SKyle Evans ret = fp_init(&t3, out->crv->a.ctx); EG(ret, err); 987*f0865ec9SKyle Evans ret = fp_init(&t4, out->crv->a.ctx); EG(ret, err); 988*f0865ec9SKyle Evans ret = fp_init(&t5, out->crv->a.ctx); EG(ret, err); 989*f0865ec9SKyle Evans 990*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &in1->X, &in2->X); EG(ret, err); 991*f0865ec9SKyle Evans ret = fp_mul_monty(&t1, &in1->Y, &in2->Y); EG(ret, err); 992*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in1->Z, &in2->Z); EG(ret, err); 993*f0865ec9SKyle Evans ret = fp_add_monty(&t3, &in1->X, &in1->Y); EG(ret, err); 994*f0865ec9SKyle Evans ret = fp_add_monty(&t4, &in2->X, &in2->Y); EG(ret, err); 995*f0865ec9SKyle Evans 996*f0865ec9SKyle Evans ret = fp_mul_monty(&t3, &t3, &t4); EG(ret, err); 997*f0865ec9SKyle Evans ret = fp_add_monty(&t4, &t0, &t1); EG(ret, err); 998*f0865ec9SKyle Evans ret = fp_sub_monty(&t3, &t3, &t4); EG(ret, err); 999*f0865ec9SKyle Evans ret = fp_add_monty(&t4, &in1->X, &in1->Z); EG(ret, err); 1000*f0865ec9SKyle Evans ret = fp_add_monty(&t5, &in2->X, &in2->Z); EG(ret, err); 1001*f0865ec9SKyle Evans 1002*f0865ec9SKyle Evans ret = fp_mul_monty(&t4, &t4, &t5); EG(ret, err); 1003*f0865ec9SKyle Evans ret = fp_add_monty(&t5, &t0, &t2); EG(ret, err); 1004*f0865ec9SKyle Evans ret = fp_sub_monty(&t4, &t4, &t5); EG(ret, err); 1005*f0865ec9SKyle Evans ret = fp_add_monty(&t5, &in1->Y, &in1->Z); EG(ret, err); 1006*f0865ec9SKyle Evans ret = fp_add_monty(&out->X, &in2->Y, &in2->Z); EG(ret, err); 1007*f0865ec9SKyle Evans 1008*f0865ec9SKyle Evans ret = fp_mul_monty(&t5, &t5, &out->X); EG(ret, err); 1009*f0865ec9SKyle Evans ret = fp_add_monty(&out->X, &t1, &t2); EG(ret, err); 1010*f0865ec9SKyle Evans ret = fp_sub_monty(&t5, &t5, &out->X); EG(ret, err); 1011*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Z, &in1->crv->a_monty, &t4); EG(ret, err); 1012*f0865ec9SKyle Evans ret = fp_mul_monty(&out->X, &in1->crv->b3_monty, &t2); EG(ret, err); 1013*f0865ec9SKyle Evans 1014*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &out->X, &out->Z); EG(ret, err); 1015*f0865ec9SKyle Evans ret = fp_sub_monty(&out->X, &t1, &out->Z); EG(ret, err); 1016*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &t1, &out->Z); EG(ret, err); 1017*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Y, &out->X, &out->Z); EG(ret, err); 1018*f0865ec9SKyle Evans ret = fp_add_monty(&t1, &t0, &t0); EG(ret, err); 1019*f0865ec9SKyle Evans 1020*f0865ec9SKyle Evans ret = fp_add_monty(&t1, &t1, &t0); EG(ret, err); 1021*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err); 1022*f0865ec9SKyle Evans ret = fp_mul_monty(&t4, &in1->crv->b3_monty, &t4); EG(ret, err); 1023*f0865ec9SKyle Evans ret = fp_add_monty(&t1, &t1, &t2); EG(ret, err); 1024*f0865ec9SKyle Evans ret = fp_sub_monty(&t2, &t0, &t2); EG(ret, err); 1025*f0865ec9SKyle Evans 1026*f0865ec9SKyle Evans ret = fp_mul_monty(&t2, &in1->crv->a_monty, &t2); EG(ret, err); 1027*f0865ec9SKyle Evans ret = fp_add_monty(&t4, &t4, &t2); EG(ret, err); 1028*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &t1, &t4); EG(ret, err); 1029*f0865ec9SKyle Evans ret = fp_add_monty(&out->Y, &out->Y, &t0); EG(ret, err); 1030*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &t5, &t4); EG(ret, err); 1031*f0865ec9SKyle Evans 1032*f0865ec9SKyle Evans ret = fp_mul_monty(&out->X, &t3, &out->X); EG(ret, err); 1033*f0865ec9SKyle Evans ret = fp_sub_monty(&out->X, &out->X, &t0); EG(ret, err); 1034*f0865ec9SKyle Evans ret = fp_mul_monty(&t0, &t3, &t1); EG(ret, err); 1035*f0865ec9SKyle Evans ret = fp_mul_monty(&out->Z, &t5, &out->Z); EG(ret, err); 1036*f0865ec9SKyle Evans ret = fp_add_monty(&out->Z, &out->Z, &t0); 1037*f0865ec9SKyle Evans 1038*f0865ec9SKyle Evans /* Check for "exceptional" pairs of input points with 1039*f0865ec9SKyle Evans * checking if Y = Z = 0 as output (see the Bosma-Lenstra 1040*f0865ec9SKyle Evans * article "Complete Systems of Two Addition Laws for 1041*f0865ec9SKyle Evans * Elliptic Curves"). This should only happen on composite 1042*f0865ec9SKyle Evans * order curves (i.e. not on prime order curves). 1043*f0865ec9SKyle Evans * 1044*f0865ec9SKyle Evans * In this case, we raise an error as the result is 1045*f0865ec9SKyle Evans * not sound. This should not happen in our nominal 1046*f0865ec9SKyle Evans * cases with regular signature and protocols, and if 1047*f0865ec9SKyle Evans * it happens this usually means that bad points have 1048*f0865ec9SKyle Evans * been injected. 1049*f0865ec9SKyle Evans * 1050*f0865ec9SKyle Evans * NOTE: if for some reasons you need to deal with 1051*f0865ec9SKyle Evans * all the possible pairs of points including these 1052*f0865ec9SKyle Evans * exceptional pairs of inputs with an order 2 difference, 1053*f0865ec9SKyle Evans * you should fallback to the incomplete formulas using the 1054*f0865ec9SKyle Evans * COMPLETE=0 compilation toggle. Beware that in this 1055*f0865ec9SKyle Evans * case, the library will be more sensitive to 1056*f0865ec9SKyle Evans * side-channel attacks. 1057*f0865ec9SKyle Evans */ 1058*f0865ec9SKyle Evans ret = fp_iszero(&(out->Z), &cmp1); EG(ret, err); 1059*f0865ec9SKyle Evans ret = fp_iszero(&(out->Y), &cmp2); EG(ret, err); 1060*f0865ec9SKyle Evans MUST_HAVE(!((cmp1) && (cmp2)), ret, err); 1061*f0865ec9SKyle Evans 1062*f0865ec9SKyle Evans err: 1063*f0865ec9SKyle Evans fp_uninit(&t0); 1064*f0865ec9SKyle Evans fp_uninit(&t1); 1065*f0865ec9SKyle Evans fp_uninit(&t2); 1066*f0865ec9SKyle Evans fp_uninit(&t3); 1067*f0865ec9SKyle Evans fp_uninit(&t4); 1068*f0865ec9SKyle Evans fp_uninit(&t5); 1069*f0865ec9SKyle Evans 1070*f0865ec9SKyle Evans return ret; 1071*f0865ec9SKyle Evans } 1072*f0865ec9SKyle Evans #endif /* NO_USE_COMPLETE_FORMULAS */ 1073*f0865ec9SKyle Evans 1074*f0865ec9SKyle Evans /* 1075*f0865ec9SKyle Evans * Internal function: 1076*f0865ec9SKyle Evans * 1077*f0865ec9SKyle Evans * - not supporting aliasing, 1078*f0865ec9SKyle Evans * - requiring caller to check in parameter is initialized 1079*f0865ec9SKyle Evans * 1080*f0865ec9SKyle Evans * Based on library configuration, the function either use complete formulas 1081*f0865ec9SKyle Evans * or not. 1082*f0865ec9SKyle Evans */ 1083*f0865ec9SKyle Evans static int _prj_pt_dbl_monty(prj_pt_t out, prj_pt_src_t in) 1084*f0865ec9SKyle Evans { 1085*f0865ec9SKyle Evans int ret; 1086*f0865ec9SKyle Evans 1087*f0865ec9SKyle Evans #ifdef NO_USE_COMPLETE_FORMULAS 1088*f0865ec9SKyle Evans int iszero; 1089*f0865ec9SKyle Evans ret = prj_pt_iszero(in, &iszero); EG(ret, err); 1090*f0865ec9SKyle Evans if (iszero) { 1091*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 1092*f0865ec9SKyle Evans ret = prj_pt_zero(out); 1093*f0865ec9SKyle Evans } else { 1094*f0865ec9SKyle Evans ret = __prj_pt_dbl_monty_no_cf(out, in); 1095*f0865ec9SKyle Evans } 1096*f0865ec9SKyle Evans #else 1097*f0865ec9SKyle Evans ret = __prj_pt_dbl_monty_cf(out, in); EG(ret, err); 1098*f0865ec9SKyle Evans #endif 1099*f0865ec9SKyle Evans 1100*f0865ec9SKyle Evans err: 1101*f0865ec9SKyle Evans return ret; 1102*f0865ec9SKyle Evans } 1103*f0865ec9SKyle Evans 1104*f0865ec9SKyle Evans /* 1105*f0865ec9SKyle Evans * Internal version that peform in place doubling of given val, 1106*f0865ec9SKyle Evans * by using a temporary copy. Sanity checks on parameters must 1107*f0865ec9SKyle Evans * be done by caller. 1108*f0865ec9SKyle Evans */ 1109*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_dbl_monty_aliased(prj_pt_t val) 1110*f0865ec9SKyle Evans { 1111*f0865ec9SKyle Evans prj_pt out_cpy; 1112*f0865ec9SKyle Evans int ret; 1113*f0865ec9SKyle Evans out_cpy.magic = WORD(0); 1114*f0865ec9SKyle Evans 1115*f0865ec9SKyle Evans ret = _prj_pt_dbl_monty(&out_cpy, val); EG(ret, err); 1116*f0865ec9SKyle Evans ret = prj_pt_copy(val, &out_cpy); 1117*f0865ec9SKyle Evans 1118*f0865ec9SKyle Evans err: 1119*f0865ec9SKyle Evans prj_pt_uninit(&out_cpy); 1120*f0865ec9SKyle Evans 1121*f0865ec9SKyle Evans return ret; 1122*f0865ec9SKyle Evans } 1123*f0865ec9SKyle Evans 1124*f0865ec9SKyle Evans /* 1125*f0865ec9SKyle Evans * Public function for projective point doubling. The function handles the init 1126*f0865ec9SKyle Evans * check of 'in' parameter which must be guaranteed for internal functions. 1127*f0865ec9SKyle Evans * 'out' parameter need not be initialized and can be aliased with 'in' 1128*f0865ec9SKyle Evans * parameter. 1129*f0865ec9SKyle Evans * 1130*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 1131*f0865ec9SKyle Evans */ 1132*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int prj_pt_dbl(prj_pt_t out, prj_pt_src_t in) 1133*f0865ec9SKyle Evans { 1134*f0865ec9SKyle Evans int ret; 1135*f0865ec9SKyle Evans 1136*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 1137*f0865ec9SKyle Evans 1138*f0865ec9SKyle Evans if (out == in) { 1139*f0865ec9SKyle Evans ret = _prj_pt_dbl_monty_aliased(out); 1140*f0865ec9SKyle Evans } else { 1141*f0865ec9SKyle Evans ret = _prj_pt_dbl_monty(out, in); 1142*f0865ec9SKyle Evans } 1143*f0865ec9SKyle Evans 1144*f0865ec9SKyle Evans err: 1145*f0865ec9SKyle Evans return ret; 1146*f0865ec9SKyle Evans } 1147*f0865ec9SKyle Evans 1148*f0865ec9SKyle Evans /* 1149*f0865ec9SKyle Evans * Internal function: 1150*f0865ec9SKyle Evans * 1151*f0865ec9SKyle Evans * - not supporting aliasing, 1152*f0865ec9SKyle Evans * - requiring caller to check in1 and in2 parameter 1153*f0865ec9SKyle Evans * 1154*f0865ec9SKyle Evans * Based on library configuration, the function either use complete formulas 1155*f0865ec9SKyle Evans * or not. 1156*f0865ec9SKyle Evans */ 1157*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _prj_pt_add_monty(prj_pt_t out, 1158*f0865ec9SKyle Evans prj_pt_src_t in1, 1159*f0865ec9SKyle Evans prj_pt_src_t in2) 1160*f0865ec9SKyle Evans { 1161*f0865ec9SKyle Evans #ifndef NO_USE_COMPLETE_FORMULAS 1162*f0865ec9SKyle Evans return __prj_pt_add_monty_cf(out, in1, in2); 1163*f0865ec9SKyle Evans #else 1164*f0865ec9SKyle Evans return __prj_pt_add_monty_no_cf(out, in1, in2); 1165*f0865ec9SKyle Evans #endif 1166*f0865ec9SKyle Evans } 1167*f0865ec9SKyle Evans 1168*f0865ec9SKyle Evans /* 1169*f0865ec9SKyle Evans * The function is an internal one that specifically handles aliasing. No check 1170*f0865ec9SKyle Evans * is performed on parameters, this MUST be done by the caller: 1171*f0865ec9SKyle Evans * 1172*f0865ec9SKyle Evans * - in1 and in2 are initialized 1173*f0865ec9SKyle Evans * - in1 and in2 are on the same curve 1174*f0865ec9SKyle Evans * 1175*f0865ec9SKyle Evans * The function will initialize 'out'. The function returns 0 on success, -1 1176*f0865ec9SKyle Evans * on error. 1177*f0865ec9SKyle Evans */ 1178*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_add_monty_aliased(prj_pt_t out, 1179*f0865ec9SKyle Evans prj_pt_src_t in1, 1180*f0865ec9SKyle Evans prj_pt_src_t in2) 1181*f0865ec9SKyle Evans { 1182*f0865ec9SKyle Evans int ret; 1183*f0865ec9SKyle Evans prj_pt out_cpy; 1184*f0865ec9SKyle Evans out_cpy.magic = WORD(0); 1185*f0865ec9SKyle Evans 1186*f0865ec9SKyle Evans ret = _prj_pt_add_monty(&out_cpy, in1, in2); EG(ret, err); 1187*f0865ec9SKyle Evans ret = prj_pt_copy(out, &out_cpy); EG(ret, err); 1188*f0865ec9SKyle Evans 1189*f0865ec9SKyle Evans err: 1190*f0865ec9SKyle Evans prj_pt_uninit(&out_cpy); 1191*f0865ec9SKyle Evans 1192*f0865ec9SKyle Evans return ret; 1193*f0865ec9SKyle Evans } 1194*f0865ec9SKyle Evans 1195*f0865ec9SKyle Evans /* 1196*f0865ec9SKyle Evans * Public function for projective point addition. The function handles the 1197*f0865ec9SKyle Evans * init checks of 'in1' and 'in2' parameters, along with the check they 1198*f0865ec9SKyle Evans * use the same curve. This must be guaranteed for internal functions. 1199*f0865ec9SKyle Evans * 'out' parameter need not be initialized and can be aliased with either 1200*f0865ec9SKyle Evans * 'in1' or 'in2' parameter. 1201*f0865ec9SKyle Evans * 1202*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 1203*f0865ec9SKyle Evans */ 1204*f0865ec9SKyle Evans int prj_pt_add(prj_pt_t out, prj_pt_src_t in1, prj_pt_src_t in2) 1205*f0865ec9SKyle Evans { 1206*f0865ec9SKyle Evans int ret; 1207*f0865ec9SKyle Evans 1208*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in1); EG(ret, err); 1209*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in2); EG(ret, err); 1210*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 1211*f0865ec9SKyle Evans 1212*f0865ec9SKyle Evans if ((out == in1) || (out == in2)) { 1213*f0865ec9SKyle Evans ret = _prj_pt_add_monty_aliased(out, in1, in2); 1214*f0865ec9SKyle Evans } else { 1215*f0865ec9SKyle Evans ret = _prj_pt_add_monty(out, in1, in2); 1216*f0865ec9SKyle Evans } 1217*f0865ec9SKyle Evans 1218*f0865ec9SKyle Evans err: 1219*f0865ec9SKyle Evans return ret; 1220*f0865ec9SKyle Evans } 1221*f0865ec9SKyle Evans 1222*f0865ec9SKyle Evans /*******************************************************************************/ 1223*f0865ec9SKyle Evans /****** Scalar multiplication algorithms ***************************************/ 1224*f0865ec9SKyle Evans /***********/ 1225*f0865ec9SKyle Evans /* 1226*f0865ec9SKyle Evans * The description below summarizes the following algorithms. 1227*f0865ec9SKyle Evans * 1228*f0865ec9SKyle Evans * Double-and-Add-Always and Montgomery Ladder masked using Itoh et al. anti-ADPA 1229*f0865ec9SKyle Evans * (Address-bit DPA) countermeasure. 1230*f0865ec9SKyle Evans * See "A Practical Countermeasure against Address-Bit Differential Power Analysis" 1231*f0865ec9SKyle Evans * by Itoh, Izu and Takenaka for more information. 1232*f0865ec9SKyle Evans * 1233*f0865ec9SKyle Evans * NOTE: these masked variants of the Double-and-Add-Always and Montgomery Ladder algorithms 1234*f0865ec9SKyle Evans * are used by default as Itoh et al. countermeasure has a very small impact on performance 1235*f0865ec9SKyle Evans * and is inherently more robust againt DPA. The only case where we use another variant is 1236*f0865ec9SKyle Evans * for devices with low memory as Itoh requires many temporary variables that consume many 1237*f0865ec9SKyle Evans * temporary stack space. 1238*f0865ec9SKyle Evans * 1239*f0865ec9SKyle Evans * NOTE: the algorithms inherently depend on the MSB of the 1240*f0865ec9SKyle Evans * scalar. In order to avoid leaking this MSB and fall into HNP (Hidden Number 1241*f0865ec9SKyle Evans * Problem) issues, we use the trick described in https://eprint.iacr.org/2011/232.pdf 1242*f0865ec9SKyle Evans * to have the MSB always set. However, since the scalar m might be less or bigger than 1243*f0865ec9SKyle Evans * the order q of the curve, we distinguish three situations: 1244*f0865ec9SKyle Evans * - The scalar m is < q (the order), in this case we compute: 1245*f0865ec9SKyle Evans * - 1246*f0865ec9SKyle Evans * | m' = m + (2 * q) if [log(k + q)] == [log(q)], 1247*f0865ec9SKyle Evans * | m' = m + q otherwise. 1248*f0865ec9SKyle Evans * - 1249*f0865ec9SKyle Evans * - The scalar m is >= q and < q**2, in this case we compute: 1250*f0865ec9SKyle Evans * - 1251*f0865ec9SKyle Evans * | m' = m + (2 * (q**2)) if [log(k + (q**2))] == [log(q**2)], 1252*f0865ec9SKyle Evans * | m' = m + (q**2) otherwise. 1253*f0865ec9SKyle Evans * - 1254*f0865ec9SKyle Evans * - The scalar m is >= (q**2), in this case m == m' 1255*f0865ec9SKyle Evans * 1256*f0865ec9SKyle Evans * => We only deal with 0 <= m < (q**2) using the countermeasure. When m >= (q**2), 1257*f0865ec9SKyle Evans * we stick with m' = m, accepting MSB issues (not much can be done in this case 1258*f0865ec9SKyle Evans * anyways). In the two first cases, Double-and-Add-Always and Montgomery Ladder are 1259*f0865ec9SKyle Evans * performed in constant time wrt the size of the scalar m. 1260*f0865ec9SKyle Evans */ 1261*f0865ec9SKyle Evans /***********/ 1262*f0865ec9SKyle Evans /* 1263*f0865ec9SKyle Evans * Internal point blinding function: as it is internal, in is supposed to be initialized and 1264*f0865ec9SKyle Evans * aliasing is NOT supported. 1265*f0865ec9SKyle Evans */ 1266*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _blind_projective_point(prj_pt_t out, prj_pt_src_t in) 1267*f0865ec9SKyle Evans { 1268*f0865ec9SKyle Evans int ret; 1269*f0865ec9SKyle Evans 1270*f0865ec9SKyle Evans /* Random for projective coordinates masking */ 1271*f0865ec9SKyle Evans /* NOTE: to limit stack usage, we reuse out->Z as a temporary 1272*f0865ec9SKyle Evans * variable. This does not work if in == out, hence the check. 1273*f0865ec9SKyle Evans */ 1274*f0865ec9SKyle Evans MUST_HAVE((in != out), ret, err); 1275*f0865ec9SKyle Evans 1276*f0865ec9SKyle Evans ret = prj_pt_init(out, in->crv); EG(ret, err); 1277*f0865ec9SKyle Evans 1278*f0865ec9SKyle Evans /* Get a random value l in Fp */ 1279*f0865ec9SKyle Evans ret = fp_get_random(&(out->Z), in->X.ctx); EG(ret, err); 1280*f0865ec9SKyle Evans 1281*f0865ec9SKyle Evans /* 1282*f0865ec9SKyle Evans * Blind the point with projective coordinates 1283*f0865ec9SKyle Evans * (X, Y, Z) => (l*X, l*Y, l*Z) 1284*f0865ec9SKyle Evans */ 1285*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->X), &(in->X), &(out->Z)); EG(ret, err); 1286*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->Y), &(in->Y), &(out->Z)); EG(ret, err); 1287*f0865ec9SKyle Evans ret = fp_mul_monty(&(out->Z), &(in->Z), &(out->Z)); 1288*f0865ec9SKyle Evans 1289*f0865ec9SKyle Evans err: 1290*f0865ec9SKyle Evans return ret; 1291*f0865ec9SKyle Evans } 1292*f0865ec9SKyle Evans 1293*f0865ec9SKyle Evans /* If nothing is specified regarding the scalar multiplication algorithm, we use 1294*f0865ec9SKyle Evans * the Montgomery Ladder. For the specific case of small stack devices, we release 1295*f0865ec9SKyle Evans * some pressure on the stack by explicitly using double and always WITHOUT the Itoh 1296*f0865ec9SKyle Evans * et al. countermeasure against A-DPA as it is quite consuming. 1297*f0865ec9SKyle Evans */ 1298*f0865ec9SKyle Evans #if defined(USE_SMALL_STACK) && defined(USE_MONTY_LADDER) 1299*f0865ec9SKyle Evans #error "Small stack is only compatible with USE_DOUBLE_ADD_ALWAYS while USE_MONTY_LADDER has been explicitly asked!" 1300*f0865ec9SKyle Evans #endif 1301*f0865ec9SKyle Evans 1302*f0865ec9SKyle Evans #if defined(USE_SMALL_STACK) 1303*f0865ec9SKyle Evans #ifndef USE_DOUBLE_ADD_ALWAYS 1304*f0865ec9SKyle Evans #define USE_DOUBLE_ADD_ALWAYS 1305*f0865ec9SKyle Evans #endif 1306*f0865ec9SKyle Evans #endif 1307*f0865ec9SKyle Evans 1308*f0865ec9SKyle Evans #if !defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_MONTY_LADDER) 1309*f0865ec9SKyle Evans #define USE_MONTY_LADDER 1310*f0865ec9SKyle Evans #endif 1311*f0865ec9SKyle Evans 1312*f0865ec9SKyle Evans #if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_MONTY_LADDER) 1313*f0865ec9SKyle Evans #error "You can either choose USE_DOUBLE_ADD_ALWAYS or USE_MONTY_LADDER, not both!" 1314*f0865ec9SKyle Evans #endif 1315*f0865ec9SKyle Evans 1316*f0865ec9SKyle Evans #if defined(USE_DOUBLE_ADD_ALWAYS) && !defined(USE_SMALL_STACK) 1317*f0865ec9SKyle Evans ATTRIBUTE_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) 1318*f0865ec9SKyle Evans { 1319*f0865ec9SKyle Evans /* We use Itoh et al. notations here for T and the random r */ 1320*f0865ec9SKyle Evans prj_pt T[3]; 1321*f0865ec9SKyle Evans bitcnt_t mlen; 1322*f0865ec9SKyle Evans u8 mbit, rbit; 1323*f0865ec9SKyle Evans /* Random for masking the Double and Add Always algorithm */ 1324*f0865ec9SKyle Evans nn r; 1325*f0865ec9SKyle Evans /* The new scalar we will use with MSB fixed to 1 (noted m' above). 1326*f0865ec9SKyle Evans * This helps dealing with constant time. 1327*f0865ec9SKyle Evans */ 1328*f0865ec9SKyle Evans nn m_msb_fixed; 1329*f0865ec9SKyle Evans nn_src_t curve_order; 1330*f0865ec9SKyle Evans nn curve_order_square; 1331*f0865ec9SKyle Evans int ret, ret_ops, cmp; 1332*f0865ec9SKyle Evans r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0); 1333*f0865ec9SKyle Evans T[0].magic = T[1].magic = T[2].magic = WORD(0); 1334*f0865ec9SKyle Evans 1335*f0865ec9SKyle Evans /* Compute m' from m depending on the rule described above */ 1336*f0865ec9SKyle Evans curve_order = &(in->crv->order); 1337*f0865ec9SKyle Evans /* First compute q**2 */ 1338*f0865ec9SKyle Evans ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err); 1339*f0865ec9SKyle Evans /* Then compute m' depending on m size */ 1340*f0865ec9SKyle Evans ret = nn_cmp(m, curve_order, &cmp); EG(ret, err); 1341*f0865ec9SKyle Evans if (cmp < 0){ 1342*f0865ec9SKyle Evans bitcnt_t msb_bit_len, order_bitlen; 1343*f0865ec9SKyle Evans 1344*f0865ec9SKyle Evans /* Case where m < q */ 1345*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err); 1346*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err); 1347*f0865ec9SKyle Evans ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err); 1348*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed, 1349*f0865ec9SKyle Evans &m_msb_fixed, curve_order); EG(ret, err); 1350*f0865ec9SKyle Evans } else { 1351*f0865ec9SKyle Evans ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err); 1352*f0865ec9SKyle Evans if (cmp < 0) { 1353*f0865ec9SKyle Evans bitcnt_t msb_bit_len, curve_order_square_bitlen; 1354*f0865ec9SKyle Evans 1355*f0865ec9SKyle Evans /* Case where m >= q and m < (q**2) */ 1356*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err); 1357*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err); 1358*f0865ec9SKyle Evans ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err); 1359*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen), 1360*f0865ec9SKyle Evans &m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err); 1361*f0865ec9SKyle Evans } else { 1362*f0865ec9SKyle Evans /* Case where m >= (q**2) */ 1363*f0865ec9SKyle Evans ret = nn_copy(&m_msb_fixed, m); EG(ret, err); 1364*f0865ec9SKyle Evans } 1365*f0865ec9SKyle Evans } 1366*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err); 1367*f0865ec9SKyle Evans MUST_HAVE(mlen != 0, ret, err); 1368*f0865ec9SKyle Evans mlen--; 1369*f0865ec9SKyle Evans 1370*f0865ec9SKyle Evans /* Hide possible internal failures for double and add 1371*f0865ec9SKyle Evans * operations and perform the operation in constant time. 1372*f0865ec9SKyle Evans */ 1373*f0865ec9SKyle Evans ret_ops = 0; 1374*f0865ec9SKyle Evans 1375*f0865ec9SKyle Evans /* Get a random r with the same size of m_msb_fixed */ 1376*f0865ec9SKyle Evans ret = nn_get_random_len(&r, m_msb_fixed.wlen * WORD_BYTES); EG(ret, err); 1377*f0865ec9SKyle Evans 1378*f0865ec9SKyle Evans ret = nn_getbit(&r, mlen, &rbit); EG(ret, err); 1379*f0865ec9SKyle Evans 1380*f0865ec9SKyle Evans /* Initialize points */ 1381*f0865ec9SKyle Evans ret = prj_pt_init(&T[0], in->crv); EG(ret, err); 1382*f0865ec9SKyle Evans ret = prj_pt_init(&T[1], in->crv); EG(ret, err); 1383*f0865ec9SKyle Evans 1384*f0865ec9SKyle Evans /* 1385*f0865ec9SKyle Evans * T[2] = R(P) 1386*f0865ec9SKyle Evans * Blind the point with projective coordinates 1387*f0865ec9SKyle Evans * (X, Y, Z) => (l*X, l*Y, l*Z) 1388*f0865ec9SKyle Evans */ 1389*f0865ec9SKyle Evans ret = _blind_projective_point(&T[2], in); EG(ret, err); 1390*f0865ec9SKyle Evans 1391*f0865ec9SKyle Evans /* T[r[n-1]] = T[2] */ 1392*f0865ec9SKyle Evans ret = prj_pt_copy(&T[rbit], &T[2]); EG(ret, err); 1393*f0865ec9SKyle Evans 1394*f0865ec9SKyle Evans /* Main loop of Double and Add Always */ 1395*f0865ec9SKyle Evans while (mlen > 0) { 1396*f0865ec9SKyle Evans u8 rbit_next; 1397*f0865ec9SKyle Evans --mlen; 1398*f0865ec9SKyle Evans /* rbit is r[i+1], and rbit_next is r[i] */ 1399*f0865ec9SKyle Evans ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err); 1400*f0865ec9SKyle Evans 1401*f0865ec9SKyle Evans /* mbit is m[i] */ 1402*f0865ec9SKyle Evans ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err); 1403*f0865ec9SKyle Evans 1404*f0865ec9SKyle Evans /* Double: T[r[i+1]] = ECDBL(T[r[i+1]]) */ 1405*f0865ec9SKyle Evans #ifndef NO_USE_COMPLETE_FORMULAS 1406*f0865ec9SKyle Evans /* 1407*f0865ec9SKyle Evans * NOTE: in case of complete formulas, we use the 1408*f0865ec9SKyle Evans * addition for doubling, incurring a small performance hit 1409*f0865ec9SKyle Evans * for better SCA resistance. 1410*f0865ec9SKyle Evans */ 1411*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&T[rbit], &T[rbit], &T[rbit]); 1412*f0865ec9SKyle Evans #else 1413*f0865ec9SKyle Evans ret_ops |= prj_pt_dbl(&T[rbit], &T[rbit]); 1414*f0865ec9SKyle Evans #endif 1415*f0865ec9SKyle Evans /* Add: T[1-r[i+1]] = ECADD(T[r[i+1]],T[2]) */ 1416*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[2]); 1417*f0865ec9SKyle Evans 1418*f0865ec9SKyle Evans /* 1419*f0865ec9SKyle Evans * T[r[i]] = T[d[i] ^ r[i+1]] 1420*f0865ec9SKyle Evans * NOTE: we use the low level nn_copy function here to avoid 1421*f0865ec9SKyle Evans * any possible leakage on operands with prj_pt_copy 1422*f0865ec9SKyle Evans */ 1423*f0865ec9SKyle Evans ret = nn_copy(&(T[rbit_next].X.fp_val), &(T[mbit ^ rbit].X.fp_val)); EG(ret, err); 1424*f0865ec9SKyle Evans ret = nn_copy(&(T[rbit_next].Y.fp_val), &(T[mbit ^ rbit].Y.fp_val)); EG(ret, err); 1425*f0865ec9SKyle Evans ret = nn_copy(&(T[rbit_next].Z.fp_val), &(T[mbit ^ rbit].Z.fp_val)); EG(ret, err); 1426*f0865ec9SKyle Evans 1427*f0865ec9SKyle Evans /* Update rbit */ 1428*f0865ec9SKyle Evans rbit = rbit_next; 1429*f0865ec9SKyle Evans } 1430*f0865ec9SKyle Evans /* Output: T[r[0]] */ 1431*f0865ec9SKyle Evans ret = prj_pt_copy(out, &T[rbit]); EG(ret, err); 1432*f0865ec9SKyle Evans 1433*f0865ec9SKyle Evans /* Take into consideration our double and add errors */ 1434*f0865ec9SKyle Evans ret |= ret_ops; 1435*f0865ec9SKyle Evans 1436*f0865ec9SKyle Evans err: 1437*f0865ec9SKyle Evans prj_pt_uninit(&T[0]); 1438*f0865ec9SKyle Evans prj_pt_uninit(&T[1]); 1439*f0865ec9SKyle Evans prj_pt_uninit(&T[2]); 1440*f0865ec9SKyle Evans nn_uninit(&r); 1441*f0865ec9SKyle Evans nn_uninit(&m_msb_fixed); 1442*f0865ec9SKyle Evans nn_uninit(&curve_order_square); 1443*f0865ec9SKyle Evans 1444*f0865ec9SKyle Evans PTR_NULLIFY(curve_order); 1445*f0865ec9SKyle Evans 1446*f0865ec9SKyle Evans return ret; 1447*f0865ec9SKyle Evans } 1448*f0865ec9SKyle Evans #endif 1449*f0865ec9SKyle Evans 1450*f0865ec9SKyle Evans #if defined(USE_DOUBLE_ADD_ALWAYS) && defined(USE_SMALL_STACK) 1451*f0865ec9SKyle Evans /* NOTE: in small stack case where we compile for low memory devices, we do not use Itoh et al. countermeasure 1452*f0865ec9SKyle Evans * as it requires too much temporary space on the stack. 1453*f0865ec9SKyle Evans */ 1454*f0865ec9SKyle Evans ATTRIBUTE_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) 1455*f0865ec9SKyle Evans { 1456*f0865ec9SKyle Evans int ret, ret_ops; 1457*f0865ec9SKyle Evans 1458*f0865ec9SKyle Evans /* Hide possible internal failures for double and add 1459*f0865ec9SKyle Evans * operations and perform the operation in constant time. 1460*f0865ec9SKyle Evans */ 1461*f0865ec9SKyle Evans ret_ops = 0; 1462*f0865ec9SKyle Evans 1463*f0865ec9SKyle Evans /* Blind the input point projective coordinates */ 1464*f0865ec9SKyle Evans ret = _blind_projective_point(out, in); EG(ret, err); 1465*f0865ec9SKyle Evans 1466*f0865ec9SKyle Evans /*******************/ 1467*f0865ec9SKyle Evans { 1468*f0865ec9SKyle Evans bitcnt_t mlen; 1469*f0865ec9SKyle Evans u8 mbit; 1470*f0865ec9SKyle Evans /* The new scalar we will use with MSB fixed to 1 (noted m' above). 1471*f0865ec9SKyle Evans * This helps dealing with constant time. 1472*f0865ec9SKyle Evans */ 1473*f0865ec9SKyle Evans nn m_msb_fixed; 1474*f0865ec9SKyle Evans nn_src_t curve_order; 1475*f0865ec9SKyle Evans int cmp; 1476*f0865ec9SKyle Evans m_msb_fixed.magic = WORD(0); 1477*f0865ec9SKyle Evans 1478*f0865ec9SKyle Evans { 1479*f0865ec9SKyle Evans nn curve_order_square; 1480*f0865ec9SKyle Evans curve_order_square.magic = WORD(0); 1481*f0865ec9SKyle Evans 1482*f0865ec9SKyle Evans /* Compute m' from m depending on the rule described above */ 1483*f0865ec9SKyle Evans curve_order = &(in->crv->order); 1484*f0865ec9SKyle Evans /* First compute q**2 */ 1485*f0865ec9SKyle Evans ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err1); 1486*f0865ec9SKyle Evans /* Then compute m' depending on m size */ 1487*f0865ec9SKyle Evans ret = nn_cmp(m, curve_order, &cmp); EG(ret, err1); 1488*f0865ec9SKyle Evans if (cmp < 0){ 1489*f0865ec9SKyle Evans bitcnt_t msb_bit_len, order_bitlen; 1490*f0865ec9SKyle Evans 1491*f0865ec9SKyle Evans /* Case where m < q */ 1492*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err1); 1493*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1); 1494*f0865ec9SKyle Evans ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err1); 1495*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed, 1496*f0865ec9SKyle Evans &m_msb_fixed, curve_order); EG(ret, err1); 1497*f0865ec9SKyle Evans } else { 1498*f0865ec9SKyle Evans ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err1); 1499*f0865ec9SKyle Evans if (cmp < 0) { 1500*f0865ec9SKyle Evans bitcnt_t msb_bit_len, curve_order_square_bitlen; 1501*f0865ec9SKyle Evans 1502*f0865ec9SKyle Evans /* Case where m >= q and m < (q**2) */ 1503*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err1); 1504*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err1); 1505*f0865ec9SKyle Evans ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err1); 1506*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen), 1507*f0865ec9SKyle Evans &m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err1); 1508*f0865ec9SKyle Evans } else { 1509*f0865ec9SKyle Evans /* Case where m >= (q**2) */ 1510*f0865ec9SKyle Evans ret = nn_copy(&m_msb_fixed, m); EG(ret, err1); 1511*f0865ec9SKyle Evans } 1512*f0865ec9SKyle Evans } 1513*f0865ec9SKyle Evans err1: 1514*f0865ec9SKyle Evans nn_uninit(&curve_order_square); EG(ret, err); 1515*f0865ec9SKyle Evans } 1516*f0865ec9SKyle Evans 1517*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err); 1518*f0865ec9SKyle Evans MUST_HAVE((mlen != 0), ret, err); 1519*f0865ec9SKyle Evans mlen--; 1520*f0865ec9SKyle Evans 1521*f0865ec9SKyle Evans { 1522*f0865ec9SKyle Evans prj_pt dbl; 1523*f0865ec9SKyle Evans dbl.magic = WORD(0); 1524*f0865ec9SKyle Evans 1525*f0865ec9SKyle Evans /* Initialize temporary point */ 1526*f0865ec9SKyle Evans ret = prj_pt_init(&dbl, in->crv); EG(ret, err2); 1527*f0865ec9SKyle Evans 1528*f0865ec9SKyle Evans /* Main loop of Double and Add Always */ 1529*f0865ec9SKyle Evans while (mlen > 0) { 1530*f0865ec9SKyle Evans --mlen; 1531*f0865ec9SKyle Evans /* mbit is m[i] */ 1532*f0865ec9SKyle Evans ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err2); 1533*f0865ec9SKyle Evans 1534*f0865ec9SKyle Evans #ifndef NO_USE_COMPLETE_FORMULAS 1535*f0865ec9SKyle Evans /* 1536*f0865ec9SKyle Evans * NOTE: in case of complete formulas, we use the 1537*f0865ec9SKyle Evans * addition for doubling, incurring a small performance hit 1538*f0865ec9SKyle Evans * for better SCA resistance. 1539*f0865ec9SKyle Evans */ 1540*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&dbl, out, out); 1541*f0865ec9SKyle Evans #else 1542*f0865ec9SKyle Evans ret_ops |= prj_pt_dbl(&dbl, out); 1543*f0865ec9SKyle Evans #endif 1544*f0865ec9SKyle Evans ret_ops |= prj_pt_add(out, &dbl, in); 1545*f0865ec9SKyle Evans /* Swap */ 1546*f0865ec9SKyle Evans ret = nn_cnd_swap(!mbit, &(out->X.fp_val), &(dbl.X.fp_val)); EG(ret, err2); 1547*f0865ec9SKyle Evans ret = nn_cnd_swap(!mbit, &(out->Y.fp_val), &(dbl.Y.fp_val)); EG(ret, err2); 1548*f0865ec9SKyle Evans ret = nn_cnd_swap(!mbit, &(out->Z.fp_val), &(dbl.Z.fp_val)); EG(ret, err2); 1549*f0865ec9SKyle Evans } 1550*f0865ec9SKyle Evans err2: 1551*f0865ec9SKyle Evans prj_pt_uninit(&dbl); EG(ret, err); 1552*f0865ec9SKyle Evans } 1553*f0865ec9SKyle Evans 1554*f0865ec9SKyle Evans err: 1555*f0865ec9SKyle Evans nn_uninit(&m_msb_fixed); 1556*f0865ec9SKyle Evans 1557*f0865ec9SKyle Evans PTR_NULLIFY(curve_order); 1558*f0865ec9SKyle Evans } 1559*f0865ec9SKyle Evans 1560*f0865ec9SKyle Evans /* Take into consideration our double and add errors */ 1561*f0865ec9SKyle Evans ret |= ret_ops; 1562*f0865ec9SKyle Evans 1563*f0865ec9SKyle Evans return ret; 1564*f0865ec9SKyle Evans } 1565*f0865ec9SKyle Evans #endif 1566*f0865ec9SKyle Evans 1567*f0865ec9SKyle Evans 1568*f0865ec9SKyle Evans #ifdef USE_MONTY_LADDER 1569*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_ladder(prj_pt_t out, nn_src_t m, prj_pt_src_t in) 1570*f0865ec9SKyle Evans { 1571*f0865ec9SKyle Evans /* We use Itoh et al. notations here for T and the random r */ 1572*f0865ec9SKyle Evans prj_pt T[3]; 1573*f0865ec9SKyle Evans bitcnt_t mlen; 1574*f0865ec9SKyle Evans u8 mbit, rbit; 1575*f0865ec9SKyle Evans /* Random for masking the Montgomery Ladder algorithm */ 1576*f0865ec9SKyle Evans nn r; 1577*f0865ec9SKyle Evans /* The new scalar we will use with MSB fixed to 1 (noted m' above). 1578*f0865ec9SKyle Evans * This helps dealing with constant time. 1579*f0865ec9SKyle Evans */ 1580*f0865ec9SKyle Evans nn m_msb_fixed; 1581*f0865ec9SKyle Evans nn_src_t curve_order; 1582*f0865ec9SKyle Evans nn curve_order_square; 1583*f0865ec9SKyle Evans int ret, ret_ops, cmp; 1584*f0865ec9SKyle Evans r.magic = m_msb_fixed.magic = curve_order_square.magic = WORD(0); 1585*f0865ec9SKyle Evans T[0].magic = T[1].magic = T[2].magic = WORD(0); 1586*f0865ec9SKyle Evans 1587*f0865ec9SKyle Evans /* Compute m' from m depending on the rule described above */ 1588*f0865ec9SKyle Evans curve_order = &(in->crv->order); 1589*f0865ec9SKyle Evans 1590*f0865ec9SKyle Evans /* First compute q**2 */ 1591*f0865ec9SKyle Evans ret = nn_sqr(&curve_order_square, curve_order); EG(ret, err); 1592*f0865ec9SKyle Evans 1593*f0865ec9SKyle Evans /* Then compute m' depending on m size */ 1594*f0865ec9SKyle Evans ret = nn_cmp(m, curve_order, &cmp); EG(ret, err); 1595*f0865ec9SKyle Evans if (cmp < 0) { 1596*f0865ec9SKyle Evans bitcnt_t msb_bit_len, order_bitlen; 1597*f0865ec9SKyle Evans 1598*f0865ec9SKyle Evans /* Case where m < q */ 1599*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, curve_order); EG(ret, err); 1600*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err); 1601*f0865ec9SKyle Evans ret = nn_bitlen(curve_order, &order_bitlen); EG(ret, err); 1602*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == order_bitlen), &m_msb_fixed, 1603*f0865ec9SKyle Evans &m_msb_fixed, curve_order); EG(ret, err); 1604*f0865ec9SKyle Evans } else { 1605*f0865ec9SKyle Evans ret = nn_cmp(m, &curve_order_square, &cmp); EG(ret, err); 1606*f0865ec9SKyle Evans if (cmp < 0) { 1607*f0865ec9SKyle Evans bitcnt_t msb_bit_len, curve_order_square_bitlen; 1608*f0865ec9SKyle Evans 1609*f0865ec9SKyle Evans /* Case where m >= q and m < (q**2) */ 1610*f0865ec9SKyle Evans ret = nn_add(&m_msb_fixed, m, &curve_order_square); EG(ret, err); 1611*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &msb_bit_len); EG(ret, err); 1612*f0865ec9SKyle Evans ret = nn_bitlen(&curve_order_square, &curve_order_square_bitlen); EG(ret, err); 1613*f0865ec9SKyle Evans ret = nn_cnd_add((msb_bit_len == curve_order_square_bitlen), 1614*f0865ec9SKyle Evans &m_msb_fixed, &m_msb_fixed, &curve_order_square); EG(ret, err); 1615*f0865ec9SKyle Evans } else { 1616*f0865ec9SKyle Evans /* Case where m >= (q**2) */ 1617*f0865ec9SKyle Evans ret = nn_copy(&m_msb_fixed, m); EG(ret, err); 1618*f0865ec9SKyle Evans } 1619*f0865ec9SKyle Evans } 1620*f0865ec9SKyle Evans 1621*f0865ec9SKyle Evans ret = nn_bitlen(&m_msb_fixed, &mlen); EG(ret, err); 1622*f0865ec9SKyle Evans MUST_HAVE((mlen != 0), ret, err); 1623*f0865ec9SKyle Evans mlen--; 1624*f0865ec9SKyle Evans 1625*f0865ec9SKyle Evans /* Hide possible internal failures for double and add 1626*f0865ec9SKyle Evans * operations and perform the operation in constant time. 1627*f0865ec9SKyle Evans */ 1628*f0865ec9SKyle Evans ret_ops = 0; 1629*f0865ec9SKyle Evans 1630*f0865ec9SKyle Evans /* Get a random r with the same size of m_msb_fixed */ 1631*f0865ec9SKyle Evans ret = nn_get_random_len(&r, (u16)(m_msb_fixed.wlen * WORD_BYTES)); EG(ret, err); 1632*f0865ec9SKyle Evans 1633*f0865ec9SKyle Evans ret = nn_getbit(&r, mlen, &rbit); EG(ret, err); 1634*f0865ec9SKyle Evans 1635*f0865ec9SKyle Evans /* Initialize points */ 1636*f0865ec9SKyle Evans ret = prj_pt_init(&T[0], in->crv); EG(ret, err); 1637*f0865ec9SKyle Evans ret = prj_pt_init(&T[1], in->crv); EG(ret, err); 1638*f0865ec9SKyle Evans ret = prj_pt_init(&T[2], in->crv); EG(ret, err); 1639*f0865ec9SKyle Evans 1640*f0865ec9SKyle Evans /* Initialize T[r[n-1]] to input point */ 1641*f0865ec9SKyle Evans /* 1642*f0865ec9SKyle Evans * Blind the point with projective coordinates 1643*f0865ec9SKyle Evans * (X, Y, Z) => (l*X, l*Y, l*Z) 1644*f0865ec9SKyle Evans */ 1645*f0865ec9SKyle Evans ret = _blind_projective_point(&T[rbit], in); EG(ret, err); 1646*f0865ec9SKyle Evans 1647*f0865ec9SKyle Evans /* Initialize T[1-r[n-1]] with ECDBL(T[r[n-1]])) */ 1648*f0865ec9SKyle Evans #ifndef NO_USE_COMPLETE_FORMULAS 1649*f0865ec9SKyle Evans /* 1650*f0865ec9SKyle Evans * NOTE: in case of complete formulas, we use the 1651*f0865ec9SKyle Evans * addition for doubling, incurring a small performance hit 1652*f0865ec9SKyle Evans * for better SCA resistance. 1653*f0865ec9SKyle Evans */ 1654*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&T[1-rbit], &T[rbit], &T[rbit]); 1655*f0865ec9SKyle Evans #else 1656*f0865ec9SKyle Evans ret_ops |= prj_pt_dbl(&T[1-rbit], &T[rbit]); 1657*f0865ec9SKyle Evans #endif 1658*f0865ec9SKyle Evans 1659*f0865ec9SKyle Evans /* Main loop of the Montgomery Ladder */ 1660*f0865ec9SKyle Evans while (mlen > 0) { 1661*f0865ec9SKyle Evans u8 rbit_next; 1662*f0865ec9SKyle Evans --mlen; 1663*f0865ec9SKyle Evans /* rbit is r[i+1], and rbit_next is r[i] */ 1664*f0865ec9SKyle Evans ret = nn_getbit(&r, mlen, &rbit_next); EG(ret, err); 1665*f0865ec9SKyle Evans 1666*f0865ec9SKyle Evans /* mbit is m[i] */ 1667*f0865ec9SKyle Evans ret = nn_getbit(&m_msb_fixed, mlen, &mbit); EG(ret, err); 1668*f0865ec9SKyle Evans /* Double: T[2] = ECDBL(T[d[i] ^ r[i+1]]) */ 1669*f0865ec9SKyle Evans 1670*f0865ec9SKyle Evans #ifndef NO_USE_COMPLETE_FORMULAS 1671*f0865ec9SKyle Evans /* NOTE: in case of complete formulas, we use the 1672*f0865ec9SKyle Evans * addition for doubling, incurring a small performance hit 1673*f0865ec9SKyle Evans * for better SCA resistance. 1674*f0865ec9SKyle Evans */ 1675*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&T[2], &T[mbit ^ rbit], &T[mbit ^ rbit]); 1676*f0865ec9SKyle Evans #else 1677*f0865ec9SKyle Evans ret_ops |= prj_pt_dbl(&T[2], &T[mbit ^ rbit]); 1678*f0865ec9SKyle Evans #endif 1679*f0865ec9SKyle Evans 1680*f0865ec9SKyle Evans /* Add: T[1] = ECADD(T[0],T[1]) */ 1681*f0865ec9SKyle Evans ret_ops |= prj_pt_add(&T[1], &T[0], &T[1]); 1682*f0865ec9SKyle Evans 1683*f0865ec9SKyle Evans /* T[0] = T[2-(d[i] ^ r[i])] */ 1684*f0865ec9SKyle Evans /* 1685*f0865ec9SKyle Evans * NOTE: we use the low level nn_copy function here to avoid 1686*f0865ec9SKyle Evans * any possible leakage on operands with prj_pt_copy 1687*f0865ec9SKyle Evans */ 1688*f0865ec9SKyle Evans ret = nn_copy(&(T[0].X.fp_val), &(T[2-(mbit ^ rbit_next)].X.fp_val)); EG(ret, err); 1689*f0865ec9SKyle Evans ret = nn_copy(&(T[0].Y.fp_val), &(T[2-(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err); 1690*f0865ec9SKyle Evans ret = nn_copy(&(T[0].Z.fp_val), &(T[2-(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err); 1691*f0865ec9SKyle Evans 1692*f0865ec9SKyle Evans /* T[1] = T[1+(d[i] ^ r[i])] */ 1693*f0865ec9SKyle Evans /* NOTE: we use the low level nn_copy function here to avoid 1694*f0865ec9SKyle Evans * any possible leakage on operands with prj_pt_copy 1695*f0865ec9SKyle Evans */ 1696*f0865ec9SKyle Evans ret = nn_copy(&(T[1].X.fp_val), &(T[1+(mbit ^ rbit_next)].X.fp_val)); EG(ret, err); 1697*f0865ec9SKyle Evans ret = nn_copy(&(T[1].Y.fp_val), &(T[1+(mbit ^ rbit_next)].Y.fp_val)); EG(ret, err); 1698*f0865ec9SKyle Evans ret = nn_copy(&(T[1].Z.fp_val), &(T[1+(mbit ^ rbit_next)].Z.fp_val)); EG(ret, err); 1699*f0865ec9SKyle Evans 1700*f0865ec9SKyle Evans /* Update rbit */ 1701*f0865ec9SKyle Evans rbit = rbit_next; 1702*f0865ec9SKyle Evans } 1703*f0865ec9SKyle Evans /* Output: T[r[0]] */ 1704*f0865ec9SKyle Evans ret = prj_pt_copy(out, &T[rbit]); EG(ret, err); 1705*f0865ec9SKyle Evans 1706*f0865ec9SKyle Evans /* Take into consideration our double and add errors */ 1707*f0865ec9SKyle Evans ret |= ret_ops; 1708*f0865ec9SKyle Evans 1709*f0865ec9SKyle Evans err: 1710*f0865ec9SKyle Evans prj_pt_uninit(&T[0]); 1711*f0865ec9SKyle Evans prj_pt_uninit(&T[1]); 1712*f0865ec9SKyle Evans prj_pt_uninit(&T[2]); 1713*f0865ec9SKyle Evans nn_uninit(&r); 1714*f0865ec9SKyle Evans nn_uninit(&m_msb_fixed); 1715*f0865ec9SKyle Evans nn_uninit(&curve_order_square); 1716*f0865ec9SKyle Evans 1717*f0865ec9SKyle Evans PTR_NULLIFY(curve_order); 1718*f0865ec9SKyle Evans 1719*f0865ec9SKyle Evans return ret; 1720*f0865ec9SKyle Evans } 1721*f0865ec9SKyle Evans #endif 1722*f0865ec9SKyle Evans 1723*f0865ec9SKyle Evans /* Main projective scalar multiplication function. 1724*f0865ec9SKyle Evans * Depending on the preprocessing options, we use either the 1725*f0865ec9SKyle Evans * Double and Add Always algorithm, or the Montgomery Ladder one. 1726*f0865ec9SKyle Evans */ 1727*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty(prj_pt_t out, nn_src_t m, prj_pt_src_t in){ 1728*f0865ec9SKyle Evans #if defined(USE_DOUBLE_ADD_ALWAYS) 1729*f0865ec9SKyle Evans return _prj_pt_mul_ltr_monty_dbl_add_always(out, m, in); 1730*f0865ec9SKyle Evans #elif defined(USE_MONTY_LADDER) 1731*f0865ec9SKyle Evans return _prj_pt_mul_ltr_monty_ladder(out, m, in); 1732*f0865ec9SKyle Evans #else 1733*f0865ec9SKyle Evans #error "Error: neither Double and Add Always nor Montgomery Ladder has been selected!" 1734*f0865ec9SKyle Evans #endif 1735*f0865ec9SKyle Evans } 1736*f0865ec9SKyle Evans 1737*f0865ec9SKyle Evans /* version with 'm' passed via 'out'. */ 1738*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _prj_pt_mul_ltr_monty_aliased(prj_pt_t out, nn_src_t m, prj_pt_src_t in) 1739*f0865ec9SKyle Evans { 1740*f0865ec9SKyle Evans prj_pt out_cpy; 1741*f0865ec9SKyle Evans int ret; 1742*f0865ec9SKyle Evans out_cpy.magic = WORD(0); 1743*f0865ec9SKyle Evans 1744*f0865ec9SKyle Evans ret = prj_pt_init(&out_cpy, in->crv); EG(ret, err); 1745*f0865ec9SKyle Evans ret = _prj_pt_mul_ltr_monty(&out_cpy, m, in); EG(ret, err); 1746*f0865ec9SKyle Evans ret = prj_pt_copy(out, &out_cpy); 1747*f0865ec9SKyle Evans 1748*f0865ec9SKyle Evans err: 1749*f0865ec9SKyle Evans prj_pt_uninit(&out_cpy); 1750*f0865ec9SKyle Evans return ret; 1751*f0865ec9SKyle Evans } 1752*f0865ec9SKyle Evans 1753*f0865ec9SKyle Evans /* Aliased version. This is the public main interface of our 1754*f0865ec9SKyle Evans * scalar multiplication algorithm. Checks that the input point 1755*f0865ec9SKyle Evans * and that the output point are on the curve are performed here 1756*f0865ec9SKyle Evans * (before and after calling the core algorithm, albeit Double and 1757*f0865ec9SKyle Evans * Add Always or Montgomery Ladder). 1758*f0865ec9SKyle Evans */ 1759*f0865ec9SKyle Evans int prj_pt_mul(prj_pt_t out, nn_src_t m, prj_pt_src_t in) 1760*f0865ec9SKyle Evans { 1761*f0865ec9SKyle Evans int ret, on_curve; 1762*f0865ec9SKyle Evans 1763*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 1764*f0865ec9SKyle Evans ret = nn_check_initialized(m); EG(ret, err); 1765*f0865ec9SKyle Evans 1766*f0865ec9SKyle Evans /* Check that the input is on the curve */ 1767*f0865ec9SKyle Evans MUST_HAVE((!prj_pt_is_on_curve(in, &on_curve)) && on_curve, ret, err); 1768*f0865ec9SKyle Evans 1769*f0865ec9SKyle Evans if (out == in) { 1770*f0865ec9SKyle Evans ret = _prj_pt_mul_ltr_monty_aliased(out, m, in); EG(ret, err); 1771*f0865ec9SKyle Evans } else { 1772*f0865ec9SKyle Evans ret = _prj_pt_mul_ltr_monty(out, m, in); EG(ret, err); 1773*f0865ec9SKyle Evans } 1774*f0865ec9SKyle Evans 1775*f0865ec9SKyle Evans /* Check that the output is on the curve */ 1776*f0865ec9SKyle Evans MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err); 1777*f0865ec9SKyle Evans 1778*f0865ec9SKyle Evans err: 1779*f0865ec9SKyle Evans return ret; 1780*f0865ec9SKyle Evans } 1781*f0865ec9SKyle Evans 1782*f0865ec9SKyle Evans int prj_pt_mul_blind(prj_pt_t out, nn_src_t m, prj_pt_src_t in) 1783*f0865ec9SKyle Evans { 1784*f0865ec9SKyle Evans /* Blind the scalar m with (b*q) where q is the curve order. 1785*f0865ec9SKyle Evans * NOTE: the curve order and the "generator" order are 1786*f0865ec9SKyle Evans * usually the same (i.e. cofactor = 1) for the classical 1787*f0865ec9SKyle Evans * prime fields curves. However some exceptions exist 1788*f0865ec9SKyle Evans * (e.g. Wei25519 and Wei448), and in this case it is 1789*f0865ec9SKyle Evans * curcial to use the curve order for a generic blinding 1790*f0865ec9SKyle Evans * working on any point on the curve. 1791*f0865ec9SKyle Evans */ 1792*f0865ec9SKyle Evans nn b; 1793*f0865ec9SKyle Evans nn_src_t q; 1794*f0865ec9SKyle Evans int ret; 1795*f0865ec9SKyle Evans b.magic = WORD(0); 1796*f0865ec9SKyle Evans 1797*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in); EG(ret, err); 1798*f0865ec9SKyle Evans 1799*f0865ec9SKyle Evans q = &(in->crv->order); 1800*f0865ec9SKyle Evans 1801*f0865ec9SKyle Evans ret = nn_init(&b, 0); EG(ret, err); 1802*f0865ec9SKyle Evans 1803*f0865ec9SKyle Evans ret = nn_get_random_mod(&b, q); EG(ret, err); 1804*f0865ec9SKyle Evans 1805*f0865ec9SKyle Evans ret = nn_mul(&b, &b, q); EG(ret, err); 1806*f0865ec9SKyle Evans ret = nn_add(&b, &b, m); EG(ret, err); 1807*f0865ec9SKyle Evans 1808*f0865ec9SKyle Evans /* NOTE: point blinding is performed in the lower functions */ 1809*f0865ec9SKyle Evans /* NOTE: check that input and output points are on the curve are 1810*f0865ec9SKyle Evans * performed in the lower functions. 1811*f0865ec9SKyle Evans */ 1812*f0865ec9SKyle Evans 1813*f0865ec9SKyle Evans /* Perform the scalar multiplication */ 1814*f0865ec9SKyle Evans ret = prj_pt_mul(out, &b, in); 1815*f0865ec9SKyle Evans 1816*f0865ec9SKyle Evans err: 1817*f0865ec9SKyle Evans nn_uninit(&b); 1818*f0865ec9SKyle Evans 1819*f0865ec9SKyle Evans PTR_NULLIFY(q); 1820*f0865ec9SKyle Evans 1821*f0865ec9SKyle Evans return ret; 1822*f0865ec9SKyle Evans } 1823*f0865ec9SKyle Evans 1824*f0865ec9SKyle Evans /* Naive double and add scalar multiplication. 1825*f0865ec9SKyle Evans * 1826*f0865ec9SKyle Evans * This scalar multiplication is used on public values and is optimized with no 1827*f0865ec9SKyle Evans * countermeasures, and it is usually faster as scalar can be small with few bits 1828*f0865ec9SKyle Evans * to process (e.g. cofactors, etc.). 1829*f0865ec9SKyle Evans * 1830*f0865ec9SKyle Evans * out is initialized by the function. 1831*f0865ec9SKyle Evans * 1832*f0865ec9SKyle Evans * XXX: WARNING: this function must only be used on public points! 1833*f0865ec9SKyle Evans * 1834*f0865ec9SKyle Evans */ 1835*f0865ec9SKyle Evans static int __prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in) 1836*f0865ec9SKyle Evans { 1837*f0865ec9SKyle Evans u8 expbit; 1838*f0865ec9SKyle Evans bitcnt_t explen; 1839*f0865ec9SKyle Evans int ret, iszero, on_curve; 1840*f0865ec9SKyle Evans 1841*f0865ec9SKyle Evans ret = prj_pt_check_initialized(public_in); EG(ret, err); 1842*f0865ec9SKyle Evans ret = nn_check_initialized(scalar); EG(ret, err); 1843*f0865ec9SKyle Evans 1844*f0865ec9SKyle Evans /* This function does not support aliasing */ 1845*f0865ec9SKyle Evans MUST_HAVE((out != public_in), ret, err); 1846*f0865ec9SKyle Evans 1847*f0865ec9SKyle Evans /* Check that the input is on the curve */ 1848*f0865ec9SKyle Evans MUST_HAVE((!prj_pt_is_on_curve(public_in, &on_curve)) && on_curve, ret, err); 1849*f0865ec9SKyle Evans 1850*f0865ec9SKyle Evans ret = nn_iszero(scalar, &iszero); EG(ret, err); 1851*f0865ec9SKyle Evans /* Multiplication by zero is the point at infinity */ 1852*f0865ec9SKyle Evans if(iszero){ 1853*f0865ec9SKyle Evans ret = prj_pt_zero(out); EG(ret, err); 1854*f0865ec9SKyle Evans goto err; 1855*f0865ec9SKyle Evans } 1856*f0865ec9SKyle Evans 1857*f0865ec9SKyle Evans ret = nn_bitlen(scalar, &explen); EG(ret, err); 1858*f0865ec9SKyle Evans /* Sanity check */ 1859*f0865ec9SKyle Evans MUST_HAVE((explen > 0), ret, err); 1860*f0865ec9SKyle Evans explen = (bitcnt_t)(explen - 1); 1861*f0865ec9SKyle Evans ret = prj_pt_copy(out, public_in); EG(ret, err); 1862*f0865ec9SKyle Evans 1863*f0865ec9SKyle Evans while (explen > 0) { 1864*f0865ec9SKyle Evans explen = (bitcnt_t)(explen - 1); 1865*f0865ec9SKyle Evans ret = nn_getbit(scalar, explen, &expbit); EG(ret, err); 1866*f0865ec9SKyle Evans ret = prj_pt_dbl(out, out); EG(ret, err); 1867*f0865ec9SKyle Evans if(expbit){ 1868*f0865ec9SKyle Evans ret = prj_pt_add(out, out, public_in); EG(ret, err); 1869*f0865ec9SKyle Evans } 1870*f0865ec9SKyle Evans } 1871*f0865ec9SKyle Evans 1872*f0865ec9SKyle Evans /* Check that the output is on the curve */ 1873*f0865ec9SKyle Evans MUST_HAVE((!prj_pt_is_on_curve(out, &on_curve)) && on_curve, ret, err); 1874*f0865ec9SKyle Evans 1875*f0865ec9SKyle Evans err: 1876*f0865ec9SKyle Evans VAR_ZEROIFY(expbit); 1877*f0865ec9SKyle Evans VAR_ZEROIFY(explen); 1878*f0865ec9SKyle Evans 1879*f0865ec9SKyle Evans return ret; 1880*f0865ec9SKyle Evans } 1881*f0865ec9SKyle Evans 1882*f0865ec9SKyle Evans /* Aliased version of __prj_pt_unprotected_mult */ 1883*f0865ec9SKyle Evans int _prj_pt_unprotected_mult(prj_pt_t out, nn_src_t scalar, prj_pt_src_t public_in) 1884*f0865ec9SKyle Evans { 1885*f0865ec9SKyle Evans int ret; 1886*f0865ec9SKyle Evans 1887*f0865ec9SKyle Evans if(out == public_in){ 1888*f0865ec9SKyle Evans prj_pt A; 1889*f0865ec9SKyle Evans A.magic = WORD(0); 1890*f0865ec9SKyle Evans 1891*f0865ec9SKyle Evans ret = prj_pt_copy(&A, public_in); EG(ret, err1); 1892*f0865ec9SKyle Evans ret = __prj_pt_unprotected_mult(out, scalar, &A); 1893*f0865ec9SKyle Evans err1: 1894*f0865ec9SKyle Evans prj_pt_uninit(&A); 1895*f0865ec9SKyle Evans goto err; 1896*f0865ec9SKyle Evans } 1897*f0865ec9SKyle Evans else{ 1898*f0865ec9SKyle Evans ret = __prj_pt_unprotected_mult(out, scalar, public_in); 1899*f0865ec9SKyle Evans } 1900*f0865ec9SKyle Evans err: 1901*f0865ec9SKyle Evans return ret; 1902*f0865ec9SKyle Evans } 1903*f0865ec9SKyle Evans /* 1904*f0865ec9SKyle Evans * Check if an integer is (a multiple of) a projective point order. 1905*f0865ec9SKyle Evans * 1906*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. The value check is set to 1 if the projective 1907*f0865ec9SKyle Evans * point has order in_isorder, 0 otherwise. The value is meaningless on error. 1908*f0865ec9SKyle Evans */ 1909*f0865ec9SKyle Evans int check_prj_pt_order(prj_pt_src_t in_shortw, nn_src_t in_isorder, prj_pt_sensitivity s, int *check) 1910*f0865ec9SKyle Evans { 1911*f0865ec9SKyle Evans int ret, iszero; 1912*f0865ec9SKyle Evans prj_pt res; 1913*f0865ec9SKyle Evans res.magic = WORD(0); 1914*f0865ec9SKyle Evans 1915*f0865ec9SKyle Evans /* First sanity checks */ 1916*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in_shortw); EG(ret, err); 1917*f0865ec9SKyle Evans ret = nn_check_initialized(in_isorder); EG(ret, err); 1918*f0865ec9SKyle Evans MUST_HAVE((check != NULL), ret, err); 1919*f0865ec9SKyle Evans 1920*f0865ec9SKyle Evans /* Then, perform the scalar multiplication */ 1921*f0865ec9SKyle Evans if(s == PUBLIC_PT){ 1922*f0865ec9SKyle Evans /* If this is a public point, we can use the naive scalar multiplication */ 1923*f0865ec9SKyle Evans ret = _prj_pt_unprotected_mult(&res, in_isorder, in_shortw); EG(ret, err); 1924*f0865ec9SKyle Evans } 1925*f0865ec9SKyle Evans else{ 1926*f0865ec9SKyle Evans /* If the point is private, it is sensitive and we proceed with the secure 1927*f0865ec9SKyle Evans * scalar blind multiplication. 1928*f0865ec9SKyle Evans */ 1929*f0865ec9SKyle Evans ret = prj_pt_mul_blind(&res, in_isorder, in_shortw); EG(ret, err); 1930*f0865ec9SKyle Evans } 1931*f0865ec9SKyle Evans 1932*f0865ec9SKyle Evans /* Check if we have the point at infinity */ 1933*f0865ec9SKyle Evans ret = prj_pt_iszero(&res, &iszero); EG(ret, err); 1934*f0865ec9SKyle Evans (*check) = iszero; 1935*f0865ec9SKyle Evans 1936*f0865ec9SKyle Evans err: 1937*f0865ec9SKyle Evans prj_pt_uninit(&res); 1938*f0865ec9SKyle Evans 1939*f0865ec9SKyle Evans return ret; 1940*f0865ec9SKyle Evans } 1941*f0865ec9SKyle Evans 1942*f0865ec9SKyle Evans /*****************************************************************************/ 1943*f0865ec9SKyle Evans 1944*f0865ec9SKyle Evans /* 1945*f0865ec9SKyle Evans * Map points from Edwards to short Weierstrass projective points through Montgomery (composition mapping). 1946*f0865ec9SKyle Evans * Point at infinity (0, 1) -> (0, 1, 0) is treated as an exception, which is trivially not constant time. 1947*f0865ec9SKyle Evans * This is OK since our mapping functions should be used at the non sensitive input and output 1948*f0865ec9SKyle Evans * interfaces. 1949*f0865ec9SKyle Evans * 1950*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 1951*f0865ec9SKyle Evans */ 1952*f0865ec9SKyle Evans int aff_pt_edwards_to_prj_pt_shortw(aff_pt_edwards_src_t in_edwards, 1953*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv, 1954*f0865ec9SKyle Evans prj_pt_t out_shortw, 1955*f0865ec9SKyle Evans fp_src_t alpha_edwards) 1956*f0865ec9SKyle Evans { 1957*f0865ec9SKyle Evans int ret, iszero, cmp; 1958*f0865ec9SKyle Evans aff_pt out_shortw_aff; 1959*f0865ec9SKyle Evans fp one; 1960*f0865ec9SKyle Evans out_shortw_aff.magic = one.magic = WORD(0); 1961*f0865ec9SKyle Evans 1962*f0865ec9SKyle Evans /* Check the curves compatibility */ 1963*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err); 1964*f0865ec9SKyle Evans ret = curve_edwards_shortw_check(in_edwards->crv, shortw_crv, alpha_edwards); EG(ret, err); 1965*f0865ec9SKyle Evans 1966*f0865ec9SKyle Evans /* Initialize output point with curve */ 1967*f0865ec9SKyle Evans ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err); 1968*f0865ec9SKyle Evans 1969*f0865ec9SKyle Evans ret = fp_init(&one, in_edwards->x.ctx); EG(ret, err); 1970*f0865ec9SKyle Evans ret = fp_one(&one); EG(ret, err); 1971*f0865ec9SKyle Evans 1972*f0865ec9SKyle Evans /* Check if we are the point at infinity 1973*f0865ec9SKyle Evans * This check induces a non consant time exception, but the current function must be called on 1974*f0865ec9SKyle Evans * public data anyways. 1975*f0865ec9SKyle Evans */ 1976*f0865ec9SKyle Evans ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err); 1977*f0865ec9SKyle Evans ret = fp_cmp(&(in_edwards->y), &one, &cmp); EG(ret, err); 1978*f0865ec9SKyle Evans if(iszero && (cmp == 0)){ 1979*f0865ec9SKyle Evans ret = prj_pt_zero(out_shortw); EG(ret, err); 1980*f0865ec9SKyle Evans ret = 0; 1981*f0865ec9SKyle Evans goto err; 1982*f0865ec9SKyle Evans } 1983*f0865ec9SKyle Evans 1984*f0865ec9SKyle Evans /* Use the affine mapping */ 1985*f0865ec9SKyle Evans ret = aff_pt_edwards_to_shortw(in_edwards, shortw_crv, &out_shortw_aff, alpha_edwards); EG(ret, err); 1986*f0865ec9SKyle Evans /* And then map the short Weierstrass affine to projective coordinates */ 1987*f0865ec9SKyle Evans ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff); 1988*f0865ec9SKyle Evans 1989*f0865ec9SKyle Evans err: 1990*f0865ec9SKyle Evans fp_uninit(&one); 1991*f0865ec9SKyle Evans aff_pt_uninit(&out_shortw_aff); 1992*f0865ec9SKyle Evans 1993*f0865ec9SKyle Evans return ret; 1994*f0865ec9SKyle Evans } 1995*f0865ec9SKyle Evans 1996*f0865ec9SKyle Evans /* 1997*f0865ec9SKyle Evans * Map points from short Weierstrass projective points to Edwards through Montgomery (composition mapping). 1998*f0865ec9SKyle Evans * Point at infinity with Z=0 (in projective coordinates) -> (0, 1) is treated as an exception, which is trivially not constant time. 1999*f0865ec9SKyle Evans * This is OK since our mapping functions should be used at the non sensitive input and output 2000*f0865ec9SKyle Evans * interfaces. 2001*f0865ec9SKyle Evans * 2002*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 2003*f0865ec9SKyle Evans */ 2004*f0865ec9SKyle Evans int prj_pt_shortw_to_aff_pt_edwards(prj_pt_src_t in_shortw, 2005*f0865ec9SKyle Evans ec_edwards_crv_src_t edwards_crv, 2006*f0865ec9SKyle Evans aff_pt_edwards_t out_edwards, 2007*f0865ec9SKyle Evans fp_src_t alpha_edwards) 2008*f0865ec9SKyle Evans { 2009*f0865ec9SKyle Evans int ret, iszero; 2010*f0865ec9SKyle Evans aff_pt in_shortw_aff; 2011*f0865ec9SKyle Evans in_shortw_aff.magic = WORD(0); 2012*f0865ec9SKyle Evans 2013*f0865ec9SKyle Evans /* Check the curves compatibility */ 2014*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in_shortw); EG(ret, err); 2015*f0865ec9SKyle Evans ret = curve_edwards_shortw_check(edwards_crv, in_shortw->crv, alpha_edwards); EG(ret, err); 2016*f0865ec9SKyle Evans 2017*f0865ec9SKyle Evans /* Initialize output point with curve */ 2018*f0865ec9SKyle Evans ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err); 2019*f0865ec9SKyle Evans 2020*f0865ec9SKyle Evans /* Check if we are the point at infinity 2021*f0865ec9SKyle Evans * This check induces a non consant time exception, but the current function must be called on 2022*f0865ec9SKyle Evans * public data anyways. 2023*f0865ec9SKyle Evans */ 2024*f0865ec9SKyle Evans ret = prj_pt_iszero(in_shortw, &iszero); EG(ret, err); 2025*f0865ec9SKyle Evans if(iszero){ 2026*f0865ec9SKyle Evans fp zero, one; 2027*f0865ec9SKyle Evans zero.magic = one.magic = WORD(0); 2028*f0865ec9SKyle Evans 2029*f0865ec9SKyle Evans ret = fp_init(&zero, in_shortw->X.ctx); EG(ret, err1); 2030*f0865ec9SKyle Evans ret = fp_init(&one, in_shortw->X.ctx); EG(ret, err1); 2031*f0865ec9SKyle Evans 2032*f0865ec9SKyle Evans ret = fp_zero(&zero); EG(ret, err1); 2033*f0865ec9SKyle Evans ret = fp_one(&one); EG(ret, err1); 2034*f0865ec9SKyle Evans 2035*f0865ec9SKyle Evans ret = aff_pt_edwards_init_from_coords(out_edwards, edwards_crv, &zero, &one); 2036*f0865ec9SKyle Evans 2037*f0865ec9SKyle Evans err1: 2038*f0865ec9SKyle Evans fp_uninit(&zero); 2039*f0865ec9SKyle Evans fp_uninit(&one); 2040*f0865ec9SKyle Evans 2041*f0865ec9SKyle Evans goto err; 2042*f0865ec9SKyle Evans } 2043*f0865ec9SKyle Evans 2044*f0865ec9SKyle Evans /* Map projective to affine on the short Weierstrass */ 2045*f0865ec9SKyle Evans ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err); 2046*f0865ec9SKyle Evans /* Use the affine mapping */ 2047*f0865ec9SKyle Evans ret = aff_pt_shortw_to_edwards(&in_shortw_aff, edwards_crv, out_edwards, alpha_edwards); 2048*f0865ec9SKyle Evans 2049*f0865ec9SKyle Evans err: 2050*f0865ec9SKyle Evans aff_pt_uninit(&in_shortw_aff); 2051*f0865ec9SKyle Evans 2052*f0865ec9SKyle Evans return ret; 2053*f0865ec9SKyle Evans } 2054*f0865ec9SKyle Evans 2055*f0865ec9SKyle Evans /* 2056*f0865ec9SKyle Evans * Map points from Montgomery to short Weierstrass projective points. 2057*f0865ec9SKyle Evans * 2058*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 2059*f0865ec9SKyle Evans */ 2060*f0865ec9SKyle Evans int aff_pt_montgomery_to_prj_pt_shortw(aff_pt_montgomery_src_t in_montgomery, 2061*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv, 2062*f0865ec9SKyle Evans prj_pt_t out_shortw) 2063*f0865ec9SKyle Evans { 2064*f0865ec9SKyle Evans int ret; 2065*f0865ec9SKyle Evans aff_pt out_shortw_aff; 2066*f0865ec9SKyle Evans out_shortw_aff.magic = WORD(0); 2067*f0865ec9SKyle Evans 2068*f0865ec9SKyle Evans /* Check the curves compatibility */ 2069*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err); 2070*f0865ec9SKyle Evans ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err); 2071*f0865ec9SKyle Evans 2072*f0865ec9SKyle Evans /* Initialize output point with curve */ 2073*f0865ec9SKyle Evans ret = prj_pt_init(out_shortw, shortw_crv); EG(ret, err); 2074*f0865ec9SKyle Evans 2075*f0865ec9SKyle Evans /* Use the affine mapping */ 2076*f0865ec9SKyle Evans ret = aff_pt_montgomery_to_shortw(in_montgomery, shortw_crv, &out_shortw_aff); EG(ret, err); 2077*f0865ec9SKyle Evans /* And then map the short Weierstrass affine to projective coordinates */ 2078*f0865ec9SKyle Evans ret = ec_shortw_aff_to_prj(out_shortw, &out_shortw_aff); 2079*f0865ec9SKyle Evans 2080*f0865ec9SKyle Evans err: 2081*f0865ec9SKyle Evans aff_pt_uninit(&out_shortw_aff); 2082*f0865ec9SKyle Evans 2083*f0865ec9SKyle Evans return ret; 2084*f0865ec9SKyle Evans } 2085*f0865ec9SKyle Evans 2086*f0865ec9SKyle Evans /* 2087*f0865ec9SKyle Evans * Map points from short Weierstrass projective points to Montgomery. 2088*f0865ec9SKyle Evans * 2089*f0865ec9SKyle Evans * The function returns 0 on success, -1 on error. 2090*f0865ec9SKyle Evans */ 2091*f0865ec9SKyle Evans int 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) 2092*f0865ec9SKyle Evans { 2093*f0865ec9SKyle Evans int ret; 2094*f0865ec9SKyle Evans aff_pt in_shortw_aff; 2095*f0865ec9SKyle Evans in_shortw_aff.magic = WORD(0); 2096*f0865ec9SKyle Evans 2097*f0865ec9SKyle Evans /* Check the curves compatibility */ 2098*f0865ec9SKyle Evans ret = prj_pt_check_initialized(in_shortw); EG(ret, err); 2099*f0865ec9SKyle Evans ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err); 2100*f0865ec9SKyle Evans 2101*f0865ec9SKyle Evans /* Initialize output point with curve */ 2102*f0865ec9SKyle Evans ret = aff_pt_init(&in_shortw_aff, in_shortw->crv); EG(ret, err); 2103*f0865ec9SKyle Evans 2104*f0865ec9SKyle Evans /* Map projective to affine on the short Weierstrass */ 2105*f0865ec9SKyle Evans ret = prj_pt_to_aff(&in_shortw_aff, in_shortw); EG(ret, err); 2106*f0865ec9SKyle Evans /* Use the affine mapping */ 2107*f0865ec9SKyle Evans ret = aff_pt_shortw_to_montgomery(&in_shortw_aff, montgomery_crv, out_montgomery); 2108*f0865ec9SKyle Evans 2109*f0865ec9SKyle Evans err: 2110*f0865ec9SKyle Evans aff_pt_uninit(&in_shortw_aff); 2111*f0865ec9SKyle Evans 2112*f0865ec9SKyle Evans return ret; 2113*f0865ec9SKyle Evans } 2114