Tecnico › Crittografia

Hash: Keccak, Hs e Hp

Come Monero trasforma byte arbitrari in un numero o in un punto

In breve

Monero usa la funzione di hash Keccak-256 (il Keccak originale, non lo SHA3-256 standardizzato). Da essa derivano due funzioni: Hs, "hash a scalare", e Hp, "hash a punto".

Keccak-256

Una funzione di hash prende dati qualsiasi e restituisce 32 byte dall'aspetto casuale. Cambiare un solo bit in ingresso cambia tutto il risultato; trovare l'input partendo dall'output, o due input con lo stesso output, è impraticabile.

Monero (come Ethereum) usa Keccak così come ha vinto la competizione SHA-3, prima che il NIST cambiasse il byte di padding. Per questo dettaglio, sha3_256() di una libreria standard dà un risultato diverso. Se il tuo codice non coincide con Monero, controlla prima questo.

FunzioneHash della stringa vuota
Keccak-256 (Monero)c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
SHA3-256 (NIST)a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

Nel codice di Monero questa funzione si chiama cn_fast_hash.

Hs: hash a scalare

Spesso non ci servono semplici byte ma uno scalare, cioè un numero modulo l (l'ordine del punto base). Hs lo fa direttamente:

Hs(data) = Keccak256(data) mod l i 32 byte dell'hash vengono letti come numero little-endian e ridotti modulo l (nel codice: sc_reduce32)

Dove si usa Hs:

Hp: hash a punto

A volte ci serve un punto di cui nessuno conosca il logaritmo discreto. Non possiamo semplicemente prendere Hs(data)·G: il logaritmo sarebbe Hs(data) e lo conoscerebbero tutti. Hp costruisce un punto direttamente dall'hash tramite una mappa speciale (in Monero una variante di Elligator 2, la funzione ge_fromfe_frombytes_vartime), poi lo moltiplica per il cofattore 8 così che il punto finisca nel sottogruppo giusto.

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

Dove si usa Hp:

  • le key image: I = x·Hp(P), l'uso principale;
  • il secondo generatore H per i commitment di Pedersen: H = Hp(G) (a meno di dettagli di codifica). Nessuno conosce un k tale che H = k·G, ed è fondamentale perché gli importi non si possano falsificare.
Separazione dei domini

Una buona pratica è anteporre ai dati una stringa etichetta ("SubAddr", "view_tag", "amount") prima di calcolare l'hash, così che un hash calcolato per uno scopo non possa essere spacciato per un altro. Il vecchio codice CryptoNote ha poche etichette; le parti più recenti (view tag, Carrot, FCMP++) le usano sistematicamente.