@@ -3668,8 +3668,40 @@ bool ECKeyPointer::setPublicKey(const ECPointPointer& pub) {
36683668bool ECKeyPointer::setPublicKeyRaw (const BignumPointer& x,
36693669 const BignumPointer& y) {
36703670 if (!key_) return false ;
3671- return EC_KEY_set_public_key_affine_coordinates (
3672- key_.get (), x.get (), y.get ()) == 1 ;
3671+ const EC_GROUP* group = EC_KEY_get0_group (key_.get ());
3672+ if (group == nullptr ) return false ;
3673+
3674+ // For curves with cofactor h=1, use EC_POINT_oct2point +
3675+ // EC_KEY_set_public_key instead of
3676+ // EC_KEY_set_public_key_affine_coordinates.
3677+ // The latter internally calls EC_KEY_check_key() which performs a scalar
3678+ // multiplication (n*Q) for order validation — redundant when h=1 since every
3679+ // on-curve point already has order n. EC_POINT_oct2point validates the point
3680+ // is on the curve, which is sufficient. For curves with h!=1, fall back to
3681+ // the full check.
3682+ auto cofactor = BignumPointer::New ();
3683+ if (!cofactor || !EC_GROUP_get_cofactor (group, cofactor.get (), nullptr ) ||
3684+ !cofactor.isOne ()) {
3685+ return EC_KEY_set_public_key_affine_coordinates (
3686+ key_.get (), x.get (), y.get ()) == 1 ;
3687+ }
3688+
3689+ // Field element byte length: ceil(degree_bits / 8).
3690+ size_t field_len = (EC_GROUP_get_degree (group) + 7 ) / 8 ;
3691+
3692+ // Build an uncompressed point: 0x04 || x || y, each padded to field_len.
3693+ size_t uncompressed_len = 1 + 2 * field_len;
3694+ auto buf = DataPointer::Alloc (uncompressed_len);
3695+ if (!buf) return false ;
3696+ unsigned char * ptr = static_cast <unsigned char *>(buf.get ());
3697+ ptr[0 ] = POINT_CONVERSION_UNCOMPRESSED;
3698+ x.encodePaddedInto (ptr + 1 , field_len);
3699+ y.encodePaddedInto (ptr + 1 + field_len, field_len);
3700+
3701+ auto point = ECPointPointer::New (group);
3702+ if (!point) return false ;
3703+ if (!point.setFromBuffer ({ptr, uncompressed_len}, group)) return false ;
3704+ return EC_KEY_set_public_key (key_.get (), point.get ()) == 1 ;
36733705}
36743706
36753707bool ECKeyPointer::setPrivateKey (const BignumPointer& priv) {
@@ -3930,6 +3962,35 @@ bool EVPKeyCtxPointer::setSignatureMd(const EVPMDCtxPointer& md) {
39303962 1 ;
39313963}
39323964
3965+ bool EVPKeyCtxPointer::setSignatureMd (const Digest& md) {
3966+ if (!ctx_ || !md) return false ;
3967+ return EVP_PKEY_CTX_set_signature_md (ctx_.get (), md.get ()) == 1 ;
3968+ }
3969+
3970+ #if OPENSSL_VERSION_MAJOR >= 3
3971+ int EVPKeyCtxPointer::initForSignEx (const OSSL_PARAM params[]) {
3972+ if (!ctx_) return 0 ;
3973+ return EVP_PKEY_sign_init_ex (ctx_.get (), params);
3974+ }
3975+
3976+ int EVPKeyCtxPointer::initForVerifyEx (const OSSL_PARAM params[]) {
3977+ if (!ctx_) return 0 ;
3978+ return EVP_PKEY_verify_init_ex (ctx_.get (), params);
3979+ }
3980+ #endif
3981+
3982+ #ifdef OSSL_SIGNATURE_PARAM_MU
3983+ int EVPKeyCtxPointer::initForSignMessage (const OSSL_PARAM params[]) {
3984+ if (!ctx_) return 0 ;
3985+ return EVP_PKEY_sign_message_init (ctx_.get (), nullptr , params);
3986+ }
3987+
3988+ int EVPKeyCtxPointer::initForVerifyMessage (const OSSL_PARAM params[]) {
3989+ if (!ctx_) return 0 ;
3990+ return EVP_PKEY_verify_message_init (ctx_.get (), nullptr , params);
3991+ }
3992+ #endif
3993+
39333994bool EVPKeyCtxPointer::initForEncrypt () {
39343995 if (!ctx_) return false ;
39353996 return EVP_PKEY_encrypt_init (ctx_.get ()) == 1 ;
@@ -4491,6 +4552,27 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInitWithContext(
44914552#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
44924553 EVP_PKEY_CTX* ctx = nullptr ;
44934554
4555+ #ifdef OSSL_SIGNATURE_PARAM_INSTANCE
4556+ // Ed25519ctx requires the INSTANCE param to enable context string support.
4557+ // Ed25519 pure mode ignores context strings without this.
4558+ if (key.id () == EVP_PKEY_ED25519) {
4559+ const OSSL_PARAM params[] = {
4560+ OSSL_PARAM_construct_utf8_string (
4561+ OSSL_SIGNATURE_PARAM_INSTANCE, const_cast <char *>(" Ed25519ctx" ), 0 ),
4562+ OSSL_PARAM_construct_octet_string (
4563+ OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
4564+ const_cast <unsigned char *>(context_string.data ),
4565+ context_string.len ),
4566+ OSSL_PARAM_END};
4567+
4568+ if (!EVP_DigestSignInit_ex (
4569+ ctx_.get (), &ctx, nullptr , nullptr , nullptr , key.get (), params)) {
4570+ return std::nullopt ;
4571+ }
4572+ return ctx;
4573+ }
4574+ #endif // OSSL_SIGNATURE_PARAM_INSTANCE
4575+
44944576 const OSSL_PARAM params[] = {
44954577 OSSL_PARAM_construct_octet_string (
44964578 OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
@@ -4515,6 +4597,27 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInitWithContext(
45154597#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING
45164598 EVP_PKEY_CTX* ctx = nullptr ;
45174599
4600+ #ifdef OSSL_SIGNATURE_PARAM_INSTANCE
4601+ // Ed25519ctx requires the INSTANCE param to enable context string support.
4602+ // Ed25519 pure mode ignores context strings without this.
4603+ if (key.id () == EVP_PKEY_ED25519) {
4604+ const OSSL_PARAM params[] = {
4605+ OSSL_PARAM_construct_utf8_string (
4606+ OSSL_SIGNATURE_PARAM_INSTANCE, const_cast <char *>(" Ed25519ctx" ), 0 ),
4607+ OSSL_PARAM_construct_octet_string (
4608+ OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
4609+ const_cast <unsigned char *>(context_string.data ),
4610+ context_string.len ),
4611+ OSSL_PARAM_END};
4612+
4613+ if (!EVP_DigestVerifyInit_ex (
4614+ ctx_.get (), &ctx, nullptr , nullptr , nullptr , key.get (), params)) {
4615+ return std::nullopt ;
4616+ }
4617+ return ctx;
4618+ }
4619+ #endif // OSSL_SIGNATURE_PARAM_INSTANCE
4620+
45184621 const OSSL_PARAM params[] = {
45194622 OSSL_PARAM_construct_octet_string (
45204623 OSSL_SIGNATURE_PARAM_CONTEXT_STRING,
0 commit comments