Technik › Kryptografie

Hashes: Keccak, Hs und Hp

Wie Monero beliebige Bytes in eine Zahl oder einen Punkt verwandelt

Kurz gesagt

Monero verwendet die Hashfunktion Keccak-256 (das ursprüngliche Keccak, nicht das standardisierte SHA3-256). Daraus werden zwei abgeleitete Funktionen gebaut: Hs – „Hash zu Skalar“ und Hp – „Hash zu Punkt“.

Keccak-256

Eine Hashfunktion nimmt beliebige Daten und gibt 32 Bytes aus, die zufällig aussehen. Ändert sich ein Bit der Eingabe, ändert sich die ganze Ausgabe; die Eingabe aus der Ausgabe zu finden oder zwei Eingaben mit derselben Ausgabe ist praktisch unmöglich.

Monero verwendet (wie Ethereum) Keccak in der Form, in der es den SHA-3-Wettbewerb gewann – bevor das NIST das Padding-Byte änderte. Wegen dieses Details liefert sha3_256() aus einer Standardbibliothek ein anderes Ergebnis. Wenn dein Code nicht mit Monero übereinstimmt, prüfe zuerst das.

FunktionHash des leeren Strings
Keccak-256 (Monero)c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
SHA3-256 (NIST)a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

Im Code von Monero heißt diese Funktion cn_fast_hash.

Hs: Hash zu Skalar

Oft brauchen wir nicht bloß Bytes, sondern einen Skalar – eine Zahl modulo l (die Ordnung des Basispunkts). Hs liefert ihn direkt:

Hs(data) = Keccak256(data) mod l die 32 Hash-Bytes werden als Little-Endian-Zahl gelesen und modulo l reduziert (im Code: sc_reduce32)

Wo Hs verwendet wird:

Hp: Hash zu Punkt

Manchmal brauchen wir einen Punkt, dessen diskreten Logarithmus niemand kennt. Wir können nicht einfach Hs(data)·G nehmen – dann wäre der Logarithmus Hs(data), und den kennt jeder. Hp baut über eine spezielle Abbildung direkt aus dem Hash einen Punkt (in Monero eine Variante von Elligator 2, die Funktion ge_fromfe_frombytes_vartime) und multipliziert dann mit dem Kofaktor 8, damit der Punkt in der richtigen Untergruppe landet.

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

Wo Hp verwendet wird:

  • Key Images: I = x·Hp(P) – die wichtigste Anwendung;
  • der zweite Generator H für Pedersen-Commitments: H = Hp(G) (bis auf Details der Kodierung). Niemand kennt ein k mit H = k·G – und das ist entscheidend, damit sich Beträge nicht fälschen lassen.
Domain Separation

Gute Praxis ist es, Daten vor dem Hashen eine Kennzeichnung voranzustellen („SubAddr“, „view_tag“, „amount“), damit ein für einen Zweck berechneter Hash nicht für einen anderen ausgegeben werden kann. Der alte CryptoNote-Code hat wenige solcher Kennzeichnungen; neuere Teile (View Tags, Carrot, FCMP++) verwenden sie systematisch.