Make built-in curves static.

This replaces our dynamically creating singleton EC_GROUPs from curve
data with static EC_GROUP instances.

They're just shy of being fully static because delocate still forces us
go to through CRYPTO_once to initialize structures with pointers.
(Though, without delocate, the loader would need similar initialization
via a runtime relocation.)

This means we can now have functions like EC_group_p256(), analogous to
EVP_sha256(). These are infallible functions that return const EC_GROUP
pointers. Although there is an initial 2KiB hit to binary size (now we
precompute a few more Montgomery values), I'm hoping it'll eventually
help binaries that only use a few of the curves to drop the others. Also
it removes some locks used to initialize the static curve objects, as
well as removing an annoying error condition.

Bug: 20
Change-Id: Id051c5439f2b2fe2b09bf10964d656503ee27d9e
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60931
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
chromium-stable
David Benjamin 2 years ago committed by Boringssl LUCI CQ
parent 8267582590
commit 417069f8b2
  1. 177
      crypto/ec_extra/ec_asn1.c
  2. 2
      crypto/fipsmodule/bcm.c
  3. 14
      crypto/fipsmodule/bn/rsaz_exp.c
  4. 277
      crypto/fipsmodule/ec/builtin_curves.h
  5. 479
      crypto/fipsmodule/ec/ec.c
  6. 30
      crypto/fipsmodule/ec/internal.h
  7. 322
      crypto/fipsmodule/ec/make_tables.go
  8. 23
      include/openssl/ec.h
  9. 25
      include/openssl/ec_key.h

@ -72,6 +72,16 @@ static const CBS_ASN1_TAG kParametersTag =
static const CBS_ASN1_TAG kPublicKeyTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
// TODO(https://crbug.com/boringssl/497): Allow parsers to specify a list of
// acceptable groups, so parsers don't have to pull in all four.
typedef const EC_GROUP *(*ec_group_func)(void);
static const ec_group_func kAllGroups[] = {
&EC_group_p224,
&EC_group_p256,
&EC_group_p384,
&EC_group_p521,
};
EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
CBS ec_private_key, private_key;
uint64_t version;
@ -244,9 +254,12 @@ int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
// kPrimeFieldOID is the encoding of 1.2.840.10045.1.1.
static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01};
static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
CBS *out_b, CBS *out_base_x,
CBS *out_base_y, CBS *out_order) {
struct explicit_prime_curve {
CBS prime, a, b, base_x, base_y, order;
};
static int parse_explicit_prime_curve(CBS *in,
struct explicit_prime_curve *out) {
// See RFC 3279, section 2.3.5. Note that RFC 3279 calls this structure an
// ECParameters while RFC 5480 calls it a SpecifiedECDomain.
CBS params, field_id, field_type, curve, base, cofactor;
@ -260,18 +273,18 @@ static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
CBS_len(&field_type) != sizeof(kPrimeField) ||
OPENSSL_memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) !=
0 ||
!CBS_get_asn1(&field_id, out_prime, CBS_ASN1_INTEGER) ||
!CBS_is_unsigned_asn1_integer(out_prime) ||
!CBS_get_asn1(&field_id, &out->prime, CBS_ASN1_INTEGER) ||
!CBS_is_unsigned_asn1_integer(&out->prime) ||
CBS_len(&field_id) != 0 ||
!CBS_get_asn1(&params, &curve, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&curve, out_a, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&curve, out_b, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&curve, &out->a, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&curve, &out->b, CBS_ASN1_OCTETSTRING) ||
// |curve| has an optional BIT STRING seed which we ignore.
!CBS_get_optional_asn1(&curve, NULL, NULL, CBS_ASN1_BITSTRING) ||
CBS_len(&curve) != 0 ||
!CBS_get_asn1(&params, &base, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&params, out_order, CBS_ASN1_INTEGER) ||
!CBS_is_unsigned_asn1_integer(out_order) ||
!CBS_get_asn1(&params, &out->order, CBS_ASN1_INTEGER) ||
!CBS_is_unsigned_asn1_integer(&out->order) ||
!CBS_get_optional_asn1(&params, &cofactor, &has_cofactor,
CBS_ASN1_INTEGER) ||
CBS_len(&params) != 0) {
@ -300,25 +313,33 @@ static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
return 0;
}
size_t field_len = CBS_len(&base) / 2;
CBS_init(out_base_x, CBS_data(&base), field_len);
CBS_init(out_base_y, CBS_data(&base) + field_len, field_len);
CBS_init(&out->base_x, CBS_data(&base), field_len);
CBS_init(&out->base_y, CBS_data(&base) + field_len, field_len);
return 1;
}
// integers_equal returns one if |a| and |b| are equal, up to leading zeros, and
// integers_equal returns one if |bytes| is a big-endian encoding of |bn|, and
// zero otherwise.
static int integers_equal(const CBS *a, const uint8_t *b, size_t b_len) {
// Remove leading zeros from |a| and |b|.
CBS a_copy = *a;
while (CBS_len(&a_copy) > 0 && CBS_data(&a_copy)[0] == 0) {
CBS_skip(&a_copy, 1);
static int integers_equal(const CBS *bytes, const BIGNUM *bn) {
// Although, in SEC 1, Field-Element-to-Octet-String has a fixed width,
// OpenSSL mis-encodes the |a| and |b|, so we tolerate any number of leading
// zeros. (This matters for P-521 whose |b| has a leading 0.)
CBS copy = *bytes;
while (CBS_len(&copy) > 0 && CBS_data(&copy)[0] == 0) {
CBS_skip(&copy, 1);
}
while (b_len > 0 && b[0] == 0) {
b++;
b_len--;
if (CBS_len(&copy) > EC_MAX_BYTES) {
return 0;
}
return CBS_mem_equal(&a_copy, b, b_len);
uint8_t buf[EC_MAX_BYTES];
if (!BN_bn2bin_padded(buf, CBS_len(&copy), bn)) {
ERR_clear_error();
return 0;
}
return CBS_mem_equal(&copy, buf, CBS_len(&copy));
}
EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
@ -329,13 +350,12 @@ EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
}
// Look for a matching curve.
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
const struct built_in_curve *curve = &curves->curves[i];
if (CBS_len(&named_curve) == curve->oid_len &&
OPENSSL_memcmp(CBS_data(&named_curve), curve->oid, curve->oid_len) ==
0) {
return EC_GROUP_new_by_curve_name(curve->nid);
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kAllGroups); i++) {
const EC_GROUP *group = kAllGroups[i]();
if (CBS_mem_equal(&named_curve, group->oid, group->oid_len)) {
// TODO(davidben): Remove unnecessary calls to |EC_GROUP_free| within the
// library.
return (EC_GROUP *)group;
}
}
@ -344,25 +364,15 @@ EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
}
int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) {
int nid = EC_GROUP_get_curve_name(group);
if (nid == NID_undef) {
if (group->oid_len == 0) {
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return 0;
}
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
const struct built_in_curve *curve = &curves->curves[i];
if (curve->nid == nid) {
CBB child;
return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) &&
CBB_add_bytes(&child, curve->oid, curve->oid_len) &&
CBB_flush(cbb);
}
}
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return 0;
CBB child;
return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) &&
CBB_add_bytes(&child, group->oid, group->oid_len) && //
CBB_flush(cbb);
}
EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
@ -374,34 +384,58 @@ EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
// of named curves.
//
// TODO(davidben): Remove support for this.
CBS prime, a, b, base_x, base_y, order;
if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y,
&order)) {
struct explicit_prime_curve curve;
if (!parse_explicit_prime_curve(cbs, &curve)) {
return NULL;
}
// Look for a matching prime curve.
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
const struct built_in_curve *curve = &curves->curves[i];
const unsigned param_len = curve->param_len;
// |curve->params| is ordered p, a, b, x, y, order, each component
// zero-padded up to the field length. Although SEC 1 states that the
// Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes
// |a| and |b|, so this comparison must allow omitting leading zeros. (This
// is relevant for P-521 whose |b| has a leading 0.)
if (integers_equal(&prime, curve->params, param_len) &&
integers_equal(&a, curve->params + param_len, param_len) &&
integers_equal(&b, curve->params + param_len * 2, param_len) &&
integers_equal(&base_x, curve->params + param_len * 3, param_len) &&
integers_equal(&base_y, curve->params + param_len * 4, param_len) &&
integers_equal(&order, curve->params + param_len * 5, param_len)) {
return EC_GROUP_new_by_curve_name(curve->nid);
const EC_GROUP *ret = NULL;
BIGNUM *p = BN_new(), *a = BN_new(), *b = BN_new(), *x = BN_new(),
*y = BN_new();
if (p == NULL || a == NULL || b == NULL || x == NULL || y == NULL) {
goto err;
}
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kAllGroups); i++) {
const EC_GROUP *group = kAllGroups[i]();
if (!integers_equal(&curve.order, EC_GROUP_get0_order(group))) {
continue;
}
// The order alone uniquely identifies the group, but we check the other
// parameters to avoid misinterpreting the group.
if (!EC_GROUP_get_curve_GFp(group, p, a, b, NULL)) {
goto err;
}
if (!integers_equal(&curve.prime, p) || !integers_equal(&curve.a, a) ||
!integers_equal(&curve.b, b)) {
break;
}
if (!EC_POINT_get_affine_coordinates_GFp(
group, EC_GROUP_get0_generator(group), x, y, NULL)) {
goto err;
}
if (!integers_equal(&curve.base_x, x) ||
!integers_equal(&curve.base_y, y)) {
break;
}
ret = group;
break;
}
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return NULL;
if (ret == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
}
err:
BN_free(p);
BN_free(a);
BN_free(b);
BN_free(x);
BN_free(y);
// TODO(davidben): Remove unnecessary calls to |EC_GROUP_free| within the
// library.
return (EC_GROUP *)ret;
}
int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point,
@ -532,3 +566,16 @@ int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) {
// Historically, this function used the wrong return value on error.
return ret > 0 ? ret : 0;
}
size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
size_t max_num_curves) {
if (max_num_curves > OPENSSL_ARRAY_SIZE(kAllGroups)) {
max_num_curves = OPENSSL_ARRAY_SIZE(kAllGroups);
}
for (size_t i = 0; i < max_num_curves; i++) {
const EC_GROUP *group = kAllGroups[i]();
out_curves[i].nid = group->curve_name;
out_curves[i].comment = group->comment;
}
return OPENSSL_ARRAY_SIZE(kAllGroups);
}

