O elliptic implementa ECDSA sobre as curvas do NIST e a secp256k1, além do Ed25519, em JavaScript puro sobre o bn.js. Ele se espalhou por meio do crypto-browserify, de bibliotecas mais antigas de Ethereum e Bitcoin e dos polyfills do Node.js que o Webpack 4 injetava nos bundles de navegador, e é por isso que ainda aparece em arquivos de lock. O ethers v6 e o viem usam, em vez dele, a @noble/curves, que cobre as mesmas curvas com padrões mais rigorosos.
A API difere da maioria das bibliotecas em três pontos que causam bugs de interoperabilidade. sign() recebe o digest, não a mensagem, e trata quaisquer bytes que receber como esse digest — o teste assinou uma mensagem bruta e obteve uma assinatura diferente da obtida para o SHA-256 dela. Ele retorna um objeto Signature com r, s e recoveryParam, então o formato de transmissão é o que você serializar: toDER() para sistemas no estilo do OpenSSL, ou os dois valores preenchidos até 32 bytes para r‖s bruto. E o s não é normalizado, a menos que você passe canonical: true, enquanto a verificação aceita as duas metades.
Os nonces seguem a RFC 6979 — o vetor de teste da P-256 foi reproduzido exatamente —, mas o alerta de segurança GHSA-848j-6mx2-7j84 (CVE-2025-14505), ainda em aberto para a versão 6.6.1, relata que um valor intermediário é truncado quando tem bytes zero à esquerda. O teste reproduziu o problema: na P-521 com SHA-512, 9 de 2.048 entradas fixas produziram um nonce diferente do da RFC 6979, enquanto secp256k1 com SHA-256 e P-256 com SHA-512 não mostraram diferença em 4.096 entradas cada. Essas assinaturas continuam passando na verificação, mas assinar a mesma mensagem com a mesma chave em outra implementação da RFC 6979 gera nonces relacionados, o que, segundo o alerta, pode expor a chave. Evite o elliptic para P-521 e veja no verificador de reutilização de nonce por que nonces relacionados importam.
Alertas anteriores foram corrigidos da 6.5.7 à 6.6.1, entre eles a aceitação de assinaturas com codificação BER e um bug de extração da chave quando uma string era assinada no lugar de um hash; no teste, a 6.6.1 rejeitou uma assinatura DER com um zero à esquerda redundante. As chaves são strings hexadecimais ou arrays de bytes — pontos SEC1, comprimidos ou não comprimidos, e escalares brutos —, sem suporte a PEM, SPKI ou JWK.
O exemplo calcula o hash primeiro, pede uma assinatura low-S canônica e mostra as duas serializações. Quando uma assinatura do elliptic falhar em outro lugar, compare as duas codificações dela no conversor DER ⇄ bruto.