Kryptowährungen, Blockchains und Hashfunktionen

Die eigene Blockchain programmieren

Kryptowährungen, Blockchains & Hashfunktionen sind in aller Munde - und gleichzeitig für die Meisten erstmal sehr technisch und abstrakt. Aber ist das so schwer? Mit nur wenigen Zeilen Code kann eine eigene Blockchain programmiert und grundlegende Prinzipien selbst erfahren werden. Ein spannendes fachübergreifendes Projekt in der Schule!

Die Blockchain basiert auf digitaler Verschlüsselung
Grafik: © denisismagilov/adobestock.com

Kryptowährungen, Blockchains und Hashfunktionen gehören inzwischen fest zu den aktuellen gesellschaftlichen Themen und entsprechende Beiträge sind aus den Medien kaum mehr wegzudenken (vgl. etwa SZ). Gleichzeitig herrscht ein fast schon gefährliches Halbwissen über die Begriffe, die oft als sehr technisch angesehen werden und – wenn überhaupt – nur oberflächlich verstanden sind.

Der Themenkomplex eignet sehr gut für fächerübergreifenden Unterricht (beispielsweise unter Einbezug der Fächer Mathematik, Informatik und Wirtschaft). Die Grundlagen von Blockchain und Hashfunktion werden in dem Beitrag Blockchains und Hashfunktionen in mathematik lehren 219 dargestellt. Dort wird das aus mathematischer Sicht interessanteste Konzept der Hashfunktion genauer unter die Lupe genommen, Blockchains werden jedoch nur theoretisch behandelt.

Am Ende dieses Beitrags finden Sie vertiefende Materialien als kostenlosen Download

Hinweise zum Unterricht

Offensichtlich erfordert die Programmierung einer eigenen Blockchain gewisse Vorerfahrungen im Umgang mit Programmiersprachen und kann entsprechend der Vorkenntnisse der Lehrkraft/der Klasse sehr unterschiedlich durchgeführt werden. Auch liegt der Fokus hier stärker im Bereich der Informatik als im Bereich der Kryptographie oder der Mathematik, obwohl verschiedene mathematische Konzepte behandelt werden können. Jedoch bietet der fächerübergreifende Unterricht eine sinnvolle Weiterführung einer Unterrichtseinheit zu Hashfunktionen sowie als Grundlage einer im Wirtschaftsunterricht möglichen Unterrichtsstunde zu Kryptowährungen. Zentrale Elemente bei der unterrichtlichen Bearbeitung könnten sein:

  • Ausführen und Nachvollziehen des Codes
  • Mündliche Beschreibung des Codes und der einzelnen Befehle
  • Nachvollziehen der Manipulationen in den verschiedenen Versionen der Blockchain
  • Besprechen einzelner Konzepte der Informatik (wie Klassen, Instanzen, for-Schleifen) oder der Mathematik (etwa Variablendefinition, Iterationen, Folgen), je nach Klassenstufe
  • Überarbeiten einzelner Aspekte des Codes (zum Beispiel hinsichtlich der verwendeten Daten, for-Schleifen usw.; vgl. die Tipps weiter unten)
  • Selbstständiges Erweitern des Codes um weitere Aspekte von Blockchains (etwa um den aktuellen Kontostand anstelle der reinen Kontobewegungen) sowie einer Funktion zur Überprüfung, ob das Konto ausreichend gedeckt ist, bevor eine Kontobewegung durchgeführt wird
  • Selbstständiges Erweitern des Codes von einem auf beliebig viele Nutzerkonten
  • Speichern der Blockchain als Datei und ggfs. Abgleich mit anderen Dateien auf Netzlaufwerken der anderen Schülerinnen und Schüler

Ja, ich möchte gratis 6 vollständige Unterrichtseinheiten aus Friedrich+ bekommen. Keine Kosten, keine Werbung – versprochen!

Vorbereitungen

