О чем статья

На просторах интернета есть несколько статей об алгоритме получения хеш-функции Стрибог (ГОСТ 34.11-2012), в том числе и на Хабре. Однако везде в качестве примера приводится реализация на языках программирования C, C#, Python и других. То есть идет последовательное выполнение операций алгоритма. В данной статье я хочу затронуть аппаратную реализацию на языке System Verilog, уделить внимание распараллеливанию вычислений и описанию интерфейсов модулей. Для начала кратко рассмотрим теорию.

Краткая теория

Основу алгоритма составляют последовательное исполнение так называемой g функции и функции сложения в кольце. Структурную схему можно увидеть на рисунке 1. Подробную теорию и математическое описание можно почитать в ГОСТ 34.11—2012 или в этой статье. Мы же рассмотрим, что подается на вход и получается на выходе. А далее рассмотрим практическую реализацию.

Рисунок 1. Структурная схема хеш-функции Стрибог
Рисунок 1. Структурная схема хеш-функции Стрибог

Сложение в кольце

На рисунке обозначено sc(a,b). В данной функции 512-разрядный вход а складывается с 512-разрядным входом b, результат пишется в 512 разрядный выход s. Если есть переполнение, то оно отбрасывается.

G функция

На рисунке обозначено g(m,h,n).

m – это входной массив данных, для которого считается хеш-функция, разбитый по 512 бит. Если последний кусочек меньше 512 бит, то оно сразу дополняется нулями с единичкой в первом дополнительном разряде до полных 512 бит;

h – это выход функции от предыдущей итерации, если итерация первая, то подается инициализационное значение V0 = `{64{8`h00}} или V0 = `{64{8`h01}} ;

n – количество бит исходного сообщения в 512 битном кусочке. Для целого кусочка значения будет 512 бит;

Если исходный массив больше 512 бит, то вычисления состоят из трех этапов :

  • Инициализация

  • Рекурсия

  • Дополнение

Если исходный массив меньше или равен 512 бит, то вычисления состоят из двух этапов :

  • Инициализация

  • Дополнение

Хеш-функция «Стрибог» может иметь две реализации с результирующим значением длиной 256 или 512 бит. Для реализации 512 бит на этапе инициализации V0 = `{64{8`h00}}, для реализации 256 бит на этапе инициализации V0 = `{64{8`h01}}, а c выхода последней g функции берутся старшие 256 бит.

Рассмотрим внутреннее устройство g функции. Структурная схема представлена на рисунке 2. Данная функция состоит из LPSX функций и операций исключающего “ИЛИ”. Кроме того, используется массив итерационных констант, который используется для входного аргумента b функции LPSX на итерациях с 1 по 12. Значения констант из массива приведено в ГОСТ 34.11-2012.

Рисунок 2. Структурная схема G функции
Рисунок 2. Структурная схема G функции

LPSX-функция

Структурная схема представлена на рисунке 3. Функция LPSX представляет из себя алгоритм преобразования и перестановки байт, который можно реализовать последовательно через функции X,S,P,L про которые можно подробно почитать здесь или здесь. Преобразования S и L можно выполнить заранее и сформировать восемь массивов по 256 восьмибайтовых чисел, в которых будут содержаться все возможные значения этих двух преобразований. Помимо этого, при вычислении хеш‑суммы с использованием заранее рассчитанных значений можно сразу сделать и нужные перестановки в соответствии с преобразованием P. Таким образом последовательные преобразования LPSX можно заменить одним преобразованием PRECALC с массивом заранее расчитанных значений.

Рисунок 3. Структурные схемы LPSX функций
Рисунок 3. Структурные схемы LPSX функций

Аппаратная реализация

Распараллеливание вычислений

В отличие от программной реализации, аппаратная реализация в ПЛИС или ASIC позволяет распараллеливать вычисления. Так, на верхнем уровне параллельно и независимо друг от друга в каждой итерации производятся вычисления в двух функциях суммирования по модулю 2 и вычисление g функции. Если посмотреть на структурную схему реализации g функции, то можно заметить, что вычисление LPSX функций от входа n и массива констант C идет независимо от вычисления LPSX функций от входа m (см. рисунок 2). Следовательно, при вычислении g функции можно создать два экземпляра LPSX функций, которые будут работать параллельно, производя по 12 итераций до получения выходного значения g функции. Схематично такая реализация представлена на рисунке 4.

