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 #define AFF_PT_MONTGOMERY_MAGIC ((word_t)(0x7390a9bc43d94598ULL)) 14*f0865ec9SKyle Evans 15*f0865ec9SKyle Evans /* Verify that an affine point has already been initialized. 16*f0865ec9SKyle Evans * 17*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 18*f0865ec9SKyle Evans */ 19*f0865ec9SKyle Evans int aff_pt_montgomery_check_initialized(aff_pt_montgomery_src_t in) 20*f0865ec9SKyle Evans { 21*f0865ec9SKyle Evans int ret; 22*f0865ec9SKyle Evans 23*f0865ec9SKyle Evans MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC)), ret, err); 24*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(in->crv); 25*f0865ec9SKyle Evans 26*f0865ec9SKyle Evans err: 27*f0865ec9SKyle Evans return ret; 28*f0865ec9SKyle Evans } 29*f0865ec9SKyle Evans 30*f0865ec9SKyle Evans /* 31*f0865ec9SKyle Evans * Initialize pointed aff_pt_montgomery structure to make it usable by library 32*f0865ec9SKyle Evans * function on given curve. 33*f0865ec9SKyle Evans * 34*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 35*f0865ec9SKyle Evans */ 36*f0865ec9SKyle Evans int aff_pt_montgomery_init(aff_pt_montgomery_t in, ec_montgomery_crv_src_t curve) 37*f0865ec9SKyle Evans { 38*f0865ec9SKyle Evans int ret; 39*f0865ec9SKyle Evans 40*f0865ec9SKyle Evans MUST_HAVE((in != NULL), ret, err); 41*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err); 42*f0865ec9SKyle Evans 43*f0865ec9SKyle Evans ret = fp_init(&(in->u), curve->A.ctx); EG(ret, err); 44*f0865ec9SKyle Evans ret = fp_init(&(in->v), curve->A.ctx); EG(ret, err); 45*f0865ec9SKyle Evans 46*f0865ec9SKyle Evans in->crv = curve; 47*f0865ec9SKyle Evans in->magic = AFF_PT_MONTGOMERY_MAGIC; 48*f0865ec9SKyle Evans 49*f0865ec9SKyle Evans err: 50*f0865ec9SKyle Evans return ret; 51*f0865ec9SKyle Evans } 52*f0865ec9SKyle Evans 53*f0865ec9SKyle Evans /* 54*f0865ec9SKyle Evans * Initialize pointed aff_pt_montgomery structure to make it usable by library 55*f0865ec9SKyle Evans * function on given curve with explicit coordinates. 56*f0865ec9SKyle Evans * 57*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 58*f0865ec9SKyle Evans */ 59*f0865ec9SKyle Evans int aff_pt_montgomery_init_from_coords(aff_pt_montgomery_t in, 60*f0865ec9SKyle Evans ec_montgomery_crv_src_t curve, 61*f0865ec9SKyle Evans fp_src_t ucoord, fp_src_t vcoord) 62*f0865ec9SKyle Evans { 63*f0865ec9SKyle Evans int ret; 64*f0865ec9SKyle Evans 65*f0865ec9SKyle Evans ret = aff_pt_montgomery_init(in, curve); EG(ret, err); 66*f0865ec9SKyle Evans ret = fp_copy(&(in->u), ucoord); EG(ret, err); 67*f0865ec9SKyle Evans ret = fp_copy(&(in->v), vcoord); 68*f0865ec9SKyle Evans 69*f0865ec9SKyle Evans err: 70*f0865ec9SKyle Evans return ret; 71*f0865ec9SKyle Evans } 72*f0865ec9SKyle Evans 73*f0865ec9SKyle Evans /* 74*f0865ec9SKyle Evans * Uninitialize pointed affine point to prevent further use (magic field 75*f0865ec9SKyle Evans * in the structure is zeroized) and zeroize associated storage space. 76*f0865ec9SKyle Evans * Note that the curve context pointed to by the point element (passed 77*f0865ec9SKyle Evans * during init) is left untouched. 78*f0865ec9SKyle Evans * 79*f0865ec9SKyle Evans */ 80*f0865ec9SKyle Evans void aff_pt_montgomery_uninit(aff_pt_montgomery_t in) 81*f0865ec9SKyle Evans { 82*f0865ec9SKyle Evans if ((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC) && (in->crv != NULL)) { 83*f0865ec9SKyle Evans fp_uninit(&(in->u)); 84*f0865ec9SKyle Evans fp_uninit(&(in->v)); 85*f0865ec9SKyle Evans 86*f0865ec9SKyle Evans in->crv = NULL; 87*f0865ec9SKyle Evans in->magic = WORD(0); 88*f0865ec9SKyle Evans } 89*f0865ec9SKyle Evans 90*f0865ec9SKyle Evans return; 91*f0865ec9SKyle Evans } 92*f0865ec9SKyle Evans 93*f0865ec9SKyle Evans /* 94*f0865ec9SKyle Evans * 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it 95*f0865ec9SKyle Evans * verifies curve equation B*v^2 = u^3 + A*u^2 + u. It is set to 0 otherwise. 96*f0865ec9SKyle Evans * 'on_curve' is not meaningful on error. 97*f0865ec9SKyle Evans * 98*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 99*f0865ec9SKyle Evans */ 100*f0865ec9SKyle Evans int is_on_montgomery_curve(fp_src_t u, fp_src_t v, ec_montgomery_crv_src_t curve, int *on_curve) 101*f0865ec9SKyle Evans { 102*f0865ec9SKyle Evans fp Bv2, u3, Au2, tmp; 103*f0865ec9SKyle Evans int ret, cmp; 104*f0865ec9SKyle Evans Bv2.magic = u3.magic = Au2.magic = tmp.magic = WORD(0); 105*f0865ec9SKyle Evans 106*f0865ec9SKyle Evans MUST_HAVE((on_curve != NULL), ret, err); 107*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err); 108*f0865ec9SKyle Evans 109*f0865ec9SKyle Evans ret = fp_check_initialized(u); EG(ret, err); 110*f0865ec9SKyle Evans ret = fp_check_initialized(v); EG(ret, err); 111*f0865ec9SKyle Evans 112*f0865ec9SKyle Evans MUST_HAVE((u->ctx == v->ctx), ret, err); 113*f0865ec9SKyle Evans MUST_HAVE((u->ctx == curve->A.ctx), ret, err); 114*f0865ec9SKyle Evans 115*f0865ec9SKyle Evans ret = fp_init(&Bv2, v->ctx); EG(ret, err); 116*f0865ec9SKyle Evans ret = fp_sqr(&Bv2, v); EG(ret, err); 117*f0865ec9SKyle Evans ret = fp_mul(&Bv2, &(curve->B), &Bv2); EG(ret, err); 118*f0865ec9SKyle Evans 119*f0865ec9SKyle Evans ret = fp_init(&Au2, u->ctx); EG(ret, err); 120*f0865ec9SKyle Evans ret = fp_sqr(&Au2, u); EG(ret, err); 121*f0865ec9SKyle Evans ret = fp_copy(&u3, &Au2); EG(ret, err); 122*f0865ec9SKyle Evans ret = fp_mul(&Au2, &(curve->A), &Au2); EG(ret, err); 123*f0865ec9SKyle Evans 124*f0865ec9SKyle Evans ret = fp_mul(&u3, &u3, u); EG(ret, err); 125*f0865ec9SKyle Evans 126*f0865ec9SKyle Evans ret = fp_init(&tmp, u->ctx); EG(ret, err); 127*f0865ec9SKyle Evans ret = fp_add(&tmp, &u3, &Au2); EG(ret, err); 128*f0865ec9SKyle Evans ret = fp_add(&tmp, &tmp, u); EG(ret, err); 129*f0865ec9SKyle Evans 130*f0865ec9SKyle Evans ret = fp_cmp(&tmp, &Bv2, &cmp); EG(ret, err); 131*f0865ec9SKyle Evans 132*f0865ec9SKyle Evans (*on_curve) = (!cmp); 133*f0865ec9SKyle Evans 134*f0865ec9SKyle Evans err: 135*f0865ec9SKyle Evans fp_uninit(&Bv2); 136*f0865ec9SKyle Evans fp_uninit(&u3); 137*f0865ec9SKyle Evans fp_uninit(&Au2); 138*f0865ec9SKyle Evans fp_uninit(&tmp); 139*f0865ec9SKyle Evans 140*f0865ec9SKyle Evans return ret; 141*f0865ec9SKyle Evans } 142*f0865ec9SKyle Evans 143*f0865ec9SKyle Evans /* Checks if affine coordinates point is on a Montgomery curve. 'on_curve' is set to 1 if yes, 144*f0865ec9SKyle Evans * 0 if no. 'on_curve' is not meaningful in case of error. 145*f0865ec9SKyle Evans * 146*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 147*f0865ec9SKyle Evans */ 148*f0865ec9SKyle Evans int aff_pt_montgomery_is_on_curve(aff_pt_montgomery_src_t pt, int *on_curve) 149*f0865ec9SKyle Evans { 150*f0865ec9SKyle Evans int ret; 151*f0865ec9SKyle Evans 152*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err); 153*f0865ec9SKyle Evans 154*f0865ec9SKyle Evans ret = is_on_montgomery_curve(&(pt->u), &(pt->v), pt->crv, on_curve); 155*f0865ec9SKyle Evans 156*f0865ec9SKyle Evans err: 157*f0865ec9SKyle Evans return ret; 158*f0865ec9SKyle Evans } 159*f0865ec9SKyle Evans 160*f0865ec9SKyle Evans /* Copy a Montgomery affine point in an output. The output is initialized properly. 161*f0865ec9SKyle Evans * 162*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 163*f0865ec9SKyle Evans */ 164*f0865ec9SKyle Evans int ec_montgomery_aff_copy(aff_pt_montgomery_t out, aff_pt_montgomery_src_t in) 165*f0865ec9SKyle Evans { 166*f0865ec9SKyle Evans int ret; 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(in); EG(ret, err); 169*f0865ec9SKyle Evans 170*f0865ec9SKyle Evans ret = aff_pt_montgomery_init(out, in->crv); EG(ret, err); 171*f0865ec9SKyle Evans ret = fp_copy(&(out->u), &(in->u)); EG(ret, err); 172*f0865ec9SKyle Evans ret = fp_copy(&(out->v), &(in->v)); 173*f0865ec9SKyle Evans 174*f0865ec9SKyle Evans err: 175*f0865ec9SKyle Evans return ret; 176*f0865ec9SKyle Evans } 177*f0865ec9SKyle Evans 178*f0865ec9SKyle Evans /* 179*f0865ec9SKyle Evans * Compares two given affine points on a Montgomery curve, it returns 0 in input 'cmp' if 180*f0865ec9SKyle Evans * they correspond or not 0 if not. 'cmp' is not meaningful on error. 181*f0865ec9SKyle Evans * 182*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 183*f0865ec9SKyle Evans */ 184*f0865ec9SKyle Evans int ec_montgomery_aff_cmp(aff_pt_montgomery_src_t in1, aff_pt_montgomery_src_t in2, int *cmp) 185*f0865ec9SKyle Evans { 186*f0865ec9SKyle Evans int ret, cmp1, cmp2; 187*f0865ec9SKyle Evans 188*f0865ec9SKyle Evans MUST_HAVE((cmp != NULL), ret, err); 189*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(in1); EG(ret, err); 190*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(in2); EG(ret, err); 191*f0865ec9SKyle Evans MUST_HAVE((in1->crv == in2->crv), ret, err); 192*f0865ec9SKyle Evans 193*f0865ec9SKyle Evans ret = fp_cmp(&(in1->u), &(in2->u), &cmp1); EG(ret, err); 194*f0865ec9SKyle Evans ret = fp_cmp(&(in1->v), &(in2->v), &cmp2); EG(ret, err); 195*f0865ec9SKyle Evans 196*f0865ec9SKyle Evans (*cmp) = (cmp1 | cmp2); 197*f0865ec9SKyle Evans 198*f0865ec9SKyle Evans err: 199*f0865ec9SKyle Evans return ret; 200*f0865ec9SKyle Evans } 201*f0865ec9SKyle Evans 202*f0865ec9SKyle Evans /* 203*f0865ec9SKyle Evans * Import an Montgomery affine point from a buffer with the following layout; the 2 204*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 205*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 206*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 207*f0865ec9SKyle Evans * 2 * p_len. 208*f0865ec9SKyle Evans * 209*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 210*f0865ec9SKyle Evans */ 211*f0865ec9SKyle Evans int aff_pt_montgomery_import_from_buf(aff_pt_montgomery_t pt, 212*f0865ec9SKyle Evans const u8 *pt_buf, 213*f0865ec9SKyle Evans u16 pt_buf_len, ec_montgomery_crv_src_t crv) 214*f0865ec9SKyle Evans { 215*f0865ec9SKyle Evans fp_ctx_src_t ctx; 216*f0865ec9SKyle Evans u16 coord_len; 217*f0865ec9SKyle Evans int ret, on_curve; 218*f0865ec9SKyle Evans 219*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err); 220*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err); 221*f0865ec9SKyle Evans 222*f0865ec9SKyle Evans ctx = crv->A.ctx; 223*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 224*f0865ec9SKyle Evans 225*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 226*f0865ec9SKyle Evans 227*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->u), ctx, pt_buf, coord_len); EG(ret, err); 228*f0865ec9SKyle Evans ret = fp_init_from_buf(&(pt->v), ctx, pt_buf + coord_len, coord_len); EG(ret, err); 229*f0865ec9SKyle Evans 230*f0865ec9SKyle Evans /* Set the curve */ 231*f0865ec9SKyle Evans pt->crv = crv; 232*f0865ec9SKyle Evans 233*f0865ec9SKyle Evans /* Mark the point as initialized */ 234*f0865ec9SKyle Evans pt->magic = AFF_PT_MONTGOMERY_MAGIC; 235*f0865ec9SKyle Evans 236*f0865ec9SKyle Evans /* Check that the point is indeed on the provided curve, uninitialize it 237*f0865ec9SKyle Evans * if this is not the case. 238*f0865ec9SKyle Evans */ 239*f0865ec9SKyle Evans ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err); 240*f0865ec9SKyle Evans if (!on_curve) { 241*f0865ec9SKyle Evans aff_pt_montgomery_uninit(pt); 242*f0865ec9SKyle Evans ret = -1; 243*f0865ec9SKyle Evans } 244*f0865ec9SKyle Evans 245*f0865ec9SKyle Evans err: 246*f0865ec9SKyle Evans return ret; 247*f0865ec9SKyle Evans } 248*f0865ec9SKyle Evans 249*f0865ec9SKyle Evans 250*f0865ec9SKyle Evans /* Export an Montgomery affine point to a buffer with the following layout; the 2 251*f0865ec9SKyle Evans * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len 252*f0865ec9SKyle Evans * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each 253*f0865ec9SKyle Evans * coordinate is encoded in big endian. Size of buffer must exactly match 254*f0865ec9SKyle Evans * 2 * p_len. 255*f0865ec9SKyle Evans * 256*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 257*f0865ec9SKyle Evans */ 258*f0865ec9SKyle Evans int aff_pt_montgomery_export_to_buf(aff_pt_montgomery_src_t pt, u8 *pt_buf, u32 pt_buf_len) 259*f0865ec9SKyle Evans { 260*f0865ec9SKyle Evans fp_ctx_src_t ctx; 261*f0865ec9SKyle Evans u16 coord_len; 262*f0865ec9SKyle Evans int ret, on_curve; 263*f0865ec9SKyle Evans 264*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err); 265*f0865ec9SKyle Evans MUST_HAVE((pt_buf != NULL), ret, err); 266*f0865ec9SKyle Evans 267*f0865ec9SKyle Evans /* The point to be exported must be on the curve */ 268*f0865ec9SKyle Evans ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err); 269*f0865ec9SKyle Evans MUST_HAVE(on_curve, ret, err); 270*f0865ec9SKyle Evans 271*f0865ec9SKyle Evans ctx = pt->crv->A.ctx; 272*f0865ec9SKyle Evans coord_len = (u16)BYTECEIL(ctx->p_bitlen); 273*f0865ec9SKyle Evans 274*f0865ec9SKyle Evans MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err); 275*f0865ec9SKyle Evans 276*f0865ec9SKyle Evans /* Export the three coordinates */ 277*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf, coord_len, &(pt->u)); EG(ret, err); 278*f0865ec9SKyle Evans ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->v)); 279*f0865ec9SKyle Evans 280*f0865ec9SKyle Evans err: 281*f0865ec9SKyle Evans return ret; 282*f0865ec9SKyle Evans } 283*f0865ec9SKyle Evans 284*f0865ec9SKyle Evans /**** Mappings between curves *************/ 285*f0865ec9SKyle Evans /* 286*f0865ec9SKyle Evans * Mapping curves from Montgomery to short Weiertstrass. 287*f0865ec9SKyle Evans * 288*f0865ec9SKyle Evans * M{A, B} is mapped to W{a, b} using the formula: 289*f0865ec9SKyle Evans * a = (3-A^2)/(3*B^2) 290*f0865ec9SKyle Evans * b = (2*A^3-9*A)/(27*B^3) 291*f0865ec9SKyle Evans * 292*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 293*f0865ec9SKyle Evans */ 294*f0865ec9SKyle Evans int curve_montgomery_to_shortw(ec_montgomery_crv_src_t montgomery_crv, ec_shortw_crv_t shortw_crv) 295*f0865ec9SKyle Evans { 296*f0865ec9SKyle Evans fp tmp, tmp2, a, b; 297*f0865ec9SKyle Evans int ret; 298*f0865ec9SKyle Evans tmp.magic = tmp2.magic = a.magic = b.magic = WORD(0); 299*f0865ec9SKyle Evans 300*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err); 301*f0865ec9SKyle Evans 302*f0865ec9SKyle Evans ret = fp_init(&tmp, montgomery_crv->A.ctx); EG(ret, err); 303*f0865ec9SKyle Evans ret = fp_init(&tmp2, montgomery_crv->A.ctx); EG(ret, err); 304*f0865ec9SKyle Evans ret = fp_init(&a, montgomery_crv->A.ctx); EG(ret, err); 305*f0865ec9SKyle Evans ret = fp_init(&b, montgomery_crv->A.ctx); EG(ret, err); 306*f0865ec9SKyle Evans 307*f0865ec9SKyle Evans /* Compute a */ 308*f0865ec9SKyle Evans ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err); 309*f0865ec9SKyle Evans ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err); 310*f0865ec9SKyle Evans /* 3*B^2 */ 311*f0865ec9SKyle Evans ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err); 312*f0865ec9SKyle Evans /* (3*B^2)^-1 */ 313*f0865ec9SKyle Evans ret = fp_inv(&tmp, &tmp); EG(ret, err); 314*f0865ec9SKyle Evans 315*f0865ec9SKyle Evans /* (3-A^2) */ 316*f0865ec9SKyle Evans ret = fp_sqr(&tmp2, &(montgomery_crv->A)); EG(ret, err); 317*f0865ec9SKyle Evans ret = fp_set_word_value(&a, WORD(3)); EG(ret, err); 318*f0865ec9SKyle Evans ret = fp_sub(&tmp2, &a, &tmp2); EG(ret, err); 319*f0865ec9SKyle Evans 320*f0865ec9SKyle Evans ret = fp_mul(&a, &tmp2, &tmp); EG(ret, err); 321*f0865ec9SKyle Evans 322*f0865ec9SKyle Evans /* Compute b */ 323*f0865ec9SKyle Evans ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err); 324*f0865ec9SKyle Evans ret = fp_mul(&tmp, &tmp, &(montgomery_crv->B)); EG(ret, err); 325*f0865ec9SKyle Evans ret = fp_set_word_value(&tmp2, WORD(27)); EG(ret, err); 326*f0865ec9SKyle Evans /* (27*B^3) */ 327*f0865ec9SKyle Evans ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err); 328*f0865ec9SKyle Evans /* (27*B^3)^-1 */ 329*f0865ec9SKyle Evans ret = fp_inv(&tmp, &tmp); EG(ret, err); 330*f0865ec9SKyle Evans 331*f0865ec9SKyle Evans /* (2*A^3-9*A) */ 332*f0865ec9SKyle Evans ret = fp_set_word_value(&tmp2, WORD(2)); EG(ret, err); 333*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err); 334*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err); 335*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err); 336*f0865ec9SKyle Evans 337*f0865ec9SKyle Evans ret = fp_set_word_value(&b, WORD(9)); EG(ret, err); 338*f0865ec9SKyle Evans ret = fp_mul(&b, &b, &(montgomery_crv->A)); EG(ret, err); 339*f0865ec9SKyle Evans ret = fp_sub(&b, &tmp2, &b); EG(ret, err); 340*f0865ec9SKyle Evans 341*f0865ec9SKyle Evans ret = fp_mul(&b, &b, &tmp); EG(ret, err); 342*f0865ec9SKyle Evans 343*f0865ec9SKyle Evans /* Initialize our short Weiertstrass curve */ 344*f0865ec9SKyle Evans ret = ec_shortw_crv_init(shortw_crv, &a, &b, &(montgomery_crv->order)); 345*f0865ec9SKyle Evans 346*f0865ec9SKyle Evans err: 347*f0865ec9SKyle Evans fp_uninit(&a); 348*f0865ec9SKyle Evans fp_uninit(&b); 349*f0865ec9SKyle Evans fp_uninit(&tmp); 350*f0865ec9SKyle Evans fp_uninit(&tmp2); 351*f0865ec9SKyle Evans 352*f0865ec9SKyle Evans return ret; 353*f0865ec9SKyle Evans } 354*f0865ec9SKyle Evans 355*f0865ec9SKyle Evans /* 356*f0865ec9SKyle Evans * Checks that a short Weiertstrass 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_montgomery_shortw_check(ec_montgomery_crv_src_t montgomery_crv, 361*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv) 362*f0865ec9SKyle Evans { 363*f0865ec9SKyle Evans int ret, cmp; 364*f0865ec9SKyle Evans ec_shortw_crv check; 365*f0865ec9SKyle Evans check.magic = WORD(0); 366*f0865ec9SKyle Evans 367*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err); 368*f0865ec9SKyle Evans ret = curve_montgomery_to_shortw(montgomery_crv, &check); EG(ret, err); 369*f0865ec9SKyle Evans 370*f0865ec9SKyle Evans /* Check elements */ 371*f0865ec9SKyle Evans MUST_HAVE((!fp_cmp(&(check.a), &(shortw_crv->a), &cmp)) && (!cmp), ret, err); 372*f0865ec9SKyle Evans MUST_HAVE((!fp_cmp(&(check.b), &(shortw_crv->b), &cmp)) && (!cmp), ret, err); 373*f0865ec9SKyle Evans MUST_HAVE((!nn_cmp(&(check.order), &(shortw_crv->order), &cmp)) && (!cmp), ret, err); 374*f0865ec9SKyle Evans 375*f0865ec9SKyle Evans err: 376*f0865ec9SKyle Evans ec_shortw_crv_uninit(&check); 377*f0865ec9SKyle Evans 378*f0865ec9SKyle Evans return ret; 379*f0865ec9SKyle Evans } 380*f0865ec9SKyle Evans 381*f0865ec9SKyle Evans /* 382*f0865ec9SKyle Evans * Mapping curves from short Weiertstrass to Montgomery 383*f0865ec9SKyle Evans * 384*f0865ec9SKyle Evans * W{a, b} is mapped to M{A, B} using the formula: 385*f0865ec9SKyle Evans * A = 3 * alpha / gamma 386*f0865ec9SKyle Evans * B = 1 / gamma 387*f0865ec9SKyle Evans * with gamma square root of c = a + 3 * alpha**2 388*f0865ec9SKyle Evans * 389*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 390*f0865ec9SKyle Evans */ 391*f0865ec9SKyle Evans int curve_shortw_to_montgomery(ec_shortw_crv_src_t shortw_crv, 392*f0865ec9SKyle Evans ec_montgomery_crv_t montgomery_crv, 393*f0865ec9SKyle Evans fp_src_t alpha, fp_src_t gamma) 394*f0865ec9SKyle Evans { 395*f0865ec9SKyle Evans int ret, cmp; 396*f0865ec9SKyle Evans fp c, gamma_inv, A, tmp; 397*f0865ec9SKyle Evans c.magic = gamma_inv.magic = A.magic = tmp.magic = WORD(0); 398*f0865ec9SKyle Evans 399*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err); 400*f0865ec9SKyle Evans ret = fp_check_initialized(alpha); EG(ret, err); 401*f0865ec9SKyle Evans ret = fp_check_initialized(gamma); EG(ret, err); 402*f0865ec9SKyle Evans MUST_HAVE((alpha->ctx == shortw_crv->a.ctx) && (gamma->ctx == shortw_crv->a.ctx), ret, err); 403*f0865ec9SKyle Evans 404*f0865ec9SKyle Evans ret = fp_init(&A, shortw_crv->a.ctx); EG(ret, err); 405*f0865ec9SKyle Evans ret = fp_init(&gamma_inv, shortw_crv->a.ctx); EG(ret, err); 406*f0865ec9SKyle Evans ret = fp_init(&c, shortw_crv->a.ctx); EG(ret, err); 407*f0865ec9SKyle Evans ret = fp_init(&tmp, shortw_crv->a.ctx); EG(ret, err); 408*f0865ec9SKyle Evans 409*f0865ec9SKyle Evans /* Compute 1 / gamma */ 410*f0865ec9SKyle Evans ret = fp_inv(&gamma_inv, gamma); EG(ret, err); 411*f0865ec9SKyle Evans 412*f0865ec9SKyle Evans /* Compute A */ 413*f0865ec9SKyle Evans ret = fp_set_word_value(&A, WORD(3)); EG(ret, err); 414*f0865ec9SKyle Evans ret = fp_mul(&A, &A, alpha); EG(ret, err); 415*f0865ec9SKyle Evans ret = fp_mul(&A, &A, &gamma_inv); EG(ret, err); 416*f0865ec9SKyle Evans 417*f0865ec9SKyle Evans /* Sanity check on c */ 418*f0865ec9SKyle Evans ret = fp_set_word_value(&c, WORD(3)); EG(ret, err); 419*f0865ec9SKyle Evans ret = fp_mul(&c, &c, alpha); EG(ret, err); 420*f0865ec9SKyle Evans ret = fp_mul(&c, &c, alpha); EG(ret, err); 421*f0865ec9SKyle Evans ret = fp_add(&c, &c, &(shortw_crv->a)); EG(ret, err); 422*f0865ec9SKyle Evans ret = fp_sqr(&tmp, gamma); EG(ret, err); 423*f0865ec9SKyle Evans /* gamma ** 2 must be equal to c */ 424*f0865ec9SKyle Evans MUST_HAVE((!fp_cmp(&c, &tmp, &cmp)) && (!cmp), ret, err); 425*f0865ec9SKyle Evans 426*f0865ec9SKyle Evans /* B is simply the inverse of gamma */ 427*f0865ec9SKyle Evans ret = ec_montgomery_crv_init(montgomery_crv, &A, &gamma_inv, &(shortw_crv->order)); 428*f0865ec9SKyle Evans 429*f0865ec9SKyle Evans err: 430*f0865ec9SKyle Evans fp_uninit(&A); 431*f0865ec9SKyle Evans fp_uninit(&gamma_inv); 432*f0865ec9SKyle Evans fp_uninit(&c); 433*f0865ec9SKyle Evans fp_uninit(&tmp); 434*f0865ec9SKyle Evans 435*f0865ec9SKyle Evans return ret; 436*f0865ec9SKyle Evans } 437*f0865ec9SKyle Evans 438*f0865ec9SKyle Evans /* 439*f0865ec9SKyle Evans * Mapping points from Montgomery to short Weierstrass. 440*f0865ec9SKyle Evans * Point M(u, v) is mapped to W(x, y) with the formula: 441*f0865ec9SKyle Evans * - (x, y) = ((u/B)+(A/3B), v/B) 442*f0865ec9SKyle Evans * 443*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 444*f0865ec9SKyle Evans */ 445*f0865ec9SKyle Evans int aff_pt_montgomery_to_shortw(aff_pt_montgomery_src_t in_montgomery, 446*f0865ec9SKyle Evans ec_shortw_crv_src_t shortw_crv, aff_pt_t out_shortw) 447*f0865ec9SKyle Evans { 448*f0865ec9SKyle Evans int ret, on_curve; 449*f0865ec9SKyle Evans fp tmp, tmp2; 450*f0865ec9SKyle Evans tmp.magic = tmp2.magic = WORD(0); 451*f0865ec9SKyle Evans 452*f0865ec9SKyle Evans ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err); 453*f0865ec9SKyle Evans 454*f0865ec9SKyle Evans /* Check that our input point is on its curve */ 455*f0865ec9SKyle Evans MUST_HAVE((!aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve)) && on_curve, ret, err); 456*f0865ec9SKyle Evans 457*f0865ec9SKyle Evans ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err); 458*f0865ec9SKyle Evans ret = fp_init(&tmp2, in_montgomery->crv->A.ctx); EG(ret, err); 459*f0865ec9SKyle Evans 460*f0865ec9SKyle Evans ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err); 461*f0865ec9SKyle Evans ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err); 462*f0865ec9SKyle Evans 463*f0865ec9SKyle Evans ret = aff_pt_init(out_shortw, shortw_crv); EG(ret, err); 464*f0865ec9SKyle Evans 465*f0865ec9SKyle Evans ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err); 466*f0865ec9SKyle Evans ret = fp_mul(&tmp, &tmp, &(in_montgomery->u)); EG(ret, err); 467*f0865ec9SKyle Evans 468*f0865ec9SKyle Evans ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err); 469*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->B)); EG(ret, err); 470*f0865ec9SKyle Evans ret = fp_inv(&tmp2, &tmp2); EG(ret, err); 471*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->A)); EG(ret, err); 472*f0865ec9SKyle Evans 473*f0865ec9SKyle Evans ret = fp_add(&(out_shortw->x), &tmp, &tmp2); EG(ret, err); 474*f0865ec9SKyle Evans 475*f0865ec9SKyle Evans ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err); 476*f0865ec9SKyle Evans ret = fp_mul(&(out_shortw->y), &tmp, &(in_montgomery->v)); EG(ret, err); 477*f0865ec9SKyle Evans 478*f0865ec9SKyle Evans /* Final check that the point is on the curve */ 479*f0865ec9SKyle Evans MUST_HAVE((!aff_pt_is_on_curve(out_shortw, &on_curve)) && on_curve, ret, err); 480*f0865ec9SKyle Evans 481*f0865ec9SKyle Evans err: 482*f0865ec9SKyle Evans fp_uninit(&tmp); 483*f0865ec9SKyle Evans fp_uninit(&tmp2); 484*f0865ec9SKyle Evans 485*f0865ec9SKyle Evans return ret; 486*f0865ec9SKyle Evans } 487*f0865ec9SKyle Evans 488*f0865ec9SKyle Evans /* 489*f0865ec9SKyle Evans * Mapping from short Weierstrass to Montgomery. 490*f0865ec9SKyle Evans * Point W(x, y) is mapped to M(u, v) with the formula: 491*f0865ec9SKyle Evans * - (u, v) = (((Bx)−(A/3), By) 492*f0865ec9SKyle Evans * 493*f0865ec9SKyle Evans * Returns 0 on success, -1 on error. 494*f0865ec9SKyle Evans */ 495*f0865ec9SKyle Evans int aff_pt_shortw_to_montgomery(aff_pt_src_t in_shortw, 496*f0865ec9SKyle Evans ec_montgomery_crv_src_t montgomery_crv, 497*f0865ec9SKyle Evans aff_pt_montgomery_t out_montgomery) 498*f0865ec9SKyle Evans { 499*f0865ec9SKyle Evans int ret, on_curve; 500*f0865ec9SKyle Evans fp tmp, tmp2; 501*f0865ec9SKyle Evans tmp.magic = tmp2.magic = WORD(0); 502*f0865ec9SKyle Evans 503*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err); 504*f0865ec9SKyle Evans 505*f0865ec9SKyle Evans /* Check that our input point is on its curve */ 506*f0865ec9SKyle Evans MUST_HAVE((!aff_pt_is_on_curve(in_shortw, &on_curve)) && on_curve, ret, err); 507*f0865ec9SKyle Evans 508*f0865ec9SKyle Evans ret = fp_init(&tmp, in_shortw->crv->a.ctx); EG(ret, err); 509*f0865ec9SKyle Evans ret = fp_init(&tmp2, in_shortw->crv->a.ctx); EG(ret, err); 510*f0865ec9SKyle Evans 511*f0865ec9SKyle Evans ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err); 512*f0865ec9SKyle Evans 513*f0865ec9SKyle Evans ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err); 514*f0865ec9SKyle Evans 515*f0865ec9SKyle Evans /* A/3 */ 516*f0865ec9SKyle Evans ret = fp_inv_word(&tmp, WORD(3)); EG(ret, err); 517*f0865ec9SKyle Evans ret = fp_mul(&tmp, &tmp, &(montgomery_crv->A)); EG(ret, err); 518*f0865ec9SKyle Evans 519*f0865ec9SKyle Evans /* Bx */ 520*f0865ec9SKyle Evans ret = fp_mul(&tmp2, &(montgomery_crv->B), &(in_shortw->x)); EG(ret, err); 521*f0865ec9SKyle Evans 522*f0865ec9SKyle Evans /* u = (Bx) - (A/3) */ 523*f0865ec9SKyle Evans ret = fp_sub(&(out_montgomery->u), &tmp2, &tmp); EG(ret, err); 524*f0865ec9SKyle Evans 525*f0865ec9SKyle Evans /* v = By */ 526*f0865ec9SKyle Evans ret = fp_mul(&(out_montgomery->v), &(montgomery_crv->B), &(in_shortw->y)); EG(ret, err); 527*f0865ec9SKyle Evans 528*f0865ec9SKyle Evans /* Final check that the point is on the curve */ 529*f0865ec9SKyle Evans MUST_HAVE((!aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve)) && on_curve, ret, err); 530*f0865ec9SKyle Evans 531*f0865ec9SKyle Evans err: 532*f0865ec9SKyle Evans fp_uninit(&tmp); 533*f0865ec9SKyle Evans fp_uninit(&tmp2); 534*f0865ec9SKyle Evans 535*f0865ec9SKyle Evans return ret; 536*f0865ec9SKyle Evans } 537*f0865ec9SKyle Evans 538*f0865ec9SKyle Evans 539*f0865ec9SKyle Evans /* 540*f0865ec9SKyle Evans * Recover the two possible v coordinates from one u on a given 541*f0865ec9SKyle Evans * curve. 542*f0865ec9SKyle Evans * The two outputs v1 and v2 are initialized in the function. 543*f0865ec9SKyle Evans * 544*f0865ec9SKyle Evans * The function returns -1 on error, 0 on success. 545*f0865ec9SKyle Evans * 546*f0865ec9SKyle Evans */ 547*f0865ec9SKyle Evans int aff_pt_montgomery_v_from_u(fp_t v1, fp_t v2, fp_src_t u, ec_montgomery_crv_src_t crv) 548*f0865ec9SKyle Evans { 549*f0865ec9SKyle Evans int ret; 550*f0865ec9SKyle Evans 551*f0865ec9SKyle Evans /* Sanity checks */ 552*f0865ec9SKyle Evans ret = fp_check_initialized(u); EG(ret, err); 553*f0865ec9SKyle Evans ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err); 554*f0865ec9SKyle Evans MUST_HAVE((u->ctx == crv->A.ctx) && (u->ctx == crv->B.ctx), ret, err); 555*f0865ec9SKyle Evans MUST_HAVE((v1 != NULL) && (v2 != NULL), ret, err); 556*f0865ec9SKyle Evans /* Aliasing is not supported */ 557*f0865ec9SKyle Evans MUST_HAVE((v1 != v2) && (v1 != u), ret, err); 558*f0865ec9SKyle Evans 559*f0865ec9SKyle Evans /* Initialize v1 and v2 with context */ 560*f0865ec9SKyle Evans ret = fp_init(v1, u->ctx); EG(ret, err); 561*f0865ec9SKyle Evans ret = fp_init(v2, u->ctx); EG(ret, err); 562*f0865ec9SKyle Evans 563*f0865ec9SKyle Evans /* v must satisfy the equation B v^2 = u^3 + A u^2 + u, 564*f0865ec9SKyle Evans * so we compute square root for B^-1 * (u^3 + A u^2 + u) 565*f0865ec9SKyle Evans */ 566*f0865ec9SKyle Evans ret = fp_sqr(v2, u); EG(ret, err); 567*f0865ec9SKyle Evans ret = fp_mul(v1, v2, u); EG(ret, err); 568*f0865ec9SKyle Evans ret = fp_mul(v2, v2, &(crv->A)); EG(ret, err); 569*f0865ec9SKyle Evans ret = fp_add(v1, v1, v2); EG(ret, err); 570*f0865ec9SKyle Evans ret = fp_add(v1, v1, u); EG(ret, err); 571*f0865ec9SKyle Evans ret = fp_inv(v2, &(crv->B)); EG(ret, err); 572*f0865ec9SKyle Evans ret = fp_mul(v1, v1, v2); EG(ret, err); 573*f0865ec9SKyle Evans 574*f0865ec9SKyle Evans /* Choose any of the two square roots as the solution */ 575*f0865ec9SKyle Evans ret = fp_sqrt(v1, v2, v1); 576*f0865ec9SKyle Evans 577*f0865ec9SKyle Evans err: 578*f0865ec9SKyle Evans return ret; 579*f0865ec9SKyle Evans } 580