Когда сравнивают ECDSA и EdDSA, обычно имеют в виду ECDSA на кривой P-256 и EdDSA на Ed25519: на этих двух схемах подписи построены почти все современные системы, использующие эллиптические кривые. Они одинаково стойкие и одинаково компактные, поэтому выбор определяется безопасностью реализации, с одной стороны, и поддержкой в экосистеме — с другой.
Коротко о главном
| ECDSA (P-256) | EdDSA (Ed25519) | |
|---|---|---|
| Стандарт | FIPS 186-5, § 6; SEC 1; ANSI X9.62 | RFC 8032; FIPS 186-5, § 7 (допускается с 2023 года) |
| Форма кривой | Короткая форма Вейерштрасса, простой порядок (кофактор 1) | Скрученная форма Эдвардса, кофактор 8 |
| Стойкость | около 128 бит | около 128 бит |
| Закрытый ключ | 32-байтный скаляр | 32-байтный seed |
| Открытый ключ | 65 байт в несжатой форме, 33 в сжатой, 91 в виде SPKI DER | 32 байта, 44 в виде SPKI DER |
| Подпись | 64 байта в формате raw r‖s, 70–72 байта в DER | 64 байта R‖S, единственная кодировка |
| Nonce | Случайный для каждой подписи или детерминированный по RFC 6979 | По построению выводится из ключа и сообщения |
| Пластичность | Да: (r, n − s) тоже проходит проверку | Нет, если проверяющая сторона требует, чтобы S было меньше порядка группы |
| Подписей / проверок в секунду, OpenSSL 3.6.5 | около 87 000 / 29 000 | около 60 000 / 25 000 |
| Подписей / проверок в секунду, @noble/curves 2.3 | около 3 800 / 870 | около 3 100 / 1 280 |
| JOSE / COSE | ES256 / −7 | Ed25519 (RFC 9864) / −19, прежний EdDSA / −8 |
| Схема в TLS 1.3 | ecdsa_secp256r1_sha256 (0x0403) | ed25519 (0x0807) |
| Публично доверенные TLS-сертификаты | Да | Нет (Baseline Requirements допускают только RSA и P-256/384/521) |
Скорость измерялась на одном ядре Apple M4 Max с помощью OpenSSL 3.6.5 (openssl speed), а для строки с чистым JavaScript — с помощью @noble/curves 2.3.0 на Node.js 26.10.
Чем различается устройство схем
Обе схемы — подписи на эллиптических кривых, основанные на задаче дискретного логарифмирования, но их разработали с разницей примерно в 20 лет (ECDSA — в 1992 году, EdDSA — в 2011-м), и это заметно.
Nonce
Каждая подпись ECDSA расходует своё секретное одноразовое число — nonce k. Если k повторится для двух сообщений или всего лишь окажется смещённым на несколько бит во множестве подписей, закрытый ключ можно вычислить; именно так утёк ключ подписи PlayStation 3 и так были опустошены многие криптовалютные кошельки. FIPS 186-5 допускает либо случайный k из одобренного генератора, либо детерминированный вывод по RFC 6979, и большинство современных библиотек по умолчанию используют один из этих способов, но сама возможность такого отказа заложена в схему.
EdDSA устраняет эту проблему: nonce — это хеш от половины секретного ключа и сообщения (RFC 8032, § 5.1.6). Если подписать одно и то же сообщение дважды, получится одна и та же подпись, а разные сообщения всегда получают разные nonce, причём генератор случайных чисел в этом не участвует. Обратная сторона — атаки с внесением сбоев: сбой при повторном подписании того же сообщения может раскрыть ключ, поэтому некоторые аппаратные кошельки и постквантовый стандарт ML-DSA предпочитают хеджированное подписание, в котором подмешиваются ещё и свежие случайные данные.
Кодировка и пластичность
У подписи ECDSA две кодировки: raw r‖s (JOSE, WebCrypto, COSE, PKCS #11) и ASN.1 DER SEQUENCE (X.509, TLS, OpenSSL, Java, assertion в WebAuthn). Путаница между ними — самая распространённая причина ошибки «invalid signature», и руководство по DER и raw подробно её разбирает. Кроме того, подписи ECDSA пластичны: любой может превратить (r, s) в столь же верную (r, n − s), поэтому Bitcoin и Ethereum требуют low-S.
У Ed25519 одна 64-байтная кодировка, а RFC 8032, § 5.1.7 требует, чтобы S было меньше порядка группы, и это устраняет очевидную пластичность.
Граничные случаи проверки
Проверка ECDSA определена однозначно: убедиться, что r и s лежат в диапазоне 1…n−1, вычислить u₁·G + u₂·Q и сравнить координату x результата с r. Пропуск проверки диапазона фатален: Java версий 15–18 принимала подпись из одних нулей для любого сообщения (CVE-2022-21449).
С проверкой EdDSA связана более тонкая проблема. Поскольку у Edwards25519 кофактор 8, RFC 8032 допускает как проверку с кофактором [8][S]B = [8]R + [8][k]A, так и проверку без кофактора [S]B = R + [k]A, а ещё библиотеки по-разному обрабатывают точки малого порядка и кодировки, отличные от канонической формы. Для честно созданных подписей результаты совпадают, для специально подобранных входных данных — нет. Системы, в которых многие участники должны одинаково решать, действительна ли подпись (например, блокчейны), закрепляют один конкретный набор правил; обычно выбирают ZIP 215 от Zcash.
Где какая схема поддерживается
ECDSA P-256 — наименьший общий знаменатель для оборудования и веб-платформы. Эту схему поддерживает WebCrypto в любом браузере, её предлагают (часто как единственный вариант) Secure Enclave от Apple и большинство TPM, HSM, смарт-карт и типов ключей в облачных KMS, ключи доступа по умолчанию используют именно её (COSE −7), а Baseline Requirements CA/Browser Forum (§ 6.1.5) для публично доверенных TLS-сертификатов допускают только RSA и ECDSA на P-256, P-384 и P-521.
В программных экосистемах доминирует Ed25519. OpenSSH по умолчанию генерирует ключи Ed25519 начиная с версии 9.5 (октябрь 2023 года); Signal, WireGuard, Tor, age и большинство новых протоколов построены на кривых 25519 (X25519 для обмена ключами, Ed25519 для подписей); ключи OpenPGP v6 поддерживают Ed25519 нативно (RFC 9580); а WebCrypto поддерживает эту схему начиная с Firefox 129, Safari 17 и Chrome 137. В JOSE RFC 9864 заменяет полиморфный идентификатор EdDSA полностью определённым Ed25519.
Для систем, сертифицированных по FIPS, обе схемы одобрены в FIPS 186-5, хотя старые сертифицированные модули могут не поддерживать EdDSA, так как появились раньше. В долгосрочной перспективе обе схемы не устоят перед квантовым компьютером, и NIST IR 8547 (пока это черновик) предлагает запретить обе после 2035 года.
Производительность
Принято считать, что Ed25519 намного быстрее ECDSA. Так было, пока реализации P-256 были универсальными; к сегодняшнему OpenSSL, в котором есть вручную оптимизированный код для P-256, это не относится. На одном ядре Apple M4 Max OpenSSL 3.6.5 создавал около 87 000 подписей P-256 в секунду против примерно 60 000 для Ed25519 и проверял около 29 000 подписей против 25 000. На чистом JavaScript (@noble/curves 2.3.0) Ed25519 проверяет подписи примерно на 50 % быстрее, а P-256 немного быстрее подписывает. В любом случае речь идёт о микросекундах, и это редко на что-то влияет; важно то, что обе схемы на один-два порядка быстрее подписи RSA.
Скрипт ниже, запущенный на Node.js 26.10, в нескольких строках показывает практические различия.
import { generateKeyPairSync, sign, verify } from "node:crypto";
const message = Buffer.from("transfer 100 to alice");
const ed = generateKeyPairSync("ed25519");
const ec = generateKeyPairSync("ec", { namedCurve: "P-256" });
// Ed25519: the algorithm argument is null because the hash is fixed (SHA-512).
const ed1 = sign(null, message, ed.privateKey);
const ed2 = sign(null, message, ed.privateKey);
// ECDSA P-256 with SHA-256, raw r||s output as used by JOSE and WebCrypto.
const ec1 = sign("sha256", message, { key: ec.privateKey, dsaEncoding: "ieee-p1363" });
const ec2 = sign("sha256", message, { key: ec.privateKey, dsaEncoding: "ieee-p1363" });
console.log("Ed25519 signature bytes:", ed1.length, "deterministic:", ed1.equals(ed2));
console.log("ECDSA P-256 signature bytes:", ec1.length, "deterministic:", ec1.equals(ec2));
console.log("Ed25519 public key (SPKI DER) bytes:", ed.publicKey.export({ type: "spki", format: "der" }).length);
console.log("P-256 public key (SPKI DER) bytes:", ec.publicKey.export({ type: "spki", format: "der" }).length);
console.log("both verify:", verify(null, message, ed.publicKey, ed1) && verify("sha256", message, { key: ec.publicKey, dsaEncoding: "ieee-p1363" }, ec1));
Ed25519 signature bytes: 64 deterministic: true
ECDSA P-256 signature bytes: 64 deterministic: false
Ed25519 public key (SPKI DER) bytes: 44
P-256 public key (SPKI DER) bytes: 91
both verify: true
ECDSA в Node подписывает со случайными nonce, поэтому две подписи одного и того же сообщения различаются, но обе проходят проверку. Инструмент проверки подписей принимает обе схемы и показывает, какую кодировку он распознал.
Что когда выбирать
- Пользовательские ключи и ключи хостов SSH: Ed25519 или
ed25519-skс ключом безопасности FIDO. ECDSA используйте только для старых серверов или оборудования, которое не поддерживает Ed25519. - Ключи доступа и WebAuthn: принимайте обе схемы (COSE −7 и −8 или −19), но рассчитывайте на то, что платформенные аутентификаторы выдадут ES256.
- Публично доверенные TLS-сертификаты: ECDSA P-256 (или P-384); Baseline Requirements не допускают Ed25519.
- JWT и API-токены: ES256 — для максимальной совместимости и для ключей, которые хранятся в облачном KMS; Ed25519 — там, где все получатели токенов поддерживают RFC 8037 или RFC 9864. Подробнее об этом — на странице ES256 или EdDSA для JWT.
- Ключи в Secure Enclave, TPM, смарт-картах или большинстве HSM: ECDSA P-256, потому что именно эту схему предлагает оборудование.
- Блокчейны: здесь выбор не за вами; следуйте правилам сети (ECDSA или Schnorr на secp256k1 для Bitcoin и Ethereum, Ed25519 для Solana).
- Новые протоколы, в которых от проверки подписи зависит консенсус: Ed25519 с явно заданным правилом проверки, например ZIP 215.
Заметки о миграции
Ключ P-256 нельзя преобразовать в ключ Ed25519 и наоборот: у них разные кривые и разные форматы ключей. Переход с одного на другой — это ротация ключей.
- Генерируйте новые ключи там, где они будут храниться. С помощью
openssl genpkey -algorithm ED25519илиssh-keygen -t ed25519либо внутри HSM, если он поддерживает Ed25519. Прежде чем планировать переход, проверьте поддержку в прошивке. - На переходный период опубликуйте оба ключа. В JWKS задайте каждому ключу собственные
kidиalg; вauthorized_keysдобавьте новую строку, прежде чем удалять старую; для сертификатов запросите новый сертификат на новый ключ. - Обновите проверяющие стороны раньше подписантов. Проверяющие стороны должны принимать новый идентификатор алгоритма (
Ed25519илиEdDSAв JOSE, OID1.3.101.112в X.509,ssh-ed25519в SSH), но по-прежнему сверяться с закреплённым списком разрешённых алгоритмов и никогда не позволять токену или сообщению выбирать алгоритм. - Переключите подписание на новый ключ, затем выведите старый из оборота, когда истечёт срок действия всего, что им подписано.
- Следите за кодировками. Код для ECDSA часто преобразует подписи между DER и raw; код для Ed25519 этого делать не должен, а размер «закрытого ключа» Ed25519 зависит от API (32-байтный seed или 64 байта: seed плюс открытый ключ).
Обратный переход, с Ed25519 на ECDSA, случается в основном тогда, когда ключи переносят в оборудование. Используйте детерминированные или хеджированные nonce, требуйте low-S, если подписи служат идентификаторами, и проверьте обработку DER и raw с помощью конвертера DER и raw.
Источники
- FIPS 186-5, стандарт цифровой подписи (ECDSA в § 6, EdDSA в § 7)
- RFC 8032, алгоритм цифровой подписи на кривых Эдвардса (EdDSA)
- RFC 6979, детерминированное использование DSA и ECDSA
- SEC 1 v2, криптография на эллиптических кривых
- RFC 9864, полностью определённые алгоритмы для JOSE и COSE
- RFC 8410, Ed25519 и Ed448 в X.509
- ZIP 215, явное определение правил проверки Ed25519
- Baseline Requirements CA/Browser Forum, § 6.1.5
- Примечания к выпуску OpenSSH 9.5