Aller au contenu
ecdsa.com

ECDSA vs EdDSA : P-256 ou Ed25519 pour les signatures

Tous deux produisent des signatures sur courbes elliptiques de 64 octets, avec 128 bits de sécurité. Ils diffèrent par la sûreté de leurs modes de défaillance, par les plateformes qui les prennent en charge et par la rigueur avec laquelle les vérificateurs s’accordent entre eux.

ECDSA vs EdDSA, c’est en général ECDSA sur P-256 face à EdDSA sur Ed25519 : les deux schémas de signature qui couvrent la quasi-totalité des déploiements modernes sur courbes elliptiques. Ils sont aussi robustes et aussi compacts l’un que l’autre ; le choix se joue donc sur la sûreté de l’implémentation d’un côté et sur la prise en charge par l’écosystème de l’autre.

Vue d’ensemble

ECDSA (P-256)EdDSA (Ed25519)
NormeFIPS 186-5 §6, SEC 1, ANSI X9.62RFC 8032, FIPS 186-5 §7 (approuvé depuis 2023)
Forme de la courbeWeierstrass réduite, ordre premier (cofacteur 1)Edwards tordue, cofacteur 8
Sécuritéenviron 128 bitsenviron 128 bits
Clé privéeScalaire de 32 octetsGraine de 32 octets
Clé publique65 octets en forme non compressée, 33 en forme compressée, 91 en SPKI DER32 octets, 44 en SPKI DER
Signature64 octets bruts r‖s, 70–72 octets en DER64 octets R‖S, un seul encodage
NonceAléatoire pour chaque signature, ou déterministe selon la RFC 6979Dérivé de la clé et du message, par conception
MalléableOui : (r, n − s) se vérifie aussiNon, si le vérificateur contrôle que S est inférieur à l’ordre du groupe
Signatures / vérifications par seconde, OpenSSL 3.6.5environ 87 000 / 29 000environ 60 000 / 25 000
Signatures / vérifications par seconde, @noble/curves 2.3environ 3800 / 870environ 3100 / 1280
JOSE / COSEES256 / −7Ed25519 (RFC 9864) / −19, l’ancien EdDSA / −8
Schéma TLS 1.3ecdsa_secp256r1_sha256 (0x0403)ed25519 (0x0807)
Certificats TLS de confiance publiqueOuiNon (les Baseline Requirements n’autorisent que RSA et P-256/384/521)

Les vitesses ont été mesurées sur un cœur d’un Apple M4 Max avec OpenSSL 3.6.5 (openssl speed) et, pour la ligne en JavaScript pur, avec @noble/curves 2.3.0 sous Node.js 26.10.

En quoi les conceptions diffèrent

Tous deux sont des schémas de signature sur courbes elliptiques fondés sur le logarithme discret, mais ils ont été conçus à une vingtaine d’années d’écart, ECDSA en 1992 et EdDSA en 2011, et cela se voit.

Le nonce

Une signature ECDSA consomme un nonce k secret, propre à chaque signature. Si k se répète pour deux messages, ou s’il présente seulement un biais de quelques bits sur de nombreuses signatures, la clé privée peut être calculée ; c’est ainsi qu’a fuité la clé de signature de la PlayStation 3 et qu’ont été vidés de nombreux portefeuilles de cryptomonnaies. FIPS 186-5 autorise soit un k aléatoire issu d’un générateur approuvé, soit la dérivation déterministe de la RFC 6979, et la plupart des bibliothèques modernes utilisent l’une ou l’autre par défaut, mais ce mode de défaillance est inhérent au schéma.

EdDSA l’élimine : le nonce est le condensat d’une moitié de la clé secrète et du message (RFC 8032 §5.1.6). Signer deux fois le même message donne la même signature, et des messages différents reçoivent toujours des nonces différents, sans aucun générateur de nombres aléatoires. La contrepartie, ce sont les attaques par injection de fautes : une perturbation (glitch) pendant deux signatures du même message peut faire fuiter la clé, ce qui explique pourquoi certains portefeuilles matériels et la norme post-quantique ML-DSA préfèrent une signature hedged, qui mêle aussi un aléa frais.

