KAPITEL 1
Grundlagen
Blockchains setzen zwei kryptografische Grundbausteine voraus, die wir am Anfang dieses Kapitels kennenlernen: kryptografische Hashfunktionen und digitale Signaturen. Beide sind verhältnismäßig einfach und gut erforscht. Leser mit entsprechendem Vorwissen sind eingeladen, die entsprechenden Abschnitte zu überspringen.
Dann werden wir sehen, wie man auf das berühmte Double-Spending-Problem stößt, wenn man versucht, mithilfe digitaler Signaturen digitales Bargeld zu schaffen. Das Double-Spending-Problem besteht darin, dass ein dezentrales Netzwerk bei zwei widersprüchlichen Transaktionen nicht ohne Weiteres zu einem Konsens darüber kommen kann, welche der beiden Transaktionen gelten soll. Die Blockchain ist in erster Linie eine Lösung dieses Problems.
Danach betrachten wir digitale Zeitstempel oder Timestamping. Zeitstempel sind zum einen eine gute Illustration der Sicherheitseigenschaften von Hashfunktionen und digitalen Signaturen. Zum anderen ist eine Blockchain im Kern eben eine dezentrale Timestamping-Methode: Wenn das Netzwerk die zeitliche Reihenfolge der beiden widersprüchlichen Transaktionen kennen würde, dann könnte es einfach die erste gelten lassen und die zweite verwerfen. Dann wäre das Double-Spending-Problem gelöst.
Dieser dezentrale Timestamping-Mechanismus beruht auf einem weiteren kryptografischen Konzept: Proof-of-Work. Proof-of-Work ist integraler Bestandteil einer Blockchain und bezeichnet eine Methode, mit der man beweisen kann, dass man eine bestimmte Rechenarbeit geleistet hat.
Proof-of-Work wurde schon vor der Erfindung einer Blockchain genutzt, zum Beispiel im sogenannten Hashcash-Protokoll, das dazu dient, Spam zu bekämpfen. Eine Einführung von Proof-of-Work beendet das Kapitel zu den kryptografischen Grundlagen.
Hashfunktionen
Eine Hashfunktion bildet eine Bitfolge beliebiger Länge auf eine Bitfolge fester Länge ab und ist effizient berechenbar.
Eine vielfach verwendete Hashfunktion ist SHA-256. Eine Implementation finden wir zum Beispiel in der Python-Standardbibliothek.
$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more
information.
>>>
>>> import hashlib
>>> print(hashlib.sha256(b"Satoshi Nakamoto").hexdigest())
a0dc65ffca799873cbea0ac274015b9526505daaaed385155425f7337704883e
>>>
Im gegebenen Beispiel wird der Hash der zugrunde liegenden Bitfolge des Strings Satoshi Nakamoto berechnet. Die Funktion sha256() gibt ein Objekt zurück, das den 256-bittigen binären Ausgabewert der Hashfunktion enthält. Auf diesem wird dann die Funktion hexdigest() aufgerufen, die diesen Ausgabewert in Hexadezimaldarstellung zurückgibt.
Änderungen am Eingabewert führen mit an Sicherheit grenzender Wahrscheinlichkeit zu Änderungen am Ausgabewert. Wenn wir zum Beispiel das letzte Zeichen unseres Eingabestrings ändern, erhalten wir einen völlig anderen Hashwert:
>>> print(hashlib.sha256(b"Satoshi Nakamot0").hexdigest())
73d607aab917435d5e79857769996c95027d4e42172698e0776e1295e285730e
Eine mögliche Anwendung von Hashfunktionen ist das Erkennen von Übertragungsfehlern. Alice hat wenig Platz auf ihrem Laptop, sie will deshalb eine große Datei auf dem Server von Bob speichern und sie lokal löschen. Bevor sie die Datei auf den Server von Bob hochlädt, berechnet sie den Hashwert der Datei und speichert ihn lokal. So kann sie bei späterem Herunterladen der Datei erkennen, ob es zu Übertragungsfehlern gekommen ist: Alice berechnet den Hash der heruntergeladenen Datei und vergleicht ihn mit ihrem lokal gespeicherten Hash. Wenn beide gleich sind, kann Alice davon ausgehen, dass die Datei korrekt übertragen wurde.
Kryptografische Hashfunktionen. Eine kryptografische Hashfunktion ist eine Hashfunktion, die gewisse Sicherheitseigenschaften hat. Die beiden wichtigsten typischerweise geforderten Sicherheitseigenschaften sind die Einwegfunktionseigenschaft (englisch: preimage-resistance) und die Kollisionsresistenz (englisch: collisionresistance). Die Hashfunktion SHA-256 ist eine Einwegfunktion und auch kollisionsresistent.
| Definition: Einwegfunktion Eine Hashfunktion h ist eine Einwegfunktion, wenn es praktisch unmöglich ist, zu einem gegebenen Ausgabewert y einen Eingabewert x zu finden, den die Hashfunktion auf y abbildet: h(x) = y. |
Diese Definition lässt offen, was mit »praktisch unmöglich« gemeint ist. Eine mathematisch exakte Definition ist für unsere Zwecke zu aufwendig, aber wir bemerken Folgendes:
Es ist nicht unmöglich, einen Eingabewert zu finden, der auf einen gegebenen Ausgabewert abgebildet wird. Eingabewerte sind Bitfolgen. Wir können also wie folgt alle Eingabewerte aufzählen:
(leere Bitfolge), 0, 1, 00, 01, 10, 11, 000, … und so weiter.
Für jeden Eingabewert berechnen wir dabei seinen Hash und vergleichen diesen mit dem gegebenen Ausgabewert. Auf diese Weise finden wir mit Sicherheit irgendwann den passenden Eingabewert.
Aber wie praktikabel ist diese Methode? Für jeden Versuch liegt die Wahrscheinlichkeit, den richtigen Ausgabewert zu treffen, bei 2–256 ≈ 10–77. Selbst wenn eine GPU1 1010 Hashwerte pro Sekunde berechnet und alle 1010 GPUs der Welt 100 Jahre lang rechnen (rund 1010 Sekunden), ist die Wahrscheinlichkeit, dass sie diesen Ausgabewert treffen, immer noch praktisch gleich null (10–47).
»Praktisch unmöglich« in der obigen Definition heißt nun, dass kein wesentlich besseres Verfahren zum Finden eines passenden Eingabewerts bekannt ist als das soeben beschriebene.
Sofern Alice in unserem Beispiel eine Einwegfunktion benutzt, um den lokal gespeicherten Hashwert zu berechnen, kann sie sicher sein, dass niemand aus dem Hashwert den Dateiinhalt rekonstruieren kann. Wenn also zum Beispiel Charlie durch Zugriff auf Alice’ Laptop Kenntnis dieses Hashwerts erlangt, kann Alice sicher sein, dass der Dateiinhalt trotzdem vor ihm geheim bleibt.
| Achtung! Wenn der Raum der möglichen Eingabewerte klein ist, dann ist es auch bei einer Einwegfunktion trivial, den entsprechenden Eingabewert zu finden! Bei dem Eingabewert »Satoshi Nakamoto« aus unserem Beispiel ist das leider der Fall, er besteht lediglich aus zwei Wörtern. Die Anzahl möglicher Wörter liegt nur in der Größenordnung von etwa 106, bei zwei Wörtern haben wir also 1012 Möglichkeiten. Eine einzelne GPU durchsucht diesen Raum vollständig in nur etwa 100 Sekunden! Einwegfunktionen sind also nur dann sinnvoll anwendbar, wenn ihre Eingabewerte aus einem genügend großen Raum stammen. In der Praxis werden deshalb meist Zufallswerte an die Eingabewerte angefügt, bevor Hashfunktionen darauf angewendet werden. |
| Definition: Kollisionsresistenz Eine Hashfunktion h ist kollisionsresistent, wenn es praktisch unmöglich ist, zwei verschiedene Eingabewerte x und y zu finden, sodass h(x) = h(y). Ein Paar zweier solcher Eingabewerte x und y mit gleichem Ausgabewert wird auch Kollision genannt. |
Ähnlich wie bei der Einwegfunktionseigenschaft ist es auch hier zwar einfach, einen Algorithmus anzugeben, der eine Kollision finden kann, aber es ist kein Algorithmus bekannt, der bei sinnvoller Begrenzung der Rechenkapazität auch tatsächlich in nützlicher Zeit eine Kollision findet.