elliptic реализует на обычном JavaScript поверх bn.js ECDSA на кривых NIST и secp256k1, а также Ed25519. Библиотека распространилась через crypto-browserify, старые библиотеки для Ethereum и Bitcoin и полифилы Node.js, которые Webpack 4 встраивал в браузерные бандлы, поэтому она до сих пор встречается в lock-файлах. ethers v6 и viem вместо неё используют @noble/curves: эта библиотека поддерживает те же кривые и имеет более строгие настройки по умолчанию.
API библиотеки отличается от большинства других тремя особенностями, из-за которых возникают ошибки совместимости. sign() принимает дайджест, а не сообщение, и считает дайджестом любые переданные ему байты: при проверке подпись исходного сообщения отличалась от подписи его SHA-256. Метод возвращает объект Signature с полями r, s и recoveryParam, поэтому формат передачи зависит от того, как вы его сериализуете: toDER() для сторон в стиле OpenSSL или оба значения, дополненные до 32 байт, для raw r‖s. Наконец, s не нормализуется, если не передать canonical: true, а проверка принимает значения s из обеих половин диапазона.
Nonce вычисляются по RFC 6979 (тестовый вектор для P-256 воспроизвёлся точно), но бюллетень безопасности GHSA-848j-6mx2-7j84 (CVE-2025-14505), который для 6.6.1 всё ещё открыт, сообщает, что промежуточное значение усекается, если начинается с нулевых байтов. Проверка это подтвердила: на P-521 с SHA-512 для 9 из 2 048 фиксированных наборов входных данных nonce отличался от RFC 6979, тогда как для secp256k1 с SHA-256 и P-256 с SHA-512 расхождений не нашлось ни на одном из 4 096 наборов в каждом случае. Такие подписи всё равно проходят проверку, но если подписать то же сообщение тем же ключом другой реализацией RFC 6979, получатся связанные nonce, а это, по данным бюллетеня, может раскрыть ключ. Не используйте elliptic для P-521; почему связанные nonce опасны, объясняет проверка повторного использования nonce.
Проблемы из более ранних бюллетеней исправлены в версиях с 6.5.7 по 6.6.1, среди них приём подписей в кодировке BER и ошибка, позволявшая извлечь ключ, если вместо хеша подписывалась строка; в ходе проверки версия 6.6.1 отклонила подпись DER с лишним ведущим нулём. Ключи задаются строками hex или массивами байтов — это сжатые или несжатые точки SEC1 и скаляры в формате raw; PEM, SPKI и JWK не поддерживаются.
Пример сначала хеширует сообщение, запрашивает каноническую подпись low-S и показывает обе сериализации. Если подпись из elliptic не проходит проверку в другом месте, сравните две её кодировки в конвертере DER ⇄ raw.