Encodage et malléabilité

ECDSA a deux encodages de signature : r‖s brut (JOSE, WebCrypto, COSE, PKCS #11) et une SEQUENCE ASN.1 DER (X.509, TLS, OpenSSL, Java, assertions WebAuthn). Les confondre est la toute première cause des erreurs « signature invalide », et le guide sur les formats DER et brut traite le sujet en détail. ECDSA est aussi malléable : n’importe qui peut transformer (r, s) en (r, n − s), tout aussi valide, ce qui explique pourquoi Bitcoin et Ethereum imposent la règle low-S.

Ed25519 n’a qu’un seul encodage de 64 octets, et la RFC 8032 §5.1.7 exige que S soit inférieur à l’ordre du groupe, ce qui supprime la forme évidente de malléabilité.

Cas limites de la vérification

La vérification ECDSA est bien définie : vérifiez que r et s sont compris dans l’intervalle 1…n−1, calculez u₁·G + u₂·Q et comparez sa coordonnée x à r. Omettre le contrôle d’intervalle est fatal ; Java 15 à 18 acceptait une signature entièrement nulle pour n’importe quel message (CVE-2022-21449).

La vérification EdDSA pose un problème plus subtil. Comme Edwards25519 a un cofacteur 8, la RFC 8032 autorise soit une vérification avec cofacteur [8][S]B = [8]R + [8][k]A, soit la vérification sans cofacteur [S]B = R + [k]A, et les bibliothèques divergent aussi sur les points de petit ordre et les encodages qui ne respectent pas la forme canonique. Pour des signatures générées honnêtement, les résultats concordent ; pour des entrées malveillantes, non. Les systèmes où de nombreuses parties doivent s’accorder sur la validité, comme les blockchains, s’en tiennent à un seul ensemble de règles ; ZIP 215 de Zcash est le choix courant.

Où chacun est pris en charge

ECDSA P-256 est le plus petit dénominateur commun du matériel et de la plateforme web. Tous les navigateurs le prennent en charge dans WebCrypto, la Secure Enclave d’Apple et la plupart des TPM, des HSM, des cartes à puce et des types de clés des KMS cloud le proposent (souvent exclusivement), les clés d’accès l’utilisent par défaut (COSE −7), et les Baseline Requirements du CA/Browser Forum (§6.1.5) n’autorisent que RSA et ECDSA sur P-256, P-384 et P-521 pour les certificats TLS de confiance publique.

Ed25519 domine les écosystèmes purement logiciels. OpenSSH génère des clés Ed25519 par défaut depuis la version 9.5 (octobre 2023) ; Signal, WireGuard, Tor, age et la plupart des nouveaux protocoles reposent sur les courbes 25519 (X25519 pour l’échange de clés, Ed25519 pour les signatures) ; les clés OpenPGP v6 le prennent en charge nativement (RFC 9580) ; et WebCrypto le prend en charge à partir de Firefox 129, Safari 17 et Chrome 137. Dans JOSE, la RFC 9864 remplace l’identifiant polymorphe EdDSA par l’identifiant entièrement spécifié Ed25519.

Pour les déploiements validés FIPS, les deux sont approuvés par FIPS 186-5, même si des modules validés plus anciens peuvent être antérieurs à la prise en charge d’EdDSA. À long terme, les deux tombent face à un ordinateur quantique, et le NIST IR 8547 (encore à l’état de projet) propose de ne plus autoriser ni l’un ni l’autre après 2035.

Performances

Selon une idée répandue, Ed25519 serait bien plus rapide qu’ECDSA. C’était vrai lorsque les implémentations de P-256 étaient génériques ; ce n’est plus le cas d’OpenSSL aujourd’hui, qui embarque du code P-256 optimisé à la main. Sur un cœur d’Apple M4 Max, OpenSSL 3.6.5 a produit environ 87 000 signatures P-256 par seconde contre environ 60 000 pour Ed25519, et en a vérifié environ 29 000 contre 25 000. En JavaScript pur (@noble/curves 2.3.0), Ed25519 vérifie environ 50 % plus vite, tandis que P-256 signe un peu plus vite. Dans les deux cas, le coût se compte en microsecondes et est rarement décisif ; l’essentiel est que tous deux soient d’un à deux ordres de grandeur plus rapides que la signature RSA.

Le script ci-dessous, exécuté avec Node.js 26.10, montre les différences pratiques en quelques lignes.

Node.js : tailles et déterminisme d’Ed25519 et d’ECDSA P-256
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));
Sortie
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

