Der euklidische Algorithmus für ganze Zahlen Ein unverzichtbares Verfahren in der Kryptographie ist der euklidische Algorithmus. In diesem Kapitel stellen wir die erste Version für ganze Zahlen vor. Sei im folgenden Z die Menge der ganzen Zahlen und sei der Betrag |a| von a œ Z definiert als a für a Ø 0 und als ≠a für a < 0. Definition 1. Eine Zahl a œ Z teilt genau dann eine Zahl b œ Z, wenn es eine Zahl c œ Z gibt mit ac = b. Wir nennen dann a auch einen Teiler von b. Grundlage für unsere weiteren Betrachtungen ist die ganzzahlige Division mit Rest. Theorem 1. Für a, b œ Z, b ”= 0, existieren eindeutige Zahlen r, s œ Z mit a = sb + r, wobei 0 Æ r < |b| gilt. Die Zahl s heißt der Quotient von a durch b und r heißt der (modulare) Rest von a durch b. Wir schreiben auch a mod b := r. Beweis. Zunächst zeigen wir die Existenz von Quotient und Rest: Wir setzen S := {a ≠ sb | s œ Z} fl N und wählen ein minimales r0 := a ≠ s0 b œ S. Wir nehmen nun an, dass a ≠ s0 b = r0 Ø |b| gilt. Falls b > 0, dann wäre r := r0 ≠ b = a ≠ (s0 + 1)b œ S, bzw. falls b < 0, dann wäre r := r0 + b = a ≠ (s0 ≠ 1)b œ S. In beiden Fällen hätten wir r < r0 , also einen Widerspruch zur Minimalität von r0 . Folglich ist die Annahme falsch und es gilt r0 < |b| und a = s0 b + r0 . Als nächstes zeigen wir die Eindeutigkeit: Angenommen es gibt zwei ganzzahlige Paare (s0 , r0 ) und (s1 , r1 ) mit r0 Ø r1 und a = s0 b + r0 und b = s1 b + r1 mit 0 Æ r0 , r1 < |b|. Subtraktion 16 michael braun der beiden Gleichungen ergibt (s0 ≠ s1 )b = r0 ≠ r1 . Folglich muss r0 ≠ r1 Ø 0 ein Teiler von b sein. Da aber 0 Æ r0 ≠ r1 < |b|, muss r0 ≠ r1 = 0 also r0 = r1 gelten. In diesem Fall gilt dann auch s0 ≠ s1 = 0 und somit s0 = s1 , da b ”= 0. Insgesamt ist somit auch die Eindeutigkeit von Quotient und Rest bewiesen. Wir definieren nun die Menge der größten gemeinsamen Teiler zweier ganzer Zahlen. Definition 2. Eine Zahl t œ Z heißt genau dann ein größter gemeinsamer Teiler von a, b œ Z, falls t ein Teiler von a und b ist und falls jeder Teiler s œ Z von a und b die Zahl t teilt. Die Menge der größten gemeinsamen Teiler von a und b wird mit gcd(a, b) abgekürzt. In dieser Definition haben wir den größten gemeinsamen Teiler nicht als einzelne Zahl, sondern als Menge angegeben. Diese Definition ist aber sinnvoll, da mit jedem größten gemeinsamen Teiler t von a und b auch ≠t ein größter gemeinsamer Teiler von a und b ist. Genaugenommen gilt t œ gcd(a, b) genau dann, wenn gcd(a, b) = {t, ≠t} gilt. Folglich ist der größte gemeinsame Teiler eindeutig bis auf die Menge der Einheiten Zú = {1, ≠1}. In der Praxis beschränkt man sich bei der Definition des größten gemeinsamen Teilers jedoch auf den normierten Wert |t| als eindeutigen Repräsentanten. Die Menge der größten gemeinsamen Teiler erfüllt folgende Rechenregeln. Lemma 1. Für a, b, s œ Z gilt: 1. gcd(a, b) = gcd(±a, ±b) 2. gcd(a, a) = aZú 3. gcd(a, 0) = aZú 4. gcd(a, 1) = Zú 5. gcd(as, bs) = s gcd(a, b) 6. gcd(b, a ≠ sb) = gcd(a, b) 7. gcd(b, a mod b) = gcd(a, b) public-key-algorithmen 17 Ein konstruktives Verfahren, welches zu a, b œ Z einen größten gemeinsamen Teiler berechnet, liefert der euklidische Algorithmus. Da die Berechnung bis auf Vorzeichen eindeutig ist, können wir uns darauf beschränken, dass a, b positiv sind und als größter gemeinsamer Teiler eine positive Zahl bestimmt wird. Der Algorithmus basiert auf der letzten Identität von Lemma 1, welche rekursiv angewandt wird. Algorithmus 1. Euklidischer Algorithmus (rekursiv) Input: a, b œ N mit a Ø b Output: t œ gcd(a, b) Procedure: Euklid(a, b) 1 if b = 0 then return a 2 else return Euklid(b, a mod b) Da aufgrund von Theorem 1 a mod b < b gilt, terminiert der Algorithmus nach endlichen vielen Schritten. Die Idee des euklidischen Algorithmus geht dem Namen nach bereits auf Euklid (300 v. Chr.) zurück. In seinem berühmten Werk „Die Elemente“1 wird die Methode zur Bestimmung eines größten gemeinsamen Teilers beschrieben, indem sukzessive die kleinere von der größeren Zahl abgezogen wird. Die ganzzahligen Divisionen werden also in dieser ersten Version von Euklid durch iterierte Subtraktionen erreicht. Eine nicht-rekursive Version ergibt sich durch die Division mit Rest. Durch eine iterierte Division mit Rest ri≠2 = si≠1 ri≠1 + ri werden ausgehend von r0 = a und r1 = b mit a Ø b solange die Reste ri mit i Ø 2 berechnet, bis rn+1 = 0 gilt. In diesem Fall erhalten wir dann rn œ gcd(a, b). Algorithmus 2. Euklidischer Algorithmus (iterativ) Input: a, b œ N mit a Ø b Output: t œ gcd(a, b) 1 v := a, u := b 2 while u ”= 0 do 3 r := v mod u /* r = v ≠ su für s = Âv/uÊ */ 4 v := u, u := r 5 return v Euklid. Die Elemente des Euklid, Euklides: Stoicheia. http://www.operaplatonis.de/euklid/ 1 18 michael braun Um nun die Anzahl der Schritte im euklidischen Algorithmus zu ermitteln, gehen wir vom schlechtesten Fall aus, dass bei der ganzzahligen Division mit Rest der ganzzahlige Anteil s = 1 ist. Dies führt zur Folge der Fibonacci-Zahlen, welche durch die Rekursion fi = fi≠1 + fi≠2 für i Ø 2 mit den Anfangsbedingungen f0 = 0 und f1 = 1 definiert ist. Führt man den Euklidischen Algorithmus mit zwei aufeinanderfolgenden Fibonacci-Zahlen fi+1 und fi aus, so ergibt sich als Rest immer die nächst kleinere Fibonacci-Zahl fi≠1 , also Âfi+1 /fi Ê = 1 und fi+1 mod fi = fi≠1 . Demnach müssen für die Anfangswerte fn+1 und fn im Euklidischen Algorithmus n Iterationen, d.h. n Divisionen mit Rest durchgeführt werden. Da Ô Ô fn = (Fn ≠ (1 ≠ F)n ) 5, wobei F = (1 + 5)/2 ¥ 1, 62 der Goldene Schnitt ist, erhalten wir, dass fn exponentiell wächst mit einem ansteigenden Wert für n. Diese Worst-Case-Betrachtung hat zur Folge, dass die Berechnung von gcd(a, b) höchstens logarithmisch für a und b ist, also linear mit der Stellenanzahl von a und b. Diese Tatsache, dass die Anzahl der ganzzahligen Divisionen mit Rest maximal für die Fibonacci-Zahlen ist, geht auf Lamé (1844) zurück2 . Korollar 1. Der euklidische Algorithmus für zwei ganze Zahlen a, b œ N mit a Ø b > 0 terminiert nach ¸ Æ logF (b) + 1 Schritten, Ô wobei F = (1 + 5)/2 ¥ 1, 62. Um nun den Gesamtaufwand des euklidischen Algorithmus zweier Zahlen a, b œ Z mit m ¥ log2 (a) ¥ log2 (b) zu bestimmen, können wir uns überlegen, dass eine Division mit Rest einen quadratischen Aufwand O (m2 ) besitzt. Da im schlechesten Fall O (m) Divisionsschritte benötigt werden, kommt man daher auf eine erste Gesamtaufwandsabschätzung von O (m3 ). Da durch die iterierten Divisionen die Zahlen aber kleiner werden, liefert der genaue Blick auf den Aufwand eine quadratische Komplexität. Ein Beweis ist beispielsweise bei Shoup3 zu finden. Theorem 2. Der euklidische Algorithmus für zwei Zahlen a, b œ N besitzt eine Komplexität von O (log(a) log(b)). Eine Version des euklidischen Algorithmus, welche binärer 2 T. E. Moore. Euclid’s Algorithm and Lamé’s Theorem on a Microcomputer. 27(4):290–295, August 1989 V. Shoup. A Computational Introduction to Number Theory and Algebra. Cambridge University Press, 2008 3 public-key-algorithmen euklidischer Algorithmus genannt wird, geht auf Stein4 zurück. Laut Knuth5 wurde diese Version bereits von Silver und Tersian verwendet, aber niemals publiziert. Die Idee ist, die teuren Divisionen durch Divisionen mit 2 und Subtraktionen zu ersetzen. Der binäre euklidische Algorithmus, auch zu Ehren seines Erfinders steinscher Algorithmus genannt, basiert auf folgenden Rechenregeln für den größten gemeinsamen Teiler, welche direkt aus Lemma 1 abgeleitet werden können. Korollar 2. Für die Menge der größten gemeinsamen Teiler von a, b œ Z gilt: 1. gcd(a, b) = 2 gcd(a/2, b/2), falls a und b gerade. 2. gcd(a, b) = gcd(a/2, b), falls a gerade und b ungerade. Diese beiden Regeln und Lemma 1(6) für s = 1 liefert folgenden Algorithmus. Algorithmus 3. Steinscher Algorithmus (rekursiv) Input: a, b œ N mit a Ø b Output: t œ gcd(a, b) Procedure: Stein(a, b) 1 if a = b then return a 2 if a is even then 3 if b is even then return 2 · Stein(a/2, b/2) 4 else return Stein(a/2, b) 5 else 6 if b is even then return Stein(a, b/2) 7 else return Stein(b, a ≠ b) Bei der Anweisung 6 sind beide Zahlen a und b ungerade. Somit ist die Zahl a ≠ b gerade und gcd(a, b) = gcd(b, a ≠ b) = gcd(b, (a ≠ b)/2). Anstelle von Stein(b, a ≠ b) hätten wir auch Stein(b, (a ≠ b)/2) setzen können. Eine nicht-rekursive Version kann wie folgt formuliert werden. Algorithmus 4. Steinscher Algorithmus (iterativ) Input: a, b œ N mit a Ø b Output: t œ gcd(a, b) 19 J. Stein. Computational Problems Associated with Racah Algebra. Journal of Computational Physics, 1(3):397–405, 1967 5 D. E. Knuth. The Art of Computer Programming. Volume 2: Seminumerical Algorithms. Addison-Wesley Professional, 1997 4 20 michael braun 1 2 3 4 5 6 7 v := a, u := b, e := 1 while v and u are even do v := v/2, u := u/2, e := 2e while u ”= 0 do while v is even do v := v/2 while u is even do u := u/2 if v Ø u then v := v ≠ u else u := u ≠ v return ev Das folgende Lemma von Bézout besagt, dass man einen größten gemeinsamen Teiler zweier Zahlen als ganzzahlige Linearkombination der beiden Ausgangszahlen darstellen kann. Lemma 2 (Bézout). Für ganze Zahlen a, b œ Z existieren ganze Zahlen g, h œ Z mit ag + bh œ gcd(a, b). Der Beweis erfolgt konstruktiv mit Hilfe des erweiterten euklidischen Algorithmus: Ohne Einschränkung der Allgemeinheit nehmen wir a, b œ N mit a Ø b an. Wir gehen von den Gleichungen a·1+b·0 = a a·0+b·1 = b aus und führen auf der rechten Seite den ersten Schritt des euklidischen Algorithmus aus, d.h. wir ziehen ein Vielfaches von b von a ab, so dass es den Rest r = a mod b ergibt, etwa r = a ≠ s · b. Die Erweiterung ist nun, dass wir auf der linken Seite denselben Schritt durchführen, d.h. wir ziehen das s-fache der zweiten Gleichung von der ersten Gleichung ab und erhalten a(1 ≠ s · 0) + b(0 ≠ s · 1) = r. Als nächstes setzen wir den euklidischen Algorithmus für b und r fort – sowohl für die rechte als auch für die linke Seite der Gleichungen – bis der positive größte gemeinsame Teiler von a und b auf der rechten Seite berechnet ist. Die entsprechenden Koeffizienten für a und b auf der linken Seite sind dann die gesuchten Werte für g und h. Allgemein starten wir mit v := a und u := b und berechnen mit Algorithmus 4 den größten gemeinsamen Teiler, wobei die Gleichungen ag1 + bh1 = v ag2 + bh2 = u public-key-algorithmen mit v Ø u erfüllt bleiben. Der Algorithmus terminiert, wenn u = 0. In diesem Fall gilt dann v œ gcd(a, b) und g := g1 und h := h1 sind die gesuchten Koeffizienten mit ag + bh œ gcd(a, b). Durch diese Modifikation von Algorithmus 4 können wir eine Variante des euklidischen Algorithmus in erweiterter Form angeben. Algorithmus 5. Erweiterter euklidischer Alg. (iterativ) Input: a, b œ N mit a Ø b Output: (t, g, h) mit ag + bh = t œ gcd(a, b) 1 g1 := 1, h1 := 0, v := a 2 g2 := 0, h2 := 1, u := b 3 while u ”= 0 do 4 s := Âv/uÊ 5 r := v ≠ su, g := g1 ≠ sg2 , h := h1 ≠ sh2 6 g1 := g2 , h1 := h2 , v := u 7 g2 := g, h2 := h, u := r 8 return (v, g1 , h1 ) Des weiteren kann der steinsche Algorithmus auch um die Berechnung der Bézout-Koeffizienten erweitert werden. Wir können ohne Einschränkung davon ausgehen, dass nicht beide Werte a und b gleichzeitig gerade sein können. Ansonsten können wir aufgrund von Korollar 2 (1) solange den Faktor 2 ausklammern, bis mindestens einer der neuen Werte a oder b ungerade ist. Außerdem gilt weiterhin a Ø b. Falls dies nicht gilt, müssen die beide Werte einfach vertauscht werden. Anschließend setzen wir mit den Startbedinungen g1 := 1, h1 := 0, v := a und g2 := 0, h2 := 1, u := b den steinschen Algorithmus fort, so dass zu jedem Zeitpunkt die Invarianzen ag1 + bh1 = v ag2 + bh2 = u mit |v| Ø |u| erfüllt bleiben. Falls v gerade ist und u ungerade, dann gilt gcd(v, u) = gcd(v/2, u), d.h. wir müssen die Gleichung ag1 + bh1 = v derart anpassen, dass hinterher v mit v/2 überschrieben wird. Dabei müssen folgende Fälle betrachtet werden. 1. Falls g1 und h1 gerade sind, so gilt a(g1 /2) + b(h1 /2) = v/2. 21 22 michael braun 2. Falls g1 und h1 ungerade sind, so müssen a und b beide ungerade sein. 3. Falls g1 gerade und h1 ungerade sind, so muss h1 · b gerade sein und somit auch b. Folglich ist a ungerade. 4. Falls h1 gerade und g1 ungerade sind, so muss g1 · a gerade sein und somit auch a. Folglich ist b ungerade. In allen drei Fällen (2),(3) und (4) sind g1 + b und h1 ≠ a gerade und es gilt folgende Gleichung a(g1 + b) + b(h1 ≠ a) = v bzw. a(g1 + b)/2 + b(h1 ≠ a)/2 = v/2. Analog können wir die zweite Gleichung ag2 + bh2 = u behandeln. Insgesamt kann der steinsche Algorithmus wie folgt erweitert werden. Algorithmus 6. Erweiterter steinscher Algorithmus (iterativ) Input: a, b œ N mit a Ø b Output: (t, g, h) mit ag + bh = t œ gcd(a, b) 1 aÕ := a, bÕ := b, e := 1 2 while aÕ and bÕ are even do aÕ := aÕ /2, bÕ := bÕ /2, e := 2e 3 g1 := 1, h1 := 0, v := a 4 g2 := 0, h2 := 1, u := b 5 while u ”= 0 do 6 while v is even do 7 v := v/2 8 if g1 and h1 are even then g1 := g1 /2, h1 := h1 /2 9 else g1 := (g1 + bÕ )/2, h1 := (h1 ≠ aÕ )/2 10 while u is even do 11 u := u/2 12 if g2 and h2 are even then g2 := g2 /2, h2 := h2 /2 13 else g2 := (g2 + bÕ )/2, h2 := (h2 ≠ aÕ )/2 14 if v Ø u then v := v ≠ u, g1 := g1 ≠ g2 , h1 := h1 ≠ h2 15 else u := u ≠ v, g2 := g2 ≠ g1 , h2 := h2 ≠ h1 16 return (ev, eg1 , eh1 )