1109998Smarkm/* crypto/ec/ecp_smpl.c */ 2296341Sdelphij/* 3296341Sdelphij * Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> 4296341Sdelphij * for the OpenSSL project. Includes code written by Bodo Moeller for the 5296341Sdelphij * OpenSSL project. 6296341Sdelphij */ 7109998Smarkm/* ==================================================================== 8160814Ssimon * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. 9109998Smarkm * 10109998Smarkm * Redistribution and use in source and binary forms, with or without 11109998Smarkm * modification, are permitted provided that the following conditions 12109998Smarkm * are met: 13109998Smarkm * 14109998Smarkm * 1. Redistributions of source code must retain the above copyright 15296341Sdelphij * notice, this list of conditions and the following disclaimer. 16109998Smarkm * 17109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 18109998Smarkm * notice, this list of conditions and the following disclaimer in 19109998Smarkm * the documentation and/or other materials provided with the 20109998Smarkm * distribution. 21109998Smarkm * 22109998Smarkm * 3. All advertising materials mentioning features or use of this 23109998Smarkm * software must display the following acknowledgment: 24109998Smarkm * "This product includes software developed by the OpenSSL Project 25109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 26109998Smarkm * 27109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 28109998Smarkm * endorse or promote products derived from this software without 29109998Smarkm * prior written permission. For written permission, please contact 30109998Smarkm * openssl-core@openssl.org. 31109998Smarkm * 32109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 33109998Smarkm * nor may "OpenSSL" appear in their names without prior written 34109998Smarkm * permission of the OpenSSL Project. 35109998Smarkm * 36109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 37109998Smarkm * acknowledgment: 38109998Smarkm * "This product includes software developed by the OpenSSL Project 39109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 40109998Smarkm * 41109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 42109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 44109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 45109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 48109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 50109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 51109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 52109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 53109998Smarkm * ==================================================================== 54109998Smarkm * 55109998Smarkm * This product includes cryptographic software written by Eric Young 56109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 57109998Smarkm * Hudson (tjh@cryptsoft.com). 58109998Smarkm * 59109998Smarkm */ 60160814Ssimon/* ==================================================================== 61160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 62160814Ssimon * Portions of this software developed by SUN MICROSYSTEMS, INC., 63160814Ssimon * and contributed to the OpenSSL project. 64160814Ssimon */ 65109998Smarkm 66109998Smarkm#include <openssl/err.h> 67160814Ssimon#include <openssl/symhacks.h> 68109998Smarkm 69238405Sjkim#ifdef OPENSSL_FIPS 70296341Sdelphij# include <openssl/fips.h> 71238405Sjkim#endif 72238405Sjkim 73109998Smarkm#include "ec_lcl.h" 74109998Smarkm 75109998Smarkmconst EC_METHOD *EC_GFp_simple_method(void) 76296341Sdelphij{ 77296341Sdelphij static const EC_METHOD ret = { 78296341Sdelphij EC_FLAGS_DEFAULT_OCT, 79296341Sdelphij NID_X9_62_prime_field, 80296341Sdelphij ec_GFp_simple_group_init, 81296341Sdelphij ec_GFp_simple_group_finish, 82296341Sdelphij ec_GFp_simple_group_clear_finish, 83296341Sdelphij ec_GFp_simple_group_copy, 84296341Sdelphij ec_GFp_simple_group_set_curve, 85296341Sdelphij ec_GFp_simple_group_get_curve, 86296341Sdelphij ec_GFp_simple_group_get_degree, 87296341Sdelphij ec_GFp_simple_group_check_discriminant, 88296341Sdelphij ec_GFp_simple_point_init, 89296341Sdelphij ec_GFp_simple_point_finish, 90296341Sdelphij ec_GFp_simple_point_clear_finish, 91296341Sdelphij ec_GFp_simple_point_copy, 92296341Sdelphij ec_GFp_simple_point_set_to_infinity, 93296341Sdelphij ec_GFp_simple_set_Jprojective_coordinates_GFp, 94296341Sdelphij ec_GFp_simple_get_Jprojective_coordinates_GFp, 95296341Sdelphij ec_GFp_simple_point_set_affine_coordinates, 96296341Sdelphij ec_GFp_simple_point_get_affine_coordinates, 97296341Sdelphij 0, 0, 0, 98296341Sdelphij ec_GFp_simple_add, 99296341Sdelphij ec_GFp_simple_dbl, 100296341Sdelphij ec_GFp_simple_invert, 101296341Sdelphij ec_GFp_simple_is_at_infinity, 102296341Sdelphij ec_GFp_simple_is_on_curve, 103296341Sdelphij ec_GFp_simple_cmp, 104296341Sdelphij ec_GFp_simple_make_affine, 105296341Sdelphij ec_GFp_simple_points_make_affine, 106296341Sdelphij 0 /* mul */ , 107296341Sdelphij 0 /* precompute_mult */ , 108296341Sdelphij 0 /* have_precompute_mult */ , 109296341Sdelphij ec_GFp_simple_field_mul, 110296341Sdelphij ec_GFp_simple_field_sqr, 111296341Sdelphij 0 /* field_div */ , 112296341Sdelphij 0 /* field_encode */ , 113296341Sdelphij 0 /* field_decode */ , 114296341Sdelphij 0 /* field_set_to_one */ 115296341Sdelphij }; 116109998Smarkm 117273399Sdelphij#ifdef OPENSSL_FIPS 118296341Sdelphij if (FIPS_mode()) 119296341Sdelphij return fips_ec_gfp_simple_method(); 120273399Sdelphij#endif 121273399Sdelphij 122296341Sdelphij return &ret; 123296341Sdelphij} 124109998Smarkm 125296341Sdelphij/* 126296341Sdelphij * Most method functions in this file are designed to work with 127160814Ssimon * non-trivial representations of field elements if necessary 128160814Ssimon * (see ecp_mont.c): while standard modular addition and subtraction 129160814Ssimon * are used, the field_mul and field_sqr methods will be used for 130160814Ssimon * multiplication, and field_encode and field_decode (if defined) 131160814Ssimon * will be used for converting between representations. 132296341Sdelphij * 133160814Ssimon * Functions ec_GFp_simple_points_make_affine() and 134160814Ssimon * ec_GFp_simple_point_get_affine_coordinates() specifically assume 135160814Ssimon * that if a non-trivial representation is used, it is a Montgomery 136160814Ssimon * representation (i.e. 'encoding' means multiplying by some factor R). 137160814Ssimon */ 138160814Ssimon 139109998Smarkmint ec_GFp_simple_group_init(EC_GROUP *group) 140296341Sdelphij{ 141296341Sdelphij BN_init(&group->field); 142296341Sdelphij BN_init(&group->a); 143296341Sdelphij BN_init(&group->b); 144296341Sdelphij group->a_is_minus3 = 0; 145296341Sdelphij return 1; 146296341Sdelphij} 147109998Smarkm 148109998Smarkmvoid ec_GFp_simple_group_finish(EC_GROUP *group) 149296341Sdelphij{ 150296341Sdelphij BN_free(&group->field); 151296341Sdelphij BN_free(&group->a); 152296341Sdelphij BN_free(&group->b); 153296341Sdelphij} 154109998Smarkm 155109998Smarkmvoid ec_GFp_simple_group_clear_finish(EC_GROUP *group) 156296341Sdelphij{ 157296341Sdelphij BN_clear_free(&group->field); 158296341Sdelphij BN_clear_free(&group->a); 159296341Sdelphij BN_clear_free(&group->b); 160296341Sdelphij} 161109998Smarkm 162109998Smarkmint ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) 163296341Sdelphij{ 164296341Sdelphij if (!BN_copy(&dest->field, &src->field)) 165296341Sdelphij return 0; 166296341Sdelphij if (!BN_copy(&dest->a, &src->a)) 167296341Sdelphij return 0; 168296341Sdelphij if (!BN_copy(&dest->b, &src->b)) 169296341Sdelphij return 0; 170109998Smarkm 171296341Sdelphij dest->a_is_minus3 = src->a_is_minus3; 172109998Smarkm 173296341Sdelphij return 1; 174296341Sdelphij} 175109998Smarkm 176160814Ssimonint ec_GFp_simple_group_set_curve(EC_GROUP *group, 177296341Sdelphij const BIGNUM *p, const BIGNUM *a, 178296341Sdelphij const BIGNUM *b, BN_CTX *ctx) 179296341Sdelphij{ 180296341Sdelphij int ret = 0; 181296341Sdelphij BN_CTX *new_ctx = NULL; 182296341Sdelphij BIGNUM *tmp_a; 183109998Smarkm 184296341Sdelphij /* p must be a prime > 3 */ 185296341Sdelphij if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { 186296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD); 187296341Sdelphij return 0; 188296341Sdelphij } 189109998Smarkm 190296341Sdelphij if (ctx == NULL) { 191296341Sdelphij ctx = new_ctx = BN_CTX_new(); 192296341Sdelphij if (ctx == NULL) 193296341Sdelphij return 0; 194296341Sdelphij } 195109998Smarkm 196296341Sdelphij BN_CTX_start(ctx); 197296341Sdelphij tmp_a = BN_CTX_get(ctx); 198296341Sdelphij if (tmp_a == NULL) 199296341Sdelphij goto err; 200109998Smarkm 201296341Sdelphij /* group->field */ 202296341Sdelphij if (!BN_copy(&group->field, p)) 203296341Sdelphij goto err; 204296341Sdelphij BN_set_negative(&group->field, 0); 205109998Smarkm 206296341Sdelphij /* group->a */ 207296341Sdelphij if (!BN_nnmod(tmp_a, a, p, ctx)) 208296341Sdelphij goto err; 209296341Sdelphij if (group->meth->field_encode) { 210296341Sdelphij if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) 211296341Sdelphij goto err; 212296341Sdelphij } else if (!BN_copy(&group->a, tmp_a)) 213296341Sdelphij goto err; 214109998Smarkm 215296341Sdelphij /* group->b */ 216296341Sdelphij if (!BN_nnmod(&group->b, b, p, ctx)) 217296341Sdelphij goto err; 218296341Sdelphij if (group->meth->field_encode) 219296341Sdelphij if (!group->meth->field_encode(group, &group->b, &group->b, ctx)) 220296341Sdelphij goto err; 221296341Sdelphij 222296341Sdelphij /* group->a_is_minus3 */ 223296341Sdelphij if (!BN_add_word(tmp_a, 3)) 224296341Sdelphij goto err; 225296341Sdelphij group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); 226296341Sdelphij 227296341Sdelphij ret = 1; 228296341Sdelphij 229109998Smarkm err: 230296341Sdelphij BN_CTX_end(ctx); 231296341Sdelphij if (new_ctx != NULL) 232296341Sdelphij BN_CTX_free(new_ctx); 233296341Sdelphij return ret; 234296341Sdelphij} 235109998Smarkm 236296341Sdelphijint ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, 237296341Sdelphij BIGNUM *b, BN_CTX *ctx) 238296341Sdelphij{ 239296341Sdelphij int ret = 0; 240296341Sdelphij BN_CTX *new_ctx = NULL; 241109998Smarkm 242296341Sdelphij if (p != NULL) { 243296341Sdelphij if (!BN_copy(p, &group->field)) 244296341Sdelphij return 0; 245296341Sdelphij } 246109998Smarkm 247296341Sdelphij if (a != NULL || b != NULL) { 248296341Sdelphij if (group->meth->field_decode) { 249296341Sdelphij if (ctx == NULL) { 250296341Sdelphij ctx = new_ctx = BN_CTX_new(); 251296341Sdelphij if (ctx == NULL) 252296341Sdelphij return 0; 253296341Sdelphij } 254296341Sdelphij if (a != NULL) { 255296341Sdelphij if (!group->meth->field_decode(group, a, &group->a, ctx)) 256296341Sdelphij goto err; 257296341Sdelphij } 258296341Sdelphij if (b != NULL) { 259296341Sdelphij if (!group->meth->field_decode(group, b, &group->b, ctx)) 260296341Sdelphij goto err; 261296341Sdelphij } 262296341Sdelphij } else { 263296341Sdelphij if (a != NULL) { 264296341Sdelphij if (!BN_copy(a, &group->a)) 265296341Sdelphij goto err; 266296341Sdelphij } 267296341Sdelphij if (b != NULL) { 268296341Sdelphij if (!BN_copy(b, &group->b)) 269296341Sdelphij goto err; 270296341Sdelphij } 271296341Sdelphij } 272296341Sdelphij } 273296341Sdelphij 274296341Sdelphij ret = 1; 275296341Sdelphij 276109998Smarkm err: 277296341Sdelphij if (new_ctx) 278296341Sdelphij BN_CTX_free(new_ctx); 279296341Sdelphij return ret; 280296341Sdelphij} 281109998Smarkm 282160814Ssimonint ec_GFp_simple_group_get_degree(const EC_GROUP *group) 283296341Sdelphij{ 284296341Sdelphij return BN_num_bits(&group->field); 285296341Sdelphij} 286109998Smarkm 287160814Ssimonint ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) 288296341Sdelphij{ 289296341Sdelphij int ret = 0; 290296341Sdelphij BIGNUM *a, *b, *order, *tmp_1, *tmp_2; 291296341Sdelphij const BIGNUM *p = &group->field; 292296341Sdelphij BN_CTX *new_ctx = NULL; 293160814Ssimon 294296341Sdelphij if (ctx == NULL) { 295296341Sdelphij ctx = new_ctx = BN_CTX_new(); 296296341Sdelphij if (ctx == NULL) { 297296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, 298296341Sdelphij ERR_R_MALLOC_FAILURE); 299296341Sdelphij goto err; 300296341Sdelphij } 301296341Sdelphij } 302296341Sdelphij BN_CTX_start(ctx); 303296341Sdelphij a = BN_CTX_get(ctx); 304296341Sdelphij b = BN_CTX_get(ctx); 305296341Sdelphij tmp_1 = BN_CTX_get(ctx); 306296341Sdelphij tmp_2 = BN_CTX_get(ctx); 307296341Sdelphij order = BN_CTX_get(ctx); 308296341Sdelphij if (order == NULL) 309296341Sdelphij goto err; 310109998Smarkm 311296341Sdelphij if (group->meth->field_decode) { 312296341Sdelphij if (!group->meth->field_decode(group, a, &group->a, ctx)) 313296341Sdelphij goto err; 314296341Sdelphij if (!group->meth->field_decode(group, b, &group->b, ctx)) 315296341Sdelphij goto err; 316296341Sdelphij } else { 317296341Sdelphij if (!BN_copy(a, &group->a)) 318296341Sdelphij goto err; 319296341Sdelphij if (!BN_copy(b, &group->b)) 320296341Sdelphij goto err; 321296341Sdelphij } 322109998Smarkm 323296341Sdelphij /*- 324296341Sdelphij * check the discriminant: 325296341Sdelphij * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) 326296341Sdelphij * 0 =< a, b < p 327296341Sdelphij */ 328296341Sdelphij if (BN_is_zero(a)) { 329296341Sdelphij if (BN_is_zero(b)) 330296341Sdelphij goto err; 331296341Sdelphij } else if (!BN_is_zero(b)) { 332296341Sdelphij if (!BN_mod_sqr(tmp_1, a, p, ctx)) 333296341Sdelphij goto err; 334296341Sdelphij if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) 335296341Sdelphij goto err; 336296341Sdelphij if (!BN_lshift(tmp_1, tmp_2, 2)) 337296341Sdelphij goto err; 338296341Sdelphij /* tmp_1 = 4*a^3 */ 339109998Smarkm 340296341Sdelphij if (!BN_mod_sqr(tmp_2, b, p, ctx)) 341296341Sdelphij goto err; 342296341Sdelphij if (!BN_mul_word(tmp_2, 27)) 343296341Sdelphij goto err; 344296341Sdelphij /* tmp_2 = 27*b^2 */ 345109998Smarkm 346296341Sdelphij if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) 347296341Sdelphij goto err; 348296341Sdelphij if (BN_is_zero(a)) 349296341Sdelphij goto err; 350296341Sdelphij } 351296341Sdelphij ret = 1; 352109998Smarkm 353296341Sdelphij err: 354296341Sdelphij if (ctx != NULL) 355296341Sdelphij BN_CTX_end(ctx); 356296341Sdelphij if (new_ctx != NULL) 357296341Sdelphij BN_CTX_free(new_ctx); 358296341Sdelphij return ret; 359296341Sdelphij} 360109998Smarkm 361109998Smarkmint ec_GFp_simple_point_init(EC_POINT *point) 362296341Sdelphij{ 363296341Sdelphij BN_init(&point->X); 364296341Sdelphij BN_init(&point->Y); 365296341Sdelphij BN_init(&point->Z); 366296341Sdelphij point->Z_is_one = 0; 367109998Smarkm 368296341Sdelphij return 1; 369296341Sdelphij} 370109998Smarkm 371109998Smarkmvoid ec_GFp_simple_point_finish(EC_POINT *point) 372296341Sdelphij{ 373296341Sdelphij BN_free(&point->X); 374296341Sdelphij BN_free(&point->Y); 375296341Sdelphij BN_free(&point->Z); 376296341Sdelphij} 377109998Smarkm 378109998Smarkmvoid ec_GFp_simple_point_clear_finish(EC_POINT *point) 379296341Sdelphij{ 380296341Sdelphij BN_clear_free(&point->X); 381296341Sdelphij BN_clear_free(&point->Y); 382296341Sdelphij BN_clear_free(&point->Z); 383296341Sdelphij point->Z_is_one = 0; 384296341Sdelphij} 385109998Smarkm 386109998Smarkmint ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) 387296341Sdelphij{ 388296341Sdelphij if (!BN_copy(&dest->X, &src->X)) 389296341Sdelphij return 0; 390296341Sdelphij if (!BN_copy(&dest->Y, &src->Y)) 391296341Sdelphij return 0; 392296341Sdelphij if (!BN_copy(&dest->Z, &src->Z)) 393296341Sdelphij return 0; 394296341Sdelphij dest->Z_is_one = src->Z_is_one; 395109998Smarkm 396296341Sdelphij return 1; 397296341Sdelphij} 398109998Smarkm 399296341Sdelphijint ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, 400296341Sdelphij EC_POINT *point) 401296341Sdelphij{ 402296341Sdelphij point->Z_is_one = 0; 403296341Sdelphij BN_zero(&point->Z); 404296341Sdelphij return 1; 405296341Sdelphij} 406109998Smarkm 407296341Sdelphijint ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group, 408296341Sdelphij EC_POINT *point, 409296341Sdelphij const BIGNUM *x, 410296341Sdelphij const BIGNUM *y, 411296341Sdelphij const BIGNUM *z, 412296341Sdelphij BN_CTX *ctx) 413296341Sdelphij{ 414296341Sdelphij BN_CTX *new_ctx = NULL; 415296341Sdelphij int ret = 0; 416109998Smarkm 417296341Sdelphij if (ctx == NULL) { 418296341Sdelphij ctx = new_ctx = BN_CTX_new(); 419296341Sdelphij if (ctx == NULL) 420296341Sdelphij return 0; 421296341Sdelphij } 422109998Smarkm 423296341Sdelphij if (x != NULL) { 424296341Sdelphij if (!BN_nnmod(&point->X, x, &group->field, ctx)) 425296341Sdelphij goto err; 426296341Sdelphij if (group->meth->field_encode) { 427296341Sdelphij if (!group->meth->field_encode(group, &point->X, &point->X, ctx)) 428296341Sdelphij goto err; 429296341Sdelphij } 430296341Sdelphij } 431109998Smarkm 432296341Sdelphij if (y != NULL) { 433296341Sdelphij if (!BN_nnmod(&point->Y, y, &group->field, ctx)) 434296341Sdelphij goto err; 435296341Sdelphij if (group->meth->field_encode) { 436296341Sdelphij if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx)) 437296341Sdelphij goto err; 438296341Sdelphij } 439296341Sdelphij } 440109998Smarkm 441296341Sdelphij if (z != NULL) { 442296341Sdelphij int Z_is_one; 443296341Sdelphij 444296341Sdelphij if (!BN_nnmod(&point->Z, z, &group->field, ctx)) 445296341Sdelphij goto err; 446296341Sdelphij Z_is_one = BN_is_one(&point->Z); 447296341Sdelphij if (group->meth->field_encode) { 448296341Sdelphij if (Z_is_one && (group->meth->field_set_to_one != 0)) { 449296341Sdelphij if (!group->meth->field_set_to_one(group, &point->Z, ctx)) 450296341Sdelphij goto err; 451296341Sdelphij } else { 452296341Sdelphij if (!group-> 453296341Sdelphij meth->field_encode(group, &point->Z, &point->Z, ctx)) 454296341Sdelphij goto err; 455296341Sdelphij } 456296341Sdelphij } 457296341Sdelphij point->Z_is_one = Z_is_one; 458296341Sdelphij } 459296341Sdelphij 460296341Sdelphij ret = 1; 461296341Sdelphij 462109998Smarkm err: 463296341Sdelphij if (new_ctx != NULL) 464296341Sdelphij BN_CTX_free(new_ctx); 465296341Sdelphij return ret; 466296341Sdelphij} 467109998Smarkm 468296341Sdelphijint ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, 469296341Sdelphij const EC_POINT *point, 470296341Sdelphij BIGNUM *x, BIGNUM *y, 471296341Sdelphij BIGNUM *z, BN_CTX *ctx) 472296341Sdelphij{ 473296341Sdelphij BN_CTX *new_ctx = NULL; 474296341Sdelphij int ret = 0; 475109998Smarkm 476296341Sdelphij if (group->meth->field_decode != 0) { 477296341Sdelphij if (ctx == NULL) { 478296341Sdelphij ctx = new_ctx = BN_CTX_new(); 479296341Sdelphij if (ctx == NULL) 480296341Sdelphij return 0; 481296341Sdelphij } 482109998Smarkm 483296341Sdelphij if (x != NULL) { 484296341Sdelphij if (!group->meth->field_decode(group, x, &point->X, ctx)) 485296341Sdelphij goto err; 486296341Sdelphij } 487296341Sdelphij if (y != NULL) { 488296341Sdelphij if (!group->meth->field_decode(group, y, &point->Y, ctx)) 489296341Sdelphij goto err; 490296341Sdelphij } 491296341Sdelphij if (z != NULL) { 492296341Sdelphij if (!group->meth->field_decode(group, z, &point->Z, ctx)) 493296341Sdelphij goto err; 494296341Sdelphij } 495296341Sdelphij } else { 496296341Sdelphij if (x != NULL) { 497296341Sdelphij if (!BN_copy(x, &point->X)) 498296341Sdelphij goto err; 499296341Sdelphij } 500296341Sdelphij if (y != NULL) { 501296341Sdelphij if (!BN_copy(y, &point->Y)) 502296341Sdelphij goto err; 503296341Sdelphij } 504296341Sdelphij if (z != NULL) { 505296341Sdelphij if (!BN_copy(z, &point->Z)) 506296341Sdelphij goto err; 507296341Sdelphij } 508296341Sdelphij } 509109998Smarkm 510296341Sdelphij ret = 1; 511296341Sdelphij 512109998Smarkm err: 513296341Sdelphij if (new_ctx != NULL) 514296341Sdelphij BN_CTX_free(new_ctx); 515296341Sdelphij return ret; 516296341Sdelphij} 517109998Smarkm 518296341Sdelphijint ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, 519296341Sdelphij EC_POINT *point, 520296341Sdelphij const BIGNUM *x, 521296341Sdelphij const BIGNUM *y, BN_CTX *ctx) 522296341Sdelphij{ 523296341Sdelphij if (x == NULL || y == NULL) { 524296341Sdelphij /* 525296341Sdelphij * unlike for projective coordinates, we do not tolerate this 526296341Sdelphij */ 527296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES, 528296341Sdelphij ERR_R_PASSED_NULL_PARAMETER); 529296341Sdelphij return 0; 530296341Sdelphij } 531109998Smarkm 532296341Sdelphij return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, 533296341Sdelphij BN_value_one(), ctx); 534296341Sdelphij} 535109998Smarkm 536296341Sdelphijint ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, 537296341Sdelphij const EC_POINT *point, 538296341Sdelphij BIGNUM *x, BIGNUM *y, 539296341Sdelphij BN_CTX *ctx) 540296341Sdelphij{ 541296341Sdelphij BN_CTX *new_ctx = NULL; 542296341Sdelphij BIGNUM *Z, *Z_1, *Z_2, *Z_3; 543296341Sdelphij const BIGNUM *Z_; 544296341Sdelphij int ret = 0; 545109998Smarkm 546296341Sdelphij if (EC_POINT_is_at_infinity(group, point)) { 547296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, 548296341Sdelphij EC_R_POINT_AT_INFINITY); 549296341Sdelphij return 0; 550296341Sdelphij } 551109998Smarkm 552296341Sdelphij if (ctx == NULL) { 553296341Sdelphij ctx = new_ctx = BN_CTX_new(); 554296341Sdelphij if (ctx == NULL) 555296341Sdelphij return 0; 556296341Sdelphij } 557109998Smarkm 558296341Sdelphij BN_CTX_start(ctx); 559296341Sdelphij Z = BN_CTX_get(ctx); 560296341Sdelphij Z_1 = BN_CTX_get(ctx); 561296341Sdelphij Z_2 = BN_CTX_get(ctx); 562296341Sdelphij Z_3 = BN_CTX_get(ctx); 563296341Sdelphij if (Z_3 == NULL) 564296341Sdelphij goto err; 565109998Smarkm 566296341Sdelphij /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ 567109998Smarkm 568296341Sdelphij if (group->meth->field_decode) { 569296341Sdelphij if (!group->meth->field_decode(group, Z, &point->Z, ctx)) 570296341Sdelphij goto err; 571296341Sdelphij Z_ = Z; 572296341Sdelphij } else { 573296341Sdelphij Z_ = &point->Z; 574296341Sdelphij } 575109998Smarkm 576296341Sdelphij if (BN_is_one(Z_)) { 577296341Sdelphij if (group->meth->field_decode) { 578296341Sdelphij if (x != NULL) { 579296341Sdelphij if (!group->meth->field_decode(group, x, &point->X, ctx)) 580296341Sdelphij goto err; 581296341Sdelphij } 582296341Sdelphij if (y != NULL) { 583296341Sdelphij if (!group->meth->field_decode(group, y, &point->Y, ctx)) 584296341Sdelphij goto err; 585296341Sdelphij } 586296341Sdelphij } else { 587296341Sdelphij if (x != NULL) { 588296341Sdelphij if (!BN_copy(x, &point->X)) 589296341Sdelphij goto err; 590296341Sdelphij } 591296341Sdelphij if (y != NULL) { 592296341Sdelphij if (!BN_copy(y, &point->Y)) 593296341Sdelphij goto err; 594296341Sdelphij } 595296341Sdelphij } 596296341Sdelphij } else { 597296341Sdelphij if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { 598296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, 599296341Sdelphij ERR_R_BN_LIB); 600296341Sdelphij goto err; 601296341Sdelphij } 602109998Smarkm 603296341Sdelphij if (group->meth->field_encode == 0) { 604296341Sdelphij /* field_sqr works on standard representation */ 605296341Sdelphij if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) 606296341Sdelphij goto err; 607296341Sdelphij } else { 608296341Sdelphij if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) 609296341Sdelphij goto err; 610296341Sdelphij } 611160814Ssimon 612296341Sdelphij if (x != NULL) { 613296341Sdelphij /* 614296341Sdelphij * in the Montgomery case, field_mul will cancel out Montgomery 615296341Sdelphij * factor in X: 616296341Sdelphij */ 617296341Sdelphij if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx)) 618296341Sdelphij goto err; 619296341Sdelphij } 620109998Smarkm 621296341Sdelphij if (y != NULL) { 622296341Sdelphij if (group->meth->field_encode == 0) { 623296341Sdelphij /* 624296341Sdelphij * field_mul works on standard representation 625296341Sdelphij */ 626296341Sdelphij if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) 627296341Sdelphij goto err; 628296341Sdelphij } else { 629296341Sdelphij if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) 630296341Sdelphij goto err; 631296341Sdelphij } 632109998Smarkm 633296341Sdelphij /* 634296341Sdelphij * in the Montgomery case, field_mul will cancel out Montgomery 635296341Sdelphij * factor in Y: 636296341Sdelphij */ 637296341Sdelphij if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) 638296341Sdelphij goto err; 639296341Sdelphij } 640296341Sdelphij } 641296341Sdelphij 642296341Sdelphij ret = 1; 643296341Sdelphij 644109998Smarkm err: 645296341Sdelphij BN_CTX_end(ctx); 646296341Sdelphij if (new_ctx != NULL) 647296341Sdelphij BN_CTX_free(new_ctx); 648296341Sdelphij return ret; 649296341Sdelphij} 650109998Smarkm 651296341Sdelphijint ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 652296341Sdelphij const EC_POINT *b, BN_CTX *ctx) 653296341Sdelphij{ 654296341Sdelphij int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 655296341Sdelphij const BIGNUM *, BN_CTX *); 656296341Sdelphij int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 657296341Sdelphij const BIGNUM *p; 658296341Sdelphij BN_CTX *new_ctx = NULL; 659296341Sdelphij BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; 660296341Sdelphij int ret = 0; 661109998Smarkm 662296341Sdelphij if (a == b) 663296341Sdelphij return EC_POINT_dbl(group, r, a, ctx); 664296341Sdelphij if (EC_POINT_is_at_infinity(group, a)) 665296341Sdelphij return EC_POINT_copy(r, b); 666296341Sdelphij if (EC_POINT_is_at_infinity(group, b)) 667296341Sdelphij return EC_POINT_copy(r, a); 668109998Smarkm 669296341Sdelphij field_mul = group->meth->field_mul; 670296341Sdelphij field_sqr = group->meth->field_sqr; 671296341Sdelphij p = &group->field; 672109998Smarkm 673296341Sdelphij if (ctx == NULL) { 674296341Sdelphij ctx = new_ctx = BN_CTX_new(); 675296341Sdelphij if (ctx == NULL) 676296341Sdelphij return 0; 677296341Sdelphij } 678109998Smarkm 679296341Sdelphij BN_CTX_start(ctx); 680296341Sdelphij n0 = BN_CTX_get(ctx); 681296341Sdelphij n1 = BN_CTX_get(ctx); 682296341Sdelphij n2 = BN_CTX_get(ctx); 683296341Sdelphij n3 = BN_CTX_get(ctx); 684296341Sdelphij n4 = BN_CTX_get(ctx); 685296341Sdelphij n5 = BN_CTX_get(ctx); 686296341Sdelphij n6 = BN_CTX_get(ctx); 687296341Sdelphij if (n6 == NULL) 688296341Sdelphij goto end; 689109998Smarkm 690296341Sdelphij /* 691296341Sdelphij * Note that in this function we must not read components of 'a' or 'b' 692296341Sdelphij * once we have written the corresponding components of 'r'. ('r' might 693296341Sdelphij * be one of 'a' or 'b'.) 694296341Sdelphij */ 695109998Smarkm 696296341Sdelphij /* n1, n2 */ 697296341Sdelphij if (b->Z_is_one) { 698296341Sdelphij if (!BN_copy(n1, &a->X)) 699296341Sdelphij goto end; 700296341Sdelphij if (!BN_copy(n2, &a->Y)) 701296341Sdelphij goto end; 702296341Sdelphij /* n1 = X_a */ 703296341Sdelphij /* n2 = Y_a */ 704296341Sdelphij } else { 705296341Sdelphij if (!field_sqr(group, n0, &b->Z, ctx)) 706296341Sdelphij goto end; 707296341Sdelphij if (!field_mul(group, n1, &a->X, n0, ctx)) 708296341Sdelphij goto end; 709296341Sdelphij /* n1 = X_a * Z_b^2 */ 710109998Smarkm 711296341Sdelphij if (!field_mul(group, n0, n0, &b->Z, ctx)) 712296341Sdelphij goto end; 713296341Sdelphij if (!field_mul(group, n2, &a->Y, n0, ctx)) 714296341Sdelphij goto end; 715296341Sdelphij /* n2 = Y_a * Z_b^3 */ 716296341Sdelphij } 717109998Smarkm 718296341Sdelphij /* n3, n4 */ 719296341Sdelphij if (a->Z_is_one) { 720296341Sdelphij if (!BN_copy(n3, &b->X)) 721296341Sdelphij goto end; 722296341Sdelphij if (!BN_copy(n4, &b->Y)) 723296341Sdelphij goto end; 724296341Sdelphij /* n3 = X_b */ 725296341Sdelphij /* n4 = Y_b */ 726296341Sdelphij } else { 727296341Sdelphij if (!field_sqr(group, n0, &a->Z, ctx)) 728296341Sdelphij goto end; 729296341Sdelphij if (!field_mul(group, n3, &b->X, n0, ctx)) 730296341Sdelphij goto end; 731296341Sdelphij /* n3 = X_b * Z_a^2 */ 732109998Smarkm 733296341Sdelphij if (!field_mul(group, n0, n0, &a->Z, ctx)) 734296341Sdelphij goto end; 735296341Sdelphij if (!field_mul(group, n4, &b->Y, n0, ctx)) 736296341Sdelphij goto end; 737296341Sdelphij /* n4 = Y_b * Z_a^3 */ 738296341Sdelphij } 739109998Smarkm 740296341Sdelphij /* n5, n6 */ 741296341Sdelphij if (!BN_mod_sub_quick(n5, n1, n3, p)) 742296341Sdelphij goto end; 743296341Sdelphij if (!BN_mod_sub_quick(n6, n2, n4, p)) 744296341Sdelphij goto end; 745296341Sdelphij /* n5 = n1 - n3 */ 746296341Sdelphij /* n6 = n2 - n4 */ 747109998Smarkm 748296341Sdelphij if (BN_is_zero(n5)) { 749296341Sdelphij if (BN_is_zero(n6)) { 750296341Sdelphij /* a is the same point as b */ 751296341Sdelphij BN_CTX_end(ctx); 752296341Sdelphij ret = EC_POINT_dbl(group, r, a, ctx); 753296341Sdelphij ctx = NULL; 754296341Sdelphij goto end; 755296341Sdelphij } else { 756296341Sdelphij /* a is the inverse of b */ 757296341Sdelphij BN_zero(&r->Z); 758296341Sdelphij r->Z_is_one = 0; 759296341Sdelphij ret = 1; 760296341Sdelphij goto end; 761296341Sdelphij } 762296341Sdelphij } 763109998Smarkm 764296341Sdelphij /* 'n7', 'n8' */ 765296341Sdelphij if (!BN_mod_add_quick(n1, n1, n3, p)) 766296341Sdelphij goto end; 767296341Sdelphij if (!BN_mod_add_quick(n2, n2, n4, p)) 768296341Sdelphij goto end; 769296341Sdelphij /* 'n7' = n1 + n3 */ 770296341Sdelphij /* 'n8' = n2 + n4 */ 771109998Smarkm 772296341Sdelphij /* Z_r */ 773296341Sdelphij if (a->Z_is_one && b->Z_is_one) { 774296341Sdelphij if (!BN_copy(&r->Z, n5)) 775296341Sdelphij goto end; 776296341Sdelphij } else { 777296341Sdelphij if (a->Z_is_one) { 778296341Sdelphij if (!BN_copy(n0, &b->Z)) 779296341Sdelphij goto end; 780296341Sdelphij } else if (b->Z_is_one) { 781296341Sdelphij if (!BN_copy(n0, &a->Z)) 782296341Sdelphij goto end; 783296341Sdelphij } else { 784296341Sdelphij if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) 785296341Sdelphij goto end; 786296341Sdelphij } 787296341Sdelphij if (!field_mul(group, &r->Z, n0, n5, ctx)) 788296341Sdelphij goto end; 789296341Sdelphij } 790296341Sdelphij r->Z_is_one = 0; 791296341Sdelphij /* Z_r = Z_a * Z_b * n5 */ 792109998Smarkm 793296341Sdelphij /* X_r */ 794296341Sdelphij if (!field_sqr(group, n0, n6, ctx)) 795296341Sdelphij goto end; 796296341Sdelphij if (!field_sqr(group, n4, n5, ctx)) 797296341Sdelphij goto end; 798296341Sdelphij if (!field_mul(group, n3, n1, n4, ctx)) 799296341Sdelphij goto end; 800296341Sdelphij if (!BN_mod_sub_quick(&r->X, n0, n3, p)) 801296341Sdelphij goto end; 802296341Sdelphij /* X_r = n6^2 - n5^2 * 'n7' */ 803109998Smarkm 804296341Sdelphij /* 'n9' */ 805296341Sdelphij if (!BN_mod_lshift1_quick(n0, &r->X, p)) 806296341Sdelphij goto end; 807296341Sdelphij if (!BN_mod_sub_quick(n0, n3, n0, p)) 808296341Sdelphij goto end; 809296341Sdelphij /* n9 = n5^2 * 'n7' - 2 * X_r */ 810296341Sdelphij 811296341Sdelphij /* Y_r */ 812296341Sdelphij if (!field_mul(group, n0, n0, n6, ctx)) 813296341Sdelphij goto end; 814296341Sdelphij if (!field_mul(group, n5, n4, n5, ctx)) 815296341Sdelphij goto end; /* now n5 is n5^3 */ 816296341Sdelphij if (!field_mul(group, n1, n2, n5, ctx)) 817296341Sdelphij goto end; 818296341Sdelphij if (!BN_mod_sub_quick(n0, n0, n1, p)) 819296341Sdelphij goto end; 820296341Sdelphij if (BN_is_odd(n0)) 821296341Sdelphij if (!BN_add(n0, n0, p)) 822296341Sdelphij goto end; 823296341Sdelphij /* now 0 <= n0 < 2*p, and n0 is even */ 824296341Sdelphij if (!BN_rshift1(&r->Y, n0)) 825296341Sdelphij goto end; 826296341Sdelphij /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ 827296341Sdelphij 828296341Sdelphij ret = 1; 829296341Sdelphij 830109998Smarkm end: 831296341Sdelphij if (ctx) /* otherwise we already called BN_CTX_end */ 832296341Sdelphij BN_CTX_end(ctx); 833296341Sdelphij if (new_ctx != NULL) 834296341Sdelphij BN_CTX_free(new_ctx); 835296341Sdelphij return ret; 836296341Sdelphij} 837109998Smarkm 838296341Sdelphijint ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 839296341Sdelphij BN_CTX *ctx) 840296341Sdelphij{ 841296341Sdelphij int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 842296341Sdelphij const BIGNUM *, BN_CTX *); 843296341Sdelphij int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 844296341Sdelphij const BIGNUM *p; 845296341Sdelphij BN_CTX *new_ctx = NULL; 846296341Sdelphij BIGNUM *n0, *n1, *n2, *n3; 847296341Sdelphij int ret = 0; 848109998Smarkm 849296341Sdelphij if (EC_POINT_is_at_infinity(group, a)) { 850296341Sdelphij BN_zero(&r->Z); 851296341Sdelphij r->Z_is_one = 0; 852296341Sdelphij return 1; 853296341Sdelphij } 854109998Smarkm 855296341Sdelphij field_mul = group->meth->field_mul; 856296341Sdelphij field_sqr = group->meth->field_sqr; 857296341Sdelphij p = &group->field; 858109998Smarkm 859296341Sdelphij if (ctx == NULL) { 860296341Sdelphij ctx = new_ctx = BN_CTX_new(); 861296341Sdelphij if (ctx == NULL) 862296341Sdelphij return 0; 863296341Sdelphij } 864109998Smarkm 865296341Sdelphij BN_CTX_start(ctx); 866296341Sdelphij n0 = BN_CTX_get(ctx); 867296341Sdelphij n1 = BN_CTX_get(ctx); 868296341Sdelphij n2 = BN_CTX_get(ctx); 869296341Sdelphij n3 = BN_CTX_get(ctx); 870296341Sdelphij if (n3 == NULL) 871296341Sdelphij goto err; 872109998Smarkm 873296341Sdelphij /* 874296341Sdelphij * Note that in this function we must not read components of 'a' once we 875296341Sdelphij * have written the corresponding components of 'r'. ('r' might the same 876296341Sdelphij * as 'a'.) 877296341Sdelphij */ 878109998Smarkm 879296341Sdelphij /* n1 */ 880296341Sdelphij if (a->Z_is_one) { 881296341Sdelphij if (!field_sqr(group, n0, &a->X, ctx)) 882296341Sdelphij goto err; 883296341Sdelphij if (!BN_mod_lshift1_quick(n1, n0, p)) 884296341Sdelphij goto err; 885296341Sdelphij if (!BN_mod_add_quick(n0, n0, n1, p)) 886296341Sdelphij goto err; 887296341Sdelphij if (!BN_mod_add_quick(n1, n0, &group->a, p)) 888296341Sdelphij goto err; 889296341Sdelphij /* n1 = 3 * X_a^2 + a_curve */ 890296341Sdelphij } else if (group->a_is_minus3) { 891296341Sdelphij if (!field_sqr(group, n1, &a->Z, ctx)) 892296341Sdelphij goto err; 893296341Sdelphij if (!BN_mod_add_quick(n0, &a->X, n1, p)) 894296341Sdelphij goto err; 895296341Sdelphij if (!BN_mod_sub_quick(n2, &a->X, n1, p)) 896296341Sdelphij goto err; 897296341Sdelphij if (!field_mul(group, n1, n0, n2, ctx)) 898296341Sdelphij goto err; 899296341Sdelphij if (!BN_mod_lshift1_quick(n0, n1, p)) 900296341Sdelphij goto err; 901296341Sdelphij if (!BN_mod_add_quick(n1, n0, n1, p)) 902296341Sdelphij goto err; 903296341Sdelphij /*- 904296341Sdelphij * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) 905296341Sdelphij * = 3 * X_a^2 - 3 * Z_a^4 906296341Sdelphij */ 907296341Sdelphij } else { 908296341Sdelphij if (!field_sqr(group, n0, &a->X, ctx)) 909296341Sdelphij goto err; 910296341Sdelphij if (!BN_mod_lshift1_quick(n1, n0, p)) 911296341Sdelphij goto err; 912296341Sdelphij if (!BN_mod_add_quick(n0, n0, n1, p)) 913296341Sdelphij goto err; 914296341Sdelphij if (!field_sqr(group, n1, &a->Z, ctx)) 915296341Sdelphij goto err; 916296341Sdelphij if (!field_sqr(group, n1, n1, ctx)) 917296341Sdelphij goto err; 918296341Sdelphij if (!field_mul(group, n1, n1, &group->a, ctx)) 919296341Sdelphij goto err; 920296341Sdelphij if (!BN_mod_add_quick(n1, n1, n0, p)) 921296341Sdelphij goto err; 922296341Sdelphij /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ 923296341Sdelphij } 924109998Smarkm 925296341Sdelphij /* Z_r */ 926296341Sdelphij if (a->Z_is_one) { 927296341Sdelphij if (!BN_copy(n0, &a->Y)) 928296341Sdelphij goto err; 929296341Sdelphij } else { 930296341Sdelphij if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) 931296341Sdelphij goto err; 932296341Sdelphij } 933296341Sdelphij if (!BN_mod_lshift1_quick(&r->Z, n0, p)) 934296341Sdelphij goto err; 935296341Sdelphij r->Z_is_one = 0; 936296341Sdelphij /* Z_r = 2 * Y_a * Z_a */ 937109998Smarkm 938296341Sdelphij /* n2 */ 939296341Sdelphij if (!field_sqr(group, n3, &a->Y, ctx)) 940296341Sdelphij goto err; 941296341Sdelphij if (!field_mul(group, n2, &a->X, n3, ctx)) 942296341Sdelphij goto err; 943296341Sdelphij if (!BN_mod_lshift_quick(n2, n2, 2, p)) 944296341Sdelphij goto err; 945296341Sdelphij /* n2 = 4 * X_a * Y_a^2 */ 946109998Smarkm 947296341Sdelphij /* X_r */ 948296341Sdelphij if (!BN_mod_lshift1_quick(n0, n2, p)) 949296341Sdelphij goto err; 950296341Sdelphij if (!field_sqr(group, &r->X, n1, ctx)) 951296341Sdelphij goto err; 952296341Sdelphij if (!BN_mod_sub_quick(&r->X, &r->X, n0, p)) 953296341Sdelphij goto err; 954296341Sdelphij /* X_r = n1^2 - 2 * n2 */ 955109998Smarkm 956296341Sdelphij /* n3 */ 957296341Sdelphij if (!field_sqr(group, n0, n3, ctx)) 958296341Sdelphij goto err; 959296341Sdelphij if (!BN_mod_lshift_quick(n3, n0, 3, p)) 960296341Sdelphij goto err; 961296341Sdelphij /* n3 = 8 * Y_a^4 */ 962109998Smarkm 963296341Sdelphij /* Y_r */ 964296341Sdelphij if (!BN_mod_sub_quick(n0, n2, &r->X, p)) 965296341Sdelphij goto err; 966296341Sdelphij if (!field_mul(group, n0, n1, n0, ctx)) 967296341Sdelphij goto err; 968296341Sdelphij if (!BN_mod_sub_quick(&r->Y, n0, n3, p)) 969296341Sdelphij goto err; 970296341Sdelphij /* Y_r = n1 * (n2 - X_r) - n3 */ 971296341Sdelphij 972296341Sdelphij ret = 1; 973296341Sdelphij 974109998Smarkm err: 975296341Sdelphij BN_CTX_end(ctx); 976296341Sdelphij if (new_ctx != NULL) 977296341Sdelphij BN_CTX_free(new_ctx); 978296341Sdelphij return ret; 979296341Sdelphij} 980109998Smarkm 981109998Smarkmint ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) 982296341Sdelphij{ 983296341Sdelphij if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) 984296341Sdelphij /* point is its own inverse */ 985296341Sdelphij return 1; 986109998Smarkm 987296341Sdelphij return BN_usub(&point->Y, &group->field, &point->Y); 988296341Sdelphij} 989109998Smarkm 990109998Smarkmint ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) 991296341Sdelphij{ 992296341Sdelphij return BN_is_zero(&point->Z); 993296341Sdelphij} 994109998Smarkm 995296341Sdelphijint ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 996296341Sdelphij BN_CTX *ctx) 997296341Sdelphij{ 998296341Sdelphij int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 999296341Sdelphij const BIGNUM *, BN_CTX *); 1000296341Sdelphij int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 1001296341Sdelphij const BIGNUM *p; 1002296341Sdelphij BN_CTX *new_ctx = NULL; 1003296341Sdelphij BIGNUM *rh, *tmp, *Z4, *Z6; 1004296341Sdelphij int ret = -1; 1005109998Smarkm 1006296341Sdelphij if (EC_POINT_is_at_infinity(group, point)) 1007296341Sdelphij return 1; 1008109998Smarkm 1009296341Sdelphij field_mul = group->meth->field_mul; 1010296341Sdelphij field_sqr = group->meth->field_sqr; 1011296341Sdelphij p = &group->field; 1012109998Smarkm 1013296341Sdelphij if (ctx == NULL) { 1014296341Sdelphij ctx = new_ctx = BN_CTX_new(); 1015296341Sdelphij if (ctx == NULL) 1016296341Sdelphij return -1; 1017296341Sdelphij } 1018109998Smarkm 1019296341Sdelphij BN_CTX_start(ctx); 1020296341Sdelphij rh = BN_CTX_get(ctx); 1021296341Sdelphij tmp = BN_CTX_get(ctx); 1022296341Sdelphij Z4 = BN_CTX_get(ctx); 1023296341Sdelphij Z6 = BN_CTX_get(ctx); 1024296341Sdelphij if (Z6 == NULL) 1025296341Sdelphij goto err; 1026109998Smarkm 1027296341Sdelphij /*- 1028296341Sdelphij * We have a curve defined by a Weierstrass equation 1029296341Sdelphij * y^2 = x^3 + a*x + b. 1030296341Sdelphij * The point to consider is given in Jacobian projective coordinates 1031296341Sdelphij * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). 1032296341Sdelphij * Substituting this and multiplying by Z^6 transforms the above equation into 1033296341Sdelphij * Y^2 = X^3 + a*X*Z^4 + b*Z^6. 1034296341Sdelphij * To test this, we add up the right-hand side in 'rh'. 1035296341Sdelphij */ 1036109998Smarkm 1037296341Sdelphij /* rh := X^2 */ 1038296341Sdelphij if (!field_sqr(group, rh, &point->X, ctx)) 1039296341Sdelphij goto err; 1040109998Smarkm 1041296341Sdelphij if (!point->Z_is_one) { 1042296341Sdelphij if (!field_sqr(group, tmp, &point->Z, ctx)) 1043296341Sdelphij goto err; 1044296341Sdelphij if (!field_sqr(group, Z4, tmp, ctx)) 1045296341Sdelphij goto err; 1046296341Sdelphij if (!field_mul(group, Z6, Z4, tmp, ctx)) 1047296341Sdelphij goto err; 1048109998Smarkm 1049296341Sdelphij /* rh := (rh + a*Z^4)*X */ 1050296341Sdelphij if (group->a_is_minus3) { 1051296341Sdelphij if (!BN_mod_lshift1_quick(tmp, Z4, p)) 1052296341Sdelphij goto err; 1053296341Sdelphij if (!BN_mod_add_quick(tmp, tmp, Z4, p)) 1054296341Sdelphij goto err; 1055296341Sdelphij if (!BN_mod_sub_quick(rh, rh, tmp, p)) 1056296341Sdelphij goto err; 1057296341Sdelphij if (!field_mul(group, rh, rh, &point->X, ctx)) 1058296341Sdelphij goto err; 1059296341Sdelphij } else { 1060296341Sdelphij if (!field_mul(group, tmp, Z4, &group->a, ctx)) 1061296341Sdelphij goto err; 1062296341Sdelphij if (!BN_mod_add_quick(rh, rh, tmp, p)) 1063296341Sdelphij goto err; 1064296341Sdelphij if (!field_mul(group, rh, rh, &point->X, ctx)) 1065296341Sdelphij goto err; 1066296341Sdelphij } 1067109998Smarkm 1068296341Sdelphij /* rh := rh + b*Z^6 */ 1069296341Sdelphij if (!field_mul(group, tmp, &group->b, Z6, ctx)) 1070296341Sdelphij goto err; 1071296341Sdelphij if (!BN_mod_add_quick(rh, rh, tmp, p)) 1072296341Sdelphij goto err; 1073296341Sdelphij } else { 1074296341Sdelphij /* point->Z_is_one */ 1075109998Smarkm 1076296341Sdelphij /* rh := (rh + a)*X */ 1077296341Sdelphij if (!BN_mod_add_quick(rh, rh, &group->a, p)) 1078296341Sdelphij goto err; 1079296341Sdelphij if (!field_mul(group, rh, rh, &point->X, ctx)) 1080296341Sdelphij goto err; 1081296341Sdelphij /* rh := rh + b */ 1082296341Sdelphij if (!BN_mod_add_quick(rh, rh, &group->b, p)) 1083296341Sdelphij goto err; 1084296341Sdelphij } 1085109998Smarkm 1086296341Sdelphij /* 'lh' := Y^2 */ 1087296341Sdelphij if (!field_sqr(group, tmp, &point->Y, ctx)) 1088296341Sdelphij goto err; 1089109998Smarkm 1090296341Sdelphij ret = (0 == BN_ucmp(tmp, rh)); 1091109998Smarkm 1092109998Smarkm err: 1093296341Sdelphij BN_CTX_end(ctx); 1094296341Sdelphij if (new_ctx != NULL) 1095296341Sdelphij BN_CTX_free(new_ctx); 1096296341Sdelphij return ret; 1097296341Sdelphij} 1098109998Smarkm 1099296341Sdelphijint ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, 1100296341Sdelphij const EC_POINT *b, BN_CTX *ctx) 1101296341Sdelphij{ 1102296341Sdelphij /*- 1103296341Sdelphij * return values: 1104296341Sdelphij * -1 error 1105296341Sdelphij * 0 equal (in affine coordinates) 1106296341Sdelphij * 1 not equal 1107296341Sdelphij */ 1108109998Smarkm 1109296341Sdelphij int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 1110296341Sdelphij const BIGNUM *, BN_CTX *); 1111296341Sdelphij int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 1112296341Sdelphij BN_CTX *new_ctx = NULL; 1113296341Sdelphij BIGNUM *tmp1, *tmp2, *Za23, *Zb23; 1114296341Sdelphij const BIGNUM *tmp1_, *tmp2_; 1115296341Sdelphij int ret = -1; 1116109998Smarkm 1117296341Sdelphij if (EC_POINT_is_at_infinity(group, a)) { 1118296341Sdelphij return EC_POINT_is_at_infinity(group, b) ? 0 : 1; 1119296341Sdelphij } 1120237657Sjkim 1121296341Sdelphij if (EC_POINT_is_at_infinity(group, b)) 1122296341Sdelphij return 1; 1123109998Smarkm 1124296341Sdelphij if (a->Z_is_one && b->Z_is_one) { 1125296341Sdelphij return ((BN_cmp(&a->X, &b->X) == 0) 1126296341Sdelphij && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; 1127296341Sdelphij } 1128109998Smarkm 1129296341Sdelphij field_mul = group->meth->field_mul; 1130296341Sdelphij field_sqr = group->meth->field_sqr; 1131109998Smarkm 1132296341Sdelphij if (ctx == NULL) { 1133296341Sdelphij ctx = new_ctx = BN_CTX_new(); 1134296341Sdelphij if (ctx == NULL) 1135296341Sdelphij return -1; 1136296341Sdelphij } 1137109998Smarkm 1138296341Sdelphij BN_CTX_start(ctx); 1139296341Sdelphij tmp1 = BN_CTX_get(ctx); 1140296341Sdelphij tmp2 = BN_CTX_get(ctx); 1141296341Sdelphij Za23 = BN_CTX_get(ctx); 1142296341Sdelphij Zb23 = BN_CTX_get(ctx); 1143296341Sdelphij if (Zb23 == NULL) 1144296341Sdelphij goto end; 1145109998Smarkm 1146296341Sdelphij /*- 1147296341Sdelphij * We have to decide whether 1148296341Sdelphij * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), 1149296341Sdelphij * or equivalently, whether 1150296341Sdelphij * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). 1151296341Sdelphij */ 1152109998Smarkm 1153296341Sdelphij if (!b->Z_is_one) { 1154296341Sdelphij if (!field_sqr(group, Zb23, &b->Z, ctx)) 1155296341Sdelphij goto end; 1156296341Sdelphij if (!field_mul(group, tmp1, &a->X, Zb23, ctx)) 1157296341Sdelphij goto end; 1158296341Sdelphij tmp1_ = tmp1; 1159296341Sdelphij } else 1160296341Sdelphij tmp1_ = &a->X; 1161296341Sdelphij if (!a->Z_is_one) { 1162296341Sdelphij if (!field_sqr(group, Za23, &a->Z, ctx)) 1163296341Sdelphij goto end; 1164296341Sdelphij if (!field_mul(group, tmp2, &b->X, Za23, ctx)) 1165296341Sdelphij goto end; 1166296341Sdelphij tmp2_ = tmp2; 1167296341Sdelphij } else 1168296341Sdelphij tmp2_ = &b->X; 1169109998Smarkm 1170296341Sdelphij /* compare X_a*Z_b^2 with X_b*Z_a^2 */ 1171296341Sdelphij if (BN_cmp(tmp1_, tmp2_) != 0) { 1172296341Sdelphij ret = 1; /* points differ */ 1173296341Sdelphij goto end; 1174296341Sdelphij } 1175109998Smarkm 1176296341Sdelphij if (!b->Z_is_one) { 1177296341Sdelphij if (!field_mul(group, Zb23, Zb23, &b->Z, ctx)) 1178296341Sdelphij goto end; 1179296341Sdelphij if (!field_mul(group, tmp1, &a->Y, Zb23, ctx)) 1180296341Sdelphij goto end; 1181296341Sdelphij /* tmp1_ = tmp1 */ 1182296341Sdelphij } else 1183296341Sdelphij tmp1_ = &a->Y; 1184296341Sdelphij if (!a->Z_is_one) { 1185296341Sdelphij if (!field_mul(group, Za23, Za23, &a->Z, ctx)) 1186296341Sdelphij goto end; 1187296341Sdelphij if (!field_mul(group, tmp2, &b->Y, Za23, ctx)) 1188296341Sdelphij goto end; 1189296341Sdelphij /* tmp2_ = tmp2 */ 1190296341Sdelphij } else 1191296341Sdelphij tmp2_ = &b->Y; 1192109998Smarkm 1193296341Sdelphij /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ 1194296341Sdelphij if (BN_cmp(tmp1_, tmp2_) != 0) { 1195296341Sdelphij ret = 1; /* points differ */ 1196296341Sdelphij goto end; 1197296341Sdelphij } 1198109998Smarkm 1199296341Sdelphij /* points are equal */ 1200296341Sdelphij ret = 0; 1201296341Sdelphij 1202109998Smarkm end: 1203296341Sdelphij BN_CTX_end(ctx); 1204296341Sdelphij if (new_ctx != NULL) 1205296341Sdelphij BN_CTX_free(new_ctx); 1206296341Sdelphij return ret; 1207296341Sdelphij} 1208109998Smarkm 1209296341Sdelphijint ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, 1210296341Sdelphij BN_CTX *ctx) 1211296341Sdelphij{ 1212296341Sdelphij BN_CTX *new_ctx = NULL; 1213296341Sdelphij BIGNUM *x, *y; 1214296341Sdelphij int ret = 0; 1215109998Smarkm 1216296341Sdelphij if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) 1217296341Sdelphij return 1; 1218109998Smarkm 1219296341Sdelphij if (ctx == NULL) { 1220296341Sdelphij ctx = new_ctx = BN_CTX_new(); 1221296341Sdelphij if (ctx == NULL) 1222296341Sdelphij return 0; 1223296341Sdelphij } 1224109998Smarkm 1225296341Sdelphij BN_CTX_start(ctx); 1226296341Sdelphij x = BN_CTX_get(ctx); 1227296341Sdelphij y = BN_CTX_get(ctx); 1228296341Sdelphij if (y == NULL) 1229296341Sdelphij goto err; 1230109998Smarkm 1231296341Sdelphij if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) 1232296341Sdelphij goto err; 1233296341Sdelphij if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) 1234296341Sdelphij goto err; 1235296341Sdelphij if (!point->Z_is_one) { 1236296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR); 1237296341Sdelphij goto err; 1238296341Sdelphij } 1239109998Smarkm 1240296341Sdelphij ret = 1; 1241109998Smarkm 1242109998Smarkm err: 1243296341Sdelphij BN_CTX_end(ctx); 1244296341Sdelphij if (new_ctx != NULL) 1245296341Sdelphij BN_CTX_free(new_ctx); 1246296341Sdelphij return ret; 1247296341Sdelphij} 1248109998Smarkm 1249296341Sdelphijint ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, 1250296341Sdelphij EC_POINT *points[], BN_CTX *ctx) 1251296341Sdelphij{ 1252296341Sdelphij BN_CTX *new_ctx = NULL; 1253296341Sdelphij BIGNUM *tmp, *tmp_Z; 1254296341Sdelphij BIGNUM **prod_Z = NULL; 1255296341Sdelphij size_t i; 1256296341Sdelphij int ret = 0; 1257109998Smarkm 1258296341Sdelphij if (num == 0) 1259296341Sdelphij return 1; 1260109998Smarkm 1261296341Sdelphij if (ctx == NULL) { 1262296341Sdelphij ctx = new_ctx = BN_CTX_new(); 1263296341Sdelphij if (ctx == NULL) 1264296341Sdelphij return 0; 1265296341Sdelphij } 1266109998Smarkm 1267296341Sdelphij BN_CTX_start(ctx); 1268296341Sdelphij tmp = BN_CTX_get(ctx); 1269296341Sdelphij tmp_Z = BN_CTX_get(ctx); 1270296341Sdelphij if (tmp == NULL || tmp_Z == NULL) 1271296341Sdelphij goto err; 1272109998Smarkm 1273296341Sdelphij prod_Z = OPENSSL_malloc(num * sizeof prod_Z[0]); 1274296341Sdelphij if (prod_Z == NULL) 1275296341Sdelphij goto err; 1276296341Sdelphij for (i = 0; i < num; i++) { 1277296341Sdelphij prod_Z[i] = BN_new(); 1278296341Sdelphij if (prod_Z[i] == NULL) 1279296341Sdelphij goto err; 1280296341Sdelphij } 1281109998Smarkm 1282296341Sdelphij /* 1283296341Sdelphij * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, 1284296341Sdelphij * skipping any zero-valued inputs (pretend that they're 1). 1285296341Sdelphij */ 1286109998Smarkm 1287296341Sdelphij if (!BN_is_zero(&points[0]->Z)) { 1288296341Sdelphij if (!BN_copy(prod_Z[0], &points[0]->Z)) 1289296341Sdelphij goto err; 1290296341Sdelphij } else { 1291296341Sdelphij if (group->meth->field_set_to_one != 0) { 1292296341Sdelphij if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) 1293296341Sdelphij goto err; 1294296341Sdelphij } else { 1295296341Sdelphij if (!BN_one(prod_Z[0])) 1296296341Sdelphij goto err; 1297296341Sdelphij } 1298296341Sdelphij } 1299109998Smarkm 1300296341Sdelphij for (i = 1; i < num; i++) { 1301296341Sdelphij if (!BN_is_zero(&points[i]->Z)) { 1302296341Sdelphij if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], 1303296341Sdelphij &points[i]->Z, ctx)) 1304296341Sdelphij goto err; 1305296341Sdelphij } else { 1306296341Sdelphij if (!BN_copy(prod_Z[i], prod_Z[i - 1])) 1307296341Sdelphij goto err; 1308296341Sdelphij } 1309296341Sdelphij } 1310109998Smarkm 1311296341Sdelphij /* 1312296341Sdelphij * Now use a single explicit inversion to replace every non-zero 1313296341Sdelphij * points[i]->Z by its inverse. 1314296341Sdelphij */ 1315269686Sjkim 1316296341Sdelphij if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { 1317296341Sdelphij ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB); 1318296341Sdelphij goto err; 1319296341Sdelphij } 1320296341Sdelphij if (group->meth->field_encode != 0) { 1321296341Sdelphij /* 1322296341Sdelphij * In the Montgomery case, we just turned R*H (representing H) into 1323296341Sdelphij * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to 1324296341Sdelphij * multiply by the Montgomery factor twice. 1325296341Sdelphij */ 1326296341Sdelphij if (!group->meth->field_encode(group, tmp, tmp, ctx)) 1327296341Sdelphij goto err; 1328296341Sdelphij if (!group->meth->field_encode(group, tmp, tmp, ctx)) 1329296341Sdelphij goto err; 1330296341Sdelphij } 1331269686Sjkim 1332296341Sdelphij for (i = num - 1; i > 0; --i) { 1333296341Sdelphij /* 1334296341Sdelphij * Loop invariant: tmp is the product of the inverses of points[0]->Z 1335296341Sdelphij * .. points[i]->Z (zero-valued inputs skipped). 1336296341Sdelphij */ 1337296341Sdelphij if (!BN_is_zero(&points[i]->Z)) { 1338296341Sdelphij /* 1339296341Sdelphij * Set tmp_Z to the inverse of points[i]->Z (as product of Z 1340296341Sdelphij * inverses 0 .. i, Z values 0 .. i - 1). 1341296341Sdelphij */ 1342296341Sdelphij if (!group-> 1343296341Sdelphij meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) 1344296341Sdelphij goto err; 1345296341Sdelphij /* 1346296341Sdelphij * Update tmp to satisfy the loop invariant for i - 1. 1347296341Sdelphij */ 1348296341Sdelphij if (!group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx)) 1349296341Sdelphij goto err; 1350296341Sdelphij /* Replace points[i]->Z by its inverse. */ 1351296341Sdelphij if (!BN_copy(&points[i]->Z, tmp_Z)) 1352296341Sdelphij goto err; 1353296341Sdelphij } 1354296341Sdelphij } 1355109998Smarkm 1356296341Sdelphij if (!BN_is_zero(&points[0]->Z)) { 1357296341Sdelphij /* Replace points[0]->Z by its inverse. */ 1358296341Sdelphij if (!BN_copy(&points[0]->Z, tmp)) 1359296341Sdelphij goto err; 1360296341Sdelphij } 1361109998Smarkm 1362296341Sdelphij /* Finally, fix up the X and Y coordinates for all points. */ 1363269686Sjkim 1364296341Sdelphij for (i = 0; i < num; i++) { 1365296341Sdelphij EC_POINT *p = points[i]; 1366269686Sjkim 1367296341Sdelphij if (!BN_is_zero(&p->Z)) { 1368296341Sdelphij /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ 1369269686Sjkim 1370296341Sdelphij if (!group->meth->field_sqr(group, tmp, &p->Z, ctx)) 1371296341Sdelphij goto err; 1372296341Sdelphij if (!group->meth->field_mul(group, &p->X, &p->X, tmp, ctx)) 1373296341Sdelphij goto err; 1374109998Smarkm 1375296341Sdelphij if (!group->meth->field_mul(group, tmp, tmp, &p->Z, ctx)) 1376296341Sdelphij goto err; 1377296341Sdelphij if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) 1378296341Sdelphij goto err; 1379109998Smarkm 1380296341Sdelphij if (group->meth->field_set_to_one != 0) { 1381296341Sdelphij if (!group->meth->field_set_to_one(group, &p->Z, ctx)) 1382296341Sdelphij goto err; 1383296341Sdelphij } else { 1384296341Sdelphij if (!BN_one(&p->Z)) 1385296341Sdelphij goto err; 1386296341Sdelphij } 1387296341Sdelphij p->Z_is_one = 1; 1388296341Sdelphij } 1389296341Sdelphij } 1390269686Sjkim 1391296341Sdelphij ret = 1; 1392109998Smarkm 1393109998Smarkm err: 1394296341Sdelphij BN_CTX_end(ctx); 1395296341Sdelphij if (new_ctx != NULL) 1396296341Sdelphij BN_CTX_free(new_ctx); 1397296341Sdelphij if (prod_Z != NULL) { 1398296341Sdelphij for (i = 0; i < num; i++) { 1399296341Sdelphij if (prod_Z[i] == NULL) 1400296341Sdelphij break; 1401296341Sdelphij BN_clear_free(prod_Z[i]); 1402296341Sdelphij } 1403296341Sdelphij OPENSSL_free(prod_Z); 1404296341Sdelphij } 1405296341Sdelphij return ret; 1406296341Sdelphij} 1407109998Smarkm 1408296341Sdelphijint ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1409296341Sdelphij const BIGNUM *b, BN_CTX *ctx) 1410296341Sdelphij{ 1411296341Sdelphij return BN_mod_mul(r, a, b, &group->field, ctx); 1412296341Sdelphij} 1413109998Smarkm 1414296341Sdelphijint ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1415296341Sdelphij BN_CTX *ctx) 1416296341Sdelphij{ 1417296341Sdelphij return BN_mod_sqr(r, a, &group->field, ctx); 1418296341Sdelphij} 1419