Рисунок 4. Структурная схема распараллеливания вычислений LPSX функций внутри G функции
Рисунок 4. Структурная схема распараллеливания вычислений LPSX функций внутри G функции

Описание интерфейсов

Для каждой функции приведу интерфейс для реализации на языке описания аппаратуры Verilog или VHDL, а также диаграмму сигналов.

LPSX-функция

Представляет из себя регистровый конвейер вычислений. На вход подаются данные и сигнал валидности. На выходе преобразованные данные и сигнал валидности.

Рисунок 5. Интерфейс LPSX-функции
Рисунок 5. Интерфейс LPSX-функции
Рисунок 6. Временная диаграмма LPSX-функции

G функция

Представляет из себя регистровый конвейер вычислений. На вход подаются данные и сигнал валидности. На выходе преобразованные данные и сигнал валидности.

Рисунок 7. Интерфейс G-функции
Рисунок 7. Интерфейс G-функции
Рисунок 8. Временная диаграмма G-функции
Рисунок 8. Временная диаграмма G-функции

Функция сложения в кольце

Представляет из себя регистровый конвейер вычислений. На вход подаются данные и сигнал валидности. Поскольку идет суммирование входного числа с результатом предыдущего вычисления, то удобнее оставить один вход данных и добавить сигнал очистки модуля clear_i.

Рисунок 9. Интерфейс функции сложения в кольце
Рисунок 9. Интерфейс функции сложения в кольце
Рисунок 10. Временная диаграмма функции сложения в кольце
Рисунок 10. Временная диаграмма функции сложения в кольце

Модуль верхнего уровня

Представляет из себя регистровый конвейер вычислений. На модуль приходят 5 групп сигналов:

  • системные – частота и сброс

  • настройки – выбор длины хеша

  • входные данные – данные с рукопожатием valid/ready, а также флаг последнего сообщения и количество значимых бит в последнем сообщении

  • управление – запрос на старт работы автоматов модуля и подтверждение выставляемое после получения хеша

  • выходные данные — данные с рукопожатием valid/ready

    Рисунок 11. Интерфейс модуля верхнего уровня хеш-функции Стрибог
    Рисунок 11. Интерфейс модуля верхнего уровня хеш-функции Стрибог
    Рисунок 12. Временная диаграмма модуля верхнего уровня хеш-функции Стрибог
    Рисунок 12. Временная диаграмма модуля верхнего уровня хеш-функции Стрибог

Заключение. Описание исходников

Исходные файлы хеш-функции Стрибог на языке System Verilog находятся в моем репозитории git. Также там представлен тестбенч с примерами из ГОСТа. Для запуска симуляции в программе QuestaSim необходимо выполнить:

в консольном режиме для реализации без предвычислений,

make run_questa_console

в консольном режиме для реализации c предвычислениями,

make precalc=1 run_questa_console

в графическом режиме для реализации без предвычислений,

make run_questa_gui

в графическом режиме для реализации c предвычислениями.

make precalc=1 run_questa_gui

