Commit 37843d65ea for openssl.org

commit 37843d65ea0f3b4eed7c37d1eb591791c0cc01d8
Author: Pauli <paul.dale@oracle.com>
Date:   Tue Aug 25 12:01:49 2026 +1000

    ec: use generated tries in crypto helpers

    Assisted-by: ChatGPT:gpt-5.6Sol

    Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    (Merged from https://github.com/openssl/openssl/pull/32502)

diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c
index a274f720f3..e32055a06c 100644
--- a/crypto/ec/ec_ameth.c
+++ b/crypto/ec/ec_ameth.c
@@ -21,6 +21,7 @@
 #include <openssl/asn1t.h>
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "crypto/ec_params.h"
 #include "crypto/x509.h"
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
@@ -598,15 +599,20 @@ static int ec_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     EVP_PKEY_CTX *pctx = vpctx;
     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
     EC_KEY *ec = EC_KEY_new_ex(pctx->libctx, pctx->propquery);
+    EC_PARAMS p;

     if (ec == NULL) {
         ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
         return 0;
     }
+    if (!ec_pkey_import_from_decoder(params, &p)) {
+        EC_KEY_free(ec);
+        return 0;
+    }

-    if (!ossl_ec_group_fromdata(ec, params)
-        || !ossl_ec_key_otherparams_fromdata(ec, params)
-        || !ossl_ec_key_fromdata(ec, params, 1)
+    if (!ossl_ec_group_fromdata_parsed(ec, &p)
+        || !ossl_ec_key_otherparams_fromdata_parsed(ec, &p)
+        || !ossl_ec_key_fromdata_parsed(ec, &p, 1)
         || !EVP_PKEY_assign_EC_KEY(pkey, ec)) {
         EC_KEY_free(ec);
         return 0;
diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c
index 764ab7558b..4c6302c5b5 100644
--- a/crypto/ec/ec_backend.c
+++ b/crypto/ec/ec_backend.c
@@ -22,6 +22,7 @@
 #endif
 #include "crypto/bn.h"
 #include "crypto/ec.h"
+#include "crypto/ec_params.h"
 #include "ec_local.h"
 #include "internal/e_os.h"
 #include "internal/nelem.h"
@@ -156,15 +157,15 @@ char *ossl_ec_pt_format_id2name(int id)
 }

 static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
-    OSSL_PARAM params[], BN_CTX *bnctx,
+    const EC_PARAMS *params, BN_CTX *bnctx,
     unsigned char **genbuf)
 {
     int ret = 0, fid;
     const char *field_type;
-    const OSSL_PARAM *param = NULL;
-    const OSSL_PARAM *param_p = NULL;
-    const OSSL_PARAM *param_a = NULL;
-    const OSSL_PARAM *param_b = NULL;
+    OSSL_PARAM *param = NULL;
+    OSSL_PARAM *param_p = NULL;
+    OSSL_PARAM *param_a = NULL;
+    OSSL_PARAM *param_b = NULL;

     fid = EC_GROUP_get_field_type(group);

@@ -182,9 +183,11 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
         return 0;
     }

-    param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_P);
-    param_a = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_A);
-    param_b = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_B);
+    if (params != NULL) {
+        param_p = params->p;
+        param_a = params->a;
+        param_b = params->b;
+    }
     if (tmpl != NULL || param_p != NULL || param_a != NULL || param_b != NULL) {
         BIGNUM *p = BN_CTX_get(bnctx);
         BIGNUM *a = BN_CTX_get(bnctx);
@@ -199,15 +202,17 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE);
             goto err;
         }
-        if (!ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_P, p)
-            || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_A, a)
-            || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_B, b)) {
+        if (!ossl_param_build_set_bn(tmpl, param_p, OSSL_PKEY_PARAM_EC_P, p)
+            || !ossl_param_build_set_bn(tmpl, param_a,
+                OSSL_PKEY_PARAM_EC_A, a)
+            || !ossl_param_build_set_bn(tmpl, param_b,
+                OSSL_PKEY_PARAM_EC_B, b)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
             goto err;
         }
     }

