ECDSA frente a EdDSA suele significar ECDSA sobre P-256 frente a EdDSA sobre Ed25519: los dos esquemas de firma que cubren casi todos los despliegues modernos de curva elíptica. Son igual de robustos e igual de compactos, así que la elección depende de la seguridad de la implementación, por un lado, y de la compatibilidad del ecosistema, por el otro.
De un vistazo
| ECDSA (P-256) | EdDSA (Ed25519) | |
|---|---|---|
| Estándar | FIPS 186-5 §6, SEC 1, ANSI X9.62 | RFC 8032, FIPS 186-5 §7 (aprobado desde 2023) |
| Forma de la curva | Weierstrass corta, orden primo (cofactor 1) | Edwards torcida, cofactor 8 |
| Seguridad | unos 128 bits | unos 128 bits |
| Clave privada | Escalar de 32 bytes | Semilla de 32 bytes |
| Clave pública | 65 bytes sin comprimir, 33 en formato comprimido, 91 como SPKI DER | 32 bytes, 44 como SPKI DER |
| Firma | 64 bytes r‖s en bruto, 70–72 bytes en DER | 64 bytes R‖S, una sola codificación |
| Nonce | Aleatorio en cada firma, o determinista con RFC 6979 | Derivado de la clave y del mensaje por diseño |
| Maleable | Sí: (r, n − s) también se verifica | No, si el verificador comprueba que S es menor que el orden del grupo |
| Firmas / verificaciones por segundo, OpenSSL 3.6.5 | unas 87.000 / 29.000 | unas 60.000 / 25.000 |
| Firmas / verificaciones por segundo, @noble/curves 2.3 | unas 3800 / 870 | unas 3100 / 1280 |
| JOSE / COSE | ES256 / −7 | Ed25519 (RFC 9864) / −19, el antiguo EdDSA / −8 |
| Esquema de TLS 1.3 | ecdsa_secp256r1_sha256 (0x0403) | ed25519 (0x0807) |
| Certificados TLS de confianza pública | Sí | No (los Baseline Requirements solo permiten RSA y P-256/384/521) |
Las velocidades se midieron en un núcleo de un Apple M4 Max con OpenSSL 3.6.5 (openssl speed) y, en la fila de JavaScript puro, con @noble/curves 2.3.0 sobre Node.js 26.10.
En qué se diferencian los diseños
Ambas son firmas basadas en el logaritmo discreto sobre curvas elípticas, pero se diseñaron con unos veinte años de diferencia —ECDSA en 1992 y EdDSA en 2011—, y se nota.
El nonce
Una firma ECDSA consume un nonce k secreto y distinto para cada firma. Si k se repite en dos mensajes, o simplemente tiene un sesgo de unos pocos bits a lo largo de muchas firmas, se puede calcular la clave privada: así se filtró la clave de firma de la PlayStation 3 y así se vaciaron muchas billeteras de criptomonedas. FIPS 186-5 permite tanto un k aleatorio procedente de un generador aprobado como la derivación determinista del RFC 6979, y la mayoría de las bibliotecas modernas usan una de las dos de forma predeterminada, pero el modo de fallo forma parte del propio esquema.
EdDSA lo elimina: el nonce es el hash de una mitad de la clave secreta y del mensaje (RFC 8032 §5.1.6). Firmar dos veces el mismo mensaje da la misma firma, y mensajes distintos reciben siempre nonces distintos, sin que intervenga ningún generador de números aleatorios. La contrapartida son los ataques por inyección de fallos: un fallo transitorio (glitch) mientras se firma dos veces el mismo mensaje puede filtrar la clave, y por eso algunas billeteras de hardware y el estándar poscuántico ML-DSA prefieren la firma hedged, que además mezcla aleatoriedad nueva.
Codificación y maleabilidad
ECDSA tiene dos codificaciones de firma: r‖s en bruto (JOSE, WebCrypto, COSE, PKCS #11) y una SEQUENCE ASN.1 DER (X.509, TLS, OpenSSL, Java, aserciones de WebAuthn). Confundirlas es, con diferencia, la causa más habitual del error «invalid signature», y la guía sobre los formatos DER y en bruto lo trata en detalle. ECDSA también es maleable: cualquiera puede convertir (r, s) en (r, n − s), igual de válida, y por eso Bitcoin y Ethereum exigen low-S.
Ed25519 tiene una sola codificación de 64 bytes, y el RFC 8032 §5.1.7 exige que S sea menor que el orden del grupo, lo que elimina la maleabilidad evidente.
Casos límite de la verificación
La verificación de ECDSA está bien definida: comprueba que r y s están en 1…n−1, calcula u₁·G + u₂·Q y compara su coordenada x con r. Omitir la comprobación del rango es fatal: las versiones 15 a 18 de Java aceptaban una firma formada solo por ceros para cualquier mensaje (CVE-2022-21449).
La verificación de EdDSA tiene un problema más sutil. Como Edwards25519 tiene cofactor 8, el RFC 8032 permite tanto una comprobación con cofactor, [8][S]B = [8]R + [8][k]A, como la versión sin cofactor, [S]B = R + [k]A, y además las bibliotecas difieren en el tratamiento de los puntos de orden pequeño y de las codificaciones que no están en forma canónica. Con firmas generadas honestamente, los resultados coinciden; con entradas maliciosas, no. Los sistemas en los que muchas partes deben ponerse de acuerdo sobre la validez, como las cadenas de bloques, fijan un único conjunto de reglas; ZIP 215 de Zcash es la opción habitual.
Dónde se admite cada uno
ECDSA P-256 es el mínimo común denominador del hardware y de la plataforma web. WebCrypto lo admite en todos los navegadores; el Secure Enclave de Apple y la mayoría de los TPM, HSM, tarjetas inteligentes y tipos de clave de los KMS en la nube lo ofrecen (a menudo en exclusiva); las llaves de acceso lo usan de forma predeterminada (COSE −7), y los Baseline Requirements del CA/Browser Forum (§6.1.5) solo permiten RSA y ECDSA sobre P-256, P-384 y P-521 para los certificados TLS de confianza pública.
Ed25519 domina los ecosistemas definidos por software. OpenSSH genera claves Ed25519 de forma predeterminada desde la versión 9.5 (octubre de 2023); Signal, WireGuard, Tor, age y la mayoría de los protocolos de diseño reciente se basan en las curvas 25519 (X25519 para el intercambio de claves, Ed25519 para las firmas); las claves OpenPGP v6 lo admiten de forma nativa (RFC 9580), y WebCrypto lo admite en Firefox 129, Safari 17 y Chrome 137 y versiones posteriores. En JOSE, el RFC 9864 sustituye el identificador polimórfico EdDSA por Ed25519, totalmente especificado.
En los despliegues con validación FIPS, ambos están aprobados por FIPS 186-5, aunque los módulos validados más antiguos pueden ser anteriores a la compatibilidad con EdDSA. A largo plazo, los dos caen ante una computadora cuántica, y NIST IR 8547 (todavía un borrador) propone prohibir ambos después de 2035.
Rendimiento
La creencia popular dice que Ed25519 es mucho más rápido que ECDSA. Era cierto cuando las implementaciones de P-256 eran genéricas; no lo es en el OpenSSL actual, que incluye código de P-256 optimizado a mano. En un núcleo de un Apple M4 Max, OpenSSL 3.6.5 produjo unas 87.000 firmas P-256 por segundo frente a unas 60.000 de Ed25519, y verificó unas 29.000 frente a 25.000. En JavaScript puro (@noble/curves 2.3.0), Ed25519 verifica alrededor de un 50 % más rápido, mientras que P-256 firma algo más rápido. En cualquier caso, cada operación cuesta microsegundos y eso rara vez decide nada; lo que importa es que ambos son entre uno y dos órdenes de magnitud más rápidos que la firma RSA.
El script siguiente, ejecutado con Node.js 26.10, muestra las diferencias prácticas en unas pocas líneas.
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
El firmante ECDSA de Node usa nonces aleatorios, así que dos firmas del mismo mensaje son distintas; aun así, ambas se verifican. El verificador de firmas acepta cualquiera de los dos esquemas y muestra qué codificación detecta.
Cuándo elegir cada uno
- Claves SSH de usuario y de host: Ed25519, o
ed25519-skcon una llave de seguridad FIDO. Usa ECDSA solo con servidores antiguos o con hardware que no admita Ed25519. - Llaves de acceso y WebAuthn: acepta ambos (COSE −7, y −8 o −19), pero cuenta con recibir ES256 de los autenticadores de plataforma.
- Certificados TLS de confianza pública: ECDSA P-256 (o P-384); los Baseline Requirements no permiten Ed25519.
- JWT y tokens de API: ES256 para la máxima compatibilidad y para las claves guardadas en un KMS en la nube; Ed25519 donde todos los consumidores admitan RFC 8037 o RFC 9864. La página ES256 frente a EdDSA para JWT profundiza en el tema.
- Claves dentro del Secure Enclave, de TPM, de tarjetas inteligentes o de la mayoría de los HSM: ECDSA P-256, porque es lo que ofrece el hardware.
- Cadenas de bloques: la elección no es tuya; sigue lo que use la cadena (ECDSA o Schnorr sobre secp256k1 para Bitcoin y Ethereum, Ed25519 para Solana).
- Protocolos nuevos con verificación crítica para el consenso: Ed25519 con una regla de verificación especificada de forma explícita, como ZIP 215.
Notas de migración
No hay conversión posible entre una clave P-256 y una clave Ed25519: curvas distintas, formatos de clave distintos. Pasar de una a otra es una rotación de claves.
- Genera las claves nuevas donde vayan a residir. Con
openssl genpkey -algorithm ED25519ossh-keygen -t ed25519, o dentro del HSM si admite Ed25519. Comprueba la compatibilidad del firmware antes de planificar. - Publica ambas claves durante el periodo de transición. En un JWKS, da a cada clave su propio
kidy su propioalg; enauthorized_keys, añade la línea nueva antes de quitar la antigua; en el caso de los certificados, solicita uno nuevo para la clave nueva. - Actualiza los verificadores antes que los firmantes. Los verificadores deben aceptar el nuevo identificador de algoritmo (
Ed25519oEdDSAen JOSE, el OID1.3.101.112en X.509,ssh-ed25519en SSH) sin dejar de fijar una lista de algoritmos permitidos, y nunca deben dejar que el token o el mensaje elijan. - Pasa a firmar con la clave nueva y después retira la antigua cuando haya caducado todo lo que se firmó con ella.
- Vigila las codificaciones. El código de ECDSA a menudo convierte entre firmas DER y en bruto; el de Ed25519 no debe hacerlo, y el tamaño de la «clave privada» de Ed25519 varía según la API (semilla de 32 bytes o 64 bytes de semilla más clave pública).
El camino inverso, de Ed25519 a ECDSA, se da sobre todo cuando las claves pasan a hardware. Usa nonces deterministas o hedged, exige low-S si las firmas funcionan como identificadores y prueba el tratamiento de las firmas DER y en bruto con el conversor entre DER y r‖s en bruto.
Referencias
- FIPS 186-5, estándar de firma digital (§6 ECDSA, §7 EdDSA)
- RFC 8032, algoritmo de firma digital de curva de Edwards
- RFC 6979, uso determinista de DSA y ECDSA
- SEC 1 v2, criptografía de curva elíptica
- RFC 9864, algoritmos totalmente especificados para JOSE y COSE
- RFC 8410, Ed25519 y Ed448 en X.509
- ZIP 215, definición explícita de la validación de Ed25519
- Baseline Requirements del CA/Browser Forum §6.1.5
- Notas de la versión de OpenSSH 9.5