Técnico › Criptografía

Hashes: Keccak, Hs y Hp

Cómo Monero convierte bytes arbitrarios en un número o en un punto

En resumen

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ónHash 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:

Hs(data) = Keccak256(data) mod l los 32 bytes del hash se leen como un número little-endian y se reducen módulo l (en el código: sc_reduce32)

Dónde se usa Hs:

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.

Hp(data) = 8 · map_to_curve( Keccak256(data) )

Dónde se usa Hp:

  • key images: I = x·Hp(P), su uso principal;
  • el segundo generador H de los compromisos de Pedersen: H = Hp(G) (salvo detalles de codificación). Nadie conoce un k tal que H = k·G, y eso es crucial para que no se puedan falsificar importes.
Separación de dominios

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.