Basierend auf der dargestellten Unterrichtsidee zu Hashfunktionen kann nun – gerade im fächerübergreifenden Unterricht mit der Informatik – mit der Gestaltung einer eigenen Blockchain begonnen werden, um deren Funktionsweise zu ergründen sowie den praktischen Einsatz von Hashfunktionen genauer zu betrachten. Neben dem besseren Verständnis von Blockchains und Hashfunktionen können dabei vor allem Prinzipien der Informatik genauer betrachtet werden (wie etwa Klassen oder Schleifen). Durch eingebaute Schleifen können aber auch das Variablenkonzept, Prinzipien der Iteration und (fast schon) Induktion sowie Folgen als mathematische Lerninhalte thematisiert werden. Die zahlreichen Möglichkeiten werden hier nicht detailliert dargestellt, sondern der Fokus liegt auf den beispielhaften Programmiercode und dessen Erläuterung.

Grundprinzipien einer Blockchain bzw. einer Kryptowährung können mittels aktueller Programmiersprachen gut nachempfunden werden. Vergleichsweise einfach zu realisieren sind dabei die Verwendung von Hashfunktionen und die Verknüpfung der einzelnen Blöcke zu einer Kette. Weitere Aspekte einer Blockchain, etwa in Bezug auf die Netzwerkstruktur, das Schürfen von Bitcoins usw. sind komplexer und für den regulären Unterricht kaum geeignet. Entsprechende Ideen für Umsetzungen können im Internet gefunden werden (hier ein Beispiel in Java script für den Bildungsbereich).

Vereinfachte Funktionsweise einer Blockchain
Zeichnung: Friedrich Verlag 2020

Zur Umsetzung können bspw. Online-IDEs (engl. Integrierte Entwicklungsumgebungen) wie repl.it verwendet werden, sodass keine Installation von Software notwendig ist und praktisch mit jedem internetfähigen Gerät gearbeitet werden kann. Als Programmiersprache kommen besonders objektorientierte Programmiersprachen wie Python, Java(script) oder C++ in Frage, da hier Unterschiede zwischen Klassen, Funktionen für diese Klassen und spezifischen Instanzen deutlich werden. Im Unterricht sollte bei der Umsetzung auf einen Editor mit Syntaxhervorhebung geachtet werden.

Der Code – Übersicht

Zur Programmierung einer eigenen Blockchain sowie dem Erkunden ihrer Eigenschaften – insbesondere in Bezug auf mögliche Manipulationen – werden im Wesentlichen vier Schritte benötigt:

  1. Einbinden einer Hashfunktion zur Verschlüsselung von Informationen
  2. Erstellen der Klassen block und blockchain sowie die Definition verschiedener Befehle für beide Klassen, bspw. um einen weiteren Block an eine Chain anzufügen oder die Gültigkeit der Blockchain zu überprüfen
  3. Erstellen einer spezifischen Instanz einer Blockchain sowie von ersten Blöcken
  4. Manipulieren der Blockchain (zur Illustration werden hier drei Arten vorgestellt):
    • Bei Manipulation 1 wird ausschließlich die Information eines einzelnen Blocks geändert.
    • Bei Manipulation 2 wird zusätzlich der Hash des manipulierten Blocks neu berechnet und im folgenden Block abgespeichert.
    • Bei Manipulation 3 werden zusätzlich die Hashwerte aller folgenden Blöcke neu berechnet und im jeweils folgenden Block abgespeichert, um die Manipulation zu vertuschen.

Der Code – Abschnitt 1

# Hashfunktion sha256 einbinden

from hashlib import sha256


Zum Verschlüsseln der Daten in den Blöcken der Blockchain bzw. zum Erzeugen der Hashwerte der einzelnen Blöcke einer Blockchain muss eine Hashfunktion verwendet werden (vgl. Beitrag Blockchains und Hashfunktionen). Dafür wird aus der Bibliothek hashlib die sha256 Funktion geladen, welche auch beim Bitcoin Anwendung findet und Hashwerte mit einer Länge von 64 Zeichen (in Hexadezimalschreibweise) erzeugt.

