Сообщение об ошибке
Invalid EC key. Point is not on the curve specified.
Воспроизведено на cryptography 50.0. EllipticCurvePublicKey.from_encoded_point() сообщает о той же ошибке короче: «Invalid EC key.». Другие стеки формулируют её по-своему: стек ошибок OpenSSL 1.1 выдаёт «point is not on curve», Node отклоняет JWK с сообщением «Invalid JWK EC key», — но математика за всеми этими сообщениями одна и та же.
Python cryptography — ValueError from EllipticCurvePublicNumbers.public_key()
Что это означает
Переданная пара (x, y) не удовлетворяет уравнению кривой y² = x³ + ax + b (mod p) для указанной кривой. Библиотеки проверяют это при импорте, потому что, если принимать точки вне кривой, становятся возможны атаки с недопустимой кривой (invalid-curve attacks), которые могут привести к утечке закрытых ключей, — так что отказ здесь — защитная проверка, а не педантизм. Проверка сводится к одному дешёвому вычислению уравнения кривой, и её выполняет любая серьёзная библиотека: точку вне кривой где-нибудь да отклонят, и лучше здесь, с явной ошибкой, чем дальше по цепочке обработки.
Почему это происходит
Координаты привязаны не к той кривой
частоТочка secp256k1 (Bitcoin/Ethereum) объявлена как SECP256R1/P-256 — или наоборот. Обе кривые используют 32-байтовые координаты, поэтому подмену не выявляет ничто, кроме уравнения кривой.
Повреждённые или усечённые байты координаты
частоОтброшенный ведущий ноль (31-байтовая координата), hex, декодированный с ошибкой на единицу, путаница base64 и base64url или один инвертированный бит — любое изменение x или y почти наверняка уводит точку с кривой.
Неверный порядок байтов
иногдаВо всех стандартных кодировках координаты записываются в порядке big-endian. Байты, развёрнутые в little-endian (так часто бывает при работе с оборудованием или с самописным кодом), описывают совсем другую точку — лежащую вне кривой.
Как исправить
- 1.
Соберите ключ из закодированной точки с правильной кривой
from_encoded_point за один шаг проверяет и длину, и структуру; если по источнику нельзя однозначно определить кривую, попробуйте другую возможную кривую.
python from cryptography.hazmat.primitives.asymmetric import ec point = b"\x04" + x_bytes + y_bytes # uncompressed, 65 bytes for P-256 key = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), point) # if that raises, test: ec.SECP256K1() — the other 256-bit suspect - 2.
Проверьте исходные данные
Перед сборкой ключа убедитесь, что длина координат — 32 байта, а значения правдоподобны; отброшенные нули восстановите дополнением координаты нулями слева.
python print(len(x_bytes), len(y_bytes)) # must be 32, 32 for P-256 x_bytes = x_bytes.rjust(32, b"\x00") # repair stripped leading zeros y_bytes = y_bytes.rjust(32, b"\x00")