*Alexander Kanavin*
+ * ECC groups may now customize their initialization to save CPU by using
+ precomputed values. This is used by the P-256 implementation.
+
+ *Watson Ladd*
+
OpenSSL 3.3
-----------
CRYPTO_THREAD_unlock(lock);
return ret;
}
+
+int ossl_bn_mont_ctx_set(BN_MONT_CTX *ctx, const BIGNUM *modulus, int ri, const unsigned char *rr,
+ size_t rrlen, uint32_t nlo, uint32_t nhi)
+{
+ if (BN_copy(&ctx->N, modulus) == NULL)
+ return 0;
+ if (BN_bin2bn(rr, rrlen, &ctx->RR) == NULL)
+ return 0;
+ ctx->ri = ri;
+#if (BN_BITS2 <= 32) && defined(OPENSSL_BN_ASM_MONT)
+ ctx->n0[0] = nlo;
+ ctx->n0[1] = nhi;
+#elif BN_BITS2 <= 32
+ ctx->n0[0] = nlo;
+ ctx->n0[1] = 0;
+#else
+ ctx->n0[0] = ((BN_ULONG)nhi << 32)| nlo;
+ ctx->n0[1] = 0;
+#endif
+
+ return 1;
+}
+
+int ossl_bn_mont_ctx_eq(const BN_MONT_CTX *m1, const BN_MONT_CTX *m2)
+{
+ if (m1->ri != m2->ri)
+ return 0;
+ if (BN_cmp(&m1->RR, &m2->RR) != 0)
+ return 0;
+ if (m1->flags != m2->flags)
+ return 0;
+#ifdef MONT_WORD
+ if (m1->n0[0] != m2->n0[0])
+ return 0;
+ if (m1->n0[1] != m2->n0[1])
+ return 0;
+#else
+ if (BN_cmp(&m1->Ni, &m2->Ni) != 0)
+ return 0;
+#endif
+ return 1;
+}
static const struct {
EC_CURVE_DATA h;
- unsigned char data[20 + 32 * 6];
+ unsigned char data[20 + 32 * 8];
} _EC_X9_62_PRIME_256V1 = {
{
NID_X9_62_prime_field, 20, 32, 1
/* 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
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51,
+ /* RR for prime */
+ 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ /* RR for order */
+ 0x66, 0xe1, 0x2d, 0x94, 0xf3, 0xd9, 0x56, 0x20, 0x28, 0x45, 0xb2, 0x39,
+ 0x2b, 0x6b, 0xec, 0x59, 0x46, 0x99, 0x79, 0x9c, 0x49, 0xbd, 0x6f, 0xa6,
+ 0x83, 0x24, 0x4c, 0x95, 0xbe, 0x79, 0xee, 0xa2
}
};
seed_len = data->seed_len;
param_len = data->param_len;
params = (const unsigned char *)(data + 1); /* skip header */
+
+ if (curve.meth != NULL) {
+ meth = curve.meth();
+ if ((group = ossl_ec_group_new_ex(libctx, propq, meth)) == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (group->meth->group_full_init != NULL) {
+ if (!group->meth->group_full_init(group, params)){
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+ EC_GROUP_set_curve_name(group, curve.nid);
+ BN_CTX_free(ctx);
+ return group;
+ }
+ }
+
params += seed_len; /* skip seed */
if ((p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) == NULL
goto err;
}
- if (curve.meth != 0) {
- meth = curve.meth();
- if (((group = ossl_ec_group_new_ex(libctx, propq, meth)) == NULL) ||
- (!(group->meth->group_set_curve(group, p, a, b, ctx)))) {
+ if (group != NULL) {
+ if (group->meth->group_set_curve(group, p, a, b, ctx) == 0) {
ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
goto err;
}
int (*ladder_post)(const EC_GROUP *group,
EC_POINT *r, EC_POINT *s,
EC_POINT *p, BN_CTX *ctx);
+ int (*group_full_init)(EC_GROUP *group, const unsigned char *data);
};
/*
# define ecp_nistz256_inv_mod_ord NULL
#endif
+static int ecp_nistz256group_full_init(EC_GROUP *group,
+ const unsigned char *params) {
+ BN_CTX *ctx = NULL;
+ BN_MONT_CTX *mont = NULL, *ordmont = NULL;
+ const int param_len = 32;
+ const int seed_len = 20;
+ int ok = 0;
+ uint32_t hi_order_n = 0xccd1c8aa;
+ uint32_t lo_order_n = 0xee00bc4f;
+ BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL, *one = NULL,
+ *order = NULL;
+ EC_POINT *P = NULL;
+
+ if ((ctx = BN_CTX_new_ex(group->libctx)) == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!EC_GROUP_set_seed(group, params, seed_len)) {
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+ params += seed_len;
+
+ if ((p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) == NULL
+ || (a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) == NULL
+ || (b = BN_bin2bn(params + 2 * param_len, param_len, NULL)) == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ /*
+ * Set up curve params and montgomery for field
+ * Start by setting up montgomery and one
+ */
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL)
+ goto err;
+
+ if (!ossl_bn_mont_ctx_set(mont, p, 256, params + 6 * param_len, param_len,
+ 1, 0))
+ goto err;
+
+ one = BN_new();
+ if (one == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
+ goto err;
+ }
+ if (!BN_to_montgomery(one, BN_value_one(), mont, ctx)){
+ ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
+ goto err;
+ }
+ group->field_data1 = mont;
+ mont = NULL;
+ group->field_data2 = one;
+ one = NULL;
+
+ if (!ossl_ec_GFp_simple_group_set_curve(group, p, a, b, ctx)) {
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((P = EC_POINT_new(group)) == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ if ((x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) == NULL
+ || (y = BN_bin2bn(params + 4 * param_len, param_len, NULL)) == NULL) {
+ ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
+ goto err;
+ }
+ if (!EC_POINT_set_affine_coordinates(group, P, x, y, ctx)) {
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+ if ((order = BN_bin2bn(params + 5 * param_len, param_len, NULL)) == NULL
+ || !BN_set_word(x, (BN_ULONG)1)) { // cofactor is 1
+ ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ /*
+ * Set up generator and order and montgomery data
+ */
+ group->generator = EC_POINT_new(group);
+ if (group->generator == NULL){
+ ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (!EC_POINT_copy(group->generator, P))
+ goto err;
+ if (!BN_copy(group->order, order))
+ goto err;
+ if (!BN_set_word(group->cofactor, 1))
+ goto err;
+
+ ordmont = BN_MONT_CTX_new();
+ if (ordmont == NULL)
+ goto err;
+ if (!ossl_bn_mont_ctx_set(ordmont, order, 256, params + 7 * param_len,
+ param_len, lo_order_n, hi_order_n))
+ goto err;
+
+ group->mont_data = ordmont;
+ ordmont = NULL;
+
+ ok = 1;
+
+ err:
+ EC_POINT_free(P);
+ BN_CTX_free(ctx);
+ BN_MONT_CTX_free(mont);
+ BN_MONT_CTX_free(ordmont);
+ BN_free(p);
+ BN_free(one);
+ BN_free(a);
+ BN_free(b);
+ BN_free(order);
+ BN_free(x);
+ BN_free(y);
+
+ return ok;
+}
+
const EC_METHOD *EC_GFp_nistz256_method(void)
{
static const EC_METHOD ret = {
0, /* blind_coordinates */
0, /* ladder_pre */
0, /* ladder_step */
- 0 /* ladder_post */
+ 0, /* ladder_post */
+ ecp_nistz256group_full_init
};
return &ret;
const BIGNUM *dmp, const BIGNUM *dmq, const BIGNUM *iqmp);
#endif
+
+int ossl_bn_mont_ctx_set(BN_MONT_CTX *ctx, const BIGNUM *modulus, int ri,
+ const unsigned char *rr, size_t rrlen,
+ uint32_t nlo, uint32_t nhi);
+
+int ossl_bn_mont_ctx_eq(const BN_MONT_CTX *m1, const BN_MONT_CTX *m2);
#include "testutil.h"
#include <openssl/ec.h>
#include "ec_local.h"
+#include <crypto/bn.h>
#include <openssl/objects.h>
static size_t crv_len = 0;
return testresult;
}
+
+static int check_bn_mont_ctx(BN_MONT_CTX *mont, BIGNUM *mod, BN_CTX *ctx)
+{
+ int ret = 0;
+ BN_MONT_CTX *regenerated = BN_MONT_CTX_new();
+
+ if (!TEST_ptr(regenerated))
+ return ret;
+ if (!TEST_ptr(mont))
+ goto err;
+
+ if (!TEST_true(BN_MONT_CTX_set(regenerated, mod, ctx)))
+ goto err;
+
+ if (!TEST_true(ossl_bn_mont_ctx_eq(regenerated, mont)))
+ goto err;
+
+ ret = 1;
+
+ err:
+ BN_MONT_CTX_free(regenerated);
+ return ret;
+}
+
+static int montgomery_correctness_test(EC_GROUP *group)
+{
+ int ret = 0;
+ BN_CTX *ctx = NULL;
+
+ ctx = BN_CTX_new();
+ if (!TEST_ptr(ctx))
+ return ret;
+ if (!TEST_true(check_bn_mont_ctx(group->mont_data, group->order, ctx))) {
+ TEST_error("group order issue");
+ goto err;
+ }
+ if (group->field_data1 != NULL) {
+ if (!TEST_true(check_bn_mont_ctx(group->field_data1, group->field, ctx)))
+ goto err;
+ }
+ ret = 1;
+ err:
+ BN_CTX_free(ctx);
+ return ret;
+}
+
+static int named_group_creation_test(void)
+{
+ int ret = 0;
+ EC_GROUP *group = NULL;
+
+ if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1))
+ || !TEST_true(montgomery_correctness_test(group)))
+ goto err;
+
+ ret = 1;
+
+ err:
+ EC_GROUP_free(group);
+ return ret;
+}
+
int setup_tests(void)
{
crv_len = EC_get_builtin_curves(NULL, 0);
ADD_TEST(set_private_key);
ADD_TEST(decoded_flag_test);
ADD_ALL_TESTS(ecpkparams_i2d2i_test, crv_len);
+ ADD_TEST(named_group_creation_test);
return 1;
}