Криптографическая хэш-функция CryptoNight

Ruslan Ospanov 08 April 2019 Алгоритмы хэш-функция, криптография 1528

CryptoNight - криптографическая хэш-функция, по умолчанию применяемое для доказательства выполнения работы (Proof-of-Work, PoW) в протоколе CryptoNote.

Описание алгоритма:

1. Инициализация ОЗУ.

1.1. Для входного сообщения вычисляется конечное состояние хэш-функции Keccak с параметрами b=1600 и c=512 (длина строки состояния 1600 бит).

1.2. 0-ой, 1-ый, ..., 31-ый байты вычисленного конечного состояния (256 бит) интерпретируются как 256-битный ключ алгоритма AES-256, из которого генерируются 10 раундовых ключей (алгоритма AES-256).

1.3. Выделяются 2097152 байт (2Мб) ОЗУ.

1.4. 64-ый, ..., 191-ый байты вычисленного конечного состояния (128 байтов) делятся на 8 блоков по 16 байтов каждый.

1.5. Каждый из этих 8 блоков зашифровывается с помощью следующих преобразований:

       for i = 1..10 do:

             block = aes_round(block, round_keys[i]),

       где block - 16-байтный блок, aes_round - раунд алгоритма AES-256 (SubBytes, ShiftRows, MixColumns, AddRoundKey), i - номер раунда, round_keys[i] - раундовый ключ i-го раунда.

1.6. Полученные в результате 8 зашифрованных 16-байтных блоков записываются в первые 128 байтов ОЗУ.

1.7. Далее эти же 8 блоков снова зашифровываются как в шаге 1.5.

1.8. Полученные в результате 8 зашифрованных 16-байтных блоков записываются в следующие 128 байтов ОЗУ.

1.9. Каждый следующий раз в ОЗУ записываются 128 байтов, представляющие собой результат шифрования ранее записанных 128 байт. Этот процесс повторяется до тех пор, пока ОЗУ не будет полностью инициализирован.

2. Memory-Hard Цикл (Memory-Hard Loop).

2.1. 0-ой, 1-ый, ..., 31-ый байты складываются по модулю 2 (XOR) с 32-ым, 33-им, ..., 63-им байтами вычисленного конечного состояния хэш-функции Keccak.

2.2. Полученные в результате 32 байта используются для инициализации двух переменных a и b, каждая по 16 байтов.

Следующая последовательность шагов (2.3- 2.11) повторяется 524288 раз

2.3. С помощью значения переменной а вычисляется адрес 16 байтов в ОЗУ.  Для этого 16 байтовое значение переменной а интерпретируется как бинарное представление целого числа, записанное в порядке от младшего к старшему, и первые 21 младших бит используются как индекс байта в ОЗУ, при этом первые 4 младших бита очищаются для их полного перебора и последовательного получения индексов 16 байтов в ОЗУ.

2.4. 16 байтов (128 бит), записанные в ОЗУ по вычисленному адресу, зашифровываются одним раундом алгоритма AES-256, используюя качестве раундового ключа 16 байтов (128 бит) переменной а.

2.5. Полученные зашифрованные 16 байтов складываются по модулю 2 (XOR) с 16 байтами переменной b, и также эти зашифрованные 16 байтов становятся новым значением переменной b.

2.6. Полученные в результате сложения 16 байтов обратно записываются в ОЗУ по вычисленному адресу.

2.7. С помощью уже нового значения переменной b вычисляется новый адрес 16 байтов в ОЗУ (как в шаге 2.3).

2.8. Первые 8 байтов  из 16 байтов, записанных в ОЗУ по вычисленному адресу, интерпретируются как бинарное представление 64-битового беззнакового целого числа, записанное в порядке от младшего к старшему. Первые 8 байтов значения переменной b также интерпретируются как бинарное представление 64-битового беззнакового целого числа, записанное в порядке от младшего к старшему. К этой паре 8-мибайтовых значений применяется покомпонентное умножение по модулю 2^64. Результат преобразуется в 16 байт, и, наконец, две 8-байтовые части результата меняются местами.

2.9. Полученный результат интерпретируется как бинарное представление пары 64-битовых беззнаковых целых чисел, записанных в порядке от младшего к старшему. Значение переменной а также интерпретируется как бинарное представление пары 64-битовых беззнаковых целых чисел, записанных в порядке от младшего к старшему. К этим 4-м 8-мибайтовым значениям применяется покомпонентное умножение по модулю 2^64. Результат преобразуется в 16 байт и становится новым значением переменной а.

2.10. Также полученный результат обратно записывается в ОЗУ по вычисленному адресу. При этом 16 байтов,  ранее записанных в ОЗУ по вычисленному адресу, складываются по модулю 2 (XOR) с новым значением 16 байтов переменной а.

2.11. Результат сложения становится новым значением переменной а.

3. Вычисление результата хеширования.

3.1. 32-ой, 33-ий, ..., 63-ий байты вычисленного конечного состояния хэш-функции Keccak интерпретируются как 256-битный ключ алгоритма AES-256, из которого генерируются 10 раундовых ключей (алгоритма AES-256) (как в шаге 1.2).

3.2. 64-ый, 65-ый, ..., 191-ый байты вычисленного конечного состояния хэш-функции Keccak складываются по модулю 2 (XOR) с первыми 128 байтами ОЗУ.

3.3. Полученные в результате сложения 128 байтов зашифровываются как в шагах 1.4, 1.5 с использованием раундовых ключей, полученных в шаге 3.1.

3.4. Полученные в результате 128 байтов складываются по модулю 2 (XOR) с вторыми 128 байтами ОЗУ.

3.5. Полученные в результате сложения 128 байтов снова зашифровываются как в шагах 1.4, 1.5 с использованием раундовых ключей, полученных в шаге 3.1, и затем складываются по модулю 2 (XOR) со следующими 128 байтами ОЗУ, и так далее.

3.6. После сложения с последними 128 байтами ОЗУ результат последний раз зашифровывается.

3.7. 64-ый, 65-ый, ..., 191-ый байты конечного состояния хэш-функции Keccak заменяются полученными в результате зашифрования 128 байтами.

3.8. Затем к измененному состоянию хэш-функции Keccak применяется функция Keccak-f (с параметром b=1600).

3.9. Затем 2 младших бита первого байта состояния используются для выбора хеш-функции:

0 = BLAKE-256 [BLAKE],

1 = Groestl-256 [GROESTL],

2 = JH-256 [JH]

и 3 = Skein-256 [SKEIN].

3.10. Выбранная хеш-функция затем применяется к состоянию Keccak, и получается результат CryptoNight.

Related Post