Комментарии (19)


  1. Brak0del
    02.04.2024 02:39
    +3

    Круто! Если не секрет, какие получились характеристики: сколько оно заняло по ресурсам (ПЛИС), на какой частоте, какую производительность в МБ/с имеет?


    1. mpa4b
      02.04.2024 02:39

      И ещё бы хорошо в сравнении с более традиционными хешами, например sha256/sha512, ну и например sha3, skein, blake.


      1. iDoka
        02.04.2024 02:39
        +1

        Имплементировал его во времена лихорадки.

        Если вам нужен результат каждый такт (конвейер), то хэша хуже Стрибога придумать сложно.

        Процитирую себя самого же с Электроникса:

        Sboxes на BRAM (утилизация BRAM свыше 3000 шт).


        1. Brak0del
          02.04.2024 02:39

          Интересная инфа, спасибо!


        1. mpa4b
          02.04.2024 02:39
          +1

          Лично я не знаю традиционного криптохеша, который мог бы принимать данные каждый такт. Ну кроме читов вроде буферизации по 1 байтику или всяких распараллеливаний по 4к или деревом. А вот штуки, пригодные только для MACа, типа того, что в aes-gcm или chacha20-poly1305 -- теоретически (и зачастую практически) могут. Но они не полноценные хеши.


          1. Brak0del
            02.04.2024 02:39

            Лично я не знаю традиционного криптохеша, который мог бы принимать данные каждый такт.

            В примере из Электроникса, насколько понимаю, ограниченная постановка: хэшируют блоки фиксированной длины 64 байта, а не произвольной.


            1. mpa4b
              02.04.2024 02:39

              Ну, если хешировать куски данных размером в 1 блок хеша, тогда конечно можно. Но это бессмысленно, т.к. обычно хешируются всё же сообщения в несколько блоков хеша. Иногда в очень много.


        1. mpa4b
          02.04.2024 02:39

          Sboxes на BRAM (утилизация BRAM свыше 3000 шт).

          А если логикой?


    1. rvvernin Автор
      02.04.2024 02:39
      +1

      Синтезизировал данный модуль в вивадо для ПЛИС xcvu19p-fsva3824-2-e, по ресурсам получилась следующая картинка.

      По частоте синтез проходит на 400 МГц. Но в принципе можно и выше поднять у меня пока кольцевое суммирование идет за 1 такт, но там есть запас в 29 тактов на выполнение g - функции, и соответвенно суммирование можно конвейеризировать. В целом на вычисление хеша для одного 512 битного слова нужно 29 тактов в варианте с предвычислениями. По поводу производительности - это сильно зависит в целом от архитектуры системы - откуда, куда и как передаем данных.


      1. Brak0del
        02.04.2024 02:39

        Полезная инфа, спасибо!


  1. aystarik
    02.04.2024 02:39

    smod2(a,b) -- это разве не xor?


    1. rvvernin Автор
      02.04.2024 02:39

      В данном случае это операция сложения в кольце, если брать формулировку из ГОСТ. Но в целом вы правы суммирование по модулю 2 это XOR. Я поправил статью, теперь более корректное название функции. Спасибо за замечание.


      1. aystarik
        02.04.2024 02:39

        вроде как и в стрибоге это xor -- по вашей ссылке на c++ реализацию...

        "X-преобразование. На вход функции X подаются две последовательности длиной 512 бит каждая, выходом функции является XOR этих последовательностей."


        1. rvvernin Автор
          02.04.2024 02:39

          X преобразование входит в LPSX функцию (рис. 3). У меня это обозначено как XOR(a,b). А кольцевое суммирование идёт на верхнем уровне (рис. 1) . В статье на которую ссылаетесь это ... "

          5.Вычислить N = (N + |M|) mod 2 512

          6.Вычислить Σ = (Σ + m) mod 2 512 "


  1. deafcafe
    02.04.2024 02:39

    В 2013 на Delphi дипломную работу делал, Стрибог, подпись на тестовых эллиптических кривых (512-битная), сейчас флешбек словил.


  1. bk_space
    02.04.2024 02:39

    Здорово!

    Единственное, что пока вызывает вопросы - верификация. Наверное, 4х примеров из госта, как в ващем тестбенче, не хватит чтобы полноценно верифицировать блок.

    Но тогда наверное придётся подумать как нагенерировать еще валидных примеров (есть ли код, например на C, в правильности которого уже никто не станет сомневаться)?

    Автору успехов)


  1. rvvernin Автор
    02.04.2024 02:39

    Согласен. Здесь речь идет не о верификации, а лишь о первичной проверки работоспособности. Для верификации необходима, так называемая, gold model (например на C или на несинтезируемых конструкция system verilog), с которой можно сранивать результаты. Причем правильно если написанием rtl и верификацией занимаются разные люди.


  1. kuznet1
    02.04.2024 02:39

    Интересно, для чего потребовалось реализовывать Стрибог в FPGA, неужели сделали криптовалюту с консенсусом на ней?


    1. rvvernin Автор
      02.04.2024 02:39

      В моем случае это кусочек ip блока для ASIC. Сценарии применения еще прорабатываются.