Der Code – Abschnitt 2

# Die Klasse block für die einzelnen Blöcke der Blockchain wird definiert.

class block:

  #Definition, wie ein Block erstellt wird.

  def __init__(self,blocknummer, date, information):

    self.blocknummer = blocknummer

    self.date = date

    self.letzterHash = ''

    self.information = information

  #Definition, welche Informationen über einen Block via "print" ausgegeben werden.

  def __str__(self):

    return ('Block       #{}'.format(self.blocknummer)+ "\n"+

    'Datum       {}'.format(self.date) + "\n"+

    'letzterHash {}'.format(self.letzterHash) + "\n"+

    'Information {}'.format(self.information)+ "\n")

  #Definition des Befehls "hashBerechnen", der auf Elemente der Klasse block angewendet werden kann.

  def hashBerechnen(self):

    return(sha256(bytes(str(self.blocknummer) + str(self.date) + str(self.letzterHash) + str(self.information), encoding='utf-8')).hexdigest())


Vor Definition der Blockchain wird zunächst die Klasse block erstellt, wobei jeder Block eine Blocknummer, das jeweilige Erstellungsdatum, den Hash des (in der Blockchain) vorangegangen Blocks sowie einen beliebigen Informationsteil enthalten soll. Beim Erstellen eines Blocks müssen dabei Blocknummer, Erstellungsdatum und die zu speichernden Informationen explizit angegeben werden, der Hash des vorhergehenden Blocks jedoch nicht. Dieser wird später beim Anfügen an eine Blockchain automatisch hinzugefügt und bleibt zunächst leer.

Friedrich Plus Mathematik

Ihr kostenloser 30-Tage-Pass für alle -Artikel + 5 Downloads:

Anmelden

Für Instanzen der Klasse Block wird anschließend definiert, welche Informationen durch den print-Befehl ausgegeben werden sollen. Desweiteren wird der Befehl hashBerechnen für die Klasse block definiert, welcher den Hashwert eines Blocks in Hexadezimalschreibweise ausgibt. Zur Berechnung des Hashwertes wird die Funktion sha256 verwendet und alle im Block enthaltenen Daten (Blocknummer, Datum, letzter Hash und die gespeicherte Information) verwendet.

# Die Klasse blockchain für die gesamte Blockchain wird eingeführt.

class blockchain:

  #Definition, wie eine Blockchain erstellt wird. Dafür wird der aktuelle Block auf 0 gesetzt, sowie eine Liste "chain" erstellt, welche die Blöcke der Blockchain enthält. Als erstes Element der Liste wird ein GenesisBlock erstellt.

  def __init__(self):

    self.aktBlock = 0

    self.chain = [self.genesisBlockErstellen()]

  #Definition, welche Informationen über eine Blockchain via "print" ausgegeben werden.

  def __str__(self):

    temp = ""

    for j in range(0,self.aktBlock+1):

      temp+=str(self.chain[j])

    return temp


Anschließend wird die Klasse blockchain definiert. Bei der Initiierung einer entsprechenden Blockchain Instanz wird dabei zunächst die aktuelle Anzahl an Blöcken der Blockchain auf 0 gesetzt, sowie ein GenesisBlock erstellt, wobei letzteres mit dem Befehl genesisBlockErstellen, der noch definiert wird, geschieht.

Vor der Definition von Befehlen für Instanzen der Klasse Blockchain wird zunächst definiert, welche Informationen durch den print-Befehl ausgegeben werden sollen. Dabei wird zum ersten Mal eine for-Schleife verwendet, welche die Blöcke der Blockchain automatisch durchgeht. Dabei wird die Variable j verwendet, um die einzelnen Blöcke der Blockchain durchzugehen und die Variable temp für jeden Wert der Variable j um die Daten von Block j erweitert.

