1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2021 - 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 * 8*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 9*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 10*f0865ec9SKyle Evans */ 11*f0865ec9SKyle Evans #include <libecc/curves/aff_pt.h> 12*f0865ec9SKyle Evans 13*f0865ec9SKyle Evans /* NOTE: Edwards here implies Twisted Edwards curves 14*f0865ec9SKyle Evans * (these in fact include/extend basic form Edwards curves). 15*f0865ec9SKyle Evans */ 16*f0865ec9SKyle Evans 17*f0865ec9SKyle Evans #define AFF_PT_EDWARDS_MAGIC ((word_t)(0x8390a9bc43d9ffabULL)) 18*f0865ec9SKyle Evans 19*f0865ec9SKyle Evans /* Verify that an affine point has already been initialized 20*f0865ec9SKyle Evans * 21*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 22*f0865ec9SKyle Evans */ 23*f0865ec9SKyle Evans int aff_pt_edwards_check_initialized(aff_pt_edwards_src_t in) 24*f0865ec9SKyle Evans { 25*f0865ec9SKyle Evans int ret; 26*f0865ec9SKyle Evans 27*f0865ec9SKyle Evans MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC)), ret, err); 28*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(in->crv); 29*f0865ec9SKyle Evans 30*f0865ec9SKyle Evans err: 31*f0865ec9SKyle Evans return ret; 32*f0865ec9SKyle Evans } 33*f0865ec9SKyle Evans 34*f0865ec9SKyle Evans /* 35*f0865ec9SKyle Evans * Initialize pointed aff_pt_edwards structure to make it usable by library 36*f0865ec9SKyle Evans * function on given curve. 37*f0865ec9SKyle Evans * 38*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 39*f0865ec9SKyle Evans */ 40*f0865ec9SKyle Evans int aff_pt_edwards_init(aff_pt_edwards_t in, ec_edwards_crv_src_t curve) 41*f0865ec9SKyle Evans { 42*f0865ec9SKyle Evans int ret; 43*f0865ec9SKyle Evans 44*f0865ec9SKyle Evans MUST_HAVE((in != NULL), ret, err); 45*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(curve); EG(ret, err); 46*f0865ec9SKyle Evans 47*f0865ec9SKyle Evans ret = fp_init(&(in->x), curve->a.ctx); EG(ret, err); 48*f0865ec9SKyle Evans ret = fp_init(&(in->y), curve->a.ctx); EG(ret, err); 49*f0865ec9SKyle Evans 50*f0865ec9SKyle Evans in->crv = curve; 51*f0865ec9SKyle Evans in->magic = AFF_PT_EDWARDS_MAGIC; 52*f0865ec9SKyle Evans 53*f0865ec9SKyle Evans err: 54*f0865ec9SKyle Evans return ret; 55*f0865ec9SKyle Evans } 56*f0865ec9SKyle Evans 57*f0865ec9SKyle Evans /* 58*f0865ec9SKyle Evans * Initialize pointed aff_pt_edwards structure to make it usable by library 59*f0865ec9SKyle Evans * function on given curve with explicit coordinates. 60*f0865ec9SKyle Evans * 61*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 62*f0865ec9SKyle Evans */ 63*f0865ec9SKyle Evans int aff_pt_edwards_init_from_coords(aff_pt_edwards_t in, 64*f0865ec9SKyle Evans ec_edwards_crv_src_t curve, 65*f0865ec9SKyle Evans fp_src_t xcoord, fp_src_t ycoord) 66*f0865ec9SKyle Evans { 67*f0865ec9SKyle Evans int ret; 68*f0865ec9SKyle Evans 69*f0865ec9SKyle Evans ret = aff_pt_edwards_init(in, curve); EG(ret, err); 70*f0865ec9SKyle Evans ret = fp_copy(&(in->x), xcoord); EG(ret, err); 71*f0865ec9SKyle Evans ret = fp_copy(&(in->y), ycoord); 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evans err: 74*f0865ec9SKyle Evans return ret; 75*f0865ec9SKyle Evans } 76*f0865ec9SKyle Evans 77*f0865ec9SKyle Evans /* 78*f0865ec9SKyle Evans * Uninitialize pointed affine point to prevent further use (magic field 79*f0865ec9SKyle Evans * in the structure is zeroized) and zeroize associated storage space. 80*f0865ec9SKyle Evans * Note that the curve context pointed to by the point element (passed 81*f0865ec9SKyle Evans * during init) is left untouched. 82*f0865ec9SKyle Evans * 83*f0865ec9SKyle Evans */ 84*f0865ec9SKyle Evans void aff_pt_edwards_uninit(aff_pt_edwards_t in) 85*f0865ec9SKyle Evans { 86*f0865ec9SKyle Evans if ((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC) && (in->crv != NULL)) { 87*f0865ec9SKyle Evans fp_uninit(&(in->x)); 88*f0865ec9SKyle Evans fp_uninit(&(in->y)); 89*f0865ec9SKyle Evans 90*f0865ec9SKyle Evans in->crv = NULL; 91*f0865ec9SKyle Evans in->magic = WORD(0); 92*f0865ec9SKyle Evans } 93*f0865ec9SKyle Evans 94*f0865ec9SKyle Evans return; 95*f0865ec9SKyle Evans } 96*f0865ec9SKyle Evans 97*f0865ec9SKyle Evans /* 98*f0865ec9SKyle Evans * 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it 99*f0865ec9SKyle Evans * verifies curve equation a*x^2 + y^2 = 1 + d*x^2*y^2. It is set to 0 otherwise. 100*f0865ec9SKyle Evans * 'on_curve' is not meaningful on error. 101*f0865ec9SKyle Evans * 102*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 103*f0865ec9SKyle Evans */ 104*f0865ec9SKyle Evans int is_on_edwards_curve(fp_src_t x, fp_src_t y, 105*f0865ec9SKyle Evans ec_edwards_crv_src_t curve, 106*f0865ec9SKyle Evans int *on_curve) 107*f0865ec9SKyle Evans { 108*f0865ec9SKyle Evans fp x2, y2, tmp1, tmp2; 109*f0865ec9SKyle Evans int ret, cmp; 110*f0865ec9SKyle Evans x2.magic = y2.magic = tmp1.magic = tmp2.magic = WORD(0); 111*f0865ec9SKyle Evans 112*f0865ec9SKyle Evans MUST_HAVE((on_curve != NULL), ret, err); 113*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(curve); EG(ret, err); 114*f0865ec9SKyle Evans 115*f0865ec9SKyle Evans ret = fp_check_initialized(x); EG(ret, err); 116*f0865ec9SKyle Evans ret = fp_check_initialized(y); EG(ret, err); 117*f0865ec9SKyle Evans 118*f0865ec9SKyle Evans MUST_HAVE((x->ctx == y->ctx), ret, err); 119*f0865ec9SKyle Evans MUST_HAVE((x->ctx == curve->a.ctx), ret, err); 120*f0865ec9SKyle Evans 121*f0865ec9SKyle Evans ret = fp_init(&x2, x->ctx); EG(ret, err); 122*f0865ec9SKyle Evans ret = fp_sqr(&x2, x); EG(ret, err); 123*f0865ec9SKyle Evans ret = fp_init(&y2, x->ctx); EG(ret, err); 124*f0865ec9SKyle Evans ret = fp_sqr(&y2, y); EG(ret, err); 125*f0865ec9SKyle Evans 126*f0865ec9SKyle Evans ret = fp_init(&tmp1, x->ctx); EG(ret, err); 127*f0865ec9SKyle Evans ret = fp_init(&tmp2, x->ctx); EG(ret, err); 128*f0865ec9SKyle Evans 129*f0865ec9SKyle Evans ret = fp_mul(&tmp1, &x2, &y2); EG(ret, err); 130*f0865ec9SKyle Evans ret = fp_mul(&tmp1, &tmp1, &(curve->d)); EG(ret, err); 131*f0865ec9SKyle Evans ret = fp_inc(&tmp1, &tmp1); EG(ret, err); 132*f0865ec9SKyle Evans 133*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &x2, &(curve->a)); EG(ret, err); 134*f0865ec9SKyle Evans ret = fp_add(&tmp2, &tmp2, &y2); EG(ret, err); 135*f0865ec9SKyle Evans 136*f0865ec9SKyle Evans ret = fp_cmp(&tmp1, &tmp2, &cmp); 137*f0865ec9SKyle Evans 138*f0865ec9SKyle Evans if (!ret) { 139*f0865ec9SKyle Evans (*on_curve) = (!cmp); 140*f0865ec9SKyle Evans } 141*f0865ec9SKyle Evans 142*f0865ec9SKyle Evans err: 143*f0865ec9SKyle Evans fp_uninit(&x2); 144*f0865ec9SKyle Evans fp_uninit(&y2); 145*f0865ec9SKyle Evans fp_uninit(&tmp1); 146*f0865ec9SKyle Evans fp_uninit(&tmp2); 147*f0865ec9SKyle Evans 148*f0865ec9SKyle Evans return ret; 149*f0865ec9SKyle Evans } 150*f0865ec9SKyle Evans 151*f0865ec9SKyle Evans /* 152*f0865ec9SKyle Evans * Checks if affine coordinates point is on an Edwards curve. 'on_curve' is set 153*f0865ec9SKyle Evans * to 1 if yes, 0 if no. 'on_curve' is not meaningful in case of error. 154*f0865ec9SKyle Evans * 155*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 156*f0865ec9SKyle Evans */ 157*f0865ec9SKyle Evans int aff_pt_edwards_is_on_curve(aff_pt_edwards_src_t pt, int *on_curve) 158*f0865ec9SKyle Evans { 159*f0865ec9SKyle Evans int ret; 160*f0865ec9SKyle Evans 161*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(pt); EG(ret, err); 162*f0865ec9SKyle Evans 163*f0865ec9SKyle Evans ret = is_on_edwards_curve(&(pt->x), &(pt->y), pt->crv, on_curve); 164*f0865ec9SKyle Evans 165*f0865ec9SKyle Evans err: 166*f0865ec9SKyle Evans return ret; 167*f0865ec9SKyle Evans } 168*f0865ec9SKyle Evans 169*f0865ec9SKyle Evans /* 170*f0865ec9SKyle Evans * Copy an Edwards affine point in an output. The output is initialized properly. 171*f0865ec9SKyle Evans * 172*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 173*f0865ec9SKyle Evans */ 174*f0865ec9SKyle Evans int ec_edwards_aff_copy(aff_pt_edwards_t out, aff_pt_edwards_src_t in) 175*f0865ec9SKyle Evans { 176*f0865ec9SKyle Evans int ret; 177*f0865ec9SKyle Evans 178*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(in); EG(ret, err); 179*f0865ec9SKyle Evans ret = aff_pt_edwards_init(out, in->crv); EG(ret, err); 180*f0865ec9SKyle Evans 181*f0865ec9SKyle Evans ret = fp_copy(&(out->x), &(in->x)); EG(ret, err); 182*f0865ec9SKyle Evans ret = fp_copy(&(out->y), &(in->y)); 183*f0865ec9SKyle Evans 184*f0865ec9SKyle Evans err: 185*f0865ec9SKyle Evans return ret; 186*f0865ec9SKyle Evans } 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans /* 189*f0865ec9SKyle Evans * Compares two given affine points on an Edwards curve, it returns 0 in input 190*f0865ec9SKyle Evans * 'cmp' if they correspond or not 0 if not. 'cmp' is not meaningful on error. 191*f0865ec9SKyle Evans * 192*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 193*f0865ec9SKyle Evans */ 194*f0865ec9SKyle Evans int ec_edwards_aff_cmp(aff_pt_edwards_src_t in1, aff_pt_edwards_src_t in2, 195*f0865ec9SKyle Evans int *cmp) 196*f0865ec9SKyle Evans { 197*f0865ec9SKyle Evans int ret, cmp1, cmp2; 198*f0865ec9SKyle Evans 199*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 200*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(in1); EG(ret, err); 201*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(in2); EG(ret, err); 202*f0865ec9SKyle Evans 203*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 204*f0865ec9SKyle Evans 205*f0865ec9SKyle Evans ret = fp_cmp(&(in1->x), &(in2->x), &cmp1); EG(ret, err); 206*f0865ec9SKyle Evans ret = fp_cmp(&(in1->y), &(in2->y), &cmp2); 207*f0865ec9SKyle Evans 208*f0865ec9SKyle Evans if (!ret) { 209*f0865ec9SKyle Evans (*cmp) = (cmp1 | cmp2); 210*f0865ec9SKyle Evans } 211*f0865ec9SKyle Evans 212*f0865ec9SKyle Evans err: 213*f0865ec9SKyle Evans return ret; 214*f0865ec9SKyle Evans } 215*f0865ec9SKyle Evans 216*f0865ec9SKyle Evans /* 217*f0865ec9SKyle Evans * Import an Edwards affine point from a buffer with the following layout; the 2 218*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 219*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 220*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 221*f0865ec9SKyle Evans * 2 * p_len. 222*f0865ec9SKyle Evans * 223*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 224*f0865ec9SKyle Evans */ 225*f0865ec9SKyle Evans int aff_pt_edwards_import_from_buf(aff_pt_edwards_t pt, 226*f0865ec9SKyle Evans const u8 *pt_buf, 227*f0865ec9SKyle Evans u16 pt_buf_len, ec_edwards_crv_src_t crv) 228*f0865ec9SKyle Evans { 229*f0865ec9SKyle Evans fp_ctx_src_t ctx; 230*f0865ec9SKyle Evans u16 coord_len; 231*f0865ec9SKyle Evans int ret, on_curve; 232*f0865ec9SKyle Evans 233*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(crv); EG(ret, err); 234*f0865ec9SKyle Evans MUST_HAVE(((pt_buf != NULL) && (pt != NULL)), ret, err); 235*f0865ec9SKyle Evans 236*f0865ec9SKyle Evans ctx = crv->a.ctx; 237*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 238*f0865ec9SKyle Evans 239*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 240*f0865ec9SKyle Evans 241*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->x), ctx, pt_buf, coord_len); EG(ret, err); 242*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->y), ctx, pt_buf + coord_len, coord_len); EG(ret, err); 243*f0865ec9SKyle Evans 244*f0865ec9SKyle Evans /* Set the curve */ 245*f0865ec9SKyle Evans pt->crv = crv; 246*f0865ec9SKyle Evans 247*f0865ec9SKyle Evans /* Mark the point as initialized */ 248*f0865ec9SKyle Evans pt->magic = AFF_PT_EDWARDS_MAGIC; 249*f0865ec9SKyle Evans 250*f0865ec9SKyle Evans /* Check that the point is indeed on the provided curve, uninitialize it 251*f0865ec9SKyle Evans * if this is not the case. 252*f0865ec9SKyle Evans */ 253*f0865ec9SKyle Evans ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err); 254*f0865ec9SKyle Evans if (!on_curve) { 255*f0865ec9SKyle Evans aff_pt_edwards_uninit(pt); 256*f0865ec9SKyle Evans ret = -1; 257*f0865ec9SKyle Evans } 258*f0865ec9SKyle Evans 259*f0865ec9SKyle Evans err: 260*f0865ec9SKyle Evans return ret; 261*f0865ec9SKyle Evans } 262*f0865ec9SKyle Evans 263*f0865ec9SKyle Evans 264*f0865ec9SKyle Evans /* Export an Edwards affine point to a buffer with the following layout; the 2 265*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 266*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 267*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 268*f0865ec9SKyle Evans * 2 * p_len. 269*f0865ec9SKyle Evans * 270*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 271*f0865ec9SKyle Evans */ 272*f0865ec9SKyle Evans int aff_pt_edwards_export_to_buf(aff_pt_edwards_src_t pt, 273*f0865ec9SKyle Evans u8 *pt_buf, u32 pt_buf_len) 274*f0865ec9SKyle Evans { 275*f0865ec9SKyle Evans fp_ctx_src_t ctx; 276*f0865ec9SKyle Evans u16 coord_len; 277*f0865ec9SKyle Evans int ret, on_curve; 278*f0865ec9SKyle Evans 279*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(pt); EG(ret, err); 280*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 281*f0865ec9SKyle Evans 282*f0865ec9SKyle Evans /* The point to be exported must be on the curve */ 283*f0865ec9SKyle Evans ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err); 284*f0865ec9SKyle Evans MUST_HAVE(on_curve, ret, err); 285*f0865ec9SKyle Evans 286*f0865ec9SKyle Evans ctx = pt->crv->a.ctx; 287*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 288*f0865ec9SKyle Evans 289*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 290*f0865ec9SKyle Evans 291*f0865ec9SKyle Evans /* Export the three coordinates */ 292*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf, coord_len, &(pt->x)); EG(ret, err); 293*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->y)); 294*f0865ec9SKyle Evans 295*f0865ec9SKyle Evans err: 296*f0865ec9SKyle Evans return ret; 297*f0865ec9SKyle Evans } 298*f0865ec9SKyle Evans 299*f0865ec9SKyle Evans /* 300*f0865ec9SKyle Evans * Mapping curves from twisted Edwards to Montgomery. 301*f0865ec9SKyle Evans * 302*f0865ec9SKyle Evans * E{a, d} is mapped to M{A, B} using the formula: 303*f0865ec9SKyle Evans * A = 2(a+d)/(a-d) 304*f0865ec9SKyle Evans * B = 4/((a-d) * alpha^2) 305*f0865ec9SKyle Evans * 306*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 307*f0865ec9SKyle Evans */ 308*f0865ec9SKyle Evans int curve_edwards_to_montgomery(ec_edwards_crv_src_t edwards_crv, 309*f0865ec9SKyle Evans ec_montgomery_crv_t montgomery_crv, 310*f0865ec9SKyle Evans fp_src_t alpha_edwards) 311*f0865ec9SKyle Evans { 312*f0865ec9SKyle Evans fp tmp1, tmp2, A, B; 313*f0865ec9SKyle Evans int ret; 314*f0865ec9SKyle Evans tmp1.magic = tmp2.magic = A.magic = B.magic = WORD(0); 315*f0865ec9SKyle Evans 316*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err); 317*f0865ec9SKyle Evans ret = fp_check_initialized(alpha_edwards); EG(ret, err); 318*f0865ec9SKyle Evans MUST_HAVE((edwards_crv->a.ctx == alpha_edwards->ctx), ret, err); 319*f0865ec9SKyle Evans 320*f0865ec9SKyle Evans ret = fp_init(&tmp1, edwards_crv->a.ctx); EG(ret, err); 321*f0865ec9SKyle Evans ret = fp_init(&tmp2, edwards_crv->a.ctx); EG(ret, err); 322*f0865ec9SKyle Evans ret = fp_init(&A, edwards_crv->a.ctx); EG(ret, err); 323*f0865ec9SKyle Evans ret = fp_init(&B, edwards_crv->a.ctx); EG(ret, err); 324*f0865ec9SKyle Evans 325*f0865ec9SKyle Evans 326*f0865ec9SKyle Evans /* Compute Z = (alpha ^ 2) et T = 2 / ((a-d) * Z) 327*f0865ec9SKyle Evans * and then: 328*f0865ec9SKyle Evans * A = 2(a+d)/(a-d) = Z * (a + d) * T 329*f0865ec9SKyle Evans * B = 4/((a-d) * alpha^2) = 2 * T 330*f0865ec9SKyle Evans */ 331*f0865ec9SKyle Evans ret = fp_sqr(&tmp1, alpha_edwards); EG(ret, err); 332*f0865ec9SKyle Evans ret = fp_sub(&tmp2, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err); 333*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &tmp1); EG(ret, err); 334*f0865ec9SKyle Evans ret = fp_inv(&tmp2, &tmp2); EG(ret, err); 335*f0865ec9SKyle Evans ret = fp_set_word_value(&B, WORD(2)); EG(ret, err); 336*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &B); EG(ret, err); 337*f0865ec9SKyle Evans 338*f0865ec9SKyle Evans ret = fp_add(&A, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err); 339*f0865ec9SKyle Evans ret = fp_mul(&A, &A, &tmp1); EG(ret, err); 340*f0865ec9SKyle Evans ret = fp_mul(&A, &A, &tmp2); EG(ret, err); 341*f0865ec9SKyle Evans ret = fp_mul(&B, &B, &tmp2); EG(ret, err); 342*f0865ec9SKyle Evans 343*f0865ec9SKyle Evans /* Initialize our Montgomery curve */ 344*f0865ec9SKyle Evans ret = ec_montgomery_crv_init(montgomery_crv, &A, &B, &(edwards_crv->order)); 345*f0865ec9SKyle Evans 346*f0865ec9SKyle Evans err: 347*f0865ec9SKyle Evans fp_uninit(&tmp1); 348*f0865ec9SKyle Evans fp_uninit(&tmp2); 349*f0865ec9SKyle Evans fp_uninit(&A); 350*f0865ec9SKyle Evans fp_uninit(&B); 351*f0865ec9SKyle Evans 352*f0865ec9SKyle Evans return ret; 353*f0865ec9SKyle Evans } 354*f0865ec9SKyle Evans 355*f0865ec9SKyle Evans /* 356*f0865ec9SKyle Evans * Checks that an Edwards curve and Montgomery curve are compatible. 357*f0865ec9SKyle Evans * 358*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 359*f0865ec9SKyle Evans */ 360*f0865ec9SKyle Evans int curve_edwards_montgomery_check(ec_edwards_crv_src_t e_crv, 361*f0865ec9SKyle Evans ec_montgomery_crv_src_t m_crv, 362*f0865ec9SKyle Evans fp_src_t alpha_edwards) 363*f0865ec9SKyle Evans { 364*f0865ec9SKyle Evans int ret, cmp; 365*f0865ec9SKyle Evans ec_montgomery_crv check; 366*f0865ec9SKyle Evans check.magic = WORD(0); 367*f0865ec9SKyle Evans 368*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err); 369*f0865ec9SKyle Evans ret = curve_edwards_to_montgomery(e_crv, &check, alpha_edwards); EG(ret, err); 370*f0865ec9SKyle Evans 371*f0865ec9SKyle Evans /* Check elements */ 372*f0865ec9SKyle Evans MUST_HAVE((!fp_cmp(&(check.A), &(m_crv->A), &cmp)) && (!cmp), ret, err); 373*f0865ec9SKyle Evans MUST_HAVE((!fp_cmp(&(check.B), &(m_crv->B), &cmp)) && (!cmp), ret, err); 374*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(&(check.order), &(m_crv->order), &cmp)) && (!cmp), ret, err); 375*f0865ec9SKyle Evans 376*f0865ec9SKyle Evans err: 377*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&check); 378*f0865ec9SKyle Evans 379*f0865ec9SKyle Evans return ret; 380*f0865ec9SKyle Evans } 381*f0865ec9SKyle Evans 382*f0865ec9SKyle Evans /* 383*f0865ec9SKyle Evans * Mapping curves from Montgomery to twisted Edwards. 384*f0865ec9SKyle Evans * 385*f0865ec9SKyle Evans * M{A, B} is mapped to E{a, d} using the formula: 386*f0865ec9SKyle Evans * a = (A+2)/(B * alpha^2) 387*f0865ec9SKyle Evans * d = (A-2)/(B * alpha^2) 388*f0865ec9SKyle Evans * 389*f0865ec9SKyle Evans * Or the inverse (switch a and d roles). 390*f0865ec9SKyle Evans * 391*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 392*f0865ec9SKyle Evans */ 393*f0865ec9SKyle Evans int curve_montgomery_to_edwards(ec_montgomery_crv_src_t m_crv, 394*f0865ec9SKyle Evans ec_edwards_crv_t e_crv, 395*f0865ec9SKyle Evans fp_src_t alpha_edwards) 396*f0865ec9SKyle Evans { 397*f0865ec9SKyle Evans int ret, cmp; 398*f0865ec9SKyle Evans fp tmp, tmp2, a, d; 399*f0865ec9SKyle Evans tmp.magic = tmp2.magic = a.magic = d.magic = WORD(0); 400*f0865ec9SKyle Evans 401*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err); 402*f0865ec9SKyle Evans ret = fp_check_initialized(alpha_edwards); EG(ret, err); 403*f0865ec9SKyle Evans MUST_HAVE((m_crv->A.ctx == alpha_edwards->ctx), ret, err); 404*f0865ec9SKyle Evans 405*f0865ec9SKyle Evans ret = fp_init(&tmp, m_crv->A.ctx); EG(ret, err); 406*f0865ec9SKyle Evans ret = fp_init(&tmp2, m_crv->A.ctx); EG(ret, err); 407*f0865ec9SKyle Evans ret = fp_init(&a, m_crv->A.ctx); EG(ret, err); 408*f0865ec9SKyle Evans ret = fp_init(&d, m_crv->A.ctx); EG(ret, err); 409*f0865ec9SKyle Evans 410*f0865ec9SKyle Evans ret = fp_set_word_value(&tmp, WORD(2)); EG(ret, err); 411*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &(m_crv->B), alpha_edwards); EG(ret, err); 412*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, alpha_edwards); EG(ret, err); 413*f0865ec9SKyle Evans ret = fp_inv(&tmp2, &tmp2); EG(ret, err); 414*f0865ec9SKyle Evans 415*f0865ec9SKyle Evans /* a = (A+2)/(B * alpha^2) */ 416*f0865ec9SKyle Evans ret = fp_add(&a, &(m_crv->A), &tmp); EG(ret, err); 417*f0865ec9SKyle Evans ret = fp_mul(&a, &a, &tmp2); EG(ret, err); 418*f0865ec9SKyle Evans 419*f0865ec9SKyle Evans /* d = (A-2)/(B * alpha^2) */ 420*f0865ec9SKyle Evans ret = fp_sub(&d, &(m_crv->A), &tmp); EG(ret, err); 421*f0865ec9SKyle Evans ret = fp_mul(&d, &d, &tmp2); EG(ret, err); 422*f0865ec9SKyle Evans 423*f0865ec9SKyle Evans /* Initialize our Edwards curve */ 424*f0865ec9SKyle Evans /* Check if we have to inverse a and d */ 425*f0865ec9SKyle Evans ret = fp_one(&tmp); EG(ret, err); 426*f0865ec9SKyle Evans ret = fp_cmp(&d, &tmp, &cmp); EG(ret, err); 427*f0865ec9SKyle Evans if (cmp == 0) { 428*f0865ec9SKyle Evans ret = ec_edwards_crv_init(e_crv, &d, &a, &(m_crv->order)); 429*f0865ec9SKyle Evans } else { 430*f0865ec9SKyle Evans ret = ec_edwards_crv_init(e_crv, &a, &d, &(m_crv->order)); 431*f0865ec9SKyle Evans } 432*f0865ec9SKyle Evans 433*f0865ec9SKyle Evans err: 434*f0865ec9SKyle Evans fp_uninit(&tmp); 435*f0865ec9SKyle Evans fp_uninit(&tmp2); 436*f0865ec9SKyle Evans fp_uninit(&a); 437*f0865ec9SKyle Evans fp_uninit(&d); 438*f0865ec9SKyle Evans 439*f0865ec9SKyle Evans return ret; 440*f0865ec9SKyle Evans } 441*f0865ec9SKyle Evans 442*f0865ec9SKyle Evans /* 443*f0865ec9SKyle Evans * Mapping curve from Edwards to short Weierstrass. 444*f0865ec9SKyle Evans * 445*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 446*f0865ec9SKyle Evans */ 447*f0865ec9SKyle Evans int curve_edwards_to_shortw(ec_edwards_crv_src_t edwards_crv, 448*f0865ec9SKyle Evans ec_shortw_crv_t shortw_crv, 449*f0865ec9SKyle Evans fp_src_t alpha_edwards) 450*f0865ec9SKyle Evans { 451*f0865ec9SKyle Evans int ret; 452*f0865ec9SKyle Evans ec_montgomery_crv montgomery_crv; 453*f0865ec9SKyle Evans montgomery_crv.magic = WORD(0); 454*f0865ec9SKyle Evans 455*f0865ec9SKyle Evans ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err); 456*f0865ec9SKyle Evans ret = curve_montgomery_to_shortw(&montgomery_crv, shortw_crv); 457*f0865ec9SKyle Evans 458*f0865ec9SKyle Evans err: 459*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&montgomery_crv); 460*f0865ec9SKyle Evans 461*f0865ec9SKyle Evans return ret; 462*f0865ec9SKyle Evans } 463*f0865ec9SKyle Evans 464*f0865ec9SKyle Evans /* Checking if an Edwards curve and short Weierstrass curve are compliant (through Montgomery mapping). 465*f0865ec9SKyle Evans * 466*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 467*f0865ec9SKyle Evans */ 468*f0865ec9SKyle Evans int curve_edwards_shortw_check(ec_edwards_crv_src_t edwards_crv, 469*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv, 470*f0865ec9SKyle Evans fp_src_t alpha_edwards) 471*f0865ec9SKyle Evans { 472*f0865ec9SKyle Evans int ret; 473*f0865ec9SKyle Evans ec_montgomery_crv montgomery_crv; 474*f0865ec9SKyle Evans montgomery_crv.magic = WORD(0); 475*f0865ec9SKyle Evans 476*f0865ec9SKyle Evans ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err); 477*f0865ec9SKyle Evans 478*f0865ec9SKyle Evans ret = curve_montgomery_shortw_check(&montgomery_crv, shortw_crv); 479*f0865ec9SKyle Evans 480*f0865ec9SKyle Evans err: 481*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&montgomery_crv); 482*f0865ec9SKyle Evans 483*f0865ec9SKyle Evans return ret; 484*f0865ec9SKyle Evans } 485*f0865ec9SKyle Evans 486*f0865ec9SKyle Evans /* 487*f0865ec9SKyle Evans * Mapping curve from short Weierstrass to Edwards. 488*f0865ec9SKyle Evans * 489*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 490*f0865ec9SKyle Evans */ 491*f0865ec9SKyle Evans int curve_shortw_to_edwards(ec_shortw_crv_src_t shortw_crv, 492*f0865ec9SKyle Evans ec_edwards_crv_t edwards_crv, 493*f0865ec9SKyle Evans fp_src_t alpha_montgomery, 494*f0865ec9SKyle Evans fp_src_t gamma_montgomery, 495*f0865ec9SKyle Evans fp_src_t alpha_edwards) 496*f0865ec9SKyle Evans { 497*f0865ec9SKyle Evans int ret; 498*f0865ec9SKyle Evans ec_montgomery_crv montgomery_crv; 499*f0865ec9SKyle Evans montgomery_crv.magic = WORD(0); 500*f0865ec9SKyle Evans 501*f0865ec9SKyle Evans ret = curve_shortw_to_montgomery(shortw_crv, &montgomery_crv, alpha_montgomery, gamma_montgomery); EG(ret, err); 502*f0865ec9SKyle Evans 503*f0865ec9SKyle Evans ret = curve_montgomery_to_edwards(&montgomery_crv, edwards_crv, alpha_edwards); 504*f0865ec9SKyle Evans 505*f0865ec9SKyle Evans err: 506*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&montgomery_crv); 507*f0865ec9SKyle Evans 508*f0865ec9SKyle Evans return ret; 509*f0865ec9SKyle Evans } 510*f0865ec9SKyle Evans 511*f0865ec9SKyle Evans /* 512*f0865ec9SKyle Evans * Mapping points from twisted Edwards to Montgomery. 513*f0865ec9SKyle Evans * Point E(x, y) is mapped to M(u, v) with the formula: 514*f0865ec9SKyle Evans * - (0, 1) mapped to the point at infinity (not possible in our affine coordinates) 515*f0865ec9SKyle Evans * - (0, -1) mapped to (0, 0) 516*f0865ec9SKyle Evans * - (u, v) mapped to ((1+y)/(1-y), alpha * (1+y)/((1-y)x)) 517*f0865ec9SKyle Evans * 518*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 519*f0865ec9SKyle Evans */ 520*f0865ec9SKyle Evans int aff_pt_edwards_to_montgomery(aff_pt_edwards_src_t in_edwards, 521*f0865ec9SKyle Evans ec_montgomery_crv_src_t montgomery_crv, 522*f0865ec9SKyle Evans aff_pt_montgomery_t out_montgomery, 523*f0865ec9SKyle Evans fp_src_t alpha_edwards) 524*f0865ec9SKyle Evans { 525*f0865ec9SKyle Evans /* NOTE: we attempt to perform the (0, -1) -> (0, 0) mapping in constant time. 526*f0865ec9SKyle Evans * Hence the weird table selection. 527*f0865ec9SKyle Evans */ 528*f0865ec9SKyle Evans int ret, iszero, on_curve, cmp; 529*f0865ec9SKyle Evans fp tmp, tmp2, x, y; 530*f0865ec9SKyle Evans fp tab_x[2]; 531*f0865ec9SKyle Evans fp_src_t tab_x_t[2] = { &tab_x[0], &tab_x[1] }; 532*f0865ec9SKyle Evans fp tab_y[2]; 533*f0865ec9SKyle Evans fp_src_t tab_y_t[2] = { &tab_y[0], &tab_y[1] }; 534*f0865ec9SKyle Evans u8 idx = 0; 535*f0865ec9SKyle Evans tmp.magic = tmp2.magic = x.magic = y.magic = WORD(0); 536*f0865ec9SKyle Evans tab_x[0].magic = tab_x[1].magic = WORD(0); 537*f0865ec9SKyle Evans tab_y[0].magic = tab_y[1].magic = WORD(0); 538*f0865ec9SKyle Evans 539*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err); 540*f0865ec9SKyle Evans 541*f0865ec9SKyle Evans /* Check input point is on its curve */ 542*f0865ec9SKyle Evans ret = aff_pt_edwards_is_on_curve(in_edwards, &on_curve); EG(ret, err); 543*f0865ec9SKyle Evans MUST_HAVE(on_curve, ret, err); 544*f0865ec9SKyle Evans 545*f0865ec9SKyle Evans ret = curve_edwards_montgomery_check(in_edwards->crv, montgomery_crv, alpha_edwards); EG(ret, err); 546*f0865ec9SKyle Evans 547*f0865ec9SKyle Evans ret = fp_init(&tmp, in_edwards->crv->a.ctx); EG(ret, err); 548*f0865ec9SKyle Evans ret = fp_init(&tmp2, in_edwards->crv->a.ctx); EG(ret, err); 549*f0865ec9SKyle Evans ret = fp_init(&x, in_edwards->crv->a.ctx); EG(ret, err); 550*f0865ec9SKyle Evans ret = fp_init(&y, in_edwards->crv->a.ctx); EG(ret, err); 551*f0865ec9SKyle Evans ret = fp_init(&tab_x[0], in_edwards->crv->a.ctx); EG(ret, err); 552*f0865ec9SKyle Evans ret = fp_init(&tab_x[1], in_edwards->crv->a.ctx); EG(ret, err); 553*f0865ec9SKyle Evans ret = fp_init(&tab_y[0], in_edwards->crv->a.ctx); EG(ret, err); 554*f0865ec9SKyle Evans ret = fp_init(&tab_y[1], in_edwards->crv->a.ctx); EG(ret, err); 555*f0865ec9SKyle Evans 556*f0865ec9SKyle Evans ret = fp_one(&tmp); EG(ret, err); 557*f0865ec9SKyle Evans /* We do not handle point at infinity in affine coordinates */ 558*f0865ec9SKyle Evans ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err); 559*f0865ec9SKyle Evans ret = fp_cmp(&(in_edwards->y), &tmp, &cmp); EG(ret, err); 560*f0865ec9SKyle Evans MUST_HAVE(!(iszero && (cmp == 0)), ret, err); 561*f0865ec9SKyle Evans /* Map (0, -1) to (0, 0) */ 562*f0865ec9SKyle Evans ret = fp_zero(&tmp2); EG(ret, err); 563*f0865ec9SKyle Evans ret = fp_sub(&tmp2, &tmp2, &tmp); EG(ret, err); 564*f0865ec9SKyle Evans /* Copy 1 as x as dummy value */ 565*f0865ec9SKyle Evans ret = fp_one(&tab_x[0]); EG(ret, err); 566*f0865ec9SKyle Evans ret = fp_copy(&tab_x[1], &(in_edwards->x)); EG(ret, err); 567*f0865ec9SKyle Evans /* Copy -1 as y to produce (0, 0) */ 568*f0865ec9SKyle Evans ret = fp_copy(&tab_y[0], &tmp2); EG(ret, err); 569*f0865ec9SKyle Evans ret = fp_copy(&tab_y[1], &(in_edwards->y)); EG(ret, err); 570*f0865ec9SKyle Evans 571*f0865ec9SKyle Evans ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err); 572*f0865ec9SKyle Evans ret = fp_cmp(&(in_edwards->y), &tmp2, &cmp); EG(ret, err); 573*f0865ec9SKyle Evans idx = !(iszero && cmp); 574*f0865ec9SKyle Evans ret = fp_tabselect(&x, idx, tab_x_t, 2); EG(ret, err); 575*f0865ec9SKyle Evans ret = fp_tabselect(&y, idx, tab_y_t, 2); EG(ret, err); 576*f0865ec9SKyle Evans 577*f0865ec9SKyle Evans ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err); 578*f0865ec9SKyle Evans /* Compute general case */ 579*f0865ec9SKyle Evans ret = fp_copy(&tmp2, &tmp); EG(ret, err); 580*f0865ec9SKyle Evans /* Put 1/(1-y) in tmp */ 581*f0865ec9SKyle Evans ret = fp_sub(&tmp, &tmp, &y); EG(ret, err); 582*f0865ec9SKyle Evans ret = fp_inv(&tmp, &tmp); EG(ret, err); 583*f0865ec9SKyle Evans /* Put (1+y) in tmp2 */ 584*f0865ec9SKyle Evans ret = fp_add(&tmp2, &tmp2, &y); EG(ret, err); 585*f0865ec9SKyle Evans /* u = (1+y) / (1-y) */ 586*f0865ec9SKyle Evans ret = fp_mul(&(out_montgomery->u), &tmp, &tmp2); EG(ret, err); 587*f0865ec9SKyle Evans /* v = alpha_edwards * (1+y)/((1-y)x) */ 588*f0865ec9SKyle Evans ret = fp_inv(&(out_montgomery->v), &x); EG(ret, err); 589*f0865ec9SKyle Evans ret = fp_mul(&(out_montgomery->v), &(out_montgomery->v), alpha_edwards); EG(ret, err); 590*f0865ec9SKyle Evans ret = fp_mul(&(out_montgomery->v), &(out_montgomery->u), &(out_montgomery->v)); EG(ret, err); 591*f0865ec9SKyle Evans 592*f0865ec9SKyle Evans /* Final check that the point is on the curve */ 593*f0865ec9SKyle Evans ret = aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve); EG(ret, err); 594*f0865ec9SKyle Evans if (!on_curve) { 595*f0865ec9SKyle Evans ret = -1; 596*f0865ec9SKyle Evans } 597*f0865ec9SKyle Evans 598*f0865ec9SKyle Evans err: 599*f0865ec9SKyle Evans fp_uninit(&tmp); 600*f0865ec9SKyle Evans fp_uninit(&tmp2); 601*f0865ec9SKyle Evans fp_uninit(&x); 602*f0865ec9SKyle Evans fp_uninit(&y); 603*f0865ec9SKyle Evans fp_uninit(&tab_x[0]); 604*f0865ec9SKyle Evans fp_uninit(&tab_x[1]); 605*f0865ec9SKyle Evans fp_uninit(&tab_y[0]); 606*f0865ec9SKyle Evans fp_uninit(&tab_y[1]); 607*f0865ec9SKyle Evans 608*f0865ec9SKyle Evans return ret; 609*f0865ec9SKyle Evans } 610*f0865ec9SKyle Evans 611*f0865ec9SKyle Evans /* 612*f0865ec9SKyle Evans * Mapping points from Montgomery to twisted Edwards. 613*f0865ec9SKyle Evans * Point M(u, v) is mapped to E(x, y) with the formula: 614*f0865ec9SKyle Evans * - Point at infinity mapped to (0, 1) (not possible in our affine coordinates) 615*f0865ec9SKyle Evans * - (0, 0) mapped to (0, -1) 616*f0865ec9SKyle Evans * - (x, y) mapped to (alpha * (u/v), (u-1)/(u+1)) 617*f0865ec9SKyle Evans * 618*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 619*f0865ec9SKyle Evans */ 620*f0865ec9SKyle Evans int aff_pt_montgomery_to_edwards(aff_pt_montgomery_src_t in_montgomery, 621*f0865ec9SKyle Evans ec_edwards_crv_src_t edwards_crv, 622*f0865ec9SKyle Evans aff_pt_edwards_t out_edwards, 623*f0865ec9SKyle Evans fp_src_t alpha) 624*f0865ec9SKyle Evans { 625*f0865ec9SKyle Evans /* NOTE: we attempt to perform the (0, 0) -> (0, -1) mapping in constant time. 626*f0865ec9SKyle Evans * Hence the weird table selection. 627*f0865ec9SKyle Evans */ 628*f0865ec9SKyle Evans int ret, iszero1, iszero2, on_curve; 629*f0865ec9SKyle Evans fp tmp, u, v; 630*f0865ec9SKyle Evans fp tab_u[2]; 631*f0865ec9SKyle Evans fp_src_t tab_u_t[2] = { &tab_u[0], &tab_u[1] }; 632*f0865ec9SKyle Evans fp tab_v[2]; 633*f0865ec9SKyle Evans fp_src_t tab_v_t[2] = { &tab_v[0], &tab_v[1] }; 634*f0865ec9SKyle Evans u8 idx = 0; 635*f0865ec9SKyle Evans tmp.magic = u.magic = v.magic = 0; 636*f0865ec9SKyle Evans tab_u[0].magic = tab_u[1].magic = WORD(0); 637*f0865ec9SKyle Evans tab_v[0].magic = tab_v[1].magic = WORD(0); 638*f0865ec9SKyle Evans 639*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err); 640*f0865ec9SKyle Evans 641*f0865ec9SKyle Evans /* Check input point is on its curve */ 642*f0865ec9SKyle Evans ret = aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve); EG(ret, err); 643*f0865ec9SKyle Evans MUST_HAVE(on_curve, ret, err); 644*f0865ec9SKyle Evans 645*f0865ec9SKyle Evans ret = curve_edwards_montgomery_check(edwards_crv, in_montgomery->crv, alpha); EG(ret, err); 646*f0865ec9SKyle Evans 647*f0865ec9SKyle Evans ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err); 648*f0865ec9SKyle Evans ret = fp_init(&u, in_montgomery->crv->A.ctx); EG(ret, err); 649*f0865ec9SKyle Evans ret = fp_init(&v, in_montgomery->crv->A.ctx); EG(ret, err); 650*f0865ec9SKyle Evans ret = fp_init(&tab_u[0], in_montgomery->crv->A.ctx); EG(ret, err); 651*f0865ec9SKyle Evans ret = fp_init(&tab_u[1], in_montgomery->crv->A.ctx); EG(ret, err); 652*f0865ec9SKyle Evans ret = fp_init(&tab_v[0], in_montgomery->crv->A.ctx); EG(ret, err); 653*f0865ec9SKyle Evans ret = fp_init(&tab_v[1], in_montgomery->crv->A.ctx); EG(ret, err); 654*f0865ec9SKyle Evans 655*f0865ec9SKyle Evans ret = fp_one(&tmp); EG(ret, err); 656*f0865ec9SKyle Evans /* Map (0, 0) to (0, -1) */ 657*f0865ec9SKyle Evans /* Copy 0 as u as dummy value */ 658*f0865ec9SKyle Evans ret = fp_zero(&tab_u[0]); EG(ret, err); 659*f0865ec9SKyle Evans ret = fp_copy(&tab_u[1], &(in_montgomery->u)); EG(ret, err); 660*f0865ec9SKyle Evans /* Copy 1 as v dummy value to produce (0, -1) */ 661*f0865ec9SKyle Evans ret = fp_copy(&tab_v[0], &tmp); EG(ret, err); 662*f0865ec9SKyle Evans ret = fp_copy(&tab_v[1], &(in_montgomery->v)); EG(ret, err); 663*f0865ec9SKyle Evans 664*f0865ec9SKyle Evans ret = fp_iszero(&(in_montgomery->u), &iszero1); EG(ret, err); 665*f0865ec9SKyle Evans ret = fp_iszero(&(in_montgomery->v), &iszero2); EG(ret, err); 666*f0865ec9SKyle Evans idx = (iszero1 && iszero2) ? 0 : 1; 667*f0865ec9SKyle Evans ret = fp_tabselect(&u, idx, tab_u_t, 2); EG(ret, err); 668*f0865ec9SKyle Evans ret = fp_tabselect(&v, idx, tab_v_t, 2); EG(ret, err); 669*f0865ec9SKyle Evans 670*f0865ec9SKyle Evans ret = aff_pt_edwards_init(out_edwards, edwards_crv); EG(ret, err); 671*f0865ec9SKyle Evans /* x = alpha * (u / v) */ 672*f0865ec9SKyle Evans ret = fp_inv(&(out_edwards->x), &v); EG(ret, err); 673*f0865ec9SKyle Evans ret = fp_mul(&(out_edwards->x), &(out_edwards->x), alpha); EG(ret, err); 674*f0865ec9SKyle Evans ret = fp_mul(&(out_edwards->x), &(out_edwards->x), &u); EG(ret, err); 675*f0865ec9SKyle Evans /* y = (u-1)/(u+1) */ 676*f0865ec9SKyle Evans ret = fp_add(&(out_edwards->y), &u, &tmp); EG(ret, err); 677*f0865ec9SKyle Evans ret = fp_inv(&(out_edwards->y), &(out_edwards->y)); EG(ret, err); 678*f0865ec9SKyle Evans ret = fp_sub(&tmp, &u, &tmp); EG(ret, err); 679*f0865ec9SKyle Evans ret = fp_mul(&(out_edwards->y), &(out_edwards->y), &tmp); EG(ret, err); 680*f0865ec9SKyle Evans 681*f0865ec9SKyle Evans /* Final check that the point is on the curve */ 682*f0865ec9SKyle Evans ret = aff_pt_edwards_is_on_curve(out_edwards, &on_curve); EG(ret, err); 683*f0865ec9SKyle Evans if (!on_curve) { 684*f0865ec9SKyle Evans ret = -1; 685*f0865ec9SKyle Evans } 686*f0865ec9SKyle Evans 687*f0865ec9SKyle Evans err: 688*f0865ec9SKyle Evans fp_uninit(&tmp); 689*f0865ec9SKyle Evans fp_uninit(&u); 690*f0865ec9SKyle Evans fp_uninit(&v); 691*f0865ec9SKyle Evans fp_uninit(&tab_u[0]); 692*f0865ec9SKyle Evans fp_uninit(&tab_u[1]); 693*f0865ec9SKyle Evans fp_uninit(&tab_v[0]); 694*f0865ec9SKyle Evans fp_uninit(&tab_v[1]); 695*f0865ec9SKyle Evans 696*f0865ec9SKyle Evans return ret; 697*f0865ec9SKyle Evans } 698*f0865ec9SKyle Evans 699*f0865ec9SKyle Evans 700*f0865ec9SKyle Evans /* 701*f0865ec9SKyle Evans * Map points from Edwards to short Weierstrass through Montgomery (composition mapping). 702*f0865ec9SKyle Evans * 703*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 704*f0865ec9SKyle Evans */ 705*f0865ec9SKyle Evans int aff_pt_edwards_to_shortw(aff_pt_edwards_src_t in_edwards, 706*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv, 707*f0865ec9SKyle Evans aff_pt_t out_shortw, fp_src_t alpha_edwards) 708*f0865ec9SKyle Evans { 709*f0865ec9SKyle Evans int ret; 710*f0865ec9SKyle Evans aff_pt_montgomery inter_montgomery; 711*f0865ec9SKyle Evans ec_montgomery_crv inter_montgomery_crv; 712*f0865ec9SKyle Evans inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0); 713*f0865ec9SKyle Evans 714*f0865ec9SKyle Evans /* First, map from Edwards to Montgomery */ 715*f0865ec9SKyle Evans ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err); 716*f0865ec9SKyle Evans ret = curve_edwards_to_montgomery(in_edwards->crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err); 717*f0865ec9SKyle Evans ret = aff_pt_edwards_to_montgomery(in_edwards, &inter_montgomery_crv, &inter_montgomery, alpha_edwards); EG(ret, err); 718*f0865ec9SKyle Evans 719*f0865ec9SKyle Evans /* Then map from Montgomery to short Weierstrass */ 720*f0865ec9SKyle Evans ret = aff_pt_montgomery_to_shortw(&inter_montgomery, shortw_crv, out_shortw); 721*f0865ec9SKyle Evans 722*f0865ec9SKyle Evans err: 723*f0865ec9SKyle Evans aff_pt_montgomery_uninit(&inter_montgomery); 724*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&inter_montgomery_crv); 725*f0865ec9SKyle Evans 726*f0865ec9SKyle Evans return ret; 727*f0865ec9SKyle Evans } 728*f0865ec9SKyle Evans 729*f0865ec9SKyle Evans /* 730*f0865ec9SKyle Evans * Map points from projective short Weierstrass to Edwards through Montgomery (composition mapping). 731*f0865ec9SKyle Evans * 732*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 733*f0865ec9SKyle Evans */ 734*f0865ec9SKyle Evans int aff_pt_shortw_to_edwards(aff_pt_src_t in_shortw, 735*f0865ec9SKyle Evans ec_edwards_crv_src_t edwards_crv, 736*f0865ec9SKyle Evans aff_pt_edwards_t out_edwards, 737*f0865ec9SKyle Evans fp_src_t alpha_edwards) 738*f0865ec9SKyle Evans { 739*f0865ec9SKyle Evans int ret; 740*f0865ec9SKyle Evans aff_pt_montgomery inter_montgomery; 741*f0865ec9SKyle Evans ec_montgomery_crv inter_montgomery_crv; 742*f0865ec9SKyle Evans inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0); 743*f0865ec9SKyle Evans 744*f0865ec9SKyle Evans /* First, map from short Weierstrass to Montgomery */ 745*f0865ec9SKyle Evans ret = curve_edwards_to_montgomery(edwards_crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err); 746*f0865ec9SKyle Evans ret = aff_pt_shortw_to_montgomery(in_shortw, &inter_montgomery_crv, &inter_montgomery); EG(ret, err); 747*f0865ec9SKyle Evans 748*f0865ec9SKyle Evans /* Then map from Montgomery to Edwards */ 749*f0865ec9SKyle Evans ret = aff_pt_montgomery_to_edwards(&inter_montgomery, edwards_crv, out_edwards, alpha_edwards); 750*f0865ec9SKyle Evans 751*f0865ec9SKyle Evans err: 752*f0865ec9SKyle Evans aff_pt_montgomery_uninit(&inter_montgomery); 753*f0865ec9SKyle Evans ec_montgomery_crv_uninit(&inter_montgomery_crv); 754*f0865ec9SKyle Evans 755*f0865ec9SKyle Evans return ret; 756*f0865ec9SKyle Evans } 757*f0865ec9SKyle Evans 758*f0865ec9SKyle Evans /* 759*f0865ec9SKyle Evans * Recover the two possible y coordinates from one x on a given 760*f0865ec9SKyle Evans * curve. 761*f0865ec9SKyle Evans * The two outputs y1 and y2 are initialized in the function. 762*f0865ec9SKyle Evans * 763*f0865ec9SKyle Evans * The function returns -1 on error, 0 on success. 764*f0865ec9SKyle Evans * 765*f0865ec9SKyle Evans */ 766*f0865ec9SKyle Evans int aff_pt_edwards_y_from_x(fp_t y1, fp_t y2, fp_src_t x, ec_edwards_crv_src_t crv) 767*f0865ec9SKyle Evans { 768*f0865ec9SKyle Evans int ret; 769*f0865ec9SKyle Evans fp tmp; 770*f0865ec9SKyle Evans tmp.magic = WORD(0); 771*f0865ec9SKyle Evans 772*f0865ec9SKyle Evans /* Sanity checks */ 773*f0865ec9SKyle Evans ret = fp_check_initialized(x); EG(ret, err); 774*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(crv); EG(ret, err); 775*f0865ec9SKyle Evans MUST_HAVE((x->ctx == crv->a.ctx) && (x->ctx == crv->d.ctx), ret, err); 776*f0865ec9SKyle Evans MUST_HAVE((y1 != NULL) && (y2 != NULL), ret, err); 777*f0865ec9SKyle Evans /* Aliasing is not supported */ 778*f0865ec9SKyle Evans MUST_HAVE((y1 != y2) && (y1 != x), ret, err); 779*f0865ec9SKyle Evans 780*f0865ec9SKyle Evans ret = fp_init(y1, x->ctx); EG(ret, err); 781*f0865ec9SKyle Evans ret = fp_init(y2, x->ctx); EG(ret, err); 782*f0865ec9SKyle Evans ret = fp_init(&tmp, x->ctx); EG(ret, err); 783*f0865ec9SKyle Evans 784*f0865ec9SKyle Evans /* In order to find our two possible y, we have to find the square 785*f0865ec9SKyle Evans * roots of (1 - a x**2) / (1 - d * x**2). 786*f0865ec9SKyle Evans */ 787*f0865ec9SKyle Evans ret = fp_one(&tmp); EG(ret, err); 788*f0865ec9SKyle Evans /* (1 - a x**2) */ 789*f0865ec9SKyle Evans ret = fp_mul(y1, x, &(crv->a)); EG(ret, err); 790*f0865ec9SKyle Evans ret = fp_mul(y1, y1, x); EG(ret, err); 791*f0865ec9SKyle Evans ret = fp_sub(y1, &tmp, y1); EG(ret, err); 792*f0865ec9SKyle Evans /* 1 / (1 - d * x**2) */ 793*f0865ec9SKyle Evans ret = fp_mul(y2, x, &(crv->d)); EG(ret, err); 794*f0865ec9SKyle Evans ret = fp_mul(y2, y2, x); EG(ret, err); 795*f0865ec9SKyle Evans ret = fp_sub(y2, &tmp, y2); EG(ret, err); 796*f0865ec9SKyle Evans ret = fp_inv(y2, y2); EG(ret, err); 797*f0865ec9SKyle Evans 798*f0865ec9SKyle Evans ret = fp_mul(&tmp, y1, y2); EG(ret, err); 799*f0865ec9SKyle Evans 800*f0865ec9SKyle Evans ret = fp_sqrt(y1, y2, &tmp); 801*f0865ec9SKyle Evans 802*f0865ec9SKyle Evans err: 803*f0865ec9SKyle Evans fp_uninit(&tmp); 804*f0865ec9SKyle Evans 805*f0865ec9SKyle Evans return ret; 806*f0865ec9SKyle Evans } 807*f0865ec9SKyle Evans 808*f0865ec9SKyle Evans /* 809*f0865ec9SKyle Evans * Recover the two possible x coordinates from one y on a given 810*f0865ec9SKyle Evans * curve. 811*f0865ec9SKyle Evans * The two outputs x1 and x2 are initialized in the function. 812*f0865ec9SKyle Evans * 813*f0865ec9SKyle Evans * The function returns -1 on error, 0 on success. 814*f0865ec9SKyle Evans * 815*f0865ec9SKyle Evans */ 816*f0865ec9SKyle Evans int aff_pt_edwards_x_from_y(fp_t x1, fp_t x2, fp_src_t y, ec_edwards_crv_src_t crv) 817*f0865ec9SKyle Evans { 818*f0865ec9SKyle Evans int ret; 819*f0865ec9SKyle Evans fp tmp; 820*f0865ec9SKyle Evans tmp.magic = WORD(0); 821*f0865ec9SKyle Evans 822*f0865ec9SKyle Evans /* Sanity checks */ 823*f0865ec9SKyle Evans ret = fp_check_initialized(y); EG(ret, err); 824*f0865ec9SKyle Evans ret = ec_edwards_crv_check_initialized(crv); EG(ret, err); 825*f0865ec9SKyle Evans MUST_HAVE((y->ctx == crv->a.ctx) && (y->ctx == crv->d.ctx), ret, err); 826*f0865ec9SKyle Evans MUST_HAVE((x1 != NULL) && (x2 != NULL), ret, err); 827*f0865ec9SKyle Evans /* Aliasing is not supported */ 828*f0865ec9SKyle Evans MUST_HAVE((x1 != x2) && (x1 != y), ret, err); 829*f0865ec9SKyle Evans 830*f0865ec9SKyle Evans ret = fp_init(x1, y->ctx); EG(ret, err); 831*f0865ec9SKyle Evans ret = fp_init(x2, y->ctx); EG(ret, err); 832*f0865ec9SKyle Evans ret = fp_init(&tmp, y->ctx); EG(ret, err); 833*f0865ec9SKyle Evans 834*f0865ec9SKyle Evans /* In order to find our two possible y, we have to find the square 835*f0865ec9SKyle Evans * roots of (1 - y**2) / (a - d * y**2). 836*f0865ec9SKyle Evans */ 837*f0865ec9SKyle Evans ret = fp_one(&tmp); EG(ret, err); 838*f0865ec9SKyle Evans /* (1 - y**2) */ 839*f0865ec9SKyle Evans ret = fp_mul(x1, y, y); EG(ret, err); 840*f0865ec9SKyle Evans ret = fp_sub(x1, &tmp, x1); EG(ret, err); 841*f0865ec9SKyle Evans /* 1 / (a - d * x**2) */ 842*f0865ec9SKyle Evans ret = fp_mul(x2, y, &(crv->d)); EG(ret, err); 843*f0865ec9SKyle Evans ret = fp_mul(x2, x2, y); EG(ret, err); 844*f0865ec9SKyle Evans ret = fp_sub(x2, &(crv->a), x2); EG(ret, err); 845*f0865ec9SKyle Evans ret = fp_inv(x2, x2); EG(ret, err); 846*f0865ec9SKyle Evans 847*f0865ec9SKyle Evans ret = fp_mul(&tmp, x1, x2); EG(ret, err); 848*f0865ec9SKyle Evans 849*f0865ec9SKyle Evans ret = fp_sqrt(x1, x2, &tmp); 850*f0865ec9SKyle Evans 851*f0865ec9SKyle Evans err: 852*f0865ec9SKyle Evans fp_uninit(&tmp); 853*f0865ec9SKyle Evans 854*f0865ec9SKyle Evans return ret; 855*f0865ec9SKyle Evans } 856