Хеши: Keccak, Hs и Hp
Как Monero превращает произвольные байты в число или в точку
Monero использует хеш-функцию Keccak-256 (оригинальный Keccak, не стандартизованный SHA3-256). Из неё строятся две производные функции: Hs — «хеш в скаляр» и Hp — «хеш в точку».
Keccak-256
Хеш-функция берёт любые данные и выдаёт 32 байта, которые выглядят случайно. Изменение одного бита на входе меняет весь выход; найти вход по выходу или два входа с одинаковым выходом невозможно на практике.
Monero (как и Ethereum) использует Keccak в том виде, в каком он победил в конкурсе SHA-3, — до того, как NIST поменял байт дополнения (padding). Из-за этой мелочи sha3_256() из стандартной библиотеки даёт другой результат. Если ваш код не совпадает с Monero — первым делом проверьте это.
| Функция | Хеш пустой строки |
|---|---|
| Keccak-256 (Monero) | c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 |
| SHA3-256 (NIST) | a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a |
В коде Monero эта функция называется cn_fast_hash.
Hs: хеш в скаляр
Часто нужно получить из данных не просто байты, а скаляр — число по модулю l (порядка базовой точки). Hs делает это прямолинейно:
Где используется Hs:
- ключ просмотра из ключа траты:
a = Hs(b); - одноразовые адреса:
Hs(8rA ‖ i); - подадреса:
Hs("SubAddr\0" ‖ a ‖ i ‖ j); - вызовы (challenges) в подписях.
Hp: хеш в точку
Иногда нужна точка, про которую никто не знает дискретного логарифма. Нельзя просто взять Hs(data)·G — тогда логарифм равен Hs(data), и его знают все. Hp строит точку напрямую из хеша, через специальное отображение (в Monero — вариант Elligator 2, функция ge_fromfe_frombytes_vartime), а затем умножает на кофактор 8, чтобы точка лежала в нужной подгруппе.
Где используется Hp:
- key image:
I = x·Hp(P)— это главное применение; - второй генератор
Hдля обязательств Педерсена:H = Hp(G)(с точностью до деталей кодирования). Никто не знает такогоk, чтоH = k·G— и это критично для того, чтобы нельзя было подделать сумму.
Хорошая практика — добавлять к данным перед хешированием строку-метку («SubAddr», «view_tag», «amount»), чтобы хеш, вычисленный для одной цели, нельзя было подсунуть в другую. В старом коде CryptoNote меток мало, в новых частях (view tags, Carrot, FCMP++) они используются систематически.