1 /* $OpenBSD: ec_lib.c,v 1.116 2025/01/25 13:13:57 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 /* 226 * If there is a user-provided cofactor, sanity check and use it. Otherwise 227 * try computing the cofactor from generator order n and field cardinality p. 228 * This works for all curves of cryptographic interest. 229 * 230 * Hasse's theorem: | h * n - (p + 1) | <= 2 * sqrt(p) 231 * 232 * So: h_min = (p + 1 - 2*sqrt(p)) / n and h_max = (p + 1 + 2*sqrt(p)) / n and 233 * therefore h_max - h_min = 4*sqrt(p) / n. So if n > 4*sqrt(p) holds, there is 234 * only one possible value for h: 235 * 236 * h = \lfloor (h_min + h_max)/2 \rceil = \lfloor (p + 1)/n \rceil 237 * 238 * Otherwise, zero cofactor and return success. 239 */ 240 static int 241 ec_set_cofactor(EC_GROUP *group, const BIGNUM *in_cofactor) 242 { 243 BN_CTX *ctx = NULL; 244 BIGNUM *cofactor; 245 int ret = 0; 246 247 BN_zero(group->cofactor); 248 249 if ((ctx = BN_CTX_new()) == NULL) 250 goto err; 251 252 BN_CTX_start(ctx); 253 if ((cofactor = BN_CTX_get(ctx)) == NULL) 254 goto err; 255 256 /* 257 * Unfortunately, the cofactor is an optional field in many standards. 258 * Internally, the library uses a 0 cofactor as a marker for "unknown 259 * cofactor". So accept in_cofactor == NULL or in_cofactor >= 0. 260 */ 261 if (in_cofactor != NULL && !BN_is_zero(in_cofactor)) { 262 if (BN_is_negative(in_cofactor)) { 263 ECerror(EC_R_UNKNOWN_COFACTOR); 264 goto err; 265 } 266 if (!bn_copy(cofactor, in_cofactor)) 267 goto err; 268 goto done; 269 } 270 271 /* 272 * If the cofactor is too large, we cannot guess it and default to zero. 273 * The RHS of below is a strict overestimate of log(4 * sqrt(p)). 274 */ 275 if (BN_num_bits(group->order) <= (BN_num_bits(group->p) + 1) / 2 + 3) 276 goto done; 277 278 /* 279 * Compute 280 * h = \lfloor (p + 1)/n \rceil = \lfloor (p + 1 + n/2) / n \rfloor. 281 */ 282 283 /* h = n/2 */ 284 if (!BN_rshift1(cofactor, group->order)) 285 goto err; 286 /* h = 1 + n/2 */ 287 if (!BN_add_word(cofactor, 1)) 288 goto err; 289 /* h = p + 1 + n/2 */ 290 if (!BN_add(cofactor, cofactor, group->p)) 291 goto err; 292 /* h = (p + 1 + n/2) / n */ 293 if (!BN_div_ct(cofactor, NULL, cofactor, group->order, ctx)) 294 goto err; 295 296 done: 297 /* Use Hasse's theorem to bound the cofactor. */ 298 if (BN_num_bits(cofactor) > BN_num_bits(group->p) + 1) { 299 ECerror(EC_R_INVALID_GROUP_ORDER); 300 goto err; 301 } 302 303 if (!bn_copy(group->cofactor, cofactor)) 304 goto err; 305 306 ret = 1; 307 308 err: 309 BN_CTX_end(ctx); 310 BN_CTX_free(ctx); 311 312 return ret; 313 } 314 315 int 316 EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, 317 const BIGNUM *order, const BIGNUM *cofactor) 318 { 319 if (generator == NULL) { 320 ECerror(ERR_R_PASSED_NULL_PARAMETER); 321 return 0; 322 } 323 324 /* Require p >= 1. */ 325 if (BN_is_zero(group->p) || BN_is_negative(group->p)) { 326 ECerror(EC_R_INVALID_FIELD); 327 return 0; 328 } 329 330 /* 331 * Require order > 1 and enforce an upper bound of at most one bit more 332 * than the field cardinality due to Hasse's theorem. 333 */ 334 if (order == NULL || BN_cmp(order, BN_value_one()) <= 0 || 335 BN_num_bits(order) > BN_num_bits(group->p) + 1) { 336 ECerror(EC_R_INVALID_GROUP_ORDER); 337 return 0; 338 } 339 340 if (group->generator == NULL) 341 group->generator = EC_POINT_new(group); 342 if (group->generator == NULL) 343 return 0; 344 345 if (!EC_POINT_copy(group->generator, generator)) 346 return 0; 347 348 if (!bn_copy(group->order, order)) 349 return 0; 350 351 if (!ec_set_cofactor(group, cofactor)) 352 return 0; 353 354 return 1; 355 } 356 LCRYPTO_ALIAS(EC_GROUP_set_generator); 357 358 const EC_POINT * 359 EC_GROUP_get0_generator(const EC_GROUP *group) 360 { 361 return group->generator; 362 } 363 LCRYPTO_ALIAS(EC_GROUP_get0_generator); 364 365 int 366 EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) 367 { 368 if (!bn_copy(order, group->order)) 369 return 0; 370 371 return !BN_is_zero(order); 372 } 373 LCRYPTO_ALIAS(EC_GROUP_get_order); 374 375 const BIGNUM * 376 EC_GROUP_get0_order(const EC_GROUP *group) 377 { 378 return group->order; 379 } 380 381 int 382 EC_GROUP_order_bits(const EC_GROUP *group) 383 { 384 return BN_num_bits(group->order); 385 } 386 LCRYPTO_ALIAS(EC_GROUP_order_bits); 387 388 int 389 EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx) 390 { 391 if (!bn_copy(cofactor, group->cofactor)) 392 return 0; 393 394 return !BN_is_zero(group->cofactor); 395 } 396 LCRYPTO_ALIAS(EC_GROUP_get_cofactor); 397 398 const BIGNUM * 399 EC_GROUP_get0_cofactor(const EC_GROUP *group) 400 { 401 return group->cofactor; 402 } 403 404 void 405 EC_GROUP_set_curve_name(EC_GROUP *group, int nid) 406 { 407 group->nid = nid; 408 } 409 LCRYPTO_ALIAS(EC_GROUP_set_curve_name); 410 411 int 412 EC_GROUP_get_curve_name(const EC_GROUP *group) 413 { 414 return group->nid; 415 } 416 LCRYPTO_ALIAS(EC_GROUP_get_curve_name); 417 418 void 419 EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) 420 { 421 group->asn1_flag = flag; 422 } 423 LCRYPTO_ALIAS(EC_GROUP_set_asn1_flag); 424 425 int 426 EC_GROUP_get_asn1_flag(const EC_GROUP *group) 427 { 428 return group->asn1_flag; 429 } 430 LCRYPTO_ALIAS(EC_GROUP_get_asn1_flag); 431 432 void 433 EC_GROUP_set_point_conversion_form(EC_GROUP *group, 434 point_conversion_form_t form) 435 { 436 group->asn1_form = form; 437 } 438 LCRYPTO_ALIAS(EC_GROUP_set_point_conversion_form); 439 440 point_conversion_form_t 441 EC_GROUP_get_point_conversion_form(const EC_GROUP *group) 442 { 443 return group->asn1_form; 444 } 445 LCRYPTO_ALIAS(EC_GROUP_get_point_conversion_form); 446 447 size_t 448 EC_GROUP_set_seed(EC_GROUP *group, const unsigned char *seed, size_t len) 449 { 450 free(group->seed); 451 group->seed = NULL; 452 group->seed_len = 0; 453 454 if (seed == NULL || len == 0) 455 return 1; 456 457 if ((group->seed = malloc(len)) == NULL) 458 return 0; 459 memcpy(group->seed, seed, len); 460 group->seed_len = len; 461 462 return len; 463 } 464 LCRYPTO_ALIAS(EC_GROUP_set_seed); 465 466 unsigned char * 467 EC_GROUP_get0_seed(const EC_GROUP *group) 468 { 469 return group->seed; 470 } 471 LCRYPTO_ALIAS(EC_GROUP_get0_seed); 472 473 size_t 474 EC_GROUP_get_seed_len(const EC_GROUP *group) 475 { 476 return group->seed_len; 477 } 478 LCRYPTO_ALIAS(EC_GROUP_get_seed_len); 479 480 int 481 EC_GROUP_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, 482 const BIGNUM *b, BN_CTX *ctx_in) 483 { 484 BN_CTX *ctx; 485 int ret = 0; 486 487 if ((ctx = ctx_in) == NULL) 488 ctx = BN_CTX_new(); 489 if (ctx == NULL) 490 goto err; 491 492 if (group->meth->group_set_curve == NULL) { 493 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 494 goto err; 495 } 496 ret = group->meth->group_set_curve(group, p, a, b, ctx); 497 498 err: 499 if (ctx != ctx_in) 500 BN_CTX_free(ctx); 501 502 return ret; 503 } 504 LCRYPTO_ALIAS(EC_GROUP_set_curve); 505 506 int 507 EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, 508 BN_CTX *ctx_in) 509 { 510 BN_CTX *ctx; 511 int ret = 0; 512 513 if ((ctx = ctx_in) == NULL) 514 ctx = BN_CTX_new(); 515 if (ctx == NULL) 516 goto err; 517 518 if (group->meth->group_get_curve == NULL) { 519 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 520 goto err; 521 } 522 ret = group->meth->group_get_curve(group, p, a, b, ctx); 523 524 err: 525 if (ctx != ctx_in) 526 BN_CTX_free(ctx); 527 528 return ret; 529 } 530 LCRYPTO_ALIAS(EC_GROUP_get_curve); 531 532 int 533 EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, 534 const BIGNUM *b, BN_CTX *ctx) 535 { 536 return EC_GROUP_set_curve(group, p, a, b, ctx); 537 } 538 LCRYPTO_ALIAS(EC_GROUP_set_curve_GFp); 539 540 int 541 EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, 542 BN_CTX *ctx) 543 { 544 return EC_GROUP_get_curve(group, p, a, b, ctx); 545 } 546 LCRYPTO_ALIAS(EC_GROUP_get_curve_GFp); 547 548 EC_GROUP * 549 EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, 550 BN_CTX *ctx) 551 { 552 EC_GROUP *group; 553 554 if ((group = EC_GROUP_new(EC_GFp_mont_method())) == NULL) 555 goto err; 556 557 if (!EC_GROUP_set_curve(group, p, a, b, ctx)) 558 goto err; 559 560 return group; 561 562 err: 563 EC_GROUP_free(group); 564 565 return NULL; 566 } 567 LCRYPTO_ALIAS(EC_GROUP_new_curve_GFp); 568 569 int 570 EC_GROUP_get_degree(const EC_GROUP *group) 571 { 572 return BN_num_bits(group->p); 573 } 574 LCRYPTO_ALIAS(EC_GROUP_get_degree); 575 576 int 577 EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx_in) 578 { 579 BN_CTX *ctx; 580 BIGNUM *p, *a, *b, *discriminant; 581 int ret = 0; 582 583 if ((ctx = ctx_in) == NULL) 584 ctx = BN_CTX_new(); 585 if (ctx == NULL) 586 goto err; 587 588 BN_CTX_start(ctx); 589 590 if ((p = BN_CTX_get(ctx)) == NULL) 591 goto err; 592 if ((a = BN_CTX_get(ctx)) == NULL) 593 goto err; 594 if ((b = BN_CTX_get(ctx)) == NULL) 595 goto err; 596 if ((discriminant = BN_CTX_get(ctx)) == NULL) 597 goto err; 598 599 if (!EC_GROUP_get_curve(group, p, a, b, ctx)) 600 goto err; 601 602 /* 603 * Check that the discriminant 4a^3 + 27b^2 is non-zero modulo p 604 * assuming that p > 3 is prime and that a and b are in [0, p). 605 */ 606 607 if (BN_is_zero(a) && BN_is_zero(b)) 608 goto err; 609 if (BN_is_zero(a) || BN_is_zero(b)) 610 goto done; 611 612 /* Compute the discriminant: first 4a^3, then 27b^2, then their sum. */ 613 if (!BN_mod_sqr(discriminant, a, p, ctx)) 614 goto err; 615 if (!BN_mod_mul(discriminant, discriminant, a, p, ctx)) 616 goto err; 617 if (!BN_lshift(discriminant, discriminant, 2)) 618 goto err; 619 620 if (!BN_mod_sqr(b, b, p, ctx)) 621 goto err; 622 if (!BN_mul_word(b, 27)) 623 goto err; 624 625 if (!BN_mod_add(discriminant, discriminant, b, p, ctx)) 626 goto err; 627 628 if (BN_is_zero(discriminant)) 629 goto err; 630 631 done: 632 ret = 1; 633 634 err: 635 if (ctx != ctx_in) 636 BN_CTX_free(ctx); 637 638 return ret; 639 } 640 LCRYPTO_ALIAS(EC_GROUP_check_discriminant); 641 642 int 643 EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx_in) 644 { 645 BN_CTX *ctx; 646 EC_POINT *point = NULL; 647 const EC_POINT *generator; 648 const BIGNUM *order; 649 int ret = 0; 650 651 if ((ctx = ctx_in) == NULL) 652 ctx = BN_CTX_new(); 653 if (ctx == NULL) 654 goto err; 655 656 if (!EC_GROUP_check_discriminant(group, ctx)) { 657 ECerror(EC_R_DISCRIMINANT_IS_ZERO); 658 goto err; 659 } 660 661 if ((generator = EC_GROUP_get0_generator(group)) == NULL) { 662 ECerror(EC_R_UNDEFINED_GENERATOR); 663 goto err; 664 } 665 if (EC_POINT_is_on_curve(group, generator, ctx) <= 0) { 666 ECerror(EC_R_POINT_IS_NOT_ON_CURVE); 667 goto err; 668 } 669 670 if ((point = EC_POINT_new(group)) == NULL) 671 goto err; 672 if ((order = EC_GROUP_get0_order(group)) == NULL) 673 goto err; 674 if (BN_is_zero(order)) { 675 ECerror(EC_R_UNDEFINED_ORDER); 676 goto err; 677 } 678 if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx)) 679 goto err; 680 if (!EC_POINT_is_at_infinity(group, point)) { 681 ECerror(EC_R_INVALID_GROUP_ORDER); 682 goto err; 683 } 684 685 ret = 1; 686 687 err: 688 if (ctx != ctx_in) 689 BN_CTX_free(ctx); 690 691 EC_POINT_free(point); 692 693 return ret; 694 } 695 LCRYPTO_ALIAS(EC_GROUP_check); 696 697 /* 698 * Returns -1 on error, 0 if the groups are equal, 1 if they are distinct. 699 */ 700 int 701 EC_GROUP_cmp(const EC_GROUP *group1, const EC_GROUP *group2, BN_CTX *ctx_in) 702 { 703 BN_CTX *ctx = NULL; 704 BIGNUM *p1, *a1, *b1, *p2, *a2, *b2; 705 const EC_POINT *generator1, *generator2; 706 const BIGNUM *order1, *order2, *cofactor1, *cofactor2; 707 int nid1, nid2; 708 int cmp = 1; 709 int ret = -1; 710 711 if ((ctx = ctx_in) == NULL) 712 ctx = BN_CTX_new(); 713 if (ctx == NULL) 714 goto err; 715 716 BN_CTX_start(ctx); 717 718 if ((nid1 = EC_GROUP_get_curve_name(group1)) != NID_undef && 719 (nid2 = EC_GROUP_get_curve_name(group2)) != NID_undef) { 720 if (nid1 != nid2) 721 goto distinct; 722 } 723 724 if ((p1 = BN_CTX_get(ctx)) == NULL) 725 goto err; 726 if ((a1 = BN_CTX_get(ctx)) == NULL) 727 goto err; 728 if ((b1 = BN_CTX_get(ctx)) == NULL) 729 goto err; 730 if ((p2 = BN_CTX_get(ctx)) == NULL) 731 goto err; 732 if ((a2 = BN_CTX_get(ctx)) == NULL) 733 goto err; 734 if ((b2 = BN_CTX_get(ctx)) == NULL) 735 goto err; 736 737 /* 738 * If we ever support curves in non-Weierstrass form, this check needs 739 * to be adjusted. The comparison of the generators will fail anyway. 740 */ 741 if (!EC_GROUP_get_curve(group1, p1, a1, b1, ctx)) 742 goto err; 743 if (!EC_GROUP_get_curve(group2, p2, a2, b2, ctx)) 744 goto err; 745 746 if (BN_cmp(p1, p2) != 0 || BN_cmp(a1, a2) != 0 || BN_cmp(b1, b2) != 0) 747 goto distinct; 748 749 if ((generator1 = EC_GROUP_get0_generator(group1)) == NULL) 750 goto err; 751 if ((generator2 = EC_GROUP_get0_generator(group2)) == NULL) 752 goto err; 753 754 /* 755 * It does not matter whether group1 or group2 is used: both points must 756 * have a matching method for this to succeed. 757 */ 758 if ((cmp = EC_POINT_cmp(group1, generator1, generator2, ctx)) < 0) 759 goto err; 760 if (cmp == 1) 761 goto distinct; 762 cmp = 1; 763 764 if ((order1 = EC_GROUP_get0_order(group1)) == NULL) 765 goto err; 766 if ((order2 = EC_GROUP_get0_order(group2)) == NULL) 767 goto err; 768 769 if ((cofactor1 = EC_GROUP_get0_cofactor(group1)) == NULL) 770 goto err; 771 if ((cofactor2 = EC_GROUP_get0_cofactor(group2)) == NULL) 772 goto err; 773 774 if (BN_cmp(order1, order2) != 0 || BN_cmp(cofactor1, cofactor2) != 0) 775 goto distinct; 776 777 /* All parameters match: the groups are equal. */ 778 cmp = 0; 779 780 distinct: 781 ret = cmp; 782 783 err: 784 BN_CTX_end(ctx); 785 786 if (ctx != ctx_in) 787 BN_CTX_free(ctx); 788 789 return ret; 790 } 791 LCRYPTO_ALIAS(EC_GROUP_cmp); 792 793 EC_POINT * 794 EC_POINT_new(const EC_GROUP *group) 795 { 796 EC_POINT *point = NULL; 797 798 if (group == NULL) { 799 ECerror(ERR_R_PASSED_NULL_PARAMETER); 800 goto err; 801 } 802 803 if ((point = calloc(1, sizeof(*point))) == NULL) { 804 ECerror(ERR_R_MALLOC_FAILURE); 805 goto err; 806 } 807 808 if ((point->X = BN_new()) == NULL) 809 goto err; 810 if ((point->Y = BN_new()) == NULL) 811 goto err; 812 if ((point->Z = BN_new()) == NULL) 813 goto err; 814 815 point->meth = group->meth; 816 817 return point; 818 819 err: 820 EC_POINT_free(point); 821 822 return NULL; 823 } 824 LCRYPTO_ALIAS(EC_POINT_new); 825 826 void 827 EC_POINT_free(EC_POINT *point) 828 { 829 if (point == NULL) 830 return; 831 832 BN_free(point->X); 833 BN_free(point->Y); 834 BN_free(point->Z); 835 836 freezero(point, sizeof *point); 837 } 838 LCRYPTO_ALIAS(EC_POINT_free); 839 840 void 841 EC_POINT_clear_free(EC_POINT *point) 842 { 843 EC_POINT_free(point); 844 } 845 LCRYPTO_ALIAS(EC_POINT_clear_free); 846 847 int 848 EC_POINT_copy(EC_POINT *dst, const EC_POINT *src) 849 { 850 if (dst->meth != src->meth) { 851 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 852 return 0; 853 } 854 if (dst == src) 855 return 1; 856 857 if (!bn_copy(dst->X, src->X)) 858 return 0; 859 if (!bn_copy(dst->Y, src->Y)) 860 return 0; 861 if (!bn_copy(dst->Z, src->Z)) 862 return 0; 863 dst->Z_is_one = src->Z_is_one; 864 865 return 1; 866 } 867 LCRYPTO_ALIAS(EC_POINT_copy); 868 869 EC_POINT * 870 EC_POINT_dup(const EC_POINT *in_point, const EC_GROUP *group) 871 { 872 EC_POINT *point = NULL; 873 874 if (in_point == NULL) 875 goto err; 876 877 if ((point = EC_POINT_new(group)) == NULL) 878 goto err; 879 880 if (!EC_POINT_copy(point, in_point)) 881 goto err; 882 883 return point; 884 885 err: 886 EC_POINT_free(point); 887 888 return NULL; 889 } 890 LCRYPTO_ALIAS(EC_POINT_dup); 891 892 int 893 EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) 894 { 895 if (group->meth != point->meth) { 896 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 897 return 0; 898 } 899 900 BN_zero(point->Z); 901 point->Z_is_one = 0; 902 903 return 1; 904 } 905 LCRYPTO_ALIAS(EC_POINT_set_to_infinity); 906 907 int 908 EC_POINT_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point, 909 const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx_in) 910 { 911 BN_CTX *ctx; 912 int ret = 0; 913 914 if ((ctx = ctx_in) == NULL) 915 ctx = BN_CTX_new(); 916 if (ctx == NULL) 917 goto err; 918 919 if (group->meth->point_set_affine_coordinates == NULL) { 920 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 921 goto err; 922 } 923 if (group->meth != point->meth) { 924 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 925 goto err; 926 } 927 if (!group->meth->point_set_affine_coordinates(group, point, x, y, ctx)) 928 goto err; 929 930 if (EC_POINT_is_on_curve(group, point, ctx) <= 0) { 931 ECerror(EC_R_POINT_IS_NOT_ON_CURVE); 932 goto err; 933 } 934 935 ret = 1; 936 937 err: 938 if (ctx != ctx_in) 939 BN_CTX_free(ctx); 940 941 return ret; 942 } 943 LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates); 944 945 int 946 EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 947 const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) 948 { 949 return EC_POINT_set_affine_coordinates(group, point, x, y, ctx); 950 } 951 LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates_GFp); 952 953 int 954 EC_POINT_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, 955 BIGNUM *x, BIGNUM *y, BN_CTX *ctx_in) 956 { 957 BN_CTX *ctx = NULL; 958 int ret = 0; 959 960 if (EC_POINT_is_at_infinity(group, point) > 0) { 961 ECerror(EC_R_POINT_AT_INFINITY); 962 goto err; 963 } 964 965 if ((ctx = ctx_in) == NULL) 966 ctx = BN_CTX_new(); 967 if (ctx == NULL) 968 goto err; 969 970 if (group->meth->point_get_affine_coordinates == NULL) { 971 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 972 goto err; 973 } 974 if (group->meth != point->meth) { 975 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 976 goto err; 977 } 978 ret = group->meth->point_get_affine_coordinates(group, point, x, y, ctx); 979 980 err: 981 if (ctx != ctx_in) 982 BN_CTX_free(ctx); 983 984 return ret; 985 } 986 LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates); 987 988 int 989 EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point, 990 BIGNUM *x, BIGNUM *y, BN_CTX *ctx) 991 { 992 return EC_POINT_get_affine_coordinates(group, point, x, y, ctx); 993 } 994 LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates_GFp); 995 996 int 997 EC_POINT_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, 998 const BIGNUM *in_x, int y_bit, BN_CTX *ctx_in) 999 { 1000 BIGNUM *p, *a, *b, *w, *x, *y; 1001 BN_CTX *ctx; 1002 int ret = 0; 1003 1004 if ((ctx = ctx_in) == NULL) 1005 ctx = BN_CTX_new(); 1006 if (ctx == NULL) 1007 goto err; 1008 1009 y_bit = (y_bit != 0); 1010 1011 BN_CTX_start(ctx); 1012 1013 if ((p = BN_CTX_get(ctx)) == NULL) 1014 goto err; 1015 if ((a = BN_CTX_get(ctx)) == NULL) 1016 goto err; 1017 if ((b = BN_CTX_get(ctx)) == NULL) 1018 goto err; 1019 if ((w = BN_CTX_get(ctx)) == NULL) 1020 goto err; 1021 if ((x = BN_CTX_get(ctx)) == NULL) 1022 goto err; 1023 if ((y = BN_CTX_get(ctx)) == NULL) 1024 goto err; 1025 1026 /* 1027 * Weierstrass equation: y^2 = x^3 + ax + b, so y is one of the 1028 * square roots of x^3 + ax + b. The y-bit indicates which one. 1029 */ 1030 1031 if (!EC_GROUP_get_curve(group, p, a, b, ctx)) 1032 goto err; 1033 1034 /* XXX - should we not insist on 0 <= x < p instead? */ 1035 if (!BN_nnmod(x, in_x, p, ctx)) 1036 goto err; 1037 1038 /* y = x^3 */ 1039 if (!BN_mod_sqr(y, x, p, ctx)) 1040 goto err; 1041 if (!BN_mod_mul(y, y, x, p, ctx)) 1042 goto err; 1043 1044 /* y += ax */ 1045 if (group->a_is_minus3) { 1046 if (!BN_mod_lshift1_quick(w, x, p)) 1047 goto err; 1048 if (!BN_mod_add_quick(w, w, x, p)) 1049 goto err; 1050 if (!BN_mod_sub_quick(y, y, w, p)) 1051 goto err; 1052 } else { 1053 if (!BN_mod_mul(w, a, x, p, ctx)) 1054 goto err; 1055 if (!BN_mod_add_quick(y, y, w, p)) 1056 goto err; 1057 } 1058 1059 /* y += b */ 1060 if (!BN_mod_add_quick(y, y, b, p)) 1061 goto err; 1062 1063 if (!BN_mod_sqrt(y, y, p, ctx)) { 1064 ECerror(EC_R_INVALID_COMPRESSED_POINT); 1065 goto err; 1066 } 1067 1068 if (y_bit == BN_is_odd(y)) 1069 goto done; 1070 1071 if (BN_is_zero(y)) { 1072 ECerror(EC_R_INVALID_COMPRESSION_BIT); 1073 goto err; 1074 } 1075 if (!BN_usub(y, p, y)) 1076 goto err; 1077 1078 if (y_bit != BN_is_odd(y)) { 1079 /* Can only happen if p is even and should not be reachable. */ 1080 ECerror(ERR_R_INTERNAL_ERROR); 1081 goto err; 1082 } 1083 1084 done: 1085 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 1086 goto err; 1087 1088 ret = 1; 1089 1090 err: 1091 BN_CTX_end(ctx); 1092 1093 if (ctx != ctx_in) 1094 BN_CTX_free(ctx); 1095 1096 return ret; 1097 } 1098 LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates); 1099 1100 int 1101 EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 1102 const BIGNUM *x, int y_bit, BN_CTX *ctx) 1103 { 1104 return EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx); 1105 } 1106 LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates_GFp); 1107 1108 int 1109 EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 1110 const EC_POINT *b, BN_CTX *ctx_in) 1111 { 1112 BN_CTX *ctx; 1113 int ret = 0; 1114 1115 if ((ctx = ctx_in) == NULL) 1116 ctx = BN_CTX_new(); 1117 if (ctx == NULL) 1118 goto err; 1119 1120 if (group->meth->add == NULL) { 1121 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1122 goto err; 1123 } 1124 if (group->meth != r->meth || group->meth != a->meth || 1125 group->meth != b->meth) { 1126 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1127 goto err; 1128 } 1129 ret = group->meth->add(group, r, a, b, ctx); 1130 1131 err: 1132 if (ctx != ctx_in) 1133 BN_CTX_free(ctx); 1134 1135 return ret; 1136 } 1137 LCRYPTO_ALIAS(EC_POINT_add); 1138 1139 int 1140 EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 1141 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->dbl == NULL) { 1152 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1153 goto err; 1154 } 1155 if (group->meth != r->meth || r->meth != a->meth) { 1156 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1157 goto err; 1158 } 1159 ret = group->meth->dbl(group, r, a, ctx); 1160 1161 err: 1162 if (ctx != ctx_in) 1163 BN_CTX_free(ctx); 1164 1165 return ret; 1166 } 1167 LCRYPTO_ALIAS(EC_POINT_dbl); 1168 1169 int 1170 EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx_in) 1171 { 1172 BN_CTX *ctx; 1173 int ret = 0; 1174 1175 if ((ctx = ctx_in) == NULL) 1176 ctx = BN_CTX_new(); 1177 if (ctx == NULL) 1178 goto err; 1179 1180 if (group->meth->invert == NULL) { 1181 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1182 goto err; 1183 } 1184 if (group->meth != a->meth) { 1185 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1186 goto err; 1187 } 1188 ret = group->meth->invert(group, a, ctx); 1189 1190 err: 1191 if (ctx != ctx_in) 1192 BN_CTX_free(ctx); 1193 1194 return ret; 1195 } 1196 LCRYPTO_ALIAS(EC_POINT_invert); 1197 1198 int 1199 EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) 1200 { 1201 if (group->meth != point->meth) { 1202 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1203 return 0; 1204 } 1205 1206 return BN_is_zero(point->Z); 1207 } 1208 LCRYPTO_ALIAS(EC_POINT_is_at_infinity); 1209 1210 int 1211 EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 1212 BN_CTX *ctx_in) 1213 { 1214 BN_CTX *ctx; 1215 int ret = -1; 1216 1217 if ((ctx = ctx_in) == NULL) 1218 ctx = BN_CTX_new(); 1219 if (ctx == NULL) 1220 goto err; 1221 1222 if (group->meth->point_is_on_curve == NULL) { 1223 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1224 goto err; 1225 } 1226 if (group->meth != point->meth) { 1227 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1228 goto err; 1229 } 1230 ret = group->meth->point_is_on_curve(group, point, ctx); 1231 1232 err: 1233 if (ctx != ctx_in) 1234 BN_CTX_free(ctx); 1235 1236 return ret; 1237 } 1238 LCRYPTO_ALIAS(EC_POINT_is_on_curve); 1239 1240 int 1241 EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, 1242 BN_CTX *ctx_in) 1243 { 1244 BN_CTX *ctx; 1245 int ret = -1; 1246 1247 if ((ctx = ctx_in) == NULL) 1248 ctx = BN_CTX_new(); 1249 if (ctx == NULL) 1250 goto err; 1251 1252 if (group->meth->point_cmp == NULL) { 1253 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1254 goto err; 1255 } 1256 if (group->meth != a->meth || a->meth != b->meth) { 1257 ECerror(EC_R_INCOMPATIBLE_OBJECTS); 1258 goto err; 1259 } 1260 ret = group->meth->point_cmp(group, a, b, ctx); 1261 1262 err: 1263 if (ctx != ctx_in) 1264 BN_CTX_free(ctx); 1265 1266 return ret; 1267 } 1268 LCRYPTO_ALIAS(EC_POINT_cmp); 1269 1270 int 1271 EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx_in) 1272 { 1273 BN_CTX *ctx; 1274 BIGNUM *x, *y; 1275 int ret = 0; 1276 1277 if ((ctx = ctx_in) == NULL) 1278 ctx = BN_CTX_new(); 1279 if (ctx == NULL) 1280 goto err; 1281 1282 BN_CTX_start(ctx); 1283 1284 if ((x = BN_CTX_get(ctx)) == NULL) 1285 goto err; 1286 if ((y = BN_CTX_get(ctx)) == NULL) 1287 goto err; 1288 1289 if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) 1290 goto err; 1291 if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 1292 goto err; 1293 1294 ret = 1; 1295 1296 err: 1297 BN_CTX_end(ctx); 1298 1299 if (ctx != ctx_in) 1300 BN_CTX_free(ctx); 1301 1302 return ret; 1303 } 1304 LCRYPTO_ALIAS(EC_POINT_make_affine); 1305 1306 int 1307 EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, 1308 const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx_in) 1309 { 1310 BN_CTX *ctx; 1311 int ret = 0; 1312 1313 if ((ctx = ctx_in) == NULL) 1314 ctx = BN_CTX_new(); 1315 if (ctx == NULL) 1316 goto err; 1317 1318 if (group->meth->mul_single_ct == NULL || 1319 group->meth->mul_double_nonct == NULL) { 1320 ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1321 goto err; 1322 } 1323 1324 if (g_scalar != NULL && point == NULL && p_scalar == NULL) { 1325 /* 1326 * In this case we want to compute g_scalar * GeneratorPoint: 1327 * this codepath is reached most prominently by (ephemeral) key 1328 * generation of EC cryptosystems (i.e. ECDSA keygen and sign 1329 * setup, ECDH keygen/first half), where the scalar is always 1330 * secret. This is why we ignore if BN_FLG_CONSTTIME is actually 1331 * set and we always call the constant time version. 1332 */ 1333 ret = group->meth->mul_single_ct(group, r, g_scalar, 1334 group->generator, ctx); 1335 } else if (g_scalar == NULL && point != NULL && p_scalar != NULL) { 1336 /* 1337 * In this case we want to compute p_scalar * GenericPoint: 1338 * this codepath is reached most prominently by the second half 1339 * of ECDH, where the secret scalar is multiplied by the peer's 1340 * public point. To protect the secret scalar, we ignore if 1341 * BN_FLG_CONSTTIME is actually set and we always call the 1342 * constant time version. 1343 */ 1344 ret = group->meth->mul_single_ct(group, r, p_scalar, point, ctx); 1345 } else if (g_scalar != NULL && point != NULL && p_scalar != NULL) { 1346 /* 1347 * In this case we want to compute 1348 * g_scalar * GeneratorPoint + p_scalar * GenericPoint: 1349 * this codepath is reached most prominently by ECDSA signature 1350 * verification. So we call the non-ct version. 1351 */ 1352 ret = group->meth->mul_double_nonct(group, r, g_scalar, 1353 p_scalar, point, ctx); 1354 } else { 1355 /* Anything else is an error. */ 1356 ECerror(ERR_R_EC_LIB); 1357 goto err; 1358 } 1359 1360 err: 1361 if (ctx != ctx_in) 1362 BN_CTX_free(ctx); 1363 1364 return ret; 1365 } 1366 LCRYPTO_ALIAS(EC_POINT_mul); 1367 1368 /* 1369 * XXX - remove everything below in the next bump 1370 */ 1371 1372 int 1373 EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, 1374 const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) 1375 { 1376 ECerror(ERR_R_DISABLED); 1377 return 0; 1378 } 1379 LCRYPTO_ALIAS(EC_POINT_set_Jprojective_coordinates_GFp); 1380 1381 int 1382 EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, 1383 const EC_POINT *point, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx) 1384 { 1385 ECerror(ERR_R_DISABLED); 1386 return 0; 1387 } 1388 LCRYPTO_ALIAS(EC_POINT_get_Jprojective_coordinates_GFp); 1389 1390 int 1391 EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], 1392 BN_CTX *ctx_in) 1393 { 1394 ECerror(ERR_R_DISABLED); 1395 return 0; 1396 } 1397 LCRYPTO_ALIAS(EC_POINTs_make_affine); 1398 1399 int 1400 EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, 1401 size_t num, const EC_POINT *points[], const BIGNUM *scalars[], 1402 BN_CTX *ctx_in) 1403 { 1404 ECerror(ERR_R_DISABLED); 1405 return 0; 1406 } 1407 LCRYPTO_ALIAS(EC_POINTs_mul); 1408 1409 const EC_METHOD * 1410 EC_GROUP_method_of(const EC_GROUP *group) 1411 { 1412 ECerror(ERR_R_DISABLED); 1413 return NULL; 1414 } 1415 LCRYPTO_ALIAS(EC_GROUP_method_of); 1416 1417 int 1418 EC_METHOD_get_field_type(const EC_METHOD *meth) 1419 { 1420 ECerror(ERR_R_DISABLED); 1421 return NID_undef; 1422 } 1423 LCRYPTO_ALIAS(EC_METHOD_get_field_type); 1424 1425 const EC_METHOD * 1426 EC_POINT_method_of(const EC_POINT *point) 1427 { 1428 ECerror(ERR_R_DISABLED); 1429 return NULL; 1430 } 1431 LCRYPTO_ALIAS(EC_POINT_method_of); 1432 1433 int 1434 EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx_in) 1435 { 1436 ECerror(ERR_R_DISABLED); 1437 return 0; 1438 } 1439 LCRYPTO_ALIAS(EC_GROUP_precompute_mult); 1440 1441 int 1442 EC_GROUP_have_precompute_mult(const EC_GROUP *group) 1443 { 1444 ECerror(ERR_R_DISABLED); 1445 return 0; 1446 } 1447 LCRYPTO_ALIAS(EC_GROUP_have_precompute_mult); 1448