Выбор между детерминированным и рандомизированным ECDSA касается одного значения — одноразового числа nonce k, своего для каждой подписи. От его качества зависит, останется ли закрытый ключ в секрете: чтобы вычислить ключ, достаточно одного повторившегося nonce или небольшого смещения в распределении nonce по множеству подписей. FIPS 186-5 допускает два способа его получения, а третий, хеджированное подписание (hedged signing), объединяет их.
Коротко о главном
| Рандомизированный | Детерминированный (RFC 6979) | Хеджированный | |
|---|---|---|---|
| Источник nonce | Новый результат CSPRNG для каждой подписи | HMAC-DRBG от закрытого ключа и хеша сообщения | Детерминированный вывод с добавлением свежих случайных данных |
| Стандарт | FIPS 186-5, § 6.3.1, приложения A.3.1 и A.3.2 | RFC 6979, § 3.2; FIPS 186-5, § 6.3.2 и приложение A.3.3 | Опция из RFC 6979, § 3.6; черновик CFRG с истёкшим сроком действия; вспомогательная случайность в BIP-340 |
| Одно сообщение подписано дважды | Разные подписи | Одинаковые подписи | Разные подписи |
| Слабый или неисправный ГСЧ | Ключ может утечь | Не влияет | Не влияет |
| Внесение сбоев при повторном подписании | Атака затруднена | Ключ может утечь | Атака затруднена |
| Воспроизводимые тестовые векторы | Нет | Да (RFC 6979, приложение A.2) | Только с фиксированными дополнительными входными данными |
| Изменения у проверяющей стороны | Не нужны | Не нужны | Не нужны |
| По умолчанию в | OpenSSL, Node.js, Java, Python cryptography | libsecp256k1, @noble/curves | Включается явно: @noble/curves с extraEntropy: true, подписание по BIP-340 |
Когда каждый способ даёт сбой
Рандомизированные nonce полностью зависят от генератора случайных чисел. Если он повторяет значение (в PlayStation 3 от Sony использовалась константа), ключ вычисляется простой алгеброй. Если его выход всего лишь смещён (например, старшие биты всегда нулевые или побочный канал по времени выполнения выдаёт длину nonce), методы на основе решёток, решающие задачу скрытого числа, восстанавливают ключ по выборке от нескольких сотен до нескольких тысяч подписей; именно это сделали атаки Minerva и TPM-Fail (2019) против смарт-карт и TPM. Классическая группа риска — встраиваемые устройства, которые подписывают вскоре после загрузки, клонированные виртуальные машины и процессы, порождённые вызовом fork.
Детерминированные nonce исключают генератор из процесса: k выводится с помощью HMAC из закрытого ключа и хеша сообщения, поэтому одни и те же входные данные всегда дают один и тот же nonce, а разные сообщения — никак не связанные между собой nonce. Риск смещается в сторону физических атак. Если атакующий может вызвать сбой в работе устройства, пока оно дважды подписывает одно и то же сообщение, одна верная и одна ошибочная подпись с одним и тем же nonce способны раскрыть ключ; Poddebniak и соавторы продемонстрировали такие атаки с внесением сбоев на детерминированные ECDSA и EdDSA в 2018 году. Кроме того, детерминированное подписание делает подписи повторяемыми: одним протоколам это нужно, а для других это утечка информации, которую допускать нельзя.
Хеджированные nonce выводятся и из детерминированных входных данных, и из свежих случайных данных. При неисправном генераторе схема сводится к детерминированному подписанию, а атака с внесением сбоев каждый раз сталкивается с новым nonce. RFC 6979, § 3.6 уже допускает дополнительные входные данные, BIP-340 рекомендует 32 байта вспомогательных случайных данных, ML-DSA (FIPS 204, § 3.4) по умолчанию работает в хеджированном режиме, а срок действия черновика IRTF о стандартизации хеджированных ECDSA и EdDSA истёк в 2025 году, и RFC он так и не стал.
Все три способа дают обычные подписи. Проверяющая сторона не может их различить, а значит, и стратегию выбора nonce у подписанта нельзя проверить по его подписям, разве что заметив, что одинаковые сообщения дают одинаковые подписи.
Поведение библиотек
- OpenSSL по умолчанию подписывает со случайными nonce. В OpenSSL 3.2 (ноябрь 2023 года) появилась поддержка RFC 6979 через параметр подписи
nonce-typeсо значением 1, для которого нужно явно указать дайджест, а в OpenSSL 3.6 детерминированный ECDSA появился в FIPS-провайдере. В командной строке:openssl pkeyutl -sign -pkeyopt nonce-type:1 -pkeyopt digest:sha256. - Python
cryptographyпо умолчанию подписывает со случайными nonce, а с версии 43.0 (июль 2024 года) поддерживаетec.ECDSA(hashes.SHA256(), deterministic_signing=True). - Node.js
crypto.sign()и WebCrypto используют случайные nonce, и изменить это нельзя. - @noble/curves по умолчанию выводит
kпо RFC 6979, а при вызове сextraEntropy: trueили с дополнительными байтами переходит в хеджированный режим. - libsecp256k1, которую использует Bitcoin Core, применяет RFC 6979 с необязательными дополнительными данными.
- EdDSA детерминирован по определению (RFC 8032), но некоторые платформенные реализации всё равно добавляют случайность.
Разницу видно на нескольких строках Python с cryptography 46.0.3:
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
key = ec.generate_private_key(ec.SECP256R1())
message = b"invoice 2026-10-20 #4411"
randomized = [key.sign(message, ec.ECDSA(hashes.SHA256())) for _ in range(2)]
deterministic = [
key.sign(message, ec.ECDSA(hashes.SHA256(), deterministic_signing=True)) for _ in range(2)
]
print("randomized signatures equal: ", randomized[0] == randomized[1])
print("deterministic signatures equal:", deterministic[0] == deterministic[1])
for sig in randomized + deterministic:
key.public_key().verify(sig, message, ec.ECDSA(hashes.SHA256()))
print("all four verify with the same verifier")
randomized signatures equal: False
deterministic signatures equal: True
all four verify with the same verifier
Тестирование и воспроизводимость
Детерминированное подписание делает возможными тесты с известным ответом (known-answer tests): в приложении A.2 к RFC 6979 перечислены ожидаемые подписи для кривых от P-192 до P-521 и других, и на таких векторах построены инструмент для генерации тестовых векторов и Project Wycheproof. При рандомизированном или хеджированном подписании можно проверить только то, что подписи проходят проверку, а искажённые — нет. При аудите детерминированный режим помогает проверить и подозрительного подписанта: подпишите с его помощью одно и то же сообщение дважды и посмотрите, повторится ли результат.
Чтобы обнаружить фактическое повторное использование nonce в уже имеющихся подписях, сравните значения r в подписях, сделанных одним ключом: повторившийся r означает повторившийся nonce. Средство проверки повторного использования nonce делает это сразу для набора подписей.
Что когда выбирать
- Серверы и CI с исправным генератором ОС: подходит любой из трёх способов; лучше выбрать детерминированный или хеджированный, чтобы избавиться от одной зависимости.
- Встраиваемые устройства, код ранней загрузки, клонированные виртуальные машины: детерминированный или хеджированный, но никогда не чисто случайный.
- Оборудование, доступное атакующим (аппаратные кошельки, смарт-карты, платёжные терминалы): хеджированный вместе с защитой от сбоев, например с проверкой каждой подписи перед тем, как её выдать.
- Наборы тестов и проверка совместимости: детерминированный, чтобы векторы были воспроизводимы.
- Протоколы, в которых повторяющиеся одинаковые подписи раскрыли бы информацию (например, что то же сообщение подписали ещё раз): рандомизированный или хеджированный.
Заметки о миграции
Смена стратегии выбора nonce затрагивает только подписанта. Ключи, форматы подписей и проверяющая сторона остаются прежними.
- Проверьте поддержку в библиотеке и версии: OpenSSL 3.2 или новее,
cryptography43 или новее либо библиотека со встроенной поддержкой RFC 6979. - Убедитесь, что дайджест задан явно, когда включаете RFC 6979: от него зависит вывод nonce.
- Добавьте регрессионный тест, который дважды подписывает одно сообщение и проверяет ожидаемое поведение (для детерминированного режима подписи совпадают, для хеджированного — различаются).
- Всё равно следите за качеством случайности: хеджированному подписанию хороший генератор по-прежнему полезен, а для генерации ключей он нужен всегда.
- Проверьте все места, где подписи сравниваются или кешируются: с детерминированными подписями правило «одинаковые входные данные — одинаковый результат» впервые становится верным.
Источники
- RFC 6979: детерминированное использование DSA и ECDSA (§ 3.2, § 3.6, приложение A.2)
- FIPS 186-5, § 6.3: секретное число для каждого сообщения
- FIPS 204, § 3.4: хеджированное и детерминированное подписание
- draft-irtf-cfrg-det-sigs-with-noise (Internet-Draft с истёкшим сроком действия)
- BIP-340: подписание по умолчанию со вспомогательными случайными данными
- Minerva: атаки на основе решёток, использующие утечку nonce в ECDSA
- OpenSSL CHANGES (3.2.0: поддержка RFC 6979)
- Журнал изменений pyca/cryptography (43.0.0: детерминированный ECDSA)