1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2001-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci */ 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ci/* 12e1051a39Sopenharmony_ci * ECDSA low level APIs are deprecated for public use, but still ok for 13e1051a39Sopenharmony_ci * internal use. 14e1051a39Sopenharmony_ci */ 15e1051a39Sopenharmony_ci#include "internal/deprecated.h" 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci#include <openssl/err.h> 18e1051a39Sopenharmony_ci#include <openssl/symhacks.h> 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_ci#include "ec_local.h" 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_ciconst EC_METHOD *EC_GFp_simple_method(void) 23e1051a39Sopenharmony_ci{ 24e1051a39Sopenharmony_ci static const EC_METHOD ret = { 25e1051a39Sopenharmony_ci EC_FLAGS_DEFAULT_OCT, 26e1051a39Sopenharmony_ci NID_X9_62_prime_field, 27e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_init, 28e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_finish, 29e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_clear_finish, 30e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_copy, 31e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_set_curve, 32e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_get_curve, 33e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_get_degree, 34e1051a39Sopenharmony_ci ossl_ec_group_simple_order_bits, 35e1051a39Sopenharmony_ci ossl_ec_GFp_simple_group_check_discriminant, 36e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_init, 37e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_finish, 38e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_clear_finish, 39e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_copy, 40e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_set_to_infinity, 41e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_set_affine_coordinates, 42e1051a39Sopenharmony_ci ossl_ec_GFp_simple_point_get_affine_coordinates, 43e1051a39Sopenharmony_ci 0, 0, 0, 44e1051a39Sopenharmony_ci ossl_ec_GFp_simple_add, 45e1051a39Sopenharmony_ci ossl_ec_GFp_simple_dbl, 46e1051a39Sopenharmony_ci ossl_ec_GFp_simple_invert, 47e1051a39Sopenharmony_ci ossl_ec_GFp_simple_is_at_infinity, 48e1051a39Sopenharmony_ci ossl_ec_GFp_simple_is_on_curve, 49e1051a39Sopenharmony_ci ossl_ec_GFp_simple_cmp, 50e1051a39Sopenharmony_ci ossl_ec_GFp_simple_make_affine, 51e1051a39Sopenharmony_ci ossl_ec_GFp_simple_points_make_affine, 52e1051a39Sopenharmony_ci 0 /* mul */ , 53e1051a39Sopenharmony_ci 0 /* precompute_mult */ , 54e1051a39Sopenharmony_ci 0 /* have_precompute_mult */ , 55e1051a39Sopenharmony_ci ossl_ec_GFp_simple_field_mul, 56e1051a39Sopenharmony_ci ossl_ec_GFp_simple_field_sqr, 57e1051a39Sopenharmony_ci 0 /* field_div */ , 58e1051a39Sopenharmony_ci ossl_ec_GFp_simple_field_inv, 59e1051a39Sopenharmony_ci 0 /* field_encode */ , 60e1051a39Sopenharmony_ci 0 /* field_decode */ , 61e1051a39Sopenharmony_ci 0, /* field_set_to_one */ 62e1051a39Sopenharmony_ci ossl_ec_key_simple_priv2oct, 63e1051a39Sopenharmony_ci ossl_ec_key_simple_oct2priv, 64e1051a39Sopenharmony_ci 0, /* set private */ 65e1051a39Sopenharmony_ci ossl_ec_key_simple_generate_key, 66e1051a39Sopenharmony_ci ossl_ec_key_simple_check_key, 67e1051a39Sopenharmony_ci ossl_ec_key_simple_generate_public_key, 68e1051a39Sopenharmony_ci 0, /* keycopy */ 69e1051a39Sopenharmony_ci 0, /* keyfinish */ 70e1051a39Sopenharmony_ci ossl_ecdh_simple_compute_key, 71e1051a39Sopenharmony_ci ossl_ecdsa_simple_sign_setup, 72e1051a39Sopenharmony_ci ossl_ecdsa_simple_sign_sig, 73e1051a39Sopenharmony_ci ossl_ecdsa_simple_verify_sig, 74e1051a39Sopenharmony_ci 0, /* field_inverse_mod_ord */ 75e1051a39Sopenharmony_ci ossl_ec_GFp_simple_blind_coordinates, 76e1051a39Sopenharmony_ci ossl_ec_GFp_simple_ladder_pre, 77e1051a39Sopenharmony_ci ossl_ec_GFp_simple_ladder_step, 78e1051a39Sopenharmony_ci ossl_ec_GFp_simple_ladder_post 79e1051a39Sopenharmony_ci }; 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_ci return &ret; 82e1051a39Sopenharmony_ci} 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci/* 85e1051a39Sopenharmony_ci * Most method functions in this file are designed to work with 86e1051a39Sopenharmony_ci * non-trivial representations of field elements if necessary 87e1051a39Sopenharmony_ci * (see ecp_mont.c): while standard modular addition and subtraction 88e1051a39Sopenharmony_ci * are used, the field_mul and field_sqr methods will be used for 89e1051a39Sopenharmony_ci * multiplication, and field_encode and field_decode (if defined) 90e1051a39Sopenharmony_ci * will be used for converting between representations. 91e1051a39Sopenharmony_ci * 92e1051a39Sopenharmony_ci * Functions ec_GFp_simple_points_make_affine() and 93e1051a39Sopenharmony_ci * ec_GFp_simple_point_get_affine_coordinates() specifically assume 94e1051a39Sopenharmony_ci * that if a non-trivial representation is used, it is a Montgomery 95e1051a39Sopenharmony_ci * representation (i.e. 'encoding' means multiplying by some factor R). 96e1051a39Sopenharmony_ci */ 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_init(EC_GROUP *group) 99e1051a39Sopenharmony_ci{ 100e1051a39Sopenharmony_ci group->field = BN_new(); 101e1051a39Sopenharmony_ci group->a = BN_new(); 102e1051a39Sopenharmony_ci group->b = BN_new(); 103e1051a39Sopenharmony_ci if (group->field == NULL || group->a == NULL || group->b == NULL) { 104e1051a39Sopenharmony_ci BN_free(group->field); 105e1051a39Sopenharmony_ci BN_free(group->a); 106e1051a39Sopenharmony_ci BN_free(group->b); 107e1051a39Sopenharmony_ci return 0; 108e1051a39Sopenharmony_ci } 109e1051a39Sopenharmony_ci group->a_is_minus3 = 0; 110e1051a39Sopenharmony_ci return 1; 111e1051a39Sopenharmony_ci} 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_group_finish(EC_GROUP *group) 114e1051a39Sopenharmony_ci{ 115e1051a39Sopenharmony_ci BN_free(group->field); 116e1051a39Sopenharmony_ci BN_free(group->a); 117e1051a39Sopenharmony_ci BN_free(group->b); 118e1051a39Sopenharmony_ci} 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_group_clear_finish(EC_GROUP *group) 121e1051a39Sopenharmony_ci{ 122e1051a39Sopenharmony_ci BN_clear_free(group->field); 123e1051a39Sopenharmony_ci BN_clear_free(group->a); 124e1051a39Sopenharmony_ci BN_clear_free(group->b); 125e1051a39Sopenharmony_ci} 126e1051a39Sopenharmony_ci 127e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) 128e1051a39Sopenharmony_ci{ 129e1051a39Sopenharmony_ci if (!BN_copy(dest->field, src->field)) 130e1051a39Sopenharmony_ci return 0; 131e1051a39Sopenharmony_ci if (!BN_copy(dest->a, src->a)) 132e1051a39Sopenharmony_ci return 0; 133e1051a39Sopenharmony_ci if (!BN_copy(dest->b, src->b)) 134e1051a39Sopenharmony_ci return 0; 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ci dest->a_is_minus3 = src->a_is_minus3; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci return 1; 139e1051a39Sopenharmony_ci} 140e1051a39Sopenharmony_ci 141e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_set_curve(EC_GROUP *group, 142e1051a39Sopenharmony_ci const BIGNUM *p, const BIGNUM *a, 143e1051a39Sopenharmony_ci const BIGNUM *b, BN_CTX *ctx) 144e1051a39Sopenharmony_ci{ 145e1051a39Sopenharmony_ci int ret = 0; 146e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 147e1051a39Sopenharmony_ci BIGNUM *tmp_a; 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci /* p must be a prime > 3 */ 150e1051a39Sopenharmony_ci if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { 151e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_INVALID_FIELD); 152e1051a39Sopenharmony_ci return 0; 153e1051a39Sopenharmony_ci } 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci if (ctx == NULL) { 156e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 157e1051a39Sopenharmony_ci if (ctx == NULL) 158e1051a39Sopenharmony_ci return 0; 159e1051a39Sopenharmony_ci } 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci BN_CTX_start(ctx); 162e1051a39Sopenharmony_ci tmp_a = BN_CTX_get(ctx); 163e1051a39Sopenharmony_ci if (tmp_a == NULL) 164e1051a39Sopenharmony_ci goto err; 165e1051a39Sopenharmony_ci 166e1051a39Sopenharmony_ci /* group->field */ 167e1051a39Sopenharmony_ci if (!BN_copy(group->field, p)) 168e1051a39Sopenharmony_ci goto err; 169e1051a39Sopenharmony_ci BN_set_negative(group->field, 0); 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci /* group->a */ 172e1051a39Sopenharmony_ci if (!BN_nnmod(tmp_a, a, p, ctx)) 173e1051a39Sopenharmony_ci goto err; 174e1051a39Sopenharmony_ci if (group->meth->field_encode) { 175e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, group->a, tmp_a, ctx)) 176e1051a39Sopenharmony_ci goto err; 177e1051a39Sopenharmony_ci } else if (!BN_copy(group->a, tmp_a)) 178e1051a39Sopenharmony_ci goto err; 179e1051a39Sopenharmony_ci 180e1051a39Sopenharmony_ci /* group->b */ 181e1051a39Sopenharmony_ci if (!BN_nnmod(group->b, b, p, ctx)) 182e1051a39Sopenharmony_ci goto err; 183e1051a39Sopenharmony_ci if (group->meth->field_encode) 184e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, group->b, group->b, ctx)) 185e1051a39Sopenharmony_ci goto err; 186e1051a39Sopenharmony_ci 187e1051a39Sopenharmony_ci /* group->a_is_minus3 */ 188e1051a39Sopenharmony_ci if (!BN_add_word(tmp_a, 3)) 189e1051a39Sopenharmony_ci goto err; 190e1051a39Sopenharmony_ci group->a_is_minus3 = (0 == BN_cmp(tmp_a, group->field)); 191e1051a39Sopenharmony_ci 192e1051a39Sopenharmony_ci ret = 1; 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_ci err: 195e1051a39Sopenharmony_ci BN_CTX_end(ctx); 196e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 197e1051a39Sopenharmony_ci return ret; 198e1051a39Sopenharmony_ci} 199e1051a39Sopenharmony_ci 200e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, 201e1051a39Sopenharmony_ci BIGNUM *a, BIGNUM *b, BN_CTX *ctx) 202e1051a39Sopenharmony_ci{ 203e1051a39Sopenharmony_ci int ret = 0; 204e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 205e1051a39Sopenharmony_ci 206e1051a39Sopenharmony_ci if (p != NULL) { 207e1051a39Sopenharmony_ci if (!BN_copy(p, group->field)) 208e1051a39Sopenharmony_ci return 0; 209e1051a39Sopenharmony_ci } 210e1051a39Sopenharmony_ci 211e1051a39Sopenharmony_ci if (a != NULL || b != NULL) { 212e1051a39Sopenharmony_ci if (group->meth->field_decode) { 213e1051a39Sopenharmony_ci if (ctx == NULL) { 214e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 215e1051a39Sopenharmony_ci if (ctx == NULL) 216e1051a39Sopenharmony_ci return 0; 217e1051a39Sopenharmony_ci } 218e1051a39Sopenharmony_ci if (a != NULL) { 219e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, a, group->a, ctx)) 220e1051a39Sopenharmony_ci goto err; 221e1051a39Sopenharmony_ci } 222e1051a39Sopenharmony_ci if (b != NULL) { 223e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, b, group->b, ctx)) 224e1051a39Sopenharmony_ci goto err; 225e1051a39Sopenharmony_ci } 226e1051a39Sopenharmony_ci } else { 227e1051a39Sopenharmony_ci if (a != NULL) { 228e1051a39Sopenharmony_ci if (!BN_copy(a, group->a)) 229e1051a39Sopenharmony_ci goto err; 230e1051a39Sopenharmony_ci } 231e1051a39Sopenharmony_ci if (b != NULL) { 232e1051a39Sopenharmony_ci if (!BN_copy(b, group->b)) 233e1051a39Sopenharmony_ci goto err; 234e1051a39Sopenharmony_ci } 235e1051a39Sopenharmony_ci } 236e1051a39Sopenharmony_ci } 237e1051a39Sopenharmony_ci 238e1051a39Sopenharmony_ci ret = 1; 239e1051a39Sopenharmony_ci 240e1051a39Sopenharmony_ci err: 241e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 242e1051a39Sopenharmony_ci return ret; 243e1051a39Sopenharmony_ci} 244e1051a39Sopenharmony_ci 245e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_get_degree(const EC_GROUP *group) 246e1051a39Sopenharmony_ci{ 247e1051a39Sopenharmony_ci return BN_num_bits(group->field); 248e1051a39Sopenharmony_ci} 249e1051a39Sopenharmony_ci 250e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, 251e1051a39Sopenharmony_ci BN_CTX *ctx) 252e1051a39Sopenharmony_ci{ 253e1051a39Sopenharmony_ci int ret = 0; 254e1051a39Sopenharmony_ci BIGNUM *a, *b, *order, *tmp_1, *tmp_2; 255e1051a39Sopenharmony_ci const BIGNUM *p = group->field; 256e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 257e1051a39Sopenharmony_ci 258e1051a39Sopenharmony_ci if (ctx == NULL) { 259e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 260e1051a39Sopenharmony_ci if (ctx == NULL) { 261e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); 262e1051a39Sopenharmony_ci goto err; 263e1051a39Sopenharmony_ci } 264e1051a39Sopenharmony_ci } 265e1051a39Sopenharmony_ci BN_CTX_start(ctx); 266e1051a39Sopenharmony_ci a = BN_CTX_get(ctx); 267e1051a39Sopenharmony_ci b = BN_CTX_get(ctx); 268e1051a39Sopenharmony_ci tmp_1 = BN_CTX_get(ctx); 269e1051a39Sopenharmony_ci tmp_2 = BN_CTX_get(ctx); 270e1051a39Sopenharmony_ci order = BN_CTX_get(ctx); 271e1051a39Sopenharmony_ci if (order == NULL) 272e1051a39Sopenharmony_ci goto err; 273e1051a39Sopenharmony_ci 274e1051a39Sopenharmony_ci if (group->meth->field_decode) { 275e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, a, group->a, ctx)) 276e1051a39Sopenharmony_ci goto err; 277e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, b, group->b, ctx)) 278e1051a39Sopenharmony_ci goto err; 279e1051a39Sopenharmony_ci } else { 280e1051a39Sopenharmony_ci if (!BN_copy(a, group->a)) 281e1051a39Sopenharmony_ci goto err; 282e1051a39Sopenharmony_ci if (!BN_copy(b, group->b)) 283e1051a39Sopenharmony_ci goto err; 284e1051a39Sopenharmony_ci } 285e1051a39Sopenharmony_ci 286e1051a39Sopenharmony_ci /*- 287e1051a39Sopenharmony_ci * check the discriminant: 288e1051a39Sopenharmony_ci * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) 289e1051a39Sopenharmony_ci * 0 =< a, b < p 290e1051a39Sopenharmony_ci */ 291e1051a39Sopenharmony_ci if (BN_is_zero(a)) { 292e1051a39Sopenharmony_ci if (BN_is_zero(b)) 293e1051a39Sopenharmony_ci goto err; 294e1051a39Sopenharmony_ci } else if (!BN_is_zero(b)) { 295e1051a39Sopenharmony_ci if (!BN_mod_sqr(tmp_1, a, p, ctx)) 296e1051a39Sopenharmony_ci goto err; 297e1051a39Sopenharmony_ci if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) 298e1051a39Sopenharmony_ci goto err; 299e1051a39Sopenharmony_ci if (!BN_lshift(tmp_1, tmp_2, 2)) 300e1051a39Sopenharmony_ci goto err; 301e1051a39Sopenharmony_ci /* tmp_1 = 4*a^3 */ 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci if (!BN_mod_sqr(tmp_2, b, p, ctx)) 304e1051a39Sopenharmony_ci goto err; 305e1051a39Sopenharmony_ci if (!BN_mul_word(tmp_2, 27)) 306e1051a39Sopenharmony_ci goto err; 307e1051a39Sopenharmony_ci /* tmp_2 = 27*b^2 */ 308e1051a39Sopenharmony_ci 309e1051a39Sopenharmony_ci if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) 310e1051a39Sopenharmony_ci goto err; 311e1051a39Sopenharmony_ci if (BN_is_zero(a)) 312e1051a39Sopenharmony_ci goto err; 313e1051a39Sopenharmony_ci } 314e1051a39Sopenharmony_ci ret = 1; 315e1051a39Sopenharmony_ci 316e1051a39Sopenharmony_ci err: 317e1051a39Sopenharmony_ci BN_CTX_end(ctx); 318e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 319e1051a39Sopenharmony_ci return ret; 320e1051a39Sopenharmony_ci} 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_init(EC_POINT *point) 323e1051a39Sopenharmony_ci{ 324e1051a39Sopenharmony_ci point->X = BN_new(); 325e1051a39Sopenharmony_ci point->Y = BN_new(); 326e1051a39Sopenharmony_ci point->Z = BN_new(); 327e1051a39Sopenharmony_ci point->Z_is_one = 0; 328e1051a39Sopenharmony_ci 329e1051a39Sopenharmony_ci if (point->X == NULL || point->Y == NULL || point->Z == NULL) { 330e1051a39Sopenharmony_ci BN_free(point->X); 331e1051a39Sopenharmony_ci BN_free(point->Y); 332e1051a39Sopenharmony_ci BN_free(point->Z); 333e1051a39Sopenharmony_ci return 0; 334e1051a39Sopenharmony_ci } 335e1051a39Sopenharmony_ci return 1; 336e1051a39Sopenharmony_ci} 337e1051a39Sopenharmony_ci 338e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_point_finish(EC_POINT *point) 339e1051a39Sopenharmony_ci{ 340e1051a39Sopenharmony_ci BN_free(point->X); 341e1051a39Sopenharmony_ci BN_free(point->Y); 342e1051a39Sopenharmony_ci BN_free(point->Z); 343e1051a39Sopenharmony_ci} 344e1051a39Sopenharmony_ci 345e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_point_clear_finish(EC_POINT *point) 346e1051a39Sopenharmony_ci{ 347e1051a39Sopenharmony_ci BN_clear_free(point->X); 348e1051a39Sopenharmony_ci BN_clear_free(point->Y); 349e1051a39Sopenharmony_ci BN_clear_free(point->Z); 350e1051a39Sopenharmony_ci point->Z_is_one = 0; 351e1051a39Sopenharmony_ci} 352e1051a39Sopenharmony_ci 353e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) 354e1051a39Sopenharmony_ci{ 355e1051a39Sopenharmony_ci if (!BN_copy(dest->X, src->X)) 356e1051a39Sopenharmony_ci return 0; 357e1051a39Sopenharmony_ci if (!BN_copy(dest->Y, src->Y)) 358e1051a39Sopenharmony_ci return 0; 359e1051a39Sopenharmony_ci if (!BN_copy(dest->Z, src->Z)) 360e1051a39Sopenharmony_ci return 0; 361e1051a39Sopenharmony_ci dest->Z_is_one = src->Z_is_one; 362e1051a39Sopenharmony_ci dest->curve_name = src->curve_name; 363e1051a39Sopenharmony_ci 364e1051a39Sopenharmony_ci return 1; 365e1051a39Sopenharmony_ci} 366e1051a39Sopenharmony_ci 367e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, 368e1051a39Sopenharmony_ci EC_POINT *point) 369e1051a39Sopenharmony_ci{ 370e1051a39Sopenharmony_ci point->Z_is_one = 0; 371e1051a39Sopenharmony_ci BN_zero(point->Z); 372e1051a39Sopenharmony_ci return 1; 373e1051a39Sopenharmony_ci} 374e1051a39Sopenharmony_ci 375e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group, 376e1051a39Sopenharmony_ci EC_POINT *point, 377e1051a39Sopenharmony_ci const BIGNUM *x, 378e1051a39Sopenharmony_ci const BIGNUM *y, 379e1051a39Sopenharmony_ci const BIGNUM *z, 380e1051a39Sopenharmony_ci BN_CTX *ctx) 381e1051a39Sopenharmony_ci{ 382e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 383e1051a39Sopenharmony_ci int ret = 0; 384e1051a39Sopenharmony_ci 385e1051a39Sopenharmony_ci if (ctx == NULL) { 386e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 387e1051a39Sopenharmony_ci if (ctx == NULL) 388e1051a39Sopenharmony_ci return 0; 389e1051a39Sopenharmony_ci } 390e1051a39Sopenharmony_ci 391e1051a39Sopenharmony_ci if (x != NULL) { 392e1051a39Sopenharmony_ci if (!BN_nnmod(point->X, x, group->field, ctx)) 393e1051a39Sopenharmony_ci goto err; 394e1051a39Sopenharmony_ci if (group->meth->field_encode) { 395e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, point->X, point->X, ctx)) 396e1051a39Sopenharmony_ci goto err; 397e1051a39Sopenharmony_ci } 398e1051a39Sopenharmony_ci } 399e1051a39Sopenharmony_ci 400e1051a39Sopenharmony_ci if (y != NULL) { 401e1051a39Sopenharmony_ci if (!BN_nnmod(point->Y, y, group->field, ctx)) 402e1051a39Sopenharmony_ci goto err; 403e1051a39Sopenharmony_ci if (group->meth->field_encode) { 404e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, point->Y, point->Y, ctx)) 405e1051a39Sopenharmony_ci goto err; 406e1051a39Sopenharmony_ci } 407e1051a39Sopenharmony_ci } 408e1051a39Sopenharmony_ci 409e1051a39Sopenharmony_ci if (z != NULL) { 410e1051a39Sopenharmony_ci int Z_is_one; 411e1051a39Sopenharmony_ci 412e1051a39Sopenharmony_ci if (!BN_nnmod(point->Z, z, group->field, ctx)) 413e1051a39Sopenharmony_ci goto err; 414e1051a39Sopenharmony_ci Z_is_one = BN_is_one(point->Z); 415e1051a39Sopenharmony_ci if (group->meth->field_encode) { 416e1051a39Sopenharmony_ci if (Z_is_one && (group->meth->field_set_to_one != 0)) { 417e1051a39Sopenharmony_ci if (!group->meth->field_set_to_one(group, point->Z, ctx)) 418e1051a39Sopenharmony_ci goto err; 419e1051a39Sopenharmony_ci } else { 420e1051a39Sopenharmony_ci if (!group-> 421e1051a39Sopenharmony_ci meth->field_encode(group, point->Z, point->Z, ctx)) 422e1051a39Sopenharmony_ci goto err; 423e1051a39Sopenharmony_ci } 424e1051a39Sopenharmony_ci } 425e1051a39Sopenharmony_ci point->Z_is_one = Z_is_one; 426e1051a39Sopenharmony_ci } 427e1051a39Sopenharmony_ci 428e1051a39Sopenharmony_ci ret = 1; 429e1051a39Sopenharmony_ci 430e1051a39Sopenharmony_ci err: 431e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 432e1051a39Sopenharmony_ci return ret; 433e1051a39Sopenharmony_ci} 434e1051a39Sopenharmony_ci 435e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, 436e1051a39Sopenharmony_ci const EC_POINT *point, 437e1051a39Sopenharmony_ci BIGNUM *x, BIGNUM *y, 438e1051a39Sopenharmony_ci BIGNUM *z, BN_CTX *ctx) 439e1051a39Sopenharmony_ci{ 440e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 441e1051a39Sopenharmony_ci int ret = 0; 442e1051a39Sopenharmony_ci 443e1051a39Sopenharmony_ci if (group->meth->field_decode != 0) { 444e1051a39Sopenharmony_ci if (ctx == NULL) { 445e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 446e1051a39Sopenharmony_ci if (ctx == NULL) 447e1051a39Sopenharmony_ci return 0; 448e1051a39Sopenharmony_ci } 449e1051a39Sopenharmony_ci 450e1051a39Sopenharmony_ci if (x != NULL) { 451e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, x, point->X, ctx)) 452e1051a39Sopenharmony_ci goto err; 453e1051a39Sopenharmony_ci } 454e1051a39Sopenharmony_ci if (y != NULL) { 455e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, y, point->Y, ctx)) 456e1051a39Sopenharmony_ci goto err; 457e1051a39Sopenharmony_ci } 458e1051a39Sopenharmony_ci if (z != NULL) { 459e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, z, point->Z, ctx)) 460e1051a39Sopenharmony_ci goto err; 461e1051a39Sopenharmony_ci } 462e1051a39Sopenharmony_ci } else { 463e1051a39Sopenharmony_ci if (x != NULL) { 464e1051a39Sopenharmony_ci if (!BN_copy(x, point->X)) 465e1051a39Sopenharmony_ci goto err; 466e1051a39Sopenharmony_ci } 467e1051a39Sopenharmony_ci if (y != NULL) { 468e1051a39Sopenharmony_ci if (!BN_copy(y, point->Y)) 469e1051a39Sopenharmony_ci goto err; 470e1051a39Sopenharmony_ci } 471e1051a39Sopenharmony_ci if (z != NULL) { 472e1051a39Sopenharmony_ci if (!BN_copy(z, point->Z)) 473e1051a39Sopenharmony_ci goto err; 474e1051a39Sopenharmony_ci } 475e1051a39Sopenharmony_ci } 476e1051a39Sopenharmony_ci 477e1051a39Sopenharmony_ci ret = 1; 478e1051a39Sopenharmony_ci 479e1051a39Sopenharmony_ci err: 480e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 481e1051a39Sopenharmony_ci return ret; 482e1051a39Sopenharmony_ci} 483e1051a39Sopenharmony_ci 484e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, 485e1051a39Sopenharmony_ci EC_POINT *point, 486e1051a39Sopenharmony_ci const BIGNUM *x, 487e1051a39Sopenharmony_ci const BIGNUM *y, BN_CTX *ctx) 488e1051a39Sopenharmony_ci{ 489e1051a39Sopenharmony_ci if (x == NULL || y == NULL) { 490e1051a39Sopenharmony_ci /* 491e1051a39Sopenharmony_ci * unlike for projective coordinates, we do not tolerate this 492e1051a39Sopenharmony_ci */ 493e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_PASSED_NULL_PARAMETER); 494e1051a39Sopenharmony_ci return 0; 495e1051a39Sopenharmony_ci } 496e1051a39Sopenharmony_ci 497e1051a39Sopenharmony_ci return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, 498e1051a39Sopenharmony_ci BN_value_one(), ctx); 499e1051a39Sopenharmony_ci} 500e1051a39Sopenharmony_ci 501e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, 502e1051a39Sopenharmony_ci const EC_POINT *point, 503e1051a39Sopenharmony_ci BIGNUM *x, BIGNUM *y, 504e1051a39Sopenharmony_ci BN_CTX *ctx) 505e1051a39Sopenharmony_ci{ 506e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 507e1051a39Sopenharmony_ci BIGNUM *Z, *Z_1, *Z_2, *Z_3; 508e1051a39Sopenharmony_ci const BIGNUM *Z_; 509e1051a39Sopenharmony_ci int ret = 0; 510e1051a39Sopenharmony_ci 511e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point)) { 512e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_POINT_AT_INFINITY); 513e1051a39Sopenharmony_ci return 0; 514e1051a39Sopenharmony_ci } 515e1051a39Sopenharmony_ci 516e1051a39Sopenharmony_ci if (ctx == NULL) { 517e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 518e1051a39Sopenharmony_ci if (ctx == NULL) 519e1051a39Sopenharmony_ci return 0; 520e1051a39Sopenharmony_ci } 521e1051a39Sopenharmony_ci 522e1051a39Sopenharmony_ci BN_CTX_start(ctx); 523e1051a39Sopenharmony_ci Z = BN_CTX_get(ctx); 524e1051a39Sopenharmony_ci Z_1 = BN_CTX_get(ctx); 525e1051a39Sopenharmony_ci Z_2 = BN_CTX_get(ctx); 526e1051a39Sopenharmony_ci Z_3 = BN_CTX_get(ctx); 527e1051a39Sopenharmony_ci if (Z_3 == NULL) 528e1051a39Sopenharmony_ci goto err; 529e1051a39Sopenharmony_ci 530e1051a39Sopenharmony_ci /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ 531e1051a39Sopenharmony_ci 532e1051a39Sopenharmony_ci if (group->meth->field_decode) { 533e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, Z, point->Z, ctx)) 534e1051a39Sopenharmony_ci goto err; 535e1051a39Sopenharmony_ci Z_ = Z; 536e1051a39Sopenharmony_ci } else { 537e1051a39Sopenharmony_ci Z_ = point->Z; 538e1051a39Sopenharmony_ci } 539e1051a39Sopenharmony_ci 540e1051a39Sopenharmony_ci if (BN_is_one(Z_)) { 541e1051a39Sopenharmony_ci if (group->meth->field_decode) { 542e1051a39Sopenharmony_ci if (x != NULL) { 543e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, x, point->X, ctx)) 544e1051a39Sopenharmony_ci goto err; 545e1051a39Sopenharmony_ci } 546e1051a39Sopenharmony_ci if (y != NULL) { 547e1051a39Sopenharmony_ci if (!group->meth->field_decode(group, y, point->Y, ctx)) 548e1051a39Sopenharmony_ci goto err; 549e1051a39Sopenharmony_ci } 550e1051a39Sopenharmony_ci } else { 551e1051a39Sopenharmony_ci if (x != NULL) { 552e1051a39Sopenharmony_ci if (!BN_copy(x, point->X)) 553e1051a39Sopenharmony_ci goto err; 554e1051a39Sopenharmony_ci } 555e1051a39Sopenharmony_ci if (y != NULL) { 556e1051a39Sopenharmony_ci if (!BN_copy(y, point->Y)) 557e1051a39Sopenharmony_ci goto err; 558e1051a39Sopenharmony_ci } 559e1051a39Sopenharmony_ci } 560e1051a39Sopenharmony_ci } else { 561e1051a39Sopenharmony_ci if (!group->meth->field_inv(group, Z_1, Z_, ctx)) { 562e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); 563e1051a39Sopenharmony_ci goto err; 564e1051a39Sopenharmony_ci } 565e1051a39Sopenharmony_ci 566e1051a39Sopenharmony_ci if (group->meth->field_encode == 0) { 567e1051a39Sopenharmony_ci /* field_sqr works on standard representation */ 568e1051a39Sopenharmony_ci if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) 569e1051a39Sopenharmony_ci goto err; 570e1051a39Sopenharmony_ci } else { 571e1051a39Sopenharmony_ci if (!BN_mod_sqr(Z_2, Z_1, group->field, ctx)) 572e1051a39Sopenharmony_ci goto err; 573e1051a39Sopenharmony_ci } 574e1051a39Sopenharmony_ci 575e1051a39Sopenharmony_ci if (x != NULL) { 576e1051a39Sopenharmony_ci /* 577e1051a39Sopenharmony_ci * in the Montgomery case, field_mul will cancel out Montgomery 578e1051a39Sopenharmony_ci * factor in X: 579e1051a39Sopenharmony_ci */ 580e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, x, point->X, Z_2, ctx)) 581e1051a39Sopenharmony_ci goto err; 582e1051a39Sopenharmony_ci } 583e1051a39Sopenharmony_ci 584e1051a39Sopenharmony_ci if (y != NULL) { 585e1051a39Sopenharmony_ci if (group->meth->field_encode == 0) { 586e1051a39Sopenharmony_ci /* 587e1051a39Sopenharmony_ci * field_mul works on standard representation 588e1051a39Sopenharmony_ci */ 589e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) 590e1051a39Sopenharmony_ci goto err; 591e1051a39Sopenharmony_ci } else { 592e1051a39Sopenharmony_ci if (!BN_mod_mul(Z_3, Z_2, Z_1, group->field, ctx)) 593e1051a39Sopenharmony_ci goto err; 594e1051a39Sopenharmony_ci } 595e1051a39Sopenharmony_ci 596e1051a39Sopenharmony_ci /* 597e1051a39Sopenharmony_ci * in the Montgomery case, field_mul will cancel out Montgomery 598e1051a39Sopenharmony_ci * factor in Y: 599e1051a39Sopenharmony_ci */ 600e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, y, point->Y, Z_3, ctx)) 601e1051a39Sopenharmony_ci goto err; 602e1051a39Sopenharmony_ci } 603e1051a39Sopenharmony_ci } 604e1051a39Sopenharmony_ci 605e1051a39Sopenharmony_ci ret = 1; 606e1051a39Sopenharmony_ci 607e1051a39Sopenharmony_ci err: 608e1051a39Sopenharmony_ci BN_CTX_end(ctx); 609e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 610e1051a39Sopenharmony_ci return ret; 611e1051a39Sopenharmony_ci} 612e1051a39Sopenharmony_ci 613e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 614e1051a39Sopenharmony_ci const EC_POINT *b, BN_CTX *ctx) 615e1051a39Sopenharmony_ci{ 616e1051a39Sopenharmony_ci int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 617e1051a39Sopenharmony_ci const BIGNUM *, BN_CTX *); 618e1051a39Sopenharmony_ci int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 619e1051a39Sopenharmony_ci const BIGNUM *p; 620e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 621e1051a39Sopenharmony_ci BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; 622e1051a39Sopenharmony_ci int ret = 0; 623e1051a39Sopenharmony_ci 624e1051a39Sopenharmony_ci if (a == b) 625e1051a39Sopenharmony_ci return EC_POINT_dbl(group, r, a, ctx); 626e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, a)) 627e1051a39Sopenharmony_ci return EC_POINT_copy(r, b); 628e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, b)) 629e1051a39Sopenharmony_ci return EC_POINT_copy(r, a); 630e1051a39Sopenharmony_ci 631e1051a39Sopenharmony_ci field_mul = group->meth->field_mul; 632e1051a39Sopenharmony_ci field_sqr = group->meth->field_sqr; 633e1051a39Sopenharmony_ci p = group->field; 634e1051a39Sopenharmony_ci 635e1051a39Sopenharmony_ci if (ctx == NULL) { 636e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 637e1051a39Sopenharmony_ci if (ctx == NULL) 638e1051a39Sopenharmony_ci return 0; 639e1051a39Sopenharmony_ci } 640e1051a39Sopenharmony_ci 641e1051a39Sopenharmony_ci BN_CTX_start(ctx); 642e1051a39Sopenharmony_ci n0 = BN_CTX_get(ctx); 643e1051a39Sopenharmony_ci n1 = BN_CTX_get(ctx); 644e1051a39Sopenharmony_ci n2 = BN_CTX_get(ctx); 645e1051a39Sopenharmony_ci n3 = BN_CTX_get(ctx); 646e1051a39Sopenharmony_ci n4 = BN_CTX_get(ctx); 647e1051a39Sopenharmony_ci n5 = BN_CTX_get(ctx); 648e1051a39Sopenharmony_ci n6 = BN_CTX_get(ctx); 649e1051a39Sopenharmony_ci if (n6 == NULL) 650e1051a39Sopenharmony_ci goto end; 651e1051a39Sopenharmony_ci 652e1051a39Sopenharmony_ci /* 653e1051a39Sopenharmony_ci * Note that in this function we must not read components of 'a' or 'b' 654e1051a39Sopenharmony_ci * once we have written the corresponding components of 'r'. ('r' might 655e1051a39Sopenharmony_ci * be one of 'a' or 'b'.) 656e1051a39Sopenharmony_ci */ 657e1051a39Sopenharmony_ci 658e1051a39Sopenharmony_ci /* n1, n2 */ 659e1051a39Sopenharmony_ci if (b->Z_is_one) { 660e1051a39Sopenharmony_ci if (!BN_copy(n1, a->X)) 661e1051a39Sopenharmony_ci goto end; 662e1051a39Sopenharmony_ci if (!BN_copy(n2, a->Y)) 663e1051a39Sopenharmony_ci goto end; 664e1051a39Sopenharmony_ci /* n1 = X_a */ 665e1051a39Sopenharmony_ci /* n2 = Y_a */ 666e1051a39Sopenharmony_ci } else { 667e1051a39Sopenharmony_ci if (!field_sqr(group, n0, b->Z, ctx)) 668e1051a39Sopenharmony_ci goto end; 669e1051a39Sopenharmony_ci if (!field_mul(group, n1, a->X, n0, ctx)) 670e1051a39Sopenharmony_ci goto end; 671e1051a39Sopenharmony_ci /* n1 = X_a * Z_b^2 */ 672e1051a39Sopenharmony_ci 673e1051a39Sopenharmony_ci if (!field_mul(group, n0, n0, b->Z, ctx)) 674e1051a39Sopenharmony_ci goto end; 675e1051a39Sopenharmony_ci if (!field_mul(group, n2, a->Y, n0, ctx)) 676e1051a39Sopenharmony_ci goto end; 677e1051a39Sopenharmony_ci /* n2 = Y_a * Z_b^3 */ 678e1051a39Sopenharmony_ci } 679e1051a39Sopenharmony_ci 680e1051a39Sopenharmony_ci /* n3, n4 */ 681e1051a39Sopenharmony_ci if (a->Z_is_one) { 682e1051a39Sopenharmony_ci if (!BN_copy(n3, b->X)) 683e1051a39Sopenharmony_ci goto end; 684e1051a39Sopenharmony_ci if (!BN_copy(n4, b->Y)) 685e1051a39Sopenharmony_ci goto end; 686e1051a39Sopenharmony_ci /* n3 = X_b */ 687e1051a39Sopenharmony_ci /* n4 = Y_b */ 688e1051a39Sopenharmony_ci } else { 689e1051a39Sopenharmony_ci if (!field_sqr(group, n0, a->Z, ctx)) 690e1051a39Sopenharmony_ci goto end; 691e1051a39Sopenharmony_ci if (!field_mul(group, n3, b->X, n0, ctx)) 692e1051a39Sopenharmony_ci goto end; 693e1051a39Sopenharmony_ci /* n3 = X_b * Z_a^2 */ 694e1051a39Sopenharmony_ci 695e1051a39Sopenharmony_ci if (!field_mul(group, n0, n0, a->Z, ctx)) 696e1051a39Sopenharmony_ci goto end; 697e1051a39Sopenharmony_ci if (!field_mul(group, n4, b->Y, n0, ctx)) 698e1051a39Sopenharmony_ci goto end; 699e1051a39Sopenharmony_ci /* n4 = Y_b * Z_a^3 */ 700e1051a39Sopenharmony_ci } 701e1051a39Sopenharmony_ci 702e1051a39Sopenharmony_ci /* n5, n6 */ 703e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n5, n1, n3, p)) 704e1051a39Sopenharmony_ci goto end; 705e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n6, n2, n4, p)) 706e1051a39Sopenharmony_ci goto end; 707e1051a39Sopenharmony_ci /* n5 = n1 - n3 */ 708e1051a39Sopenharmony_ci /* n6 = n2 - n4 */ 709e1051a39Sopenharmony_ci 710e1051a39Sopenharmony_ci if (BN_is_zero(n5)) { 711e1051a39Sopenharmony_ci if (BN_is_zero(n6)) { 712e1051a39Sopenharmony_ci /* a is the same point as b */ 713e1051a39Sopenharmony_ci BN_CTX_end(ctx); 714e1051a39Sopenharmony_ci ret = EC_POINT_dbl(group, r, a, ctx); 715e1051a39Sopenharmony_ci ctx = NULL; 716e1051a39Sopenharmony_ci goto end; 717e1051a39Sopenharmony_ci } else { 718e1051a39Sopenharmony_ci /* a is the inverse of b */ 719e1051a39Sopenharmony_ci BN_zero(r->Z); 720e1051a39Sopenharmony_ci r->Z_is_one = 0; 721e1051a39Sopenharmony_ci ret = 1; 722e1051a39Sopenharmony_ci goto end; 723e1051a39Sopenharmony_ci } 724e1051a39Sopenharmony_ci } 725e1051a39Sopenharmony_ci 726e1051a39Sopenharmony_ci /* 'n7', 'n8' */ 727e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n1, n1, n3, p)) 728e1051a39Sopenharmony_ci goto end; 729e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n2, n2, n4, p)) 730e1051a39Sopenharmony_ci goto end; 731e1051a39Sopenharmony_ci /* 'n7' = n1 + n3 */ 732e1051a39Sopenharmony_ci /* 'n8' = n2 + n4 */ 733e1051a39Sopenharmony_ci 734e1051a39Sopenharmony_ci /* Z_r */ 735e1051a39Sopenharmony_ci if (a->Z_is_one && b->Z_is_one) { 736e1051a39Sopenharmony_ci if (!BN_copy(r->Z, n5)) 737e1051a39Sopenharmony_ci goto end; 738e1051a39Sopenharmony_ci } else { 739e1051a39Sopenharmony_ci if (a->Z_is_one) { 740e1051a39Sopenharmony_ci if (!BN_copy(n0, b->Z)) 741e1051a39Sopenharmony_ci goto end; 742e1051a39Sopenharmony_ci } else if (b->Z_is_one) { 743e1051a39Sopenharmony_ci if (!BN_copy(n0, a->Z)) 744e1051a39Sopenharmony_ci goto end; 745e1051a39Sopenharmony_ci } else { 746e1051a39Sopenharmony_ci if (!field_mul(group, n0, a->Z, b->Z, ctx)) 747e1051a39Sopenharmony_ci goto end; 748e1051a39Sopenharmony_ci } 749e1051a39Sopenharmony_ci if (!field_mul(group, r->Z, n0, n5, ctx)) 750e1051a39Sopenharmony_ci goto end; 751e1051a39Sopenharmony_ci } 752e1051a39Sopenharmony_ci r->Z_is_one = 0; 753e1051a39Sopenharmony_ci /* Z_r = Z_a * Z_b * n5 */ 754e1051a39Sopenharmony_ci 755e1051a39Sopenharmony_ci /* X_r */ 756e1051a39Sopenharmony_ci if (!field_sqr(group, n0, n6, ctx)) 757e1051a39Sopenharmony_ci goto end; 758e1051a39Sopenharmony_ci if (!field_sqr(group, n4, n5, ctx)) 759e1051a39Sopenharmony_ci goto end; 760e1051a39Sopenharmony_ci if (!field_mul(group, n3, n1, n4, ctx)) 761e1051a39Sopenharmony_ci goto end; 762e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(r->X, n0, n3, p)) 763e1051a39Sopenharmony_ci goto end; 764e1051a39Sopenharmony_ci /* X_r = n6^2 - n5^2 * 'n7' */ 765e1051a39Sopenharmony_ci 766e1051a39Sopenharmony_ci /* 'n9' */ 767e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(n0, r->X, p)) 768e1051a39Sopenharmony_ci goto end; 769e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n0, n3, n0, p)) 770e1051a39Sopenharmony_ci goto end; 771e1051a39Sopenharmony_ci /* n9 = n5^2 * 'n7' - 2 * X_r */ 772e1051a39Sopenharmony_ci 773e1051a39Sopenharmony_ci /* Y_r */ 774e1051a39Sopenharmony_ci if (!field_mul(group, n0, n0, n6, ctx)) 775e1051a39Sopenharmony_ci goto end; 776e1051a39Sopenharmony_ci if (!field_mul(group, n5, n4, n5, ctx)) 777e1051a39Sopenharmony_ci goto end; /* now n5 is n5^3 */ 778e1051a39Sopenharmony_ci if (!field_mul(group, n1, n2, n5, ctx)) 779e1051a39Sopenharmony_ci goto end; 780e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n0, n0, n1, p)) 781e1051a39Sopenharmony_ci goto end; 782e1051a39Sopenharmony_ci if (BN_is_odd(n0)) 783e1051a39Sopenharmony_ci if (!BN_add(n0, n0, p)) 784e1051a39Sopenharmony_ci goto end; 785e1051a39Sopenharmony_ci /* now 0 <= n0 < 2*p, and n0 is even */ 786e1051a39Sopenharmony_ci if (!BN_rshift1(r->Y, n0)) 787e1051a39Sopenharmony_ci goto end; 788e1051a39Sopenharmony_ci /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ 789e1051a39Sopenharmony_ci 790e1051a39Sopenharmony_ci ret = 1; 791e1051a39Sopenharmony_ci 792e1051a39Sopenharmony_ci end: 793e1051a39Sopenharmony_ci BN_CTX_end(ctx); 794e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 795e1051a39Sopenharmony_ci return ret; 796e1051a39Sopenharmony_ci} 797e1051a39Sopenharmony_ci 798e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, 799e1051a39Sopenharmony_ci BN_CTX *ctx) 800e1051a39Sopenharmony_ci{ 801e1051a39Sopenharmony_ci int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 802e1051a39Sopenharmony_ci const BIGNUM *, BN_CTX *); 803e1051a39Sopenharmony_ci int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 804e1051a39Sopenharmony_ci const BIGNUM *p; 805e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 806e1051a39Sopenharmony_ci BIGNUM *n0, *n1, *n2, *n3; 807e1051a39Sopenharmony_ci int ret = 0; 808e1051a39Sopenharmony_ci 809e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, a)) { 810e1051a39Sopenharmony_ci BN_zero(r->Z); 811e1051a39Sopenharmony_ci r->Z_is_one = 0; 812e1051a39Sopenharmony_ci return 1; 813e1051a39Sopenharmony_ci } 814e1051a39Sopenharmony_ci 815e1051a39Sopenharmony_ci field_mul = group->meth->field_mul; 816e1051a39Sopenharmony_ci field_sqr = group->meth->field_sqr; 817e1051a39Sopenharmony_ci p = group->field; 818e1051a39Sopenharmony_ci 819e1051a39Sopenharmony_ci if (ctx == NULL) { 820e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 821e1051a39Sopenharmony_ci if (ctx == NULL) 822e1051a39Sopenharmony_ci return 0; 823e1051a39Sopenharmony_ci } 824e1051a39Sopenharmony_ci 825e1051a39Sopenharmony_ci BN_CTX_start(ctx); 826e1051a39Sopenharmony_ci n0 = BN_CTX_get(ctx); 827e1051a39Sopenharmony_ci n1 = BN_CTX_get(ctx); 828e1051a39Sopenharmony_ci n2 = BN_CTX_get(ctx); 829e1051a39Sopenharmony_ci n3 = BN_CTX_get(ctx); 830e1051a39Sopenharmony_ci if (n3 == NULL) 831e1051a39Sopenharmony_ci goto err; 832e1051a39Sopenharmony_ci 833e1051a39Sopenharmony_ci /* 834e1051a39Sopenharmony_ci * Note that in this function we must not read components of 'a' once we 835e1051a39Sopenharmony_ci * have written the corresponding components of 'r'. ('r' might the same 836e1051a39Sopenharmony_ci * as 'a'.) 837e1051a39Sopenharmony_ci */ 838e1051a39Sopenharmony_ci 839e1051a39Sopenharmony_ci /* n1 */ 840e1051a39Sopenharmony_ci if (a->Z_is_one) { 841e1051a39Sopenharmony_ci if (!field_sqr(group, n0, a->X, ctx)) 842e1051a39Sopenharmony_ci goto err; 843e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(n1, n0, p)) 844e1051a39Sopenharmony_ci goto err; 845e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n0, n0, n1, p)) 846e1051a39Sopenharmony_ci goto err; 847e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n1, n0, group->a, p)) 848e1051a39Sopenharmony_ci goto err; 849e1051a39Sopenharmony_ci /* n1 = 3 * X_a^2 + a_curve */ 850e1051a39Sopenharmony_ci } else if (group->a_is_minus3) { 851e1051a39Sopenharmony_ci if (!field_sqr(group, n1, a->Z, ctx)) 852e1051a39Sopenharmony_ci goto err; 853e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n0, a->X, n1, p)) 854e1051a39Sopenharmony_ci goto err; 855e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n2, a->X, n1, p)) 856e1051a39Sopenharmony_ci goto err; 857e1051a39Sopenharmony_ci if (!field_mul(group, n1, n0, n2, ctx)) 858e1051a39Sopenharmony_ci goto err; 859e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(n0, n1, p)) 860e1051a39Sopenharmony_ci goto err; 861e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n1, n0, n1, p)) 862e1051a39Sopenharmony_ci goto err; 863e1051a39Sopenharmony_ci /*- 864e1051a39Sopenharmony_ci * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) 865e1051a39Sopenharmony_ci * = 3 * X_a^2 - 3 * Z_a^4 866e1051a39Sopenharmony_ci */ 867e1051a39Sopenharmony_ci } else { 868e1051a39Sopenharmony_ci if (!field_sqr(group, n0, a->X, ctx)) 869e1051a39Sopenharmony_ci goto err; 870e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(n1, n0, p)) 871e1051a39Sopenharmony_ci goto err; 872e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n0, n0, n1, p)) 873e1051a39Sopenharmony_ci goto err; 874e1051a39Sopenharmony_ci if (!field_sqr(group, n1, a->Z, ctx)) 875e1051a39Sopenharmony_ci goto err; 876e1051a39Sopenharmony_ci if (!field_sqr(group, n1, n1, ctx)) 877e1051a39Sopenharmony_ci goto err; 878e1051a39Sopenharmony_ci if (!field_mul(group, n1, n1, group->a, ctx)) 879e1051a39Sopenharmony_ci goto err; 880e1051a39Sopenharmony_ci if (!BN_mod_add_quick(n1, n1, n0, p)) 881e1051a39Sopenharmony_ci goto err; 882e1051a39Sopenharmony_ci /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ 883e1051a39Sopenharmony_ci } 884e1051a39Sopenharmony_ci 885e1051a39Sopenharmony_ci /* Z_r */ 886e1051a39Sopenharmony_ci if (a->Z_is_one) { 887e1051a39Sopenharmony_ci if (!BN_copy(n0, a->Y)) 888e1051a39Sopenharmony_ci goto err; 889e1051a39Sopenharmony_ci } else { 890e1051a39Sopenharmony_ci if (!field_mul(group, n0, a->Y, a->Z, ctx)) 891e1051a39Sopenharmony_ci goto err; 892e1051a39Sopenharmony_ci } 893e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(r->Z, n0, p)) 894e1051a39Sopenharmony_ci goto err; 895e1051a39Sopenharmony_ci r->Z_is_one = 0; 896e1051a39Sopenharmony_ci /* Z_r = 2 * Y_a * Z_a */ 897e1051a39Sopenharmony_ci 898e1051a39Sopenharmony_ci /* n2 */ 899e1051a39Sopenharmony_ci if (!field_sqr(group, n3, a->Y, ctx)) 900e1051a39Sopenharmony_ci goto err; 901e1051a39Sopenharmony_ci if (!field_mul(group, n2, a->X, n3, ctx)) 902e1051a39Sopenharmony_ci goto err; 903e1051a39Sopenharmony_ci if (!BN_mod_lshift_quick(n2, n2, 2, p)) 904e1051a39Sopenharmony_ci goto err; 905e1051a39Sopenharmony_ci /* n2 = 4 * X_a * Y_a^2 */ 906e1051a39Sopenharmony_ci 907e1051a39Sopenharmony_ci /* X_r */ 908e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(n0, n2, p)) 909e1051a39Sopenharmony_ci goto err; 910e1051a39Sopenharmony_ci if (!field_sqr(group, r->X, n1, ctx)) 911e1051a39Sopenharmony_ci goto err; 912e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(r->X, r->X, n0, p)) 913e1051a39Sopenharmony_ci goto err; 914e1051a39Sopenharmony_ci /* X_r = n1^2 - 2 * n2 */ 915e1051a39Sopenharmony_ci 916e1051a39Sopenharmony_ci /* n3 */ 917e1051a39Sopenharmony_ci if (!field_sqr(group, n0, n3, ctx)) 918e1051a39Sopenharmony_ci goto err; 919e1051a39Sopenharmony_ci if (!BN_mod_lshift_quick(n3, n0, 3, p)) 920e1051a39Sopenharmony_ci goto err; 921e1051a39Sopenharmony_ci /* n3 = 8 * Y_a^4 */ 922e1051a39Sopenharmony_ci 923e1051a39Sopenharmony_ci /* Y_r */ 924e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(n0, n2, r->X, p)) 925e1051a39Sopenharmony_ci goto err; 926e1051a39Sopenharmony_ci if (!field_mul(group, n0, n1, n0, ctx)) 927e1051a39Sopenharmony_ci goto err; 928e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(r->Y, n0, n3, p)) 929e1051a39Sopenharmony_ci goto err; 930e1051a39Sopenharmony_ci /* Y_r = n1 * (n2 - X_r) - n3 */ 931e1051a39Sopenharmony_ci 932e1051a39Sopenharmony_ci ret = 1; 933e1051a39Sopenharmony_ci 934e1051a39Sopenharmony_ci err: 935e1051a39Sopenharmony_ci BN_CTX_end(ctx); 936e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 937e1051a39Sopenharmony_ci return ret; 938e1051a39Sopenharmony_ci} 939e1051a39Sopenharmony_ci 940e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, 941e1051a39Sopenharmony_ci BN_CTX *ctx) 942e1051a39Sopenharmony_ci{ 943e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y)) 944e1051a39Sopenharmony_ci /* point is its own inverse */ 945e1051a39Sopenharmony_ci return 1; 946e1051a39Sopenharmony_ci 947e1051a39Sopenharmony_ci return BN_usub(point->Y, group->field, point->Y); 948e1051a39Sopenharmony_ci} 949e1051a39Sopenharmony_ci 950e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_is_at_infinity(const EC_GROUP *group, 951e1051a39Sopenharmony_ci const EC_POINT *point) 952e1051a39Sopenharmony_ci{ 953e1051a39Sopenharmony_ci return BN_is_zero(point->Z); 954e1051a39Sopenharmony_ci} 955e1051a39Sopenharmony_ci 956e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 957e1051a39Sopenharmony_ci BN_CTX *ctx) 958e1051a39Sopenharmony_ci{ 959e1051a39Sopenharmony_ci int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 960e1051a39Sopenharmony_ci const BIGNUM *, BN_CTX *); 961e1051a39Sopenharmony_ci int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 962e1051a39Sopenharmony_ci const BIGNUM *p; 963e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 964e1051a39Sopenharmony_ci BIGNUM *rh, *tmp, *Z4, *Z6; 965e1051a39Sopenharmony_ci int ret = -1; 966e1051a39Sopenharmony_ci 967e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point)) 968e1051a39Sopenharmony_ci return 1; 969e1051a39Sopenharmony_ci 970e1051a39Sopenharmony_ci field_mul = group->meth->field_mul; 971e1051a39Sopenharmony_ci field_sqr = group->meth->field_sqr; 972e1051a39Sopenharmony_ci p = group->field; 973e1051a39Sopenharmony_ci 974e1051a39Sopenharmony_ci if (ctx == NULL) { 975e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 976e1051a39Sopenharmony_ci if (ctx == NULL) 977e1051a39Sopenharmony_ci return -1; 978e1051a39Sopenharmony_ci } 979e1051a39Sopenharmony_ci 980e1051a39Sopenharmony_ci BN_CTX_start(ctx); 981e1051a39Sopenharmony_ci rh = BN_CTX_get(ctx); 982e1051a39Sopenharmony_ci tmp = BN_CTX_get(ctx); 983e1051a39Sopenharmony_ci Z4 = BN_CTX_get(ctx); 984e1051a39Sopenharmony_ci Z6 = BN_CTX_get(ctx); 985e1051a39Sopenharmony_ci if (Z6 == NULL) 986e1051a39Sopenharmony_ci goto err; 987e1051a39Sopenharmony_ci 988e1051a39Sopenharmony_ci /*- 989e1051a39Sopenharmony_ci * We have a curve defined by a Weierstrass equation 990e1051a39Sopenharmony_ci * y^2 = x^3 + a*x + b. 991e1051a39Sopenharmony_ci * The point to consider is given in Jacobian projective coordinates 992e1051a39Sopenharmony_ci * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). 993e1051a39Sopenharmony_ci * Substituting this and multiplying by Z^6 transforms the above equation into 994e1051a39Sopenharmony_ci * Y^2 = X^3 + a*X*Z^4 + b*Z^6. 995e1051a39Sopenharmony_ci * To test this, we add up the right-hand side in 'rh'. 996e1051a39Sopenharmony_ci */ 997e1051a39Sopenharmony_ci 998e1051a39Sopenharmony_ci /* rh := X^2 */ 999e1051a39Sopenharmony_ci if (!field_sqr(group, rh, point->X, ctx)) 1000e1051a39Sopenharmony_ci goto err; 1001e1051a39Sopenharmony_ci 1002e1051a39Sopenharmony_ci if (!point->Z_is_one) { 1003e1051a39Sopenharmony_ci if (!field_sqr(group, tmp, point->Z, ctx)) 1004e1051a39Sopenharmony_ci goto err; 1005e1051a39Sopenharmony_ci if (!field_sqr(group, Z4, tmp, ctx)) 1006e1051a39Sopenharmony_ci goto err; 1007e1051a39Sopenharmony_ci if (!field_mul(group, Z6, Z4, tmp, ctx)) 1008e1051a39Sopenharmony_ci goto err; 1009e1051a39Sopenharmony_ci 1010e1051a39Sopenharmony_ci /* rh := (rh + a*Z^4)*X */ 1011e1051a39Sopenharmony_ci if (group->a_is_minus3) { 1012e1051a39Sopenharmony_ci if (!BN_mod_lshift1_quick(tmp, Z4, p)) 1013e1051a39Sopenharmony_ci goto err; 1014e1051a39Sopenharmony_ci if (!BN_mod_add_quick(tmp, tmp, Z4, p)) 1015e1051a39Sopenharmony_ci goto err; 1016e1051a39Sopenharmony_ci if (!BN_mod_sub_quick(rh, rh, tmp, p)) 1017e1051a39Sopenharmony_ci goto err; 1018e1051a39Sopenharmony_ci if (!field_mul(group, rh, rh, point->X, ctx)) 1019e1051a39Sopenharmony_ci goto err; 1020e1051a39Sopenharmony_ci } else { 1021e1051a39Sopenharmony_ci if (!field_mul(group, tmp, Z4, group->a, ctx)) 1022e1051a39Sopenharmony_ci goto err; 1023e1051a39Sopenharmony_ci if (!BN_mod_add_quick(rh, rh, tmp, p)) 1024e1051a39Sopenharmony_ci goto err; 1025e1051a39Sopenharmony_ci if (!field_mul(group, rh, rh, point->X, ctx)) 1026e1051a39Sopenharmony_ci goto err; 1027e1051a39Sopenharmony_ci } 1028e1051a39Sopenharmony_ci 1029e1051a39Sopenharmony_ci /* rh := rh + b*Z^6 */ 1030e1051a39Sopenharmony_ci if (!field_mul(group, tmp, group->b, Z6, ctx)) 1031e1051a39Sopenharmony_ci goto err; 1032e1051a39Sopenharmony_ci if (!BN_mod_add_quick(rh, rh, tmp, p)) 1033e1051a39Sopenharmony_ci goto err; 1034e1051a39Sopenharmony_ci } else { 1035e1051a39Sopenharmony_ci /* point->Z_is_one */ 1036e1051a39Sopenharmony_ci 1037e1051a39Sopenharmony_ci /* rh := (rh + a)*X */ 1038e1051a39Sopenharmony_ci if (!BN_mod_add_quick(rh, rh, group->a, p)) 1039e1051a39Sopenharmony_ci goto err; 1040e1051a39Sopenharmony_ci if (!field_mul(group, rh, rh, point->X, ctx)) 1041e1051a39Sopenharmony_ci goto err; 1042e1051a39Sopenharmony_ci /* rh := rh + b */ 1043e1051a39Sopenharmony_ci if (!BN_mod_add_quick(rh, rh, group->b, p)) 1044e1051a39Sopenharmony_ci goto err; 1045e1051a39Sopenharmony_ci } 1046e1051a39Sopenharmony_ci 1047e1051a39Sopenharmony_ci /* 'lh' := Y^2 */ 1048e1051a39Sopenharmony_ci if (!field_sqr(group, tmp, point->Y, ctx)) 1049e1051a39Sopenharmony_ci goto err; 1050e1051a39Sopenharmony_ci 1051e1051a39Sopenharmony_ci ret = (0 == BN_ucmp(tmp, rh)); 1052e1051a39Sopenharmony_ci 1053e1051a39Sopenharmony_ci err: 1054e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1055e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 1056e1051a39Sopenharmony_ci return ret; 1057e1051a39Sopenharmony_ci} 1058e1051a39Sopenharmony_ci 1059e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, 1060e1051a39Sopenharmony_ci const EC_POINT *b, BN_CTX *ctx) 1061e1051a39Sopenharmony_ci{ 1062e1051a39Sopenharmony_ci /*- 1063e1051a39Sopenharmony_ci * return values: 1064e1051a39Sopenharmony_ci * -1 error 1065e1051a39Sopenharmony_ci * 0 equal (in affine coordinates) 1066e1051a39Sopenharmony_ci * 1 not equal 1067e1051a39Sopenharmony_ci */ 1068e1051a39Sopenharmony_ci 1069e1051a39Sopenharmony_ci int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 1070e1051a39Sopenharmony_ci const BIGNUM *, BN_CTX *); 1071e1051a39Sopenharmony_ci int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 1072e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 1073e1051a39Sopenharmony_ci BIGNUM *tmp1, *tmp2, *Za23, *Zb23; 1074e1051a39Sopenharmony_ci const BIGNUM *tmp1_, *tmp2_; 1075e1051a39Sopenharmony_ci int ret = -1; 1076e1051a39Sopenharmony_ci 1077e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, a)) { 1078e1051a39Sopenharmony_ci return EC_POINT_is_at_infinity(group, b) ? 0 : 1; 1079e1051a39Sopenharmony_ci } 1080e1051a39Sopenharmony_ci 1081e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, b)) 1082e1051a39Sopenharmony_ci return 1; 1083e1051a39Sopenharmony_ci 1084e1051a39Sopenharmony_ci if (a->Z_is_one && b->Z_is_one) { 1085e1051a39Sopenharmony_ci return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1; 1086e1051a39Sopenharmony_ci } 1087e1051a39Sopenharmony_ci 1088e1051a39Sopenharmony_ci field_mul = group->meth->field_mul; 1089e1051a39Sopenharmony_ci field_sqr = group->meth->field_sqr; 1090e1051a39Sopenharmony_ci 1091e1051a39Sopenharmony_ci if (ctx == NULL) { 1092e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 1093e1051a39Sopenharmony_ci if (ctx == NULL) 1094e1051a39Sopenharmony_ci return -1; 1095e1051a39Sopenharmony_ci } 1096e1051a39Sopenharmony_ci 1097e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1098e1051a39Sopenharmony_ci tmp1 = BN_CTX_get(ctx); 1099e1051a39Sopenharmony_ci tmp2 = BN_CTX_get(ctx); 1100e1051a39Sopenharmony_ci Za23 = BN_CTX_get(ctx); 1101e1051a39Sopenharmony_ci Zb23 = BN_CTX_get(ctx); 1102e1051a39Sopenharmony_ci if (Zb23 == NULL) 1103e1051a39Sopenharmony_ci goto end; 1104e1051a39Sopenharmony_ci 1105e1051a39Sopenharmony_ci /*- 1106e1051a39Sopenharmony_ci * We have to decide whether 1107e1051a39Sopenharmony_ci * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), 1108e1051a39Sopenharmony_ci * or equivalently, whether 1109e1051a39Sopenharmony_ci * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). 1110e1051a39Sopenharmony_ci */ 1111e1051a39Sopenharmony_ci 1112e1051a39Sopenharmony_ci if (!b->Z_is_one) { 1113e1051a39Sopenharmony_ci if (!field_sqr(group, Zb23, b->Z, ctx)) 1114e1051a39Sopenharmony_ci goto end; 1115e1051a39Sopenharmony_ci if (!field_mul(group, tmp1, a->X, Zb23, ctx)) 1116e1051a39Sopenharmony_ci goto end; 1117e1051a39Sopenharmony_ci tmp1_ = tmp1; 1118e1051a39Sopenharmony_ci } else 1119e1051a39Sopenharmony_ci tmp1_ = a->X; 1120e1051a39Sopenharmony_ci if (!a->Z_is_one) { 1121e1051a39Sopenharmony_ci if (!field_sqr(group, Za23, a->Z, ctx)) 1122e1051a39Sopenharmony_ci goto end; 1123e1051a39Sopenharmony_ci if (!field_mul(group, tmp2, b->X, Za23, ctx)) 1124e1051a39Sopenharmony_ci goto end; 1125e1051a39Sopenharmony_ci tmp2_ = tmp2; 1126e1051a39Sopenharmony_ci } else 1127e1051a39Sopenharmony_ci tmp2_ = b->X; 1128e1051a39Sopenharmony_ci 1129e1051a39Sopenharmony_ci /* compare X_a*Z_b^2 with X_b*Z_a^2 */ 1130e1051a39Sopenharmony_ci if (BN_cmp(tmp1_, tmp2_) != 0) { 1131e1051a39Sopenharmony_ci ret = 1; /* points differ */ 1132e1051a39Sopenharmony_ci goto end; 1133e1051a39Sopenharmony_ci } 1134e1051a39Sopenharmony_ci 1135e1051a39Sopenharmony_ci if (!b->Z_is_one) { 1136e1051a39Sopenharmony_ci if (!field_mul(group, Zb23, Zb23, b->Z, ctx)) 1137e1051a39Sopenharmony_ci goto end; 1138e1051a39Sopenharmony_ci if (!field_mul(group, tmp1, a->Y, Zb23, ctx)) 1139e1051a39Sopenharmony_ci goto end; 1140e1051a39Sopenharmony_ci /* tmp1_ = tmp1 */ 1141e1051a39Sopenharmony_ci } else 1142e1051a39Sopenharmony_ci tmp1_ = a->Y; 1143e1051a39Sopenharmony_ci if (!a->Z_is_one) { 1144e1051a39Sopenharmony_ci if (!field_mul(group, Za23, Za23, a->Z, ctx)) 1145e1051a39Sopenharmony_ci goto end; 1146e1051a39Sopenharmony_ci if (!field_mul(group, tmp2, b->Y, Za23, ctx)) 1147e1051a39Sopenharmony_ci goto end; 1148e1051a39Sopenharmony_ci /* tmp2_ = tmp2 */ 1149e1051a39Sopenharmony_ci } else 1150e1051a39Sopenharmony_ci tmp2_ = b->Y; 1151e1051a39Sopenharmony_ci 1152e1051a39Sopenharmony_ci /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ 1153e1051a39Sopenharmony_ci if (BN_cmp(tmp1_, tmp2_) != 0) { 1154e1051a39Sopenharmony_ci ret = 1; /* points differ */ 1155e1051a39Sopenharmony_ci goto end; 1156e1051a39Sopenharmony_ci } 1157e1051a39Sopenharmony_ci 1158e1051a39Sopenharmony_ci /* points are equal */ 1159e1051a39Sopenharmony_ci ret = 0; 1160e1051a39Sopenharmony_ci 1161e1051a39Sopenharmony_ci end: 1162e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1163e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 1164e1051a39Sopenharmony_ci return ret; 1165e1051a39Sopenharmony_ci} 1166e1051a39Sopenharmony_ci 1167e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, 1168e1051a39Sopenharmony_ci BN_CTX *ctx) 1169e1051a39Sopenharmony_ci{ 1170e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 1171e1051a39Sopenharmony_ci BIGNUM *x, *y; 1172e1051a39Sopenharmony_ci int ret = 0; 1173e1051a39Sopenharmony_ci 1174e1051a39Sopenharmony_ci if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) 1175e1051a39Sopenharmony_ci return 1; 1176e1051a39Sopenharmony_ci 1177e1051a39Sopenharmony_ci if (ctx == NULL) { 1178e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 1179e1051a39Sopenharmony_ci if (ctx == NULL) 1180e1051a39Sopenharmony_ci return 0; 1181e1051a39Sopenharmony_ci } 1182e1051a39Sopenharmony_ci 1183e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1184e1051a39Sopenharmony_ci x = BN_CTX_get(ctx); 1185e1051a39Sopenharmony_ci y = BN_CTX_get(ctx); 1186e1051a39Sopenharmony_ci if (y == NULL) 1187e1051a39Sopenharmony_ci goto err; 1188e1051a39Sopenharmony_ci 1189e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) 1190e1051a39Sopenharmony_ci goto err; 1191e1051a39Sopenharmony_ci if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) 1192e1051a39Sopenharmony_ci goto err; 1193e1051a39Sopenharmony_ci if (!point->Z_is_one) { 1194e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); 1195e1051a39Sopenharmony_ci goto err; 1196e1051a39Sopenharmony_ci } 1197e1051a39Sopenharmony_ci 1198e1051a39Sopenharmony_ci ret = 1; 1199e1051a39Sopenharmony_ci 1200e1051a39Sopenharmony_ci err: 1201e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1202e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 1203e1051a39Sopenharmony_ci return ret; 1204e1051a39Sopenharmony_ci} 1205e1051a39Sopenharmony_ci 1206e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, 1207e1051a39Sopenharmony_ci EC_POINT *points[], BN_CTX *ctx) 1208e1051a39Sopenharmony_ci{ 1209e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 1210e1051a39Sopenharmony_ci BIGNUM *tmp, *tmp_Z; 1211e1051a39Sopenharmony_ci BIGNUM **prod_Z = NULL; 1212e1051a39Sopenharmony_ci size_t i; 1213e1051a39Sopenharmony_ci int ret = 0; 1214e1051a39Sopenharmony_ci 1215e1051a39Sopenharmony_ci if (num == 0) 1216e1051a39Sopenharmony_ci return 1; 1217e1051a39Sopenharmony_ci 1218e1051a39Sopenharmony_ci if (ctx == NULL) { 1219e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new_ex(group->libctx); 1220e1051a39Sopenharmony_ci if (ctx == NULL) 1221e1051a39Sopenharmony_ci return 0; 1222e1051a39Sopenharmony_ci } 1223e1051a39Sopenharmony_ci 1224e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1225e1051a39Sopenharmony_ci tmp = BN_CTX_get(ctx); 1226e1051a39Sopenharmony_ci tmp_Z = BN_CTX_get(ctx); 1227e1051a39Sopenharmony_ci if (tmp_Z == NULL) 1228e1051a39Sopenharmony_ci goto err; 1229e1051a39Sopenharmony_ci 1230e1051a39Sopenharmony_ci prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0])); 1231e1051a39Sopenharmony_ci if (prod_Z == NULL) 1232e1051a39Sopenharmony_ci goto err; 1233e1051a39Sopenharmony_ci for (i = 0; i < num; i++) { 1234e1051a39Sopenharmony_ci prod_Z[i] = BN_new(); 1235e1051a39Sopenharmony_ci if (prod_Z[i] == NULL) 1236e1051a39Sopenharmony_ci goto err; 1237e1051a39Sopenharmony_ci } 1238e1051a39Sopenharmony_ci 1239e1051a39Sopenharmony_ci /* 1240e1051a39Sopenharmony_ci * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, 1241e1051a39Sopenharmony_ci * skipping any zero-valued inputs (pretend that they're 1). 1242e1051a39Sopenharmony_ci */ 1243e1051a39Sopenharmony_ci 1244e1051a39Sopenharmony_ci if (!BN_is_zero(points[0]->Z)) { 1245e1051a39Sopenharmony_ci if (!BN_copy(prod_Z[0], points[0]->Z)) 1246e1051a39Sopenharmony_ci goto err; 1247e1051a39Sopenharmony_ci } else { 1248e1051a39Sopenharmony_ci if (group->meth->field_set_to_one != 0) { 1249e1051a39Sopenharmony_ci if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) 1250e1051a39Sopenharmony_ci goto err; 1251e1051a39Sopenharmony_ci } else { 1252e1051a39Sopenharmony_ci if (!BN_one(prod_Z[0])) 1253e1051a39Sopenharmony_ci goto err; 1254e1051a39Sopenharmony_ci } 1255e1051a39Sopenharmony_ci } 1256e1051a39Sopenharmony_ci 1257e1051a39Sopenharmony_ci for (i = 1; i < num; i++) { 1258e1051a39Sopenharmony_ci if (!BN_is_zero(points[i]->Z)) { 1259e1051a39Sopenharmony_ci if (!group-> 1260e1051a39Sopenharmony_ci meth->field_mul(group, prod_Z[i], prod_Z[i - 1], points[i]->Z, 1261e1051a39Sopenharmony_ci ctx)) 1262e1051a39Sopenharmony_ci goto err; 1263e1051a39Sopenharmony_ci } else { 1264e1051a39Sopenharmony_ci if (!BN_copy(prod_Z[i], prod_Z[i - 1])) 1265e1051a39Sopenharmony_ci goto err; 1266e1051a39Sopenharmony_ci } 1267e1051a39Sopenharmony_ci } 1268e1051a39Sopenharmony_ci 1269e1051a39Sopenharmony_ci /* 1270e1051a39Sopenharmony_ci * Now use a single explicit inversion to replace every non-zero 1271e1051a39Sopenharmony_ci * points[i]->Z by its inverse. 1272e1051a39Sopenharmony_ci */ 1273e1051a39Sopenharmony_ci 1274e1051a39Sopenharmony_ci if (!group->meth->field_inv(group, tmp, prod_Z[num - 1], ctx)) { 1275e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); 1276e1051a39Sopenharmony_ci goto err; 1277e1051a39Sopenharmony_ci } 1278e1051a39Sopenharmony_ci if (group->meth->field_encode != 0) { 1279e1051a39Sopenharmony_ci /* 1280e1051a39Sopenharmony_ci * In the Montgomery case, we just turned R*H (representing H) into 1281e1051a39Sopenharmony_ci * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to 1282e1051a39Sopenharmony_ci * multiply by the Montgomery factor twice. 1283e1051a39Sopenharmony_ci */ 1284e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, tmp, tmp, ctx)) 1285e1051a39Sopenharmony_ci goto err; 1286e1051a39Sopenharmony_ci if (!group->meth->field_encode(group, tmp, tmp, ctx)) 1287e1051a39Sopenharmony_ci goto err; 1288e1051a39Sopenharmony_ci } 1289e1051a39Sopenharmony_ci 1290e1051a39Sopenharmony_ci for (i = num - 1; i > 0; --i) { 1291e1051a39Sopenharmony_ci /* 1292e1051a39Sopenharmony_ci * Loop invariant: tmp is the product of the inverses of points[0]->Z 1293e1051a39Sopenharmony_ci * .. points[i]->Z (zero-valued inputs skipped). 1294e1051a39Sopenharmony_ci */ 1295e1051a39Sopenharmony_ci if (!BN_is_zero(points[i]->Z)) { 1296e1051a39Sopenharmony_ci /* 1297e1051a39Sopenharmony_ci * Set tmp_Z to the inverse of points[i]->Z (as product of Z 1298e1051a39Sopenharmony_ci * inverses 0 .. i, Z values 0 .. i - 1). 1299e1051a39Sopenharmony_ci */ 1300e1051a39Sopenharmony_ci if (!group-> 1301e1051a39Sopenharmony_ci meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) 1302e1051a39Sopenharmony_ci goto err; 1303e1051a39Sopenharmony_ci /* 1304e1051a39Sopenharmony_ci * Update tmp to satisfy the loop invariant for i - 1. 1305e1051a39Sopenharmony_ci */ 1306e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, tmp, tmp, points[i]->Z, ctx)) 1307e1051a39Sopenharmony_ci goto err; 1308e1051a39Sopenharmony_ci /* Replace points[i]->Z by its inverse. */ 1309e1051a39Sopenharmony_ci if (!BN_copy(points[i]->Z, tmp_Z)) 1310e1051a39Sopenharmony_ci goto err; 1311e1051a39Sopenharmony_ci } 1312e1051a39Sopenharmony_ci } 1313e1051a39Sopenharmony_ci 1314e1051a39Sopenharmony_ci if (!BN_is_zero(points[0]->Z)) { 1315e1051a39Sopenharmony_ci /* Replace points[0]->Z by its inverse. */ 1316e1051a39Sopenharmony_ci if (!BN_copy(points[0]->Z, tmp)) 1317e1051a39Sopenharmony_ci goto err; 1318e1051a39Sopenharmony_ci } 1319e1051a39Sopenharmony_ci 1320e1051a39Sopenharmony_ci /* Finally, fix up the X and Y coordinates for all points. */ 1321e1051a39Sopenharmony_ci 1322e1051a39Sopenharmony_ci for (i = 0; i < num; i++) { 1323e1051a39Sopenharmony_ci EC_POINT *p = points[i]; 1324e1051a39Sopenharmony_ci 1325e1051a39Sopenharmony_ci if (!BN_is_zero(p->Z)) { 1326e1051a39Sopenharmony_ci /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ 1327e1051a39Sopenharmony_ci 1328e1051a39Sopenharmony_ci if (!group->meth->field_sqr(group, tmp, p->Z, ctx)) 1329e1051a39Sopenharmony_ci goto err; 1330e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, p->X, p->X, tmp, ctx)) 1331e1051a39Sopenharmony_ci goto err; 1332e1051a39Sopenharmony_ci 1333e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, tmp, tmp, p->Z, ctx)) 1334e1051a39Sopenharmony_ci goto err; 1335e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, p->Y, p->Y, tmp, ctx)) 1336e1051a39Sopenharmony_ci goto err; 1337e1051a39Sopenharmony_ci 1338e1051a39Sopenharmony_ci if (group->meth->field_set_to_one != 0) { 1339e1051a39Sopenharmony_ci if (!group->meth->field_set_to_one(group, p->Z, ctx)) 1340e1051a39Sopenharmony_ci goto err; 1341e1051a39Sopenharmony_ci } else { 1342e1051a39Sopenharmony_ci if (!BN_one(p->Z)) 1343e1051a39Sopenharmony_ci goto err; 1344e1051a39Sopenharmony_ci } 1345e1051a39Sopenharmony_ci p->Z_is_one = 1; 1346e1051a39Sopenharmony_ci } 1347e1051a39Sopenharmony_ci } 1348e1051a39Sopenharmony_ci 1349e1051a39Sopenharmony_ci ret = 1; 1350e1051a39Sopenharmony_ci 1351e1051a39Sopenharmony_ci err: 1352e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1353e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 1354e1051a39Sopenharmony_ci if (prod_Z != NULL) { 1355e1051a39Sopenharmony_ci for (i = 0; i < num; i++) { 1356e1051a39Sopenharmony_ci if (prod_Z[i] == NULL) 1357e1051a39Sopenharmony_ci break; 1358e1051a39Sopenharmony_ci BN_clear_free(prod_Z[i]); 1359e1051a39Sopenharmony_ci } 1360e1051a39Sopenharmony_ci OPENSSL_free(prod_Z); 1361e1051a39Sopenharmony_ci } 1362e1051a39Sopenharmony_ci return ret; 1363e1051a39Sopenharmony_ci} 1364e1051a39Sopenharmony_ci 1365e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1366e1051a39Sopenharmony_ci const BIGNUM *b, BN_CTX *ctx) 1367e1051a39Sopenharmony_ci{ 1368e1051a39Sopenharmony_ci return BN_mod_mul(r, a, b, group->field, ctx); 1369e1051a39Sopenharmony_ci} 1370e1051a39Sopenharmony_ci 1371e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, 1372e1051a39Sopenharmony_ci BN_CTX *ctx) 1373e1051a39Sopenharmony_ci{ 1374e1051a39Sopenharmony_ci return BN_mod_sqr(r, a, group->field, ctx); 1375e1051a39Sopenharmony_ci} 1376e1051a39Sopenharmony_ci 1377e1051a39Sopenharmony_ci/*- 1378e1051a39Sopenharmony_ci * Computes the multiplicative inverse of a in GF(p), storing the result in r. 1379e1051a39Sopenharmony_ci * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error. 1380e1051a39Sopenharmony_ci * Since we don't have a Mont structure here, SCA hardening is with blinding. 1381e1051a39Sopenharmony_ci * NB: "a" must be in _decoded_ form. (i.e. field_decode must precede.) 1382e1051a39Sopenharmony_ci */ 1383e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_inv(const EC_GROUP *group, BIGNUM *r, 1384e1051a39Sopenharmony_ci const BIGNUM *a, BN_CTX *ctx) 1385e1051a39Sopenharmony_ci{ 1386e1051a39Sopenharmony_ci BIGNUM *e = NULL; 1387e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 1388e1051a39Sopenharmony_ci int ret = 0; 1389e1051a39Sopenharmony_ci 1390e1051a39Sopenharmony_ci if (ctx == NULL 1391e1051a39Sopenharmony_ci && (ctx = new_ctx = BN_CTX_secure_new_ex(group->libctx)) == NULL) 1392e1051a39Sopenharmony_ci return 0; 1393e1051a39Sopenharmony_ci 1394e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1395e1051a39Sopenharmony_ci if ((e = BN_CTX_get(ctx)) == NULL) 1396e1051a39Sopenharmony_ci goto err; 1397e1051a39Sopenharmony_ci 1398e1051a39Sopenharmony_ci do { 1399e1051a39Sopenharmony_ci if (!BN_priv_rand_range_ex(e, group->field, 0, ctx)) 1400e1051a39Sopenharmony_ci goto err; 1401e1051a39Sopenharmony_ci } while (BN_is_zero(e)); 1402e1051a39Sopenharmony_ci 1403e1051a39Sopenharmony_ci /* r := a * e */ 1404e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, r, a, e, ctx)) 1405e1051a39Sopenharmony_ci goto err; 1406e1051a39Sopenharmony_ci /* r := 1/(a * e) */ 1407e1051a39Sopenharmony_ci if (!BN_mod_inverse(r, r, group->field, ctx)) { 1408e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_CANNOT_INVERT); 1409e1051a39Sopenharmony_ci goto err; 1410e1051a39Sopenharmony_ci } 1411e1051a39Sopenharmony_ci /* r := e/(a * e) = 1/a */ 1412e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, r, r, e, ctx)) 1413e1051a39Sopenharmony_ci goto err; 1414e1051a39Sopenharmony_ci 1415e1051a39Sopenharmony_ci ret = 1; 1416e1051a39Sopenharmony_ci 1417e1051a39Sopenharmony_ci err: 1418e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1419e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 1420e1051a39Sopenharmony_ci return ret; 1421e1051a39Sopenharmony_ci} 1422e1051a39Sopenharmony_ci 1423e1051a39Sopenharmony_ci/*- 1424e1051a39Sopenharmony_ci * Apply randomization of EC point projective coordinates: 1425e1051a39Sopenharmony_ci * 1426e1051a39Sopenharmony_ci * (X, Y ,Z ) = (lambda^2*X, lambda^3*Y, lambda*Z) 1427e1051a39Sopenharmony_ci * lambda = [1,group->field) 1428e1051a39Sopenharmony_ci * 1429e1051a39Sopenharmony_ci */ 1430e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p, 1431e1051a39Sopenharmony_ci BN_CTX *ctx) 1432e1051a39Sopenharmony_ci{ 1433e1051a39Sopenharmony_ci int ret = 0; 1434e1051a39Sopenharmony_ci BIGNUM *lambda = NULL; 1435e1051a39Sopenharmony_ci BIGNUM *temp = NULL; 1436e1051a39Sopenharmony_ci 1437e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1438e1051a39Sopenharmony_ci lambda = BN_CTX_get(ctx); 1439e1051a39Sopenharmony_ci temp = BN_CTX_get(ctx); 1440e1051a39Sopenharmony_ci if (temp == NULL) { 1441e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); 1442e1051a39Sopenharmony_ci goto end; 1443e1051a39Sopenharmony_ci } 1444e1051a39Sopenharmony_ci 1445e1051a39Sopenharmony_ci /*- 1446e1051a39Sopenharmony_ci * Make sure lambda is not zero. 1447e1051a39Sopenharmony_ci * If the RNG fails, we cannot blind but nevertheless want 1448e1051a39Sopenharmony_ci * code to continue smoothly and not clobber the error stack. 1449e1051a39Sopenharmony_ci */ 1450e1051a39Sopenharmony_ci do { 1451e1051a39Sopenharmony_ci ERR_set_mark(); 1452e1051a39Sopenharmony_ci ret = BN_priv_rand_range_ex(lambda, group->field, 0, ctx); 1453e1051a39Sopenharmony_ci ERR_pop_to_mark(); 1454e1051a39Sopenharmony_ci if (ret == 0) { 1455e1051a39Sopenharmony_ci ret = 1; 1456e1051a39Sopenharmony_ci goto end; 1457e1051a39Sopenharmony_ci } 1458e1051a39Sopenharmony_ci } while (BN_is_zero(lambda)); 1459e1051a39Sopenharmony_ci 1460e1051a39Sopenharmony_ci /* if field_encode defined convert between representations */ 1461e1051a39Sopenharmony_ci if ((group->meth->field_encode != NULL 1462e1051a39Sopenharmony_ci && !group->meth->field_encode(group, lambda, lambda, ctx)) 1463e1051a39Sopenharmony_ci || !group->meth->field_mul(group, p->Z, p->Z, lambda, ctx) 1464e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, temp, lambda, ctx) 1465e1051a39Sopenharmony_ci || !group->meth->field_mul(group, p->X, p->X, temp, ctx) 1466e1051a39Sopenharmony_ci || !group->meth->field_mul(group, temp, temp, lambda, ctx) 1467e1051a39Sopenharmony_ci || !group->meth->field_mul(group, p->Y, p->Y, temp, ctx)) 1468e1051a39Sopenharmony_ci goto end; 1469e1051a39Sopenharmony_ci 1470e1051a39Sopenharmony_ci p->Z_is_one = 0; 1471e1051a39Sopenharmony_ci ret = 1; 1472e1051a39Sopenharmony_ci 1473e1051a39Sopenharmony_ci end: 1474e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1475e1051a39Sopenharmony_ci return ret; 1476e1051a39Sopenharmony_ci} 1477e1051a39Sopenharmony_ci 1478e1051a39Sopenharmony_ci/*- 1479e1051a39Sopenharmony_ci * Input: 1480e1051a39Sopenharmony_ci * - p: affine coordinates 1481e1051a39Sopenharmony_ci * 1482e1051a39Sopenharmony_ci * Output: 1483e1051a39Sopenharmony_ci * - s := p, r := 2p: blinded projective (homogeneous) coordinates 1484e1051a39Sopenharmony_ci * 1485e1051a39Sopenharmony_ci * For doubling we use Formula 3 from Izu-Takagi "A fast parallel elliptic curve 1486e1051a39Sopenharmony_ci * multiplication resistant against side channel attacks" appendix, described at 1487e1051a39Sopenharmony_ci * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#doubling-dbl-2002-it-2 1488e1051a39Sopenharmony_ci * simplified for Z1=1. 1489e1051a39Sopenharmony_ci * 1490e1051a39Sopenharmony_ci * Blinding uses the equivalence relation (\lambda X, \lambda Y, \lambda Z) 1491e1051a39Sopenharmony_ci * for any non-zero \lambda that holds for projective (homogeneous) coords. 1492e1051a39Sopenharmony_ci */ 1493e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_pre(const EC_GROUP *group, 1494e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 1495e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 1496e1051a39Sopenharmony_ci{ 1497e1051a39Sopenharmony_ci BIGNUM *t1, *t2, *t3, *t4, *t5 = NULL; 1498e1051a39Sopenharmony_ci 1499e1051a39Sopenharmony_ci t1 = s->Z; 1500e1051a39Sopenharmony_ci t2 = r->Z; 1501e1051a39Sopenharmony_ci t3 = s->X; 1502e1051a39Sopenharmony_ci t4 = r->X; 1503e1051a39Sopenharmony_ci t5 = s->Y; 1504e1051a39Sopenharmony_ci 1505e1051a39Sopenharmony_ci if (!p->Z_is_one /* r := 2p */ 1506e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t3, p->X, ctx) 1507e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t4, t3, group->a, group->field) 1508e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t4, t4, ctx) 1509e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t5, p->X, group->b, ctx) 1510e1051a39Sopenharmony_ci || !BN_mod_lshift_quick(t5, t5, 3, group->field) 1511e1051a39Sopenharmony_ci /* r->X coord output */ 1512e1051a39Sopenharmony_ci || !BN_mod_sub_quick(r->X, t4, t5, group->field) 1513e1051a39Sopenharmony_ci || !BN_mod_add_quick(t1, t3, group->a, group->field) 1514e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, p->X, t1, ctx) 1515e1051a39Sopenharmony_ci || !BN_mod_add_quick(t2, group->b, t2, group->field) 1516e1051a39Sopenharmony_ci /* r->Z coord output */ 1517e1051a39Sopenharmony_ci || !BN_mod_lshift_quick(r->Z, t2, 2, group->field)) 1518e1051a39Sopenharmony_ci return 0; 1519e1051a39Sopenharmony_ci 1520e1051a39Sopenharmony_ci /* make sure lambda (r->Y here for storage) is not zero */ 1521e1051a39Sopenharmony_ci do { 1522e1051a39Sopenharmony_ci if (!BN_priv_rand_range_ex(r->Y, group->field, 0, ctx)) 1523e1051a39Sopenharmony_ci return 0; 1524e1051a39Sopenharmony_ci } while (BN_is_zero(r->Y)); 1525e1051a39Sopenharmony_ci 1526e1051a39Sopenharmony_ci /* make sure lambda (s->Z here for storage) is not zero */ 1527e1051a39Sopenharmony_ci do { 1528e1051a39Sopenharmony_ci if (!BN_priv_rand_range_ex(s->Z, group->field, 0, ctx)) 1529e1051a39Sopenharmony_ci return 0; 1530e1051a39Sopenharmony_ci } while (BN_is_zero(s->Z)); 1531e1051a39Sopenharmony_ci 1532e1051a39Sopenharmony_ci /* if field_encode defined convert between representations */ 1533e1051a39Sopenharmony_ci if (group->meth->field_encode != NULL 1534e1051a39Sopenharmony_ci && (!group->meth->field_encode(group, r->Y, r->Y, ctx) 1535e1051a39Sopenharmony_ci || !group->meth->field_encode(group, s->Z, s->Z, ctx))) 1536e1051a39Sopenharmony_ci return 0; 1537e1051a39Sopenharmony_ci 1538e1051a39Sopenharmony_ci /* blind r and s independently */ 1539e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, r->Z, r->Z, r->Y, ctx) 1540e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->X, r->X, r->Y, ctx) 1541e1051a39Sopenharmony_ci || !group->meth->field_mul(group, s->X, p->X, s->Z, ctx)) /* s := p */ 1542e1051a39Sopenharmony_ci return 0; 1543e1051a39Sopenharmony_ci 1544e1051a39Sopenharmony_ci r->Z_is_one = 0; 1545e1051a39Sopenharmony_ci s->Z_is_one = 0; 1546e1051a39Sopenharmony_ci 1547e1051a39Sopenharmony_ci return 1; 1548e1051a39Sopenharmony_ci} 1549e1051a39Sopenharmony_ci 1550e1051a39Sopenharmony_ci/*- 1551e1051a39Sopenharmony_ci * Input: 1552e1051a39Sopenharmony_ci * - s, r: projective (homogeneous) coordinates 1553e1051a39Sopenharmony_ci * - p: affine coordinates 1554e1051a39Sopenharmony_ci * 1555e1051a39Sopenharmony_ci * Output: 1556e1051a39Sopenharmony_ci * - s := r + s, r := 2r: projective (homogeneous) coordinates 1557e1051a39Sopenharmony_ci * 1558e1051a39Sopenharmony_ci * Differential addition-and-doubling using Eq. (9) and (10) from Izu-Takagi 1559e1051a39Sopenharmony_ci * "A fast parallel elliptic curve multiplication resistant against side channel 1560e1051a39Sopenharmony_ci * attacks", as described at 1561e1051a39Sopenharmony_ci * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#ladder-mladd-2002-it-4 1562e1051a39Sopenharmony_ci */ 1563e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_step(const EC_GROUP *group, 1564e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 1565e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 1566e1051a39Sopenharmony_ci{ 1567e1051a39Sopenharmony_ci int ret = 0; 1568e1051a39Sopenharmony_ci BIGNUM *t0, *t1, *t2, *t3, *t4, *t5, *t6 = NULL; 1569e1051a39Sopenharmony_ci 1570e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1571e1051a39Sopenharmony_ci t0 = BN_CTX_get(ctx); 1572e1051a39Sopenharmony_ci t1 = BN_CTX_get(ctx); 1573e1051a39Sopenharmony_ci t2 = BN_CTX_get(ctx); 1574e1051a39Sopenharmony_ci t3 = BN_CTX_get(ctx); 1575e1051a39Sopenharmony_ci t4 = BN_CTX_get(ctx); 1576e1051a39Sopenharmony_ci t5 = BN_CTX_get(ctx); 1577e1051a39Sopenharmony_ci t6 = BN_CTX_get(ctx); 1578e1051a39Sopenharmony_ci 1579e1051a39Sopenharmony_ci if (t6 == NULL 1580e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, r->X, s->X, ctx) 1581e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, r->Z, s->Z, ctx) 1582e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t4, r->X, s->Z, ctx) 1583e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t3, r->Z, s->X, ctx) 1584e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t5, group->a, t0, ctx) 1585e1051a39Sopenharmony_ci || !BN_mod_add_quick(t5, t6, t5, group->field) 1586e1051a39Sopenharmony_ci || !BN_mod_add_quick(t6, t3, t4, group->field) 1587e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t5, t6, t5, ctx) 1588e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t0, t0, ctx) 1589e1051a39Sopenharmony_ci || !BN_mod_lshift_quick(t2, group->b, 2, group->field) 1590e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, t2, t0, ctx) 1591e1051a39Sopenharmony_ci || !BN_mod_lshift1_quick(t5, t5, group->field) 1592e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t3, t4, t3, group->field) 1593e1051a39Sopenharmony_ci /* s->Z coord output */ 1594e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, s->Z, t3, ctx) 1595e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t4, s->Z, p->X, ctx) 1596e1051a39Sopenharmony_ci || !BN_mod_add_quick(t0, t0, t5, group->field) 1597e1051a39Sopenharmony_ci /* s->X coord output */ 1598e1051a39Sopenharmony_ci || !BN_mod_sub_quick(s->X, t0, t4, group->field) 1599e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t4, r->X, ctx) 1600e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t5, r->Z, ctx) 1601e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, t5, group->a, ctx) 1602e1051a39Sopenharmony_ci || !BN_mod_add_quick(t1, r->X, r->Z, group->field) 1603e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t1, t1, ctx) 1604e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t1, t1, t4, group->field) 1605e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t1, t1, t5, group->field) 1606e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t3, t4, t6, group->field) 1607e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t3, t3, ctx) 1608e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, t5, t1, ctx) 1609e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, t2, t0, ctx) 1610e1051a39Sopenharmony_ci /* r->X coord output */ 1611e1051a39Sopenharmony_ci || !BN_mod_sub_quick(r->X, t3, t0, group->field) 1612e1051a39Sopenharmony_ci || !BN_mod_add_quick(t3, t4, t6, group->field) 1613e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t4, t5, ctx) 1614e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t4, t4, t2, ctx) 1615e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, t1, t3, ctx) 1616e1051a39Sopenharmony_ci || !BN_mod_lshift1_quick(t1, t1, group->field) 1617e1051a39Sopenharmony_ci /* r->Z coord output */ 1618e1051a39Sopenharmony_ci || !BN_mod_add_quick(r->Z, t4, t1, group->field)) 1619e1051a39Sopenharmony_ci goto err; 1620e1051a39Sopenharmony_ci 1621e1051a39Sopenharmony_ci ret = 1; 1622e1051a39Sopenharmony_ci 1623e1051a39Sopenharmony_ci err: 1624e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1625e1051a39Sopenharmony_ci return ret; 1626e1051a39Sopenharmony_ci} 1627e1051a39Sopenharmony_ci 1628e1051a39Sopenharmony_ci/*- 1629e1051a39Sopenharmony_ci * Input: 1630e1051a39Sopenharmony_ci * - s, r: projective (homogeneous) coordinates 1631e1051a39Sopenharmony_ci * - p: affine coordinates 1632e1051a39Sopenharmony_ci * 1633e1051a39Sopenharmony_ci * Output: 1634e1051a39Sopenharmony_ci * - r := (x,y): affine coordinates 1635e1051a39Sopenharmony_ci * 1636e1051a39Sopenharmony_ci * Recovers the y-coordinate of r using Eq. (8) from Brier-Joye, "Weierstrass 1637e1051a39Sopenharmony_ci * Elliptic Curves and Side-Channel Attacks", modified to work in mixed 1638e1051a39Sopenharmony_ci * projective coords, i.e. p is affine and (r,s) in projective (homogeneous) 1639e1051a39Sopenharmony_ci * coords, and return r in affine coordinates. 1640e1051a39Sopenharmony_ci * 1641e1051a39Sopenharmony_ci * X4 = two*Y1*X2*Z3*Z2; 1642e1051a39Sopenharmony_ci * Y4 = two*b*Z3*SQR(Z2) + Z3*(a*Z2+X1*X2)*(X1*Z2+X2) - X3*SQR(X1*Z2-X2); 1643e1051a39Sopenharmony_ci * Z4 = two*Y1*Z3*SQR(Z2); 1644e1051a39Sopenharmony_ci * 1645e1051a39Sopenharmony_ci * Z4 != 0 because: 1646e1051a39Sopenharmony_ci * - Z2==0 implies r is at infinity (handled by the BN_is_zero(r->Z) branch); 1647e1051a39Sopenharmony_ci * - Z3==0 implies s is at infinity (handled by the BN_is_zero(s->Z) branch); 1648e1051a39Sopenharmony_ci * - Y1==0 implies p has order 2, so either r or s are infinity and handled by 1649e1051a39Sopenharmony_ci * one of the BN_is_zero(...) branches. 1650e1051a39Sopenharmony_ci */ 1651e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_post(const EC_GROUP *group, 1652e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 1653e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 1654e1051a39Sopenharmony_ci{ 1655e1051a39Sopenharmony_ci int ret = 0; 1656e1051a39Sopenharmony_ci BIGNUM *t0, *t1, *t2, *t3, *t4, *t5, *t6 = NULL; 1657e1051a39Sopenharmony_ci 1658e1051a39Sopenharmony_ci if (BN_is_zero(r->Z)) 1659e1051a39Sopenharmony_ci return EC_POINT_set_to_infinity(group, r); 1660e1051a39Sopenharmony_ci 1661e1051a39Sopenharmony_ci if (BN_is_zero(s->Z)) { 1662e1051a39Sopenharmony_ci if (!EC_POINT_copy(r, p) 1663e1051a39Sopenharmony_ci || !EC_POINT_invert(group, r, ctx)) 1664e1051a39Sopenharmony_ci return 0; 1665e1051a39Sopenharmony_ci return 1; 1666e1051a39Sopenharmony_ci } 1667e1051a39Sopenharmony_ci 1668e1051a39Sopenharmony_ci BN_CTX_start(ctx); 1669e1051a39Sopenharmony_ci t0 = BN_CTX_get(ctx); 1670e1051a39Sopenharmony_ci t1 = BN_CTX_get(ctx); 1671e1051a39Sopenharmony_ci t2 = BN_CTX_get(ctx); 1672e1051a39Sopenharmony_ci t3 = BN_CTX_get(ctx); 1673e1051a39Sopenharmony_ci t4 = BN_CTX_get(ctx); 1674e1051a39Sopenharmony_ci t5 = BN_CTX_get(ctx); 1675e1051a39Sopenharmony_ci t6 = BN_CTX_get(ctx); 1676e1051a39Sopenharmony_ci 1677e1051a39Sopenharmony_ci if (t6 == NULL 1678e1051a39Sopenharmony_ci || !BN_mod_lshift1_quick(t4, p->Y, group->field) 1679e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, r->X, t4, ctx) 1680e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, s->Z, t6, ctx) 1681e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t5, r->Z, t6, ctx) 1682e1051a39Sopenharmony_ci || !BN_mod_lshift1_quick(t1, group->b, group->field) 1683e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, s->Z, t1, ctx) 1684e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t3, r->Z, ctx) 1685e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, t3, t1, ctx) 1686e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, r->Z, group->a, ctx) 1687e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, p->X, r->X, ctx) 1688e1051a39Sopenharmony_ci || !BN_mod_add_quick(t1, t1, t6, group->field) 1689e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, s->Z, t1, ctx) 1690e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, p->X, r->Z, ctx) 1691e1051a39Sopenharmony_ci || !BN_mod_add_quick(t6, r->X, t0, group->field) 1692e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t6, t6, t1, ctx) 1693e1051a39Sopenharmony_ci || !BN_mod_add_quick(t6, t6, t2, group->field) 1694e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t0, t0, r->X, group->field) 1695e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t0, t0, ctx) 1696e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t0, t0, s->X, ctx) 1697e1051a39Sopenharmony_ci || !BN_mod_sub_quick(t0, t6, t0, group->field) 1698e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, s->Z, t4, ctx) 1699e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, t3, t1, ctx) 1700e1051a39Sopenharmony_ci || (group->meth->field_decode != NULL 1701e1051a39Sopenharmony_ci && !group->meth->field_decode(group, t1, t1, ctx)) 1702e1051a39Sopenharmony_ci || !group->meth->field_inv(group, t1, t1, ctx) 1703e1051a39Sopenharmony_ci || (group->meth->field_encode != NULL 1704e1051a39Sopenharmony_ci && !group->meth->field_encode(group, t1, t1, ctx)) 1705e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->X, t5, t1, ctx) 1706e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->Y, t0, t1, ctx)) 1707e1051a39Sopenharmony_ci goto err; 1708e1051a39Sopenharmony_ci 1709e1051a39Sopenharmony_ci if (group->meth->field_set_to_one != NULL) { 1710e1051a39Sopenharmony_ci if (!group->meth->field_set_to_one(group, r->Z, ctx)) 1711e1051a39Sopenharmony_ci goto err; 1712e1051a39Sopenharmony_ci } else { 1713e1051a39Sopenharmony_ci if (!BN_one(r->Z)) 1714e1051a39Sopenharmony_ci goto err; 1715e1051a39Sopenharmony_ci } 1716e1051a39Sopenharmony_ci 1717e1051a39Sopenharmony_ci r->Z_is_one = 1; 1718e1051a39Sopenharmony_ci ret = 1; 1719e1051a39Sopenharmony_ci 1720e1051a39Sopenharmony_ci err: 1721e1051a39Sopenharmony_ci BN_CTX_end(ctx); 1722e1051a39Sopenharmony_ci return ret; 1723e1051a39Sopenharmony_ci} 1724