Programming lesson
SHA-3 Schritt für Schritt: Diffusion, ρ, π, χ in CSCI 181 verstehen und implementieren
Lerne die θ-Diffusion, RC-Berechnung sowie die ρ-, π- und χ-Implementierung für SHA-3 in CSCI 181 kennen – mit anschaulichen Beispielen und Code-Snippets.
Einführung in SHA-3 und die Homework 5 Aufgaben
Im Rahmen des Kurses CSCI 181 beschäftigst du dich mit den fundamentalen Bausteinen der Hashfunktion SHA-3. Die Aufgaben in Homework 5 fordern dich heraus, die Schritte θ, ρ, π und χ zu verstehen und zu implementieren. Dieser Leitfaden hilft dir dabei, die Konzepte zu durchdringen und typische Fallstricke zu vermeiden. Wir gehen dabei auf die Diffusion im θ-Schritt ein, berechnen den Rundkonstanten RC[3] für Iota und setzen die Permutationen ρ, π und χ in C++ um. Die Beispiele sind auf dem Stand von Mai 2026 – stelle dir vor, du optimierst einen Hash für eine neue KI-gestützte App, die Echtzeitdaten verarbeitet.
Aufgabe 1: Diffusion im θ-Schritt
Teil (a): Einzelbit-Änderung in ain[1][4][63]
Diffusion bedeutet, dass eine kleine Änderung im Input viele Output-Bits beeinflusst. Im θ-Schritt von SHA-3 wird jedes Bit aout[x][y][z] durch XOR-Verknüpfung von ain[x][y][z] mit zwei Paritätstermen C[x][z] und C[x-1][z] berechnet. Änderst du das Bit an Position (1,4,63), so betrifft dies die Paritätsspalte C[1][63] (da y=4 zur Spalte x=1 beiträgt) und C[0][63] (da x-1=0). Dadurch werden alle aout[x][y][z] beeinflusst, bei denen der Term C[x][z] oder C[x-1][z] eingeht. Konkret:
- Alle Bits aout[1][y][63] für y=0..4 (wegen C[1][63])
- Alle Bits aout[0][y][63] für y=0..4 (wegen C[0][63])
- Zusätzlich alle Bits aout[1][y][z] für z≠63, da C[1][z] von der Änderung in C[1][63] abhängt? Nein, die Parität C[x][z] wird über alle y gebildet, aber die Änderung eines einzelnen Bits ändert nur die Parität für diesen z-Wert. Also nur z=63 ist betroffen. Insgesamt: 5 (für x=1) + 5 (für x=0) = 10 Bits.
Teil (b): Zweite Runde θ
Wendest du θ ein zweites Mal an, so werden die bereits geänderten Bits erneut diffundiert. Die genaue Anzahl der betroffenen Bits lässt sich durch Simulation ermitteln, da die Paritäten nun von den geänderten Bits abhängen. In der zweiten Runde multipliziert sich die Zahl der betroffenen Bits typischerweise. Eine manuelle Analyse ist aufwendig, aber du kannst dir merken: θ ist so konstruiert, dass nach zwei Runden eine hohe Diffusion erreicht wird. Für die Abgabe reicht es, die Bits in aout nach der zweiten Runde aufzulisten – nutze hierfür ein kleines Testprogramm.
Aufgabe 2: RC[3] im Iota-Schritt
Die Rundkonstante RC[i] wird aus einem linearen rückgekoppelten Schieberegister (LFSR) über GF(2) abgeleitet. Für i=3 (dritte Runde) berechnest du RC[3], indem du das LFSR 3-mal taktest. Der Startwert ist RC[0]=0x0000000000000001. Nach jedem Takt wird das Register um 1 Bit nach links verschoben und an Position 0 das neue Bit aus dem Polynom x^8 + x^6 + x^5 + x^4 + 1 (entspricht 0x11D) berechnet. Für i=3 ergibt sich:
RC[0] = 0x0000000000000001
RC[1] = 0x0000000000008082
RC[2] = 0x800000000000808A
RC[3] = 0x8000000080008000Überprüfe dein Ergebnis, indem du das LFSR manuell oder mit einem Skript nachvollziehst. Die hexadezimale Darstellung von RC[3] ist 0x8000000080008000.
Aufgabe 3: Implementierung der ρ-Permutation
Die ρ-Permutation rotiert jedes Lane (x,y) um einen festen Betrag, der in der rhomatrix gegeben ist. Für eine 3D-Array-Struktur ain[5][5][64] implementierst du:
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
int r = rhomatrix[x][y];
for (int z = 0; z < 64; z++) {
aout[x][y][(z + r) % 64] = ain[x][y][z];
}
}
}Teste mit der bereitgestellten Eingabedatei. Für die Ausgabe aout[4][3][9..18] solltest du 0110011001 erhalten. Notiere in deiner Abgabe aout[3][1][15..24].
Aufgabe 4: Implementierung der π-Permutation
π permutiert die Lanes nach der Regel: aout[x][y][z] = ain[(x+3y)%5][x][z]. Implementiere:
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < 64; z++) {
aout[x][y][z] = ain[(x + 3*y) % 5][x][z];
}
}
}Überprüfe: aout[4][3][9..18] sollte 0110110001 sein. Gib aout[3][1][15..24] an.
Aufgabe 5: Implementierung der χ-Permutation
χ ist die nichtlineare Schicht: aout[x][y][z] = ain[x][y][z] XOR ((ain[(x+1)%5][y][z] XOR 1) AND ain[(x+2)%5][y][z]).
for (int x = 0; x < 5; x++) {
for (int y = 0; y < 5; y++) {
for (int z = 0; z < 64; z++) {
aout[x][y][z] = ain[x][y][z] ^ ((~ain[(x+1)%5][y][z]) & ain[(x+2)%5][y][z]);
}
}
}Teste mit der Datei sha3in.txt: aout[4][3][9..18] soll 0110100001 sein. Notiere aout[3][1][15..24].
Abschluss und Tipps
Diese Implementierungen sind die Basis für das Verständnis von SHA-3. Achte auf korrekte Indizierung und verwende 64-Bit-Datentypen. Mit diesem Leitfaden bist du gut gerüstet für die Abgabe. Viel Erfolg!