P-256 vs secp256k1, c’est rarement un libre choix : la courbe vient généralement avec l’écosystème. Ce sont deux courbes de Weierstrass de 256 bits et d’ordre premier, qui offrent environ 128 bits de sécurité et des tailles de clés et de signatures identiques. Elles diffèrent toutefois par leur origine, par les plateformes qui les prennent en charge et par les conventions qui s’y superposent, et c’est en faisant passer des données d’un monde à l’autre que naissent les bugs.
Vue d’ensemble
| P-256 (secp256r1, prime256v1) | secp256k1 | |
|---|---|---|
| Spécifiée dans | NIST SP 800-186 §3.2.1.3, SEC 2 §2.4.2 | SEC 2 §2.4.1 ; autorisée par SP 800-186, annexe H.2, pour les usages blockchain |
| Équation | y² = x³ − 3x + b sur p = 2²⁵⁶ − 2²²⁴ + 2¹⁹² + 2⁹⁶ − 1 | y² = x³ + 7 sur p = 2²⁵⁶ − 2³² − 977 |
| Origine des paramètres | b dérivé d’une graine SHA-1 jamais expliquée | Coefficients fixes et minimaux (de type Koblitz) |
| Cofacteur, sécurité | 1, environ 128 bits | 1, environ 128 bits |
| Clés et signatures | Clé privée de 32 octets, clé publique de 33/65 octets, signature brute de 64 octets | Identiques |
| OID | 1.2.840.10045.3.1.7 | 1.3.132.0.10 |
| JOSE / COSE | ES256 / −7 | ES256K / −47 (RFC 8812) |
| Node.js 26 (OpenSSL 3.6.5), signatures / vérifications par seconde | environ 68 800 / 27 200 | environ 6500 / 7200 |
| @noble/curves 2.3.0, signatures / vérifications par seconde | environ 3800 / 870 | environ 3800 / 1180 |
| WebCrypto, TLS 1.3, WebAuthn | Oui | Non |
| Secure Enclave d’Apple, cartes PIV, la plupart des HSM | Oui | Rarement (AWS KMS propose ECC_SECG_P256K1) |
| Usages typiques | Certificats TLS, clés d’accès, JWT, identité des appareils | Bitcoin, Ethereum, Nostr, la plupart des chaînes EVM |
Mesures effectuées sur un cœur d’un Apple M4 Max.
Origines et confiance
P-256 a été publiée par le NIST en 1999 et normalisée dans FIPS 186-2 (2000), ainsi que par le SECG sous le nom secp256r1. Son nombre premier a une forme particulière qui permet une réduction rapide, et son coefficient b a été généré à partir d’une graine passée par SHA-1, comme le prescrivait la procédure « vérifiablement aléatoire » de l’époque. L’origine de la graine n’a jamais été expliquée, ce qui, après les révélations sur Dual_EC_DRBG, a conduit certains concepteurs à se méfier des courbes du NIST. Aucune attaque contre P-256 fondée sur cette graine n’a jamais été trouvée, et elle reste la courbe déployée la plus scrutée.
secp256k1 provient de SEC 2 (2000). Avec a = 0 et b = 7, il n’y a rien à cacher, et sa structure particulière fournit un endomorphisme efficacement calculable (la méthode GLV) qui accélère la multiplication scalaire. Satoshi Nakamoto l’a choisie pour Bitcoin en 2009, un choix inhabituel à l’époque, et Ethereum a suivi. NIST SP 800-186 (2023) autorise explicitement secp256k1 « pour les applications liées à la blockchain ».
Les deux courbes sont d’ordre premier : il n’y a donc aucune subtilité liée au cofacteur, et toutes deux tombent de la même manière face à l’algorithme de Shor.
Prise en charge par les plateformes et les bibliothèques
C’est là que se trouve la vraie différence. P-256 est intégrée à tout ce qui gère les clés à votre place : WebCrypto dans tous les navigateurs, les piles TLS de tous les systèmes d’exploitation, la Secure Enclave et CryptoKit d’Apple, Android Keystore, TPM 2.0, les cartes à puce PIV et tous les KMS cloud. Les clés d’accès l’utilisent par défaut, et les Baseline Requirements du CA/Browser Forum l’autorisent pour les certificats de confiance publique.
secp256k1 est absente de WebCrypto et de TLS 1.3 (la RFC 8422 avait déjà déprécié son point de code pour TLS 1.2), et les bibliothèques généralistes la traitent comme un ajout accessoire. Les logiciels blockchain s’appuient donc sur des implémentations dédiées : libsecp256k1, l’implémentation en temps constant de Bitcoin Core, et ailleurs @noble/curves, k256 en Rust et go-ethereum/crypto en Go. Les portefeuilles matériels la prennent en charge ; du côté des HSM d’entreprise, cela varie, et AWS KMS la propose sous la spécification de clé ECC_SECG_P256K1, uniquement pour la signature.
Performances
À taille égale, la vitesse dépend de la qualité de l’implémentation plutôt que de la courbe. OpenSSL dispose d’un code assembleur optimisé à la main pour P-256 et d’un code générique pour secp256k1 : Node.js 26.10 (OpenSSL 3.6.5) signe donc environ dix fois plus vite avec P-256, soit environ 68 800 contre 6500 signatures par seconde sur un cœur d’Apple M4 Max. En JavaScript pur, le tableau s’inverse légèrement : @noble/curves 2.3.0 signe au même rythme sur les deux courbes et vérifie secp256k1 environ un tiers plus vite, grâce à l’endomorphisme. libsecp256k1 est encore plus rapide. La leçon : mesurez les performances de la bibliothèque que vous allez livrer, pas celles de la courbe.
Des conventions différentes
Les mêmes mathématiques d’ECDSA s’accompagnent de règles différentes dans chaque monde.
- Hachage. P-256 s’associe à SHA-256 (
ES256,ecdsa-with-SHA256). Bitcoin signe des condensats obtenus par un double SHA-256 ; Ethereum signe des condensats Keccak-256, qui ne sont pas des condensats SHA3-256. - Encodage. X.509 et TLS utilisent DER ; JOSE et WebCrypto utilisent
r‖sbrut ; Ethereum ajoute un octet de récupérationv, pour 65 octets au total, et les messages signés de Bitcoin placent un octet d’en-tête au début. - Récupération de la clé publique. Ethereum n’envoie jamais de clés publiques : la récupération (
ecrecover) calcule la clé à partir de la signature, puis l’adresse obtenue est comparée. Les protocoles fondés sur P-256 transmettent ou certifient plutôt la clé. - Low-S. Toute signature ECDSA
(r, s)a une jumelle(r, n − s). La politique de relais de Bitcoin et les règles de transaction d’Ethereum (EIP-2) n’acceptent que la forme low-S ; les vérificateurs P-256 génériques acceptent les deux. - Schnorr. Taproot, dans Bitcoin, a ajouté les signatures Schnorr BIP-340 de 64 octets, avec des clés de 32 octets réduites à la coordonnée x (x-only) sur secp256k1, également utilisées par Nostr. Il n’existe pas de schéma Schnorr standard sur P-256.
Cette malléabilité est facile à démontrer avec Node.js et sa prise en charge de secp256k1, qui repose sur OpenSSL :
import { generateKeyPairSync, sign, verify } from "node:crypto";
// Group order of secp256k1 (SEC 2 §2.4.1).
const n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "secp256k1" });
const message = Buffer.from("hello");
const raw = sign("sha256", message, { key: privateKey, dsaEncoding: "ieee-p1363" });
const r = raw.subarray(0, 32);
const s = BigInt("0x" + raw.subarray(32).toString("hex"));
const flipped = Buffer.concat([r, Buffer.from((n - s).toString(16).padStart(64, "0"), "hex")]);
const check = (sig) => verify("sha256", message, { key: publicKey, dsaEncoding: "ieee-p1363" }, sig);
console.log("(r, s) and (r, n - s) both verify:", check(raw) && check(flipped));
console.log("exactly one of them is low-S:", (s <= n / 2n) !== (n - s <= n / 2n));
(r, s) and (r, n - s) both verify: true
exactly one of them is low-S: true
OpenSSL ne garantit pas la forme low-S à la signature et ne l’exige pas à la vérification : les signatures ainsi obtenues doivent donc être normalisées avant que Bitcoin ou Ethereum ne les acceptent. Le vérificateur de signatures Ethereum signale les valeurs high-S.
Quand choisir l’une ou l’autre
- Web, TLS, clés d’accès, JWT, clés sur mobile et clés d’appareil : P-256, car les plateformes ne proposent rien d’autre dans le matériel.
- Bitcoin, Ethereum et chaînes EVM, Nostr : secp256k1, avec les règles de hachage, d’encodage, de récupération et low-S de la chaîne.
- Faire le pont entre les deux (par exemple, un portefeuille de contrat intelligent contrôlé par une clé d’accès) : gardez chaque courbe dans son couloir. La mise à niveau Fusaka d’Ethereum (décembre 2025) a ajouté EIP-7951, un contrat précompilé de vérification P-256 à l’adresse
0x100qui coûte 6900 unités de gaz, et de nombreux rollups proposent le précompilé compatible RIP-7212 : les contrats peuvent ainsi vérifier directement des signatures de clés d’accès. - Nouveau protocole, choix libre : aucune des deux ; envisagez Ed25519 pour les clés logicielles ou P-256 pour les clés adossées au matériel.
Notes de migration
Les clés ne peuvent pas être converties d’une courbe à l’autre ; changer de courbe implique de nouvelles clés et, dans les blockchains, de nouvelles adresses.
- Ne réutilisez pas de matériel de clé d’une courbe à l’autre. Un secret de 32 octets est une clé privée valide sur les deux courbes, mais les clés publiques qui en résultent n’ont aucun rapport entre elles ; voyez-y un piège, pas une fonctionnalité.
- Si vous déplacez la signature secp256k1 dans un HSM ou un KMS, vérifiez que le type de clé existe, attendez-vous à une sortie DER, convertissez-la en
r‖sbrut, normalisez-la en low-S et calculez vous-même l’identifiant de récupération en essayant les deux parités. - Pour vérifier des signatures P-256 dans un contrat EVM, utilisez une bibliothèque vérifiée ou un contrat précompilé si la chaîne en propose un ; n’écrivez jamais vous-même l’arithmétique modulaire en Solidity.
- Dans JOSE, passer de
ES256KàES256changealg,crvet la clé ; publiez les deux clés avec des valeurskiddistinctes pendant la transition.
Références
- NIST SP 800-186, paramètres de domaine des courbes elliptiques (§3.2.1.3 et annexe H.2)
- SEC 2 v2, paramètres de domaine recommandés pour les courbes elliptiques (§2.4.1, §2.4.2)
- FIPS 186-5, norme de signature numérique
- RFC 8812, ES256K et secp256k1 dans JOSE et COSE
- BIP-340, signatures Schnorr pour secp256k1
- BIP-146, LOW_S et EIP-2
- Référence des spécifications de clé AWS KMS