Tipp: Sofern nicht schon bekannt, kann an dieser Stelle die Funktionsweise einer for-Schleife und die Definition von Variablen in entsprechenden Schleifen besprochen werden. Mathematisch lässt sich dies beispielsweise an die iterative Definition von Folgen anbinden.

  #Definition mehrerer Befehle, die auf Elemente der Klasse blockchain angewendet werden können.

  #Definition des Befehls, der einen GenesisBlock erstellt.

  def genesisBlockErstellen(self):

    return Block(0, "01.01.2020","GenesisBlock")

  #Definition des Befehls "blockHinzufuegen", der an eine bestehende Blockchain einen Block anhängt.

  def blockHinzufuegen(self,newBlock):

    newBlock.letzterHash=self.chain[self.aktBlock].Hashberechnen()

    self.chain.append(newBlock)

    self.aktBlock = self.aktBlock + 1

  #Definition des Befehls "testeChainGueltig", der eine Blockchain auf ihre Gültigkeit prüft.

  def testeChainGueltig(self):

    for i in range(0,self.aktBlock):

      letzterBlock = self.chain[i]

      naechsterBlock = self.chain[i+1]

      if naechsterBlock.letzterHash != letzterBlock.hashBerechnen():

        return print('Die Blockchain ist ungültig. Der in Block ' + str(i+1) + ' hinterlegte Hash von Block '+ str((i)) + ' passt nicht zum aktuellen Hash von Block '+ str((i)) +'.')

    return print('Die Blockchain ist gültig.')


Anschließend werden die Befehle genesisBlockErstellen, blockHinzufuegen, testeChainGueltig definiert. Der Befehl genesisBlockErstellen erstellt dabei einen Block mit Blocknummer 0, dem Erstellungsdatum „01.01.2020“ sowie der Information „GenesisBlock“.

Tipp: Eine einfache Übung kann sein, statt des festen Datums „01.01.2020“ das jeweils aktuelle Datum, ggfs. auch mit Zeitstempel einzufügen. Dies kann ebenso für beliebige Instanzen der Klasse Block geschehen.

Der Befehl blockHinzufuegen wird benötigt, um einen neuen Block an eine Instanz der Klasse Blockchain anzuhängen. Dafür wird der Hash des aktuell letzten Blocks der Blockchain berechnet und im neuen Block gespeichert. Der neue Block wird anschließend an die Blockchain angefügt und die aktuelle Blocknummer um 1 erhöht.

Der Befehl testeChainGueltig ist erforderlich, um eine Instanz der Klasse Blockchain auf ihre Gültigkeit hin zu prüfen. Dafür werden jeweils die Hashwerte aller Blöcke bestimmt (mit Ausnahme des letzten, also des aktuellen Blocks) und mit den im darauffolgenden Block gespeicherten Hash verglichen. Stimmen alle Hashwerte überein, wird „Die Blockchain ist gültig“ ausgegeben, ansonsten eine Fehlermeldung, an welcher Stelle in der Blockchain der (erste) Fehler aufgetreten ist.

Der Code – Abschnitt 3

#Eine Instanz der Klasse blockchain mit Namen dsCoin wird erstellt.

dsCoin = blockchain()

print('So sieht die Blockchain momentan aus:');

print(dsCoin)

#Blöcke mit Kontobewegungen hinzufügen

dsCoin.blockHinzufuegen(block(1,"12.01.2020","Ueberweisung:+400"))

dsCoin.blockHinzufuegen(block(2,"17.01.2020","Ueberweisung:+1000"))

dsCoin.blockHinzufuegen(block(3,"31.01.2020","Ueberweisung:-1200"))

dsCoin.blockHinzufuegen(block(4,"03.02.2020","Ueberweisung:-800"))

dsCoin.blockHinzufuegen(block(5,"14.02.2020","Ueberweisung:+200"))

print('So sieht die Blockchain momentan aus:');

print(dsCoin)


Es wird zunächst eine Blockchain mit dem Namen dsCoin erzeugt und direkt mit Hilfe des print-Befehls alle enthaltenen Informationen ausgegeben. Die neu erzeugte Blockchain dsCoin besteht nur aus dem Genesisblock.

