Don't store a redundant copy of the EC_GROUP field modulus

One less value to initialize statically. Also this simplifies EC_GROUP
initialization. While I'm here, reorder EC_GROUP to pad better.

This lets us simplify the init bits slightly. It does mean p224-64.c,
the one EC_GROUP that doesn't use Montgomery reduction, carries around a
wasted Montgomery context, but it'll make generating the tables
statically much easier. Also once the data is pre-generated, the cost is
minimal.

Bug: 20
Change-Id: Ib66e655ce5a0902ab3ed6695fcbb46aa87683885
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60928
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
This commit is contained in:
David Benjamin 2023-02-12 12:27:17 -05:00 committed by Boringssl LUCI CQ
parent 1e2f169663
commit 8e8f87ea94
14 changed files with 117 additions and 212 deletions

View File

@ -179,12 +179,12 @@ static int hash_to_field2(const EC_GROUP *group, const EVP_MD *md,
size_t msg_len) {
size_t L;
uint8_t buf[4 * EC_MAX_BYTES];
if (!num_bytes_to_derive(&L, &group->field, k) ||
if (!num_bytes_to_derive(&L, &group->field->N, k) ||
!expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len)) {
return 0;
}
BN_ULONG words[2 * EC_MAX_WORDS];
size_t num_words = 2 * group->field.width;
size_t num_words = 2 * group->field->N.width;
big_endian_to_words(words, num_words, buf, L);
group->meth->felem_reduce(group, out1, words, num_words);
big_endian_to_words(words, num_words, buf + L, L);
@ -231,7 +231,7 @@ static BN_ULONG sgn0(const EC_GROUP *group, const EC_FELEM *a) {
}
OPENSSL_UNUSED static int is_3mod4(const EC_GROUP *group) {
return group->field.width > 0 && (group->field.d[0] & 3) == 3;
return group->field->N.width > 0 && (group->field->N.d[0] & 3) == 3;
}
// sqrt_ratio_3mod4 implements the operation described in appendix F.2.1.2
@ -354,8 +354,8 @@ static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
// Compute |c1| = (p - 3) / 4.
BN_ULONG c1[EC_MAX_WORDS];
size_t num_c1 = group->field.width;
if (!bn_copy_words(c1, num_c1, &group->field)) {
size_t num_c1 = group->field->N.width;
if (!bn_copy_words(c1, num_c1, &group->field->N)) {
return 0;
}
bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
@ -371,7 +371,7 @@ static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
uint8_t bytes[EC_MAX_BYTES] = {0};
size_t len = BN_num_bytes(&group->field);
size_t len = BN_num_bytes(&group->field->N);
bytes[len - 1] = a;
return ec_felem_from_bytes(group, out, bytes, len);
}

View File

@ -270,20 +270,9 @@ DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
#endif
}
EC_GROUP *ec_group_new(const EC_METHOD *meth) {
EC_GROUP *ret;
if (meth == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_SLOT_FULL);
return NULL;
}
if (meth->group_init == 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return NULL;
}
ret = OPENSSL_malloc(sizeof(EC_GROUP));
EC_GROUP *ec_group_new(const EC_METHOD *meth, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx) {
EC_GROUP *ret = OPENSSL_malloc(sizeof(EC_GROUP));
if (ret == NULL) {
return NULL;
}
@ -292,8 +281,8 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
ret->references = 1;
ret->meth = meth;
if (!meth->group_init(ret)) {
OPENSSL_free(ret);
if (!ec_GFp_simple_group_set_curve(ret, p, a, b, ctx)) {
EC_GROUP_free(ret);
return NULL;
}
@ -310,7 +299,7 @@ static int ec_group_set_generator(EC_GROUP *group, const EC_AFFINE *generator,
return 0;
}
group->field_greater_than_order = BN_cmp(&group->field, order) > 0;
group->field_greater_than_order = BN_cmp(&group->field->N, order) > 0;
group->generator = EC_POINT_new(group);
if (group->generator == NULL) {
@ -355,11 +344,8 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
goto err;
}
ret = ec_group_new(EC_GFp_mont_method());
if (ret == NULL ||
!ret->meth->group_set_curve(ret, p, a_reduced, b_reduced, ctx)) {
EC_GROUP_free(ret);
ret = NULL;
ret = ec_group_new(EC_GFp_mont_method(), p, a_reduced, b_reduced, ctx);
if (ret == NULL) {
goto err;
}
@ -403,7 +389,7 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
!BN_lshift1(tmp, order)) {
goto err;
}
if (BN_cmp(tmp, &group->field) <= 0) {
if (BN_cmp(tmp, &group->field->N) <= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
goto err;
}
@ -442,9 +428,8 @@ static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
goto err;
}
group = ec_group_new(curve->method);
if (group == NULL ||
!group->meth->group_set_curve(group, p, a, b, ctx)) {
group = ec_group_new(curve->method, p, a, b, ctx);
if (group == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
goto err;
}
@ -453,11 +438,8 @@ static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
EC_FELEM x, y;
if (!ec_felem_from_bytes(group, &x, params + 3 * param_len, param_len) ||
!ec_felem_from_bytes(group, &y, params + 4 * param_len, param_len) ||
!ec_point_set_affine_coordinates(group, &G, &x, &y)) {
goto err;
}
if (!ec_group_set_generator(group, &G, order)) {
!ec_point_set_affine_coordinates(group, &G, &x, &y) ||
!ec_group_set_generator(group, &G, order)) {
goto err;
}
@ -539,13 +521,9 @@ void EC_GROUP_free(EC_GROUP *group) {
return;
}
if (group->meth->group_finish != NULL) {
group->meth->group_finish(group);
}
ec_point_free(group->generator, 0 /* don't free group */);
BN_MONT_CTX_free(group->order);
BN_MONT_CTX_free(group->field);
OPENSSL_free(group);
}
@ -584,7 +562,7 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) {
a->generator == NULL ||
b->generator == NULL ||
BN_cmp(&a->order->N, &b->order->N) != 0 ||
BN_cmp(&a->field, &b->field) != 0 ||
BN_cmp(&a->field->N, &b->field->N) != 0 ||
!ec_felem_equal(a, &a->a, &b->a) ||
!ec_felem_equal(a, &a->b, &b->b) ||
!ec_GFp_simple_points_equal(a, &a->generator->raw, &b->generator->raw);
@ -624,7 +602,7 @@ int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a,
int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; }
unsigned EC_GROUP_get_degree(const EC_GROUP *group) {
return BN_num_bits(&group->field);
return BN_num_bits(&group->field->N);
}
const char *EC_curve_nid2nist(int nid) {
@ -1184,7 +1162,7 @@ int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
int ec_get_x_coordinate_as_bytes(const EC_GROUP *group, uint8_t *out,
size_t *out_len, size_t max_out,
const EC_JACOBIAN *p) {
size_t len = BN_num_bytes(&group->field);
size_t len = BN_num_bytes(&group->field->N);
assert(len <= EC_MAX_BYTES);
if (max_out < len) {
OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);

View File

@ -76,67 +76,35 @@
#include "internal.h"
int ec_GFp_mont_group_init(EC_GROUP *group) {
int ok;
ok = ec_GFp_simple_group_init(group);
group->mont = NULL;
return ok;
}
void ec_GFp_mont_group_finish(EC_GROUP *group) {
BN_MONT_CTX_free(group->mont);
group->mont = NULL;
ec_GFp_simple_group_finish(group);
}
int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
BN_MONT_CTX_free(group->mont);
group->mont = BN_MONT_CTX_new_for_modulus(p, ctx);
if (group->mont == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
return 0;
}
if (!ec_GFp_simple_group_set_curve(group, p, a, b, ctx)) {
BN_MONT_CTX_free(group->mont);
group->mont = NULL;
return 0;
}
return 1;
}
static void ec_GFp_mont_felem_to_montgomery(const EC_GROUP *group,
EC_FELEM *out, const EC_FELEM *in) {
bn_to_montgomery_small(out->words, in->words, group->field.width,
group->mont);
bn_to_montgomery_small(out->words, in->words, group->field->N.width,
group->field);
}
static void ec_GFp_mont_felem_from_montgomery(const EC_GROUP *group,
EC_FELEM *out,
const EC_FELEM *in) {
bn_from_montgomery_small(out->words, group->field.width, in->words,
group->field.width, group->mont);
bn_from_montgomery_small(out->words, group->field->N.width, in->words,
group->field->N.width, group->field);
}
static void ec_GFp_mont_felem_inv0(const EC_GROUP *group, EC_FELEM *out,
const EC_FELEM *a) {
bn_mod_inverse0_prime_mont_small(out->words, a->words, group->field.width,
group->mont);
bn_mod_inverse0_prime_mont_small(out->words, a->words, group->field->N.width,
group->field);
}
void ec_GFp_mont_felem_mul(const EC_GROUP *group, EC_FELEM *r,
const EC_FELEM *a, const EC_FELEM *b) {
bn_mod_mul_montgomery_small(r->words, a->words, b->words, group->field.width,
group->mont);
bn_mod_mul_montgomery_small(r->words, a->words, b->words,
group->field->N.width, group->field);
}
void ec_GFp_mont_felem_sqr(const EC_GROUP *group, EC_FELEM *r,
const EC_FELEM *a) {
bn_mod_mul_montgomery_small(r->words, a->words, a->words, group->field.width,
group->mont);
bn_mod_mul_montgomery_small(r->words, a->words, a->words,
group->field->N.width, group->field);
}
void ec_GFp_mont_felem_to_bytes(const EC_GROUP *group, uint8_t *out,
@ -159,8 +127,8 @@ int ec_GFp_mont_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
void ec_GFp_mont_felem_reduce(const EC_GROUP *group, EC_FELEM *out,
const BN_ULONG *words, size_t num) {
// Convert "from" Montgomery form so the value is reduced mod p.
bn_from_montgomery_small(out->words, group->field.width, words, num,
group->mont);
bn_from_montgomery_small(out->words, group->field->N.width, words, num,
group->field);
// Convert "to" Montgomery form to remove the R^-1 factor added.
ec_GFp_mont_felem_to_montgomery(group, out, out);
// Convert to Montgomery form to match this implementation's representation.
@ -170,8 +138,8 @@ void ec_GFp_mont_felem_reduce(const EC_GROUP *group, EC_FELEM *out,
void ec_GFp_mont_felem_exp(const EC_GROUP *group, EC_FELEM *out,
const EC_FELEM *a, const BN_ULONG *exp,
size_t num_exp) {
bn_mod_exp_mont_small(out->words, a->words, group->field.width, exp, num_exp,
group->mont);
bn_mod_exp_mont_small(out->words, a->words, group->field->N.width, exp,
num_exp, group->field);
}
static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
@ -457,7 +425,7 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
const EC_JACOBIAN *p,
const EC_SCALAR *r) {
if (!group->field_greater_than_order ||
group->field.width != group->order->N.width) {
group->field->N.width != group->order->N.width) {
// Do not bother optimizing this case. p > order in all commonly-used
// curves.
return ec_GFp_simple_cmp_x_coordinate(group, p, r);
@ -473,7 +441,8 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
EC_FELEM r_Z2, Z2_mont, X;
ec_GFp_mont_felem_mul(group, &Z2_mont, &p->Z, &p->Z);
// r < order < p, so this is valid.
OPENSSL_memcpy(r_Z2.words, r->words, group->field.width * sizeof(BN_ULONG));
OPENSSL_memcpy(r_Z2.words, r->words,
group->field->N.width * sizeof(BN_ULONG));
ec_GFp_mont_felem_mul(group, &r_Z2, &r_Z2, &Z2_mont);
ec_GFp_mont_felem_from_montgomery(group, &X, &p->X);
@ -485,10 +454,10 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
// Therefore there is a small possibility, less than 1/2^128, that group_order
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
BN_ULONG carry =
bn_add_words(r_Z2.words, r->words, group->order->N.d, group->field.width);
if (carry == 0 &&
bn_less_than_words(r_Z2.words, group->field.d, group->field.width)) {
BN_ULONG carry = bn_add_words(r_Z2.words, r->words, group->order->N.d,
group->field->N.width);
if (carry == 0 && bn_less_than_words(r_Z2.words, group->field->N.d,
group->field->N.width)) {
// r + group_order < p, so compare (r + group_order) * Z^2 against X.
ec_GFp_mont_felem_mul(group, &r_Z2, &r_Z2, &Z2_mont);
if (ec_felem_equal(group, &r_Z2, &X)) {
@ -500,9 +469,6 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
out->group_init = ec_GFp_mont_group_init;
out->group_finish = ec_GFp_mont_group_finish;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
out->jacobian_to_affine_batch = ec_GFp_mont_jacobian_to_affine_batch;
out->add = ec_GFp_mont_add;

View File

@ -25,10 +25,10 @@
int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in) {
uint8_t bytes[EC_MAX_BYTES];
size_t len = BN_num_bytes(&group->field);
size_t len = BN_num_bytes(&group->field->N);
assert(sizeof(bytes) >= len);
if (BN_is_negative(in) ||
BN_cmp(in, &group->field) >= 0 ||
BN_cmp(in, &group->field->N) >= 0 ||
!BN_bn2bin_padded(bytes, len, in)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
return 0;
@ -57,11 +57,11 @@ int ec_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out, const uint8_t *in,
void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a) {
// -a is zero if a is zero and p-a otherwise.
BN_ULONG mask = ec_felem_non_zero_mask(group, a);
BN_ULONG borrow =
bn_sub_words(out->words, group->field.d, a->words, group->field.width);
BN_ULONG borrow = bn_sub_words(out->words, group->field->N.d, a->words,
group->field->N.width);
assert(borrow == 0);
(void)borrow;
for (int i = 0; i < group->field.width; i++) {
for (int i = 0; i < group->field->N.width; i++) {
out->words[i] &= mask;
}
}
@ -69,20 +69,20 @@ void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a) {
void ec_felem_add(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
const EC_FELEM *b) {
EC_FELEM tmp;
bn_mod_add_words(out->words, a->words, b->words, group->field.d, tmp.words,
group->field.width);
bn_mod_add_words(out->words, a->words, b->words, group->field->N.d, tmp.words,
group->field->N.width);
}
void ec_felem_sub(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
const EC_FELEM *b) {
EC_FELEM tmp;
bn_mod_sub_words(out->words, a->words, b->words, group->field.d, tmp.words,
group->field.width);
bn_mod_sub_words(out->words, a->words, b->words, group->field->N.d, tmp.words,
group->field->N.width);
}
BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a) {
BN_ULONG mask = 0;
for (int i = 0; i < group->field.width; i++) {
for (int i = 0; i < group->field->N.width; i++) {
mask |= a->words[i];
}
return ~constant_time_is_zero_w(mask);
@ -90,11 +90,11 @@ BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a) {
void ec_felem_select(const EC_GROUP *group, EC_FELEM *out, BN_ULONG mask,
const EC_FELEM *a, const EC_FELEM *b) {
bn_select_words(out->words, mask, a->words, b->words, group->field.width);
bn_select_words(out->words, mask, a->words, b->words, group->field->N.width);
}
int ec_felem_equal(const EC_GROUP *group, const EC_FELEM *a,
const EC_FELEM *b) {
return CRYPTO_memcmp(a->words, b->words,
group->field.width * sizeof(BN_ULONG)) == 0;
group->field->N.width * sizeof(BN_ULONG)) == 0;
}

View File

@ -472,11 +472,6 @@ int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
// Implementation details.
struct ec_method_st {
int (*group_init)(EC_GROUP *);
void (*group_finish)(EC_GROUP *);
int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
// point_get_affine_coordinates sets |*x| and |*y| to the affine coordinates
// of |p|. Either |x| or |y| may be NULL to omit it. It returns one on success
// and zero if |p| is the point at infinity. It leaks whether |p| was the
@ -596,16 +591,13 @@ struct ec_group_st {
// and Y are suitable for use as an |EC_AFFINE|.
EC_POINT *generator;
int curve_name; // optional NID for named curve
BN_MONT_CTX *order;
// The following members are handled by the method functions,
// even if they appear generic
BIGNUM field; // For curves over GF(p), this is the modulus.
BN_MONT_CTX *field;
EC_FELEM a, b; // Curve coefficients.
EC_FELEM one; // The value one.
int curve_name; // optional NID for named curve
// a_is_minus3 is one if |a| is -3 mod |field| and zero otherwise. Point
// arithmetic is optimized for -3.
@ -616,10 +608,6 @@ struct ec_group_st {
int field_greater_than_order;
CRYPTO_refcount_t references;
BN_MONT_CTX *mont; // Montgomery structure.
EC_FELEM one; // The value one.
} /* EC_GROUP */;
struct ec_point_st {
@ -633,7 +621,8 @@ struct ec_point_st {
EC_JACOBIAN raw;
} /* EC_POINT */;
EC_GROUP *ec_group_new(const EC_METHOD *meth);
EC_GROUP *ec_group_new(const EC_METHOD *meth, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx);
void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_JACOBIAN *p, const EC_SCALAR *scalar);
@ -672,8 +661,6 @@ int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalars, size_t num);
// method functions in simple.c
int ec_GFp_simple_group_init(EC_GROUP *);
void ec_GFp_simple_group_finish(EC_GROUP *);
int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
@ -705,10 +692,6 @@ int ec_GFp_simple_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
const uint8_t *in, size_t len);
// method functions in montgomery.c
int ec_GFp_mont_group_init(EC_GROUP *);
int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
void ec_GFp_mont_group_finish(EC_GROUP *);
void ec_GFp_mont_felem_mul(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
const EC_FELEM *b);
void ec_GFp_mont_felem_sqr(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a);

View File

@ -80,7 +80,7 @@ size_t ec_point_byte_len(const EC_GROUP *group, point_conversion_form_t form) {
return 0;
}
const size_t field_len = BN_num_bytes(&group->field);
const size_t field_len = BN_num_bytes(&group->field->N);
size_t output_len = 1 /* type byte */ + field_len;
if (form == POINT_CONVERSION_UNCOMPRESSED) {
// Uncompressed points have a second coordinate.
@ -100,11 +100,11 @@ size_t ec_point_to_bytes(const EC_GROUP *group, const EC_AFFINE *point,
size_t field_len;
ec_felem_to_bytes(group, buf + 1, &field_len, &point->X);
assert(field_len == BN_num_bytes(&group->field));
assert(field_len == BN_num_bytes(&group->field->N));
if (form == POINT_CONVERSION_UNCOMPRESSED) {
ec_felem_to_bytes(group, buf + 1 + field_len, &field_len, &point->Y);
assert(field_len == BN_num_bytes(&group->field));
assert(field_len == BN_num_bytes(&group->field->N));
buf[0] = form;
} else {
uint8_t y_buf[EC_MAX_BYTES];
@ -117,7 +117,7 @@ size_t ec_point_to_bytes(const EC_GROUP *group, const EC_AFFINE *point,
int ec_point_from_uncompressed(const EC_GROUP *group, EC_AFFINE *out,
const uint8_t *in, size_t len) {
const size_t field_len = BN_num_bytes(&group->field);
const size_t field_len = BN_num_bytes(&group->field->N);
if (len != 1 + 2 * field_len || in[0] != POINT_CONVERSION_UNCOMPRESSED) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
return 0;
@ -155,7 +155,7 @@ static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
}
const int y_bit = form & 1;
const size_t field_len = BN_num_bytes(&group->field);
const size_t field_len = BN_num_bytes(&group->field->N);
form = form & ~1u;
if (form != POINT_CONVERSION_COMPRESSED ||
len != 1 /* type byte */ + field_len) {
@ -182,7 +182,7 @@ static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
if (x == NULL || !BN_bin2bn(buf + 1, field_len, x)) {
goto err;
}
if (BN_ucmp(x, &group->field) >= 0) {
if (BN_ucmp(x, &group->field->N) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
goto err;
}
@ -260,7 +260,8 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
return 0;
}
if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) {
const BIGNUM *field = &group->field->N;
if (BN_is_negative(x) || BN_cmp(x, field) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
return 0;
}
@ -295,31 +296,31 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
// so y is one of the square roots of x^3 + a*x + b.
// tmp1 := x^3
if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
!BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
if (!BN_mod_sqr(tmp2, x, field, ctx) ||
!BN_mod_mul(tmp1, tmp2, x, field, ctx)) {
goto err;
}
// tmp1 := tmp1 + a*x
if (group->a_is_minus3) {
if (!bn_mod_lshift1_consttime(tmp2, x, &group->field, ctx) ||
!bn_mod_add_consttime(tmp2, tmp2, x, &group->field, ctx) ||
!bn_mod_sub_consttime(tmp1, tmp1, tmp2, &group->field, ctx)) {
if (!bn_mod_lshift1_consttime(tmp2, x, field, ctx) ||
!bn_mod_add_consttime(tmp2, tmp2, x, field, ctx) ||
!bn_mod_sub_consttime(tmp1, tmp1, tmp2, field, ctx)) {
goto err;
}
} else {
if (!BN_mod_mul(tmp2, a, x, &group->field, ctx) ||
!bn_mod_add_consttime(tmp1, tmp1, tmp2, &group->field, ctx)) {
if (!BN_mod_mul(tmp2, a, x, field, ctx) ||
!bn_mod_add_consttime(tmp1, tmp1, tmp2, field, ctx)) {
goto err;
}
}
// tmp1 := tmp1 + b
if (!bn_mod_add_consttime(tmp1, tmp1, b, &group->field, ctx)) {
if (!bn_mod_add_consttime(tmp1, tmp1, b, field, ctx)) {
goto err;
}
if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
if (!BN_mod_sqrt(y, tmp1, field, ctx)) {
uint32_t err = ERR_peek_last_error();
if (ERR_GET_LIB(err) == ERR_LIB_BN &&
ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
@ -336,7 +337,7 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
goto err;
}
if (!BN_usub(y, &group->field, y)) {
if (!BN_usub(y, field, y)) {
goto err;
}
}

View File

@ -1142,9 +1142,6 @@ static void ec_GFp_nistp224_felem_sqr(const EC_GROUP *group, EC_FELEM *r,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
out->group_init = ec_GFp_simple_group_init;
out->group_finish = ec_GFp_simple_group_finish;
out->group_set_curve = ec_GFp_simple_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp224_point_get_affine_coordinates;
out->add = ec_GFp_nistp224_add;

View File

@ -191,7 +191,7 @@ static void ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
const EC_SCALAR *p_scalar) {
assert(p != NULL);
assert(p_scalar != NULL);
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
static const size_t kWindowSize = 5;
static const crypto_word_t kMask = (1 << (5 /* kWindowSize */ + 1)) - 1;
@ -208,7 +208,7 @@ static void ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
// not stored. All other values are actually stored with an offset of -1 in
// table.
P256_POINT *row = table;
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
OPENSSL_memcpy(row[1 - 1].X, p->X.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(row[1 - 1].Y, p->Y.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(row[1 - 1].Z, p->Z.words, P256_LIMBS * sizeof(BN_ULONG));
@ -305,7 +305,7 @@ static void ecp_nistz256_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,
alignas(32) P256_POINT out;
ecp_nistz256_windowed_mul(group, &out, p, scalar);
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, out.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, out.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, out.Z, P256_LIMBS * sizeof(BN_ULONG));
@ -349,7 +349,7 @@ static void ecp_nistz256_point_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
ecp_nistz256_point_add_affine(&p, &p, &t);
}
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, p.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, p.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, p.Z, P256_LIMBS * sizeof(BN_ULONG));
@ -413,7 +413,7 @@ static void ecp_nistz256_points_mul_public(const EC_GROUP *group,
ecp_nistz256_windowed_mul(group, &tmp, p_, p_scalar);
ecp_nistz256_point_add(&p, &p, &tmp);
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, p.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, p.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, p.Z, P256_LIMBS * sizeof(BN_ULONG));
@ -429,7 +429,7 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group,
}
BN_ULONG z_inv2[P256_LIMBS];
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
ecp_nistz256_mod_inverse_sqr_mont(z_inv2, point->Z.words);
if (x != NULL) {
@ -581,7 +581,7 @@ static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
}
assert(group->order->N.width == P256_LIMBS);
assert(group->field.width == P256_LIMBS);
assert(group->field->N.width == P256_LIMBS);
// We wish to compare X/Z^2 with r. This is equivalent to comparing X with
// r*Z^2. Note that X and Z are represented in Montgomery form, while r is
@ -600,7 +600,7 @@ static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
BN_ULONG carry = bn_add_words(r_Z2, r->words, group->order->N.d, P256_LIMBS);
if (carry == 0 && bn_less_than_words(r_Z2, group->field.d, P256_LIMBS)) {
if (carry == 0 && bn_less_than_words(r_Z2, group->field->N.d, P256_LIMBS)) {
// r + group_order < p, so compare (r + group_order) * Z^2 against X.
ecp_nistz256_mul_mont(r_Z2, r_Z2, Z2_mont);
if (OPENSSL_memcmp(r_Z2, X, sizeof(r_Z2)) == 0) {
@ -612,9 +612,6 @@ static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
out->group_init = ec_GFp_mont_group_init;
out->group_finish = ec_GFp_mont_group_finish;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ecp_nistz256_get_affine;
out->add = ecp_nistz256_add;
out->dbl = ecp_nistz256_dbl;

View File

@ -710,12 +710,12 @@ static int ec_GFp_nistp256_cmp_x_coordinate(const EC_GROUP *group,
// Therefore there is a small possibility, less than 1/2^128, that group_order
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
assert(group->field.width == group->order->N.width);
assert(group->field->N.width == group->order->N.width);
EC_FELEM tmp;
BN_ULONG carry =
bn_add_words(tmp.words, r->words, group->order->N.d, group->field.width);
BN_ULONG carry = bn_add_words(tmp.words, r->words, group->order->N.d,
group->field->N.width);
if (carry == 0 &&
bn_less_than_words(tmp.words, group->field.d, group->field.width)) {
bn_less_than_words(tmp.words, group->field->N.d, group->field->N.width)) {
fiat_p256_from_generic(r_Z2, &tmp);
fiat_p256_mul(r_Z2, r_Z2, Z2_mont);
if (OPENSSL_memcmp(&r_Z2, &X, sizeof(r_Z2)) == 0) {
@ -727,9 +727,6 @@ static int ec_GFp_nistp256_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) {
out->group_init = ec_GFp_mont_group_init;
out->group_finish = ec_GFp_mont_group_finish;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp256_point_get_affine_coordinates;
out->add = ec_GFp_nistp256_add;

View File

@ -88,16 +88,6 @@
// used, it is a Montgomery representation (i.e. 'encoding' means multiplying
// by some factor R).
int ec_GFp_simple_group_init(EC_GROUP *group) {
BN_init(&group->field);
group->a_is_minus3 = 0;
return 1;
}
void ec_GFp_simple_group_finish(EC_GROUP *group) {
BN_free(&group->field);
}
int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b,
BN_CTX *ctx) {
@ -114,13 +104,10 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
goto err;
}
// group->field
if (!BN_copy(&group->field, p)) {
group->field = BN_MONT_CTX_new_for_modulus(p, ctx);
if (group->field == NULL) {
goto err;
}
BN_set_negative(&group->field, 0);
// Store the field in minimal form, so it can be used with |BN_ULONG| arrays.
bn_set_minimal_width(&group->field);
if (!ec_bignum_to_felem(group, &group->a, a) ||
!ec_bignum_to_felem(group, &group->b, b) ||
@ -133,7 +120,7 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
!BN_add_word(tmp, 3)) {
goto err;
}
group->a_is_minus3 = (0 == BN_cmp(tmp, &group->field));
group->a_is_minus3 = (0 == BN_cmp(tmp, &group->field->N));
ret = 1;
@ -144,7 +131,7 @@ err:
int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
BIGNUM *b) {
if ((p != NULL && !BN_copy(p, &group->field)) ||
if ((p != NULL && !BN_copy(p, &group->field->N)) ||
(a != NULL && !ec_felem_to_bignum(group, a, &group->a)) ||
(b != NULL && !ec_felem_to_bignum(group, b, &group->b))) {
return 0;
@ -329,21 +316,22 @@ int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
void ec_GFp_simple_felem_to_bytes(const EC_GROUP *group, uint8_t *out,
size_t *out_len, const EC_FELEM *in) {
size_t len = BN_num_bytes(&group->field);
bn_words_to_big_endian(out, len, in->words, group->field.width);
size_t len = BN_num_bytes(&group->field->N);
bn_words_to_big_endian(out, len, in->words, group->field->N.width);
*out_len = len;
}
int ec_GFp_simple_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
const uint8_t *in, size_t len) {
if (len != BN_num_bytes(&group->field)) {
if (len != BN_num_bytes(&group->field->N)) {
OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
return 0;
}
bn_big_endian_to_words(out->words, group->field.width, in, len);
bn_big_endian_to_words(out->words, group->field->N.width, in, len);
if (!bn_less_than_words(out->words, group->field.d, group->field.width)) {
if (!bn_less_than_words(out->words, group->field->N.d,
group->field->N.width)) {
OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
return 0;
}

View File

@ -169,7 +169,7 @@ void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
}
static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group) {
return (BN_num_bits(&group->field) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
return (EC_GROUP_get_degree(group) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
EC_MONT_PRECOMP_COMB_SIZE;
}

View File

@ -160,7 +160,7 @@ static int cbs_get_prefixed_point(CBS *cbs, const EC_GROUP *group,
return 0;
}
} else {
size_t plen = 1 + 2 * BN_num_bytes(&group->field);
size_t plen = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBS_get_bytes(cbs, &child, plen)) {
return 0;
}
@ -912,7 +912,7 @@ static int pmbtoken_sign(const PMBTOKEN_METHOD *method,
}
// Skip over any unused requests.
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
size_t token_len = point_len;
if (method->prefix_point) {
token_len += 2;
@ -1015,7 +1015,7 @@ static STACK_OF(TRUST_TOKEN) *pmbtoken_unblind(
// Serialize the token. Include |key_id| to avoid an extra copy in the layer
// above.
CBB token_cbb;
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBB_init(&token_cbb,
4 + TRUST_TOKEN_NONCE_SIZE + 3 * (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||

View File

@ -1080,15 +1080,14 @@ TEST_P(TrustTokenMetadataTest, TruncatedProof) {
ASSERT_TRUE(CBS_get_u32(&real_response, &parsed_public_metadata));
ASSERT_TRUE(CBB_add_u32(bad_response.get(), parsed_public_metadata));
const EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp384r1);
size_t token_length =
TRUST_TOKEN_NONCE_SIZE + 2 * (1 + 2 * BN_num_bytes(&group->field));
const size_t kP384PointLen = 1 + 2 * (384 / 8);
size_t token_length = TRUST_TOKEN_NONCE_SIZE + 2 * kP384PointLen;
if (method() == TRUST_TOKEN_experiment_v1()) {
token_length += 4;
}
if (method() == TRUST_TOKEN_experiment_v2_voprf() ||
method() == TRUST_TOKEN_pst_v1_voprf()) {
token_length = 1 + 2 * BN_num_bytes(&group->field);
token_length = kP384PointLen;
}
for (size_t i = 0; i < count; i++) {
ASSERT_TRUE(CBB_add_bytes(bad_response.get(), CBS_data(&real_response),
@ -1149,15 +1148,14 @@ TEST_P(TrustTokenMetadataTest, ExcessDataProof) {
ASSERT_TRUE(CBS_get_u32(&real_response, &parsed_public_metadata));
ASSERT_TRUE(CBB_add_u32(bad_response.get(), parsed_public_metadata));
const EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp384r1);
size_t token_length =
TRUST_TOKEN_NONCE_SIZE + 2 * (1 + 2 * BN_num_bytes(&group->field));
const size_t kP384PointLen = 1 + 2 * (384 / 8);
size_t token_length = TRUST_TOKEN_NONCE_SIZE + 2 * kP384PointLen;
if (method() == TRUST_TOKEN_experiment_v1()) {
token_length += 4;
}
if (method() == TRUST_TOKEN_experiment_v2_voprf() ||
method() == TRUST_TOKEN_pst_v1_voprf()) {
token_length = 1 + 2 * BN_num_bytes(&group->field);
token_length = kP384PointLen;
}
for (size_t i = 0; i < count; i++) {
ASSERT_TRUE(CBB_add_bytes(bad_response.get(), CBS_data(&real_response),

View File

@ -83,7 +83,7 @@ static int cbb_serialize_point(CBB *out, const EC_GROUP *group,
static int cbs_get_point(CBS *cbs, const EC_GROUP *group, EC_AFFINE *out) {
CBS child;
size_t plen = 1 + 2 * BN_num_bytes(&group->field);
size_t plen = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBS_get_bytes(cbs, &child, plen) ||
!ec_point_from_uncompressed(group, out, CBS_data(&child),
CBS_len(&child))) {
@ -567,7 +567,7 @@ static int voprf_sign_tt(const VOPRF_METHOD *method,
}
// Skip over any unused requests.
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBS_skip(cbs, point_len * (num_requested - num_to_issue))) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
goto err;
@ -645,7 +645,7 @@ static STACK_OF(TRUST_TOKEN) *voprf_unblind_tt(
// Serialize the token. Include |key_id| to avoid an extra copy in the layer
// above.
CBB token_cbb;
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBB_init(&token_cbb, 4 + TRUST_TOKEN_NONCE_SIZE + (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||
!CBB_add_bytes(&token_cbb, pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||
@ -944,7 +944,7 @@ static int voprf_sign_impl(const VOPRF_METHOD *method,
}
// Skip over any unused requests.
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBS_skip(cbs, point_len * (num_requested - num_to_issue))) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
goto err;
@ -1044,7 +1044,7 @@ static STACK_OF(TRUST_TOKEN) *voprf_unblind(
// Serialize the token. Include |key_id| to avoid an extra copy in the layer
// above.
CBB token_cbb;
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
size_t point_len = ec_point_byte_len(group, POINT_CONVERSION_UNCOMPRESSED);
if (!CBB_init(&token_cbb, 4 + TRUST_TOKEN_NONCE_SIZE + (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||
!CBB_add_bytes(&token_cbb, pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||