Author: Arman The Parman | Original Date: 02/23| Translated by: Leon A. Wankum | SHA 256 from scratch with pen and paper
Bei all meinen Hobbies/Interessen treibe ich es gerne auf die Spitze – so bin ich eben. Zuvor habe ich gezeigt, wie man mit Würfeln oder Münzen eine Bitcoin-Seed-Phrase von Grund auf neu erstellt. Bis zur Berechnung der Prüfsumme ist kein Computergerät erforderlich, da dazu der zufällige Teil des binären Seeds gehasht wird.
Wir können theoretisch auf einen Computer verzichten, indem wir lernen, eine SHA-256-Berechnung von Hand durchzuführen. Weitere Informationen darüber, was SHA-256 ist (und wie es mit Bitcoin Mining zusammenhängt), finden Sie hier .
Bitte verstehen Sie, ich befürworte nicht, dass Sie dies für Ihre Bitcoin-Wallets tun sollten; Ich finde es einfach cool. Ihr dürft mich gerne beurteilen. Praktischerweise benötigen Sie immer einen Computer, um eine Wallet zu erstellen. Sobald Sie die Seedphrase haben, wünsche ich Ihnen viel Glück bei der Verwendung von Kryptographie, um Ihre privaten und öffentlichen Schlüssel von Hand zu erstellen!
Zum Hintergrundwissen und Verständnis habe ich einige zusätzliche Informationen dem Anhang beigefügt. Ich behandle Binärzahlen, Bits, Bytes, Hexadezimalzahlen, Konvertieren von Zahlen und Konvertieren von Text in Binärzahlen.
Die Formel für SHA256 ist frei zugänglich. Die Formel ist spezifisch und reproduzierbar, aber nicht leicht zu verstehen. Ich habe es für mich selbst entschlüsselt und hier so wiedergegeben, dass es ein Nicht-Informatiker versteht.
Um es zu demonstrieren, werde ich die „Bacon Bitcoin Wallet“ hashen. Wie Sie vielleicht wissen, ist das Prüfsummenwort (24. Wort) für die Seedphrase, die dreiundzwanzig Mal das Wort „Bacon“ enthält, ist „Bacon“, was zu einem Seed führt, der vierundzwanzig Mal „Bacon“ ist. (Um technisch korrekt zu sein, gibt es theoretisch 7 andere Wörter, die nach 23x Bacon gültig sind). Diese Anleitung zeigt, wie dieses Wort berechnet wird, um zu demonstrieren, wie man von Hand hasht.
Teil 1: Vorverarbeitung
Teil 1, Schritt 1 – binär für die Eingabe.
Wenn Sie Text hashen wollten, müssten Sie ihn in Binär umwandeln (siehe Anhang). Für diese Anleitung hash ich sowieso eine Binärzahl, sodass keine Konvertierung erforderlich ist. Ich werde die zufällige binäre Komponente der Bacon-24 BIP39-Wallet hashen, die die folgende ist (ohne Leerzeichen):
Die oben wiederholte Gruppe von 11 Binärziffern, 00010001010, ist die Zahl 138 im Dezimalsystem, die dem Wort „Bacon“ auf der Wortliste des BIP 39-Protokolls zugeordnet ist
Sie werden auf der GitHub-Liste vielleicht bemerken, dass „Bacon“ das Wort Nummer 139 zu sein scheint , aber das ist es nicht – es ist nur so, dass GitHub die Textzeilen automatisch formatiert, sodass die Zahlen bei 1 anstatt 0 beginnen, was zu einer Verschiebung aller Wörter um eine Nummer höher führt. Dies wird deutlich, wenn Sie sich das erste Wort auf der Liste ansehen, „abandon“, dass mit 1 statt 0 gekennzeichnet ist.
Die ersten 253 Ziffern oben (11×23=253) repräsentieren Bacon 23 Mal. Beachten Sie, dass am Ende drei zusätzliche Bits vorhanden sind, die kein Wort bilden (Sie benötigen 11 Bits, um ein Wort zu bilden, also fehlen 8 Bits, um das 24. Wort zu bilden). Diese 8 Ziffern sind nicht Teil der zufälligen Sammlung von 256 Bits, aber die ersten drei sind es. Da ich das Ergebnis im Voraus kenne, weiß ich, dass, wenn die letzten drei zufälligen Ziffern etwas anderes als „000“ wären, die Prüfsumme (24. Wort) am Ende etwas anderes als „Bacon“ sein wird. Ja, diese Wallet wäre auch gültig, aber nicht so cool. Da „000“ zufälligerweise alles zwischen 000 und 111 sein kann, sind 8 verschiedene Kombinationen möglich, und somit 8 verschiedene mögliche Prüfsummenwörter nach 23x Bacon.
Teil 1, Schritt 2 – hängen Sie eine '1' an die Eingabe an.
Teil 1, Schritt 3 – Hängen Sie Nullen an, bis die Gesamtzahl 64 Stellen weniger als ein Vielfaches von 512 beträgt.
Ich habe mit 256 Bit begonnen und im zweiten Schritt ein weiteres hinzugefügt, sodass es 257 Bit sind. Das nächste Vielfache von 512 über 257 ist 512. Subtrahiert man 64, erhält man 448. Also muss ich 191 Nullen hinzufügen:
Wenn Sie etwas anderes hashen wollten und die Länge Ihrer Eingabe zwischen 448 und 512 lag (weniger als 64 von 512 entfernt), sagen wir 500, dann müssten Sie zum nächsten Vielfachen, 1024, gehen und subtrahieren 64 davon, um Ihre neue Länge zu erhalten, fügen Sie dann Nullen hinzu, um Ihre Eingabe auf diese Länge zu bringen – weil wir die Zahl 64 Stellen immer kleiner als ein Vielfaches von 512 machen müssen. Ähnlich, wenn die Länge Ihrer Eingabe zwischen 960 und 1024 wäre, dann müssten Sie bis zum dritten Vielfachen von 512 minus 64 gehen.
Teil 1, Schritt 4 – addiere die Länge binär
Die Eingabe hat jetzt 448 Stellen. Wir müssen 448 in eine Binärzahl umwandeln.
Um dies von Hand zu tun, siehe Anhang.
Die Antwort ist 11100000
EDIT: Das ist falsch, beachten Sie, dass es tatsächlich 111000000 ist. Das habe ich erst entdeckt, nachdem die ganze Arbeit erledigt war. Ich werde den Fehler für die folgenden Arbeiten beibehalten, da die Anleitung dazu dient, die Berechnungen zu demonstrieren, nicht den Hash tatsächlich zu finden – wir wissen sowieso, wie die Antwort lauten sollte. Danke an @darrenahunter, dass du mich darauf aufmerksam gemacht hast.
Jetzt fügen wir diese Binärdatei als 64-stellige Big-Endian-Binärdatei hinzu. Ein was-was-was? Das musste ich erst lernen und nachschlagen. Ganz einfach ausgedrückt bezieht es sich auf die Richtung, in der ein Computer eine Zahl speichert (von links nach rechts oder von rechts nach links). Die Anweisungen, die wir haben, sind, 64 Ziffern zu verwenden, um die obige Binärzahl zu schreiben, und führende Nullen zu verwenden, um das Leerzeichen zu füllen. Das wären 56 Nullen gefolgt von 11100000, dann hängen wir diese 64 Bits an das Ende der Eingabe an.
Jetzt haben wir 512 Bit.
Teil II: Initialisieren der Hash-Werte
Es gibt 8 Konstanten als Teil des SHA256-Hashing-Algorithmus, h0 bis h7, die als „Hash-Werte“ bezeichnet werden.
Die 8 Hash-Werte „repräsentieren die ersten 32 Bits der Bruchteile der Quadratwurzeln der ersten 8 Primzahlen: 2, 3, 5, 7, 11, 13, 17 und 19“ – wieder, was-was-was ? Sehen Sie sich den Anhang an, um zu erfahren, wie Sie sie ableiten, aber es sind Konstanten – sie sind für jeden Hash, den Sie erstellen, gleich.
Sie sind wie folgt:
h0 = 0x6a09e667
h1 = 0xbb67ae85
h2 = 0x3c6ef372
h3 = 0xa54ff53a
h4 = 0x510e527f
h5 = 0x9b05688c
h6 = 0x1f83d9ab
h7 = 0x5be0cd19
Das Präfix „0x“ zeigt an, dass die folgenden Zahlen hexadezimal kodiert sind – „0x“ trägt nicht zum Wert bei, es ist nur ein Symbol. Binär umgeschrieben haben wir:
h0 = 01101010000010011110011001100111
h1 = 10111011011001111010111010000101
h2 = 00111100011011101111001101110010
h3 = 10100101010011111111010100111010
h4 = 01010001000011100101001001111111
h5 = 10011011000001010110100010001100
h6 = 00011111100000111101100110101011
h7 = 01011011111000001100110100011001
Labels für „h0“ bis „h7“ zu haben, ist nützlich, da die darin enthaltenen Werte im Verlauf der Hash-Prozedur geändert werden.
Teil III: Rundungskonstante
Wir haben jetzt mehr Konstante – 64 davon, genannt k0 bis k63.
Dies sind die Kubikwurzeln der ersten 64 Primzahlen, und genau wie bei den Hash-Werten nehmen wir für jede den Dezimalteil und wandeln ihn in ein achtstelliges Hex (oder 32-Bit-Binär) um.
Auch dies sind Konstante und gelten für jeden Hash, den Sie ausführen.
Die Berechnung der Hashwerte habe ich im Anhang demonstriert, die Prinzipien gelten auch für die runden Konstanten, daher habe ich sie nicht wiederholt. Die Werte sind:
0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5
0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5
0xd807aa98 0x12835b01 0x243185be 0x550c7dc3
0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf174
0xe49b69c1 0xefbe4786 0x0fc19dc6 0x240ca1cc
0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da
0x983e5152 0xa831c66d 0xb00327c8 0xbf597fc7
0xc6e00bf3 0xd5a79147 0x06ca6351 0x14292967
0x27b70a85 0x2e1b2138 0x4d2c6dfc 0x53380d13
0x650a7354 0x766a0abb 0x81c2c92e 0x92722c85
0xa2bfe8a1 0xa81a664b 0xc24b8b70 0xc76c51a3
0xd192e819 0xd6990624 0xf40e3585 0x106aa070
0x19a4c116 0x1e376c08 0x2748774c 0x34b0bcb5
0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff3
0x748f82ee 0x78a5636f 0x84c87814 0x8cc70208
0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2
Teil 4: Chunk-Loop
Was haben wir bisher?
- Eine modifizierte Eingabe von 512 Bit (aber wir hätten höhere Vielfache von 512 haben können, wenn unsere Eingabe größer gewesen wäre).
- 8 Hash-Werte.
- 64 runde Konstanten.
Jede 512-Bit-Gruppe wird als „Chunk“ bezeichnet.
Wir müssen einige Operationen mit den Chunk-Daten gegen die 8 Hash-Werte durchführen, die sie modifizieren. Wenn es nur einen Chunk gibt, werden diese 8 Werte am Ende aneinandergereiht, um den endgültigen Hash zu erstellen. Wenn es mehr Chunks gibt, werden die 8 Hash-Werte zum Ausgangspunkt des nächsten Chunks, und es geht durch alle.
Die Schleife beginnt mit der Erweiterung der zugewiesenen 512 Bits, die wir haben, auf 2048 Bits (durch Hinzufügen von Nullen), und jede 32-Bit-Gruppe des 2048-Bit-Ganzen wird dann mit w0 bis w63 bezeichnet:
Was haben wir jetzt?
- 32 „Wörter“: w0 bis w15 (gehören zu Block 1) und neue Nullen von w16 bis w63, wodurch der Block in insgesamt 2048 Bit geändert wird.
- 8 Hash-Werte
- 64 runde Konstanten
Umschreiben der in „Wörter“ w0 bis w63 gruppierten Chunk-Bits:
Ich habe einige Abkürzungen verwendet, um nicht unnötig lange Nullenreihen auszuschreiben.
Die neuen Wörter (w16 bis w63) werden dann durch einen Modifikationsalgorithmus geführt. Die anderen Wörter (w0 bis w15) erscheinen, wenn sie aufgerufen werden, wie noch zu sehen sein wird.
Ich werde die Anweisungen aufschreiben und dann Schritt für Schritt die Ausführung durchführen, die erklärt, was der Code bedeutet.
Der Chunk „Anweisungen“:
Erstellen Sie die Variablen S0, S1
Dann, für i in w[16-63]: (In der Sprache der Programmierer bedeutet dies, i nacheinander gleich den Werten 16 bis 63 werden zu lassen und die folgenden Anweisungen in einer Schleife zu durchlaufen, wobei i als Zahl 16 bis 63 verwendet wird ).
Die Anweisungen mögen auf den ersten Blick verwirrend sein, aber wenn ich Sie durch ein Beispiel führe, wird es leicht verständlich:
Anweisungen:
S0=(w[i-15] rightrotate 7) XOR (w[i-15] rightrotate 18) XOR (w[i-15] rightSHIFT 3)
S1=(w[i-2] rightrotate 17) XOR (w[i-2] rightrotate 19) XOR (w[i-2] rightSHIFT 10)
Verwenden Sie nach der Berechnung von S1 und S2 diese, um w[i] zu erstellen:
w[i]=w[i-16] + S0 + w[i-7] + S1 (addition with modulus 2^32)
Bevor ich diesen Code mit Stift und Papier ausführe, erkläre ich einige Dinge:
w[i-15] in Gleichung 1 bedeutet, dass wir den Wert von i ersetzen, zuerst ist es 16, aber wir wiederholen dies für jeden Wert von i von 16 bis 63. Beim ersten Mal erhalten wir w[1], was bedeutet, wir Schlagen Wort 1 nach (BEACHTEN SIE, DIES IST DAS ZWEITE WORT AUF DER LISTE, WORT 0 IST DAS ERSTE) und setzen Sie die Binärzahlen dieses Wortes in die Gleichung ein.
Das nächste, was zu diskutieren ist, ist „rightrotate“. Das heißt, wir nehmen eine Binärzahl, nehmen dann ihre Ziffer ganz rechts und platzieren sie ganz links von der Zahl. Wiederholen Sie dies so oft, wie nach dem Wort „rightrotate“ angegeben.
Betrachten Sie nun „Rechtsverschiebung“. Dies bedeutet, dass die Ziffer ganz rechts entfernt und ganz links eine Null hinzugefügt wird. Wiederholen Sie dies so oft wie angegeben.
Die XOR-Operation bedeutet, die Binärzahl auf der linken Seite (nennen wir sie A) zu nehmen und sie mit der Binärzahl auf der rechten Seite (nennen wir sie B) Ziffer für Ziffer zu vergleichen, beginnend ganz rechts und nach links. Erstellen Sie für jede Ziffernstelle ein Ergebnis (Ausgabe) gemäß der folgenden Tabelle:
Um es in Worte zu fassen – „OR“ bezieht sich darauf, dass das eine oder andere positiv ist, aber nicht beides. Zeile zwei und drei in der Tabelle haben also positive Ergebnisse. Einer von A oder B ist eine „1“, was „XOR“ erfüllt, also ist das Ergebnis „1“. In der ersten Zeile sind sowohl A als auch B negativ, sodass wir als Ausgabe „Null“ erhalten.
Die letzte Zeile ist etwas seltsam und nicht intuitiv. Wie „XOR“ hier funktioniert, unterscheidet sich von dem, was Sie vielleicht erwarten, im Vergleich dazu, wie Programmiersprachen mit der „OR“-Operation umgehen. Es sieht vielleicht so aus, als würde es ein logisches „OR“ erfüllen, aber da beide positiv sind, ist die Ausgabe falsch oder „0“.
Schließlich müssen wir wissen, wie man Binärdateien mit Modulus 2^32 hinzufügt. Das bedeutet im Grunde: Addieren Sie die Binärzahlen, aber wenn die Antwort wächst (in der Anzahl der Ziffern), wenn eine 33. Ziffer erstellt wird, verwerfen Sie sie.
Die Methode zum Addieren: Das Addieren von zwei Nullen ergibt eine 0. Das Addieren einer 0 und einer 1 ergibt eine 1. Das Addieren von zwei Einsen ergibt eine Null für diese Position, aber wir tragen eine 1 zur nächsten Position (eine nach links).
Zum Beispiel addieren wir für 11001 + 11111 (Modulus 2^5) die beiden Einsen ganz rechts und erhalten eine 0 und tragen eine 1 weiter. Für die zweite Position haben wir eine Null, eine 1 und einer getragenen 1, die Antwort ist also Null und eine 1. Für die dritte Position ist es eine 0, eine 1 und eine 1, also ist die Antwort wieder 0 und eine 1. Für die vierte Position haben wir drei 1, also lautet die Antwort 1 und eine getragene 1. Für die 5. Position haben wir wieder drei 1er, also ist die Antwort 1 und eine getragene 1. Da die getragene 1 an der 6. Position ist und der Modulus 2^5 ist, lassen wir sie einfach weg von der Antwort. Das Endergebnis ist:
11000
Der Sinn des Moduls in diesem Beispiel besteht darin, die Antwort auf der gleichen Länge wie die Eingaben (5 Bit) zu halten. Für die eigentliche Hash-Formel sind die Wörter 32 Bit lang, sodass die Verwendung von 2^32 Modulus die Antwort auf 32 Bit und nicht mehr begrenzt.
Ausführen des Chunk-Codes von Hand:
Die Formel für S0 ist als Referenz ausgeschrieben. In der nächsten Zeile habe ich das zweite „Wort“ (word[1]) herauskopiert, dass ist die zweite Gruppe von 32 Bit des 512-Bit „Chunk“. Wir können sehen, dass es mit einer Null (in Schwarz) beginnt, dann das Wort „Bacon“ in Binärform (Rot), dann wieder „Bacon“ (Blau), dann sind die grünen Ziffern am Ende die ersten 9 Ziffern von „Bacon“.
Als nächstes habe ich die 7 Ziffern ganz rechts von w1 genommen und sie an den Anfang gesetzt, wobei ich Wort 1 in die nächste Zeile umgeschrieben habe (genannt „w1(RR7)“). Die Operation Rightrotate (7) wurde nun an Wort 1 durchgeführt.
Als nächstes habe ich Wort 1 aus dem Original genommen und es diesmal mit 18 Ziffern rechtsgedreht, dann habe ich es in dieser modifizierten Form auf der letzten Zeile ausgeschrieben.
Als nächstes führe ich eine XOR-Operation durch, wobei die beiden Eingänge die beiden neuen temporären Versionen von Wort 1 (RR7 und RR18) sind. Es ist einfacher für das Auge, wenn Sie einige Linien zwischen zwei zu analysierenden Ziffern ziehen.
Ich habe die erste XOR-Operation durchgeführt, aber die S0-Gleichung hat eine zweite.
Der nächste Teil der S0-Gleichung erfordert eine Rechtsverschiebung (3) des w1-Wortes (mit der Bezeichnung „W1(RS3)“).
Dazu habe ich die drei Ziffern ganz rechts weggelassen und am Anfang von Wort 1 drei Nullen hinzugefügt. Dann habe ich die zweite XOR-Funktion (XOR2) ausgeführt. Die erste Eingabe ist das Ergebnis von XOR1 und die zweite Eingabe ist W1(RS3).
Das Ergebnis von XOR2 ist gleich S0, wenn i=16; Jetzt mache ich S1.
Ich habe bisher einfach die Formel für S1 und das Wort [i-2], das Wort 14 ist, in Grün umgeschrieben. Beachten Sie, dass ich es „Wort 14“ nenne, nicht das „14. Wort“, weil es tatsächlich das 15. Wort ist (die Liste beginnt bei Null).
Seien Sie vorsichtig, wenn Sie zu höheren Werten von i gehen, da die meisten Wörter in diesem Beispiel Null sind, Wort 15 jedoch nicht.
Sie können die Gleichung für S1 tatsächlich in Ihrem Kopf erstellen. Möchten Sie es ausprobieren, bevor Sie weiterlesen?
…
…
…
…
…
…
Antwort: alles Nullen.
Warum? Das Verschieben nach rechts oder das Drehen nach rechts eines Wortes, das nur aus Nullen besteht, führt zu lauter Nullen. Die Zahlen in den drei Klammern sind also alle gleich Null. Dann führt die Durchführung von XOR-Operationen an Nullen zu Null. Die erste und die zweite XOR-Operation geben also 32 Nullen zurück …
Wir sind fast am Ende von Teil 4.
Als nächstes gehen wir zurück zu dieser Gleichung:
- w[i]=w[i-16] + S0 + w[i-7] + S1 (Addition mit Modul 2^32)
Wenn i 16 ist, suchen wir mit w0, S0, w9 und S1 nach einem neuen w16. Wir addieren sie einfach alle einzeln zusammen, um w16 zu erhalten, dass sich von seinem aktuellen Zustand mit nur Nullen in etwas anderes ändert.
In rot haben wir eineen Arbeitsvorgang im Gange. Als Nächstes füge ich w9 hinzu, was nur aus Nullen besteht, sodass sich die Zahl in Rot nicht ändert. Als nächstes füge ich S1 hinzu, wieder alles Nullen, also ist die Zahl in Rot endgültig; das ist w[16].
Als nächstes habe ich i = 17 gemacht und das alles noch einmal wiederholt. Dann ist i=18 bis hin zu i=63. Ich werde Ihnen das Training dazu nicht zeigen, da es keine weitere Erklärung hinzufügt, aber lassen Sie mich Ihnen sagen, es ist anstrengend, und ich habe über ein paar Wochen daran gearbeitet.
Das Folgende sind die neuen Versionen von w[16 bis 63] nach Ausführung der Chunk-Anweisungen:
w[16] = 00010011010111011010110101001101
w[17] = 00011001110111011110010101100100
w[18] = 00001101110100111101001010110010
w[19] = 01010111111010011100100101011000
w[20] = 10101011111101001110010010101100
w[21] = 01010111111000010001000101000010
w[22] = 00101011111111010001101000001011
w[23] = 00100101001000101010010001010000
w]24] = 1000000000000000000000000000000
w[25] = 0000000000000000000000000000000
w[26] = 0000000000000000000000000000000
w[27] = 0000000000000000000000000000000
w[28] = 0000000000000000000000000000000
w[29] = 0000000000000000000000000000000
w[30] = 11000000001110000000000000011101
w[31] = 0000000000000000000000001110000
W[32-63] = 00000000000000000000000000000000
Beachten Sie, dass dies für jeden 512-Bit-Chunk durchgeführt werden muss. Das heißt, nehmen Sie jeden 512-Bit-Block aus der Vorverarbeitungsphase, erweitern Sie ihn auf 2048 Bit (64 x 32-Bit-„Wörter“) und modifizieren Sie dann die Wörter 16 bis 63 (17. bis 64.). Wenn Sie mit 2 Chunks (2 x 512 Bit) beginnen, hätten Sie zu diesem Zeitpunkt 128 „Wörter“.
Teil 5: Kompressionsschleife
In diesem Teil wird es richtig scharf. Die modifizierte Eingabe (w[0] bis w[64]) für jeden Chunk wird durch eine Reihe von Anweisungen mit den k-Konstanten und den anfänglichen h-Werten gemischt, und am Ende der Manipulation jedes Chunks werden die Werte h[0] bis h[8] modifiziert und als anfängliche h-Werte des nächsten Chunks weitergegeben. Am Ende bilden diese verketteten (zusammengefügten) h-Werte den endgültigen Hash.
Die Anleitungen:
Set the values of a to h equal to h0 to h7.
All additions are calculated modulo 2^32.
Perform a loop: for i in (0 to 63):
S1 = (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
ch = (e and f) xor ((not e) and g)
temp1 = h + S1 + ch + k[i] + w[i]
S0 = (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
maj = (a and b) xor (a and c) xor (b and c)
temp2 = S0 + maj
h = g
g = f
f = e
e = d + temp1
d = c
c = b
b = a
a = temp1 + temp2
Ausführen des Codes von Hand:
Ich beginne damit, i=0 zu lassen
Um S1 zu trainieren…
S1 = (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
Ich habe „e“ (das eine Kopie von h4 ist) um 6 nach rechts gedreht und dann mit einer Rechtsdrehung um 11 von „e“ XOR-verknüpft. Ich habe das unten „XOR1“ genannt. Dann habe ich das mit einer Rechtsdrehung 25 von „e“ XOR-verknüpft, was zu „XOR2“ führt, was gleich „S1“ ist.
Als nächstes berechne ich den Wert für „ch“
ch = (e and f) xor ((not e) and g)
Sowohl e als auch f wurden von h4 bzw. h5 kopiert. Ich habe bereits e, also habe ich f aufgeschrieben und es in der Zeile darunter mit UND verknüpft.
Dann habe ich den Wert für NOT(e) aufgeschrieben. Das ist im Grunde das Gegenteil von e. Das heißt, wo eine 0 steht, ersetze sie durch eine 1 und umgekehrt. Dann schrieb ich g auf und verknüpfte es mit NOT(e) in der Zeile darunter.
Schließlich wurde diese Zeile mit dem (e UND f)-Ergebnis XOR-verknüpft, um „ch“ zu ergeben.
Als nächstes ermittle ich den Wert von „temp1“:
temp1 = h + S1 + ch + k[i] + w[i]
Ich habe zuerst den Wert von h aufgeschrieben.
Fügen Sie es dann mit S1 hinzu (Beachten Sie, dass das Hinzufügen nicht dasselbe ist wie UND).
Dann habe ich ch in die obige Zeile eingefügt.
Dann den Wert von k[0] aufschreiben. Das k ist eine der „runden Konstanten“ aus Teil III. Ich habe den nullten verwendet, weil i = 0 ist. Später werde ich alle Werte bis 63 gleichsetzen, dass ist also eine große Schleife.
Als nächstes arbeite ich „temp1“ aus, indem ich w[0] mit der Linie darüber hinzufüge.
Als nächstes muss ich den Wert von S0 ausarbeiten:
S0 = (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
Als nächstes muss ich eine neue Variable „maj“ berechnen:
maj = (a and b) xor (a and c) xor (b and c)
Als nächstes muss ich temp2 berechnen
temp2 = S0 + maj
Nun müssen die Buchstaben a bis h neu zugeordnet werden.
Aus 'h' wird 'g', aus 'g' wird 'f', aus 'f' wird 'e':
'e' wird zu 'd' plus 'temp1':
'd' wird 'c', 'c' wird 'b' und 'b' wird 'a':
d = c
c = b
b = a
Schließlich wird „a“ zu „temp1“ plus „temp2“:
Wir haben jetzt neue Werte für 'a' bis 'h'
Das war eine Schleife für i=1. Jetzt muss ich alles noch einmal machen, DREIUNDSECHSZIG MAL, und mit jeder Schleife werden die Buchstaben „a“ bis „h“ geändert.
Weißt du was? Ich werde es nicht tun. Das ist lächerlich! Warte, ich kann das nicht loslassen, meine Persönlichkeit erlaubt es mir nicht, es fallen zu lassen. Ich werde hier abkürzen, aber ich werde diesen Hash eines Tages von Hand ordentlich weiterführen und fertigstellen und mich mit einem Update zurückmelden.
Teil 6: Der letzte Hash
Am Ende gibt es nach der 64 Iteration Werte für 'a' bis 'h'. Diese „verketteten“ oder aneinander angehängten Werte bilden den Hash. Sie könnten es als eine lange Binärdatei mit 256 Bits Länge darstellen, oder Sie könnten jeden 32-Bit-Buchstaben in einen 8-stelligen Hexadezimalwert konvertieren, und Sie erhalten einen 64-stelligen Hash, der die übliche Darstellung von SHA-256 ist . Für diese Binärdatei sind die 8 Hash-Werte:
h1 =8a389dba
h2 = bbeda4b1
h3 = ba4ee074
h4 =01e38740
h5 = 4e4ac579
h6 = 98f195d0
h7 = d22f547c
h8 = 00af49aa
Wenn wir sie miteinander verketten, haben wir:
8a389dbabbeda4b1ba4ee07401e387404e4ac57998f195d0d22f547c00af49aa
Die ersten beiden Hexadezimalziffern im Binärformat sind:
1000 1010
Wenn wir sie zu den letzten 3 Ziffern der Eingabe („000“) hinzufügen, erhalten wir 00010001010, was in BIP39 mit dem Wort „Bacon“ übersetzt wird. Voilà!
OK, hier die Abkürzung! Fügen Sie diesen Befehl (alles in einer Zeile und drücken Sie am Ende <enter>) in das Linux- oder Mac-Terminal ein:
echo 0001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000100010100001000101000010001010000 | shasum -a 256 -0
Und Sie erhalten den gleichen Hash.
Abschluss
Ich hoffe, Sie haben diesen Wahnsinn genossen. Ich habe selbst viel gelernt und fand die logischen Operationen auf Binär interessant. Ich hoffe, ich kann den Drang überwinden, alle 63 weiteren Iterationen von Teil 5 abzuschließen, aber ich bezweifle, dass ich diesen Kampf gegen meinen Verstand gewinnen werde.
Anhang A
Was ist binär?
Binär ist ein Zahlensystem mit nur zwei verfügbaren Symbolen, 0 und 1. Stellen Sie sich vor, Sie würden nur mit diesen Symbolen Schafe von 0 aufwärts zählen. Du fängst mit 0 an, dann mit 1 und dann um ein anderes Schaf darzustellen, was machst du? Es gibt kein „2“-Symbol, man muss sich mit „0“ und „1“ begnügen. Die Lösung besteht darin, ein zweites Symbol wie dieses hinzuzufügen: „10“.
Also, nach „1“ kommt „10“, und nach „10“ kommt „11“ und danach „100“. Dann "101", "110", "111", wieder keine Symbole mehr, wir fügen ein weiteres hinzu, "1000" usw.
Was ist ein bit?
Ein Bit ist die kleinste Informationseinheit für einen Computer, dargestellt als „1“ oder „0“. Übertragen auf den physischen Computer, der die Daten enthält, und je nach Speichermedium: positives Magnetfeld vs. negatives Magnetfeld. In logischen Systemen steht es für „wahr“ vs. „falsch“. In Maschinen oder Schaltkreisen „ein“ vs. „aus“.
Im Zusammenhang mit privaten Schlüsseln kann ein Bit eine Aufzeichnung eines zufälligen binären Ereignisses sein, wie z. B. ein Münzwurf, ein Würfelwurf (ungerade vs. gerade; oder 1,2,3 vs. 4,5,6).
Um beispielsweise die Zahl 11001010 aufzuzeichnen, kann ein Computer Magnetfelder nebeneinander drucken als:
positive : positive : negative : negative : positive : negative : positive : negative
Was ist ein Byte?
Ein Byte sind 8 Bit. Es sollte die Datenmenge sein, die einem Computer zugewiesen wurde, um ein einzelnes Textzeichen aufzuzeichnen (das ursprüngliche Protokoll war ASCII, aber es gibt noch viel mehr, und Unicode wird jetzt im Allgemeinen bevorzugt). Da ein Byte eine beliebige Zahl zwischen mindestens 00000000 und höchstens 11111111 darstellen kann (umgewandelt in Dezimalzahlen, also 0 bis 255), könnten 256 mögliche Zeichen mit einem Byte unter Verwendung des ASCII-Protokolls dargestellt werden.
Was ist hexadezimal (hex)?
Hexadezimal ist ein weiteres Zahlensystem. Statt 10 Zeichen (dezimal) oder zwei Zeichen (binär) gibt es 16 (hex = 6, dezimal = 10, hexadezimal = 16).
Es gibt die üblichen Dezimalzeichen „0“ bis „9“, aber auch „a“ bis „f“, die die Werte 10 bis 15 darstellen. Beispielsweise ist „f“ in Hex „15“ in Dezimal. Und „10“ in Hexadezimal ist eigentlich „16“ in Dezimal.
Wissen Sie, was „20“ im Hexadezimalformat im Dezimalformat wäre? Die „2“ an zweiter Stelle bedeutet, dass wir zweimal bis 16 (dezimal) gezählt haben. Wir kamen zu „f“ (Wert 15), gingen dann weiter zum Wert 16 („10“ in Hex) und zählten dann weiter bis 11 (in Hex). Sehen Sie sich diese Hex-Zahl an: 11 – verstehen Sie, dass es nicht „11“ ist, wie Sie es kennen? Es ist größer. Überlegen Sie, wie wir dorthin gekommen sind. Es repräsentiert tatsächlich den Wert 17.
Um nach 11 in Hex weiter zu zählen, schreiben wir 12, 13, 14, 15, 16, 17, 18, 19 und dann 1a. Was ist das? Die 1 an der zweiten Position steht für „16“ in Dezimalschreibweise und das „a“ hat einen Wert von 10. Also ist 1a tatsächlich 26 in Dezimalschreibweise. Zählen Sie weiter aufwärts, 1b, 1c, 1d, 1e, 1f. Hier haben wir 16 (dezimal) plus 15 (dezimal), was insgesamt 31 in dezimal ist. Können Sie herausfinden, was das Hinzufügen von 1 mehr zu 1f bewirken würde, ohne den nächsten Absatz zu lesen?
Die Antwort ist 20. Keine normale 20, sondern eine Hex-20. Das bedeutet, dass wir zweimal bis 16 (dec) gezählt haben.
Machen Sie sich keine Sorgen, wenn Sie es nicht sofort verstehen (ich habe es sicherlich nicht), es ist nicht intuitiv und sehr abstrakt. Kommen Sie später darauf zurück. Außerdem ist es nicht unbedingt erforderlich, vollständig zu verstehen, um mit der Anleitung fortzufahren.
Wenn Sie eine Zahl schreiben und angeben, dass sie hexadezimal ist, ist es üblich, der Zahl 0x voranzustellen. Zum Beispiel ist 16 in Dezimalzahl 10 in Hexadezimalzahl. Wir schreiben:
0x10
So konvertieren Sie eine Dezimalzahl in eine Hexadezimalzahl.
Wenn Sie ein Purist wie ich sind und jedes elektronische Gerät vermeiden, müssen Sie wissen, wie Sie für dieses Projekt eine Dezimalzahl in eine Hexadezimalzahl umwandeln:
Konvertieren wir z. B. 6,15 dezimal in hexadezimal:
Die erste Ziffer ist eine 6 dezimal und hexadezimal. Schreiben Sie das zunächst in die Antwort:
Laufende Antwort: 0x6
Als nächstes subtrahieren Sie die 6 von der Dezimalzahl, wir haben 0,15 übrig. Multiplizieren Sie das mit 16. Wir erhalten 2,4. Nehmen Sie die 2, wandeln Sie sie in Hex (2) um und fügen Sie sie mit einem Dezimalpunkt zur Hex-Antwort hinzu:
Laufende Antwort: 0x6.2
Subtrahieren Sie als nächstes die 2 von der Dezimalzahl 2,4, wir erhalten 0,4. Multiplizieren Sie mit 16, und wir erhalten 6,4. Setzen Sie eine 6 in das Hex-Ergebnis:
Laufende Antwort: 0x6.26
Entfernen Sie als nächstes die 6 von der 6,4, und wir erhalten (wieder) 0,4. Da wir bei diesem Schritt von nun an immer 0,4 erhalten, lautet die Antwort:
Antwort: 0x6.26666666666
Nehmen wir für größere Zahlen eine bedeutungslose Zahl, oh, ich weiß nicht, 21.000.000, und wandeln sie in Hex um. Wir dividieren zuerst durch 16:
1.312.500. Es gibt keinen Rest, also ist die erste Ziffer die Antwort (von rechts nach links) „0“. Fahren Sie fort, indem Sie 1.312.500 durch 16 teilen:
82031 und 4/16. Als nächstes schreiben wir „4“ in die Antwort an der zweiten von rechts Position.
Fahren Sie fort, indem Sie 82031 durch 16 teilen:
5126 und 15/16.
Der Rest ist 15 oder „f“. Setzen Sie „f“ an die 3. Stelle von rechts in die Antwort. Fahren Sie auf die gleiche Weise fort, bis wir die endgültige Antwort erhalten:
Antwort: 0x1406F40
Die obige Zahl ist, wie man 21.000.000 in Hex schreibt.
Konvertieren von Text in Binär
Wenn Sie Text hashen, müssen Sie den Text zuerst in eine Binärzahl konvertieren. Zum Beispiel können die Worte “Craig Wright is a liar and a fraud” („Craig Wright ist ein Lügner und ein Betrüger“) mithilfe einer ASCII-zu-Binär Umwandlungstabelle in Binär umgewandelt werden (die Umwandlung ist ein Protokoll, keine Mathematik):
01000011 01110010 01100001 01101001 01100111 00100000 01010111 01110010 01101001 01100111 01101000 01110100 00100000 01101001 01110011 00100000 01100001 00100000 01101100 01101001 01100001 01110010 00100000 01100001 01101110 01100100 00100000 01100001 00100000 01100110 01110010 01100001 01110101 01100100
Oben, unter Verwendung des ASCII-Protokolls, hat jedes Zeichen in “Craig Wright is a liar and a fraud” („Craig Wright ist ein Lügner und ein Betrüger“), einschließlich Leerzeichen, seine eigene Binärzahl, die aus 1 Byte (8 Bit) besteht.
Wir könnten ein anderes Protokoll verwenden (es gibt viele). Ein weiterer ist Unicode-16. In diesem Fall wäre die Binärdatei:
01000011 00000000 01110010 00000000 01100001 00000000 01101001 00000000 01100111 00000000 00100000 00000000 01010111 00000000 01110010 00000000 01101001 00000000 01100111 00000000 01101000 00000000 01110100 00000000 00100000 00000000 01101001 00000000 01110011 00000000 00100000 00000000 01100001 00000000 00100000 00000000 01101100 00000000 01101001 00000000 01100001 00000000 01110010 00000000 00100000 00000000 01100001 00000000 01101110 00000000 01100100 00000000 00100000 00000000 01100001 00000000 00100000 00000000 01100110 00000000 01110010 00000000 01100001 00000000 01110101 00000000 01100100 00000000
Dezimal in binär umwandeln
Wenn wir eine Dezimalzahl haben, verwenden wir 448,- und möchten diese in eine Binärzahl umwandeln, teilen wir wiederholt durch 2 und verwenden den Rest als Ergebnis. Dies ist der Prozess:
Teilen Sie 448 durch 2. Wir erhalten 224 mit Null Rest. Null ist unsere erste binäre Ziffer.
Laufende Antwort: 0
Als nächstes teilen wir 224 durch 2. Wir erhalten 112 mit Null Rest
Laufende Antwort: 00
Als nächstes erhalten wir 56 mit Null Rest
Laufende Antwort: 000
Als nächstes 28, Null Rest
Laufende Antwort: 0000
Nächste 14, Null Rest:
Laufende Antwort: 00000
Als nächstes, 7, Null Rest:
Laufende Antwort: 00000
Nächste 3, mit 1 Rest:
Laufende Antwort: 100000
Als nächstes 1 mit 1 Rest (dh 1,5)
Laufende Antwort: 1100000
Nächste 0 mit 1 Rest (dh 0,5):
Antwort: 11100000
Also ist 448 in Dezimalzahl 11100000 in Binärzahl.
Konvertieren von Hexadezimal in Binär
Diese Konvertierung ist eigentlich einfach. Jede Hex-Ziffer wird einer 4-stelligen Binärzahl zugeordnet. Das größte Hex-Symbol ist f, das binär 1111 ist. Das kleinste Hex-Symbol ist 0, was binär 0000 ist. Die Zahl 1a4f3 in Hex lautet also:
0001 1010 0100 1111 0011
Und die Zahl 11 1111 in Binärform wird zunächst in 0011 1111 umgeschrieben und in 3f umgewandelt
Ableitung der 8 Hashwerte
Die 8 Werte beginnen jeweils mit den ersten 8 Primzahlen. Ich zeige nur die erste, abgeleitet von der Primzahl 2.
Wir ziehen zuerst die Quadratwurzel:
1.41421356237
Jetzt wollen wir nur den Bruchteil (Zahlen rechts vom Dezimalkomma) in Hex. Es ist nicht offensichtlich, wie man das macht. Du kannst nicht einfach mit Faktoren von 10 multiplizieren, um das Komma nach rechts zu verschieben. Warum? Denn es ist kein Dezimalpunkt, sondern ein „Hexadezimalpunkt“ – Sie müssen mit 16 multiplizieren! Hier ist wie:
Entfernen Sie die 1, da wir nur die Bruchkomponente wollen:
0.41421356237
Multiplizieren Sie das mit 16:
6.6274
Nehmen Sie die 6 und wandeln Sie sie in Hex um, was 6 ist, und fügen Sie die laufende Antwort hinzu:
Laufende Antwort: 6
Entfernen Sie nun die 6, wir erhalten 0,6274 und multiplizieren mit 16. Wir erhalten 10,038. Nehmen Sie die „10“ und wandeln Sie sie in Hex um, wir erhalten „a“. Fügen Sie das der laufenden Antwort hinzu:
Laufantwort: 6a
Dann entfernen wir die 10 und machen mit 0,038 weiter. Fahren Sie fort, bis Sie 8 Hexadezimalziffern in der Antwort erhalten. Dies wird in 32 binäre Bits umgewandelt.
Ableitung der anfänglichen Hash-Werte
Die 8 Hashwerte stellen die ersten 32 Bits der Bruchteile der Quadratwurzeln der ersten 8 Primzahlen dar: 2, 3, 5, 7, 11, 13, 17 und 19.
Ich werde die Verwendung der ersten Primzahl, Nummer 2, demonstrieren.
Ziehen Sie zuerst die Quadratwurzel aus 2:
1.41421356237
Dann nehmen Sie nur den „gebrochenen“ Teil. (dh die Ganzzahl entfernen)
0.41421356237
Wenn wir nur den Bruchteil in Dezimalzahl benötigen, würden wir einfach immer wieder mit 10 multiplizieren, bis wir erhalten:
41421356237
Aber wir wollen „die ersten 32 Bits“, also 32 Einsen und Nullen. Wie macht man das aus einer Dezimalzahl? Der einfachere Weg ist, 8 Hexadezimalzahlen zu erhalten und diese dann in 32 Binärbits umzuwandeln (jede Hexadezimalzahl besteht aus 4 Binärbits, eine einfache Konvertierung, wie ich zeigen werde.)
Anstatt also die obige Zahl mit 10 zu multiplizieren, multiplizieren wir mit 16 und extrahieren die Ganzzahl.
0.41421356237 x 16 = 6.62741699797
6 ist die Zahl, die wir brauchen, was '6' in Hexadezimalform ist. Das ist unsere erste Ziffer für den Hashwert. Jetzt subtrahieren Sie 6 von der obigen Antwort und multiplizieren Sie mit 16:
0.62741699797 x 16 = 10.0386719675
10 ist die Zahl, die wir brauchen, was 'a' im Hexadezimalformat ist. Das ist unsere erste Ziffer für den Hashwert. Dann subtrahieren wir 10 von der obigen Antwort und multiplizieren mit 16. Wiederholen Sie den Vorgang, bis Sie 8 Hexadezimalziffern erhalten, und hören Sie dann auf. Wir bekommen:
6a09e667 in Hex, auch geschrieben als 0x6a09e667, wobei „0x“ anzeigt, dass die folgende Zahl in Hex ist.
Diese Zahl lässt sich leicht in eine Binärzahl umwandeln. Jede Ziffer liegt zwischen binär 0000-1111 (dh dezimal 0 bis 16 oder hexadezimal 0 bis f).
Hexadezimal | Binär |
6 | 0110 |
A | 1010 |
0 | 0000 |
9 | 1001 |
e | 1110 |
6 | 0110 |
6 | 0110 |
7 | 0111 |
Wenn wir alle Binärzahlen der Reihe nach zusammenfügen, haben wir h1 als:
01101010000010011110011001100111
binär
Anhang B – Beweis meiner Arbeit für Chunk Loop 1
i=17
i=18
Anhang C – Arbeitsnachweis für den Rest des gesamten Hashs (wird fortgesetzt)
Value 4 Value | Tips:
Wenn Ihnen diese Übersetzung gefallen hat, würde ich mich über eine Wertschätzung in Form von Satoshi an law@getalby.com freuen.
Sie können mir ausserdem auf Twitter folgen oder meine Homepage besuchen.
Leon A. Wankum
Bitcoin. Real Estate. Philosophy & Ethics. ⚡law@getalby.com npub1v5k43t905yz6lpr4crlgq2d99e7ahsehk27eex9mz7s3rhzvmesqum8rd9
follow me :
Related Posts
Rabbit fragt #17
Aug 28, 2024
Der Bitcoiner in der Midlife-Crisis
Jun 14, 2024
Rabbit fragt...#16...Was ist eine Hardware Wallet?
May 26, 2024