P-256 vs secp256k1 raramente é uma escolha livre: a curva costuma vir junto com o ecossistema. As duas são curvas de Weierstrass de 256 bits e ordem prima, com cerca de 128 bits de segurança e chaves e assinaturas de tamanhos idênticos, mas diferem na origem, nas plataformas que oferecem suporte a elas e nas convenções construídas por cima delas, e é na passagem de dados entre os dois mundos que os bugs aparecem.
Visão geral
| P-256 (secp256r1, prime256v1) | secp256k1 | |
|---|---|---|
| Especificada em | NIST SP 800-186 §3.2.1.3, SEC 2 §2.4.2 | SEC 2 §2.4.1; permitida pelo SP 800-186, apêndice H.2, para uso em blockchain |
| Equação | y² = x³ − 3x + b sobre p = 2²⁵⁶ − 2²²⁴ + 2¹⁹² + 2⁹⁶ − 1 | y² = x³ + 7 sobre p = 2²⁵⁶ − 2³² − 977 |
| Origem dos parâmetros | b derivado de uma semente SHA-1 nunca explicada | Coeficientes fixos e mínimos (estilo Koblitz) |
| Cofator, segurança | 1, cerca de 128 bits | 1, cerca de 128 bits |
| Chaves e assinaturas | Chave privada de 32 bytes, chave pública de 33/65 bytes, assinatura bruta de 64 bytes | Iguais |
| 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), assinaturas / verificações por segundo | cerca de 68.800 / 27.200 | cerca de 6.500 / 7.200 |
| @noble/curves 2.3.0, assinaturas / verificações por segundo | cerca de 3.800 / 870 | cerca de 3.800 / 1.180 |
| WebCrypto, TLS 1.3, WebAuthn | Sim | Não |
| Secure Enclave da Apple, cartões PIV, a maioria dos HSMs | Sim | Raramente (o AWS KMS oferece ECC_SECG_P256K1) |
| Usada por | Certificados TLS, chaves de acesso, JWTs, identidade de dispositivos | Bitcoin, Ethereum, Nostr, a maioria das cadeias EVM |
Medições em um núcleo de um Apple M4 Max.
Origem e confiança
A P-256 foi publicada pelo NIST em 1999 e padronizada no FIPS 186-2 (2000) e, pelo SECG, como secp256r1. O primo dela tem uma forma especial que permite uma redução rápida, e o coeficiente b foi gerado a partir de uma semente por meio do SHA-1, como prescrevia o procedimento “verificavelmente aleatório” da época. A origem da semente nunca foi explicada, o que, depois das revelações sobre o Dual_EC_DRBG, levou alguns projetistas a desconfiar das curvas do NIST. Nenhum ataque à P-256 baseado nessa semente foi encontrado até hoje, e ela continua sendo a curva mais escrutinada entre as que estão em uso.
A secp256k1 vem do SEC 2 (2000). Com a = 0 e b = 7, não há nada a esconder, e a estrutura especial dela fornece um endomorfismo de cálculo eficiente (o método GLV) que acelera a multiplicação escalar. Satoshi Nakamoto a escolheu para o Bitcoin em 2009, uma escolha incomum na época, e o Ethereum seguiu o mesmo caminho. O NIST SP 800-186 (2023) permite explicitamente a secp256k1 “em aplicações relacionadas a blockchain”.
As duas curvas têm ordem prima, então não há sutilezas de cofator, e as duas caem da mesma forma diante do algoritmo de Shor.
Suporte em plataformas e bibliotecas
Esta é a diferença real. A P-256 está embutida em tudo o que gerencia chaves para você: o WebCrypto em todos os navegadores, as pilhas TLS de todos os sistemas operacionais, o Secure Enclave e o CryptoKit da Apple, o Android Keystore, o TPM 2.0, os cartões inteligentes PIV e todos os KMS de nuvem. As chaves de acesso a usam por padrão, e os Baseline Requirements do CA/Browser Forum a permitem em certificados publicamente confiáveis.
A secp256k1 não está no WebCrypto nem no TLS 1.3 (a RFC 8422 já tinha descontinuado o identificador dela no TLS 1.2), e as bibliotecas de uso geral a tratam como algo secundário. Por isso, o software de blockchain depende de implementações dedicadas: a libsecp256k1 do Bitcoin Core, de tempo constante, e, fora dele, @noble/curves, o k256 do Rust e o go-ethereum/crypto do Go. As carteiras de hardware oferecem suporte a ela; nos HSMs corporativos isso varia, e o AWS KMS a oferece como a especificação de chave ECC_SECG_P256K1, apenas para assinatura.
Desempenho
Com tamanhos iguais, a velocidade depende da qualidade da implementação, e não da curva. O OpenSSL tem assembly otimizado à mão para a P-256 e código genérico para a secp256k1, então o Node.js 26.10 (OpenSSL 3.6.5) assina cerca de dez vezes mais rápido com a P-256: cerca de 68.800 contra 6.500 assinaturas por segundo em um núcleo do Apple M4 Max. Em JavaScript puro, o quadro se inverte um pouco: a @noble/curves 2.3.0 assina na mesma taxa nas duas curvas e verifica a secp256k1 cerca de um terço mais rápido, graças ao endomorfismo. A libsecp256k1 é ainda mais rápida. A lição: faça o benchmark da biblioteca que você vai colocar em produção, não da curva.
Convenções que diferem
A mesma matemática do ECDSA vem acompanhada de regras diferentes em cada mundo.
- Hash. A P-256 é combinada com SHA-256 (
ES256,ecdsa-with-SHA256). O Bitcoin assina digests de SHA-256 duplo; o Ethereum assina digests Keccak-256, que não são SHA3-256. - Codificação. O X.509 e o TLS usam DER; o JOSE e o WebCrypto usam
r‖sbruto; o Ethereum acrescenta um byte de recuperaçãov, chegando a 65 bytes no total, e as mensagens assinadas do Bitcoin colocam um byte de cabeçalho na frente. - Recuperação da chave pública. O Ethereum nunca envia chaves públicas: a recuperação (
ecrecover) calcula a chave a partir da assinatura, e o endereço é comparado. Os protocolos com P-256, em vez disso, transmitem ou certificam a chave. - Low-S. Toda assinatura ECDSA
(r, s)tem uma gêmea(r, n − s). A política de retransmissão do Bitcoin e as regras de transação do Ethereum (EIP-2) aceitam apenas a forma low-S; verificadores genéricos de P-256 aceitam as duas. - Schnorr. O Taproot do Bitcoin acrescentou assinaturas Schnorr BIP-340 de 64 bytes, com chaves x-only de 32 bytes, na secp256k1, também usadas pelo Nostr. Não existe um esquema Schnorr padronizado na P-256.
A maleabilidade é fácil de demonstrar com o Node.js e o suporte dele à secp256k1, baseado no 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
O OpenSSL não produz nem exige low-S, então assinaturas feitas assim precisam ser normalizadas antes que o Bitcoin ou o Ethereum as aceitem. O verificador de assinaturas Ethereum sinaliza valores high-S.
Quando escolher cada uma
- Web, TLS, chaves de acesso, JWTs, chaves de celulares e de dispositivos: P-256, porque as plataformas não oferecem outra coisa em hardware.
- Bitcoin, Ethereum e cadeias EVM, Nostr: secp256k1, com as regras de hash, codificação, recuperação e low-S da cadeia.
- Ponte entre as duas (por exemplo, uma carteira de contrato inteligente controlada por uma chave de acesso): mantenha cada curva no seu próprio mundo. A atualização Fusaka do Ethereum (dezembro de 2025) acrescentou a EIP-7951, um contrato pré-compilado de verificação de P-256 no endereço
0x100, com custo de 6.900 unidades de gás, e muitos rollups oferecem o pré-compilado compatível RIP-7212, então os contratos podem verificar assinaturas de chaves de acesso diretamente. - Um protocolo novo, com escolha livre: nenhuma das duas; considere o Ed25519 para chaves em software ou a P-256 para chaves protegidas por hardware.
Notas de migração
Não é possível converter chaves de uma curva para a outra; trocar de curva significa chaves novas e, nas blockchains, endereços novos.
- Não reutilize material de chave entre curvas. Um segredo de 32 bytes é uma chave privada válida nas duas curvas, mas as chaves públicas resultantes não têm relação entre si; trate isso como uma armadilha, não como um recurso.
- Ao levar a assinatura com secp256k1 para um HSM ou KMS, confirme que o tipo de chave existe, espere saída em DER, converta para
r‖sbruto, normalize para low-S e calcule você mesmo o ID de recuperação testando as duas paridades. - Ao verificar assinaturas P-256 em um contrato EVM, use uma biblioteca verificada ou um pré-compilado, onde a cadeia oferecer um; nunca implemente aritmética modular à mão em Solidity.
- No JOSE, trocar
ES256KporES256mudaalg,crve a chave; publique as duas chaves com valores dekiddistintos durante a transição.
Referências
- NIST SP 800-186, parâmetros de domínio de curvas elípticas (§3.2.1.3 e apêndice H.2)
- SEC 2 v2, parâmetros de domínio recomendados para curvas elípticas (§2.4.1, §2.4.2)
- FIPS 186-5, padrão de assinatura digital
- RFC 8812, ES256K e secp256k1 em JOSE e COSE
- BIP-340, assinaturas Schnorr para secp256k1
- BIP-146, LOW_S e EIP-2
- Referência de especificações de chave do AWS KMS