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