1 /* $OpenBSD: ec_lib.c,v 1.111 2025/01/11 15:26:07 tb Exp $ */ 2 /* 3 * Originally written by Bodo Moeller for the OpenSSL project. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * openssl-core@openssl.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 /* ==================================================================== 59 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 60 * Binary polynomial ECC support in OpenSSL originally developed by 61 * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. 62 */ 63 64 #include <stdlib.h> 65 #include <string.h> 66 67 #include <openssl/opensslconf.h> 68 69 #include <openssl/bn.h> 70 #include <openssl/ec.h> 71 #include <openssl/err.h> 72 #include <openssl/objects.h> 73 #include <openssl/opensslv.h> 74 75 #include "bn_local.h" 76 #include "ec_local.h" 77 78 EC_GROUP * 79 EC_GROUP_new(const EC_METHOD *meth) 80 { 81 EC_GROUP *group = NULL; 82 83 if (meth == NULL) { 84 ECerror(EC_R_SLOT_FULL); 85 goto err; 86 } 87 if ((group = calloc(1, sizeof(*group))) == NULL) { 88 ECerror(ERR_R_MALLOC_FAILURE); 89 goto err; 90 } 91 92 group->meth = meth; 93 94 group->asn1_flag = OPENSSL_EC_NAMED_CURVE; 95 group->asn1_form = POINT_CONVERSION_UNCOMPRESSED; 96 97 if ((group->p = BN_new()) == NULL) 98 goto err; 99 if ((group->a = BN_new()) == NULL) 100 goto err; 101 if ((group->b = BN_new()) == NULL) 102 goto err; 103 104 if ((group->order = BN_new()) == NULL) 105 goto err; 106 if ((group->cofactor = BN_new()) == NULL) 107 goto err; 108 109 /* 110 * generator, seed and mont_ctx are optional. 111 */ 112 113 return group; 114 115 err: 116 EC_GROUP_free(group); 117 118 return NULL; 119 } 120 LCRYPTO_ALIAS(EC_GROUP_new); 121 122 void 123 EC_GROUP_free(EC_GROUP *group) 124 { 125 if (group == NULL) 126 return; 127 128 BN_free(group->p); 129 BN_free(group->a); 130 BN_free(group->b); 131 132 BN_MONT_CTX_free(group->mont_ctx); 133 134 EC_POINT_free(group->generator); 135 BN_free(group->order); 136 BN_free(group->cofactor); 137 138 freezero(group->seed, group->seed_len); 139 freezero(group, sizeof *group); 140 } 141 LCRYPTO_ALIAS(EC_GROUP_free); 142 143 void 144 EC_GROUP_clear_free(EC_GROUP *group) 145 { 146 EC_GROUP_free(group); 147 } 148 LCRYPTO_ALIAS(EC_GROUP_clear_free); 149 150 int 151 EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src) 152 { 153 if (dst->meth != src->meth) { 154 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 155 return 0; 156 } 157 if (dst == src) 158 return 1; 159 160 if (!bn_copy(dst->p, src->p)) 161 return 0; 162 if (!bn_copy(dst->a, src->a)) 163 return 0; 164 if (!bn_copy(dst->b, src->b)) 165 return 0; 166 167 dst->a_is_minus3 = src->a_is_minus3; 168 169 BN_MONT_CTX_free(dst->mont_ctx); 170 dst->mont_ctx = NULL; 171 if (src->mont_ctx != NULL) { 172 if ((dst->mont_ctx = BN_MONT_CTX_new()) == NULL) 173 return 0; 174 if (!BN_MONT_CTX_copy(dst->mont_ctx, src->mont_ctx)) 175 return 0; 176 } 177 178 EC_POINT_free(dst->generator); 179 dst->generator = NULL; 180 if (src->generator != NULL) { 181 if (!EC_GROUP_set_generator(dst, src->generator, src->order, 182 src->cofactor)) 183 return 0; 184 } else { 185 /* XXX - should do the sanity checks as in set_generator() */ 186 if (!bn_copy(dst->order, src->order)) 187 return 0; 188 if (!bn_copy(dst->cofactor, src->cofactor)) 189 return 0; 190 } 191 192 dst->nid = src->nid; 193 dst->asn1_flag = src->asn1_flag; 194 dst->asn1_form = src->asn1_form; 195 196 if (!EC_GROUP_set_seed(dst, src->seed, src->seed_len)) 197 return 0; 198 199 return 1; 200 } 201 LCRYPTO_ALIAS(EC_GROUP_copy); 202 203 EC_GROUP * 204 EC_GROUP_dup(const EC_GROUP *in_group) 205 { 206 EC_GROUP *group = NULL; 207 208 if (in_group == NULL) 209 goto err; 210 211 if ((group = EC_GROUP_new(in_group->meth)) == NULL) 212 goto err; 213 if (!EC_GROUP_copy(group, in_group)) 214 goto err; 215 216 return group; 217 218 err: 219 EC_GROUP_free(group); 220 221 return NULL; 222 } 223 LCRYPTO_ALIAS(EC_GROUP_dup); 224 225 const EC_METHOD * 226 EC_GROUP_method_of(const EC_GROUP *group) 227 { 228 return group->meth; 229 } 230 LCRYPTO_ALIAS(EC_GROUP_method_of); 231 232 int 233 EC_METHOD_get_field_type(const EC_METHOD *meth) 234 { 235 return meth->field_type; 236 } 237 LCRYPTO_ALIAS(EC_METHOD_get_field_type); 238 239 int 240 ec_group_get_field_type(const EC_GROUP *group) 241 { 242 if (group == NULL || group->meth == NULL) 243 return NID_undef; 244 245 return group->meth->field_type; 246 } 247 248 /* 249 * If there is a user-provided cofactor, sanity check and use it. Otherwise 250 * try computing the cofactor from generator order n and field cardinality p. 251 * This works for all curves of cryptographic interest. 252 * 253 * Hasse's theorem: | h * n - (p + 1) | <= 2 * sqrt(p) 254 * 255 * So: h_min = (p + 1 - 2*sqrt(p)) / n and h_max = (p + 1 + 2*sqrt(p)) / n and 256 * therefore h_max - h_min = 4*sqrt(p) / n. So if n > 4*sqrt(p) holds, there is 257 * only one possible value for h: 258 * 259 * h = \lfloor (h_min + h_max)/2 \rceil = \lfloor (p + 1)/n \rceil 260 * 261 * Otherwise, zero cofactor and return success. 262 */ 263 static int 264 ec_set_cofactor(EC_GROUP *group, const BIGNUM *in_cofactor) 265 { 266 BN_CTX *ctx = NULL; 267 BIGNUM *cofactor; 268 int ret = 0; 269 270 BN_zero(group->cofactor); 271 272 if ((ctx = BN_CTX_new()) == NULL) 273 goto err; 274 275 BN_CTX_start(ctx); 276 if ((cofactor = BN_CTX_get(ctx)) == NULL) 277 goto err; 278 279 /* 280 * Unfortunately, the cofactor is an optional field in many standards. 281 * Internally, the library uses a 0 cofactor as a marker for "unknown 282 * cofactor". So accept in_cofactor == NULL or in_cofactor >= 0. 283 */ 284 if (in_cofactor != NULL && !BN_is_zero(in_cofactor)) { 285 if (BN_is_negative(in_cofactor)) { 286 ECerror(EC_R_UNKNOWN_COFACTOR); 287 goto err; 288 } 289 if (!bn_copy(cofactor, in_cofactor)) 290 goto err; 291 goto done; 292 } 293 294 /* 295 * If the cofactor is too large, we cannot guess it and default to zero. 296 * The RHS of below is a strict overestimate of log(4 * sqrt(p)). 297 */ 298 if (BN_num_bits(group->order) <= (BN_num_bits(group->p) + 1) / 2 + 3) 299 goto done; 300 301 /* 302 * Compute 303 * h = \lfloor (p + 1)/n \rceil = \lfloor (p + 1 + n/2) / n \rfloor. 304 */ 305 306 /* h = n/2 */ 307 if (!BN_rshift1(cofactor, group->order)) 308 goto err; 309 /* h = 1 + n/2 */ 310 if (!BN_add_word(cofactor, 1)) 311 goto err; 312 /* h = p + 1 + n/2 */ 313 if (!BN_add(cofactor, cofactor, group->p)) 314 goto err; 315 /* h = (p + 1 + n/2) / n */ 316 if (!BN_div_ct(cofactor, NULL, cofactor, group->order, ctx)) 317 goto err; 318 319 done: 320 /* Use Hasse's theorem to bound the cofactor. */ 321 if (BN_num_bits(cofactor) > BN_num_bits(group->p) + 1) { 322 ECerror(EC_R_INVALID_GROUP_ORDER); 323 goto err; 324 } 325 326 if (!bn_copy(group->cofactor, cofactor)) 327 goto err; 328 329 ret = 1; 330 331 err: 332 BN_CTX_end(ctx); 333 BN_CTX_free(ctx); 334 335 return ret; 336 } 337 338 int 339 EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, 340 const BIGNUM *order, const BIGNUM *cofactor) 341 { 342 if (generator == NULL) { 343 ECerror(ERR_R_PASSED_NULL_PARAMETER); 344 return 0; 345 } 346 347 /* Require p >= 1. */ 348 if (BN_is_zero(group->p) || BN_is_negative(group->p)) { 349 ECerror(EC_R_INVALID_FIELD); 350 return 0; 351 } 352 353 /* 354 * Require order > 1 and enforce an upper bound of at most one bit more 355 * than the field cardinality due to Hasse's theorem. 356 */ 357 if (order == NULL || BN_cmp(order, BN_value_one()) <= 0 || 358 BN_num_bits(order) > BN_num_bits(group->p) + 1) { 359 ECerror(EC_R_INVALID_GROUP_ORDER); 360 return 0; 361 } 362 363 if (group->generator == NULL) 364 group->generator = EC_POINT_new(group); 365 if (group->generator == NULL) 366 return 0; 367 368 if (!EC_POINT_copy(group->generator, generator)) 369 return 0; 370 371 if (!bn_copy(group->order, order)) 372 return 0; 373 374 if (!ec_set_cofactor(group, cofactor)) 375 return 0; 376 377 return 1; 378 } 379 LCRYPTO_ALIAS(EC_GROUP_set_generator); 380 381 const EC_POINT * 382 EC_GROUP_get0_generator(const EC_GROUP *group) 383 { 384 return group->generator; 385 } 386 LCRYPTO_ALIAS(EC_GROUP_get0_generator); 387 388 int 389 EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) 390 { 391 if (!bn_copy(order, group->order)) 392 return 0; 393 394 return !BN_is_zero(order); 395 } 396 LCRYPTO_ALIAS(EC_GROUP_get_order); 397 398 const BIGNUM * 399 EC_GROUP_get0_order(const EC_GROUP *group) 400 { 401 return group->order; 402 } 403 404 int 405 EC_GROUP_order_bits(const EC_GROUP *group) 406 { 407 return BN_num_bits(group->order); 408 } 409 LCRYPTO_ALIAS(EC_GROUP_order_bits); 410 411 int 412 EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) 413 { 414 if (!bn_copy(cofactor, group->cofactor)) 415 return 0; 416 417 return !BN_is_zero(group->cofactor); 418 } 419 LCRYPTO_ALIAS(EC_GROUP_get_cofactor); 420 421 const BIGNUM * 422 EC_GROUP_get0_cofactor(const EC_GROUP *group) 423 { 424 return group->cofactor; 425 } 426 427 void 428 EC_GROUP_set_curve_name(EC_GROUP *group, int nid) 429 { 430 group->nid = nid; 431 } 432 LCRYPTO_ALIAS(EC_GROUP_set_curve_name); 433 434 int 435 EC_GROUP_get_curve_name(const EC_GROUP *group) 436 { 437 return group->nid; 438 } 439 LCRYPTO_ALIAS(EC_GROUP_get_curve_name); 440 441 void 442 EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) 443 { 444 group->asn1_flag = flag; 445 } 446 LCRYPTO_ALIAS(EC_GROUP_set_asn1_flag); 447 448 int 449 EC_GROUP_get_asn1_flag(const EC_GROUP *group) 450 { 451 return group->asn1_flag; 452 } 453 LCRYPTO_ALIAS(EC_GROUP_get_asn1_flag); 454 455 void 456 EC_GROUP_set_point_conversion_form(EC_GROUP *group, 457 point_conversion_form_t form) 458 { 459 group->asn1_form = form; 460 } 461 LCRYPTO_ALIAS(EC_GROUP_set_point_conversion_form); 462 463 point_conversion_form_t 464 EC_GROUP_get_point_conversion_form(const EC_GROUP *group) 465 { 466 return group->asn1_form; 467 } 468 LCRYPTO_ALIAS(EC_GROUP_get_point_conversion_form); 469 470 size_t 471 EC_GROUP_set_seed(EC_GROUP *group, const unsigned char *seed, size_t len) 472 { 473 free(group->seed); 474 group->seed = NULL; 475 group->seed_len = 0; 476 477 if (seed == NULL || len == 0) 478 return 1; 479 480 if ((group->seed = malloc(len)) == NULL) 481 return 0; 482 memcpy(group->seed, seed, len); 483 group->seed_len = len; 484 485 return len; 486 } 487 LCRYPTO_ALIAS(EC_GROUP_set_seed); 488 489 unsigned char * 490 EC_GROUP_get0_seed(const EC_GROUP *group) 491 { 492 return group->seed; 493 } 494 LCRYPTO_ALIAS(EC_GROUP_get0_seed); 495 496 size_t 497 EC_GROUP_get_seed_len(const EC_GROUP *group) 498 { 499 return group->seed_len; 500 } 501 LCRYPTO_ALIAS(EC_GROUP_get_seed_len); 502 503 int 504 EC_GROUP_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, 505 const BIGNUM *b, BN_CTX *ctx_in) 506 { 507 BN_CTX *ctx; 508 int ret = 0; 509 510 if ((ctx = ctx_in) == NULL) 511 ctx = BN_CTX_new(); 512 if (ctx == NULL) 513 goto err; 514 515 if (group->meth->group_set_curve == NULL) { 516 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 517 goto err; 518 } 519 ret = group->meth->group_set_curve(group, p, a, b, ctx); 520 521 err: 522 if (ctx != ctx_in) 523 BN_CTX_free(ctx); 524 525 return ret; 526 } 527 LCRYPTO_ALIAS(EC_GROUP_set_curve); 528 529 int 530 EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, 531 BN_CTX *ctx_in) 532 { 533 BN_CTX *ctx; 534 int ret = 0; 535 536 if ((ctx = ctx_in) == NULL) 537 ctx = BN_CTX_new(); 538 if (ctx == NULL) 539 goto err; 540 541 if (group->meth->group_get_curve == NULL) { 542 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 543 goto err; 544 } 545 ret = group->meth->group_get_curve(group, p, a, b, ctx); 546 547 err: 548 if (ctx != ctx_in) 549 BN_CTX_free(ctx); 550 551 return ret; 552 } 553 LCRYPTO_ALIAS(EC_GROUP_get_curve); 554 555 int 556 EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, 557 const BIGNUM *b, BN_CTX *ctx) 558 { 559 return EC_GROUP_set_curve(group, p, a, b, ctx); 560 } 561 LCRYPTO_ALIAS(EC_GROUP_set_curve_GFp); 562 563 int 564 EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, 565 BN_CTX *ctx) 566 { 567 return EC_GROUP_get_curve(group, p, a, b, ctx); 568 } 569 LCRYPTO_ALIAS(EC_GROUP_get_curve_GFp); 570 571 EC_GROUP * 572 EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, 573 BN_CTX *ctx) 574 { 575 EC_GROUP *group; 576 577 if ((group = EC_GROUP_new(EC_GFp_mont_method())) == NULL) 578 goto err; 579 580 if (!EC_GROUP_set_curve(group, p, a, b, ctx)) 581 goto err; 582 583 return group; 584 585 err: 586 EC_GROUP_free(group); 587 588 return NULL; 589 } 590 LCRYPTO_ALIAS(EC_GROUP_new_curve_GFp); 591 592 int 593 EC_GROUP_get_degree(const EC_GROUP *group) 594 { 595 return BN_num_bits(group->p); 596 } 597 LCRYPTO_ALIAS(EC_GROUP_get_degree); 598 599 int 600 EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx_in) 601 { 602 BN_CTX *ctx; 603 BIGNUM *p, *a, *b, *discriminant; 604 int ret = 0; 605 606 if ((ctx = ctx_in) == NULL) 607 ctx = BN_CTX_new(); 608 if (ctx == NULL) 609 goto err; 610 611 BN_CTX_start(ctx); 612 613 if ((p = BN_CTX_get(ctx)) == NULL) 614 goto err; 615 if ((a = BN_CTX_get(ctx)) == NULL) 616 goto err; 617 if ((b = BN_CTX_get(ctx)) == NULL) 618 goto err; 619 if ((discriminant = BN_CTX_get(ctx)) == NULL) 620 goto err; 621 622 if (!EC_GROUP_get_curve(group, p, a, b, ctx)) 623 goto err; 624 625 /* 626 * Check that the discriminant 4a^3 + 27b^2 is non-zero modulo p 627 * assuming that p > 3 is prime and that a and b are in [0, p). 628 */ 629 630 if (BN_is_zero(a) && BN_is_zero(b)) 631 goto err; 632 if (BN_is_zero(a) || BN_is_zero(b)) 633 goto done; 634 635 /* Compute the discriminant: first 4a^3, then 27b^2, then their sum. */ 636 if (!BN_mod_sqr(discriminant, a, p, ctx)) 637 goto err; 638 if (!BN_mod_mul(discriminant, discriminant, a, p, ctx)) 639 goto err; 640 if (!BN_lshift(discriminant, discriminant, 2)) 641 goto err; 642 643 if (!BN_mod_sqr(b, b, p, ctx)) 644 goto err; 645 if (!BN_mul_word(b, 27)) 646 goto err; 647 648 if (!BN_mod_add(discriminant, discriminant, b, p, ctx)) 649 goto err; 650 651 if (BN_is_zero(discriminant)) 652 goto err; 653 654 done: 655 ret = 1; 656 657 err: 658 if (ctx != ctx_in) 659 BN_CTX_free(ctx); 660 661 return ret; 662 } 663 LCRYPTO_ALIAS(EC_GROUP_check_discriminant); 664 665 int 666 EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx_in) 667 { 668 BN_CTX *ctx; 669 EC_POINT *point = NULL; 670 const BIGNUM *order; 671 int ret = 0; 672 673 if ((ctx = ctx_in) == NULL) 674 ctx = BN_CTX_new(); 675 if (ctx == NULL) 676 goto err; 677 678 if (!EC_GROUP_check_discriminant(group, ctx)) { 679 ECerror(EC_R_DISCRIMINANT_IS_ZERO); 680 goto err; 681 } 682 683 if (group->generator == NULL) { 684 ECerror(EC_R_UNDEFINED_GENERATOR); 685 goto err; 686 } 687 if (EC_POINT_is_on_curve(group, group->generator, ctx) <= 0) { 688 ECerror(EC_R_POINT_IS_NOT_ON_CURVE); 689 goto err; 690 } 691 692 if ((point = EC_POINT_new(group)) == NULL) 693 goto err; 694 if ((order = EC_GROUP_get0_order(group)) == NULL) 695 goto err; 696 if (BN_is_zero(order)) { 697 ECerror(EC_R_UNDEFINED_ORDER); 698 goto err; 699 } 700 if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx)) 701 goto err; 702 if (!EC_POINT_is_at_infinity(group, point)) { 703 ECerror(EC_R_INVALID_GROUP_ORDER); 704 goto err; 705 } 706 707 ret = 1; 708 709 err: 710 if (ctx != ctx_in) 711 BN_CTX_free(ctx); 712 713 EC_POINT_free(point); 714 715 return ret; 716 } 717 LCRYPTO_ALIAS(EC_GROUP_check); 718 719 /* 720 * Returns -1 on error, 0 if the groups are equal, 1 if they are distinct. 721 */ 722 int 723 EC_GROUP_cmp(const EC_GROUP *group1, const EC_GROUP *group2, BN_CTX *ctx_in) 724 { 725 BN_CTX *ctx = NULL; 726 BIGNUM *p1, *a1, *b1, *p2, *a2, *b2; 727 const EC_POINT *generator1, *generator2; 728 const BIGNUM *order1, *order2, *cofactor1, *cofactor2; 729 int nid1, nid2; 730 int cmp = 1; 731 int ret = -1; 732 733 if ((ctx = ctx_in) == NULL) 734 ctx = BN_CTX_new(); 735 if (ctx == NULL) 736 goto err; 737 738 BN_CTX_start(ctx); 739 740 if (ec_group_get_field_type(group1) != ec_group_get_field_type(group2)) 741 goto distinct; 742 if ((nid1 = EC_GROUP_get_curve_name(group1)) != NID_undef && 743 (nid2 = EC_GROUP_get_curve_name(group2)) != NID_undef) { 744 if (nid1 != nid2) 745 goto distinct; 746 } 747 748 if ((p1 = BN_CTX_get(ctx)) == NULL) 749 goto err; 750 if ((a1 = BN_CTX_get(ctx)) == NULL) 751 goto err; 752 if ((b1 = BN_CTX_get(ctx)) == NULL) 753 goto err; 754 if ((p2 = BN_CTX_get(ctx)) == NULL) 755 goto err; 756 if ((a2 = BN_CTX_get(ctx)) == NULL) 757 goto err; 758 if ((b2 = BN_CTX_get(ctx)) == NULL) 759 goto err; 760 761 /* 762 * If we ever support curves in non-Weierstrass form, this check needs 763 * to be adjusted. The comparison of the generators will fail anyway. 764 */ 765 if (!EC_GROUP_get_curve(group1, p1, a1, b1, ctx)) 766 goto err; 767 if (!EC_GROUP_get_curve(group2, p2, a2, b2, ctx)) 768 goto err; 769 770 if (BN_cmp(p1, p2) != 0 || BN_cmp(a1, a2) != 0 || BN_cmp(b1, b2) != 0) 771 goto distinct; 772 773 if ((generator1 = EC_GROUP_get0_generator(group1)) == NULL) 774 goto err; 775 if ((generator2 = EC_GROUP_get0_generator(group2)) == NULL) 776 goto err; 777 778 /* 779 * It does not matter whether group1 or group2 is used: both points must 780 * have a matching method for this to succeed. 781 */ 782 if ((cmp = EC_POINT_cmp(group1, generator1, generator2, ctx)) < 0) 783 goto err; 784 if (cmp == 1) 785 goto distinct; 786 cmp = 1; 787 788 if ((order1 = EC_GROUP_get0_order(group1)) == NULL) 789 goto err; 790 if ((order2 = EC_GROUP_get0_order(group2)) == NULL) 791 goto err; 792 793 if ((cofactor1 = EC_GROUP_get0_cofactor(group1)) == NULL) 794 goto err; 795 if ((cofactor2 = EC_GROUP_get0_cofactor(group2)) == NULL) 796 goto err; 797 798 if (BN_cmp(order1, order2) != 0 || BN_cmp(cofactor1, cofactor2) != 0) 799 goto distinct; 800 801 /* All parameters match: the groups are equal. */ 802 cmp = 0; 803 804 distinct: 805 ret = cmp; 806 807 err: 808 BN_CTX_end(ctx); 809 810 if (ctx != ctx_in) 811 BN_CTX_free(ctx); 812 813 return ret; 814 } 815 LCRYPTO_ALIAS(EC_GROUP_cmp); 816 817 EC_POINT * 818 EC_POINT_new(const EC_GROUP *group) 819 { 820 EC_POINT *point = NULL; 821 822 if (group == NULL) { 823 ECerror(ERR_R_PASSED_NULL_PARAMETER); 824 goto err; 825 } 826 827 if ((point = calloc(1, sizeof(*point))) == NULL) { 828 ECerror(ERR_R_MALLOC_FAILURE); 829 goto err; 830 } 831 832 if ((point->X = BN_new()) == NULL) 833 goto err; 834 if ((point->Y = BN_new()) == NULL) 835 goto err; 836 if ((point->Z = BN_new()) == NULL) 837 goto err; 838 839 point->meth = group->meth; 840 841 return point; 842 843 err: 844 EC_POINT_free(point); 845 846 return NULL; 847 } 848 LCRYPTO_ALIAS(EC_POINT_new); 849 850 void 851 EC_POINT_free(EC_POINT *point) 852 { 853 if (point == NULL) 854 return; 855 856 BN_free(point->X); 857 BN_free(point->Y); 858 BN_free(point->Z); 859 860 freezero(point, sizeof *point); 861 } 862 LCRYPTO_ALIAS(EC_POINT_free); 863 864 void 865 EC_POINT_clear_free(EC_POINT *point) 866 { 867 EC_POINT_free(point); 868 } 869 LCRYPTO_ALIAS(EC_POINT_clear_free); 870 871 int 872 EC_POINT_copy(EC_POINT *dst, const EC_POINT *src) 873 { 874 if (dst->meth != src->meth) { 875 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 876 return 0; 877 } 878 if (dst == src) 879 return 1; 880 881 if (!bn_copy(dst->X, src->X)) 882 return 0; 883 if (!bn_copy(dst->Y, src->Y)) 884 return 0; 885 if (!bn_copy(dst->Z, src->Z)) 886 return 0; 887 dst->Z_is_one = src->Z_is_one; 888 889 return 1; 890 } 891 LCRYPTO_ALIAS(EC_POINT_copy); 892 893 EC_POINT * 894 EC_POINT_dup(const EC_POINT *in_point, const EC_GROUP *group) 895 { 896 EC_POINT *point = NULL; 897 898 if (in_point == NULL) 899 goto err; 900 901 if ((point = EC_POINT_new(group)) == NULL) 902 goto err; 903 904 if (!EC_POINT_copy(point, in_point)) 905 goto err; 906 907 return point; 908 909 err: 910 EC_POINT_free(point); 911 912 return NULL; 913 } 914 LCRYPTO_ALIAS(EC_POINT_dup); 915 916 const EC_METHOD * 917 EC_POINT_method_of(const EC_POINT *point) 918 { 919 return point->meth; 920 } 921 LCRYPTO_ALIAS(EC_POINT_method_of); 922 923 int 924 EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) 925 { 926 if (group->meth != point->meth) { 927 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 928 return 0; 929 } 930 931 BN_zero(point->Z); 932 point->Z_is_one = 0; 933 934 return 1; 935 } 936 LCRYPTO_ALIAS(EC_POINT_set_to_infinity); 937 938 int 939 EC_POINT_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point, 940 const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx_in) 941 { 942 BN_CTX *ctx; 943 int ret = 0; 944 945 if ((ctx = ctx_in) == NULL) 946 ctx = BN_CTX_new(); 947 if (ctx == NULL) 948 goto err; 949 950 if (group->meth->point_set_affine_coordinates == NULL) { 951 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 952 goto err; 953 } 954 if (group->meth != point->meth) { 955 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 956 goto err; 957 } 958 if (!group->meth->point_set_affine_coordinates(group, point, x, y, ctx)) 959 goto err; 960 961 if (EC_POINT_is_on_curve(group, point, ctx) <= 0) { 962 ECerror(EC_R_POINT_IS_NOT_ON_CURVE); 963 goto err; 964 } 965 966 ret = 1; 967 968 err: 969 if (ctx != ctx_in) 970 BN_CTX_free(ctx); 971 972 return ret; 973 } 974 LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates); 975 976 int 977 EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 978 const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) 979 { 980 return EC_POINT_set_affine_coordinates(group, point, x, y, ctx); 981 } 982 LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates_GFp); 983 984 int 985 EC_POINT_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, 986 BIGNUM *x, BIGNUM *y, BN_CTX *ctx_in) 987 { 988 BN_CTX *ctx = NULL; 989 int ret = 0; 990 991 if (EC_POINT_is_at_infinity(group, point) > 0) { 992 ECerror(EC_R_POINT_AT_INFINITY); 993 goto err; 994 } 995 996 if ((ctx = ctx_in) == NULL) 997 ctx = BN_CTX_new(); 998 if (ctx == NULL) 999 goto err; 1000 1001 if (group->meth->point_get_affine_coordinates == NULL) { 1002 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1003 goto err; 1004 } 1005 if (group->meth != point->meth) { 1006 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1007 goto err; 1008 } 1009 ret = group->meth->point_get_affine_coordinates(group, point, x, y, ctx); 1010 1011 err: 1012 if (ctx != ctx_in) 1013 BN_CTX_free(ctx); 1014 1015 return ret; 1016 } 1017 LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates); 1018 1019 int 1020 EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, 1021 BIGNUM *x, BIGNUM *y, BN_CTX *ctx) 1022 { 1023 return EC_POINT_get_affine_coordinates(group, point, x, y, ctx); 1024 } 1025 LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates_GFp); 1026 1027 int 1028 EC_POINT_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, 1029 const BIGNUM *in_x, int y_bit, BN_CTX *ctx_in) 1030 { 1031 BIGNUM *p, *a, *b, *w, *x, *y; 1032 BN_CTX *ctx; 1033 int ret = 0; 1034 1035 if ((ctx = ctx_in) == NULL) 1036 ctx = BN_CTX_new(); 1037 if (ctx == NULL) 1038 goto err; 1039 1040 y_bit = (y_bit != 0); 1041 1042 BN_CTX_start(ctx); 1043 1044 if ((p = BN_CTX_get(ctx)) == NULL) 1045 goto err; 1046 if ((a = BN_CTX_get(ctx)) == NULL) 1047 goto err; 1048 if ((b = BN_CTX_get(ctx)) == NULL) 1049 goto err; 1050 if ((w = BN_CTX_get(ctx)) == NULL) 1051 goto err; 1052 if ((x = BN_CTX_get(ctx)) == NULL) 1053 goto err; 1054 if ((y = BN_CTX_get(ctx)) == NULL) 1055 goto err; 1056 1057 /* 1058 * Weierstrass equation: y^2 = x^3 + ax + b, so y is one of the 1059 * square roots of x^3 + ax + b. The y-bit indicates which one. 1060 */ 1061 1062 if (!EC_GROUP_get_curve(group, p, a, b, ctx)) 1063 goto err; 1064 1065 /* XXX - should we not insist on 0 <= x < p instead? */ 1066 if (!BN_nnmod(x, in_x, p, ctx)) 1067 goto err; 1068 1069 /* y = x^3 */ 1070 if (!BN_mod_sqr(y, x, p, ctx)) 1071 goto err; 1072 if (!BN_mod_mul(y, y, x, p, ctx)) 1073 goto err; 1074 1075 /* y += ax */ 1076 if (group->a_is_minus3) { 1077 if (!BN_mod_lshift1_quick(w, x, p)) 1078 goto err; 1079 if (!BN_mod_add_quick(w, w, x, p)) 1080 goto err; 1081 if (!BN_mod_sub_quick(y, y, w, p)) 1082 goto err; 1083 } else { 1084 if (!BN_mod_mul(w, a, x, p, ctx)) 1085 goto err; 1086 if (!BN_mod_add_quick(y, y, w, p)) 1087 goto err; 1088 } 1089 1090 /* y += b */ 1091 if (!BN_mod_add_quick(y, y, b, p)) 1092 goto err; 1093 1094 if (!BN_mod_sqrt(y, y, p, ctx)) { 1095 ECerror(EC_R_INVALID_COMPRESSED_POINT); 1096 goto err; 1097 } 1098 1099 if (y_bit == BN_is_odd(y)) 1100 goto done; 1101 1102 if (BN_is_zero(y)) { 1103 ECerror(EC_R_INVALID_COMPRESSION_BIT); 1104 goto err; 1105 } 1106 if (!BN_usub(y, p, y)) 1107 goto err; 1108 1109 if (y_bit != BN_is_odd(y)) { 1110 /* Can only happen if p is even and should not be reachable. */ 1111 ECerror(ERR_R_INTERNAL_ERROR); 1112 goto err; 1113 } 1114 1115 done: 1116 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 1117 goto err; 1118 1119 ret = 1; 1120 1121 err: 1122 BN_CTX_end(ctx); 1123 1124 if (ctx != ctx_in) 1125 BN_CTX_free(ctx); 1126 1127 return ret; 1128 } 1129 LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates); 1130 1131 int 1132 EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 1133 const BIGNUM *x, int y_bit, BN_CTX *ctx) 1134 { 1135 return EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx); 1136 } 1137 LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates_GFp); 1138 1139 int 1140 EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 1141 const EC_POINT *b, BN_CTX *ctx_in) 1142 { 1143 BN_CTX *ctx; 1144 int ret = 0; 1145 1146 if ((ctx = ctx_in) == NULL) 1147 ctx = BN_CTX_new(); 1148 if (ctx == NULL) 1149 goto err; 1150 1151 if (group->meth->add == NULL) { 1152 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1153 goto err; 1154 } 1155 if (group->meth != r->meth || group->meth != a->meth || 1156 group->meth != b->meth) { 1157 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1158 goto err; 1159 } 1160 ret = group->meth->add(group, r, a, b, ctx); 1161 1162 err: 1163 if (ctx != ctx_in) 1164 BN_CTX_free(ctx); 1165 1166 return ret; 1167 } 1168 LCRYPTO_ALIAS(EC_POINT_add); 1169 1170 int 1171 EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 1172 BN_CTX *ctx_in) 1173 { 1174 BN_CTX *ctx; 1175 int ret = 0; 1176 1177 if ((ctx = ctx_in) == NULL) 1178 ctx = BN_CTX_new(); 1179 if (ctx == NULL) 1180 goto err; 1181 1182 if (group->meth->dbl == NULL) { 1183 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1184 goto err; 1185 } 1186 if (group->meth != r->meth || r->meth != a->meth) { 1187 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1188 goto err; 1189 } 1190 ret = group->meth->dbl(group, r, a, ctx); 1191 1192 err: 1193 if (ctx != ctx_in) 1194 BN_CTX_free(ctx); 1195 1196 return ret; 1197 } 1198 LCRYPTO_ALIAS(EC_POINT_dbl); 1199 1200 int 1201 EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx_in) 1202 { 1203 BN_CTX *ctx; 1204 int ret = 0; 1205 1206 if ((ctx = ctx_in) == NULL) 1207 ctx = BN_CTX_new(); 1208 if (ctx == NULL) 1209 goto err; 1210 1211 if (group->meth->invert == NULL) { 1212 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1213 goto err; 1214 } 1215 if (group->meth != a->meth) { 1216 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1217 goto err; 1218 } 1219 ret = group->meth->invert(group, a, ctx); 1220 1221 err: 1222 if (ctx != ctx_in) 1223 BN_CTX_free(ctx); 1224 1225 return ret; 1226 } 1227 LCRYPTO_ALIAS(EC_POINT_invert); 1228 1229 int 1230 EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) 1231 { 1232 if (group->meth != point->meth) { 1233 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1234 return 0; 1235 } 1236 1237 return BN_is_zero(point->Z); 1238 } 1239 LCRYPTO_ALIAS(EC_POINT_is_at_infinity); 1240 1241 int 1242 EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 1243 BN_CTX *ctx_in) 1244 { 1245 BN_CTX *ctx; 1246 int ret = -1; 1247 1248 if ((ctx = ctx_in) == NULL) 1249 ctx = BN_CTX_new(); 1250 if (ctx == NULL) 1251 goto err; 1252 1253 if (group->meth->point_is_on_curve == NULL) { 1254 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1255 goto err; 1256 } 1257 if (group->meth != point->meth) { 1258 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1259 goto err; 1260 } 1261 ret = group->meth->point_is_on_curve(group, point, ctx); 1262 1263 err: 1264 if (ctx != ctx_in) 1265 BN_CTX_free(ctx); 1266 1267 return ret; 1268 } 1269 LCRYPTO_ALIAS(EC_POINT_is_on_curve); 1270 1271 int 1272 EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, 1273 BN_CTX *ctx_in) 1274 { 1275 BN_CTX *ctx; 1276 int ret = -1; 1277 1278 if ((ctx = ctx_in) == NULL) 1279 ctx = BN_CTX_new(); 1280 if (ctx == NULL) 1281 goto err; 1282 1283 if (group->meth->point_cmp == NULL) { 1284 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1285 goto err; 1286 } 1287 if (group->meth != a->meth || a->meth != b->meth) { 1288 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1289 goto err; 1290 } 1291 ret = group->meth->point_cmp(group, a, b, ctx); 1292 1293 err: 1294 if (ctx != ctx_in) 1295 BN_CTX_free(ctx); 1296 1297 return ret; 1298 } 1299 LCRYPTO_ALIAS(EC_POINT_cmp); 1300 1301 int 1302 EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx_in) 1303 { 1304 BN_CTX *ctx; 1305 BIGNUM *x, *y; 1306 int ret = 0; 1307 1308 if ((ctx = ctx_in) == NULL) 1309 ctx = BN_CTX_new(); 1310 if (ctx == NULL) 1311 goto err; 1312 1313 BN_CTX_start(ctx); 1314 1315 if ((x = BN_CTX_get(ctx)) == NULL) 1316 goto err; 1317 if ((y = BN_CTX_get(ctx)) == NULL) 1318 goto err; 1319 1320 if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) 1321 goto err; 1322 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 1323 goto err; 1324 1325 ret = 1; 1326 1327 err: 1328 BN_CTX_end(ctx); 1329 1330 if (ctx != ctx_in) 1331 BN_CTX_free(ctx); 1332 1333 return ret; 1334 } 1335 LCRYPTO_ALIAS(EC_POINT_make_affine); 1336 1337 int 1338 EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, 1339 const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx_in) 1340 { 1341 BN_CTX *ctx; 1342 int ret = 0; 1343 1344 if ((ctx = ctx_in) == NULL) 1345 ctx = BN_CTX_new(); 1346 if (ctx == NULL) 1347 goto err; 1348 1349 if (group->meth->mul_generator_ct == NULL || 1350 group->meth->mul_single_ct == NULL || 1351 group->meth->mul_double_nonct == NULL) { 1352 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1353 goto err; 1354 } 1355 1356 if (g_scalar != NULL && point == NULL && p_scalar == NULL) { 1357 /* 1358 * In this case we want to compute g_scalar * GeneratorPoint: 1359 * this codepath is reached most prominently by (ephemeral) key 1360 * generation of EC cryptosystems (i.e. ECDSA keygen and sign 1361 * setup, ECDH keygen/first half), where the scalar is always 1362 * secret. This is why we ignore if BN_FLG_CONSTTIME is actually 1363 * set and we always call the constant time version. 1364 */ 1365 ret = group->meth->mul_generator_ct(group, r, g_scalar, ctx); 1366 } else if (g_scalar == NULL && point != NULL && p_scalar != NULL) { 1367 /* 1368 * In this case we want to compute p_scalar * GenericPoint: 1369 * this codepath is reached most prominently by the second half 1370 * of ECDH, where the secret scalar is multiplied by the peer's 1371 * public point. To protect the secret scalar, we ignore if 1372 * BN_FLG_CONSTTIME is actually set and we always call the 1373 * constant time version. 1374 */ 1375 ret = group->meth->mul_single_ct(group, r, p_scalar, point, ctx); 1376 } else if (g_scalar != NULL && point != NULL && p_scalar != NULL) { 1377 /* 1378 * In this case we want to compute 1379 * g_scalar * GeneratorPoint + p_scalar * GenericPoint: 1380 * this codepath is reached most prominently by ECDSA signature 1381 * verification. So we call the non-ct version. 1382 */ 1383 ret = group->meth->mul_double_nonct(group, r, g_scalar, 1384 p_scalar, point, ctx); 1385 } else { 1386 /* Anything else is an error. */ 1387 ECerror(ERR_R_EC_LIB); 1388 goto err; 1389 } 1390 1391 err: 1392 if (ctx != ctx_in) 1393 BN_CTX_free(ctx); 1394 1395 return ret; 1396 } 1397 LCRYPTO_ALIAS(EC_POINT_mul); 1398 1399 int 1400 EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx_in) 1401 { 1402 return 1; 1403 } 1404 LCRYPTO_ALIAS(EC_GROUP_precompute_mult); 1405 1406 int 1407 EC_GROUP_have_precompute_mult(const EC_GROUP *group) 1408 { 1409 return 0; 1410 } 1411 LCRYPTO_ALIAS(EC_GROUP_have_precompute_mult); 1412 1413 /* 1414 * XXX - remove everything below in the next bump 1415 */ 1416 1417 int 1418 EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 1419 const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) 1420 { 1421 ECerror(ERR_R_DISABLED); 1422 return 0; 1423 } 1424 LCRYPTO_ALIAS(EC_POINT_set_Jprojective_coordinates_GFp); 1425 1426 int 1427 EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, 1428 const EC_POINT *point, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx) 1429 { 1430 ECerror(ERR_R_DISABLED); 1431 return 0; 1432 } 1433 LCRYPTO_ALIAS(EC_POINT_get_Jprojective_coordinates_GFp); 1434 1435 int 1436 EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], 1437 BN_CTX *ctx_in) 1438 { 1439 ECerror(ERR_R_DISABLED); 1440 return 0; 1441 } 1442 LCRYPTO_ALIAS(EC_POINTs_make_affine); 1443 1444 int 1445 EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, 1446 size_t num, const EC_POINT *points[], const BIGNUM *scalars[], 1447 BN_CTX *ctx_in) 1448 { 1449 ECerror(ERR_R_DISABLED); 1450 return 0; 1451 } 1452 LCRYPTO_ALIAS(EC_POINTs_mul); 1453