elliptic は、NIST 曲線と secp256k1 による ECDSA、そして Ed25519 を、bn.js を基盤とする素の JavaScript で実装しています。crypto-browserify、古い Ethereum や Bitcoin のライブラリ、Webpack 4 がブラウザー向けバンドルに注入していた Node.js のポリフィルを通じて広まったため、今でもロックファイルに現れます。ethers v6 と viem は代わりに @noble/curves を基盤にしています。こちらは同じ曲線に、より厳格なデフォルトで対応しています。
API は多くのライブラリと 3 つの点で異なり、それが相互運用のバグの原因になります。まず、sign() はメッセージではなくダイジェストを受け取り、渡されたバイト列をそのままダイジェストとして扱います。チェックでは、生のメッセージに署名すると、その SHA-256 に署名した場合とは異なる署名になりました。次に、戻り値は r、s、recoveryParam を持つ Signature オブジェクトなので、送受信する形式はシリアライズの方法次第です。OpenSSL 方式の相手には toDER() を、生の r‖s には両方の値を 32 バイトにパディングしたものを使います。そして、canonical: true を渡さない限り s は正規化されず、検証は low-S と high-S のどちらも受け入れます。
nonce は RFC 6979 に従っており、P-256 のテストベクトルも正確に再現できました。しかし、6.6.1 でも未解決のアドバイザリ GHSA-848j-6mx2-7j84(CVE-2025-14505)は、途中の値の先頭にゼロのバイトがあるとその値が切り詰められると報告しています。チェックでもこれを再現できました。SHA-512 を使う P-521 では、2,048 個の固定入力のうち 9 個で RFC 6979 とは異なる nonce が生成されました。一方、SHA-256 を使う secp256k1 と SHA-512 を使う P-256 では、それぞれ 4,096 個の入力で差異はありませんでした。こうした署名はそれでも検証を通りますが、同じ鍵で同じメッセージに別の RFC 6979 実装で署名すると、関連した nonce が生じます。アドバイザリによれば、これにより鍵が漏洩するおそれがあります。P-521 には elliptic を使わないでください。関連した nonce がなぜ問題になるかは、nonce 再利用チェッカーを参照してください。
それ以前のアドバイザリは 6.5.7〜6.6.1 で修正されています。その中には、BER エンコードの署名を受け入れてしまう問題や、ハッシュの代わりに文字列に署名したときに鍵を抽出できてしまうバグが含まれます。チェックでは、6.6.1 は先頭に冗長なゼロを含む DER 署名を拒否しました。鍵は 16 進数の文字列またはバイト配列(圧縮形式または非圧縮形式の SEC1 の点と、生のスカラー)で、PEM、SPKI、JWK には対応していません。
サンプルでは、先にハッシュを計算し、正規化された low-S 署名を指定して、両方のシリアライズ形式を示しています。elliptic で作った署名が他の環境で失敗する場合は、DER ⇄ 生形式の変換ツールで 2 つのエンコーディングを比較してください。