Hash: Keccak, Hs e Hp
Come Monero trasforma byte arbitrari in un numero o in un punto
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.
| Funzione | Hash 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:
Dove si usa Hs:
- la view key a partire dalla spend key:
a = Hs(b); - gli indirizzi monouso:
Hs(8rA ‖ i); - i subaddress:
Hs("SubAddr\0" ‖ a ‖ i ‖ j); - le sfide (challenge) nelle firme.
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.
Dove si usa Hp:
- le key image:
I = x·Hp(P), l'uso principale; - il secondo generatore
Hper i commitment di Pedersen:H = Hp(G)(a meno di dettagli di codifica). Nessuno conosce unktale cheH = k·G, ed è fondamentale perché gli importi non si possano falsificare.
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.