Der Satz von Euler stellt eine Verallgemeinerung des „kleinen Satzes von Fermat“ auf beliebige Moduli dar.
Der Satz von Euler besagt folgendes:
Falls der
Beweis: Es gilt: ( sind teilerfremd). 1) man nehme zu teilerfremde Zahlen aus : 2) man multipliziere mit und erhält:
Einschub Beispiel:
für (da 2 teilerfremd zu )
Beweis (Fortsetzung): 3) Bilden des Produktes aller und aller 4) Nun kann abschließend durch geteilt werden, da alle teilerfremd zu sind.
Der Satz von Euler dient der Reduktion großer Exponenten . Praktische Anwendung findet er u.a. in der Kryptographie beispielsweise beim RSA-Verschlüsselungsverfahren.
Der kleine Satz von Fermat trifft folgende Aussage: Wenn (also wenn eine Primzahl ist) und wenn ( teilt nicht ) dann gilt für alle aus :
Beweis: Seien von verschiedene Zahlen. Dann kann gezeigt werden, dass es zu jedem genau ein gibt, so dass
(1)
vorliegt. Im Widerspruch zur Behauptung wird nun angenommen, dass und vorgefunden werden kann, so dass
(2)
gilt. Da eine Primzahl und kein Teiler von ist, muss sein. Auf Grund dessen, kann durch gekürzt werden und man erhält:
Wegen ist daher im Widerspruch zu . Die Behauptung (1) ist daher richtig.
Die jeweils zusammengehörenden Kongruenzen (1) für können nun mit erweitert werden und man erhält dann:
Da und die Primzahl teilerfremd sind können diese Konkruenzen durch dividiert werden und man erhält die obige Behauptung.
Der große Satz von Fermat
Der große Satz von Fermat wird hier nur der Vollständigkeit halber kurz vorgestellt, da wenn man vom „kleinen Satz von Fermat“ hört, man sich berechtigterweise auch die Frage stellt, ob es dann auch einen „großen Satz von Feramt“ gibt.
Der große Satz von Fermat besagt: Ist , so kann die jeder natürlichen Zahl ungleich null nicht in die Summe zweier natürlicher Zahlen ungleich null zerlegt werden.
Dies bedeutet formal ausgedrückt:
Obige Gleichung ist für positive ganze Zahlen unlösbar wenn größer als zwei ist.
Laut Wikipedia sind zwei Zahlen und kongruent , wenn sie bei der Division durch denselben Rest haben. Dies ist genau dann der Fall, wenn sie sich um ein ganzahliges Vielfaches von unterscheiden. Stimmen die Reste nicht überein, so nennt man die Zahlen inkongruent . Jede Kongruenz modulo einer ganzen Zahl ist eine Kongruenz auf dem Ring der ganzen Zahlen.
Verdeutlicht wird dies anhand folgender Beispiele:
; da und ist.
; da und ist.
; da und ist.
Ein einfaches Python-Programm zum bestimmen der Kongruenz zweier Zahlen und modulo für kann wie folgt implementiert werden:
def isKongruent(a, b, m):
restA = a % m
restB = b % m
if restA == restB:
return True
else:
return False
if __name__ == '__main__':
print("Sind a und b kongruent mod m?", isKongruent(7, 19, 4))
Obiges Programm liefert als Wahrheitswert True da ist.
Die Eulersche -Funktion gibt für jede natürliche Zahl an, wie viele zu teilerfremde natürliche Zahlen es gibt, die nicht größer als sind.
Definition:
Sei : Die Eulersche -Funktion ist dann definiert durch: dabei bezeichnet den größten gemeinsamen Teiler von .
Beispiele:
denn in der Menge sind nur die Zahlen 1, 5, 7, 11 teilerfremd.
da 13 eine Primzahl ist, sind alle Zahlen die kleiner sind als 13 teilerfremd.
Es lassen sich nun folgende Aussagen treffen:
1) Für jede Primzahl gilt: . 2) Sei eine Primzahl und . Dann gilt:
Beispiel zu 2):
In Python lässt sich die Berechnung von relativ einfach wie folgt implementieren:
def calcphi(phivonN):
i = 1
wertPhi = 0
while i < phivonN:
if testggT(i, phivonN) == 1:
wertPhi += 1
i += 1
return wertPhi
def testggT(i, phivonN):
while phivonN!=0:
i ,phivonN = phivonN, i % phivonN
return i
if __name__ == '__main__':
phivonN = 12
print("Phi(",phivonN,")", "= ", calcphi(phivonN))
Sowohl im Ring der ganzen Zahlen (ganze Zahlen können ohne Einschränkung addiert, subtrahiert und multipliziert werden) als auch im Polynomring über einem Körper kann stets die Division mit Rest (euklidischer Ring) durchgeführt werden.
Formaler Algorithmus:
Seien .
1) Berechne den ganzzahligen Quotienten von und .
2) Berechne den Rest .
3) Gebe und aus.
Dann gilt: mit .
Unter einer Primzahl versteht man eine von 1 verschiedene natürliche Zahl, die nur durch 1 und durch sich selbst teilbar ist. Die Menge der Primzahlen wird in der Regel mit dem Symbol bezeichnet. Mit verknüpft ist die Folge der nach ihrer Größe geordneten Primzahlen, die man auch Primzahlfolge nennt.
Demanch gilt:
Da wir nun festgelegt haben, was eine Primzahl ist, stellt sich nun die
Frage, wofür werden diese in der Kryptographie verwendet und warum haben
diese einen so großen Stellenwert inne? In der Kryptographie basieren viele Verschlüsselungsverfahren auf Primzahlen, so z.B. das RSA (Rivest-Shamir-Adleman)-Verfahren.
Beispiel einer verschlüsselten Übertragung anhand des RSA-Verfahrens: Die Personen Alice und Bob möchten verschlüsselt kommunizieren. Zuerst möchte Bob Alice eine geheime Nachricht schicken. Um dies zu ermöglichen, trifft Alice folgende Vorbereitungen:
1) Alice wählt zufällig zwei Primzahlen und .
2) Sie berechnet und .
3) Dann wählt Sie mit .
4) Alice bestimmt mit .
5) Dann ist der öffentliche und der geheime Schlüssel.
6) Die Werte und löscht Alice.
Bob möchte nun Alice die Nachricht schicken. Er geht nun wie folgt vor:
7) Bob berechnet und schickt an Alice.
8) Alice berechnet .
Es stellen sich nun z.B folgende Fragen:
Wie findet man ausreichend große Primzahlen und ?
Was bedeutet die Funktion ?
Wie wird die Rechenoperation (Division mit Rest) angewendet ?
Auf diese Fragen wird in Beiträgen in den Kategorien Zahlentheorie und Primzahltest noch näher eingegangen.
Die modulare Exponentiation spielt in der Kryptographie sowie zum ver- als auch zum entschlüsseln von Nachrichten eine wichtige Rolle. Beim RSA-Verfahren z.B. besteht die Chiffrierung in der Berechnung von .
Verschiedene Möglichkeiten eine Potenzierung duchzuführen:
Eine naive Methode wäre es durch eine Reihe von Multiplikationen zu berechnen. Demnach wären Multiplikation notwendig.
Eine weitere Methode wäre das Wiederholte Quadrieren:
Ein effizienteres Potenzieren kann auch wie folgt durchgeführt werden:
Ein gutes Rezept für ein schnelles Potenzieren ist für ein allgemeines b ins Binärsystem zu überführen:
anschließend berechnet man wiederholt Quadrate von , dies erzeugt nacheinander:und multipliziert ein zum Endergebnis wenn . Daraus ergibt sich eine höchste Anzahl an Multiplikationen von .
Programmbeispiel der modularen Exponentiation
Es gilt z.Bsp.:
daraus folgt für :
Rekursiv kann die modularen Exponentiation wie folgt für mit beschrieben werden:
Eine rekursive Implementierung der obigen Rekursionsformeln mit in Python mit dem Rückgabewert als Ergebnis 1:
def modexp(m, b, n):
if b == 0:
return 1
if b % 2==1:
return modexp(m, b-1, n)*m % n
else:
return modexp(m, b//2, n)**2 % n
if __name__ == '__main__':
print(modexp(2,4,5))
Eine iterative Implementierung von in Python nach der „naiven Methode“ sieht wie folgt aus:
def modexpIt(m, b, n):
bs=1
while(b > 0):
bs *= m
b -= 1
erg = bs % n
return erg
if __name__ == '__main__':
print(modexpIt(2,4,5))
Das obige Beispiel verdeutlicht nocheinmal, dass für die Berechnung von b-1 Multiplikation bzw. b-1 Schleifendurchläufe notwendig sind. Bezugnehmend auf das Laufzeitverhalten der Iterativen Implementierung zur Berechnung von kann man somit sagen, dass diese (für ) beträgt lineares Laufzeitverhalten.
Binäres Potenzieren
Das binäre Potenzieren ist eine effizientere Methode für die Exponentation, als die zuvor beschriebenen Verfahren. Sie funktioniert wie folgt:
Für wobei wird binär dargestellt. Für jede 1 wird nun die Operation quadrieren und multiplizieren (QM) und für jede 0 die Operation quadrieren (Q) durchgeführt. Wobei die führende 1 gestrichen werden kann, da die Binärdarstellung für immer mit einer 1 beginnt und damit auch die erste Anweisung mit QM, ergibt sich hierfür .
Beispiel:
für und .
die führende 1 wird nun gestrichen 101. Nun werden für folgende Operationen durchgeführt:
QMQ QM
Für ergibt sich nun:
QM
Q
QM
Kongret für erhält man:
In der Programmiersprache Python lässt sich das Ganze wie folgt beschreiben:
'''Umwandlung in binaer und Ergebnis als Liste zurueckliefern'''
def sammleBin(exponent):
binListe = []
tmpgerade = 0
if exponent % 2 == 0:
tmpgerade = exponent
exponent = exponent + 1
while exponent != 0:
binListe.insert(0,exponent % 2)
exponent = exponent // 2
if tmpgerade != 0:
binListe[len(binListe)-1] = 0
'''erstes Element aus Liste entfernen'''
del binListe[0]
return binListe
'''Entsprechende Operationen durchfuehren (QM oder Q)'''
def binPotenz(basis, expo):
binListe = sammleBin(expo).copy()
wert = basis
for i in range(0, len(binListe)):
if(binListe[i] == 1):
wert = basis * (wert**2)
else:
wert = wert**2
return wert
if __name__ == '__main__':
print("",binPotenz(5, 13))
Nähere Informationen über die Binäre Exponentiation findet man bei Wikipedia.
Die moderne Kryptographie beruht auf unterschiedlichen mathematischen Rechenverfahren. Im wesentlichen sind diese: die schnelle modulare Exponentiation , der darauf aufbauende Primzahltest und der erweiterte euklidische Algorithmus (engl. expanded greatest common divisor EGCD).
Es gibt viele Gründe, sich aus sicherheitstechnischen Überlegungen mit Kryptographie zu beschäftigen. Die Kryptographie ist aber insbesondere auch ein interdisziplnäres Feld in der Mathematik, das sich Resultaten aus Computeralgebra, Algebra, Zahlentheorie, Komplexitätstheorie usw. bedient und so zeigt , wie sich verschiedene Zweige der Mathematik in aktuellen Technologien wiederfindet.