-    param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ORDER);
+    param = params == NULL ? NULL : params->order;
     if (tmpl != NULL || param != NULL) {
         const BIGNUM *order = EC_GROUP_get0_order(group);

@@ -215,16 +220,16 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_GROUP_ORDER);
             goto err;
         }
-        if (!ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_ORDER,
+        if (!ossl_param_build_set_bn(tmpl, param, OSSL_PKEY_PARAM_EC_ORDER,
                 order)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
             goto err;
         }
     }

-    param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_FIELD_TYPE);
+    param = params == NULL ? NULL : params->field_type;
     if (tmpl != NULL || param != NULL) {
-        if (!ossl_param_build_set_utf8_string(tmpl, params,
+        if (!ossl_param_build_set_utf8_string(tmpl, param,
                 OSSL_PKEY_PARAM_EC_FIELD_TYPE,
                 field_type)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
@@ -232,7 +237,7 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
         }
     }

-    param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_GENERATOR);
+    param = params == NULL ? NULL : params->generator;
     if (tmpl != NULL || param != NULL) {
         size_t genbuf_len;
         const EC_POINT *genpt = EC_GROUP_get0_generator(group);
@@ -247,7 +252,7 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_GENERATOR);
             goto err;
         }
-        if (!ossl_param_build_set_octet_string(tmpl, params,
+        if (!ossl_param_build_set_octet_string(tmpl, param,
                 OSSL_PKEY_PARAM_EC_GENERATOR,
                 *genbuf, genbuf_len)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
@@ -255,26 +260,26 @@ static int ec_group_explicit_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
         }
     }

-    param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_COFACTOR);
+    param = params == NULL ? NULL : params->cofactor;
     if (tmpl != NULL || param != NULL) {
         const BIGNUM *cofactor = EC_GROUP_get0_cofactor(group);

         if (cofactor != NULL
-            && !ossl_param_build_set_bn(tmpl, params,
+            && !ossl_param_build_set_bn(tmpl, param,
                 OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
             goto err;
         }
     }

-    param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_SEED);
+    param = params == NULL ? NULL : params->seed;
     if (tmpl != NULL || param != NULL) {
         unsigned char *seed = EC_GROUP_get0_seed(group);
         size_t seed_len = EC_GROUP_get_seed_len(group);

         if (seed != NULL
             && seed_len > 0
-            && !ossl_param_build_set_octet_string(tmpl, params,
+            && !ossl_param_build_set_octet_string(tmpl, param,
                 OSSL_PKEY_PARAM_EC_SEED,
                 seed, seed_len)) {
             ERR_raise(ERR_LIB_EC, ERR_R_CRYPTO_LIB);
@@ -286,8 +291,8 @@ err:
     return ret;
 }

-int ossl_ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
-    OSSL_PARAM params[], OSSL_LIB_CTX *libctx,
+int ossl_ec_group_todata_parsed(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
+    const EC_PARAMS *params, OSSL_LIB_CTX *libctx,
     const char *propq,
     BN_CTX *bnctx, unsigned char **genbuf)
 {
@@ -304,7 +309,7 @@ int ossl_ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
     pt_form_name = ossl_ec_pt_format_id2name(genform);
     if (pt_form_name == NULL
         || !ossl_param_build_set_utf8_string(
-            tmpl, params,
+            tmpl, params == NULL ? NULL : params->pt_format,
             OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, pt_form_name)) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM);
         return 0;
@@ -312,14 +317,16 @@ int ossl_ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
     encoding_flag = EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE;
     encoding_name = ec_param_encoding_id2name(encoding_flag);
     if (encoding_name == NULL
-        || !ossl_param_build_set_utf8_string(tmpl, params,
+        || !ossl_param_build_set_utf8_string(tmpl,
+            params == NULL ? NULL : params->encoding,
             OSSL_PKEY_PARAM_EC_ENCODING,
             encoding_name)) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
         return 0;
     }

-    if (!ossl_param_build_set_int(tmpl, params,
+    if (!ossl_param_build_set_int(tmpl,
+            params == NULL ? NULL : params->decoded,
             OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS,
             group->decoded_from_explicit_params))
         return 0;
@@ -340,7 +347,8 @@ int ossl_ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
         const char *curve_name = OSSL_EC_curve_nid2name(curve_nid);

         if (curve_name == NULL
-            || !ossl_param_build_set_utf8_string(tmpl, params,
+            || !ossl_param_build_set_utf8_string(tmpl,
+                params == NULL ? NULL : params->group_name,
                 OSSL_PKEY_PARAM_GROUP_NAME,
                 curve_name)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE);
@@ -352,6 +360,23 @@ err:
     return ret;
 }

+int ossl_ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl,
+    OSSL_PARAM params[], OSSL_LIB_CTX *libctx,
+    const char *propq,
+    BN_CTX *bnctx, unsigned char **genbuf)
+{
+    EC_PARAMS p;
+
+    if (params != NULL) {
+        if (!ec_group_todata_decoder(params, &p))
+            return 0;
+        return ossl_ec_group_todata_parsed(group, tmpl, &p, libctx, propq,
+            bnctx, genbuf);
+    }
+    return ossl_ec_group_todata_parsed(group, tmpl, NULL, libctx, propq,
+        bnctx, genbuf);
+}
+
 /*
  * The intention with the "backend" source file is to offer backend functions
  * for legacy backends (EVP_PKEY_ASN1_METHOD) and provider implementations
@@ -394,7 +419,8 @@ int ossl_ec_set_ecdh_cofactor_mode(EC_KEY *ec, int mode)
  * parameters are treated separately, and domain parameters are required to
  * define a keypair.
  */
-int ossl_ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
+int ossl_ec_key_fromdata_parsed(EC_KEY *ec, const EC_PARAMS *params,
+    int include_private)
 {
     const OSSL_PARAM *param_priv_key = NULL, *param_pub_key = NULL;
     BN_CTX *ctx = NULL;
@@ -409,9 +435,12 @@ int ossl_ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_priv
     if (ecg == NULL)
         return 0;

-    param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+    if (params == NULL)
+        return 0;
+
+    param_pub_key = params->pub;
     if (include_private)
-        param_priv_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+        param_priv_key = params->priv;

     ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec));
     if (ctx == NULL)
@@ -504,7 +533,17 @@ err:
     return ok;
 }

-int ossl_ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+int ossl_ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[],
+    int include_private)
+{
+    EC_PARAMS p;
+
+    if (!ec_key_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_ec_key_fromdata_parsed(ec, &p, include_private);
+}
+
+int ossl_ec_group_fromdata_parsed(EC_KEY *ec, const EC_PARAMS *params)
 {
     int ok = 0;
     EC_GROUP *group = NULL;
@@ -512,7 +551,8 @@ int ossl_ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
     if (ec == NULL)
         return 0;

-    group = EC_GROUP_new_from_params(params, ossl_ec_key_get_libctx(ec),
+    group = ossl_ec_group_new_from_params_parsed(params,
+        ossl_ec_key_get_libctx(ec),
         ossl_ec_key_get0_propq(ec));

     if (!EC_KEY_set_group(ec, group))
@@ -523,14 +563,21 @@ err:
     return ok;
 }

-static int ec_key_point_format_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+int ossl_ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+{
+    EC_PARAMS p;
+
+    if (!ec_group_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_ec_group_fromdata_parsed(ec, &p);
+}
+
+static int ec_key_point_format_fromdata(EC_KEY *ec, const EC_PARAMS *params)
 {
-    const OSSL_PARAM *p;
     int format = -1;

-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT);
-    if (p != NULL) {
-        if (!ossl_ec_pt_format_param2id(p, &format)) {
+    if (params->pt_format != NULL) {
+        if (!ossl_ec_pt_format_param2id(params->pt_format, &format)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM);
             return 0;
         }
@@ -539,13 +586,10 @@ static int ec_key_point_format_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
     return 1;
 }

-static int ec_key_group_check_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+static int ec_key_group_check_fromdata(EC_KEY *ec, const EC_PARAMS *params)
 {
-    const OSSL_PARAM *p;
-
-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE);
-    if (p != NULL)
-        return ec_set_check_group_type_from_param(ec, p);
+    if (params->group_check != NULL)
+        return ec_set_check_group_type_from_param(ec, params->group_check);
     return 1;
 }

@@ -561,27 +605,24 @@ static int ec_set_include_public(EC_KEY *ec, int include)
     return 1;
 }

-int ossl_ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+int ossl_ec_key_otherparams_fromdata_parsed(EC_KEY *ec,
+    const EC_PARAMS *params)
 {
-    const OSSL_PARAM *p;
-
-    if (ec == NULL)
+    if (ec == NULL || params == NULL)
         return 0;

-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH);
-    if (p != NULL) {
+    if (params->use_cofactor != NULL) {
         int mode;

-        if (!OSSL_PARAM_get_int(p, &mode)
+        if (!OSSL_PARAM_get_int(params->use_cofactor, &mode)
             || !ossl_ec_set_ecdh_cofactor_mode(ec, mode))
             return 0;
     }

-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC);
-    if (p != NULL) {
+    if (params->include_public != NULL) {
         int include = 1;

-        if (!OSSL_PARAM_get_int(p, &include)
+        if (!OSSL_PARAM_get_int(params->include_public, &include)
             || !ec_set_include_public(ec, include))
             return 0;
     }
@@ -592,6 +633,15 @@ int ossl_ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
     return 1;
 }

+int ossl_ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[])
+{
+    EC_PARAMS p;
+
+    if (!ec_key_otherparams_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_ec_key_otherparams_fromdata_parsed(ec, &p);
+}
+
 int ossl_ec_key_is_foreign(const EC_KEY *ec)
 {
 #ifndef FIPS_MODULE
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index 51f0457f65..74d0a1da56 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -21,6 +21,7 @@
 #include <openssl/opensslv.h>
 #include <openssl/param_build.h>
 #include "crypto/ec.h"
+#include "crypto/ec_params.h"
 #include "crypto/bn.h"
 #include "internal/nelem.h"
 #include "ec_local.h"
@@ -1548,34 +1549,34 @@ static EC_GROUP *group_new_from_name(const OSSL_PARAM *p,
 }

 /* These parameters can be set directly into an EC_GROUP */
-int ossl_ec_group_set_params(EC_GROUP *group, const OSSL_PARAM params[])
+int ossl_ec_group_set_params_parsed(EC_GROUP *group, const EC_PARAMS *params)
 {
     int encoding_flag = -1, format = -1;
-    const OSSL_PARAM *p;

-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT);
-    if (p != NULL) {
-        if (!ossl_ec_pt_format_param2id(p, &format)) {
+    if (params == NULL)
+        return 0;
+
+    if (params->pt_format != NULL) {
+        if (!ossl_ec_pt_format_param2id(params->pt_format, &format)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM);
             return 0;
         }
         EC_GROUP_set_point_conversion_form(group, format);
     }

-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ENCODING);
-    if (p != NULL) {
-        if (!ossl_ec_encoding_param2id(p, &encoding_flag)) {
+    if (params->encoding != NULL) {
+        if (!ossl_ec_encoding_param2id(params->encoding, &encoding_flag)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_FORM);
             return 0;
         }
         EC_GROUP_set_asn1_flag(group, encoding_flag);
     }
     /* Optional seed */
-    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_SEED);
-    if (p != NULL) {
+    if (params->seed != NULL) {
         /* The seed is allowed to be NULL */
-        if (p->data_type != OSSL_PARAM_OCTET_STRING
-            || !EC_GROUP_set_seed(group, p->data, p->data_size)) {
+        if (params->seed->data_type != OSSL_PARAM_OCTET_STRING
+            || !EC_GROUP_set_seed(group, params->seed->data,
+                params->seed->data_size)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_SEED);
             return 0;
         }
@@ -1583,7 +1584,16 @@ int ossl_ec_group_set_params(EC_GROUP *group, const OSSL_PARAM params[])
     return 1;
 }

-EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
+int ossl_ec_group_set_params(EC_GROUP *group, const OSSL_PARAM params[])
+{
+    EC_PARAMS p;
+
+    if (!ec_group_fromdata_decoder(params, &p))
+        return 0;
+    return ossl_ec_group_set_params_parsed(group, &p);
+}
+
+EC_GROUP *ossl_ec_group_new_from_params_parsed(const EC_PARAMS *params,
     OSSL_LIB_CTX *libctx, const char *propq)
 {
     const OSSL_PARAM *ptmp;
@@ -1605,19 +1615,21 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
 #endif

     /* This is the simple named group case */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
+    if (params == NULL)
+        return NULL;
+
+    ptmp = params->group_name;
     if (ptmp != NULL) {
         int decoded = 0;

         if ((group = group_new_from_name(ptmp, libctx, propq)) == NULL)
             return NULL;
-        if (!ossl_ec_group_set_params(group, params)) {
+        if (!ossl_ec_group_set_params_parsed(group, params)) {
             EC_GROUP_free(group);
             return NULL;
         }

-        ptmp = OSSL_PARAM_locate_const(params,
-            OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAMS);
+        ptmp = params->decoded;
         if (ptmp != NULL && !OSSL_PARAM_get_int(ptmp, &decoded)) {
             ERR_raise(ERR_LIB_EC, EC_R_WRONG_CURVE_PARAMETERS);
             EC_GROUP_free(group);
@@ -1647,7 +1659,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
         goto err;
     }

-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_FIELD_TYPE);
+    ptmp = params->field_type;
     if (ptmp == NULL || ptmp->data_type != OSSL_PARAM_UTF8_STRING) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_FIELD);
         goto err;
@@ -1664,19 +1676,19 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
         goto err;
     }

-    pa = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_A);
+    pa = params->a;
     if (!OSSL_PARAM_get_BN(pa, &a)) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_A);
         goto err;
     }
-    pb = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_B);
+    pb = params->b;
     if (!OSSL_PARAM_get_BN(pb, &b)) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_B);
         goto err;
     }

     /* extract the prime number or irreducible polynomial */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_P);
