@@ -3538,8 +3538,38 @@ bool ECKeyPointer::setPublicKey(const ECPointPointer& pub) {
35383538bool ECKeyPointer::setPublicKeyRaw (const BignumPointer& x,
35393539 const BignumPointer& y) {
35403540 if (!key_) return false ;
3541- return EC_KEY_set_public_key_affine_coordinates (
3542- key_.get (), x.get (), y.get ()) == 1 ;
3541+ const EC_GROUP* group = EC_KEY_get0_group (key_.get ());
3542+ if (group == nullptr ) return false ;
3543+
3544+ // For curves with cofactor h=1, use EC_POINT_oct2point +
3545+ // EC_KEY_set_public_key instead of EC_KEY_set_public_key_affine_coordinates.
3546+ // The latter internally calls EC_KEY_check_key() which performs a scalar
3547+ // multiplication (n*Q) for order validation — redundant when h=1 since every
3548+ // on-curve point already has order n. EC_POINT_oct2point validates the point
3549+ // is on the curve, which is sufficient. For curves with h!=1, fall back to
3550+ // the full check.
3551+ auto cofactor = BignumPointer::New ();
3552+ if (!cofactor || !EC_GROUP_get_cofactor (group, cofactor.get (), nullptr ) ||
3553+ !cofactor.isOne ()) {
3554+ return EC_KEY_set_public_key_affine_coordinates (
3555+ key_.get (), x.get (), y.get ()) == 1 ;
3556+ }
3557+
3558+ // Field element byte length: ceil(degree_bits / 8).
3559+ size_t field_len = (EC_GROUP_get_degree (group) + 7 ) / 8 ;
3560+ // Build an uncompressed point: 0x04 || x || y, each padded to field_len.
3561+ size_t uncompressed_len = 1 + 2 * field_len;
3562+ auto buf = DataPointer::Alloc (uncompressed_len);
3563+ if (!buf) return false ;
3564+ unsigned char * ptr = static_cast <unsigned char *>(buf.get ());
3565+ ptr[0 ] = POINT_CONVERSION_UNCOMPRESSED;
3566+ x.encodePaddedInto (ptr + 1 , field_len);
3567+ y.encodePaddedInto (ptr + 1 + field_len, field_len);
3568+
3569+ auto point = ECPointPointer::New (group);
3570+ if (!point) return false ;
3571+ if (!point.setFromBuffer ({ptr, uncompressed_len}, group)) return false ;
3572+ return EC_KEY_set_public_key (key_.get (), point.get ()) == 1 ;
35433573}
35443574
35453575bool ECKeyPointer::setPrivateKey (const BignumPointer& priv) {
0 commit comments