diff options
Diffstat (limited to 'crypto/ec/ec_lib.c')
-rw-r--r-- | crypto/ec/ec_lib.c | 159 |
1 files changed, 152 insertions, 7 deletions
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c index cd2c420176f72..e3f2e82f68cfc 100644 --- a/crypto/ec/ec_lib.c +++ b/crypto/ec/ec_lib.c @@ -294,6 +294,67 @@ int EC_METHOD_get_field_type(const EC_METHOD *meth) return meth->field_type; } +/*- + * Try computing cofactor from the generator order (n) and field cardinality (q). + * This works for all curves of cryptographic interest. + * + * Hasse thm: q + 1 - 2*sqrt(q) <= n*h <= q + 1 + 2*sqrt(q) + * h_min = (q + 1 - 2*sqrt(q))/n + * h_max = (q + 1 + 2*sqrt(q))/n + * h_max - h_min = 4*sqrt(q)/n + * So if n > 4*sqrt(q) holds, there is only one possible value for h: + * h = \lfloor (h_min + h_max)/2 \rceil = \lfloor (q + 1)/n \rceil + * + * Otherwise, zero cofactor and return success. + */ +static int ec_guess_cofactor(EC_GROUP *group) { + int ret = 0; + BN_CTX *ctx = NULL; + BIGNUM *q = NULL; + + /*- + * If the cofactor is too large, we cannot guess it. + * The RHS of below is a strict overestimate of lg(4 * sqrt(q)) + */ + if (BN_num_bits(&group->order) <= (BN_num_bits(&group->field) + 1) / 2 + 3) { + /* default to 0 */ + BN_zero(&group->cofactor); + /* return success */ + return 1; + } + + if ((ctx = BN_CTX_new()) == NULL) + return 0; + + BN_CTX_start(ctx); + if ((q = BN_CTX_get(ctx)) == NULL) + goto err; + + /* set q = 2**m for binary fields; q = p otherwise */ + if (group->meth->field_type == NID_X9_62_characteristic_two_field) { + BN_zero(q); + if (!BN_set_bit(q, BN_num_bits(&group->field) - 1)) + goto err; + } else { + if (!BN_copy(q, &group->field)) + goto err; + } + + /* compute h = \lfloor (q + 1)/n \rceil = \lfloor (q + 1 + n/2)/n \rfloor */ + if (!BN_rshift1(&group->cofactor, &group->order) /* n/2 */ + || !BN_add(&group->cofactor, &group->cofactor, q) /* q + n/2 */ + /* q + 1 + n/2 */ + || !BN_add(&group->cofactor, &group->cofactor, BN_value_one()) + /* (q + 1 + n/2)/n */ + || !BN_div(&group->cofactor, NULL, &group->cofactor, &group->order, ctx)) + goto err; + ret = 1; + err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ret; +} + int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor) { @@ -302,6 +363,33 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, return 0; } + /* require group->field >= 1 */ + if (BN_is_zero(&group->field) || BN_is_negative(&group->field)) { + ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_INVALID_FIELD); + return 0; + } + + /*- + * - require order >= 1 + * - enforce upper bound due to Hasse thm: order can be no more than one bit + * longer than field cardinality + */ + if (order == NULL || BN_is_zero(order) || BN_is_negative(order) + || BN_num_bits(order) > BN_num_bits(&group->field) + 1) { + ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_INVALID_GROUP_ORDER); + return 0; + } + + /*- + * Unfortunately the cofactor is an optional field in many standards. + * Internally, the lib uses 0 cofactor as a marker for "unknown cofactor". + * So accept cofactor == NULL or cofactor >= 0. + */ + if (cofactor != NULL && BN_is_negative(cofactor)) { + ECerr(EC_F_EC_GROUP_SET_GENERATOR, EC_R_UNKNOWN_COFACTOR); + return 0; + } + if (group->generator == NULL) { group->generator = EC_POINT_new(group); if (group->generator == NULL) @@ -310,17 +398,17 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, if (!EC_POINT_copy(group->generator, generator)) return 0; - if (order != NULL) { - if (!BN_copy(&group->order, order)) - return 0; - } else - BN_zero(&group->order); + if (!BN_copy(&group->order, order)) + return 0; - if (cofactor != NULL) { + /* Either take the provided positive cofactor, or try to compute it */ + if (cofactor != NULL && !BN_is_zero(cofactor)) { if (!BN_copy(&group->cofactor, cofactor)) return 0; - } else + } else if (!ec_guess_cofactor(group)) { BN_zero(&group->cofactor); + return 0; + } /*- * Access to the `mont_data` field of an EC_GROUP struct should always be @@ -1169,3 +1257,60 @@ int ec_precompute_mont_data(EC_GROUP *group) BN_CTX_free(ctx); return ret; } + +/* + * This is just a wrapper around the public functions + * - EC_GROUP_get_curve_GF2m + * - EC_GROUP_get_curve_GFp + * + * It is meant to facilitate backporting of code from newer branches, where + * the public API includes a "field agnostic" version of it. + */ +int ec_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) +{ + int field_nid; + + field_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + +#ifndef OPENSSL_NO_EC2M + if (field_nid == NID_X9_62_characteristic_two_field) { + return EC_GROUP_get_curve_GF2m(group, p, a, b, ctx); + } else +#endif /* !def(OPENSSL_NO_EC2M) */ + if (field_nid == NID_X9_62_prime_field) { + return EC_GROUP_get_curve_GFp(group, p, a, b, ctx); + } else { + /* this should never happen */ + return 0; + } +} + +/* + * This is just a wrapper around the public functions + * - EC_POINT_get_affine_coordinates_GF2m + * - EC_POINT_get_affine_coordinates_GFp + * + * It is meant to facilitate backporting of code from newer branches, where + * the public API includes a "field agnostic" version of it. + */ +int ec_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) +{ + int field_nid; + + field_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + +#ifndef OPENSSL_NO_EC2M + if (field_nid == NID_X9_62_characteristic_two_field) { + return EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx); + } else +#endif /* !def(OPENSSL_NO_EC2M) */ + if (field_nid == NID_X9_62_prime_field) { + return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx); + } else { + /* this should never happen */ + return 0; + } +} |