Hashes: Keccak, Hs y Hp
Cómo Monero convierte bytes arbitrarios en un número o en un punto
Monero usa la función hash Keccak-256 (el Keccak original, no el SHA3-256 estandarizado). A partir de ella se construyen dos funciones derivadas: Hs, «hash a escalar», y Hp, «hash a punto».
Keccak-256
Una función hash toma cualquier dato y devuelve 32 bytes que parecen aleatorios. Cambiar un solo bit de la entrada cambia toda la salida; encontrar la entrada a partir de la salida, o dos entradas con la misma salida, es inviable en la práctica.
Monero (igual que Ethereum) usa Keccak tal como ganó el concurso SHA-3, antes de que el NIST cambiara el byte de relleno. Por ese detalle, sha3_256() de una biblioteca estándar da un resultado distinto. Si tu código no coincide con Monero, revisa esto primero.
| Función | Hash de la cadena vacía |
|---|---|
| Keccak-256 (Monero) | c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 |
| SHA3-256 (NIST) | a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a |
En el código de Monero esta función se llama cn_fast_hash.
Hs: hash a escalar
A menudo no necesitamos simplemente bytes, sino un escalar: un número módulo l (el orden del punto base). Hs lo hace directamente:
Dónde se usa Hs:
- la clave de visualización a partir de la clave de gasto:
a = Hs(b); - direcciones de un solo uso:
Hs(8rA ‖ i); - subdirecciones:
Hs("SubAddr\0" ‖ a ‖ i ‖ j); - los desafíos (challenges) de las firmas.
Hp: hash a punto
A veces necesitamos un punto cuyo logaritmo discreto no conozca nadie. No basta con tomar Hs(data)·G: entonces el logaritmo sería Hs(data) y todo el mundo lo conocería. Hp construye un punto directamente a partir del hash mediante una aplicación especial (en Monero, una variante de Elligator 2, la función ge_fromfe_frombytes_vartime) y luego lo multiplica por el cofactor 8 para que el punto caiga en el subgrupo correcto.
Dónde se usa Hp:
- key images:
I = x·Hp(P), su uso principal; - el segundo generador
Hde los compromisos de Pedersen:H = Hp(G)(salvo detalles de codificación). Nadie conoce unktal queH = k·G, y eso es crucial para que no se puedan falsificar importes.
Una buena práctica es anteponer a los datos una cadena-etiqueta ("SubAddr", "view_tag", "amount") antes de calcular el hash, para que un hash calculado con un propósito no pueda hacerse pasar por otro. El antiguo código de CryptoNote tiene pocas etiquetas; las partes más nuevas (view tags, Carrot, FCMP++) las usan sistemáticamente.