Anschließend werden der Blockchain fünf Blöcke hinzugefügt, die jeweils Überweisungen eines fiktiven Kontos enthalten. Bei jedem Block wird zusätzlich noch das Datum der Erstellung gespeichert (momentan noch manuell eingegeben, vgl. Tipp).

Tipp: Anstatt die Blocknummer fehleranfällig selbst einzugeben, könnte der Code auch dahingehend geändert werden, dass die Blocknummer erst beim Anhängen an eine Blockchain automatisch eingetragen wird. Dies ist analog zur Information letzterHash möglich.

Die Blockchain wird anschließend nochmals ausgegeben. Dabei werden die Hashwerte der einzelnen Blöcke (genauer der Blöcke 0 bis 4) erstmals sichtbar.

#Hashwerte aller Blöcke berechnen, um diese manuell mit den in der Blockchain gespeicherten Werten zu vergleichen.

print('Berechne Hashwerte der Blöcke:');

for i in range(0,dsCoin.aktBlock):

             print('Hash von Block ' + str(i) + ": "+ dsCoin.chain[i].hashBerechnen())


Zur Überprüfung der Hashwerte können diese anschließend manuell berechnet und ausgegeben werden. Dies ist hier mit Hilfe einer for-Schleife gelöst, welche sich automatisch an die Anzahl der Blöcke der Blockchain anpasst. Die Hashwerte können mit denen in der Blockchain verglichen werden und die Blockchain so manuell geprüft werden.

Tipp: Statt der Schleife könnten initial auch fünf einzelne Befehle für jeden Block verwendet werden und die Schülerinnen und Schüler mit der Verallgemeinerung mittels der for-Schleife beauftragt werden.

Tipp: Im Rahmen der for-Schleifen wird der Befehl range verwendet, der bei einer Eingabe range(n,m) alle Zahlen n, n+1, …, m-1 ausgibt. Das Verhalten am Rand des Bereichs, also die Inklusion von n und Exklusion von m können auch besprochen werden und sind bei der Verwendung in der Schleife sehr wichtig.

#Blockchain mit Programm auf Gültigkeit prüfen.

print('Test der Blockchain:')

dsCoin.testeChainGueltig()


Statt einer manuellen Überprüfung der Blockchain wird abschließend erstmals die dafür geschriebene Funktion verwendet, welche die Blockchain in diesem Fall als gültig ausweist.

Fachnewsletter Mathematik

  • Fertige Unterrichtseinheiten
  • Methoden für die Praxis
  • Didaktisches Hintergrundwissen
  • Kostenlos - jederzeit kündbar

Der Code – Abschnitt 4

#Manipulation 1: Kontobewegung in Block 2 verändern.

dsCoin.chain[2].information = "Ueberweisung:+10000"

#Blockchain ausgeben lassen und auf Gültigkeit prüfen.

print('So sieht die erste modifizierte Chain aus:');

print(dsCoin)

print('Aktueller Hash von Block 2: '+ dsCoin.chain[2].hashBerechnen())

print('Test der Blockchain:')

dsCoin.testeChainGueltig()


Als simpelste Manipulation der Blockchain wird zunächst der Inhalt von Block 2 durch eine wesentlich höhere Überweisung überschrieben. Offensichtlich ein plumper Manipulationsversuch.

Bei der Ausgabe der Blockchain wird klar, dass außer der Überweisung an der Blockchain keine weiteren Informationen geändert wurden, insbesondere haben sich die in der Blockchain gespeicherten Hashwerte nicht verändert.

Durch die veränderte Information in Block 2, hat sich dessen Hashwert jedoch geändert, welcher anschließend manuell ausgegeben wird.

Die Gültigkeitsprüfung der Blockchain ergibt einen Fehler, da der in Block 3 hinterlegte Hash von Block 2 nicht zum aktuellen Hash von Block 2 passt.