L’implémentation ECDSA de Node utilise des nonces aléatoires : deux signatures du même message diffèrent donc, et toutes deux se vérifient malgré tout. Le vérificateur de signatures accepte les deux schémas et indique quel encodage il a détecté.

Quand choisir l’un ou l’autre

  • Clés SSH d’utilisateur et d’hôte : Ed25519, ou ed25519-sk avec une clé de sécurité FIDO. N’utilisez ECDSA que pour d’anciens serveurs ou du matériel qui ne prend pas Ed25519 en charge.
  • Clés d’accès et WebAuthn : acceptez les deux (COSE −7 et −8 ou −19), mais attendez-vous à recevoir ES256 des authentificateurs de plateforme.
  • Certificats TLS de confiance publique : ECDSA P-256 (ou P-384) ; les Baseline Requirements n’autorisent pas Ed25519.
  • JWT et jetons d’API : ES256 pour la compatibilité la plus large et pour les clés conservées dans un KMS cloud ; Ed25519 lorsque chaque consommateur prend en charge la RFC 8037 ou la RFC 9864. La page ES256 vs EdDSA pour les JWT approfondit la question.
  • Clés conservées dans la Secure Enclave, des TPM, des cartes à puce ou la plupart des HSM : ECDSA P-256, car c’est ce que propose le matériel.
  • Blockchains : le choix ne vous appartient pas ; suivez la chaîne (ECDSA secp256k1 ou Schnorr pour Bitcoin et Ethereum, Ed25519 pour Solana).
  • Nouveaux protocoles dont le consensus dépend de la vérification : Ed25519 avec une règle de vérification explicitement spécifiée, comme ZIP 215.

Notes de migration

Il n’existe aucune conversion entre une clé P-256 et une clé Ed25519 : courbes différentes, formats de clé différents. Passer de l’une à l’autre est une rotation de clé.

  1. Générez les nouvelles clés là où elles résideront. Avec openssl genpkey -algorithm ED25519 ou ssh-keygen -t ed25519, ou dans le HSM s’il prend en charge Ed25519. Vérifiez la prise en charge par le micrologiciel avant de planifier.
  2. Publiez les deux clés pendant la période de chevauchement. Dans un JWKS, donnez à chaque clé son propre kid et son propre alg ; dans authorized_keys, ajoutez la nouvelle ligne avant de supprimer l’ancienne ; pour les certificats, demandez-en un nouveau pour la nouvelle clé.
  3. Mettez à jour les vérificateurs avant les signataires. Les vérificateurs doivent accepter le nouvel identifiant d’algorithme (Ed25519 ou EdDSA dans JOSE, l’OID 1.3.101.112 dans X.509, ssh-ed25519 dans SSH) tout en épinglant une liste d’autorisation, sans jamais laisser le jeton ou le message choisir.
  4. Basculez la signature, puis retirez l’ancienne clé une fois que tout ce qu’elle a signé a expiré.
  5. Surveillez les encodages. Le code ECDSA convertit souvent les signatures entre DER et brut ; le code Ed25519 ne doit pas le faire, et la taille de la « clé privée » Ed25519 varie selon l’API (graine de 32 octets, ou 64 octets formés de la graine et de la clé publique).

Le chemin inverse, d’Ed25519 vers ECDSA, se présente surtout lorsque les clés migrent vers du matériel. Utilisez des nonces déterministes ou hedged, imposez low-S si les signatures servent d’identifiants, et testez le traitement du DER et du brut avec le convertisseur DER ⇄ brut.

Références

Tous les comparatifs