+    ptmp = params->p;
     if (!OSSL_PARAM_get_BN(ptmp, &p)) {
         ERR_raise(ERR_LIB_EC, EC_R_INVALID_P);
         goto err;
@@ -1718,7 +1730,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
     }

     /* Optional seed */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_SEED);
+    ptmp = params->seed;
     if (ptmp != NULL) {
         if (ptmp->data_type != OSSL_PARAM_OCTET_STRING) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_SEED);
@@ -1729,7 +1741,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
     }

     /* generator base point */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_GENERATOR);
+    ptmp = params->generator;
     if (ptmp == NULL
         || ptmp->data_type != OSSL_PARAM_OCTET_STRING
         || ptmp->data_size == 0) {
@@ -1747,7 +1759,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
     }

     /* order */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ORDER);
+    ptmp = params->order;
     if (!OSSL_PARAM_get_BN(ptmp, &order)
         || (BN_is_negative(order) || BN_is_zero(order))
         || (BN_num_bits(order) > (int)field_bits + 1)) { /* Hasse bound */
@@ -1756,7 +1768,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
     }

     /* Optional cofactor */
-    ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_COFACTOR);
+    ptmp = params->cofactor;
     if (ptmp != NULL) {
         cofactor = BN_CTX_get(bnctx);
         if (cofactor == NULL || !OSSL_PARAM_get_BN(ptmp, &cofactor)) {
@@ -1787,7 +1799,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
          * If we did not find a named group then the encoding should be explicit
          * if it was specified
          */
-        ptmp = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_EC_ENCODING);
+        ptmp = params->encoding;
         if (ptmp != NULL
             && !ossl_ec_encoding_param2id(ptmp, &encoding_flag)) {
             ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING);
@@ -1819,6 +1831,16 @@ err:
 #endif /* FIPS_MODULE */
 }

+EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
+    OSSL_LIB_CTX *libctx, const char *propq)
+{
+    EC_PARAMS p;
+
+    if (!ec_group_fromdata_decoder(params, &p))
+        return NULL;
+    return ossl_ec_group_new_from_params_parsed(&p, libctx, propq);
+}
+
 OSSL_PARAM *EC_GROUP_to_params(const EC_GROUP *group, OSSL_LIB_CTX *libctx,
     const char *propq, BN_CTX *bnctx)
 {