@ -211,7 +211,7 @@ int BORINGSSL_integrity_test(void) {
#endif
assert_within(rodata_start, kPrimes, rodata_end);
assert_within(rodata_start, kP256Params, rodata_end);
assert_within(rodata_start, kP256Field, rodata_end);
assert_within(rodata_start, kPKCS1SigPrefixes, rodata_end);
uint8_t result[SHA256_DIGEST_LENGTH];

@ -24,13 +24,13 @@
#include "../../internal.h"
// one is 1 in RSAZ's representation.
alignas(64) static const BN_ULONG one[40] = {
// rsaz_one is 1 in RSAZ's representation.
alignas(64) static const BN_ULONG rsaz_one[40] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// two80 is 2^80 in RSAZ's representation. Note RSAZ uses base 2^29, so this is
// rsaz_two80 is 2^80 in RSAZ's representation. Note RSAZ uses base 2^29, so this is
// 2^(29*2 + 22) = 2^80, not 2^(64*2 + 22).
alignas(64) static const BN_ULONG two80[40] = {
alignas(64) static const BN_ULONG rsaz_two80[40] = {
0, 0, 1 << 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@ -64,12 +64,12 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
// giving R = 2^(36*29) = 2^1044.
rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
// R2 = 2^2048 * 2^2048 / 2^1044 = 2^3052
rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
rsaz_1024_mul_avx2(R2, R2, rsaz_two80, m, k0);
// R2 = 2^3052 * 2^80 / 2^1044 = 2^2088 = (2^1044)^2
// table[0] = 1
// table[1] = a_inv^1
rsaz_1024_mul_avx2(result, R2, one, m, k0);
rsaz_1024_mul_avx2(result, R2, rsaz_one, m, k0);
rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
rsaz_1024_scatter5_avx2(table_s, result, 0);
rsaz_1024_scatter5_avx2(table_s, a_inv, 1);
@ -125,7 +125,7 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
// Convert from Montgomery.
rsaz_1024_mul_avx2(result, result, one, m, k0);
rsaz_1024_mul_avx2(result, result, rsaz_one, m, k0);
rsaz_1024_red2norm_avx2(result_norm, result);
BN_ULONG scratch[16];

@ -0,0 +1,277 @@
/* Copyright (c) 2023, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// This file is generated by make_tables.go.
// P-224
OPENSSL_UNUSED static const uint64_t kP224FieldN0 = 0xffffffffffffffff;
OPENSSL_UNUSED static const uint64_t kP224OrderN0 = 0xd6e242706a1fc2eb;
#if defined(OPENSSL_64_BIT)
OPENSSL_UNUSED static const uint64_t kP224Field[] = {
0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff,
0x00000000ffffffff};
OPENSSL_UNUSED static const uint64_t kP224Order[] = {
0x13dd29455c5c2a3d, 0xffff16a2e0b8f03e, 0xffffffffffffffff,
0x00000000ffffffff};
OPENSSL_UNUSED static const uint64_t kP224B[] = {
0x270b39432355ffb4, 0x5044b0b7d7bfd8ba, 0x0c04b3abf5413256,
0x00000000b4050a85};
OPENSSL_UNUSED static const uint64_t kP224GX[] = {
0x343280d6115c1d21, 0x4a03c1d356c21122, 0x6bb4bf7f321390b9,
0x00000000b70e0cbd};
OPENSSL_UNUSED static const uint64_t kP224GY[] = {
0x44d5819985007e34, 0xcd4375a05a074764, 0xb5f723fb4c22dfe6,
0x00000000bd376388};
OPENSSL_UNUSED static const uint64_t kP224FieldR[] = {
0xffffffff00000000, 0xffffffffffffffff, 0x0000000000000000,
0x0000000000000000};
OPENSSL_UNUSED static const uint64_t kP224FieldRR[] = {
0xffffffff00000001, 0xffffffff00000000, 0xfffffffe00000000,
0x00000000ffffffff};
OPENSSL_UNUSED static const uint64_t kP224OrderRR[] = {
0x29947a695f517d15, 0xabc8ff5931d63f4b, 0x6ad15f7cd9714856,
0x00000000b1e97961};
OPENSSL_UNUSED static const uint64_t kP224MontB[] = {
0xe768cdf663c059cd, 0x107ac2f3ccf01310, 0x3dceba98c8528151,
0x000000007fc02f93};
OPENSSL_UNUSED static const uint64_t kP224MontGX[] = {
0xbc9052266d0a4aea, 0x852597366018bfaa, 0x6dd3af9bf96bec05,
0x00000000a21b5e60};
OPENSSL_UNUSED static const uint64_t kP224MontGY[] = {
0x2edca1e5eff3ede8, 0xf8cd672b05335a6b, 0xaea9c5ae03dfe878,
0x00000000614786f1};
#elif defined(OPENSSL_32_BIT)
OPENSSL_UNUSED static const uint32_t kP224Field[] = {
0x00000001, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff};
OPENSSL_UNUSED static const uint32_t kP224Order[] = {
0x5c5c2a3d, 0x13dd2945, 0xe0b8f03e, 0xffff16a2, 0xffffffff, 0xffffffff,
0xffffffff};
OPENSSL_UNUSED static const uint32_t kP224B[] = {
0x2355ffb4, 0x270b3943, 0xd7bfd8ba, 0x5044b0b7, 0xf5413256, 0x0c04b3ab,
0xb4050a85};
OPENSSL_UNUSED static const uint32_t kP224GX[] = {
0x115c1d21, 0x343280d6, 0x56c21122, 0x4a03c1d3, 0x321390b9, 0x6bb4bf7f,
0xb70e0cbd};
OPENSSL_UNUSED static const uint32_t kP224GY[] = {
0x85007e34, 0x44d58199, 0x5a074764, 0xcd4375a0, 0x4c22dfe6, 0xb5f723fb,
0xbd376388};
OPENSSL_UNUSED static const uint32_t kP224FieldR[] = {
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
0x00000000};
OPENSSL_UNUSED static const uint32_t kP224FieldRR[] = {
0x00000001, 0x00000000, 0x00000000, 0xfffffffe, 0xffffffff, 0xffffffff,
0x00000000};
OPENSSL_UNUSED static const uint32_t kP224OrderRR[] = {
0x3ad01289, 0x6bdaae6c, 0x97a54552, 0x6ad09d91, 0xb1e97961, 0x1822bc47,
0xd4baa4cf};
OPENSSL_UNUSED static const uint32_t kP224MontB[] = {
0xe768cdf7, 0xccf01310, 0x743b1cc0, 0xc8528150, 0x3dceba98, 0x7fc02f93,
0x9c3fa633};
OPENSSL_UNUSED static const uint32_t kP224MontGX[] = {
0xbc905227, 0x6018bfaa, 0xf22fe220, 0xf96bec04, 0x6dd3af9b, 0xa21b5e60,
0x92f5b516};
OPENSSL_UNUSED static const uint32_t kP224MontGY[] = {
0x2edca1e6, 0x05335a6b, 0xe8c15513, 0x03dfe878, 0xaea9c5ae, 0x614786f1,
0x100c1218};
#else
#error "unknown word size"
#endif
// P-256
OPENSSL_UNUSED static const uint64_t kP256FieldN0 = 0x0000000000000001;
OPENSSL_UNUSED static const uint64_t kP256OrderN0 = 0xccd1c8aaee00bc4f;
#if defined(OPENSSL_64_BIT)
OPENSSL_UNUSED static const uint64_t kP256Field[] = {
0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000,
0xffffffff00000001};
OPENSSL_UNUSED static const uint64_t kP256Order[] = {
0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff,
0xffffffff00000000};
OPENSSL_UNUSED static const uint64_t kP256FieldR[] = {
0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff,
0x00000000fffffffe};
OPENSSL_UNUSED static const uint64_t kP256FieldRR[] = {
0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe,
0x00000004fffffffd};
OPENSSL_UNUSED static const uint64_t kP256OrderRR[] = {
0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59,
0x66e12d94f3d95620};
OPENSSL_UNUSED static const uint64_t kP256MontB[] = {
0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6,
0xdc30061d04874834};
OPENSSL_UNUSED static const uint64_t kP256MontGX[] = {
0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510,
0x18905f76a53755c6};
OPENSSL_UNUSED static const uint64_t kP256MontGY[] = {
0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325,
0x8571ff1825885d85};
#elif defined(OPENSSL_32_BIT)
OPENSSL_UNUSED static const uint32_t kP256Field[] = {
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0xffffffff};
OPENSSL_UNUSED static const uint32_t kP256Order[] = {
0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff,
0x00000000, 0xffffffff};
OPENSSL_UNUSED static const uint32_t kP256FieldR[] = {
0x00000001, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
0xfffffffe, 0x00000000};
OPENSSL_UNUSED static const uint32_t kP256FieldRR[] = {
0x00000003, 0x00000000, 0xffffffff, 0xfffffffb, 0xfffffffe, 0xffffffff,
0xfffffffd, 0x00000004};
OPENSSL_UNUSED static const uint32_t kP256OrderRR[] = {
0xbe79eea2, 0x83244c95, 0x49bd6fa6, 0x4699799c, 0x2b6bec59, 0x2845b239,
0xf3d95620, 0x66e12d94};
OPENSSL_UNUSED static const uint32_t kP256MontB[] = {
0x29c4bddf, 0xd89cdf62, 0x78843090, 0xacf005cd, 0xf7212ed6, 0xe5a220ab,
0x04874834, 0xdc30061d};
OPENSSL_UNUSED static const uint32_t kP256MontGX[] = {
0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, 0x77622510, 0x79fb732b,
0xa53755c6, 0x18905f76};
OPENSSL_UNUSED static const uint32_t kP256MontGY[] = {
0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, 0xdd21f325, 0xd2e88688,
0x25885d85, 0x8571ff18};
#else
#error "unknown word size"
#endif
// P-384
OPENSSL_UNUSED static const uint64_t kP384FieldN0 = 0x0000000100000001;
OPENSSL_UNUSED static const uint64_t kP384OrderN0 = 0x6ed46089e88fdc45;
#if defined(OPENSSL_64_BIT)
OPENSSL_UNUSED static const uint64_t kP384Field[] = {
0x00000000ffffffff, 0xffffffff00000000, 0xfffffffffffffffe,
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
OPENSSL_UNUSED static const uint64_t kP384Order[] = {
0xecec196accc52973, 0x581a0db248b0a77a, 0xc7634d81f4372ddf,
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
OPENSSL_UNUSED static const uint64_t kP384FieldR[] = {
0xffffffff00000001, 0x00000000ffffffff, 0x0000000000000001,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
OPENSSL_UNUSED static const uint64_t kP384FieldRR[] = {
0xfffffffe00000001, 0x0000000200000000, 0xfffffffe00000000,
0x0000000200000000, 0x0000000000000001, 0x0000000000000000};
OPENSSL_UNUSED static const uint64_t kP384OrderRR[] = {
0x2d319b2419b409a9, 0xff3d81e5df1aa419, 0xbc3e483afcb82947,
0xd40d49174aab1cc5, 0x3fb05b7a28266895, 0x0c84ee012b39bf21};
OPENSSL_UNUSED static const uint64_t kP384MontB[] = {
0x081188719d412dcc, 0xf729add87a4c32ec, 0x77f2209b1920022e,
0xe3374bee94938ae2, 0xb62b21f41f022094, 0xcd08114b604fbff9};
OPENSSL_UNUSED static const uint64_t kP384MontGX[] = {
0x3dd0756649c0b528, 0x20e378e2a0d6ce38, 0x879c3afc541b4d6e,
0x6454868459a30eff, 0x812ff723614ede2b, 0x4d3aadc2299e1513};
OPENSSL_UNUSED static const uint64_t kP384MontGY[] = {
0x23043dad4b03a4fe, 0xa1bfa8bf7bb4a9ac, 0x8bade7562e83b050,
0xc6c3521968f4ffd9, 0xdd8002263969a840, 0x2b78abc25a15c5e9};
#elif defined(OPENSSL_32_BIT)
OPENSSL_UNUSED static const uint32_t kP384Field[] = {
0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xfffffffe, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
OPENSSL_UNUSED static const uint32_t kP384Order[] = {
0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, 0xf4372ddf, 0xc7634d81,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
OPENSSL_UNUSED static const uint32_t kP384FieldR[] = {
0x00000001, 0xffffffff, 0xffffffff, 0x00000000, 0x00000001, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
OPENSSL_UNUSED static const uint32_t kP384FieldRR[] = {
0x00000001, 0xfffffffe, 0x00000000, 0x00000002, 0x00000000, 0xfffffffe,
0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000};
OPENSSL_UNUSED static const uint32_t kP384OrderRR[] = {
0x19b409a9, 0x2d319b24, 0xdf1aa419, 0xff3d81e5, 0xfcb82947, 0xbc3e483a,
0x4aab1cc5, 0xd40d4917, 0x28266895, 0x3fb05b7a, 0x2b39bf21, 0x0c84ee01};
OPENSSL_UNUSED static const uint32_t kP384MontB[] = {
0x9d412dcc, 0x08118871, 0x7a4c32ec, 0xf729add8, 0x1920022e, 0x77f2209b,
0x94938ae2, 0xe3374bee, 0x1f022094, 0xb62b21f4, 0x604fbff9, 0xcd08114b};
OPENSSL_UNUSED static const uint32_t kP384MontGX[] = {
0x49c0b528, 0x3dd07566, 0xa0d6ce38, 0x20e378e2, 0x541b4d6e, 0x879c3afc,
0x59a30eff, 0x64548684, 0x614ede2b, 0x812ff723, 0x299e1513, 0x4d3aadc2};
OPENSSL_UNUSED static const uint32_t kP384MontGY[] = {
0x4b03a4fe, 0x23043dad, 0x7bb4a9ac, 0xa1bfa8bf, 0x2e83b050, 0x8bade756,
0x68f4ffd9, 0xc6c35219, 0x3969a840, 0xdd800226, 0x5a15c5e9, 0x2b78abc2};
#else
#error "unknown word size"
#endif
// P-521
OPENSSL_UNUSED static const uint64_t kP521FieldN0 = 0x0000000000000001;
OPENSSL_UNUSED static const uint64_t kP521OrderN0 = 0x1d2f5ccd79a995c7;
#if defined(OPENSSL_64_BIT)
OPENSSL_UNUSED static const uint64_t kP521Field[] = {
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff, 0x00000000000001ff};
OPENSSL_UNUSED static const uint64_t kP521Order[] = {
0xbb6fb71e91386409, 0x3bb5c9b8899c47ae, 0x7fcc0148f709a5d0,
0x51868783bf2f966b, 0xfffffffffffffffa, 0xffffffffffffffff,
0xffffffffffffffff, 0xffffffffffffffff, 0x00000000000001ff};
OPENSSL_UNUSED static const uint64_t kP521FieldR[] = {
0x0080000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
OPENSSL_UNUSED static const uint64_t kP521FieldRR[] = {
0x0000000000000000, 0x0000400000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
OPENSSL_UNUSED static const uint64_t kP521OrderRR[] = {
0x137cd04dcf15dd04, 0xf707badce5547ea3, 0x12a78d38794573ff,
0xd3721ef557f75e06, 0xdd6e23d82e49c7db, 0xcff3d142b7756e3e,
0x5bcc6d61a8e567bc, 0x2d8e03d1492d0d45, 0x000000000000003d};
OPENSSL_UNUSED static const uint64_t kP521MontB[] = {
0x8014654fae586387, 0x78f7a28fea35a81f, 0x839ab9efc41e961a,
0xbd8b29605e9dd8df, 0xf0ab0c9ca8f63f49, 0xf9dc5a44c8c77884,
0x77516d392dccd98a, 0x0fc94d10d05b42a0, 0x000000000000004d};
OPENSSL_UNUSED static const uint64_t kP521MontGX[] = {
0xb331a16381adc101, 0x4dfcbf3f18e172de, 0x6f19a459e0c2b521,
0x947f0ee093d17fd4, 0xdd50a5af3bf7f3ac, 0x90fc1457b035a69e,
0x214e32409c829fda, 0xe6cf1f65b311cada, 0x0000000000000074};
OPENSSL_UNUSED static const uint64_t kP521MontGY[] = {
0x28460e4a5a9e268e, 0x20445f4a3b4fe8b3, 0xb09a9e3843513961,
0x2062a85c809fd683, 0x164bf7394caf7a13, 0x340bd7de8b939f33,
0xeccc7aa224abcda2, 0x022e452fda163e8d, 0x00000000000001e0};
#elif defined(OPENSSL_32_BIT)
OPENSSL_UNUSED static const uint32_t kP521Field[] = {
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff};
OPENSSL_UNUSED static const uint32_t kP521Order[] = {
0x91386409, 0xbb6fb71e, 0x899c47ae, 0x3bb5c9b8, 0xf709a5d0, 0x7fcc0148,
0xbf2f966b, 0x51868783, 0xfffffffa, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff};
OPENSSL_UNUSED static const uint32_t kP521FieldR[] = {
0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
OPENSSL_UNUSED static const uint32_t kP521FieldRR[] = {
0x00000000, 0x00004000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
OPENSSL_UNUSED static const uint32_t kP521OrderRR[] = {
0x61c64ca7, 0x1163115a, 0x4374a642, 0x18354a56, 0x0791d9dc, 0x5d4dd6d3,
0xd3402705, 0x4fb35b72, 0xb7756e3a, 0xcff3d142, 0xa8e567bc, 0x5bcc6d61,
0x492d0d45, 0x2d8e03d1, 0x8c44383d, 0x5b5a3afe, 0x0000019a};
OPENSSL_UNUSED static const uint32_t kP521MontB[] = {
0x8014654f, 0xea35a81f, 0x78f7a28f, 0xc41e961a, 0x839ab9ef, 0x5e9dd8df,
0xbd8b2960, 0xa8f63f49, 0xf0ab0c9c, 0xc8c77884, 0xf9dc5a44, 0x2dccd98a,
0x77516d39, 0xd05b42a0, 0x0fc94d10, 0xb0c70e4d, 0x0000015c};
OPENSSL_UNUSED static const uint32_t kP521MontGX[] = {
0xb331a163, 0x18e172de, 0x4dfcbf3f, 0xe0c2b521, 0x6f19a459, 0x93d17fd4,
0x947f0ee0, 0x3bf7f3ac, 0xdd50a5af, 0xb035a69e, 0x90fc1457, 0x9c829fda,
0x214e3240, 0xb311cada, 0xe6cf1f65, 0x5b820274, 0x00000103};
OPENSSL_UNUSED static const uint32_t kP521MontGY[] = {
0x28460e4a, 0x3b4fe8b3, 0x20445f4a, 0x43513961, 0xb09a9e38, 0x809fd683,
0x2062a85c, 0x4caf7a13, 0x164bf739, 0x8b939f33, 0x340bd7de, 0x24abcda2,
0xeccc7aa2, 0xda163e8d, 0x022e452f, 0x3c4d1de0, 0x000000b5};
#else
#error "unknown word size"
#endif

@ -80,233 +80,147 @@
#include "../bn/internal.h"
#include "../delocate.h"
#include "builtin_curves.h"
static void ec_point_free(EC_POINT *point, int free_group);
static const uint8_t kP224Params[6 * 28] = {
// p = 2^224 - 2^96 + 1
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
// a
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE,
// b
0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56,
0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43,
0x23, 0x55, 0xFF, 0xB4,
// x
0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9,
0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6,
0x11, 0x5C, 0x1D, 0x21,
// y
0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6,
0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
0x85, 0x00, 0x7e, 0x34,
// order
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45,
0x5C, 0x5C, 0x2A, 0x3D,
};
static const uint8_t kP256Params[6 * 32] = {
// p = 2^256 - 2^224 + 2^192 + 2^96 - 1
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// a
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
// b
0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55,
0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B,
// x
0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5,
0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
// y
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a,
0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
// order
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51,
};
static const uint8_t kP384Params[6 * 48] = {
// p = 2^384 - 2^128 - 2^96 + 2^32 - 1
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
// a
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC,
// b
0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B,
0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12,
0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D,
0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF,
// x
0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E,
0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98,
0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D,
0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7,
// y
0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf,
0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce,
0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f,
// order
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2,
0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73,
};
static const uint8_t kP521Params[6 * 66] = {
// p = 2^521 - 1
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// a
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
// b
0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A,
0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3,
0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19,
0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45,
0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00,
// x
0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E,
0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F,
0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B,
0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E,
0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66,
// y
0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a,
0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee,
0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe,
0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50,
// order
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86,
0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F,
0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09,
};
DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
// 1.3.132.0.35
static const uint8_t kOIDP521[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
out->curves[0].nid = NID_secp521r1;
out->curves[0].oid = kOIDP521;
out->curves[0].oid_len = sizeof(kOIDP521);
out->curves[0].comment = "NIST P-521";
out->curves[0].param_len = 66;
out->curves[0].params = kP521Params;
out->curves[0].method = EC_GFp_mont_method();
// 1.3.132.0.34
static const uint8_t kOIDP384[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
out->curves[1].nid = NID_secp384r1;
out->curves[1].oid = kOIDP384;
out->curves[1].oid_len = sizeof(kOIDP384);
out->curves[1].comment = "NIST P-384";
out->curves[1].param_len = 48;
out->curves[1].params = kP384Params;
out->curves[1].method = EC_GFp_mont_method();
static void ec_point_free(EC_POINT *point, int free_group);
// 1.2.840.10045.3.1.7
static const uint8_t kOIDP256[] = {0x2a, 0x86, 0x48, 0xce,
0x3d, 0x03, 0x01, 0x07};
out->curves[2].nid = NID_X9_62_prime256v1;
out->curves[2].oid = kOIDP256;
out->curves[2].oid_len = sizeof(kOIDP256);
out->curves[2].comment = "NIST P-256";
out->curves[2].param_len = 32;
out->curves[2].params = kP256Params;
out->curves[2].method =
#if !defined(OPENSSL_NO_ASM) && \
(defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64)) && \
!defined(OPENSSL_SMALL)
EC_GFp_nistz256_method();
static void ec_group_init_static_mont(BN_MONT_CTX *mont, size_t num_words,
const BN_ULONG *modulus,
const BN_ULONG *rr, uint64_t n0) {
bn_set_static_words(&mont->N, modulus, num_words);
bn_set_static_words(&mont->RR, rr, num_words);
#if defined(OPENSSL_64_BIT)
mont->n0[0] = n0;
#elif defined(OPENSSL_32_BIT)
mont->n0[0] = (uint32_t)n0;
mont->n0[1] = (uint32_t)(n0 >> 32);
#else
EC_GFp_nistp256_method();
#error "unknown word length"
#endif
}
static void ec_group_set_a_minus3(EC_GROUP *group) {
const EC_FELEM *one = ec_felem_one(group);
group->a_is_minus3 = 1;
ec_felem_neg(group, &group->a, one);
ec_felem_sub(group, &group->a, &group->a, one);
ec_felem_sub(group, &group->a, &group->a, one);
}
DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p224) {
out->curve_name = NID_secp224r1;
out->comment = "NIST P-224";
// 1.3.132.0.33
static const uint8_t kOIDP224[] = {0x2b, 0x81, 0x04, 0x00, 0x21};
out->curves[3].nid = NID_secp224r1;
out->curves[3].oid = kOIDP224;
out->curves[3].oid_len = sizeof(kOIDP224);
out->curves[3].comment = "NIST P-224";
out->curves[3].param_len = 28;
out->curves[3].params = kP224Params;
out->curves[3].method =
OPENSSL_memcpy(out->oid, kOIDP224, sizeof(kOIDP224));
out->oid_len = sizeof(kOIDP224);
ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP224Field),
kP224Field, kP224FieldRR, kP224FieldN0);
ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP224Order),
kP224Order, kP224OrderRR, kP224OrderN0);
#if defined(BORINGSSL_HAS_UINT128) && !defined(OPENSSL_SMALL)
EC_GFp_nistp224_method();
out->meth = EC_GFp_nistp224_method();
OPENSSL_memcpy(out->generator.raw.X.words, kP224GX, sizeof(kP224GX));
OPENSSL_memcpy(out->generator.raw.Y.words, kP224GY, sizeof(kP224GY));
out->generator.raw.Z.words[0] = 1;
OPENSSL_memcpy(out->b.words, kP224B, sizeof(kP224B));
#else
EC_GFp_mont_method();
out->meth = EC_GFp_mont_method();
OPENSSL_memcpy(out->generator.raw.X.words, kP224MontGX, sizeof(kP224MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kP224MontGY, sizeof(kP224MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kP224FieldR, sizeof(kP224FieldR));
OPENSSL_memcpy(out->b.words, kP224MontB, sizeof(kP224MontB));
#endif
}
out->generator.group = out;
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;
}
OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
ret->references = 1;
ret->meth = meth;
bn_mont_ctx_init(&ret->field);
bn_mont_ctx_init(&ret->order);
ec_group_set_a_minus3(out);
out->has_order = 1;
out->field_greater_than_order = 1;
}
ret->generator.group = ret;
DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p256) {
out->curve_name = NID_X9_62_prime256v1;
out->comment = "NIST P-256";
// 1.2.840.10045.3.1.7
static const uint8_t kOIDP256[] = {0x2a, 0x86, 0x48, 0xce,
0x3d, 0x03, 0x01, 0x07};
OPENSSL_memcpy(out->oid, kOIDP256, sizeof(kOIDP256));
out->oid_len = sizeof(kOIDP256);
if (!ec_GFp_simple_group_set_curve(ret, p, a, b, ctx)) {
EC_GROUP_free(ret);
return NULL;
}
ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP256Field),
kP256Field, kP256FieldRR, kP256FieldN0);
ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP256Order),
kP256Order, kP256OrderRR, kP256OrderN0);
return ret;
#if !defined(OPENSSL_NO_ASM) && \
(defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64)) && \
!defined(OPENSSL_SMALL)
out->meth = EC_GFp_nistz256_method();
#else
out->meth = EC_GFp_nistp256_method();
#endif
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kP256MontGX, sizeof(kP256MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kP256MontGY, sizeof(kP256MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kP256FieldR, sizeof(kP256FieldR));
OPENSSL_memcpy(out->b.words, kP256MontB, sizeof(kP256MontB));
ec_group_set_a_minus3(out);
out->has_order = 1;
out->field_greater_than_order = 1;
}
static int ec_group_set_generator(EC_GROUP *group, const EC_AFFINE *generator,
const BIGNUM *order) {
assert(!group->has_order);
if (!BN_MONT_CTX_set(&group->order, order, NULL)) {
return 0;
}
DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p384) {
out->curve_name = NID_secp384r1;
out->comment = "NIST P-384";
// 1.3.132.0.34
static const uint8_t kOIDP384[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
OPENSSL_memcpy(out->oid, kOIDP384, sizeof(kOIDP384));
out->oid_len = sizeof(kOIDP384);
ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP384Field),
kP384Field, kP384FieldRR, kP384FieldN0);
ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP384Order),
kP384Order, kP384OrderRR, kP384OrderN0);
out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kP384MontGX, sizeof(kP384MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kP384MontGY, sizeof(kP384MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kP384FieldR, sizeof(kP384FieldR));
OPENSSL_memcpy(out->b.words, kP384MontB, sizeof(kP384MontB));
ec_group_set_a_minus3(out);
out->has_order = 1;
out->field_greater_than_order = 1;
}
group->field_greater_than_order = BN_cmp(&group->field.N, order) > 0;
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;
DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p521) {
out->curve_name = NID_secp521r1;
out->comment = "NIST P-521";
// 1.3.132.0.35
static const uint8_t kOIDP521[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
OPENSSL_memcpy(out->oid, kOIDP521, sizeof(kOIDP521));
out->oid_len = sizeof(kOIDP521);
ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP521Field),
kP521Field, kP521FieldRR, kP521FieldN0);
ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP521Order),
kP521Order, kP521OrderRR, kP521OrderN0);
out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kP521MontGX, sizeof(kP521MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kP521MontGY, sizeof(kP521MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kP521FieldR, sizeof(kP521FieldR));
OPENSSL_memcpy(out->b.words, kP521MontB, sizeof(kP521MontB));
ec_group_set_a_minus3(out);
out->has_order = 1;
out->field_greater_than_order = 1;
}
EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
@ -336,8 +250,19 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
goto err;
}
ret = ec_group_new(EC_GFp_mont_method(), p, a_reduced, b_reduced, ctx);
ret = OPENSSL_malloc(sizeof(EC_GROUP));
if (ret == NULL) {
return NULL;
}
OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
ret->references = 1;
ret->meth = EC_GFp_mont_method();
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_reduced, b_reduced, ctx)) {
EC_GROUP_free(ret);
ret = NULL;
goto err;
}
@ -388,10 +313,15 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
EC_AFFINE affine;
if (!ec_jacobian_to_affine(group, &affine, &generator->raw) ||
!ec_group_set_generator(group, &affine, order)) {
!BN_MONT_CTX_set(&group->order, order, NULL)) {
goto err;
}
group->field_greater_than_order = BN_cmp(&group->field.N, order) > 0;
group->generator.raw.X = affine.X;
group->generator.raw.Y = affine.Y;
// |raw.Z| was set to 1 by |EC_GROUP_new_curve_GFp|.
group->has_order = 1;
ret = 1;
err:
@ -399,110 +329,20 @@ err:
return ret;
}
static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
EC_GROUP *group = NULL;
BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL;
int ok = 0;
BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
}
const unsigned param_len = curve->param_len;
const uint8_t *params = curve->params;
if (!(p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) ||
!(a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) ||
!(b = BN_bin2bn(params + 2 * param_len, param_len, NULL)) ||
!(order = BN_bin2bn(params + 5 * param_len, param_len, NULL))) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
group = ec_group_new(curve->method, p, a, b, ctx);
if (group == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
goto err;
}
EC_AFFINE G;
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) ||
!ec_group_set_generator(group, &G, order)) {
goto err;
}
ok = 1;
err:
if (!ok) {
EC_GROUP_free(group);
group = NULL;
}
BN_CTX_free(ctx);
BN_free(p);
BN_free(a);
BN_free(b);
BN_free(order);
return group;
}
// Built-in groups are allocated lazily and static once allocated.
// TODO(davidben): Make these actually static. https://crbug.com/boringssl/20.
struct built_in_groups_st {
EC_GROUP *groups[OPENSSL_NUM_BUILT_IN_CURVES];
};
DEFINE_BSS_GET(struct built_in_groups_st, built_in_groups)
DEFINE_STATIC_MUTEX(built_in_groups_lock)
EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
struct built_in_groups_st *groups = built_in_groups_bss_get();
EC_GROUP **group_ptr = NULL;
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
const struct built_in_curve *curve = NULL;
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
if (curves->curves[i].nid == nid) {
curve = &curves->curves[i];
group_ptr = &groups->groups[i];
break;
}
}
if (curve == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return NULL;
}
CRYPTO_MUTEX_lock_read(built_in_groups_lock_bss_get());
EC_GROUP *ret = *group_ptr;
CRYPTO_MUTEX_unlock_read(built_in_groups_lock_bss_get());
if (ret != NULL) {
return ret;
}
ret = ec_group_new_from_data(curve);
if (ret == NULL) {
return NULL;
}
EC_GROUP *to_free = NULL;
CRYPTO_MUTEX_lock_write(built_in_groups_lock_bss_get());
if (*group_ptr == NULL) {
*group_ptr = ret;
// Filling in |ret->curve_name| makes |EC_GROUP_free| and |EC_GROUP_dup|
// into no-ops. At this point, |ret| is considered static.
ret->curve_name = nid;
} else {
to_free = ret;
ret = *group_ptr;
switch (nid) {
case NID_secp224r1:
return (EC_GROUP *)EC_group_p224();
case NID_X9_62_prime256v1:
return (EC_GROUP *)EC_group_p256();
case NID_secp384r1:
return (EC_GROUP *)EC_group_p384();
case NID_secp521r1:
return (EC_GROUP *)EC_group_p521();
default:
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return NULL;
}
CRYPTO_MUTEX_unlock_write(built_in_groups_lock_bss_get());
EC_GROUP_free(to_free);
return ret;
}
void EC_GROUP_free(EC_GROUP *group) {
@ -1202,16 +1042,3 @@ void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
abort();
}
}
size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
size_t max_num_curves) {
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
for (size_t i = 0; i < max_num_curves && i < OPENSSL_NUM_BUILT_IN_CURVES;
i++) {
out_curves[i].comment = curves->curves[i].comment;
out_curves[i].nid = curves->curves[i].nid;
}
return OPENSSL_NUM_BUILT_IN_CURVES;
}

@ -611,7 +611,12 @@ struct ec_group_st {
EC_FELEM a, b; // Curve coefficients.
// comment is a human-readable string describing the curve.
const char *comment;
int curve_name; // optional NID for named curve
uint8_t oid[9];
uint8_t oid_len;
// a_is_minus3 is one if |a| is -3 mod |field| and zero otherwise. Point
// arithmetic is optimized for -3.
@ -743,31 +748,6 @@ struct ec_key_st {
CRYPTO_EX_DATA ex_data;
} /* EC_KEY */;
struct built_in_curve {
int nid;
const uint8_t *oid;
uint8_t oid_len;
// comment is a human-readable string describing the curve.
const char *comment;
// param_len is the number of bytes needed to store a field element.
uint8_t param_len;
// params points to an array of 6*|param_len| bytes which hold the field
// elements of the following (in big-endian order): prime, a, b, generator x,
// generator y, order.
const uint8_t *params;
const EC_METHOD *method;
};
#define OPENSSL_NUM_BUILT_IN_CURVES 4
struct built_in_curves {
struct built_in_curve curves[OPENSSL_NUM_BUILT_IN_CURVES];
};
// OPENSSL_built_in_curves returns a pointer to static information about
// standard curves. The array is terminated with an entry where |nid| is
// |NID_undef|.
const struct built_in_curves *OPENSSL_built_in_curves(void);
#if defined(__cplusplus)
} // extern C

@ -17,14 +17,21 @@
package main
import (
"bytes"
"crypto/elliptic"
"fmt"
"io"
"math/big"
"os"
"strings"
)
func main() {
if err := writeBuiltinCurves("builtin_curves.h"); err != nil {
fmt.Fprintf(os.Stderr, "Error writing builtin_curves.h: %s\n", err)
os.Exit(1)
}
if err := writeP256NistzTable("p256-nistz-table.h"); err != nil {
fmt.Fprintf(os.Stderr, "Error writing p256-nistz-table.h: %s\n", err)
os.Exit(1)
@ -36,6 +43,120 @@ func main() {
}
}
func writeBuiltinCurves(path string) error {
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
w := &columnWriter{w: f}
const fileHeader = `/* Copyright (c) 2023, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
// This file is generated by make_tables.go.
`
if _, err := io.WriteString(w, fileHeader); err != nil {
return err
}
// P-224 is the only curve where we have a non-Montgomery implementation.
if err := writeCurveData(w, elliptic.P224(), true); err != nil {
return err
}
if err := writeCurveData(w, elliptic.P256(), false); err != nil {
return err
}
if err := writeCurveData(w, elliptic.P384(), false); err != nil {
return err
}
if err := writeCurveData(w, elliptic.P521(), false); err != nil {
return err
}
return nil
}
func writeCurveData(w *columnWriter, curve elliptic.Curve, includeNonMontgomery bool) error {
params := curve.Params()
if _, err := fmt.Fprintf(w, "\n// %s\n", params.Name); err != nil {
return err
}
cName := strings.Replace(params.Name, "-", "", -1)
writeDecls := func(bits int) error {
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sField", cName), params.P); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sOrder", cName), params.N); err != nil {
return err
}
if includeNonMontgomery {
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sB", cName), params.B); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sGX", cName), params.Gx); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sGY", cName), params.Gy); err != nil {
return err
}
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sFieldR", cName), montgomeryR(params.P, bits)); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sFieldRR", cName), montgomeryRR(params.P, bits)); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sOrderRR", cName), montgomeryRR(params.N, bits)); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontB", cName), toMontgomery(params.B, params.P, bits)); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontGX", cName), toMontgomery(params.Gx, params.P, bits)); err != nil {
return err
}
if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontGY", cName), toMontgomery(params.Gy, params.P, bits)); err != nil {
return err
}
return nil
}
if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint64_t k%sFieldN0 = 0x%016x;\n", cName, montgomeryN0(params.P)); err != nil {
return err
}
if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint64_t k%sOrderN0 = 0x%016x;\n", cName, montgomeryN0(params.N)); err != nil {
return err
}
if _, err := io.WriteString(w, "#if defined(OPENSSL_64_BIT)\n"); err != nil {
return err
}
if err := writeDecls(64); err != nil {
return err
}
if _, err := io.WriteString(w, "#elif defined(OPENSSL_32_BIT)\n"); err != nil {
return err
}
if err := writeDecls(32); err != nil {
return err
}
if _, err := io.WriteString(w, "#else\n#error \"unknown word size\"\n#endif\n"); err != nil {
return err
}
return nil
}
func writeP256NistzTable(path string) error {
curve := elliptic.P256()
tables := make([][][2]*big.Int, 0, 37)
@ -49,6 +170,7 @@ func writeP256NistzTable(path string) error {
return err
}
defer f.Close()
w := &columnWriter{w: f}
const fileHeader = `/*
* Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
@ -75,13 +197,13 @@ func writeP256NistzTable(path string) error {
// This file is generated by make_tables.go.
static const alignas(4096) PRECOMP256_ROW ecp_nistz256_precomputed[37] = `
if _, err := f.WriteString(fileHeader); err != nil {
if _, err := io.WriteString(w, fileHeader); err != nil {
return err
}
if err := writeTables(f, curve, tables, true, 4, writeBNMont); err != nil {
if err := writeTables(w, curve, tables, writeBNMont); err != nil {
return err
}
if _, err := f.WriteString(";\n"); err != nil {
if _, err := io.WriteString(w, ";\n"); err != nil {
return err
}
@ -100,6 +222,7 @@ func writeP256Table(path string) error {
return err
}
defer f.Close()
w := &columnWriter{w: f}
const fileHeader = `/* Copyright (c) 2020, Google Inc.
*
@ -155,19 +278,19 @@ func writeP256Table(path string) error {
// fiat_p256_g_pre_comp is the table of precomputed base points
#if defined(OPENSSL_64_BIT)
static const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = `
if _, err := f.WriteString(fileHeader); err != nil {
if _, err := io.WriteString(w, fileHeader); err != nil {
return err
}
if err := writeTables(f, curve, tables, true, 4, writeU64Mont); err != nil {
if err := writeTables(w, curve, tables, writeU64Mont); err != nil {
return err
}
if _, err := f.WriteString(";\n#else\nstatic const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = "); err != nil {
if _, err := io.WriteString(w, ";\n#else\nstatic const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = "); err != nil {
return err
}
if err := writeTables(f, curve, tables, true, 4, writeU32Mont); err != nil {
if err := writeTables(w, curve, tables, writeU32Mont); err != nil {
return err
}
if _, err := f.WriteString(";\n#endif\n"); err != nil {
if _, err := io.WriteString(w, ";\n#endif\n"); err != nil {
return err
}
@ -223,20 +346,38 @@ func makeComb(curve elliptic.Curve, stride, size, shift int) [][2]*big.Int {
return ret
}
// toMontgomery sets n to be n×R mod p, where R is the Montgomery factor.
func toMontgomery(curve elliptic.Curve, n *big.Int) *big.Int {
params := curve.Params()
func montgomeryR(p *big.Int, wordSize int) *big.Int {
// R is the bit width of p, rounded up to word size.
rounded64 := 64 * ((params.BitSize + 63) / 64)
rounded32 := 32 * ((params.BitSize + 31) / 32)
if rounded64 != rounded32 {
panic(fmt.Sprintf("Montgomery form for %s is inconsistent between 32-bit and 64-bit", params.Name))
}
rounded := wordSize * ((p.BitLen() + wordSize - 1) / wordSize)
R := new(big.Int).SetInt64(1)
R.Lsh(R, uint(rounded64))
R.Lsh(R, uint(rounded))
R.Mod(R, p)
return R
}
func montgomeryRR(p *big.Int, wordSize int) *big.Int {
R := montgomeryR(p, wordSize)
R.Mul(R, R)
R.Mod(R, p)
return R
}
ret := new(big.Int).Mul(n, R)
ret.Mod(ret, params.P)
func montgomeryN0(p *big.Int) uint64 {
two64 := new(big.Int)
two64 = two64.SetBit(two64, 64, 1)
n0 := new(big.Int).Neg(p)
n0 = n0.ModInverse(n0, two64)
if !n0.IsUint64() {
panic("n0 should fit in uint64")
}
return n0.Uint64()
}
// toMontgomery returns n×R mod p, where R is the Montgomery factor.
func toMontgomery(n, p *big.Int, wordSize int) *big.Int {
ret := montgomeryR(p, wordSize)
ret.Mul(ret, n)
ret.Mod(ret, p)
return ret
}
@ -251,17 +392,35 @@ func bigIntToU64s(curve elliptic.Curve, n *big.Int) []uint64 {
return ret
}
func bigIntToU32s(curve elliptic.Curve, n *big.Int) []uint64 {
func bigIntToU32s(curve elliptic.Curve, n *big.Int) []uint32 {
words := (curve.Params().BitSize + 31) / 32
ret := make([]uint64, words)
ret := make([]uint32, words)
bytes := n.Bytes()
for i, b := range bytes {
i = len(bytes) - i - 1
ret[i/4] |= uint64(b) << (8 * (i % 4))
ret[i/4] |= uint32(b) << (8 * (i % 4))
}
return ret
}
// A columnWriter is an io.Writer that tracks the number of columns in the
// current line.
type columnWriter struct {
w io.Writer
column int
}
func (c *columnWriter) Write(p []byte) (n int, err error) {
n, err = c.w.Write(p)
idx := bytes.LastIndexByte(p[:n], '\n')
if idx < 0 {
c.column += n
} else {
c.column = n - idx - 1
}
return
}
func writeIndent(w io.Writer, indent int) error {
for i := 0; i < indent; i++ {
if _, err := io.WriteString(w, " "); err != nil {
@ -271,17 +430,29 @@ func writeIndent(w io.Writer, indent int) error {
return nil
}
func writeWords(w io.Writer, words []uint64, wrap, indent int, format func(uint64) string) error {
func writeWordsBraced[Word any](w *columnWriter, words []Word, format func(Word) string) error {
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
if err := writeWords(w, words, format); err != nil {
return err
}
if _, err := io.WriteString(w, "}"); err != nil {
return err
}
return nil
}
func writeWords[Word any](w *columnWriter, words []Word, format func(Word) string) error {
indent := w.column
for i, word := range words {
str := format(word)
if i > 0 {
if i%wrap == 0 {
if w.column+1+len(str) > 80 {
if _, err := io.WriteString(w, ",\n"); err != nil {
return err
}
if err := writeIndent(w, indent+1); err != nil {
if err := writeIndent(w, indent); err != nil {
return err
}
} else {
@ -290,56 +461,72 @@ func writeWords(w io.Writer, words []uint64, wrap, indent int, format func(uint6
}
}
}
if _, err := io.WriteString(w, format(word)); err != nil {
if _, err := io.WriteString(w, str); err != nil {
return err
}
}
if _, err := io.WriteString(w, "}"); err != nil {
return nil
}
func writeDecl(w *columnWriter, curve elliptic.Curve, bits int, decl string, n *big.Int) error {
if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint%d_t %s[] = {\n ", bits, decl); err != nil {
return err
}
if bits == 32 {
if err := writeWords(w, bigIntToU32s(curve, n), formatU32); err != nil {
return err
}
} else if bits == 64 {
if err := writeWords(w, bigIntToU64s(curve, n), formatU64); err != nil {
return err
}
} else {
panic("unknown bit count")
}
if _, err := fmt.Fprintf(w, "};\n"); err != nil {
return err
}
return nil
}
func writeBNMont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
n = toMontgomery(curve, n)
return writeWords(w, bigIntToU64s(curve, n), 2, indent, func(word uint64) string {
return fmt.Sprintf("TOBN(0x%08x, 0x%08x)", uint32(word>>32), uint32(word))
})
func formatBN(word uint64) string {
return fmt.Sprintf("TOBN(0x%08x, 0x%08x)", uint32(word>>32), uint32(word))
}
func writeU64Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
n = toMontgomery(curve, n)
return writeWords(w, bigIntToU64s(curve, n), 3, indent, func(word uint64) string {
return fmt.Sprintf("0x%016x", word)
})
func formatU64(word uint64) string {
return fmt.Sprintf("0x%016x", word)
}
func writeU32Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
n = toMontgomery(curve, n)
return writeWords(w, bigIntToU32s(curve, n), 6, indent, func(word uint64) string {
if word >= 1<<32 {
panic(fmt.Sprintf("word too large: 0x%x", word))
}
return fmt.Sprintf("0x%08x", word)
})
func formatU32(word uint32) string {
return fmt.Sprintf("0x%08x", word)
}
func writeBNMont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
n32 := toMontgomery(n, curve.Params().P, 32)
n64 := toMontgomery(n, curve.Params().P, 64)
if n32.Cmp(n64) != 0 {
panic(fmt.Sprintf("Montgomery form for %s is inconsistent between 32-bit and 64-bit", curve.Params().Name))
}
return writeWordsBraced(w, bigIntToU64s(curve, n64), formatBN)
}
type writeBigIntFunc func(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error
func writeU64Mont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
n = toMontgomery(n, curve.Params().P, 64)
return writeWordsBraced(w, bigIntToU64s(curve, n), formatU64)
}
func writeU32Mont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
n = toMontgomery(n, curve.Params().P, 32)
return writeWordsBraced(w, bigIntToU32s(curve, n), formatU32)
}
func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
type writeBigIntFunc func(w *columnWriter, curve elliptic.Curve, n *big.Int) error
func writeTable(w *columnWriter, curve elliptic.Curve, table [][2]*big.Int, writeBigInt writeBigIntFunc) error {
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
if isRoot {
if _, err := io.WriteString(w, "\n"); err != nil {
return err
}
if err := writeIndent(w, indent); err != nil {
return err
}
} else {
indent++
}
indent := w.column
for i, point := range table {
if i != 0 {
if _, err := io.WriteString(w, ",\n"); err != nil {
@ -352,7 +539,7 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
if err := writeBigInt(w, curve, point[0], indent+1); err != nil {
if err := writeBigInt(w, curve, point[0]); err != nil {
return err
}
if _, err := io.WriteString(w, ",\n"); err != nil {
@ -361,7 +548,7 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
if err := writeIndent(w, indent+1); err != nil {
return err
}
if err := writeBigInt(w, curve, point[1], indent+1); err != nil {
if err := writeBigInt(w, curve, point[1]); err != nil {
return err
}
if _, err := io.WriteString(w, "}"); err != nil {
@ -374,20 +561,11 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
return nil
}
func writeTables(w io.Writer, curve elliptic.Curve, tables [][][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
if _, err := io.WriteString(w, "{"); err != nil {
func writeTables(w *columnWriter, curve elliptic.Curve, tables [][][2]*big.Int, writeBigInt writeBigIntFunc) error {
if _, err := io.WriteString(w, "{\n "); err != nil {
return err
}
if isRoot {
if _, err := io.WriteString(w, "\n"); err != nil {
return err
}
if err := writeIndent(w, indent); err != nil {
return err
}
} else {
indent++
}
indent := w.column
for i, table := range tables {
if i != 0 {
if _, err := io.WriteString(w, ",\n"); err != nil {
@ -397,7 +575,7 @@ func writeTables(w io.Writer, curve elliptic.Curve, tables [][][2]*big.Int, isRo
return err
}
}
if err := writeTable(w, curve, table, false, indent, writeBigInt); err != nil {
if err := writeTable(w, curve, table, writeBigInt); err != nil {
return err
}
}

@ -101,8 +101,24 @@ typedef enum {
// Elliptic curve groups.
// EC_GROUP_new_by_curve_name returns a fresh EC_GROUP object for the elliptic
// curve specified by |nid|, or NULL on unsupported NID or allocation failure.
// EC_group_p224 returns an |EC_GROUP| for P-224, also known as secp224r1.
OPENSSL_EXPORT const EC_GROUP *EC_group_p224(void);
// EC_group_p256 returns an |EC_GROUP| for P-256, also known as secp256r1 or
// prime256v1.
OPENSSL_EXPORT const EC_GROUP *EC_group_p256(void);
// EC_group_p384 returns an |EC_GROUP| for P-384, also known as secp384r1.
OPENSSL_EXPORT const EC_GROUP *EC_group_p384(void);
// EC_group_p521 returns an |EC_GROUP| for P-521, also known as secp521r1.
OPENSSL_EXPORT const EC_GROUP *EC_group_p521(void);
// EC_GROUP_new_by_curve_name returns the |EC_GROUP| object for the elliptic
// curve specified by |nid|, or NULL on unsupported NID. For OpenSSL
// compatibility, this function returns a non-const pointer which may be passed
// to |EC_GROUP_free|. However, the resulting object is actually static and
// calling |EC_GROUP_free| is optional.
//
// The supported NIDs are:
// NID_secp224r1 (P-224),
@ -110,6 +126,9 @@ typedef enum {
// NID_secp384r1 (P-384),
// NID_secp521r1 (P-521)
//
// Calling this function causes all four curves to be linked into the binary.
// Prefer calling |EC_group_*| to allow the static linker to drop unused curves.
//
// If in doubt, use |NID_X9_62_prime256v1|, or see the curve25519.h header for
// more modern primitives.
OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_by_curve_name(int nid);

@ -259,8 +259,15 @@ OPENSSL_EXPORT int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
unsigned enc_flags);
// EC_KEY_parse_curve_name parses a DER-encoded OBJECT IDENTIFIER as a curve
// name from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP|
// or NULL on error.
// name from |cbs| and advances |cbs|. It returns the decoded |EC_GROUP| or NULL
// on error.
//
// This function returns a non-const pointer which may be passed to
// |EC_GROUP_free|. However, the resulting object is actually static and calling
// |EC_GROUP_free| is optional.
//
// TODO(davidben): Make this return a const pointer, if it does not break too
// many callers.
OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs);
// EC_KEY_marshal_curve_name marshals |group| as a DER-encoded OBJECT IDENTIFIER
@ -269,10 +276,16 @@ OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs);
OPENSSL_EXPORT int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group);
// EC_KEY_parse_parameters parses a DER-encoded ECParameters structure (RFC
// 5480) from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP|
// or NULL on error. It supports the namedCurve and specifiedCurve options, but
// use of specifiedCurve is deprecated. Use |EC_KEY_parse_curve_name|
// instead.
// 5480) from |cbs| and advances |cbs|. It returns the resulting |EC_GROUP| or
// NULL on error. It supports the namedCurve and specifiedCurve options, but use
// of specifiedCurve is deprecated. Use |EC_KEY_parse_curve_name| instead.
//
// This function returns a non-const pointer which may be passed to
// |EC_GROUP_free|. However, the resulting object is actually static and calling
// |EC_GROUP_free| is optional.
//
// TODO(davidben): Make this return a const pointer, if it does not break too
// many callers.
OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_parameters(CBS *cbs);

Loading…
Cancel
Save