На этой неделе постараюсь уже закончить с RSA подписями, так как со следующей планирую уйти в долгий и долгожданный отпуск, о чем писал уже ранее. А пока что, продолжаем!
Использование только 256 бит небезопасно
Для прояснения ситуации: количество «бит» относится к размеру открытого ключа. Поэтому, когда мы говорим «RSA 2048», это означает, что число n, модуль, имеет 2048 бит. Сравнивая размеры ключей, важно помнить, что каждый дополнительный бит удваивает размер числа. Таким образом, 700 бит экспоненциально более безопасны, чем 350 бит, но не в два раза.
Самый большой ключ, который удалось взломать (разложить) на данный момент, состоял из 829 бит, и для этого потребовался современный суперкомпьютер. Команда использовала примерно 2700 процессорных ячеек в год, используя процессор Intel Xeon Gold 6130 с частотой 2,1 ГГц. Стоимость самого дешевого 16-ядерного процессора на AWS составляет 0,40 цента в час, поэтому стоимость взлома этого ключа составляет порядка 9,4 миллиона долларов. Даже при условии щедрых скидок от облачного провайдера стоимость будет исчисляться миллионами.
Модульная арифметика с более чем 256 битами в Solidity
Ethereum поддерживает только 32-байтовые типы данных, поэтому по умолчанию мы не можем выполнить:
s ^ e % n
К счастью, блокчейн ethereum добавил в EIP-198 прекомпилированный контракт специально для поддержки модульной арифметики.
Для его использования необходимо загрузить в память базу, экспоненту и модуль в кодированном формате abi. Затем вызывается контракт, находящийся по адресу 0x05. Хранение открытого ключа становится некоторой проблемой, если вы используете безопасное количество бит. Если размер ключа составляет 1024 бита, то для хранения потребуется 4 слота. Чтобы посчитать открытый ключ из хранилища, потребуется четыре операции SLOAD, что в общей сложности составит 8 400 газа.
Это само по себе уже менее эффективно, чем решение ECDSA, приведенное выше. Если мы используем неизменяемые переменные, эти затраты в значительной степени устраняются, но это создает слабое место, если мы не можем задним числом удалить кого-то из предварительной продажи аирдропа.
В традиционных ECDSA или деревьях Меркла мы бы просто заменили адрес подписи или корень Меркла. Это невозможно, если мы используем неизменяемую переменную. Однако ключевой идеей является хранение открытого ключа в байткоде, а не в памяти. Чтение байткода внешнего контракта (EXTCODECOPY) стоит 2 600 газа, что гораздо меньше, чем 8 400 газа при чтении каждой части открытого ключа в четырех экземплярах. Чтобы аннулировать открытый ключ, мы могли бы просто создать новый контракт и обновить переменную хранения, чтобы она указывала на новый адрес. Но это добавляет еще 2100 газа. И оказывается, что можно хранить адрес внешнего контракта (в байткоде которого хранится открытый ключ) в неизменяемой переменной, но при этом сделать открытый ключ недействительным, изменив байткод внешнего смарт-контракта.
Сложно, но интересно! Дальше больше!
#rsa