Embed the generator into EC_GROUP
Another point indirection removed. As part of this, remove the extra
copy of one and just use generator.raw.Z.
Bug: 20
Change-Id: I066f624fe02e17082383afc15871ab2431e97b61
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60930
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/ec_extra/hash_to_curve.c b/crypto/ec_extra/hash_to_curve.c
index d9d9d5b..2d11ef5 100644
--- a/crypto/ec_extra/hash_to_curve.c
+++ b/crypto/ec_extra/hash_to_curve.c
@@ -286,12 +286,12 @@
group->meth->felem_sqr;
EC_FELEM tv1, tv2, tv3, tv4, tv5, tv6, x, y, y1;
- felem_sqr(group, &tv1, u); // 1. tv1 = u^2
- felem_mul(group, &tv1, Z, &tv1); // 2. tv1 = Z * tv1
- felem_sqr(group, &tv2, &tv1); // 3. tv2 = tv1^2
- ec_felem_add(group, &tv2, &tv2, &tv1); // 4. tv2 = tv2 + tv1
- ec_felem_add(group, &tv3, &tv2, &group->one); // 5. tv3 = tv2 + 1
- felem_mul(group, &tv3, &group->b, &tv3); // 6. tv3 = B * tv3
+ felem_sqr(group, &tv1, u); // 1. tv1 = u^2
+ felem_mul(group, &tv1, Z, &tv1); // 2. tv1 = Z * tv1
+ felem_sqr(group, &tv2, &tv1); // 3. tv2 = tv1^2
+ ec_felem_add(group, &tv2, &tv2, &tv1); // 4. tv2 = tv2 + tv1
+ ec_felem_add(group, &tv3, &tv2, ec_felem_one(group)); // 5. tv3 = tv2 + 1
+ felem_mul(group, &tv3, &group->b, &tv3); // 6. tv3 = B * tv3
// 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
const BN_ULONG tv2_non_zero = ec_felem_non_zero_mask(group, &tv2);
diff --git a/crypto/fipsmodule/ec/ec.c b/crypto/fipsmodule/ec/ec.c
index a1d6e24..fe77396 100644
--- a/crypto/fipsmodule/ec/ec.c
+++ b/crypto/fipsmodule/ec/ec.c
@@ -283,6 +283,8 @@
bn_mont_ctx_init(&ret->field);
bn_mont_ctx_init(&ret->order);
+ ret->generator.group = ret;
+
if (!ec_GFp_simple_group_set_curve(ret, p, a, b, ctx)) {
EC_GROUP_free(ret);
return NULL;
@@ -300,19 +302,9 @@
}
group->field_greater_than_order = BN_cmp(&group->field.N, order) > 0;
- group->generator = EC_POINT_new(group);
- if (group->generator == NULL) {
- return 0;
- }
- ec_affine_to_jacobian(group, &group->generator->raw, generator);
- assert(ec_felem_equal(group, &group->one, &group->generator->raw.Z));
-
- // Avoid a reference cycle. |group->generator| does not maintain an owning
- // pointer to |group|.
- int is_zero = CRYPTO_refcount_dec_and_test_zero(&group->references);
-
- assert(!is_zero);
- (void)is_zero;
+ group->generator.raw.X = generator->X;
+ group->generator.raw.Y = generator->Y;
+ // |raw.Z| was set to 1 by |ec_GFp_simple_group_set_curve|.
group->has_order = 1;
return 1;
}
@@ -357,7 +349,7 @@
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
const BIGNUM *order, const BIGNUM *cofactor) {
- if (group->curve_name != NID_undef || group->generator != NULL ||
+ if (group->curve_name != NID_undef || group->has_order ||
generator->group != group) {
// |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by
// |EC_GROUP_new_curve_GFp| and may only used once on each group.
@@ -521,7 +513,6 @@
return;
}
- ec_point_free(group->generator, /*free_group=*/0);
bn_mont_ctx_cleanup(&group->order);
bn_mont_ctx_cleanup(&group->field);
OPENSSL_free(group);
@@ -558,18 +549,17 @@
// structure. If |a| or |b| is incomplete (due to legacy OpenSSL mistakes,
// custom curve construction is sadly done in two parts) but otherwise not the
// same object, we consider them always unequal.
- return a->meth != b->meth ||
- a->generator == NULL ||
- b->generator == NULL ||
+ return a->meth != b->meth || //
+ !a->has_order || !b->has_order ||
BN_cmp(&a->order.N, &b->order.N) != 0 ||
BN_cmp(&a->field.N, &b->field.N) != 0 ||
- !ec_felem_equal(a, &a->a, &b->a) ||
+ !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);
+ !ec_GFp_simple_points_equal(a, &a->generator.raw, &b->generator.raw);
}
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
- return group->generator;
+ return group->has_order ? &group->generator : NULL;
}
const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group) {
@@ -764,7 +754,7 @@
const EC_AFFINE *p) {
out->X = p->X;
out->Y = p->Y;
- out->Z = group->one;
+ out->Z = *ec_felem_one(group);
}
int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
@@ -801,10 +791,9 @@
// return value by setting a known safe value. Note this may not be possible
// if the caller is in the process of constructing an arbitrary group and
// the generator is missing.
- if (group->generator != NULL) {
- assert(ec_felem_equal(group, &group->one, &group->generator->raw.Z));
- out->X = group->generator->raw.X;
- out->Y = group->generator->raw.Y;
+ if (group->has_order) {
+ out->X = group->generator.raw.X;
+ out->Y = group->generator.raw.Y;
}
return 0;
}
@@ -1180,8 +1169,8 @@
}
void ec_set_to_safe_point(const EC_GROUP *group, EC_JACOBIAN *out) {
- if (group->generator != NULL) {
- ec_GFp_simple_point_copy(out, &group->generator->raw);
+ if (group->has_order) {
+ ec_GFp_simple_point_copy(out, &group->generator.raw);
} else {
// The generator can be missing if the caller is in the process of
// constructing an arbitrary group. In this case, we give up and use the
diff --git a/crypto/fipsmodule/ec/felem.c b/crypto/fipsmodule/ec/felem.c
index bc7bbb7..6064819 100644
--- a/crypto/fipsmodule/ec/felem.c
+++ b/crypto/fipsmodule/ec/felem.c
@@ -23,6 +23,11 @@
#include "../../internal.h"
+const EC_FELEM *ec_felem_one(const EC_GROUP *group) {
+ // We reuse generator.Z as a cache for 1 in the field.
+ return &group->generator.raw.Z;
+}
+
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.N);
diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h
index 64f41bb..77c3dd6 100644
--- a/crypto/fipsmodule/ec/internal.h
+++ b/crypto/fipsmodule/ec/internal.h
@@ -197,6 +197,9 @@
BN_ULONG words[EC_MAX_WORDS];
} EC_FELEM;
+// ec_felem_one returns one in |group|'s field.
+const EC_FELEM *ec_felem_one(const EC_GROUP *group);
+
// ec_bignum_to_felem converts |in| to an |EC_FELEM|. It returns one on success
// and zero if |in| is out of range.
int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in);
@@ -583,19 +586,30 @@
const EC_METHOD *EC_GFp_mont_method(void);
+struct ec_point_st {
+ // group is an owning reference to |group|, unless this is
+ // |group->generator|.
+ EC_GROUP *group;
+ // raw is the group-specific point data. Functions that take |EC_POINT|
+ // typically check consistency with |EC_GROUP| while functions that take
+ // |EC_JACOBIAN| do not. Thus accesses to this field should be externally
+ // checked for consistency.
+ EC_JACOBIAN raw;
+} /* EC_POINT */;
+
struct ec_group_st {
const EC_METHOD *meth;
// Unlike all other |EC_POINT|s, |generator| does not own |generator->group|
// to avoid a reference cycle. Additionally, Z is guaranteed to be one, so X
- // and Y are suitable for use as an |EC_AFFINE|.
- EC_POINT *generator;
+ // and Y are suitable for use as an |EC_AFFINE|. Before |has_order| is set, Z
+ // is one, but X and Y are uninitialized.
+ EC_POINT generator;
BN_MONT_CTX order;
BN_MONT_CTX field;
EC_FELEM a, b; // Curve coefficients.
- EC_FELEM one; // The value one.
int curve_name; // optional NID for named curve
@@ -613,17 +627,6 @@
CRYPTO_refcount_t references;
} /* EC_GROUP */;
-struct ec_point_st {
- // group is an owning reference to |group|, unless this is
- // |group->generator|.
- EC_GROUP *group;
- // raw is the group-specific point data. Functions that take |EC_POINT|
- // typically check consistency with |EC_GROUP| while functions that take
- // |EC_JACOBIAN| do not. Thus accesses to this field should be externally
- // checked for consistency.
- EC_JACOBIAN raw;
-} /* EC_POINT */;
-
EC_GROUP *ec_group_new(const EC_METHOD *meth, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx);
diff --git a/crypto/fipsmodule/ec/simple.c b/crypto/fipsmodule/ec/simple.c
index 624d3ce..406e108 100644
--- a/crypto/fipsmodule/ec/simple.c
+++ b/crypto/fipsmodule/ec/simple.c
@@ -107,7 +107,8 @@
if (!BN_MONT_CTX_set(&group->field, p, ctx) ||
!ec_bignum_to_felem(group, &group->a, a) ||
!ec_bignum_to_felem(group, &group->b, b) ||
- !ec_bignum_to_felem(group, &group->one, BN_value_one())) {
+ // Reuse Z from the generator to cache the value one.
+ !ec_bignum_to_felem(group, &group->generator.raw.Z, BN_value_one())) {
goto err;
}
diff --git a/crypto/fipsmodule/ec/simple_mul.c b/crypto/fipsmodule/ec/simple_mul.c
index 796c408..3ec0b12 100644
--- a/crypto/fipsmodule/ec/simple_mul.c
+++ b/crypto/fipsmodule/ec/simple_mul.c
@@ -78,7 +78,7 @@
void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
- ec_GFp_mont_mul(group, r, &group->generator->raw, scalar);
+ ec_GFp_mont_mul(group, r, &group->generator.raw, scalar);
}
static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
@@ -230,7 +230,7 @@
ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
}
BN_ULONG is_infinity = constant_time_is_zero_w(window);
- ec_felem_select(group, &out->Z, is_infinity, &out->Z, &group->one);
+ ec_felem_select(group, &out->Z, is_infinity, &out->Z, ec_felem_one(group));
}
void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
diff --git a/crypto/fipsmodule/ec/wnaf.c b/crypto/fipsmodule/ec/wnaf.c
index 2cc0fbc..f5214b2 100644
--- a/crypto/fipsmodule/ec/wnaf.c
+++ b/crypto/fipsmodule/ec/wnaf.c
@@ -214,7 +214,7 @@
int8_t g_wNAF[EC_MAX_BYTES * 8 + 1];
EC_JACOBIAN g_precomp[EC_WNAF_TABLE_SIZE];
assert(wNAF_len <= OPENSSL_ARRAY_SIZE(g_wNAF));
- const EC_JACOBIAN *g = &group->generator->raw;
+ const EC_JACOBIAN *g = &group->generator.raw;
if (g_scalar != NULL) {
ec_compute_wNAF(group, g_wNAF, g_scalar, bits, EC_WNAF_WINDOW_BITS);
compute_precomp(group, g_precomp, g, EC_WNAF_TABLE_SIZE);
diff --git a/crypto/trust_token/pmbtoken.c b/crypto/trust_token/pmbtoken.c
index be093fc..49eda91 100644
--- a/crypto/trust_token/pmbtoken.c
+++ b/crypto/trust_token/pmbtoken.c
@@ -86,7 +86,7 @@
ec_affine_to_jacobian(method->group, &method->h, &h);
if (!ec_init_precomp(method->group, &method->g_precomp,
- &method->group->generator->raw) ||
+ &method->group->generator.raw) ||
!ec_init_precomp(method->group, &method->h_precomp, &method->h)) {
return 0;
}
@@ -679,7 +679,7 @@
const EC_JACOBIAN *S, const EC_JACOBIAN *W,
const EC_JACOBIAN *Ws) {
const EC_GROUP *group = method->group;
- const EC_JACOBIAN *g = &group->generator->raw;
+ const EC_JACOBIAN *g = &group->generator.raw;
// We verify a DLEQ proof for the validity token and a DLEQOR2 proof for the
// private metadata token. To allow amortizing Jacobian-to-affine conversions,