1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2002-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 19e1051a39Sopenharmony_ci#include "crypto/bn.h" 20e1051a39Sopenharmony_ci#include "ec_local.h" 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_EC2M 23e1051a39Sopenharmony_ci 24e1051a39Sopenharmony_ci/* 25e1051a39Sopenharmony_ci * Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members 26e1051a39Sopenharmony_ci * are handled by EC_GROUP_new. 27e1051a39Sopenharmony_ci */ 28e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_init(EC_GROUP *group) 29e1051a39Sopenharmony_ci{ 30e1051a39Sopenharmony_ci group->field = BN_new(); 31e1051a39Sopenharmony_ci group->a = BN_new(); 32e1051a39Sopenharmony_ci group->b = BN_new(); 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_ci if (group->field == NULL || group->a == NULL || group->b == NULL) { 35e1051a39Sopenharmony_ci BN_free(group->field); 36e1051a39Sopenharmony_ci BN_free(group->a); 37e1051a39Sopenharmony_ci BN_free(group->b); 38e1051a39Sopenharmony_ci return 0; 39e1051a39Sopenharmony_ci } 40e1051a39Sopenharmony_ci return 1; 41e1051a39Sopenharmony_ci} 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ci/* 44e1051a39Sopenharmony_ci * Free a GF(2^m)-based EC_GROUP structure. Note that all other members are 45e1051a39Sopenharmony_ci * handled by EC_GROUP_free. 46e1051a39Sopenharmony_ci */ 47e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_group_finish(EC_GROUP *group) 48e1051a39Sopenharmony_ci{ 49e1051a39Sopenharmony_ci BN_free(group->field); 50e1051a39Sopenharmony_ci BN_free(group->a); 51e1051a39Sopenharmony_ci BN_free(group->b); 52e1051a39Sopenharmony_ci} 53e1051a39Sopenharmony_ci 54e1051a39Sopenharmony_ci/* 55e1051a39Sopenharmony_ci * Clear and free a GF(2^m)-based EC_GROUP structure. Note that all other 56e1051a39Sopenharmony_ci * members are handled by EC_GROUP_clear_free. 57e1051a39Sopenharmony_ci */ 58e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_group_clear_finish(EC_GROUP *group) 59e1051a39Sopenharmony_ci{ 60e1051a39Sopenharmony_ci BN_clear_free(group->field); 61e1051a39Sopenharmony_ci BN_clear_free(group->a); 62e1051a39Sopenharmony_ci BN_clear_free(group->b); 63e1051a39Sopenharmony_ci group->poly[0] = 0; 64e1051a39Sopenharmony_ci group->poly[1] = 0; 65e1051a39Sopenharmony_ci group->poly[2] = 0; 66e1051a39Sopenharmony_ci group->poly[3] = 0; 67e1051a39Sopenharmony_ci group->poly[4] = 0; 68e1051a39Sopenharmony_ci group->poly[5] = -1; 69e1051a39Sopenharmony_ci} 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_ci/* 72e1051a39Sopenharmony_ci * Copy a GF(2^m)-based EC_GROUP structure. Note that all other members are 73e1051a39Sopenharmony_ci * handled by EC_GROUP_copy. 74e1051a39Sopenharmony_ci */ 75e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) 76e1051a39Sopenharmony_ci{ 77e1051a39Sopenharmony_ci if (!BN_copy(dest->field, src->field)) 78e1051a39Sopenharmony_ci return 0; 79e1051a39Sopenharmony_ci if (!BN_copy(dest->a, src->a)) 80e1051a39Sopenharmony_ci return 0; 81e1051a39Sopenharmony_ci if (!BN_copy(dest->b, src->b)) 82e1051a39Sopenharmony_ci return 0; 83e1051a39Sopenharmony_ci dest->poly[0] = src->poly[0]; 84e1051a39Sopenharmony_ci dest->poly[1] = src->poly[1]; 85e1051a39Sopenharmony_ci dest->poly[2] = src->poly[2]; 86e1051a39Sopenharmony_ci dest->poly[3] = src->poly[3]; 87e1051a39Sopenharmony_ci dest->poly[4] = src->poly[4]; 88e1051a39Sopenharmony_ci dest->poly[5] = src->poly[5]; 89e1051a39Sopenharmony_ci if (bn_wexpand(dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == 90e1051a39Sopenharmony_ci NULL) 91e1051a39Sopenharmony_ci return 0; 92e1051a39Sopenharmony_ci if (bn_wexpand(dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == 93e1051a39Sopenharmony_ci NULL) 94e1051a39Sopenharmony_ci return 0; 95e1051a39Sopenharmony_ci bn_set_all_zero(dest->a); 96e1051a39Sopenharmony_ci bn_set_all_zero(dest->b); 97e1051a39Sopenharmony_ci return 1; 98e1051a39Sopenharmony_ci} 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_ci/* Set the curve parameters of an EC_GROUP structure. */ 101e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_set_curve(EC_GROUP *group, 102e1051a39Sopenharmony_ci const BIGNUM *p, const BIGNUM *a, 103e1051a39Sopenharmony_ci const BIGNUM *b, BN_CTX *ctx) 104e1051a39Sopenharmony_ci{ 105e1051a39Sopenharmony_ci int ret = 0, i; 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_ci /* group->field */ 108e1051a39Sopenharmony_ci if (!BN_copy(group->field, p)) 109e1051a39Sopenharmony_ci goto err; 110e1051a39Sopenharmony_ci i = BN_GF2m_poly2arr(group->field, group->poly, 6) - 1; 111e1051a39Sopenharmony_ci if ((i != 5) && (i != 3)) { 112e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_UNSUPPORTED_FIELD); 113e1051a39Sopenharmony_ci goto err; 114e1051a39Sopenharmony_ci } 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_ci /* group->a */ 117e1051a39Sopenharmony_ci if (!BN_GF2m_mod_arr(group->a, a, group->poly)) 118e1051a39Sopenharmony_ci goto err; 119e1051a39Sopenharmony_ci if (bn_wexpand(group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2) 120e1051a39Sopenharmony_ci == NULL) 121e1051a39Sopenharmony_ci goto err; 122e1051a39Sopenharmony_ci bn_set_all_zero(group->a); 123e1051a39Sopenharmony_ci 124e1051a39Sopenharmony_ci /* group->b */ 125e1051a39Sopenharmony_ci if (!BN_GF2m_mod_arr(group->b, b, group->poly)) 126e1051a39Sopenharmony_ci goto err; 127e1051a39Sopenharmony_ci if (bn_wexpand(group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2) 128e1051a39Sopenharmony_ci == NULL) 129e1051a39Sopenharmony_ci goto err; 130e1051a39Sopenharmony_ci bn_set_all_zero(group->b); 131e1051a39Sopenharmony_ci 132e1051a39Sopenharmony_ci ret = 1; 133e1051a39Sopenharmony_ci err: 134e1051a39Sopenharmony_ci return ret; 135e1051a39Sopenharmony_ci} 136e1051a39Sopenharmony_ci 137e1051a39Sopenharmony_ci/* 138e1051a39Sopenharmony_ci * Get the curve parameters of an EC_GROUP structure. If p, a, or b are NULL 139e1051a39Sopenharmony_ci * then there values will not be set but the method will return with success. 140e1051a39Sopenharmony_ci */ 141e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, 142e1051a39Sopenharmony_ci BIGNUM *a, BIGNUM *b, BN_CTX *ctx) 143e1051a39Sopenharmony_ci{ 144e1051a39Sopenharmony_ci int ret = 0; 145e1051a39Sopenharmony_ci 146e1051a39Sopenharmony_ci if (p != NULL) { 147e1051a39Sopenharmony_ci if (!BN_copy(p, group->field)) 148e1051a39Sopenharmony_ci return 0; 149e1051a39Sopenharmony_ci } 150e1051a39Sopenharmony_ci 151e1051a39Sopenharmony_ci if (a != NULL) { 152e1051a39Sopenharmony_ci if (!BN_copy(a, group->a)) 153e1051a39Sopenharmony_ci goto err; 154e1051a39Sopenharmony_ci } 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci if (b != NULL) { 157e1051a39Sopenharmony_ci if (!BN_copy(b, group->b)) 158e1051a39Sopenharmony_ci goto err; 159e1051a39Sopenharmony_ci } 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci ret = 1; 162e1051a39Sopenharmony_ci 163e1051a39Sopenharmony_ci err: 164e1051a39Sopenharmony_ci return ret; 165e1051a39Sopenharmony_ci} 166e1051a39Sopenharmony_ci 167e1051a39Sopenharmony_ci/* 168e1051a39Sopenharmony_ci * Gets the degree of the field. For a curve over GF(2^m) this is the value 169e1051a39Sopenharmony_ci * m. 170e1051a39Sopenharmony_ci */ 171e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_get_degree(const EC_GROUP *group) 172e1051a39Sopenharmony_ci{ 173e1051a39Sopenharmony_ci return BN_num_bits(group->field) - 1; 174e1051a39Sopenharmony_ci} 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci/* 177e1051a39Sopenharmony_ci * Checks the discriminant of the curve. y^2 + x*y = x^3 + a*x^2 + b is an 178e1051a39Sopenharmony_ci * elliptic curve <=> b != 0 (mod p) 179e1051a39Sopenharmony_ci */ 180e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group, 181e1051a39Sopenharmony_ci BN_CTX *ctx) 182e1051a39Sopenharmony_ci{ 183e1051a39Sopenharmony_ci int ret = 0; 184e1051a39Sopenharmony_ci BIGNUM *b; 185e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 186e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci if (ctx == NULL) { 189e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new(); 190e1051a39Sopenharmony_ci if (ctx == NULL) { 191e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); 192e1051a39Sopenharmony_ci goto err; 193e1051a39Sopenharmony_ci } 194e1051a39Sopenharmony_ci } 195e1051a39Sopenharmony_ci#endif 196e1051a39Sopenharmony_ci BN_CTX_start(ctx); 197e1051a39Sopenharmony_ci b = BN_CTX_get(ctx); 198e1051a39Sopenharmony_ci if (b == NULL) 199e1051a39Sopenharmony_ci goto err; 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci if (!BN_GF2m_mod_arr(b, group->b, group->poly)) 202e1051a39Sopenharmony_ci goto err; 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci /* 205e1051a39Sopenharmony_ci * check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic 206e1051a39Sopenharmony_ci * curve <=> b != 0 (mod p) 207e1051a39Sopenharmony_ci */ 208e1051a39Sopenharmony_ci if (BN_is_zero(b)) 209e1051a39Sopenharmony_ci goto err; 210e1051a39Sopenharmony_ci 211e1051a39Sopenharmony_ci ret = 1; 212e1051a39Sopenharmony_ci 213e1051a39Sopenharmony_ci err: 214e1051a39Sopenharmony_ci BN_CTX_end(ctx); 215e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 216e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 217e1051a39Sopenharmony_ci#endif 218e1051a39Sopenharmony_ci return ret; 219e1051a39Sopenharmony_ci} 220e1051a39Sopenharmony_ci 221e1051a39Sopenharmony_ci/* Initializes an EC_POINT. */ 222e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_init(EC_POINT *point) 223e1051a39Sopenharmony_ci{ 224e1051a39Sopenharmony_ci point->X = BN_new(); 225e1051a39Sopenharmony_ci point->Y = BN_new(); 226e1051a39Sopenharmony_ci point->Z = BN_new(); 227e1051a39Sopenharmony_ci 228e1051a39Sopenharmony_ci if (point->X == NULL || point->Y == NULL || point->Z == NULL) { 229e1051a39Sopenharmony_ci BN_free(point->X); 230e1051a39Sopenharmony_ci BN_free(point->Y); 231e1051a39Sopenharmony_ci BN_free(point->Z); 232e1051a39Sopenharmony_ci return 0; 233e1051a39Sopenharmony_ci } 234e1051a39Sopenharmony_ci return 1; 235e1051a39Sopenharmony_ci} 236e1051a39Sopenharmony_ci 237e1051a39Sopenharmony_ci/* Frees an EC_POINT. */ 238e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_point_finish(EC_POINT *point) 239e1051a39Sopenharmony_ci{ 240e1051a39Sopenharmony_ci BN_free(point->X); 241e1051a39Sopenharmony_ci BN_free(point->Y); 242e1051a39Sopenharmony_ci BN_free(point->Z); 243e1051a39Sopenharmony_ci} 244e1051a39Sopenharmony_ci 245e1051a39Sopenharmony_ci/* Clears and frees an EC_POINT. */ 246e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_point_clear_finish(EC_POINT *point) 247e1051a39Sopenharmony_ci{ 248e1051a39Sopenharmony_ci BN_clear_free(point->X); 249e1051a39Sopenharmony_ci BN_clear_free(point->Y); 250e1051a39Sopenharmony_ci BN_clear_free(point->Z); 251e1051a39Sopenharmony_ci point->Z_is_one = 0; 252e1051a39Sopenharmony_ci} 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_ci/* 255e1051a39Sopenharmony_ci * Copy the contents of one EC_POINT into another. Assumes dest is 256e1051a39Sopenharmony_ci * initialized. 257e1051a39Sopenharmony_ci */ 258e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src) 259e1051a39Sopenharmony_ci{ 260e1051a39Sopenharmony_ci if (!BN_copy(dest->X, src->X)) 261e1051a39Sopenharmony_ci return 0; 262e1051a39Sopenharmony_ci if (!BN_copy(dest->Y, src->Y)) 263e1051a39Sopenharmony_ci return 0; 264e1051a39Sopenharmony_ci if (!BN_copy(dest->Z, src->Z)) 265e1051a39Sopenharmony_ci return 0; 266e1051a39Sopenharmony_ci dest->Z_is_one = src->Z_is_one; 267e1051a39Sopenharmony_ci dest->curve_name = src->curve_name; 268e1051a39Sopenharmony_ci 269e1051a39Sopenharmony_ci return 1; 270e1051a39Sopenharmony_ci} 271e1051a39Sopenharmony_ci 272e1051a39Sopenharmony_ci/* 273e1051a39Sopenharmony_ci * Set an EC_POINT to the point at infinity. A point at infinity is 274e1051a39Sopenharmony_ci * represented by having Z=0. 275e1051a39Sopenharmony_ci */ 276e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group, 277e1051a39Sopenharmony_ci EC_POINT *point) 278e1051a39Sopenharmony_ci{ 279e1051a39Sopenharmony_ci point->Z_is_one = 0; 280e1051a39Sopenharmony_ci BN_zero(point->Z); 281e1051a39Sopenharmony_ci return 1; 282e1051a39Sopenharmony_ci} 283e1051a39Sopenharmony_ci 284e1051a39Sopenharmony_ci/* 285e1051a39Sopenharmony_ci * Set the coordinates of an EC_POINT using affine coordinates. Note that 286e1051a39Sopenharmony_ci * the simple implementation only uses affine coordinates. 287e1051a39Sopenharmony_ci */ 288e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group, 289e1051a39Sopenharmony_ci EC_POINT *point, 290e1051a39Sopenharmony_ci const BIGNUM *x, 291e1051a39Sopenharmony_ci const BIGNUM *y, 292e1051a39Sopenharmony_ci BN_CTX *ctx) 293e1051a39Sopenharmony_ci{ 294e1051a39Sopenharmony_ci int ret = 0; 295e1051a39Sopenharmony_ci if (x == NULL || y == NULL) { 296e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_PASSED_NULL_PARAMETER); 297e1051a39Sopenharmony_ci return 0; 298e1051a39Sopenharmony_ci } 299e1051a39Sopenharmony_ci 300e1051a39Sopenharmony_ci if (!BN_copy(point->X, x)) 301e1051a39Sopenharmony_ci goto err; 302e1051a39Sopenharmony_ci BN_set_negative(point->X, 0); 303e1051a39Sopenharmony_ci if (!BN_copy(point->Y, y)) 304e1051a39Sopenharmony_ci goto err; 305e1051a39Sopenharmony_ci BN_set_negative(point->Y, 0); 306e1051a39Sopenharmony_ci if (!BN_copy(point->Z, BN_value_one())) 307e1051a39Sopenharmony_ci goto err; 308e1051a39Sopenharmony_ci BN_set_negative(point->Z, 0); 309e1051a39Sopenharmony_ci point->Z_is_one = 1; 310e1051a39Sopenharmony_ci ret = 1; 311e1051a39Sopenharmony_ci 312e1051a39Sopenharmony_ci err: 313e1051a39Sopenharmony_ci return ret; 314e1051a39Sopenharmony_ci} 315e1051a39Sopenharmony_ci 316e1051a39Sopenharmony_ci/* 317e1051a39Sopenharmony_ci * Gets the affine coordinates of an EC_POINT. Note that the simple 318e1051a39Sopenharmony_ci * implementation only uses affine coordinates. 319e1051a39Sopenharmony_ci */ 320e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, 321e1051a39Sopenharmony_ci const EC_POINT *point, 322e1051a39Sopenharmony_ci BIGNUM *x, BIGNUM *y, 323e1051a39Sopenharmony_ci BN_CTX *ctx) 324e1051a39Sopenharmony_ci{ 325e1051a39Sopenharmony_ci int ret = 0; 326e1051a39Sopenharmony_ci 327e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point)) { 328e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_POINT_AT_INFINITY); 329e1051a39Sopenharmony_ci return 0; 330e1051a39Sopenharmony_ci } 331e1051a39Sopenharmony_ci 332e1051a39Sopenharmony_ci if (BN_cmp(point->Z, BN_value_one())) { 333e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 334e1051a39Sopenharmony_ci return 0; 335e1051a39Sopenharmony_ci } 336e1051a39Sopenharmony_ci if (x != NULL) { 337e1051a39Sopenharmony_ci if (!BN_copy(x, point->X)) 338e1051a39Sopenharmony_ci goto err; 339e1051a39Sopenharmony_ci BN_set_negative(x, 0); 340e1051a39Sopenharmony_ci } 341e1051a39Sopenharmony_ci if (y != NULL) { 342e1051a39Sopenharmony_ci if (!BN_copy(y, point->Y)) 343e1051a39Sopenharmony_ci goto err; 344e1051a39Sopenharmony_ci BN_set_negative(y, 0); 345e1051a39Sopenharmony_ci } 346e1051a39Sopenharmony_ci ret = 1; 347e1051a39Sopenharmony_ci 348e1051a39Sopenharmony_ci err: 349e1051a39Sopenharmony_ci return ret; 350e1051a39Sopenharmony_ci} 351e1051a39Sopenharmony_ci 352e1051a39Sopenharmony_ci/* 353e1051a39Sopenharmony_ci * Computes a + b and stores the result in r. r could be a or b, a could be 354e1051a39Sopenharmony_ci * b. Uses algorithm A.10.2 of IEEE P1363. 355e1051a39Sopenharmony_ci */ 356e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, 357e1051a39Sopenharmony_ci const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) 358e1051a39Sopenharmony_ci{ 359e1051a39Sopenharmony_ci BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t; 360e1051a39Sopenharmony_ci int ret = 0; 361e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 362e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 363e1051a39Sopenharmony_ci#endif 364e1051a39Sopenharmony_ci 365e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, a)) { 366e1051a39Sopenharmony_ci if (!EC_POINT_copy(r, b)) 367e1051a39Sopenharmony_ci return 0; 368e1051a39Sopenharmony_ci return 1; 369e1051a39Sopenharmony_ci } 370e1051a39Sopenharmony_ci 371e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, b)) { 372e1051a39Sopenharmony_ci if (!EC_POINT_copy(r, a)) 373e1051a39Sopenharmony_ci return 0; 374e1051a39Sopenharmony_ci return 1; 375e1051a39Sopenharmony_ci } 376e1051a39Sopenharmony_ci 377e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 378e1051a39Sopenharmony_ci if (ctx == NULL) { 379e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new(); 380e1051a39Sopenharmony_ci if (ctx == NULL) 381e1051a39Sopenharmony_ci return 0; 382e1051a39Sopenharmony_ci } 383e1051a39Sopenharmony_ci#endif 384e1051a39Sopenharmony_ci 385e1051a39Sopenharmony_ci BN_CTX_start(ctx); 386e1051a39Sopenharmony_ci x0 = BN_CTX_get(ctx); 387e1051a39Sopenharmony_ci y0 = BN_CTX_get(ctx); 388e1051a39Sopenharmony_ci x1 = BN_CTX_get(ctx); 389e1051a39Sopenharmony_ci y1 = BN_CTX_get(ctx); 390e1051a39Sopenharmony_ci x2 = BN_CTX_get(ctx); 391e1051a39Sopenharmony_ci y2 = BN_CTX_get(ctx); 392e1051a39Sopenharmony_ci s = BN_CTX_get(ctx); 393e1051a39Sopenharmony_ci t = BN_CTX_get(ctx); 394e1051a39Sopenharmony_ci if (t == NULL) 395e1051a39Sopenharmony_ci goto err; 396e1051a39Sopenharmony_ci 397e1051a39Sopenharmony_ci if (a->Z_is_one) { 398e1051a39Sopenharmony_ci if (!BN_copy(x0, a->X)) 399e1051a39Sopenharmony_ci goto err; 400e1051a39Sopenharmony_ci if (!BN_copy(y0, a->Y)) 401e1051a39Sopenharmony_ci goto err; 402e1051a39Sopenharmony_ci } else { 403e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, a, x0, y0, ctx)) 404e1051a39Sopenharmony_ci goto err; 405e1051a39Sopenharmony_ci } 406e1051a39Sopenharmony_ci if (b->Z_is_one) { 407e1051a39Sopenharmony_ci if (!BN_copy(x1, b->X)) 408e1051a39Sopenharmony_ci goto err; 409e1051a39Sopenharmony_ci if (!BN_copy(y1, b->Y)) 410e1051a39Sopenharmony_ci goto err; 411e1051a39Sopenharmony_ci } else { 412e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, b, x1, y1, ctx)) 413e1051a39Sopenharmony_ci goto err; 414e1051a39Sopenharmony_ci } 415e1051a39Sopenharmony_ci 416e1051a39Sopenharmony_ci if (BN_GF2m_cmp(x0, x1)) { 417e1051a39Sopenharmony_ci if (!BN_GF2m_add(t, x0, x1)) 418e1051a39Sopenharmony_ci goto err; 419e1051a39Sopenharmony_ci if (!BN_GF2m_add(s, y0, y1)) 420e1051a39Sopenharmony_ci goto err; 421e1051a39Sopenharmony_ci if (!group->meth->field_div(group, s, s, t, ctx)) 422e1051a39Sopenharmony_ci goto err; 423e1051a39Sopenharmony_ci if (!group->meth->field_sqr(group, x2, s, ctx)) 424e1051a39Sopenharmony_ci goto err; 425e1051a39Sopenharmony_ci if (!BN_GF2m_add(x2, x2, group->a)) 426e1051a39Sopenharmony_ci goto err; 427e1051a39Sopenharmony_ci if (!BN_GF2m_add(x2, x2, s)) 428e1051a39Sopenharmony_ci goto err; 429e1051a39Sopenharmony_ci if (!BN_GF2m_add(x2, x2, t)) 430e1051a39Sopenharmony_ci goto err; 431e1051a39Sopenharmony_ci } else { 432e1051a39Sopenharmony_ci if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) { 433e1051a39Sopenharmony_ci if (!EC_POINT_set_to_infinity(group, r)) 434e1051a39Sopenharmony_ci goto err; 435e1051a39Sopenharmony_ci ret = 1; 436e1051a39Sopenharmony_ci goto err; 437e1051a39Sopenharmony_ci } 438e1051a39Sopenharmony_ci if (!group->meth->field_div(group, s, y1, x1, ctx)) 439e1051a39Sopenharmony_ci goto err; 440e1051a39Sopenharmony_ci if (!BN_GF2m_add(s, s, x1)) 441e1051a39Sopenharmony_ci goto err; 442e1051a39Sopenharmony_ci 443e1051a39Sopenharmony_ci if (!group->meth->field_sqr(group, x2, s, ctx)) 444e1051a39Sopenharmony_ci goto err; 445e1051a39Sopenharmony_ci if (!BN_GF2m_add(x2, x2, s)) 446e1051a39Sopenharmony_ci goto err; 447e1051a39Sopenharmony_ci if (!BN_GF2m_add(x2, x2, group->a)) 448e1051a39Sopenharmony_ci goto err; 449e1051a39Sopenharmony_ci } 450e1051a39Sopenharmony_ci 451e1051a39Sopenharmony_ci if (!BN_GF2m_add(y2, x1, x2)) 452e1051a39Sopenharmony_ci goto err; 453e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, y2, y2, s, ctx)) 454e1051a39Sopenharmony_ci goto err; 455e1051a39Sopenharmony_ci if (!BN_GF2m_add(y2, y2, x2)) 456e1051a39Sopenharmony_ci goto err; 457e1051a39Sopenharmony_ci if (!BN_GF2m_add(y2, y2, y1)) 458e1051a39Sopenharmony_ci goto err; 459e1051a39Sopenharmony_ci 460e1051a39Sopenharmony_ci if (!EC_POINT_set_affine_coordinates(group, r, x2, y2, ctx)) 461e1051a39Sopenharmony_ci goto err; 462e1051a39Sopenharmony_ci 463e1051a39Sopenharmony_ci ret = 1; 464e1051a39Sopenharmony_ci 465e1051a39Sopenharmony_ci err: 466e1051a39Sopenharmony_ci BN_CTX_end(ctx); 467e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 468e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 469e1051a39Sopenharmony_ci#endif 470e1051a39Sopenharmony_ci return ret; 471e1051a39Sopenharmony_ci} 472e1051a39Sopenharmony_ci 473e1051a39Sopenharmony_ci/* 474e1051a39Sopenharmony_ci * Computes 2 * a and stores the result in r. r could be a. Uses algorithm 475e1051a39Sopenharmony_ci * A.10.2 of IEEE P1363. 476e1051a39Sopenharmony_ci */ 477e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, 478e1051a39Sopenharmony_ci const EC_POINT *a, BN_CTX *ctx) 479e1051a39Sopenharmony_ci{ 480e1051a39Sopenharmony_ci return ossl_ec_GF2m_simple_add(group, r, a, a, ctx); 481e1051a39Sopenharmony_ci} 482e1051a39Sopenharmony_ci 483e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, 484e1051a39Sopenharmony_ci BN_CTX *ctx) 485e1051a39Sopenharmony_ci{ 486e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y)) 487e1051a39Sopenharmony_ci /* point is its own inverse */ 488e1051a39Sopenharmony_ci return 1; 489e1051a39Sopenharmony_ci 490e1051a39Sopenharmony_ci if (group->meth->make_affine == NULL 491e1051a39Sopenharmony_ci || !group->meth->make_affine(group, point, ctx)) 492e1051a39Sopenharmony_ci return 0; 493e1051a39Sopenharmony_ci return BN_GF2m_add(point->Y, point->X, point->Y); 494e1051a39Sopenharmony_ci} 495e1051a39Sopenharmony_ci 496e1051a39Sopenharmony_ci/* Indicates whether the given point is the point at infinity. */ 497e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_is_at_infinity(const EC_GROUP *group, 498e1051a39Sopenharmony_ci const EC_POINT *point) 499e1051a39Sopenharmony_ci{ 500e1051a39Sopenharmony_ci return BN_is_zero(point->Z); 501e1051a39Sopenharmony_ci} 502e1051a39Sopenharmony_ci 503e1051a39Sopenharmony_ci/*- 504e1051a39Sopenharmony_ci * Determines whether the given EC_POINT is an actual point on the curve defined 505e1051a39Sopenharmony_ci * in the EC_GROUP. A point is valid if it satisfies the Weierstrass equation: 506e1051a39Sopenharmony_ci * y^2 + x*y = x^3 + a*x^2 + b. 507e1051a39Sopenharmony_ci */ 508e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, 509e1051a39Sopenharmony_ci BN_CTX *ctx) 510e1051a39Sopenharmony_ci{ 511e1051a39Sopenharmony_ci int ret = -1; 512e1051a39Sopenharmony_ci BIGNUM *lh, *y2; 513e1051a39Sopenharmony_ci int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, 514e1051a39Sopenharmony_ci const BIGNUM *, BN_CTX *); 515e1051a39Sopenharmony_ci int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); 516e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 517e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 518e1051a39Sopenharmony_ci#endif 519e1051a39Sopenharmony_ci 520e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, point)) 521e1051a39Sopenharmony_ci return 1; 522e1051a39Sopenharmony_ci 523e1051a39Sopenharmony_ci field_mul = group->meth->field_mul; 524e1051a39Sopenharmony_ci field_sqr = group->meth->field_sqr; 525e1051a39Sopenharmony_ci 526e1051a39Sopenharmony_ci /* only support affine coordinates */ 527e1051a39Sopenharmony_ci if (!point->Z_is_one) 528e1051a39Sopenharmony_ci return -1; 529e1051a39Sopenharmony_ci 530e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 531e1051a39Sopenharmony_ci if (ctx == NULL) { 532e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new(); 533e1051a39Sopenharmony_ci if (ctx == NULL) 534e1051a39Sopenharmony_ci return -1; 535e1051a39Sopenharmony_ci } 536e1051a39Sopenharmony_ci#endif 537e1051a39Sopenharmony_ci 538e1051a39Sopenharmony_ci BN_CTX_start(ctx); 539e1051a39Sopenharmony_ci y2 = BN_CTX_get(ctx); 540e1051a39Sopenharmony_ci lh = BN_CTX_get(ctx); 541e1051a39Sopenharmony_ci if (lh == NULL) 542e1051a39Sopenharmony_ci goto err; 543e1051a39Sopenharmony_ci 544e1051a39Sopenharmony_ci /*- 545e1051a39Sopenharmony_ci * We have a curve defined by a Weierstrass equation 546e1051a39Sopenharmony_ci * y^2 + x*y = x^3 + a*x^2 + b. 547e1051a39Sopenharmony_ci * <=> x^3 + a*x^2 + x*y + b + y^2 = 0 548e1051a39Sopenharmony_ci * <=> ((x + a) * x + y ) * x + b + y^2 = 0 549e1051a39Sopenharmony_ci */ 550e1051a39Sopenharmony_ci if (!BN_GF2m_add(lh, point->X, group->a)) 551e1051a39Sopenharmony_ci goto err; 552e1051a39Sopenharmony_ci if (!field_mul(group, lh, lh, point->X, ctx)) 553e1051a39Sopenharmony_ci goto err; 554e1051a39Sopenharmony_ci if (!BN_GF2m_add(lh, lh, point->Y)) 555e1051a39Sopenharmony_ci goto err; 556e1051a39Sopenharmony_ci if (!field_mul(group, lh, lh, point->X, ctx)) 557e1051a39Sopenharmony_ci goto err; 558e1051a39Sopenharmony_ci if (!BN_GF2m_add(lh, lh, group->b)) 559e1051a39Sopenharmony_ci goto err; 560e1051a39Sopenharmony_ci if (!field_sqr(group, y2, point->Y, ctx)) 561e1051a39Sopenharmony_ci goto err; 562e1051a39Sopenharmony_ci if (!BN_GF2m_add(lh, lh, y2)) 563e1051a39Sopenharmony_ci goto err; 564e1051a39Sopenharmony_ci ret = BN_is_zero(lh); 565e1051a39Sopenharmony_ci 566e1051a39Sopenharmony_ci err: 567e1051a39Sopenharmony_ci BN_CTX_end(ctx); 568e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 569e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 570e1051a39Sopenharmony_ci#endif 571e1051a39Sopenharmony_ci return ret; 572e1051a39Sopenharmony_ci} 573e1051a39Sopenharmony_ci 574e1051a39Sopenharmony_ci/*- 575e1051a39Sopenharmony_ci * Indicates whether two points are equal. 576e1051a39Sopenharmony_ci * Return values: 577e1051a39Sopenharmony_ci * -1 error 578e1051a39Sopenharmony_ci * 0 equal (in affine coordinates) 579e1051a39Sopenharmony_ci * 1 not equal 580e1051a39Sopenharmony_ci */ 581e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a, 582e1051a39Sopenharmony_ci const EC_POINT *b, BN_CTX *ctx) 583e1051a39Sopenharmony_ci{ 584e1051a39Sopenharmony_ci BIGNUM *aX, *aY, *bX, *bY; 585e1051a39Sopenharmony_ci int ret = -1; 586e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 587e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 588e1051a39Sopenharmony_ci#endif 589e1051a39Sopenharmony_ci 590e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, a)) { 591e1051a39Sopenharmony_ci return EC_POINT_is_at_infinity(group, b) ? 0 : 1; 592e1051a39Sopenharmony_ci } 593e1051a39Sopenharmony_ci 594e1051a39Sopenharmony_ci if (EC_POINT_is_at_infinity(group, b)) 595e1051a39Sopenharmony_ci return 1; 596e1051a39Sopenharmony_ci 597e1051a39Sopenharmony_ci if (a->Z_is_one && b->Z_is_one) { 598e1051a39Sopenharmony_ci return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1; 599e1051a39Sopenharmony_ci } 600e1051a39Sopenharmony_ci 601e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 602e1051a39Sopenharmony_ci if (ctx == NULL) { 603e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new(); 604e1051a39Sopenharmony_ci if (ctx == NULL) 605e1051a39Sopenharmony_ci return -1; 606e1051a39Sopenharmony_ci } 607e1051a39Sopenharmony_ci#endif 608e1051a39Sopenharmony_ci 609e1051a39Sopenharmony_ci BN_CTX_start(ctx); 610e1051a39Sopenharmony_ci aX = BN_CTX_get(ctx); 611e1051a39Sopenharmony_ci aY = BN_CTX_get(ctx); 612e1051a39Sopenharmony_ci bX = BN_CTX_get(ctx); 613e1051a39Sopenharmony_ci bY = BN_CTX_get(ctx); 614e1051a39Sopenharmony_ci if (bY == NULL) 615e1051a39Sopenharmony_ci goto err; 616e1051a39Sopenharmony_ci 617e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, a, aX, aY, ctx)) 618e1051a39Sopenharmony_ci goto err; 619e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, b, bX, bY, ctx)) 620e1051a39Sopenharmony_ci goto err; 621e1051a39Sopenharmony_ci ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1; 622e1051a39Sopenharmony_ci 623e1051a39Sopenharmony_ci err: 624e1051a39Sopenharmony_ci BN_CTX_end(ctx); 625e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 626e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 627e1051a39Sopenharmony_ci#endif 628e1051a39Sopenharmony_ci return ret; 629e1051a39Sopenharmony_ci} 630e1051a39Sopenharmony_ci 631e1051a39Sopenharmony_ci/* Forces the given EC_POINT to internally use affine coordinates. */ 632e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point, 633e1051a39Sopenharmony_ci BN_CTX *ctx) 634e1051a39Sopenharmony_ci{ 635e1051a39Sopenharmony_ci BIGNUM *x, *y; 636e1051a39Sopenharmony_ci int ret = 0; 637e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 638e1051a39Sopenharmony_ci BN_CTX *new_ctx = NULL; 639e1051a39Sopenharmony_ci#endif 640e1051a39Sopenharmony_ci 641e1051a39Sopenharmony_ci if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) 642e1051a39Sopenharmony_ci return 1; 643e1051a39Sopenharmony_ci 644e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 645e1051a39Sopenharmony_ci if (ctx == NULL) { 646e1051a39Sopenharmony_ci ctx = new_ctx = BN_CTX_new(); 647e1051a39Sopenharmony_ci if (ctx == NULL) 648e1051a39Sopenharmony_ci return 0; 649e1051a39Sopenharmony_ci } 650e1051a39Sopenharmony_ci#endif 651e1051a39Sopenharmony_ci 652e1051a39Sopenharmony_ci BN_CTX_start(ctx); 653e1051a39Sopenharmony_ci x = BN_CTX_get(ctx); 654e1051a39Sopenharmony_ci y = BN_CTX_get(ctx); 655e1051a39Sopenharmony_ci if (y == NULL) 656e1051a39Sopenharmony_ci goto err; 657e1051a39Sopenharmony_ci 658e1051a39Sopenharmony_ci if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) 659e1051a39Sopenharmony_ci goto err; 660e1051a39Sopenharmony_ci if (!BN_copy(point->X, x)) 661e1051a39Sopenharmony_ci goto err; 662e1051a39Sopenharmony_ci if (!BN_copy(point->Y, y)) 663e1051a39Sopenharmony_ci goto err; 664e1051a39Sopenharmony_ci if (!BN_one(point->Z)) 665e1051a39Sopenharmony_ci goto err; 666e1051a39Sopenharmony_ci point->Z_is_one = 1; 667e1051a39Sopenharmony_ci 668e1051a39Sopenharmony_ci ret = 1; 669e1051a39Sopenharmony_ci 670e1051a39Sopenharmony_ci err: 671e1051a39Sopenharmony_ci BN_CTX_end(ctx); 672e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 673e1051a39Sopenharmony_ci BN_CTX_free(new_ctx); 674e1051a39Sopenharmony_ci#endif 675e1051a39Sopenharmony_ci return ret; 676e1051a39Sopenharmony_ci} 677e1051a39Sopenharmony_ci 678e1051a39Sopenharmony_ci/* 679e1051a39Sopenharmony_ci * Forces each of the EC_POINTs in the given array to use affine coordinates. 680e1051a39Sopenharmony_ci */ 681e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num, 682e1051a39Sopenharmony_ci EC_POINT *points[], BN_CTX *ctx) 683e1051a39Sopenharmony_ci{ 684e1051a39Sopenharmony_ci size_t i; 685e1051a39Sopenharmony_ci 686e1051a39Sopenharmony_ci for (i = 0; i < num; i++) { 687e1051a39Sopenharmony_ci if (!group->meth->make_affine(group, points[i], ctx)) 688e1051a39Sopenharmony_ci return 0; 689e1051a39Sopenharmony_ci } 690e1051a39Sopenharmony_ci 691e1051a39Sopenharmony_ci return 1; 692e1051a39Sopenharmony_ci} 693e1051a39Sopenharmony_ci 694e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field multiplication implementation. */ 695e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r, 696e1051a39Sopenharmony_ci const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) 697e1051a39Sopenharmony_ci{ 698e1051a39Sopenharmony_ci return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx); 699e1051a39Sopenharmony_ci} 700e1051a39Sopenharmony_ci 701e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field squaring implementation. */ 702e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, 703e1051a39Sopenharmony_ci const BIGNUM *a, BN_CTX *ctx) 704e1051a39Sopenharmony_ci{ 705e1051a39Sopenharmony_ci return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx); 706e1051a39Sopenharmony_ci} 707e1051a39Sopenharmony_ci 708e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field division implementation. */ 709e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r, 710e1051a39Sopenharmony_ci const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) 711e1051a39Sopenharmony_ci{ 712e1051a39Sopenharmony_ci return BN_GF2m_mod_div(r, a, b, group->field, ctx); 713e1051a39Sopenharmony_ci} 714e1051a39Sopenharmony_ci 715e1051a39Sopenharmony_ci/*- 716e1051a39Sopenharmony_ci * Lopez-Dahab ladder, pre step. 717e1051a39Sopenharmony_ci * See e.g. "Guide to ECC" Alg 3.40. 718e1051a39Sopenharmony_ci * Modified to blind s and r independently. 719e1051a39Sopenharmony_ci * s:= p, r := 2p 720e1051a39Sopenharmony_ci */ 721e1051a39Sopenharmony_cistatic 722e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_pre(const EC_GROUP *group, 723e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 724e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 725e1051a39Sopenharmony_ci{ 726e1051a39Sopenharmony_ci /* if p is not affine, something is wrong */ 727e1051a39Sopenharmony_ci if (p->Z_is_one == 0) 728e1051a39Sopenharmony_ci return 0; 729e1051a39Sopenharmony_ci 730e1051a39Sopenharmony_ci /* s blinding: make sure lambda (s->Z here) is not zero */ 731e1051a39Sopenharmony_ci do { 732e1051a39Sopenharmony_ci if (!BN_priv_rand_ex(s->Z, BN_num_bits(group->field) - 1, 733e1051a39Sopenharmony_ci BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0, ctx)) { 734e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); 735e1051a39Sopenharmony_ci return 0; 736e1051a39Sopenharmony_ci } 737e1051a39Sopenharmony_ci } while (BN_is_zero(s->Z)); 738e1051a39Sopenharmony_ci 739e1051a39Sopenharmony_ci /* if field_encode defined convert between representations */ 740e1051a39Sopenharmony_ci if ((group->meth->field_encode != NULL 741e1051a39Sopenharmony_ci && !group->meth->field_encode(group, s->Z, s->Z, ctx)) 742e1051a39Sopenharmony_ci || !group->meth->field_mul(group, s->X, p->X, s->Z, ctx)) 743e1051a39Sopenharmony_ci return 0; 744e1051a39Sopenharmony_ci 745e1051a39Sopenharmony_ci /* r blinding: make sure lambda (r->Y here for storage) is not zero */ 746e1051a39Sopenharmony_ci do { 747e1051a39Sopenharmony_ci if (!BN_priv_rand_ex(r->Y, BN_num_bits(group->field) - 1, 748e1051a39Sopenharmony_ci BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0, ctx)) { 749e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); 750e1051a39Sopenharmony_ci return 0; 751e1051a39Sopenharmony_ci } 752e1051a39Sopenharmony_ci } while (BN_is_zero(r->Y)); 753e1051a39Sopenharmony_ci 754e1051a39Sopenharmony_ci if ((group->meth->field_encode != NULL 755e1051a39Sopenharmony_ci && !group->meth->field_encode(group, r->Y, r->Y, ctx)) 756e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, r->Z, p->X, ctx) 757e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, r->X, r->Z, ctx) 758e1051a39Sopenharmony_ci || !BN_GF2m_add(r->X, r->X, group->b) 759e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->Z, r->Z, r->Y, ctx) 760e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->X, r->X, r->Y, ctx)) 761e1051a39Sopenharmony_ci return 0; 762e1051a39Sopenharmony_ci 763e1051a39Sopenharmony_ci s->Z_is_one = 0; 764e1051a39Sopenharmony_ci r->Z_is_one = 0; 765e1051a39Sopenharmony_ci 766e1051a39Sopenharmony_ci return 1; 767e1051a39Sopenharmony_ci} 768e1051a39Sopenharmony_ci 769e1051a39Sopenharmony_ci/*- 770e1051a39Sopenharmony_ci * Ladder step: differential addition-and-doubling, mixed Lopez-Dahab coords. 771e1051a39Sopenharmony_ci * http://www.hyperelliptic.org/EFD/g12o/auto-code/shortw/xz/ladder/mladd-2003-s.op3 772e1051a39Sopenharmony_ci * s := r + s, r := 2r 773e1051a39Sopenharmony_ci */ 774e1051a39Sopenharmony_cistatic 775e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_step(const EC_GROUP *group, 776e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 777e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 778e1051a39Sopenharmony_ci{ 779e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, r->Y, r->Z, s->X, ctx) 780e1051a39Sopenharmony_ci || !group->meth->field_mul(group, s->X, r->X, s->Z, ctx) 781e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, s->Y, r->Z, ctx) 782e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, r->Z, r->X, ctx) 783e1051a39Sopenharmony_ci || !BN_GF2m_add(s->Z, r->Y, s->X) 784e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, s->Z, s->Z, ctx) 785e1051a39Sopenharmony_ci || !group->meth->field_mul(group, s->X, r->Y, s->X, ctx) 786e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->Y, s->Z, p->X, ctx) 787e1051a39Sopenharmony_ci || !BN_GF2m_add(s->X, s->X, r->Y) 788e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, r->Y, r->Z, ctx) 789e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->Z, r->Z, s->Y, ctx) 790e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, s->Y, s->Y, ctx) 791e1051a39Sopenharmony_ci || !group->meth->field_mul(group, s->Y, s->Y, group->b, ctx) 792e1051a39Sopenharmony_ci || !BN_GF2m_add(r->X, r->Y, s->Y)) 793e1051a39Sopenharmony_ci return 0; 794e1051a39Sopenharmony_ci 795e1051a39Sopenharmony_ci return 1; 796e1051a39Sopenharmony_ci} 797e1051a39Sopenharmony_ci 798e1051a39Sopenharmony_ci/*- 799e1051a39Sopenharmony_ci * Recover affine (x,y) result from Lopez-Dahab r and s, affine p. 800e1051a39Sopenharmony_ci * See e.g. "Fast Multiplication on Elliptic Curves over GF(2**m) 801e1051a39Sopenharmony_ci * without Precomputation" (Lopez and Dahab, CHES 1999), 802e1051a39Sopenharmony_ci * Appendix Alg Mxy. 803e1051a39Sopenharmony_ci */ 804e1051a39Sopenharmony_cistatic 805e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_post(const EC_GROUP *group, 806e1051a39Sopenharmony_ci EC_POINT *r, EC_POINT *s, 807e1051a39Sopenharmony_ci EC_POINT *p, BN_CTX *ctx) 808e1051a39Sopenharmony_ci{ 809e1051a39Sopenharmony_ci int ret = 0; 810e1051a39Sopenharmony_ci BIGNUM *t0, *t1, *t2 = NULL; 811e1051a39Sopenharmony_ci 812e1051a39Sopenharmony_ci if (BN_is_zero(r->Z)) 813e1051a39Sopenharmony_ci return EC_POINT_set_to_infinity(group, r); 814e1051a39Sopenharmony_ci 815e1051a39Sopenharmony_ci if (BN_is_zero(s->Z)) { 816e1051a39Sopenharmony_ci if (!EC_POINT_copy(r, p) 817e1051a39Sopenharmony_ci || !EC_POINT_invert(group, r, ctx)) { 818e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB); 819e1051a39Sopenharmony_ci return 0; 820e1051a39Sopenharmony_ci } 821e1051a39Sopenharmony_ci return 1; 822e1051a39Sopenharmony_ci } 823e1051a39Sopenharmony_ci 824e1051a39Sopenharmony_ci BN_CTX_start(ctx); 825e1051a39Sopenharmony_ci t0 = BN_CTX_get(ctx); 826e1051a39Sopenharmony_ci t1 = BN_CTX_get(ctx); 827e1051a39Sopenharmony_ci t2 = BN_CTX_get(ctx); 828e1051a39Sopenharmony_ci if (t2 == NULL) { 829e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); 830e1051a39Sopenharmony_ci goto err; 831e1051a39Sopenharmony_ci } 832e1051a39Sopenharmony_ci 833e1051a39Sopenharmony_ci if (!group->meth->field_mul(group, t0, r->Z, s->Z, ctx) 834e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, p->X, r->Z, ctx) 835e1051a39Sopenharmony_ci || !BN_GF2m_add(t1, r->X, t1) 836e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, p->X, s->Z, ctx) 837e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->Z, r->X, t2, ctx) 838e1051a39Sopenharmony_ci || !BN_GF2m_add(t2, t2, s->X) 839e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, t1, t2, ctx) 840e1051a39Sopenharmony_ci || !group->meth->field_sqr(group, t2, p->X, ctx) 841e1051a39Sopenharmony_ci || !BN_GF2m_add(t2, p->Y, t2) 842e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, t2, t0, ctx) 843e1051a39Sopenharmony_ci || !BN_GF2m_add(t1, t2, t1) 844e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, p->X, t0, ctx) 845e1051a39Sopenharmony_ci || !group->meth->field_inv(group, t2, t2, ctx) 846e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t1, t1, t2, ctx) 847e1051a39Sopenharmony_ci || !group->meth->field_mul(group, r->X, r->Z, t2, ctx) 848e1051a39Sopenharmony_ci || !BN_GF2m_add(t2, p->X, r->X) 849e1051a39Sopenharmony_ci || !group->meth->field_mul(group, t2, t2, t1, ctx) 850e1051a39Sopenharmony_ci || !BN_GF2m_add(r->Y, p->Y, t2) 851e1051a39Sopenharmony_ci || !BN_one(r->Z)) 852e1051a39Sopenharmony_ci goto err; 853e1051a39Sopenharmony_ci 854e1051a39Sopenharmony_ci r->Z_is_one = 1; 855e1051a39Sopenharmony_ci 856e1051a39Sopenharmony_ci /* GF(2^m) field elements should always have BIGNUM::neg = 0 */ 857e1051a39Sopenharmony_ci BN_set_negative(r->X, 0); 858e1051a39Sopenharmony_ci BN_set_negative(r->Y, 0); 859e1051a39Sopenharmony_ci 860e1051a39Sopenharmony_ci ret = 1; 861e1051a39Sopenharmony_ci 862e1051a39Sopenharmony_ci err: 863e1051a39Sopenharmony_ci BN_CTX_end(ctx); 864e1051a39Sopenharmony_ci return ret; 865e1051a39Sopenharmony_ci} 866e1051a39Sopenharmony_ci 867e1051a39Sopenharmony_cistatic 868e1051a39Sopenharmony_ciint ec_GF2m_simple_points_mul(const EC_GROUP *group, EC_POINT *r, 869e1051a39Sopenharmony_ci const BIGNUM *scalar, size_t num, 870e1051a39Sopenharmony_ci const EC_POINT *points[], 871e1051a39Sopenharmony_ci const BIGNUM *scalars[], 872e1051a39Sopenharmony_ci BN_CTX *ctx) 873e1051a39Sopenharmony_ci{ 874e1051a39Sopenharmony_ci int ret = 0; 875e1051a39Sopenharmony_ci EC_POINT *t = NULL; 876e1051a39Sopenharmony_ci 877e1051a39Sopenharmony_ci /*- 878e1051a39Sopenharmony_ci * We limit use of the ladder only to the following cases: 879e1051a39Sopenharmony_ci * - r := scalar * G 880e1051a39Sopenharmony_ci * Fixed point mul: scalar != NULL && num == 0; 881e1051a39Sopenharmony_ci * - r := scalars[0] * points[0] 882e1051a39Sopenharmony_ci * Variable point mul: scalar == NULL && num == 1; 883e1051a39Sopenharmony_ci * - r := scalar * G + scalars[0] * points[0] 884e1051a39Sopenharmony_ci * used, e.g., in ECDSA verification: scalar != NULL && num == 1 885e1051a39Sopenharmony_ci * 886e1051a39Sopenharmony_ci * In any other case (num > 1) we use the default wNAF implementation. 887e1051a39Sopenharmony_ci * 888e1051a39Sopenharmony_ci * We also let the default implementation handle degenerate cases like group 889e1051a39Sopenharmony_ci * order or cofactor set to 0. 890e1051a39Sopenharmony_ci */ 891e1051a39Sopenharmony_ci if (num > 1 || BN_is_zero(group->order) || BN_is_zero(group->cofactor)) 892e1051a39Sopenharmony_ci return ossl_ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); 893e1051a39Sopenharmony_ci 894e1051a39Sopenharmony_ci if (scalar != NULL && num == 0) 895e1051a39Sopenharmony_ci /* Fixed point multiplication */ 896e1051a39Sopenharmony_ci return ossl_ec_scalar_mul_ladder(group, r, scalar, NULL, ctx); 897e1051a39Sopenharmony_ci 898e1051a39Sopenharmony_ci if (scalar == NULL && num == 1) 899e1051a39Sopenharmony_ci /* Variable point multiplication */ 900e1051a39Sopenharmony_ci return ossl_ec_scalar_mul_ladder(group, r, scalars[0], points[0], ctx); 901e1051a39Sopenharmony_ci 902e1051a39Sopenharmony_ci /*- 903e1051a39Sopenharmony_ci * Double point multiplication: 904e1051a39Sopenharmony_ci * r := scalar * G + scalars[0] * points[0] 905e1051a39Sopenharmony_ci */ 906e1051a39Sopenharmony_ci 907e1051a39Sopenharmony_ci if ((t = EC_POINT_new(group)) == NULL) { 908e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); 909e1051a39Sopenharmony_ci return 0; 910e1051a39Sopenharmony_ci } 911e1051a39Sopenharmony_ci 912e1051a39Sopenharmony_ci if (!ossl_ec_scalar_mul_ladder(group, t, scalar, NULL, ctx) 913e1051a39Sopenharmony_ci || !ossl_ec_scalar_mul_ladder(group, r, scalars[0], points[0], ctx) 914e1051a39Sopenharmony_ci || !EC_POINT_add(group, r, t, r, ctx)) 915e1051a39Sopenharmony_ci goto err; 916e1051a39Sopenharmony_ci 917e1051a39Sopenharmony_ci ret = 1; 918e1051a39Sopenharmony_ci 919e1051a39Sopenharmony_ci err: 920e1051a39Sopenharmony_ci EC_POINT_free(t); 921e1051a39Sopenharmony_ci return ret; 922e1051a39Sopenharmony_ci} 923e1051a39Sopenharmony_ci 924e1051a39Sopenharmony_ci/*- 925e1051a39Sopenharmony_ci * Computes the multiplicative inverse of a in GF(2^m), storing the result in r. 926e1051a39Sopenharmony_ci * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error. 927e1051a39Sopenharmony_ci * SCA hardening is with blinding: BN_GF2m_mod_inv does that. 928e1051a39Sopenharmony_ci */ 929e1051a39Sopenharmony_cistatic int ec_GF2m_simple_field_inv(const EC_GROUP *group, BIGNUM *r, 930e1051a39Sopenharmony_ci const BIGNUM *a, BN_CTX *ctx) 931e1051a39Sopenharmony_ci{ 932e1051a39Sopenharmony_ci int ret; 933e1051a39Sopenharmony_ci 934e1051a39Sopenharmony_ci if (!(ret = BN_GF2m_mod_inv(r, a, group->field, ctx))) 935e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EC, EC_R_CANNOT_INVERT); 936e1051a39Sopenharmony_ci return ret; 937e1051a39Sopenharmony_ci} 938e1051a39Sopenharmony_ci 939e1051a39Sopenharmony_ciconst EC_METHOD *EC_GF2m_simple_method(void) 940e1051a39Sopenharmony_ci{ 941e1051a39Sopenharmony_ci static const EC_METHOD ret = { 942e1051a39Sopenharmony_ci EC_FLAGS_DEFAULT_OCT, 943e1051a39Sopenharmony_ci NID_X9_62_characteristic_two_field, 944e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_init, 945e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_finish, 946e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_clear_finish, 947e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_copy, 948e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_set_curve, 949e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_get_curve, 950e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_get_degree, 951e1051a39Sopenharmony_ci ossl_ec_group_simple_order_bits, 952e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_group_check_discriminant, 953e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_init, 954e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_finish, 955e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_clear_finish, 956e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_copy, 957e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_set_to_infinity, 958e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_set_affine_coordinates, 959e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_point_get_affine_coordinates, 960e1051a39Sopenharmony_ci 0, /* point_set_compressed_coordinates */ 961e1051a39Sopenharmony_ci 0, /* point2oct */ 962e1051a39Sopenharmony_ci 0, /* oct2point */ 963e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_add, 964e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_dbl, 965e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_invert, 966e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_is_at_infinity, 967e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_is_on_curve, 968e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_cmp, 969e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_make_affine, 970e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_points_make_affine, 971e1051a39Sopenharmony_ci ec_GF2m_simple_points_mul, 972e1051a39Sopenharmony_ci 0, /* precompute_mult */ 973e1051a39Sopenharmony_ci 0, /* have_precompute_mult */ 974e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_field_mul, 975e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_field_sqr, 976e1051a39Sopenharmony_ci ossl_ec_GF2m_simple_field_div, 977e1051a39Sopenharmony_ci ec_GF2m_simple_field_inv, 978e1051a39Sopenharmony_ci 0, /* field_encode */ 979e1051a39Sopenharmony_ci 0, /* field_decode */ 980e1051a39Sopenharmony_ci 0, /* field_set_to_one */ 981e1051a39Sopenharmony_ci ossl_ec_key_simple_priv2oct, 982e1051a39Sopenharmony_ci ossl_ec_key_simple_oct2priv, 983e1051a39Sopenharmony_ci 0, /* set private */ 984e1051a39Sopenharmony_ci ossl_ec_key_simple_generate_key, 985e1051a39Sopenharmony_ci ossl_ec_key_simple_check_key, 986e1051a39Sopenharmony_ci ossl_ec_key_simple_generate_public_key, 987e1051a39Sopenharmony_ci 0, /* keycopy */ 988e1051a39Sopenharmony_ci 0, /* keyfinish */ 989e1051a39Sopenharmony_ci ossl_ecdh_simple_compute_key, 990e1051a39Sopenharmony_ci ossl_ecdsa_simple_sign_setup, 991e1051a39Sopenharmony_ci ossl_ecdsa_simple_sign_sig, 992e1051a39Sopenharmony_ci ossl_ecdsa_simple_verify_sig, 993e1051a39Sopenharmony_ci 0, /* field_inverse_mod_ord */ 994e1051a39Sopenharmony_ci 0, /* blind_coordinates */ 995e1051a39Sopenharmony_ci ec_GF2m_simple_ladder_pre, 996e1051a39Sopenharmony_ci ec_GF2m_simple_ladder_step, 997e1051a39Sopenharmony_ci ec_GF2m_simple_ladder_post 998e1051a39Sopenharmony_ci }; 999e1051a39Sopenharmony_ci 1000e1051a39Sopenharmony_ci return &ret; 1001e1051a39Sopenharmony_ci} 1002e1051a39Sopenharmony_ci 1003e1051a39Sopenharmony_ci#endif 1004