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