#Manipulation 2: Hash von Block 2 basierend auf dem manipulierten Geldeingang neu berechnen und in Block 3 speichern.

dsCoin.chain[3].letzterHash = dsCoin.chain[2].hashBerechnen()

#Chain ausgeben lassen und auf Gültigkeit prüfen.

print('So sieht die zweite modifizierte Chain aus:');

print(dsCoin)

print('Aktueller Hash von Block 3: '+ dsCoin.chain[2].hashBerechnen())

print('Test der Blockchain:')

dsCoin.testeChainGueltig()


Als zweite Manipulation wird zur Vertuschung der Manipulation in Block 2 anschließend der neue Hashwert von Block 2 in Block 3 hinterlegt und die gesamte Blockchain erneut ausgegeben. Der in Block 3 hinterlegte Hashwert passt nun zu dem manipulierten Block 2, jedoch hat sich durch die Änderung des in Block 3 hinterlegten Hashwertes der Hashwert von Block 3 geändert.

Tipp: An dieser Stelle wird sichtbar, wie essentiell es für die Sicherheit der Blockchain ist, dass die Funktion hashBerechnen nicht nur die Informationen eines Blocks, sondern alle darin gespeicherten Daten als Grundlage verwendet. Wäre dies nicht der Fall, hätte sich hier der Hashwert von Block 3 nicht geändert und eine erfolgreiche Manipulation wäre möglich gewesen.

Die Gültigkeitsprüfung ergibt entsprechend einen Fehler, dass diesmal der in Block 4 hinterlegte Hash von Block 3 nicht zum aktuellen Hash von Block 3 passt.

#Manipulation 3: Alle Hashes ab Block 2 neu berechnen, um Manipulation zu verschleiern.

for i in range(2,dsCoin.aktBlock):

             dsCoin.chain[i+1].letzterHash = dsCoin.chain[i].hashBerechnen()

#Blockchain ausgeben lassen und auf Gültigkeit prüfen.

print('So sieht die dritte modifizierte Chain aus:');

print(dsCoin)

print('Test der Blockchain:')

dsCoin.testeChainGueltig()


Als letzte Manipulation werden alle Hashwerte beginnend bei Block 2 neu berechnet und im jeweils folgen Block abgespeichert. Die manipulierte Blockchain enthält damit sowohl die manipulierte Information aus Block 2 als auch lauter aktuelle Hashwerte, sodass eine Feststellung der Manipulation zunächst nicht möglich ist. Entsprechend positiv fällt die Gültigkeitsprüfung der Blockchain aus, welche der Blockchain die Gültigkeit attestiert.

Zur Entdeckung der Manipulation wären hier entweder andere Kopien der Blockchain nötig, um diese mit der manipulierten Blockchain abzugleichen oder eine (mehr oder minder) instantane, dauerhafte Gültigkeitsprüfung der Blockchain, welche noch während der Manipulation der Blockchain zu Inkonsistenzen geführt hätte und damit die gerade stattfindende Manipulation offengelegt hätte.

  • Der gesamte Beitrag von Daniel Sommerhoff
  • Kompletter Python Blockchain-Code
  • Monatlich neue Anregungen für Ihr Unterrichtsfach
Fakten zum Artikel
Unterricht (45-90 Min) Schuljahr 8-13
Friedrich+ Mathematik Logo

Ihr kostenloser 30-Tage-Pass für alle -Artikel + 5 Downloads:

Anmelden

Ja, ich möchte gratis 6 vollständige Unterrichtseinheiten aus Friedrich+ bekommen.

Keine Kosten, keine Werbung – versprochen!

Fachnewsletter Mathematik
Jetzt Newsletter bestellen.

  • Fertige Unterrichtseinheiten
  • Methoden für die Praxis
  • Didaktisches Hintergrundwissen
  • Kostenlos - jederzeit kündbar
  • Der gesamte Beitrag von Daniel Sommerhoff
  • Kompletter Python Blockchain-Code
  • Monatlich neue Anregungen für Ihr Unterrichtsfach