1/* Originally written by Bodo Moeller for the OpenSSL project. 2 * ==================================================================== 3 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. All advertising materials mentioning features or use of this 18 * software must display the following acknowledgment: 19 * "This product includes software developed by the OpenSSL Project 20 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 21 * 22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23 * endorse or promote products derived from this software without 24 * prior written permission. For written permission, please contact 25 * openssl-core@openssl.org. 26 * 27 * 5. Products derived from this software may not be called "OpenSSL" 28 * nor may "OpenSSL" appear in their names without prior written 29 * permission of the OpenSSL Project. 30 * 31 * 6. Redistributions of any form whatsoever must retain the following 32 * acknowledgment: 33 * "This product includes software developed by the OpenSSL Project 34 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This product includes cryptographic software written by Eric Young 51 * (eay@cryptsoft.com). This product includes software written by Tim 52 * Hudson (tjh@cryptsoft.com). 53 * 54 */ 55/* ==================================================================== 56 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 57 * 58 * Portions of the attached software ("Contribution") are developed by 59 * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. 60 * 61 * The Contribution is licensed pursuant to the OpenSSL open source 62 * license provided above. 63 * 64 * The elliptic curve binary polynomial software is originally written by 65 * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems 66 * Laboratories. */ 67 68#include <openssl/ec.h> 69 70#include <string.h> 71 72#include <openssl/bn.h> 73#include <openssl/err.h> 74#include <openssl/mem.h> 75 76#include "internal.h" 77 78 79const EC_METHOD *EC_GFp_simple_method(void) { 80 static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT, 81 ec_GFp_simple_group_init, 82 ec_GFp_simple_group_finish, 83 ec_GFp_simple_group_clear_finish, 84 ec_GFp_simple_group_copy, 85 ec_GFp_simple_group_set_curve, 86 ec_GFp_simple_group_get_curve, 87 ec_GFp_simple_group_get_degree, 88 ec_GFp_simple_group_check_discriminant, 89 ec_GFp_simple_point_init, 90 ec_GFp_simple_point_finish, 91 ec_GFp_simple_point_clear_finish, 92 ec_GFp_simple_point_copy, 93 ec_GFp_simple_point_set_to_infinity, 94 ec_GFp_simple_set_Jprojective_coordinates_GFp, 95 ec_GFp_simple_get_Jprojective_coordinates_GFp, 96 ec_GFp_simple_point_set_affine_coordinates, 97 ec_GFp_simple_point_get_affine_coordinates, 98 0, 99 0, 100 0, 101 ec_GFp_simple_add, 102 ec_GFp_simple_dbl, 103 ec_GFp_simple_invert, 104 ec_GFp_simple_is_at_infinity, 105 ec_GFp_simple_is_on_curve, 106 ec_GFp_simple_cmp, 107 ec_GFp_simple_make_affine, 108 ec_GFp_simple_points_make_affine, 109 0 /* mul */, 110 0 /* precompute_mult */, 111 0 /* have_precompute_mult */, 112 ec_GFp_simple_field_mul, 113 ec_GFp_simple_field_sqr, 114 0 /* field_div */, 115 0 /* field_encode */, 116 0 /* field_decode */, 117 0 /* field_set_to_one */}; 118 119 return &ret; 120} 121 122 123/* Most method functions in this file are designed to work with non-trivial 124 * representations of field elements if necessary (see ecp_mont.c): while 125 * standard modular addition and subtraction are used, the field_mul and 126 * field_sqr methods will be used for multiplication, and field_encode and 127 * field_decode (if defined) will be used for converting between 128 * representations. 129 130 * Functions ec_GFp_simple_points_make_affine() and 131 * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a 132 * non-trivial representation is used, it is a Montgomery representation (i.e. 133 * 'encoding' means multiplying by some factor R). */ 134 135int ec_GFp_simple_group_init(EC_GROUP *group) { 136 BN_init(&group->field); 137 BN_init(&group->a); 138 BN_init(&group->b); 139 group->a_is_minus3 = 0; 140 return 1; 141} 142 143void ec_GFp_simple_group_finish(EC_GROUP *group) { 144 BN_free(&group->field); 145 BN_free(&group->a); 146 BN_free(&group->b); 147} 148 149void ec_GFp_simple_group_clear_finish(EC_GROUP *group) { 150 BN_clear_free(&group->field); 151 BN_clear_free(&group->a); 152 BN_clear_free(&group->b); 153} 154 155int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) { 156 if (!BN_copy(&dest->field, &src->field) || 157 !BN_copy(&dest->a, &src->a) || 158 !BN_copy(&dest->b, &src->b)) { 159 return 0; 160 } 161 162 dest->a_is_minus3 = src->a_is_minus3; 163 return 1; 164} 165 166int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p, 167 const BIGNUM *a, const BIGNUM *b, 168 BN_CTX *ctx) { 169 int ret = 0; 170 BN_CTX *new_ctx = NULL; 171 BIGNUM *tmp_a; 172 173 /* p must be a prime > 3 */ 174 if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { 175 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_group_set_curve, EC_R_INVALID_FIELD); 176 return 0; 177 } 178 179 if (ctx == NULL) { 180 ctx = new_ctx = BN_CTX_new(); 181 if (ctx == NULL) { 182 return 0; 183 } 184 } 185 186 BN_CTX_start(ctx); 187 tmp_a = BN_CTX_get(ctx); 188 if (tmp_a == NULL) { 189 goto err; 190 } 191 192 /* group->field */ 193 if (!BN_copy(&group->field, p)) { 194 goto err; 195 } 196 BN_set_negative(&group->field, 0); 197 198 /* group->a */ 199 if (!BN_nnmod(tmp_a, a, p, ctx)) { 200 goto err; 201 } 202 if (group->meth->field_encode) { 203 if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) { 204 goto err; 205 } 206 } else if (!BN_copy(&group->a, tmp_a)) { 207 goto err; 208 } 209 210 /* group->b */ 211 if (!BN_nnmod(&group->b, b, p, ctx)) { 212 goto err; 213 } 214 if (group->meth->field_encode && 215 !group->meth->field_encode(group, &group->b, &group->b, ctx)) { 216 goto err; 217 } 218 219 /* group->a_is_minus3 */ 220 if (!BN_add_word(tmp_a, 3)) { 221 goto err; 222 } 223 group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); 224 225 ret = 1; 226 227err: 228 BN_CTX_end(ctx); 229 BN_CTX_free(new_ctx); 230 return ret; 231} 232 233int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, 234 BIGNUM *b, BN_CTX *ctx) { 235 int ret = 0; 236 BN_CTX *new_ctx = NULL; 237 238 if (p != NULL && !BN_copy(p, &group->field)) { 239 return 0; 240 } 241 242 if (a != NULL || b != NULL) { 243 if (group->meth->field_decode) { 244 if (ctx == NULL) { 245 ctx = new_ctx = BN_CTX_new(); 246 if (ctx == NULL) { 247 return 0; 248 } 249 } 250 if (a != NULL && !group->meth->field_decode(group, a, &group->a, ctx)) { 251 goto err; 252 } 253 if (b != NULL && !group->meth->field_decode(group, b, &group->b, ctx)) { 254 goto err; 255 } 256 } else { 257 if (a != NULL && !BN_copy(a, &group->a)) { 258 goto err; 259 } 260 if (b != NULL && !BN_copy(b, &group->b)) { 261 goto err; 262 } 263 } 264 } 265 266 ret = 1; 267 268err: 269 BN_CTX_free(new_ctx); 270 return ret; 271} 272 273int ec_GFp_simple_group_get_degree(const EC_GROUP *group) { 274 return BN_num_bits(&group->field); 275} 276 277int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { 278 int ret = 0; 279 BIGNUM *a, *b, *order, *tmp_1, *tmp_2; 280 const BIGNUM *p = &group->field; 281 BN_CTX *new_ctx = NULL; 282 283 if (ctx == NULL) { 284 ctx = new_ctx = BN_CTX_new(); 285 if (ctx == NULL) { 286 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_group_check_discriminant, 287 ERR_R_MALLOC_FAILURE); 288 goto err; 289 } 290 } 291 BN_CTX_start(ctx); 292 a = BN_CTX_get(ctx); 293 b = BN_CTX_get(ctx); 294 tmp_1 = BN_CTX_get(ctx); 295 tmp_2 = BN_CTX_get(ctx); 296 order = BN_CTX_get(ctx); 297 if (order == NULL) { 298 goto err; 299 } 300 301 if (group->meth->field_decode) { 302 if (!group->meth->field_decode(group, a, &group->a, ctx) || 303 !group->meth->field_decode(group, b, &group->b, ctx)) { 304 goto err; 305 } 306 } else { 307 if (!BN_copy(a, &group->a) || !BN_copy(b, &group->b)) { 308 goto err; 309 } 310 } 311 312 /* check the discriminant: 313 * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) 314 * 0 =< a, b < p */ 315 if (BN_is_zero(a)) { 316 if (BN_is_zero(b)) { 317 goto err; 318 } 319 } else if (!BN_is_zero(b)) { 320 if (!BN_mod_sqr(tmp_1, a, p, ctx) || 321 !BN_mod_mul(tmp_2, tmp_1, a, p, ctx) || 322 !BN_lshift(tmp_1, tmp_2, 2)) { 323 goto err; 324 } 325 /* tmp_1 = 4*a^3 */ 326 327 if (!BN_mod_sqr(tmp_2, b, p, ctx) || 328 !BN_mul_word(tmp_2, 27)) { 329 goto err; 330 } 331 /* tmp_2 = 27*b^2 */ 332 333 if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx) || 334 BN_is_zero(a)) { 335 goto err; 336 } 337 } 338 ret = 1; 339 340err: 341 if (ctx != NULL) { 342 BN_CTX_end(ctx); 343 } 344 BN_CTX_free(new_ctx); 345 return ret; 346} 347 348int ec_GFp_simple_point_init(EC_POINT *point) { 349 BN_init(&point->X); 350 BN_init(&point->Y); 351 BN_init(&point->Z); 352 point->Z_is_one = 0; 353 354 return 1; 355} 356 357void ec_GFp_simple_point_finish(EC_POINT *point) { 358 BN_free(&point->X); 359 BN_free(&point->Y); 360 BN_free(&point->Z); 361} 362 363void ec_GFp_simple_point_clear_finish(EC_POINT *point) { 364 BN_clear_free(&point->X); 365 BN_clear_free(&point->Y); 366 BN_clear_free(&point->Z); 367 point->Z_is_one = 0; 368} 369 370int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { 371 if (!BN_copy(&dest->X, &src->X) || 372 !BN_copy(&dest->Y, &src->Y) || 373 !BN_copy(&dest->Z, &src->Z)) { 374 return 0; 375 } 376 dest->Z_is_one = src->Z_is_one; 377 378 return 1; 379} 380 381int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, 382 EC_POINT *point) { 383 point->Z_is_one = 0; 384 BN_zero(&point->Z); 385 return 1; 386} 387 388int ec_GFp_simple_set_Jprojective_coordinates_GFp( 389 const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, 390 const BIGNUM *z, BN_CTX *ctx) { 391 BN_CTX *new_ctx = NULL; 392 int ret = 0; 393 394 if (ctx == NULL) { 395 ctx = new_ctx = BN_CTX_new(); 396 if (ctx == NULL) { 397 return 0; 398 } 399 } 400 401 if (x != NULL) { 402 if (!BN_nnmod(&point->X, x, &group->field, ctx)) { 403 goto err; 404 } 405 if (group->meth->field_encode && 406 !group->meth->field_encode(group, &point->X, &point->X, ctx)) { 407 goto err; 408 } 409 } 410 411 if (y != NULL) { 412 if (!BN_nnmod(&point->Y, y, &group->field, ctx)) { 413 goto err; 414 } 415 if (group->meth->field_encode && 416 !group->meth->field_encode(group, &point->Y, &point->Y, ctx)) { 417 goto err; 418 } 419 } 420 421 if (z != NULL) { 422 int Z_is_one; 423 424 if (!BN_nnmod(&point->Z, z, &group->field, ctx)) { 425 goto err; 426 } 427 Z_is_one = BN_is_one(&point->Z); 428 if (group->meth->field_encode) { 429 if (Z_is_one && (group->meth->field_set_to_one != 0)) { 430 if (!group->meth->field_set_to_one(group, &point->Z, ctx)) { 431 goto err; 432 } 433 } else if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) { 434 goto err; 435 } 436 } 437 point->Z_is_one = Z_is_one; 438 } 439 440 ret = 1; 441 442err: 443 BN_CTX_free(new_ctx); 444 return ret; 445} 446 447int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, 448 const EC_POINT *point, 449 BIGNUM *x, BIGNUM *y, 450 BIGNUM *z, BN_CTX *ctx) { 451 BN_CTX *new_ctx = NULL; 452 int ret = 0; 453 454 if (group->meth->field_decode != 0) { 455 if (ctx == NULL) { 456 ctx = new_ctx = BN_CTX_new(); 457 if (ctx == NULL) { 458 return 0; 459 } 460 } 461 462 if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { 463 goto err; 464 } 465 if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { 466 goto err; 467 } 468 if (z != NULL && !group->meth->field_decode(group, z, &point->Z, ctx)) { 469 goto err; 470 } 471 } else { 472 if (x != NULL && !BN_copy(x, &point->X)) { 473 goto err; 474 } 475 if (y != NULL && !BN_copy(y, &point->Y)) { 476 goto err; 477 } 478 if (z != NULL && !BN_copy(z, &point->Z)) { 479 goto err; 480 } 481 } 482 483 ret = 1; 484 485err: 486 BN_CTX_free(new_ctx); 487 return ret; 488} 489 490int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, 491 EC_POINT *point, const BIGNUM *x, 492 const BIGNUM *y, BN_CTX *ctx) { 493 if (x == NULL || y == NULL) { 494 /* unlike for projective coordinates, we do not tolerate this */ 495 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_set_affine_coordinates, 496 ERR_R_PASSED_NULL_PARAMETER); 497 return 0; 498 } 499 500 return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y, 501 BN_value_one(), ctx); 502} 503 504int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, 505 const EC_POINT *point, BIGNUM *x, 506 BIGNUM *y, BN_CTX *ctx) { 507 BN_CTX *new_ctx = NULL; 508 BIGNUM *Z, *Z_1, *Z_2, *Z_3; 509 const BIGNUM *Z_; 510 int ret = 0; 511 512 if (EC_POINT_is_at_infinity(group, point)) { 513 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_get_affine_coordinates, 514 EC_R_POINT_AT_INFINITY); 515 return 0; 516 } 517 518 if (ctx == NULL) { 519 ctx = new_ctx = BN_CTX_new(); 520 if (ctx == NULL) { 521 return 0; 522 } 523 } 524 525 BN_CTX_start(ctx); 526 Z = BN_CTX_get(ctx); 527 Z_1 = BN_CTX_get(ctx); 528 Z_2 = BN_CTX_get(ctx); 529 Z_3 = BN_CTX_get(ctx); 530 if (Z_3 == NULL) { 531 goto err; 532 } 533 534 /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ 535 536 if (group->meth->field_decode) { 537 if (!group->meth->field_decode(group, Z, &point->Z, ctx)) { 538 goto err; 539 } 540 Z_ = Z; 541 } else { 542 Z_ = &point->Z; 543 } 544 545 if (BN_is_one(Z_)) { 546 if (group->meth->field_decode) { 547 if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { 548 goto err; 549 } 550 if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { 551 goto err; 552 } 553 } else { 554 if (x != NULL && !BN_copy(x, &point->X)) { 555 goto err; 556 } 557 if (y != NULL && !BN_copy(y, &point->Y)) { 558 goto err; 559 } 560 } 561 } else { 562 if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { 563 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_get_affine_coordinates, 564 ERR_R_BN_LIB); 565 goto err; 566 } 567 568 if (group->meth->field_encode == 0) { 569 /* field_sqr works on standard representation */ 570 if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) { 571 goto err; 572 } 573 } else if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) { 574 goto err; 575 } 576 577 /* in the Montgomery case, field_mul will cancel out Montgomery factor in 578 * X: */ 579 if (x != NULL && !group->meth->field_mul(group, x, &point->X, Z_2, ctx)) { 580 goto err; 581 } 582 583 if (y != NULL) { 584 if (group->meth->field_encode == 0) { 585 /* field_mul works on standard representation */ 586 if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) { 587 goto err; 588 } 589 } else if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) { 590 goto err; 591 } 592 593 /* in the Montgomery case, field_mul will cancel out Montgomery factor in 594 * Y: */ 595 if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) { 596 goto err; 597 } 598 } 599 } 600 601 ret = 1; 602 603err: 604 BN_CTX_end(ctx); 605 BN_CTX_free(new_ctx); 606 return ret; 607} 608 609int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 610 const EC_POINT *b, BN_CTX *ctx) { 611 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, 612 BN_CTX *); 613 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 614 const BIGNUM *p; 615 BN_CTX *new_ctx = NULL; 616 BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; 617 int ret = 0; 618 619 if (a == b) { 620 return EC_POINT_dbl(group, r, a, ctx); 621 } 622 if (EC_POINT_is_at_infinity(group, a)) { 623 return EC_POINT_copy(r, b); 624 } 625 if (EC_POINT_is_at_infinity(group, b)) { 626 return EC_POINT_copy(r, a); 627 } 628 629 field_mul = group->meth->field_mul; 630 field_sqr = group->meth->field_sqr; 631 p = &group->field; 632 633 if (ctx == NULL) { 634 ctx = new_ctx = BN_CTX_new(); 635 if (ctx == NULL) { 636 return 0; 637 } 638 } 639 640 BN_CTX_start(ctx); 641 n0 = BN_CTX_get(ctx); 642 n1 = BN_CTX_get(ctx); 643 n2 = BN_CTX_get(ctx); 644 n3 = BN_CTX_get(ctx); 645 n4 = BN_CTX_get(ctx); 646 n5 = BN_CTX_get(ctx); 647 n6 = BN_CTX_get(ctx); 648 if (n6 == NULL) { 649 goto end; 650 } 651 652 /* Note that in this function we must not read components of 'a' or 'b' 653 * once we have written the corresponding components of 'r'. 654 * ('r' might be one of 'a' or 'b'.) 655 */ 656 657 /* n1, n2 */ 658 if (b->Z_is_one) { 659 if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { 660 goto end; 661 } 662 /* n1 = X_a */ 663 /* n2 = Y_a */ 664 } else { 665 if (!field_sqr(group, n0, &b->Z, ctx) || 666 !field_mul(group, n1, &a->X, n0, ctx)) { 667 goto end; 668 } 669 /* n1 = X_a * Z_b^2 */ 670 671 if (!field_mul(group, n0, n0, &b->Z, ctx) || 672 !field_mul(group, n2, &a->Y, n0, ctx)) { 673 goto end; 674 } 675 /* n2 = Y_a * Z_b^3 */ 676 } 677 678 /* n3, n4 */ 679 if (a->Z_is_one) { 680 if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { 681 goto end; 682 } 683 /* n3 = X_b */ 684 /* n4 = Y_b */ 685 } else { 686 if (!field_sqr(group, n0, &a->Z, ctx) || 687 !field_mul(group, n3, &b->X, n0, ctx)) { 688 goto end; 689 } 690 /* n3 = X_b * Z_a^2 */ 691 692 if (!field_mul(group, n0, n0, &a->Z, ctx) || 693 !field_mul(group, n4, &b->Y, n0, ctx)) { 694 goto end; 695 } 696 /* n4 = Y_b * Z_a^3 */ 697 } 698 699 /* n5, n6 */ 700 if (!BN_mod_sub_quick(n5, n1, n3, p) || 701 !BN_mod_sub_quick(n6, n2, n4, p)) { 702 goto end; 703 } 704 /* n5 = n1 - n3 */ 705 /* n6 = n2 - n4 */ 706 707 if (BN_is_zero(n5)) { 708 if (BN_is_zero(n6)) { 709 /* a is the same point as b */ 710 BN_CTX_end(ctx); 711 ret = EC_POINT_dbl(group, r, a, ctx); 712 ctx = NULL; 713 goto end; 714 } else { 715 /* a is the inverse of b */ 716 BN_zero(&r->Z); 717 r->Z_is_one = 0; 718 ret = 1; 719 goto end; 720 } 721 } 722 723 /* 'n7', 'n8' */ 724 if (!BN_mod_add_quick(n1, n1, n3, p) || 725 !BN_mod_add_quick(n2, n2, n4, p)) { 726 goto end; 727 } 728 /* 'n7' = n1 + n3 */ 729 /* 'n8' = n2 + n4 */ 730 731 /* Z_r */ 732 if (a->Z_is_one && b->Z_is_one) { 733 if (!BN_copy(&r->Z, n5)) { 734 goto end; 735 } 736 } else { 737 if (a->Z_is_one) { 738 if (!BN_copy(n0, &b->Z)) { 739 goto end; 740 } 741 } else if (b->Z_is_one) { 742 if (!BN_copy(n0, &a->Z)) { 743 goto end; 744 } 745 } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) { 746 goto end; 747 } 748 if (!field_mul(group, &r->Z, n0, n5, ctx)) { 749 goto end; 750 } 751 } 752 r->Z_is_one = 0; 753 /* Z_r = Z_a * Z_b * n5 */ 754 755 /* X_r */ 756 if (!field_sqr(group, n0, n6, ctx) || 757 !field_sqr(group, n4, n5, ctx) || 758 !field_mul(group, n3, n1, n4, ctx) || 759 !BN_mod_sub_quick(&r->X, n0, n3, p)) { 760 goto end; 761 } 762 /* X_r = n6^2 - n5^2 * 'n7' */ 763 764 /* 'n9' */ 765 if (!BN_mod_lshift1_quick(n0, &r->X, p) || 766 !BN_mod_sub_quick(n0, n3, n0, p)) { 767 goto end; 768 } 769 /* n9 = n5^2 * 'n7' - 2 * X_r */ 770 771 /* Y_r */ 772 if (!field_mul(group, n0, n0, n6, ctx) || 773 !field_mul(group, n5, n4, n5, ctx)) { 774 goto end; /* now n5 is n5^3 */ 775 } 776 if (!field_mul(group, n1, n2, n5, ctx) || 777 !BN_mod_sub_quick(n0, n0, n1, p)) { 778 goto end; 779 } 780 if (BN_is_odd(n0) && !BN_add(n0, n0, p)) { 781 goto end; 782 } 783 /* now 0 <= n0 < 2*p, and n0 is even */ 784 if (!BN_rshift1(&r->Y, n0)) { 785 goto end; 786 } 787 /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ 788 789 ret = 1; 790 791end: 792 if (ctx) { 793 /* otherwise we already called BN_CTX_end */ 794 BN_CTX_end(ctx); 795 } 796 BN_CTX_free(new_ctx); 797 return ret; 798} 799 800int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 801 BN_CTX *ctx) { 802 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, 803 BN_CTX *); 804 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 805 const BIGNUM *p; 806 BN_CTX *new_ctx = NULL; 807 BIGNUM *n0, *n1, *n2, *n3; 808 int ret = 0; 809 810 if (EC_POINT_is_at_infinity(group, a)) { 811 BN_zero(&r->Z); 812 r->Z_is_one = 0; 813 return 1; 814 } 815 816 field_mul = group->meth->field_mul; 817 field_sqr = group->meth->field_sqr; 818 p = &group->field; 819 820 if (ctx == NULL) { 821 ctx = new_ctx = BN_CTX_new(); 822 if (ctx == NULL) { 823 return 0; 824 } 825 } 826 827 BN_CTX_start(ctx); 828 n0 = BN_CTX_get(ctx); 829 n1 = BN_CTX_get(ctx); 830 n2 = BN_CTX_get(ctx); 831 n3 = BN_CTX_get(ctx); 832 if (n3 == NULL) { 833 goto err; 834 } 835 836 /* Note that in this function we must not read components of 'a' 837 * once we have written the corresponding components of 'r'. 838 * ('r' might the same as 'a'.) 839 */ 840 841 /* n1 */ 842 if (a->Z_is_one) { 843 if (!field_sqr(group, n0, &a->X, ctx) || 844 !BN_mod_lshift1_quick(n1, n0, p) || 845 !BN_mod_add_quick(n0, n0, n1, p) || 846 !BN_mod_add_quick(n1, n0, &group->a, p)) { 847 goto err; 848 } 849 /* n1 = 3 * X_a^2 + a_curve */ 850 } else if (group->a_is_minus3) { 851 if (!field_sqr(group, n1, &a->Z, ctx) || 852 !BN_mod_add_quick(n0, &a->X, n1, p) || 853 !BN_mod_sub_quick(n2, &a->X, n1, p) || 854 !field_mul(group, n1, n0, n2, ctx) || 855 !BN_mod_lshift1_quick(n0, n1, p) || 856 !BN_mod_add_quick(n1, n0, n1, p)) { 857 goto err; 858 } 859 /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) 860 * = 3 * X_a^2 - 3 * Z_a^4 */ 861 } else { 862 if (!field_sqr(group, n0, &a->X, ctx) || 863 !BN_mod_lshift1_quick(n1, n0, p) || 864 !BN_mod_add_quick(n0, n0, n1, p) || 865 !field_sqr(group, n1, &a->Z, ctx) || 866 !field_sqr(group, n1, n1, ctx) || 867 !field_mul(group, n1, n1, &group->a, ctx) || 868 !BN_mod_add_quick(n1, n1, n0, p)) { 869 goto err; 870 } 871 /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ 872 } 873 874 /* Z_r */ 875 if (a->Z_is_one) { 876 if (!BN_copy(n0, &a->Y)) { 877 goto err; 878 } 879 } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { 880 goto err; 881 } 882 if (!BN_mod_lshift1_quick(&r->Z, n0, p)) { 883 goto err; 884 } 885 r->Z_is_one = 0; 886 /* Z_r = 2 * Y_a * Z_a */ 887 888 /* n2 */ 889 if (!field_sqr(group, n3, &a->Y, ctx) || 890 !field_mul(group, n2, &a->X, n3, ctx) || 891 !BN_mod_lshift_quick(n2, n2, 2, p)) { 892 goto err; 893 } 894 /* n2 = 4 * X_a * Y_a^2 */ 895 896 /* X_r */ 897 if (!BN_mod_lshift1_quick(n0, n2, p) || 898 !field_sqr(group, &r->X, n1, ctx) || 899 !BN_mod_sub_quick(&r->X, &r->X, n0, p)) { 900 goto err; 901 } 902 /* X_r = n1^2 - 2 * n2 */ 903 904 /* n3 */ 905 if (!field_sqr(group, n0, n3, ctx) || 906 !BN_mod_lshift_quick(n3, n0, 3, p)) { 907 goto err; 908 } 909 /* n3 = 8 * Y_a^4 */ 910 911 /* Y_r */ 912 if (!BN_mod_sub_quick(n0, n2, &r->X, p) || 913 !field_mul(group, n0, n1, n0, ctx) || 914 !BN_mod_sub_quick(&r->Y, n0, n3, p)) { 915 goto err; 916 } 917 /* Y_r = n1 * (n2 - X_r) - n3 */ 918 919 ret = 1; 920 921err: 922 BN_CTX_end(ctx); 923 BN_CTX_free(new_ctx); 924 return ret; 925} 926 927int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { 928 if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) { 929 /* point is its own inverse */ 930 return 1; 931 } 932 933 return BN_usub(&point->Y, &group->field, &point->Y); 934} 935 936int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { 937 return !point->Z_is_one && BN_is_zero(&point->Z); 938} 939 940int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 941 BN_CTX *ctx) { 942 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, 943 BN_CTX *); 944 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 945 const BIGNUM *p; 946 BN_CTX *new_ctx = NULL; 947 BIGNUM *rh, *tmp, *Z4, *Z6; 948 int ret = -1; 949 950 if (EC_POINT_is_at_infinity(group, point)) { 951 return 1; 952 } 953 954 field_mul = group->meth->field_mul; 955 field_sqr = group->meth->field_sqr; 956 p = &group->field; 957 958 if (ctx == NULL) { 959 ctx = new_ctx = BN_CTX_new(); 960 if (ctx == NULL) { 961 return -1; 962 } 963 } 964 965 BN_CTX_start(ctx); 966 rh = BN_CTX_get(ctx); 967 tmp = BN_CTX_get(ctx); 968 Z4 = BN_CTX_get(ctx); 969 Z6 = BN_CTX_get(ctx); 970 if (Z6 == NULL) { 971 goto err; 972 } 973 974 /* We have a curve defined by a Weierstrass equation 975 * y^2 = x^3 + a*x + b. 976 * The point to consider is given in Jacobian projective coordinates 977 * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). 978 * Substituting this and multiplying by Z^6 transforms the above equation 979 * into 980 * Y^2 = X^3 + a*X*Z^4 + b*Z^6. 981 * To test this, we add up the right-hand side in 'rh'. 982 */ 983 984 /* rh := X^2 */ 985 if (!field_sqr(group, rh, &point->X, ctx)) { 986 goto err; 987 } 988 989 if (!point->Z_is_one) { 990 if (!field_sqr(group, tmp, &point->Z, ctx) || 991 !field_sqr(group, Z4, tmp, ctx) || 992 !field_mul(group, Z6, Z4, tmp, ctx)) { 993 goto err; 994 } 995 996 /* rh := (rh + a*Z^4)*X */ 997 if (group->a_is_minus3) { 998 if (!BN_mod_lshift1_quick(tmp, Z4, p) || 999 !BN_mod_add_quick(tmp, tmp, Z4, p) || 1000 !BN_mod_sub_quick(rh, rh, tmp, p) || 1001 !field_mul(group, rh, rh, &point->X, ctx)) { 1002 goto err; 1003 } 1004 } else { 1005 if (!field_mul(group, tmp, Z4, &group->a, ctx) || 1006 !BN_mod_add_quick(rh, rh, tmp, p) || 1007 !field_mul(group, rh, rh, &point->X, ctx)) { 1008 goto err; 1009 } 1010 } 1011 1012 /* rh := rh + b*Z^6 */ 1013 if (!field_mul(group, tmp, &group->b, Z6, ctx) || 1014 !BN_mod_add_quick(rh, rh, tmp, p)) { 1015 goto err; 1016 } 1017 } else { 1018 /* point->Z_is_one */ 1019 1020 /* rh := (rh + a)*X */ 1021 if (!BN_mod_add_quick(rh, rh, &group->a, p) || 1022 !field_mul(group, rh, rh, &point->X, ctx)) { 1023 goto err; 1024 } 1025 /* rh := rh + b */ 1026 if (!BN_mod_add_quick(rh, rh, &group->b, p)) { 1027 goto err; 1028 } 1029 } 1030 1031 /* 'lh' := Y^2 */ 1032 if (!field_sqr(group, tmp, &point->Y, ctx)) { 1033 goto err; 1034 } 1035 1036 ret = (0 == BN_ucmp(tmp, rh)); 1037 1038err: 1039 BN_CTX_end(ctx); 1040 BN_CTX_free(new_ctx); 1041 return ret; 1042} 1043 1044int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, 1045 const EC_POINT *b, BN_CTX *ctx) { 1046 /* return values: 1047 * -1 error 1048 * 0 equal (in affine coordinates) 1049 * 1 not equal 1050 */ 1051 1052 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, 1053 BN_CTX *); 1054 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 1055 BN_CTX *new_ctx = NULL; 1056 BIGNUM *tmp1, *tmp2, *Za23, *Zb23; 1057 const BIGNUM *tmp1_, *tmp2_; 1058 int ret = -1; 1059 1060 if (EC_POINT_is_at_infinity(group, a)) { 1061 return EC_POINT_is_at_infinity(group, b) ? 0 : 1; 1062 } 1063 1064 if (EC_POINT_is_at_infinity(group, b)) { 1065 return 1; 1066 } 1067 1068 if (a->Z_is_one && b->Z_is_one) { 1069 return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; 1070 } 1071 1072 field_mul = group->meth->field_mul; 1073 field_sqr = group->meth->field_sqr; 1074 1075 if (ctx == NULL) { 1076 ctx = new_ctx = BN_CTX_new(); 1077 if (ctx == NULL) { 1078 return -1; 1079 } 1080 } 1081 1082 BN_CTX_start(ctx); 1083 tmp1 = BN_CTX_get(ctx); 1084 tmp2 = BN_CTX_get(ctx); 1085 Za23 = BN_CTX_get(ctx); 1086 Zb23 = BN_CTX_get(ctx); 1087 if (Zb23 == NULL) { 1088 goto end; 1089 } 1090 1091 /* We have to decide whether 1092 * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), 1093 * or equivalently, whether 1094 * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). 1095 */ 1096 1097 if (!b->Z_is_one) { 1098 if (!field_sqr(group, Zb23, &b->Z, ctx) || 1099 !field_mul(group, tmp1, &a->X, Zb23, ctx)) { 1100 goto end; 1101 } 1102 tmp1_ = tmp1; 1103 } else { 1104 tmp1_ = &a->X; 1105 } 1106 if (!a->Z_is_one) { 1107 if (!field_sqr(group, Za23, &a->Z, ctx) || 1108 !field_mul(group, tmp2, &b->X, Za23, ctx)) { 1109 goto end; 1110 } 1111 tmp2_ = tmp2; 1112 } else { 1113 tmp2_ = &b->X; 1114 } 1115 1116 /* compare X_a*Z_b^2 with X_b*Z_a^2 */ 1117 if (BN_cmp(tmp1_, tmp2_) != 0) { 1118 ret = 1; /* points differ */ 1119 goto end; 1120 } 1121 1122 1123 if (!b->Z_is_one) { 1124 if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) || 1125 !field_mul(group, tmp1, &a->Y, Zb23, ctx)) { 1126 goto end; 1127 } 1128 /* tmp1_ = tmp1 */ 1129 } else { 1130 tmp1_ = &a->Y; 1131 } 1132 if (!a->Z_is_one) { 1133 if (!field_mul(group, Za23, Za23, &a->Z, ctx) || 1134 !field_mul(group, tmp2, &b->Y, Za23, ctx)) { 1135 goto end; 1136 } 1137 /* tmp2_ = tmp2 */ 1138 } else { 1139 tmp2_ = &b->Y; 1140 } 1141 1142 /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ 1143 if (BN_cmp(tmp1_, tmp2_) != 0) { 1144 ret = 1; /* points differ */ 1145 goto end; 1146 } 1147 1148 /* points are equal */ 1149 ret = 0; 1150 1151end: 1152 BN_CTX_end(ctx); 1153 BN_CTX_free(new_ctx); 1154 return ret; 1155} 1156 1157int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, 1158 BN_CTX *ctx) { 1159 BN_CTX *new_ctx = NULL; 1160 BIGNUM *x, *y; 1161 int ret = 0; 1162 1163 if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) { 1164 return 1; 1165 } 1166 1167 if (ctx == NULL) { 1168 ctx = new_ctx = BN_CTX_new(); 1169 if (ctx == NULL) { 1170 return 0; 1171 } 1172 } 1173 1174 BN_CTX_start(ctx); 1175 x = BN_CTX_get(ctx); 1176 y = BN_CTX_get(ctx); 1177 if (y == NULL) { 1178 goto err; 1179 } 1180 1181 if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) || 1182 !EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { 1183 goto err; 1184 } 1185 if (!point->Z_is_one) { 1186 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_make_affine, ERR_R_INTERNAL_ERROR); 1187 goto err; 1188 } 1189 1190 ret = 1; 1191 1192err: 1193 BN_CTX_end(ctx); 1194 BN_CTX_free(new_ctx); 1195 return ret; 1196} 1197 1198int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, 1199 EC_POINT *points[], BN_CTX *ctx) { 1200 BN_CTX *new_ctx = NULL; 1201 BIGNUM *tmp, *tmp_Z; 1202 BIGNUM **prod_Z = NULL; 1203 size_t i; 1204 int ret = 0; 1205 1206 if (num == 0) { 1207 return 1; 1208 } 1209 1210 if (ctx == NULL) { 1211 ctx = new_ctx = BN_CTX_new(); 1212 if (ctx == NULL) { 1213 return 0; 1214 } 1215 } 1216 1217 BN_CTX_start(ctx); 1218 tmp = BN_CTX_get(ctx); 1219 tmp_Z = BN_CTX_get(ctx); 1220 if (tmp == NULL || tmp_Z == NULL) { 1221 goto err; 1222 } 1223 1224 prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0])); 1225 if (prod_Z == NULL) { 1226 goto err; 1227 } 1228 memset(prod_Z, 0, num * sizeof(prod_Z[0])); 1229 for (i = 0; i < num; i++) { 1230 prod_Z[i] = BN_new(); 1231 if (prod_Z[i] == NULL) { 1232 goto err; 1233 } 1234 } 1235 1236 /* Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, 1237 * skipping any zero-valued inputs (pretend that they're 1). */ 1238 1239 if (!BN_is_zero(&points[0]->Z)) { 1240 if (!BN_copy(prod_Z[0], &points[0]->Z)) { 1241 goto err; 1242 } 1243 } else { 1244 if (group->meth->field_set_to_one != 0) { 1245 if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) { 1246 goto err; 1247 } 1248 } else { 1249 if (!BN_one(prod_Z[0])) { 1250 goto err; 1251 } 1252 } 1253 } 1254 1255 for (i = 1; i < num; i++) { 1256 if (!BN_is_zero(&points[i]->Z)) { 1257 if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], 1258 &points[i]->Z, ctx)) { 1259 goto err; 1260 } 1261 } else { 1262 if (!BN_copy(prod_Z[i], prod_Z[i - 1])) { 1263 goto err; 1264 } 1265 } 1266 } 1267 1268 /* Now use a single explicit inversion to replace every 1269 * non-zero points[i]->Z by its inverse. */ 1270 1271 if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { 1272 OPENSSL_PUT_ERROR(EC, ec_GFp_simple_points_make_affine, ERR_R_BN_LIB); 1273 goto err; 1274 } 1275 1276 if (group->meth->field_encode != NULL) { 1277 /* In the Montgomery case, we just turned R*H (representing H) 1278 * into 1/(R*H), but we need R*(1/H) (representing 1/H); 1279 * i.e. we need to multiply by the Montgomery factor twice. */ 1280 if (!group->meth->field_encode(group, tmp, tmp, ctx) || 1281 !group->meth->field_encode(group, tmp, tmp, ctx)) { 1282 goto err; 1283 } 1284 } 1285 1286 for (i = num - 1; i > 0; --i) { 1287 /* Loop invariant: tmp is the product of the inverses of 1288 * points[0]->Z .. points[i]->Z (zero-valued inputs skipped). */ 1289 if (BN_is_zero(&points[i]->Z)) { 1290 continue; 1291 } 1292 1293 /* Set tmp_Z to the inverse of points[i]->Z (as product 1294 * of Z inverses 0 .. i, Z values 0 .. i - 1). */ 1295 if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx) || 1296 /* Update tmp to satisfy the loop invariant for i - 1. */ 1297 !group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx) || 1298 /* Replace points[i]->Z by its inverse. */ 1299 !BN_copy(&points[i]->Z, tmp_Z)) { 1300 goto err; 1301 } 1302 } 1303 1304 /* Replace points[0]->Z by its inverse. */ 1305 if (!BN_is_zero(&points[0]->Z) && !BN_copy(&points[0]->Z, tmp)) { 1306 goto err; 1307 } 1308 1309 /* Finally, fix up the X and Y coordinates for all points. */ 1310 for (i = 0; i < num; i++) { 1311 EC_POINT *p = points[i]; 1312 1313 if (!BN_is_zero(&p->Z)) { 1314 /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1). */ 1315 if (!group->meth->field_sqr(group, tmp, &p->Z, ctx) || 1316 !group->meth->field_mul(group, &p->X, &p->X, tmp, ctx) || 1317 !group->meth->field_mul(group, tmp, tmp, &p->Z, ctx) || 1318 !group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) { 1319 goto err; 1320 } 1321 1322 if (group->meth->field_set_to_one != NULL) { 1323 if (!group->meth->field_set_to_one(group, &p->Z, ctx)) { 1324 goto err; 1325 } 1326 } else { 1327 if (!BN_one(&p->Z)) { 1328 goto err; 1329 } 1330 } 1331 p->Z_is_one = 1; 1332 } 1333 } 1334 1335 ret = 1; 1336 1337err: 1338 BN_CTX_end(ctx); 1339 BN_CTX_free(new_ctx); 1340 if (prod_Z != NULL) { 1341 for (i = 0; i < num; i++) { 1342 if (prod_Z[i] == NULL) { 1343 break; 1344 } 1345 BN_clear_free(prod_Z[i]); 1346 } 1347 OPENSSL_free(prod_Z); 1348 } 1349 1350 return ret; 1351} 1352 1353int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1354 const BIGNUM *b, BN_CTX *ctx) { 1355 return BN_mod_mul(r, a, b, &group->field, ctx); 1356} 1357 1358int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1359 BN_CTX *ctx) { 1360 return BN_mod_sqr(r, a, &group->field, ctx); 1361} 1362