1*6d90e046Stb /* $OpenBSD: ecp_methods.c,v 1.42 2025/01/25 13:15:21 tb Exp $ */ 2cb3e3e66Stb /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> 3cb3e3e66Stb * for the OpenSSL project. 4cb3e3e66Stb * Includes code written by Bodo Moeller for the OpenSSL project. 5cb3e3e66Stb */ 6cb3e3e66Stb /* ==================================================================== 7cb3e3e66Stb * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. 8cb3e3e66Stb * 9cb3e3e66Stb * Redistribution and use in source and binary forms, with or without 10cb3e3e66Stb * modification, are permitted provided that the following conditions 11cb3e3e66Stb * are met: 12cb3e3e66Stb * 13cb3e3e66Stb * 1. Redistributions of source code must retain the above copyright 14cb3e3e66Stb * notice, this list of conditions and the following disclaimer. 15cb3e3e66Stb * 16cb3e3e66Stb * 2. Redistributions in binary form must reproduce the above copyright 17cb3e3e66Stb * notice, this list of conditions and the following disclaimer in 18cb3e3e66Stb * the documentation and/or other materials provided with the 19cb3e3e66Stb * distribution. 20cb3e3e66Stb * 21cb3e3e66Stb * 3. All advertising materials mentioning features or use of this 22cb3e3e66Stb * software must display the following acknowledgment: 23cb3e3e66Stb * "This product includes software developed by the OpenSSL Project 24cb3e3e66Stb * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 25cb3e3e66Stb * 26cb3e3e66Stb * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27cb3e3e66Stb * endorse or promote products derived from this software without 28cb3e3e66Stb * prior written permission. For written permission, please contact 29cb3e3e66Stb * openssl-core@openssl.org. 30cb3e3e66Stb * 31cb3e3e66Stb * 5. Products derived from this software may not be called "OpenSSL" 32cb3e3e66Stb * nor may "OpenSSL" appear in their names without prior written 33cb3e3e66Stb * permission of the OpenSSL Project. 34cb3e3e66Stb * 35cb3e3e66Stb * 6. Redistributions of any form whatsoever must retain the following 36cb3e3e66Stb * acknowledgment: 37cb3e3e66Stb * "This product includes software developed by the OpenSSL Project 38cb3e3e66Stb * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 39cb3e3e66Stb * 40cb3e3e66Stb * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41cb3e3e66Stb * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42cb3e3e66Stb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43cb3e3e66Stb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44cb3e3e66Stb * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45cb3e3e66Stb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46cb3e3e66Stb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47cb3e3e66Stb * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48cb3e3e66Stb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49cb3e3e66Stb * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50cb3e3e66Stb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51cb3e3e66Stb * OF THE POSSIBILITY OF SUCH DAMAGE. 52cb3e3e66Stb * ==================================================================== 53cb3e3e66Stb * 54cb3e3e66Stb * This product includes cryptographic software written by Eric Young 55cb3e3e66Stb * (eay@cryptsoft.com). This product includes software written by Tim 56cb3e3e66Stb * Hudson (tjh@cryptsoft.com). 57cb3e3e66Stb * 58cb3e3e66Stb */ 59cb3e3e66Stb /* ==================================================================== 60cb3e3e66Stb * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 61cb3e3e66Stb * Portions of this software developed by SUN MICROSYSTEMS, INC., 62cb3e3e66Stb * and contributed to the OpenSSL project. 63cb3e3e66Stb */ 64cb3e3e66Stb 65cb3e3e66Stb #include <stdlib.h> 66cb3e3e66Stb 67cb3e3e66Stb #include <openssl/bn.h> 68cb3e3e66Stb #include <openssl/ec.h> 69cb3e3e66Stb #include <openssl/err.h> 70cb3e3e66Stb #include <openssl/objects.h> 71cb3e3e66Stb 72cb3e3e66Stb #include "bn_local.h" 73cb3e3e66Stb #include "ec_local.h" 74cb3e3e66Stb 75cb3e3e66Stb /* 76bd66d9a3Stb * Most method functions in this file are designed to work with non-trivial 77bd66d9a3Stb * representations of field elements if necessary: while standard modular 78bd66d9a3Stb * addition and subtraction are used, the field_mul and field_sqr methods will 79bd66d9a3Stb * be used for multiplication, and field_encode and field_decode (if defined) 80cb3e3e66Stb * will be used for converting between representations. 81cb3e3e66Stb * 82bd66d9a3Stb * The functions ec_points_make_affine() and ec_point_get_affine_coordinates() 833c24ce7eStb * assume that if a non-trivial representation is used, it is a Montgomery 84cb3e3e66Stb * representation (i.e. 'encoding' means multiplying by some factor R). 85cb3e3e66Stb */ 86cb3e3e66Stb 87f6116716Stb static inline int 88f6116716Stb ec_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, 89f6116716Stb BN_CTX *ctx) 90f6116716Stb { 91f6116716Stb return group->meth->field_mul(group, r, a, b, ctx); 92f6116716Stb } 93f6116716Stb 94f6116716Stb static inline int 95f6116716Stb ec_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) 96f6116716Stb { 97f6116716Stb return group->meth->field_sqr(group, r, a, ctx); 98f6116716Stb } 99f6116716Stb 100899705c2Stb static int 101cb3e3e66Stb ec_decode_scalar(const EC_GROUP *group, BIGNUM *bn, const BIGNUM *x, BN_CTX *ctx) 102cb3e3e66Stb { 103cb3e3e66Stb if (bn == NULL) 104cb3e3e66Stb return 1; 105cb3e3e66Stb 106cb3e3e66Stb if (group->meth->field_decode != NULL) 107cb3e3e66Stb return group->meth->field_decode(group, bn, x, ctx); 108cb3e3e66Stb 109cb3e3e66Stb return bn_copy(bn, x); 110cb3e3e66Stb } 111cb3e3e66Stb 112cb3e3e66Stb static int 113cb3e3e66Stb ec_encode_scalar(const EC_GROUP *group, BIGNUM *bn, const BIGNUM *x, BN_CTX *ctx) 114cb3e3e66Stb { 1153c2cb882Stb if (!BN_nnmod(bn, x, group->p, ctx)) 116cb3e3e66Stb return 0; 117cb3e3e66Stb 118cb3e3e66Stb if (group->meth->field_encode != NULL) 119cb3e3e66Stb return group->meth->field_encode(group, bn, bn, ctx); 120cb3e3e66Stb 121cb3e3e66Stb return 1; 122cb3e3e66Stb } 123cb3e3e66Stb 124cb3e3e66Stb static int 125d9a83419Stb ec_group_set_curve(EC_GROUP *group, 126cb3e3e66Stb const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) 127cb3e3e66Stb { 128cb3e3e66Stb BIGNUM *a_plus_3; 129cb3e3e66Stb int ret = 0; 130cb3e3e66Stb 131cb3e3e66Stb /* p must be a prime > 3 */ 132cb3e3e66Stb if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { 133cb3e3e66Stb ECerror(EC_R_INVALID_FIELD); 134cb3e3e66Stb return 0; 135cb3e3e66Stb } 136cb3e3e66Stb 137cb3e3e66Stb BN_CTX_start(ctx); 138cb3e3e66Stb 139cb3e3e66Stb if ((a_plus_3 = BN_CTX_get(ctx)) == NULL) 140cb3e3e66Stb goto err; 141cb3e3e66Stb 1423c2cb882Stb if (!bn_copy(group->p, p)) 143cb3e3e66Stb goto err; 1443c2cb882Stb BN_set_negative(group->p, 0); 145cb3e3e66Stb 1463c2cb882Stb if (!ec_encode_scalar(group, group->a, a, ctx)) 147cb3e3e66Stb goto err; 1483c2cb882Stb if (!ec_encode_scalar(group, group->b, b, ctx)) 149cb3e3e66Stb goto err; 150cb3e3e66Stb 151cb3e3e66Stb if (!BN_set_word(a_plus_3, 3)) 152cb3e3e66Stb goto err; 1533c2cb882Stb if (!BN_mod_add(a_plus_3, a_plus_3, a, group->p, ctx)) 154cb3e3e66Stb goto err; 155cb3e3e66Stb 156cb3e3e66Stb group->a_is_minus3 = BN_is_zero(a_plus_3); 157cb3e3e66Stb 158cb3e3e66Stb ret = 1; 159cb3e3e66Stb 160cb3e3e66Stb err: 161cb3e3e66Stb BN_CTX_end(ctx); 162cb3e3e66Stb 163cb3e3e66Stb return ret; 164cb3e3e66Stb } 165cb3e3e66Stb 166899705c2Stb static int 1673c24ce7eStb ec_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, 1683c24ce7eStb BN_CTX *ctx) 169cb3e3e66Stb { 170cb3e3e66Stb if (p != NULL) { 1713c2cb882Stb if (!bn_copy(p, group->p)) 172cb3e3e66Stb return 0; 173cb3e3e66Stb } 1743c2cb882Stb if (!ec_decode_scalar(group, a, group->a, ctx)) 175cb3e3e66Stb return 0; 1763c2cb882Stb if (!ec_decode_scalar(group, b, group->b, ctx)) 177cb3e3e66Stb return 0; 178cb3e3e66Stb 179cb3e3e66Stb return 1; 180cb3e3e66Stb } 181cb3e3e66Stb 182899705c2Stb static int 1834fb59ff9Stb ec_point_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) 184bbf457e4Stb { 185bbf457e4Stb BIGNUM *rh, *tmp, *Z4, *Z6; 186bbf457e4Stb int ret = -1; 187bbf457e4Stb 188bbf457e4Stb if (EC_POINT_is_at_infinity(group, point)) 189bbf457e4Stb return 1; 190bbf457e4Stb 191bbf457e4Stb BN_CTX_start(ctx); 192bbf457e4Stb 193bbf457e4Stb if ((rh = BN_CTX_get(ctx)) == NULL) 194bbf457e4Stb goto err; 195bbf457e4Stb if ((tmp = BN_CTX_get(ctx)) == NULL) 196bbf457e4Stb goto err; 197bbf457e4Stb if ((Z4 = BN_CTX_get(ctx)) == NULL) 198bbf457e4Stb goto err; 199bbf457e4Stb if ((Z6 = BN_CTX_get(ctx)) == NULL) 200bbf457e4Stb goto err; 201bbf457e4Stb 202bbf457e4Stb /* 2037b995231Stb * The curve is defined by a Weierstrass equation y^2 = x^3 + a*x + b. 2047b995231Stb * The point is given in Jacobian projective coordinates where (X, Y, Z) 2057b995231Stb * represents (x, y) = (X/Z^2, Y/Z^3). Substituting this and multiplying 2067b995231Stb * by Z^6 transforms the above into Y^2 = X^3 + a*X*Z^4 + b*Z^6. 207bbf457e4Stb */ 208bbf457e4Stb 209bbf457e4Stb /* rh := X^2 */ 210f6116716Stb if (!ec_field_sqr(group, rh, point->X, ctx)) 211bbf457e4Stb goto err; 212bbf457e4Stb 213bbf457e4Stb if (!point->Z_is_one) { 214f6116716Stb if (!ec_field_sqr(group, tmp, point->Z, ctx)) 215bbf457e4Stb goto err; 216f6116716Stb if (!ec_field_sqr(group, Z4, tmp, ctx)) 217bbf457e4Stb goto err; 218f6116716Stb if (!ec_field_mul(group, Z6, Z4, tmp, ctx)) 219bbf457e4Stb goto err; 220bbf457e4Stb 221bbf457e4Stb /* rh := (rh + a*Z^4)*X */ 222bbf457e4Stb if (group->a_is_minus3) { 223d6f80948Stb if (!BN_mod_lshift1_quick(tmp, Z4, group->p)) 224bbf457e4Stb goto err; 225d6f80948Stb if (!BN_mod_add_quick(tmp, tmp, Z4, group->p)) 226bbf457e4Stb goto err; 227d6f80948Stb if (!BN_mod_sub_quick(rh, rh, tmp, group->p)) 228bbf457e4Stb goto err; 229f6116716Stb if (!ec_field_mul(group, rh, rh, point->X, ctx)) 230bbf457e4Stb goto err; 231bbf457e4Stb } else { 232f6116716Stb if (!ec_field_mul(group, tmp, Z4, group->a, ctx)) 233bbf457e4Stb goto err; 234d6f80948Stb if (!BN_mod_add_quick(rh, rh, tmp, group->p)) 235bbf457e4Stb goto err; 236f6116716Stb if (!ec_field_mul(group, rh, rh, point->X, ctx)) 237bbf457e4Stb goto err; 238bbf457e4Stb } 239bbf457e4Stb 240bbf457e4Stb /* rh := rh + b*Z^6 */ 241f6116716Stb if (!ec_field_mul(group, tmp, group->b, Z6, ctx)) 242bbf457e4Stb goto err; 243d6f80948Stb if (!BN_mod_add_quick(rh, rh, tmp, group->p)) 244bbf457e4Stb goto err; 245bbf457e4Stb } else { 246bbf457e4Stb /* point->Z_is_one */ 247bbf457e4Stb 248bbf457e4Stb /* rh := (rh + a)*X */ 249d6f80948Stb if (!BN_mod_add_quick(rh, rh, group->a, group->p)) 250bbf457e4Stb goto err; 251f6116716Stb if (!ec_field_mul(group, rh, rh, point->X, ctx)) 252bbf457e4Stb goto err; 253bbf457e4Stb /* rh := rh + b */ 254d6f80948Stb if (!BN_mod_add_quick(rh, rh, group->b, group->p)) 255bbf457e4Stb goto err; 256bbf457e4Stb } 257bbf457e4Stb 258bbf457e4Stb /* 'lh' := Y^2 */ 259f6116716Stb if (!ec_field_sqr(group, tmp, point->Y, ctx)) 260bbf457e4Stb goto err; 261bbf457e4Stb 262bbf457e4Stb ret = (0 == BN_ucmp(tmp, rh)); 263bbf457e4Stb 264bbf457e4Stb err: 265bbf457e4Stb BN_CTX_end(ctx); 266bbf457e4Stb 267bbf457e4Stb return ret; 268bbf457e4Stb } 269bbf457e4Stb 270bbf457e4Stb /* 271bbf457e4Stb * Returns -1 on error, 0 if the points are equal, 1 if the points are distinct. 272bbf457e4Stb */ 273bbf457e4Stb 274bbf457e4Stb static int 2754fb59ff9Stb ec_point_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, 2764fb59ff9Stb BN_CTX *ctx) 277bbf457e4Stb { 278bbf457e4Stb BIGNUM *tmp1, *tmp2, *Za23, *Zb23; 279bbf457e4Stb const BIGNUM *tmp1_, *tmp2_; 280bbf457e4Stb int ret = -1; 281bbf457e4Stb 282bbf457e4Stb if (EC_POINT_is_at_infinity(group, a) && EC_POINT_is_at_infinity(group, b)) 283bbf457e4Stb return 0; 284bbf457e4Stb if (EC_POINT_is_at_infinity(group, a) || EC_POINT_is_at_infinity(group, b)) 285bbf457e4Stb return 1; 286bbf457e4Stb 287bbf457e4Stb if (a->Z_is_one && b->Z_is_one) 288bbf457e4Stb return BN_cmp(a->X, b->X) != 0 || BN_cmp(a->Y, b->Y) != 0; 289bbf457e4Stb 290bbf457e4Stb BN_CTX_start(ctx); 291bbf457e4Stb 292bbf457e4Stb if ((tmp1 = BN_CTX_get(ctx)) == NULL) 293bbf457e4Stb goto end; 294bbf457e4Stb if ((tmp2 = BN_CTX_get(ctx)) == NULL) 295bbf457e4Stb goto end; 296bbf457e4Stb if ((Za23 = BN_CTX_get(ctx)) == NULL) 297bbf457e4Stb goto end; 298bbf457e4Stb if ((Zb23 = BN_CTX_get(ctx)) == NULL) 299bbf457e4Stb goto end; 300bbf457e4Stb 301bbf457e4Stb /* 302c852d338Stb * Decide whether (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), or 303c852d338Stb * equivalently, (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). 304bbf457e4Stb */ 305bbf457e4Stb 306bbf457e4Stb if (!b->Z_is_one) { 307f6116716Stb if (!ec_field_sqr(group, Zb23, b->Z, ctx)) 308bbf457e4Stb goto end; 309f6116716Stb if (!ec_field_mul(group, tmp1, a->X, Zb23, ctx)) 310bbf457e4Stb goto end; 311bbf457e4Stb tmp1_ = tmp1; 312bbf457e4Stb } else 313bbf457e4Stb tmp1_ = a->X; 314bbf457e4Stb if (!a->Z_is_one) { 315f6116716Stb if (!ec_field_sqr(group, Za23, a->Z, ctx)) 316bbf457e4Stb goto end; 317f6116716Stb if (!ec_field_mul(group, tmp2, b->X, Za23, ctx)) 318bbf457e4Stb goto end; 319bbf457e4Stb tmp2_ = tmp2; 320bbf457e4Stb } else 321bbf457e4Stb tmp2_ = b->X; 322bbf457e4Stb 323bbf457e4Stb /* compare X_a*Z_b^2 with X_b*Z_a^2 */ 324bbf457e4Stb if (BN_cmp(tmp1_, tmp2_) != 0) { 325bbf457e4Stb ret = 1; /* points differ */ 326bbf457e4Stb goto end; 327bbf457e4Stb } 328bbf457e4Stb if (!b->Z_is_one) { 329f6116716Stb if (!ec_field_mul(group, Zb23, Zb23, b->Z, ctx)) 330bbf457e4Stb goto end; 331f6116716Stb if (!ec_field_mul(group, tmp1, a->Y, Zb23, ctx)) 332bbf457e4Stb goto end; 333bbf457e4Stb /* tmp1_ = tmp1 */ 334bbf457e4Stb } else 335bbf457e4Stb tmp1_ = a->Y; 336bbf457e4Stb if (!a->Z_is_one) { 337f6116716Stb if (!ec_field_mul(group, Za23, Za23, a->Z, ctx)) 338bbf457e4Stb goto end; 339f6116716Stb if (!ec_field_mul(group, tmp2, b->Y, Za23, ctx)) 340bbf457e4Stb goto end; 341bbf457e4Stb /* tmp2_ = tmp2 */ 342bbf457e4Stb } else 343bbf457e4Stb tmp2_ = b->Y; 344bbf457e4Stb 345bbf457e4Stb /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ 346bbf457e4Stb if (BN_cmp(tmp1_, tmp2_) != 0) { 347bbf457e4Stb ret = 1; /* points differ */ 348bbf457e4Stb goto end; 349bbf457e4Stb } 350bbf457e4Stb /* points are equal */ 351bbf457e4Stb ret = 0; 352bbf457e4Stb 353bbf457e4Stb end: 354bbf457e4Stb BN_CTX_end(ctx); 355bbf457e4Stb 356bbf457e4Stb return ret; 357bbf457e4Stb } 358bbf457e4Stb 359bbf457e4Stb static int 360d9a83419Stb ec_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point, 361cb3e3e66Stb const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) 362cb3e3e66Stb { 363e2762cb6Stb int ret = 0; 364e2762cb6Stb 365cb3e3e66Stb if (x == NULL || y == NULL) { 366cb3e3e66Stb ECerror(ERR_R_PASSED_NULL_PARAMETER); 367e2762cb6Stb goto err; 368cb3e3e66Stb } 369e2762cb6Stb 370e2762cb6Stb if (!ec_encode_scalar(group, point->X, x, ctx)) 371e2762cb6Stb goto err; 372e2762cb6Stb if (!ec_encode_scalar(group, point->Y, y, ctx)) 373e2762cb6Stb goto err; 374e2762cb6Stb if (!ec_encode_scalar(group, point->Z, BN_value_one(), ctx)) 375e2762cb6Stb goto err; 376e2762cb6Stb point->Z_is_one = 1; 377e2762cb6Stb 378e2762cb6Stb ret = 1; 379e2762cb6Stb 380e2762cb6Stb err: 381e2762cb6Stb return ret; 382cb3e3e66Stb } 383cb3e3e66Stb 384899705c2Stb static int 3853c24ce7eStb ec_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, 3863c24ce7eStb BIGNUM *x, BIGNUM *y, BN_CTX *ctx) 387cb3e3e66Stb { 388cb3e3e66Stb BIGNUM *z, *Z, *Z_1, *Z_2, *Z_3; 389cb3e3e66Stb int ret = 0; 390cb3e3e66Stb 391cb3e3e66Stb BN_CTX_start(ctx); 392cb3e3e66Stb 393cb3e3e66Stb if ((z = BN_CTX_get(ctx)) == NULL) 394cb3e3e66Stb goto err; 395cb3e3e66Stb if ((Z = BN_CTX_get(ctx)) == NULL) 396cb3e3e66Stb goto err; 397cb3e3e66Stb if ((Z_1 = BN_CTX_get(ctx)) == NULL) 398cb3e3e66Stb goto err; 399cb3e3e66Stb if ((Z_2 = BN_CTX_get(ctx)) == NULL) 400cb3e3e66Stb goto err; 401cb3e3e66Stb if ((Z_3 = BN_CTX_get(ctx)) == NULL) 402cb3e3e66Stb goto err; 403cb3e3e66Stb 4041cc088a1Sjsing /* 4051cc088a1Sjsing * Convert from Jacobian projective coordinates (X, Y, Z) into 4061cc088a1Sjsing * (X/Z^2, Y/Z^3). 4071cc088a1Sjsing */ 408cb3e3e66Stb 4093c2cb882Stb if (!ec_decode_scalar(group, z, point->Z, ctx)) 410cb3e3e66Stb goto err; 411cb3e3e66Stb 412cb3e3e66Stb if (BN_is_one(z)) { 4133c2cb882Stb if (!ec_decode_scalar(group, x, point->X, ctx)) 414cb3e3e66Stb goto err; 4153c2cb882Stb if (!ec_decode_scalar(group, y, point->Y, ctx)) 416cb3e3e66Stb goto err; 417cb3e3e66Stb goto done; 418cb3e3e66Stb } 419cb3e3e66Stb 4203c2cb882Stb if (BN_mod_inverse_ct(Z_1, z, group->p, ctx) == NULL) { 421cb3e3e66Stb ECerror(ERR_R_BN_LIB); 422cb3e3e66Stb goto err; 423cb3e3e66Stb } 424cb3e3e66Stb if (group->meth->field_encode == NULL) { 425cb3e3e66Stb /* field_sqr works on standard representation */ 426728db599Stb if (!ec_field_sqr(group, Z_2, Z_1, ctx)) 427cb3e3e66Stb goto err; 428cb3e3e66Stb } else { 4293c2cb882Stb if (!BN_mod_sqr(Z_2, Z_1, group->p, ctx)) 430cb3e3e66Stb goto err; 431cb3e3e66Stb } 432cb3e3e66Stb 433cb3e3e66Stb if (x != NULL) { 434cb3e3e66Stb /* 435cb3e3e66Stb * in the Montgomery case, field_mul will cancel out 436cb3e3e66Stb * Montgomery factor in X: 437cb3e3e66Stb */ 438728db599Stb if (!ec_field_mul(group, x, point->X, Z_2, ctx)) 439cb3e3e66Stb goto err; 440cb3e3e66Stb } 441cb3e3e66Stb if (y != NULL) { 442cb3e3e66Stb if (group->meth->field_encode == NULL) { 443cb3e3e66Stb /* field_mul works on standard representation */ 444728db599Stb if (!ec_field_mul(group, Z_3, Z_2, Z_1, ctx)) 445cb3e3e66Stb goto err; 446cb3e3e66Stb } else { 4473c2cb882Stb if (!BN_mod_mul(Z_3, Z_2, Z_1, group->p, ctx)) 448cb3e3e66Stb goto err; 449cb3e3e66Stb } 450cb3e3e66Stb 451cb3e3e66Stb /* 452cb3e3e66Stb * in the Montgomery case, field_mul will cancel out 453cb3e3e66Stb * Montgomery factor in Y: 454cb3e3e66Stb */ 455728db599Stb if (!ec_field_mul(group, y, point->Y, Z_3, ctx)) 456cb3e3e66Stb goto err; 457cb3e3e66Stb } 458cb3e3e66Stb 459cb3e3e66Stb done: 460cb3e3e66Stb ret = 1; 461cb3e3e66Stb 462cb3e3e66Stb err: 463cb3e3e66Stb BN_CTX_end(ctx); 464cb3e3e66Stb 465cb3e3e66Stb return ret; 466cb3e3e66Stb } 467cb3e3e66Stb 468899705c2Stb static int 46944d65b39Stb ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT **points, 47044d65b39Stb BN_CTX *ctx) 47144d65b39Stb { 47244d65b39Stb BIGNUM **prod_Z = NULL; 47344d65b39Stb BIGNUM *one, *tmp, *tmp_Z; 47444d65b39Stb size_t i; 47544d65b39Stb int ret = 0; 47644d65b39Stb 47744d65b39Stb if (num == 0) 47844d65b39Stb return 1; 47944d65b39Stb 48044d65b39Stb BN_CTX_start(ctx); 48144d65b39Stb 48244d65b39Stb if ((one = BN_CTX_get(ctx)) == NULL) 48344d65b39Stb goto err; 48444d65b39Stb if ((tmp = BN_CTX_get(ctx)) == NULL) 48544d65b39Stb goto err; 48644d65b39Stb if ((tmp_Z = BN_CTX_get(ctx)) == NULL) 48744d65b39Stb goto err; 48844d65b39Stb 48944d65b39Stb if (!ec_encode_scalar(group, one, BN_value_one(), ctx)) 49044d65b39Stb goto err; 49144d65b39Stb 49244d65b39Stb if ((prod_Z = calloc(num, sizeof *prod_Z)) == NULL) 49344d65b39Stb goto err; 49444d65b39Stb for (i = 0; i < num; i++) { 49544d65b39Stb if ((prod_Z[i] = BN_CTX_get(ctx)) == NULL) 49644d65b39Stb goto err; 49744d65b39Stb } 49844d65b39Stb 49944d65b39Stb /* 50044d65b39Stb * Set prod_Z[i] to the product of points[0]->Z, ..., points[i]->Z, 50144d65b39Stb * skipping any zero-valued inputs (pretend that they're 1). 50244d65b39Stb */ 50344d65b39Stb 50444d65b39Stb if (!BN_is_zero(points[0]->Z)) { 50544d65b39Stb if (!bn_copy(prod_Z[0], points[0]->Z)) 50644d65b39Stb goto err; 50744d65b39Stb } else { 50844d65b39Stb if (!bn_copy(prod_Z[0], one)) 50944d65b39Stb goto err; 51044d65b39Stb } 51144d65b39Stb 51244d65b39Stb for (i = 1; i < num; i++) { 51344d65b39Stb if (!BN_is_zero(points[i]->Z)) { 514728db599Stb if (!ec_field_mul(group, prod_Z[i], 51544d65b39Stb prod_Z[i - 1], points[i]->Z, ctx)) 51644d65b39Stb goto err; 51744d65b39Stb } else { 51844d65b39Stb if (!bn_copy(prod_Z[i], prod_Z[i - 1])) 51944d65b39Stb goto err; 52044d65b39Stb } 52144d65b39Stb } 52244d65b39Stb 52344d65b39Stb /* 52444d65b39Stb * Now use a single explicit inversion to replace every non-zero 52544d65b39Stb * points[i]->Z by its inverse. 52644d65b39Stb */ 52744d65b39Stb if (!BN_mod_inverse_nonct(tmp, prod_Z[num - 1], group->p, ctx)) { 52844d65b39Stb ECerror(ERR_R_BN_LIB); 52944d65b39Stb goto err; 53044d65b39Stb } 53144d65b39Stb 53244d65b39Stb if (group->meth->field_encode != NULL) { 53344d65b39Stb /* 53444d65b39Stb * In the Montgomery case we just turned R*H (representing H) 53544d65b39Stb * into 1/(R*H), but we need R*(1/H) (representing 1/H); i.e., 53644d65b39Stb * we need to multiply by the Montgomery factor twice. 53744d65b39Stb */ 53844d65b39Stb if (!group->meth->field_encode(group, tmp, tmp, ctx)) 53944d65b39Stb goto err; 54044d65b39Stb if (!group->meth->field_encode(group, tmp, tmp, ctx)) 54144d65b39Stb goto err; 54244d65b39Stb } 54344d65b39Stb 54444d65b39Stb for (i = num - 1; i > 0; i--) { 54544d65b39Stb /* 54644d65b39Stb * Loop invariant: tmp is the product of the inverses of 54744d65b39Stb * points[0]->Z, ..., points[i]->Z (zero-valued inputs skipped). 54844d65b39Stb */ 54944d65b39Stb if (BN_is_zero(points[i]->Z)) 55044d65b39Stb continue; 55144d65b39Stb 55244d65b39Stb /* Set tmp_Z to the inverse of points[i]->Z. */ 553728db599Stb if (!ec_field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) 55444d65b39Stb goto err; 55544d65b39Stb /* Adjust tmp to satisfy loop invariant. */ 556728db599Stb if (!ec_field_mul(group, tmp, tmp, points[i]->Z, ctx)) 55744d65b39Stb goto err; 55844d65b39Stb /* Replace points[i]->Z by its inverse. */ 55944d65b39Stb if (!bn_copy(points[i]->Z, tmp_Z)) 56044d65b39Stb goto err; 56144d65b39Stb } 56244d65b39Stb 56344d65b39Stb if (!BN_is_zero(points[0]->Z)) { 56444d65b39Stb /* Replace points[0]->Z by its inverse. */ 56544d65b39Stb if (!bn_copy(points[0]->Z, tmp)) 56644d65b39Stb goto err; 56744d65b39Stb } 56844d65b39Stb 56944d65b39Stb /* Finally, fix up the X and Y coordinates for all points. */ 57044d65b39Stb for (i = 0; i < num; i++) { 57144d65b39Stb EC_POINT *p = points[i]; 57244d65b39Stb 57344d65b39Stb if (BN_is_zero(p->Z)) 57444d65b39Stb continue; 57544d65b39Stb 57644d65b39Stb /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ 57744d65b39Stb 578728db599Stb if (!ec_field_sqr(group, tmp, p->Z, ctx)) 57944d65b39Stb goto err; 580728db599Stb if (!ec_field_mul(group, p->X, p->X, tmp, ctx)) 58144d65b39Stb goto err; 58244d65b39Stb 583728db599Stb if (!ec_field_mul(group, tmp, tmp, p->Z, ctx)) 58444d65b39Stb goto err; 585728db599Stb if (!ec_field_mul(group, p->Y, p->Y, tmp, ctx)) 58644d65b39Stb goto err; 58744d65b39Stb 58844d65b39Stb if (!bn_copy(p->Z, one)) 58944d65b39Stb goto err; 59044d65b39Stb p->Z_is_one = 1; 59144d65b39Stb } 59244d65b39Stb 59344d65b39Stb ret = 1; 59444d65b39Stb 59544d65b39Stb err: 59644d65b39Stb BN_CTX_end(ctx); 59744d65b39Stb free(prod_Z); 59844d65b39Stb 59944d65b39Stb return ret; 60044d65b39Stb } 60144d65b39Stb 60244d65b39Stb static int 6033c24ce7eStb ec_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, 6043c24ce7eStb BN_CTX *ctx) 605cb3e3e66Stb { 606cb3e3e66Stb BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; 607cb3e3e66Stb int ret = 0; 608cb3e3e66Stb 609cb3e3e66Stb if (a == b) 610cb3e3e66Stb return EC_POINT_dbl(group, r, a, ctx); 611cb3e3e66Stb if (EC_POINT_is_at_infinity(group, a)) 612cb3e3e66Stb return EC_POINT_copy(r, b); 613cb3e3e66Stb if (EC_POINT_is_at_infinity(group, b)) 614cb3e3e66Stb return EC_POINT_copy(r, a); 615cb3e3e66Stb 616cb3e3e66Stb BN_CTX_start(ctx); 617cb3e3e66Stb 618cb3e3e66Stb if ((n0 = BN_CTX_get(ctx)) == NULL) 619cb3e3e66Stb goto end; 620cb3e3e66Stb if ((n1 = BN_CTX_get(ctx)) == NULL) 621cb3e3e66Stb goto end; 622cb3e3e66Stb if ((n2 = BN_CTX_get(ctx)) == NULL) 623cb3e3e66Stb goto end; 624cb3e3e66Stb if ((n3 = BN_CTX_get(ctx)) == NULL) 625cb3e3e66Stb goto end; 626cb3e3e66Stb if ((n4 = BN_CTX_get(ctx)) == NULL) 627cb3e3e66Stb goto end; 628cb3e3e66Stb if ((n5 = BN_CTX_get(ctx)) == NULL) 629cb3e3e66Stb goto end; 630cb3e3e66Stb if ((n6 = BN_CTX_get(ctx)) == NULL) 631cb3e3e66Stb goto end; 632cb3e3e66Stb 633cb3e3e66Stb /* 634cb3e3e66Stb * Note that in this function we must not read components of 'a' or 635cb3e3e66Stb * 'b' once we have written the corresponding components of 'r'. ('r' 636cb3e3e66Stb * might be one of 'a' or 'b'.) 637cb3e3e66Stb */ 638cb3e3e66Stb 639cb3e3e66Stb /* n1, n2 */ 640cb3e3e66Stb if (b->Z_is_one) { 6413c2cb882Stb if (!bn_copy(n1, a->X)) 642cb3e3e66Stb goto end; 6433c2cb882Stb if (!bn_copy(n2, a->Y)) 644cb3e3e66Stb goto end; 645cb3e3e66Stb /* n1 = X_a */ 646cb3e3e66Stb /* n2 = Y_a */ 647cb3e3e66Stb } else { 648f6116716Stb if (!ec_field_sqr(group, n0, b->Z, ctx)) 649cb3e3e66Stb goto end; 650f6116716Stb if (!ec_field_mul(group, n1, a->X, n0, ctx)) 651cb3e3e66Stb goto end; 652cb3e3e66Stb /* n1 = X_a * Z_b^2 */ 653cb3e3e66Stb 654f6116716Stb if (!ec_field_mul(group, n0, n0, b->Z, ctx)) 655cb3e3e66Stb goto end; 656f6116716Stb if (!ec_field_mul(group, n2, a->Y, n0, ctx)) 657cb3e3e66Stb goto end; 658cb3e3e66Stb /* n2 = Y_a * Z_b^3 */ 659cb3e3e66Stb } 660cb3e3e66Stb 661cb3e3e66Stb /* n3, n4 */ 662cb3e3e66Stb if (a->Z_is_one) { 6633c2cb882Stb if (!bn_copy(n3, b->X)) 664cb3e3e66Stb goto end; 6653c2cb882Stb if (!bn_copy(n4, b->Y)) 666cb3e3e66Stb goto end; 667cb3e3e66Stb /* n3 = X_b */ 668cb3e3e66Stb /* n4 = Y_b */ 669cb3e3e66Stb } else { 670f6116716Stb if (!ec_field_sqr(group, n0, a->Z, ctx)) 671cb3e3e66Stb goto end; 672f6116716Stb if (!ec_field_mul(group, n3, b->X, n0, ctx)) 673cb3e3e66Stb goto end; 674cb3e3e66Stb /* n3 = X_b * Z_a^2 */ 675cb3e3e66Stb 676f6116716Stb if (!ec_field_mul(group, n0, n0, a->Z, ctx)) 677cb3e3e66Stb goto end; 678f6116716Stb if (!ec_field_mul(group, n4, b->Y, n0, ctx)) 679cb3e3e66Stb goto end; 680cb3e3e66Stb /* n4 = Y_b * Z_a^3 */ 681cb3e3e66Stb } 682cb3e3e66Stb 683cb3e3e66Stb /* n5, n6 */ 684d6f80948Stb if (!BN_mod_sub_quick(n5, n1, n3, group->p)) 685cb3e3e66Stb goto end; 686d6f80948Stb if (!BN_mod_sub_quick(n6, n2, n4, group->p)) 687cb3e3e66Stb goto end; 688cb3e3e66Stb /* n5 = n1 - n3 */ 689cb3e3e66Stb /* n6 = n2 - n4 */ 690cb3e3e66Stb 691cb3e3e66Stb if (BN_is_zero(n5)) { 692cb3e3e66Stb if (BN_is_zero(n6)) { 693cb3e3e66Stb /* a is the same point as b */ 694cb3e3e66Stb BN_CTX_end(ctx); 695cb3e3e66Stb ret = EC_POINT_dbl(group, r, a, ctx); 696cb3e3e66Stb ctx = NULL; 697cb3e3e66Stb goto end; 698cb3e3e66Stb } else { 699cb3e3e66Stb /* a is the inverse of b */ 7003c2cb882Stb BN_zero(r->Z); 701cb3e3e66Stb r->Z_is_one = 0; 702cb3e3e66Stb ret = 1; 703cb3e3e66Stb goto end; 704cb3e3e66Stb } 705cb3e3e66Stb } 706cb3e3e66Stb /* 'n7', 'n8' */ 707d6f80948Stb if (!BN_mod_add_quick(n1, n1, n3, group->p)) 708cb3e3e66Stb goto end; 709d6f80948Stb if (!BN_mod_add_quick(n2, n2, n4, group->p)) 710cb3e3e66Stb goto end; 711cb3e3e66Stb /* 'n7' = n1 + n3 */ 712cb3e3e66Stb /* 'n8' = n2 + n4 */ 713cb3e3e66Stb 714cb3e3e66Stb /* Z_r */ 715cb3e3e66Stb if (a->Z_is_one && b->Z_is_one) { 7163c2cb882Stb if (!bn_copy(r->Z, n5)) 717cb3e3e66Stb goto end; 718cb3e3e66Stb } else { 719cb3e3e66Stb if (a->Z_is_one) { 7203c2cb882Stb if (!bn_copy(n0, b->Z)) 721cb3e3e66Stb goto end; 722cb3e3e66Stb } else if (b->Z_is_one) { 7233c2cb882Stb if (!bn_copy(n0, a->Z)) 724cb3e3e66Stb goto end; 725cb3e3e66Stb } else { 726f6116716Stb if (!ec_field_mul(group, n0, a->Z, b->Z, ctx)) 727cb3e3e66Stb goto end; 728cb3e3e66Stb } 729f6116716Stb if (!ec_field_mul(group, r->Z, n0, n5, ctx)) 730cb3e3e66Stb goto end; 731cb3e3e66Stb } 732cb3e3e66Stb r->Z_is_one = 0; 733cb3e3e66Stb /* Z_r = Z_a * Z_b * n5 */ 734cb3e3e66Stb 735cb3e3e66Stb /* X_r */ 736f6116716Stb if (!ec_field_sqr(group, n0, n6, ctx)) 737cb3e3e66Stb goto end; 738f6116716Stb if (!ec_field_sqr(group, n4, n5, ctx)) 739cb3e3e66Stb goto end; 740f6116716Stb if (!ec_field_mul(group, n3, n1, n4, ctx)) 741cb3e3e66Stb goto end; 742d6f80948Stb if (!BN_mod_sub_quick(r->X, n0, n3, group->p)) 743cb3e3e66Stb goto end; 744cb3e3e66Stb /* X_r = n6^2 - n5^2 * 'n7' */ 745cb3e3e66Stb 746cb3e3e66Stb /* 'n9' */ 747d6f80948Stb if (!BN_mod_lshift1_quick(n0, r->X, group->p)) 748cb3e3e66Stb goto end; 749d6f80948Stb if (!BN_mod_sub_quick(n0, n3, n0, group->p)) 750cb3e3e66Stb goto end; 751cb3e3e66Stb /* n9 = n5^2 * 'n7' - 2 * X_r */ 752cb3e3e66Stb 753cb3e3e66Stb /* Y_r */ 754f6116716Stb if (!ec_field_mul(group, n0, n0, n6, ctx)) 755cb3e3e66Stb goto end; 756f6116716Stb if (!ec_field_mul(group, n5, n4, n5, ctx)) 757cb3e3e66Stb goto end; /* now n5 is n5^3 */ 758f6116716Stb if (!ec_field_mul(group, n1, n2, n5, ctx)) 759cb3e3e66Stb goto end; 760d6f80948Stb if (!BN_mod_sub_quick(n0, n0, n1, group->p)) 761cb3e3e66Stb goto end; 762cb3e3e66Stb if (BN_is_odd(n0)) 763d6f80948Stb if (!BN_add(n0, n0, group->p)) 764cb3e3e66Stb goto end; 765cb3e3e66Stb /* now 0 <= n0 < 2*p, and n0 is even */ 7663c2cb882Stb if (!BN_rshift1(r->Y, n0)) 767cb3e3e66Stb goto end; 768cb3e3e66Stb /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ 769cb3e3e66Stb 770cb3e3e66Stb ret = 1; 771cb3e3e66Stb 772cb3e3e66Stb end: 773cb3e3e66Stb BN_CTX_end(ctx); 774cb3e3e66Stb 775cb3e3e66Stb return ret; 776cb3e3e66Stb } 777cb3e3e66Stb 778899705c2Stb static int 779d9a83419Stb ec_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) 780cb3e3e66Stb { 781cb3e3e66Stb BIGNUM *n0, *n1, *n2, *n3; 782cb3e3e66Stb int ret = 0; 783cb3e3e66Stb 784cb3e3e66Stb if (EC_POINT_is_at_infinity(group, a)) 785cb3e3e66Stb return EC_POINT_set_to_infinity(group, r); 786cb3e3e66Stb 787cb3e3e66Stb BN_CTX_start(ctx); 788cb3e3e66Stb 789cb3e3e66Stb if ((n0 = BN_CTX_get(ctx)) == NULL) 790cb3e3e66Stb goto err; 791cb3e3e66Stb if ((n1 = BN_CTX_get(ctx)) == NULL) 792cb3e3e66Stb goto err; 793cb3e3e66Stb if ((n2 = BN_CTX_get(ctx)) == NULL) 794cb3e3e66Stb goto err; 795cb3e3e66Stb if ((n3 = BN_CTX_get(ctx)) == NULL) 796cb3e3e66Stb goto err; 797cb3e3e66Stb 798cb3e3e66Stb /* 799cb3e3e66Stb * Note that in this function we must not read components of 'a' once 800cb3e3e66Stb * we have written the corresponding components of 'r'. ('r' might 801cb3e3e66Stb * the same as 'a'.) 802cb3e3e66Stb */ 803cb3e3e66Stb 804cb3e3e66Stb /* n1 */ 805cb3e3e66Stb if (a->Z_is_one) { 806f6116716Stb if (!ec_field_sqr(group, n0, a->X, ctx)) 807cb3e3e66Stb goto err; 808d6f80948Stb if (!BN_mod_lshift1_quick(n1, n0, group->p)) 809cb3e3e66Stb goto err; 810d6f80948Stb if (!BN_mod_add_quick(n0, n0, n1, group->p)) 811cb3e3e66Stb goto err; 812d6f80948Stb if (!BN_mod_add_quick(n1, n0, group->a, group->p)) 813cb3e3e66Stb goto err; 814cb3e3e66Stb /* n1 = 3 * X_a^2 + a_curve */ 815cb3e3e66Stb } else if (group->a_is_minus3) { 816f6116716Stb if (!ec_field_sqr(group, n1, a->Z, ctx)) 817cb3e3e66Stb goto err; 818d6f80948Stb if (!BN_mod_add_quick(n0, a->X, n1, group->p)) 819cb3e3e66Stb goto err; 820d6f80948Stb if (!BN_mod_sub_quick(n2, a->X, n1, group->p)) 821cb3e3e66Stb goto err; 822f6116716Stb if (!ec_field_mul(group, n1, n0, n2, ctx)) 823cb3e3e66Stb goto err; 824d6f80948Stb if (!BN_mod_lshift1_quick(n0, n1, group->p)) 825cb3e3e66Stb goto err; 826d6f80948Stb if (!BN_mod_add_quick(n1, n0, n1, group->p)) 827cb3e3e66Stb goto err; 828cb3e3e66Stb /* 829cb3e3e66Stb * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) = 3 * X_a^2 - 3 * 830cb3e3e66Stb * Z_a^4 831cb3e3e66Stb */ 832cb3e3e66Stb } else { 833f6116716Stb if (!ec_field_sqr(group, n0, a->X, ctx)) 834cb3e3e66Stb goto err; 835d6f80948Stb if (!BN_mod_lshift1_quick(n1, n0, group->p)) 836cb3e3e66Stb goto err; 837d6f80948Stb if (!BN_mod_add_quick(n0, n0, n1, group->p)) 838cb3e3e66Stb goto err; 839f6116716Stb if (!ec_field_sqr(group, n1, a->Z, ctx)) 840cb3e3e66Stb goto err; 841f6116716Stb if (!ec_field_sqr(group, n1, n1, ctx)) 842cb3e3e66Stb goto err; 843f6116716Stb if (!ec_field_mul(group, n1, n1, group->a, ctx)) 844cb3e3e66Stb goto err; 845d6f80948Stb if (!BN_mod_add_quick(n1, n1, n0, group->p)) 846cb3e3e66Stb goto err; 847cb3e3e66Stb /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ 848cb3e3e66Stb } 849cb3e3e66Stb 850cb3e3e66Stb /* Z_r */ 851cb3e3e66Stb if (a->Z_is_one) { 8523c2cb882Stb if (!bn_copy(n0, a->Y)) 853cb3e3e66Stb goto err; 854cb3e3e66Stb } else { 855f6116716Stb if (!ec_field_mul(group, n0, a->Y, a->Z, ctx)) 856cb3e3e66Stb goto err; 857cb3e3e66Stb } 858d6f80948Stb if (!BN_mod_lshift1_quick(r->Z, n0, group->p)) 859cb3e3e66Stb goto err; 860cb3e3e66Stb r->Z_is_one = 0; 861cb3e3e66Stb /* Z_r = 2 * Y_a * Z_a */ 862cb3e3e66Stb 863cb3e3e66Stb /* n2 */ 864f6116716Stb if (!ec_field_sqr(group, n3, a->Y, ctx)) 865cb3e3e66Stb goto err; 866f6116716Stb if (!ec_field_mul(group, n2, a->X, n3, ctx)) 867cb3e3e66Stb goto err; 868d6f80948Stb if (!BN_mod_lshift_quick(n2, n2, 2, group->p)) 869cb3e3e66Stb goto err; 870cb3e3e66Stb /* n2 = 4 * X_a * Y_a^2 */ 871cb3e3e66Stb 872cb3e3e66Stb /* X_r */ 873d6f80948Stb if (!BN_mod_lshift1_quick(n0, n2, group->p)) 874cb3e3e66Stb goto err; 875f6116716Stb if (!ec_field_sqr(group, r->X, n1, ctx)) 876cb3e3e66Stb goto err; 877d6f80948Stb if (!BN_mod_sub_quick(r->X, r->X, n0, group->p)) 878cb3e3e66Stb goto err; 879cb3e3e66Stb /* X_r = n1^2 - 2 * n2 */ 880cb3e3e66Stb 881cb3e3e66Stb /* n3 */ 882f6116716Stb if (!ec_field_sqr(group, n0, n3, ctx)) 883cb3e3e66Stb goto err; 884d6f80948Stb if (!BN_mod_lshift_quick(n3, n0, 3, group->p)) 885cb3e3e66Stb goto err; 886cb3e3e66Stb /* n3 = 8 * Y_a^4 */ 887cb3e3e66Stb 888cb3e3e66Stb /* Y_r */ 889d6f80948Stb if (!BN_mod_sub_quick(n0, n2, r->X, group->p)) 890cb3e3e66Stb goto err; 891f6116716Stb if (!ec_field_mul(group, n0, n1, n0, ctx)) 892cb3e3e66Stb goto err; 893d6f80948Stb if (!BN_mod_sub_quick(r->Y, n0, n3, group->p)) 894cb3e3e66Stb goto err; 895cb3e3e66Stb /* Y_r = n1 * (n2 - X_r) - n3 */ 896cb3e3e66Stb 897cb3e3e66Stb ret = 1; 898cb3e3e66Stb 899cb3e3e66Stb err: 900cb3e3e66Stb BN_CTX_end(ctx); 901cb3e3e66Stb 902cb3e3e66Stb return ret; 903cb3e3e66Stb } 904cb3e3e66Stb 905899705c2Stb static int 906d9a83419Stb ec_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) 907cb3e3e66Stb { 9083c2cb882Stb if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y)) 909cb3e3e66Stb /* point is its own inverse */ 910cb3e3e66Stb return 1; 911cb3e3e66Stb 9123c2cb882Stb return BN_usub(point->Y, group->p, point->Y); 913cb3e3e66Stb } 914cb3e3e66Stb 915cb3e3e66Stb /* 9161cc088a1Sjsing * Apply randomization of EC point Jacobian projective coordinates: 917cb3e3e66Stb * 918cb3e3e66Stb * (X, Y, Z) = (lambda^2 * X, lambda^3 * Y, lambda * Z) 919cb3e3e66Stb * 9203fd2f05cStb * where lambda is in the interval [1, p). 921cb3e3e66Stb */ 922899705c2Stb static int 923d9a83419Stb ec_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx) 924cb3e3e66Stb { 925cb3e3e66Stb BIGNUM *lambda = NULL; 926cb3e3e66Stb BIGNUM *tmp = NULL; 927cb3e3e66Stb int ret = 0; 928cb3e3e66Stb 929cb3e3e66Stb BN_CTX_start(ctx); 930cb3e3e66Stb if ((lambda = BN_CTX_get(ctx)) == NULL) 931cb3e3e66Stb goto err; 932cb3e3e66Stb if ((tmp = BN_CTX_get(ctx)) == NULL) 933cb3e3e66Stb goto err; 934cb3e3e66Stb 9353fd2f05cStb /* Generate lambda in [1, p). */ 9363c2cb882Stb if (!bn_rand_interval(lambda, 1, group->p)) 937cb3e3e66Stb goto err; 938cb3e3e66Stb 939cb3e3e66Stb if (group->meth->field_encode != NULL && 940cb3e3e66Stb !group->meth->field_encode(group, lambda, lambda, ctx)) 941cb3e3e66Stb goto err; 942cb3e3e66Stb 943cb3e3e66Stb /* Z = lambda * Z */ 944f6116716Stb if (!ec_field_mul(group, p->Z, lambda, p->Z, ctx)) 945cb3e3e66Stb goto err; 946cb3e3e66Stb 947cb3e3e66Stb /* tmp = lambda^2 */ 948728db599Stb if (!ec_field_sqr(group, tmp, lambda, ctx)) 949cb3e3e66Stb goto err; 950cb3e3e66Stb 951cb3e3e66Stb /* X = lambda^2 * X */ 952f6116716Stb if (!ec_field_mul(group, p->X, tmp, p->X, ctx)) 953cb3e3e66Stb goto err; 954cb3e3e66Stb 955cb3e3e66Stb /* tmp = lambda^3 */ 956f6116716Stb if (!ec_field_mul(group, tmp, tmp, lambda, ctx)) 957cb3e3e66Stb goto err; 958cb3e3e66Stb 959cb3e3e66Stb /* Y = lambda^3 * Y */ 960f6116716Stb if (!ec_field_mul(group, p->Y, tmp, p->Y, ctx)) 961cb3e3e66Stb goto err; 962cb3e3e66Stb 963cb3e3e66Stb /* Disable optimized arithmetics after replacing Z by lambda * Z. */ 964cb3e3e66Stb p->Z_is_one = 0; 965cb3e3e66Stb 966cb3e3e66Stb ret = 1; 967cb3e3e66Stb 968cb3e3e66Stb err: 969cb3e3e66Stb BN_CTX_end(ctx); 970cb3e3e66Stb return ret; 971cb3e3e66Stb } 972cb3e3e66Stb 973cb3e3e66Stb #define EC_POINT_BN_set_flags(P, flags) do { \ 9743c2cb882Stb BN_set_flags((P)->X, (flags)); \ 9753c2cb882Stb BN_set_flags((P)->Y, (flags)); \ 9763c2cb882Stb BN_set_flags((P)->Z, (flags)); \ 977cb3e3e66Stb } while(0) 978cb3e3e66Stb 979cb3e3e66Stb #define EC_POINT_CSWAP(c, a, b, w, t) do { \ 9803c2cb882Stb if (!BN_swap_ct(c, (a)->X, (b)->X, w) || \ 9813c2cb882Stb !BN_swap_ct(c, (a)->Y, (b)->Y, w) || \ 9823c2cb882Stb !BN_swap_ct(c, (a)->Z, (b)->Z, w)) \ 983cb3e3e66Stb goto err; \ 984cb3e3e66Stb t = ((a)->Z_is_one ^ (b)->Z_is_one) & (c); \ 985cb3e3e66Stb (a)->Z_is_one ^= (t); \ 986cb3e3e66Stb (b)->Z_is_one ^= (t); \ 987cb3e3e66Stb } while(0) 988cb3e3e66Stb 989cb3e3e66Stb /* 990cb3e3e66Stb * This function computes (in constant time) a point multiplication over the 991cb3e3e66Stb * EC group. 992cb3e3e66Stb * 993cb3e3e66Stb * At a high level, it is Montgomery ladder with conditional swaps. 994cb3e3e66Stb * 995cb3e3e66Stb * It performs either a fixed point multiplication 996cb3e3e66Stb * (scalar * generator) 997cb3e3e66Stb * when point is NULL, or a variable point multiplication 998cb3e3e66Stb * (scalar * point) 999cb3e3e66Stb * when point is not NULL. 1000cb3e3e66Stb * 1001cb3e3e66Stb * scalar should be in the range [0,n) otherwise all constant time bets are off. 1002cb3e3e66Stb * 1003cb3e3e66Stb * NB: This says nothing about EC_POINT_add and EC_POINT_dbl, 1004cb3e3e66Stb * which of course are not constant time themselves. 1005cb3e3e66Stb * 1006cb3e3e66Stb * The product is stored in r. 1007cb3e3e66Stb * 1008cb3e3e66Stb * Returns 1 on success, 0 otherwise. 1009cb3e3e66Stb */ 1010cb3e3e66Stb static int 1011d9a83419Stb ec_mul_ct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, 1012cb3e3e66Stb const EC_POINT *point, BN_CTX *ctx) 1013cb3e3e66Stb { 1014cb3e3e66Stb int i, cardinality_bits, group_top, kbit, pbit, Z_is_one; 1015cb3e3e66Stb EC_POINT *s = NULL; 1016cb3e3e66Stb BIGNUM *k = NULL; 1017cb3e3e66Stb BIGNUM *lambda = NULL; 1018cb3e3e66Stb BIGNUM *cardinality = NULL; 1019cb3e3e66Stb int ret = 0; 1020cb3e3e66Stb 1021cb3e3e66Stb BN_CTX_start(ctx); 1022cb3e3e66Stb 1023c383f79cStb if ((s = EC_POINT_dup(point, group)) == NULL) 1024cb3e3e66Stb goto err; 1025cb3e3e66Stb 1026cb3e3e66Stb EC_POINT_BN_set_flags(s, BN_FLG_CONSTTIME); 1027cb3e3e66Stb 1028cb3e3e66Stb if ((cardinality = BN_CTX_get(ctx)) == NULL) 1029cb3e3e66Stb goto err; 1030cb3e3e66Stb if ((lambda = BN_CTX_get(ctx)) == NULL) 1031cb3e3e66Stb goto err; 1032cb3e3e66Stb if ((k = BN_CTX_get(ctx)) == NULL) 1033cb3e3e66Stb goto err; 10343c2cb882Stb if (!BN_mul(cardinality, group->order, group->cofactor, ctx)) 1035cb3e3e66Stb goto err; 1036cb3e3e66Stb 1037cb3e3e66Stb /* 1038cb3e3e66Stb * Group cardinalities are often on a word boundary. 1039cb3e3e66Stb * So when we pad the scalar, some timing diff might 1040cb3e3e66Stb * pop if it needs to be expanded due to carries. 1041cb3e3e66Stb * So expand ahead of time. 1042cb3e3e66Stb */ 1043cb3e3e66Stb cardinality_bits = BN_num_bits(cardinality); 1044cb3e3e66Stb group_top = cardinality->top; 1045cb3e3e66Stb if (!bn_wexpand(k, group_top + 2) || 1046cb3e3e66Stb !bn_wexpand(lambda, group_top + 2)) 1047cb3e3e66Stb goto err; 1048cb3e3e66Stb 1049cb3e3e66Stb if (!bn_copy(k, scalar)) 1050cb3e3e66Stb goto err; 1051cb3e3e66Stb 1052cb3e3e66Stb BN_set_flags(k, BN_FLG_CONSTTIME); 1053cb3e3e66Stb 1054cb3e3e66Stb if (BN_num_bits(k) > cardinality_bits || BN_is_negative(k)) { 1055cb3e3e66Stb /* 1056cb3e3e66Stb * This is an unusual input, and we don't guarantee 1057cb3e3e66Stb * constant-timeness 1058cb3e3e66Stb */ 1059cb3e3e66Stb if (!BN_nnmod(k, k, cardinality, ctx)) 1060cb3e3e66Stb goto err; 1061cb3e3e66Stb } 1062cb3e3e66Stb 1063cb3e3e66Stb if (!BN_add(lambda, k, cardinality)) 1064cb3e3e66Stb goto err; 1065cb3e3e66Stb BN_set_flags(lambda, BN_FLG_CONSTTIME); 1066cb3e3e66Stb if (!BN_add(k, lambda, cardinality)) 1067cb3e3e66Stb goto err; 1068cb3e3e66Stb /* 1069cb3e3e66Stb * lambda := scalar + cardinality 1070cb3e3e66Stb * k := scalar + 2*cardinality 1071cb3e3e66Stb */ 1072cb3e3e66Stb kbit = BN_is_bit_set(lambda, cardinality_bits); 1073cb3e3e66Stb if (!BN_swap_ct(kbit, k, lambda, group_top + 2)) 1074cb3e3e66Stb goto err; 1075cb3e3e66Stb 10763c2cb882Stb group_top = group->p->top; 10773c2cb882Stb if (!bn_wexpand(s->X, group_top) || 10783c2cb882Stb !bn_wexpand(s->Y, group_top) || 10793c2cb882Stb !bn_wexpand(s->Z, group_top) || 10803c2cb882Stb !bn_wexpand(r->X, group_top) || 10813c2cb882Stb !bn_wexpand(r->Y, group_top) || 10823c2cb882Stb !bn_wexpand(r->Z, group_top)) 1083cb3e3e66Stb goto err; 1084cb3e3e66Stb 1085cb3e3e66Stb /* 1086cb3e3e66Stb * Apply coordinate blinding for EC_POINT if the underlying EC_METHOD 1087cb3e3e66Stb * implements it. 1088cb3e3e66Stb */ 1089a680ff0cSjsing if (!ec_blind_coordinates(group, s, ctx)) 1090cb3e3e66Stb goto err; 1091cb3e3e66Stb 1092cb3e3e66Stb /* top bit is a 1, in a fixed pos */ 1093cb3e3e66Stb if (!EC_POINT_copy(r, s)) 1094cb3e3e66Stb goto err; 1095cb3e3e66Stb 1096cb3e3e66Stb EC_POINT_BN_set_flags(r, BN_FLG_CONSTTIME); 1097cb3e3e66Stb 1098cb3e3e66Stb if (!EC_POINT_dbl(group, s, s, ctx)) 1099cb3e3e66Stb goto err; 1100cb3e3e66Stb 1101cb3e3e66Stb pbit = 0; 1102cb3e3e66Stb 1103cb3e3e66Stb /* 1104cb3e3e66Stb * The ladder step, with branches, is 1105cb3e3e66Stb * 1106cb3e3e66Stb * k[i] == 0: S = add(R, S), R = dbl(R) 1107cb3e3e66Stb * k[i] == 1: R = add(S, R), S = dbl(S) 1108cb3e3e66Stb * 1109cb3e3e66Stb * Swapping R, S conditionally on k[i] leaves you with state 1110cb3e3e66Stb * 1111cb3e3e66Stb * k[i] == 0: T, U = R, S 1112cb3e3e66Stb * k[i] == 1: T, U = S, R 1113cb3e3e66Stb * 1114cb3e3e66Stb * Then perform the ECC ops. 1115cb3e3e66Stb * 1116cb3e3e66Stb * U = add(T, U) 1117cb3e3e66Stb * T = dbl(T) 1118cb3e3e66Stb * 1119cb3e3e66Stb * Which leaves you with state 1120cb3e3e66Stb * 1121cb3e3e66Stb * k[i] == 0: U = add(R, S), T = dbl(R) 1122cb3e3e66Stb * k[i] == 1: U = add(S, R), T = dbl(S) 1123cb3e3e66Stb * 1124cb3e3e66Stb * Swapping T, U conditionally on k[i] leaves you with state 1125cb3e3e66Stb * 1126cb3e3e66Stb * k[i] == 0: R, S = T, U 1127cb3e3e66Stb * k[i] == 1: R, S = U, T 1128cb3e3e66Stb * 1129cb3e3e66Stb * Which leaves you with state 1130cb3e3e66Stb * 1131cb3e3e66Stb * k[i] == 0: S = add(R, S), R = dbl(R) 1132cb3e3e66Stb * k[i] == 1: R = add(S, R), S = dbl(S) 1133cb3e3e66Stb * 1134cb3e3e66Stb * So we get the same logic, but instead of a branch it's a 1135cb3e3e66Stb * conditional swap, followed by ECC ops, then another conditional swap. 1136cb3e3e66Stb * 1137cb3e3e66Stb * Optimization: The end of iteration i and start of i-1 looks like 1138cb3e3e66Stb * 1139cb3e3e66Stb * ... 1140cb3e3e66Stb * CSWAP(k[i], R, S) 1141cb3e3e66Stb * ECC 1142cb3e3e66Stb * CSWAP(k[i], R, S) 1143cb3e3e66Stb * (next iteration) 1144cb3e3e66Stb * CSWAP(k[i-1], R, S) 1145cb3e3e66Stb * ECC 1146cb3e3e66Stb * CSWAP(k[i-1], R, S) 1147cb3e3e66Stb * ... 1148cb3e3e66Stb * 1149cb3e3e66Stb * So instead of two contiguous swaps, you can merge the condition 1150cb3e3e66Stb * bits and do a single swap. 1151cb3e3e66Stb * 1152cb3e3e66Stb * k[i] k[i-1] Outcome 1153cb3e3e66Stb * 0 0 No Swap 1154cb3e3e66Stb * 0 1 Swap 1155cb3e3e66Stb * 1 0 Swap 1156cb3e3e66Stb * 1 1 No Swap 1157cb3e3e66Stb * 1158cb3e3e66Stb * This is XOR. pbit tracks the previous bit of k. 1159cb3e3e66Stb */ 1160cb3e3e66Stb 1161cb3e3e66Stb for (i = cardinality_bits - 1; i >= 0; i--) { 1162cb3e3e66Stb kbit = BN_is_bit_set(k, i) ^ pbit; 1163cb3e3e66Stb EC_POINT_CSWAP(kbit, r, s, group_top, Z_is_one); 1164cb3e3e66Stb if (!EC_POINT_add(group, s, r, s, ctx)) 1165cb3e3e66Stb goto err; 1166cb3e3e66Stb if (!EC_POINT_dbl(group, r, r, ctx)) 1167cb3e3e66Stb goto err; 1168cb3e3e66Stb /* 1169cb3e3e66Stb * pbit logic merges this cswap with that of the 1170cb3e3e66Stb * next iteration 1171cb3e3e66Stb */ 1172cb3e3e66Stb pbit ^= kbit; 1173cb3e3e66Stb } 1174cb3e3e66Stb /* one final cswap to move the right value into r */ 1175cb3e3e66Stb EC_POINT_CSWAP(pbit, r, s, group_top, Z_is_one); 1176cb3e3e66Stb 1177cb3e3e66Stb ret = 1; 1178cb3e3e66Stb 1179cb3e3e66Stb err: 1180cb3e3e66Stb EC_POINT_free(s); 1181cb3e3e66Stb BN_CTX_end(ctx); 1182cb3e3e66Stb 1183cb3e3e66Stb return ret; 1184cb3e3e66Stb } 1185cb3e3e66Stb 1186cb3e3e66Stb #undef EC_POINT_BN_set_flags 1187cb3e3e66Stb #undef EC_POINT_CSWAP 1188cb3e3e66Stb 1189899705c2Stb static int 11903c24ce7eStb ec_mul_single_ct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, 11913c24ce7eStb const EC_POINT *point, BN_CTX *ctx) 1192cb3e3e66Stb { 1193d9a83419Stb return ec_mul_ct(group, r, scalar, point, ctx); 1194cb3e3e66Stb } 1195cb3e3e66Stb 1196899705c2Stb static int 11973c24ce7eStb ec_mul_double_nonct(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, 11983c24ce7eStb const BIGNUM *p_scalar, const EC_POINT *point, BN_CTX *ctx) 1199cb3e3e66Stb { 12009d4c47a8Stb return ec_wnaf_mul(group, r, g_scalar, point, p_scalar, ctx); 1201cb3e3e66Stb } 1202cb3e3e66Stb 1203107480a9Stb static int 1204f6116716Stb ec_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1205f6116716Stb const BIGNUM *b, BN_CTX *ctx) 1206f6116716Stb { 1207f6116716Stb return BN_mod_mul(r, a, b, group->p, ctx); 1208f6116716Stb } 1209f6116716Stb 1210f6116716Stb static int 1211f6116716Stb ec_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) 1212f6116716Stb { 1213f6116716Stb return BN_mod_sqr(r, a, group->p, ctx); 1214f6116716Stb } 1215f6116716Stb 1216f6116716Stb static int 1217d9a83419Stb ec_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, 1218107480a9Stb const BIGNUM *b, BN_CTX *ctx) 1219107480a9Stb { 1220107480a9Stb BN_MONT_CTX *mont = NULL; 1221107480a9Stb int ret = 0; 1222107480a9Stb 1223de420f14Stb BN_MONT_CTX_free(group->mont_ctx); 1224de420f14Stb group->mont_ctx = NULL; 1225107480a9Stb 1226de420f14Stb if ((mont = BN_MONT_CTX_new()) == NULL) 1227107480a9Stb goto err; 1228107480a9Stb if (!BN_MONT_CTX_set(mont, p, ctx)) { 1229107480a9Stb ECerror(ERR_R_BN_LIB); 1230107480a9Stb goto err; 1231107480a9Stb } 1232107480a9Stb group->mont_ctx = mont; 1233107480a9Stb mont = NULL; 1234107480a9Stb 1235de420f14Stb if (!ec_group_set_curve(group, p, a, b, ctx)) { 1236de420f14Stb BN_MONT_CTX_free(group->mont_ctx); 1237de420f14Stb group->mont_ctx = NULL; 1238de420f14Stb goto err; 1239de420f14Stb } 1240de420f14Stb 1241de420f14Stb ret = 1; 1242107480a9Stb 1243107480a9Stb err: 1244107480a9Stb BN_MONT_CTX_free(mont); 1245107480a9Stb 1246107480a9Stb return ret; 1247107480a9Stb } 1248107480a9Stb 1249107480a9Stb static int 1250d9a83419Stb ec_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1251107480a9Stb const BIGNUM *b, BN_CTX *ctx) 1252107480a9Stb { 1253107480a9Stb if (group->mont_ctx == NULL) { 1254107480a9Stb ECerror(EC_R_NOT_INITIALIZED); 1255107480a9Stb return 0; 1256107480a9Stb } 1257107480a9Stb return BN_mod_mul_montgomery(r, a, b, group->mont_ctx, ctx); 1258107480a9Stb } 1259107480a9Stb 1260107480a9Stb static int 1261d9a83419Stb ec_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1262107480a9Stb BN_CTX *ctx) 1263107480a9Stb { 1264107480a9Stb if (group->mont_ctx == NULL) { 1265107480a9Stb ECerror(EC_R_NOT_INITIALIZED); 1266107480a9Stb return 0; 1267107480a9Stb } 1268107480a9Stb return BN_mod_mul_montgomery(r, a, a, group->mont_ctx, ctx); 1269107480a9Stb } 1270107480a9Stb 1271107480a9Stb static int 1272d9a83419Stb ec_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1273107480a9Stb BN_CTX *ctx) 1274107480a9Stb { 1275107480a9Stb if (group->mont_ctx == NULL) { 1276107480a9Stb ECerror(EC_R_NOT_INITIALIZED); 1277107480a9Stb return 0; 1278107480a9Stb } 1279107480a9Stb return BN_to_montgomery(r, a, group->mont_ctx, ctx); 1280107480a9Stb } 1281107480a9Stb 1282107480a9Stb static int 1283d9a83419Stb ec_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1284107480a9Stb BN_CTX *ctx) 1285107480a9Stb { 1286107480a9Stb if (group->mont_ctx == NULL) { 1287107480a9Stb ECerror(EC_R_NOT_INITIALIZED); 1288107480a9Stb return 0; 1289107480a9Stb } 1290107480a9Stb return BN_from_montgomery(r, a, group->mont_ctx, ctx); 1291107480a9Stb } 1292107480a9Stb 1293cb3e3e66Stb static const EC_METHOD ec_GFp_simple_method = { 1294d9a83419Stb .group_set_curve = ec_group_set_curve, 1295d9a83419Stb .group_get_curve = ec_group_get_curve, 12964fb59ff9Stb .point_is_on_curve = ec_point_is_on_curve, 12974fb59ff9Stb .point_cmp = ec_point_cmp, 1298d9a83419Stb .point_set_affine_coordinates = ec_point_set_affine_coordinates, 1299d9a83419Stb .point_get_affine_coordinates = ec_point_get_affine_coordinates, 13009581610fStb .points_make_affine = ec_points_make_affine, 1301d9a83419Stb .add = ec_add, 1302d9a83419Stb .dbl = ec_dbl, 1303d9a83419Stb .invert = ec_invert, 1304d9a83419Stb .mul_single_ct = ec_mul_single_ct, 1305d9a83419Stb .mul_double_nonct = ec_mul_double_nonct, 1306f6116716Stb .field_mul = ec_simple_field_mul, 1307f6116716Stb .field_sqr = ec_simple_field_sqr, 1308cb3e3e66Stb }; 1309cb3e3e66Stb 1310cb3e3e66Stb const EC_METHOD * 1311cb3e3e66Stb EC_GFp_simple_method(void) 1312cb3e3e66Stb { 1313cb3e3e66Stb return &ec_GFp_simple_method; 1314cb3e3e66Stb } 1315cb3e3e66Stb LCRYPTO_ALIAS(EC_GFp_simple_method); 1316107480a9Stb 1317107480a9Stb static const EC_METHOD ec_GFp_mont_method = { 1318d9a83419Stb .group_set_curve = ec_mont_group_set_curve, 1319d9a83419Stb .group_get_curve = ec_group_get_curve, 13204fb59ff9Stb .point_is_on_curve = ec_point_is_on_curve, 13214fb59ff9Stb .point_cmp = ec_point_cmp, 1322d9a83419Stb .point_set_affine_coordinates = ec_point_set_affine_coordinates, 1323d9a83419Stb .point_get_affine_coordinates = ec_point_get_affine_coordinates, 13249581610fStb .points_make_affine = ec_points_make_affine, 1325d9a83419Stb .add = ec_add, 1326d9a83419Stb .dbl = ec_dbl, 1327d9a83419Stb .invert = ec_invert, 1328d9a83419Stb .mul_single_ct = ec_mul_single_ct, 1329d9a83419Stb .mul_double_nonct = ec_mul_double_nonct, 1330d9a83419Stb .field_mul = ec_mont_field_mul, 1331d9a83419Stb .field_sqr = ec_mont_field_sqr, 1332d9a83419Stb .field_encode = ec_mont_field_encode, 1333d9a83419Stb .field_decode = ec_mont_field_decode, 1334107480a9Stb }; 1335107480a9Stb 1336107480a9Stb const EC_METHOD * 1337107480a9Stb EC_GFp_mont_method(void) 1338107480a9Stb { 1339107480a9Stb return &ec_GFp_mont_method; 1340107480a9Stb } 1341107480a9Stb LCRYPTO_ALIAS(EC_GFp_mont_method); 1342