Primzahltest in Polynomialzeit Der Algorithmus von Agrawal, Kayal und Saxena 1. Worum geht es? Das Problem, um das es geht, heißt „PRIMES“. Es entscheidet für eine vorgegebene Zahl n > 2 die Frage, ob n prim oder zusammengesetzt ist. Algorithmentheoretisch heißt das: PRIMES = { bin(k) | k ist eine Primzahl } Die Menge PRIMES enthält also die Binärdarstellungen aller Primzahlen und ist damit eine Sprache: PRIMES ⊆ {0,1}*. Zuerst einmal lässt sich feststellen, dass diese Sprache entscheidbar ist, denn man kann sehr leicht einen (sogar deterministischen) Algorithmus angeben, der die Frage: „n∈ PRIMES?“ für alle natürlichen Zahlen n löst. Man prüft einfach für alle ungeraden Zahlen i mit 2 ≤ i ≤ n , ob n ohne Rest durch i teilbar ist. Wenn der Test für alle i fehlschlägt ist n prim, und ansonsten zusammengesetzt. Dieser einfache Algorithmus ist aber für die für Informatiker interessante Frage, ob PRIMES in der Klasse P, der deterministisch in polynomieller Zeit in der Länge der Eingabe entscheidbaren Sprachen, liegt, schon nicht mehr zu verwenden, denn als Länge der Eingabe gilt für PRIMES die Anzahl der Bits der Binärdarstellung von n: |bin(n)| = log 2 (n + 1) Ein Polynomialzeitalgorithmus für PRIMES hat also für ein Polynom p eine Laufzeit von O(p(|bin(n)|)) = O(p(log(n))). Der Algorithmus benötigt aber O( n ) Divisionen. Bisher hatte man aber auch keinen anderen deterministischen Algorithmus gefunden, der dieses Kriterium erfüllt. Der schnellste deterministische Algorithmus, der bis August 2002 bekannt war, lief in O((log n)c log log log n), was aber leider ganz knapp exponentiell in |bin(n)| ist. Also musste man an einer anderen Stelle Abstriche machen: Dem Determinismus. Man fand randomisierte Algorithmen, die das Problem mit einer von n unabhängigen Fehlerwahrscheinlichkeit in O(log(n)) lösten. Wollte man eine von n abhängige Fehlerwahrscheinlichkeit, also etwa n-c für eine Konstante c, kostete das eine erhöhte Laufzeit: O((log n)2) . Unglücklicherweise kann es bei solchen randomisierten Algorithmen aber vorkommen, dass eine zusammengesetzte Zahl als prim deklariert wird, wenn auch nur mit einer sehr geringen Wahrscheinlichkeit. Der neue Algorithmus von Agrawal, Kayal und Saxena, dessen Laufzeit in O~((log n)6) (das „~“ bedeutet hier, dass Faktoren der Form (loglog n)k für eine Konstante k vernachlässigt werden) ist, hat verglichen mit den randomisierten Algorithmen, die das Primzahlproblem in der Praxis gut genug lösen, eine sehr hohe Laufzeit. Deshalb beschränken sich die 1 Auswirkungen der Entdeckung des Algorithmus eher auf den theoretischen Fortschritt als auf den praktischen Gewinn. Für die Kryptographie ist der Algorithmus immerhin insofern nützlich, dass er einen Verifizierer für die Frage, ob das Problem der Primfaktorzerlegung einer gegebenen Zahl m in der Komplexitätsklasse NP liegt, liefert. Beweis: Man rät eine Menge von Zahlen und zeigt für diese Zahlen deterministisch in Polynomialzeit, dass sie die Primfaktorzerlegung von m sind. Die Anzahl dieser Primfaktoren ist höchstens |bin(m)| = log 2 (m + 1) , also im erlaubten polynomiellen Rahmen, da im schlimmsten Fall m eine Zweierpotenz ist. Für alle geratenen Zahlen kann man in Polynomialzeit mit dem Algorithmus von Agrawal, Kayal und Saxena zeigen, dass diese auch wirklich prim sind. Und die Frage, ob diese Zahlen aufmultipliziert m ergeben lässt sich sogar in logarithmischer Zeit beantworten (dazu später mehr). 2. Die Grundidee Ausgegangen sind die drei Entdecker des Algorithmus von einem Satz aus der Algebra über Primzahlen: Satz 2.1: Sei n gilt: 2 eine natürliche Zahl und a eine zu n teilerfremde natürliche Zahl. Dann n ist prim ⇔ (X + a)n ≡ (Xn + a) (mod n). Beweis siehe [2] Wenn man also bei der rechten Aussage die linke Seite ausmultipliziert fallen modulo n gerechnet alle Summanden mit Koeffizienten ≠ 1 weg, weil sie Vielfache von n sind. Ein Beispiel: Setze n = 2 (X + a)² = X² + 2Xa + a² Wenn man nun den rechten Ausdruck modulo 2 rechnet fällt der Term 2Xa weg, weil 2 ein Teiler von 2Xa ist, also ergibt sich X² + a². Nun stellt sich natürlich die Frage: Wie nützt man diesen Satz in Bezug auf die Frage, ob n prim ist, aus? Man könnte zum Beispiel a = 1 wählen und dann alle Koeffizienten (mod n) des Polynoms, das man durch einfaches Ausmultiplizieren von (X + a)n erhält, berechnen. Die müssten, wenn n prim ist, alle – außer denen bei Xn und an, die natürlich immer 1 sind – modulo n wegfallen. Wenn einer oder mehr übrig bleiben, ist n zusammengesetzt. Der Haken dabei ist aber, dass man bei diesem Verfahren noch mehr Operationen hat als bei dem ganz naiven Algorithmus aus dem ersten Abschnitt: Man muss nämlich n + 1 Terme berechnen! Der eigentliche Trick des neuen Algorithmus ist es aber die Äquivalenz (X + a)n ≡ (Xn + a) (mod n) 2 über einen „Umweg“ zu testen. Man wählt sich nämlich ein Polynom Xr – 1 mit einem geschickt ausgesuchten r (dazu im nächsten Abschnitt mehr), und vergleicht die beiden Seiten dann nicht mehr nur noch modulo n sondern auch modulo dem neuen Polynom Xr – 1. Diese modulo-Operationen sind im Übrigen assoziativ, d.h. es ist egal in welcher Reihenfolge man sie ausführt, es kommt in beiden Fällen dasselbe heraus. Man berechnet also (X + a)n mod (n , Xr – 1) und (X n + a) mod (n , Xr – 1) und vergleicht wie bisher die Koeffizienten. Wenn n prim ist, müssen selbstverständlich nach wie vor alle Summanden außer Xn mod r und a mod n wegfallen. Das heißt, dass die Äquivalenz für alle r gilt. Nun möchte man aber nicht für alle r < n alle zu n teilerfremden a durchlaufen, um die Primalität von n zu erreichen, sondern man geht vom umgekehrten Fall aus. Man möchte also, wenn n zusammengesetzt ist, ein r finden können, bei dem die Äquivalenz nicht gilt. Und dieses r darf auch nicht zu groß sein, damit die Grade der Polynome nicht zu groß werden. Das wichtigste bei diesem Primzahltest ist es also herauszufinden, was ein geeignetes r ist, und vor allem auch zu zeigen, dass die auftretenden r nicht zu groß sind. Oder genauer: im erlaubten polynomiellen Rahmen sind. Aus algebraischen Gründen muss man, wenn man ein „gutes“ r gefunden hat, noch die erwähnte Äquivalenzbedingung für eine ganze Reihe von a testen, um dann schließen zu können, dass n Potenz einer Primzahl ist. Dieser Fall ist dann endlich leicht genug zu behandeln. 3. Der Algorithmus Input: ungerade Zahl n > 2 1. if ( n hat die Form ab für b > 1 ) then output zusammengesetzt; 2. r ← 2; 3. while ( r < n ) { 4. if ( ggt(n,r) 1 ) then output zusammengesetzt; 5. if ( r prim ) then 6. q ← grösster Primfaktor von r – 1; 7. if ( q ≥ 4 r log n ) 8. and ( n(r-1)/q ≡/ 1 (mod r) ) then 9. break; 10. r ← r + 1; 11. } 12. for a = 1 to 2 r log n do 13. if (X + a)n ≡/ (Xn +a) (mod Xr – 1, n) then 14. output zusammengesetzt; 15. output prim; 3 4. Die Laufzeitanalyse 4.1 Die Einzeloperationen Die wichtigste Operation im Algorithmus ist die Exponentiation. Sie kommt in den Zeilen 1, 8 und 13 vor. Um den Berechnungsaufwand gering zu halten wird die Exponentiation mit Hilfe einer rekursiven Funktion realisiert, die sich „schnelle Exponentiation“ nennt (im Englischen „repeated squaring“ (wiederholtes Quadrieren), oder auch „binary method“): Seien a > 0 und m 0 beliebige natürliche Zahlen. für m = 0 1, am = a, für m = 1 (a ²) s für m > 1, m gerade, m = 2 s (a ²) s ⋅ a für m > 1, m ungerade, m = 2 s + 1 Offensichtlich werden für diese Art der Exponentiation maximal 2 log2 m Multiplikationen benötigt. Die Laufzeit der „schnellen Exponentiation“ ist also in O(log m). Im ganzen Algorithmus kann an keiner Stelle eine Zahl auftreten, die größer ist als n². Man beachte dazu insbesondere die Zeile 8 und 13: In Zeile 8 wird bei jedem Einzelschritt der Exponentiation durch die Operation (mod r) das Zwischenergebnis kleiner als r gemacht. Dadurch treten in Zeile 8 keine größeren Zahlen als r² auf (=r² nur im letzten Schritt falls r = n wird). Analog werden die Zahlen in Zeile 13 klein gehalten (hier werden auch die Grade der Polynome durch die modulo-Operationen klein gehalten). n ist. Für b kommen Zeile 1: Hier wird getestet ob n echte Potenz ab einer Zahl 2 a dann offensichtlich nur Zahlen von 2 bis log2 n in Frage. Für alle diese b stellt man nun mit Hilfe der „schnellen Exponentiation“ in O(log b) Operationen fest, ob ab < n, oder ab = n, oder ab > n gilt. Auf diese Weise kann man {1,…,n} binär nach dem richtigen a durchsuchen. Wenn es ein a gibt für das ab = n gilt, ist man fertig, falls nicht, sucht man mit dem nächsten b weiter. Die binäre Suche nach dem richtigen a benötigt O(log n) Exponentiationen, jede Exponentiation noch einmal O(log n) Operationen, macht mit O(log n) zu prüfenden b zusammen O((log n)³) Operationen für die erste Zeile. Definition 4.1.1 Sei n eine natürliche Zahl. Wir nennen eine Primzahl r < n „n-gut“, wenn r /| n und der größte Primfaktor q von r – 1 die beiden folgenden Bedingungen erfüllt: (i) (ii) q ≥ 4 r log n, und n(r-1)/q ≡/ 1 (mod r) Die Schleife in den Zeilen 3 – 11 sucht eine Primzahl r, die genau diese beiden Bedingungen erfüllt. Die Frage, wie oft diese Schleife durchlaufen wird, hängt davon ab, welcher der drei folgenden Fälle zuerst eintritt: 1. 2. 3. Fall: ggt(n,r) 1 Fall: r ist n-gut Fall: r = n 4 Sei p(n) nun das kleinste r, für das einer der drei Fälle eingetreten sei. In Abschnitt 4.2 werden wir sehen, dass p(n) = O((log n)6). Zeile 4 Die ggt-Berechnung wird mit dem euklidischen Algorithmus erledigt, der für ein r einen Aufwand von O(log n) hat. Der Aufwand für den ganzen Algorithmus kann also mit O(p(n) log n) abgeschätzt werden. Zeile 5 Die Frage, ob r prim ist, ist streng genommen ein rekursiver Aufruf des zugrunde liegenden Problems. Da wir r aber polynomiell in der Eingabelänge vorliegen haben (siehe Abschnitt 4.2) dürften wir an dieser Stelle - theoretisch - unseren naiven Algorithmus aus dem ersten Abschnitt (der an dieser Stelle r auf Teilbarkeit mit allen ungeraden Zahlen von 2 bis r testen würde) verwenden ohne die Polynomialität des Algorithmus zu verletzen. Aber es geht schneller: Man führt eine Primzahltabelle mit, die immer alle Primzahlen bis zur nächsten Zweierpotenz 2 log2 r enthält. Das ist ebenfalls wegen der Polynomialität von r erlaubt, hat aber einen geringeren Gesamtaufwand von O(p(n) loglog(p(n))) gegenüber O p(n ) p (n ) . ( ) Zeile 6 Um zu bestimmen, ob der größte Primteiler von r – 1 mindestens 4 r log n ist, nimmt man dieselbe Tabelle, und verwendet jetzt endlich doch unseren anfangs eingeführten, naiven Algorithmus, allerdings für ein anderes Ziel. Man dividiert r – 1 durch alle seine Primfaktoren zwischen 2 und r , und schaut jedes Mal nach, ob das Ergebnis eine Primzahl ist (die man in der Tabelle hat). Wenn ja hat man den größten Primteiler gefunden. Wenn nicht, sucht man weiter Primteiler. Gesamtaufwand: O p(n ) p (n ) ( ) Zeile 8 Hier nimmt man wie schon erwähnt die schnelle Exponentiation, die einen Gesamtaufwand von O(p(n) log n) verursacht. Der Gesamtaufwand für alle Schleifendurchläufe ist zusammengerechnet also O(p(n)3/2 + p(n) log n). Die Schleife in den Zeilen 12 – 14 prüft für das vorher gefundene r und alle a mit 1 a 2 r log n, ob das Polynom (X + a)n bei Ausmultiplizieren alle seine Summanden außer denen mit Koeffizienten 1 modulo (Xr – 1,n) verliert, oder nicht. Auch hier verwendet man, wie erwähnt, die schnelle Exponentiation, wobei nach jeder einzelnen Multiplikation die Rechnung modulo n und modulo Xr – 1 durchgeführt wird. Auf diese Weise ist während der ganzen Rechnung sichergestellt, dass keine Polynome mit Grad größer als r – 1 und auch keine Koeffizienten größer als n – 1 auftauchen. Eine Multiplikation von Polynomen mit Grad < r hat einen Aufwand von O(r²). Zusammen mit der schnellen Exponentiation ergibt sich für die Berechnung des gesamten Ausdrucks eine Laufzeit von O(p(n)² log n). Für alle a im erwähnten Intervall ergibt das einen Gesamtaufwand von O( p (n) log n . p(n)² log n) = O(p(n)5/2 (log n)²). Wenn also r nach oben durch ein Polynom p(n) = O((log n)6) abgeschätzt werden kann, dann liegt die Laufzeit des Algorithmus in O((log n)17). Mit schnelleren PolynomMultiplikationsverfahren kann diese Schranke noch auf O((log n)12) gesenkt werden. 5 Man vermutet sogar, dass sich innerhalb der ersten O((log n)²) Zahlen ein r finden lässt, für das (r – 1)/2 prim ist (eine sogenannte Sophie-Germain-Primzahl). Dann würde sich die Laufzeit sogar auf O~((log n)6) verringern[3]. 4.2 Schranke für „gute“ r Um zu zeigen, dass die while-Schleife im Algorithmus nach spätestens O((log n)6) Durchläufen abbricht, benötigen wir drei Aussagen aus der Zahlentheorie. Definition: Für eine positive reelle Zahl x sei (x) = |{ p x | p ist eine Primzahl}|. In (x) steht also die Anzahl der Primzahlen, die höchstens so groß wie x sind. Satz 4.2.1 (Primzahlsatz) π ( x) lim x / ln x =1 x →∞ Der Primzahlsatzes besagt, dass die Anzahl der Primzahlen asymptotisch betrachtet so schnell wächst wie x/ln x. Wir brauchen aber nur eine abgeschwächte Version: Fakt 4.2.2 Für alle x x 6 log x (x) 2 gilt: 8x log x „log“ steht ab hier für den Logarithmus zur Basis 2. In unserem Algorithmus interessieren uns besonders diejenigen Primzahlen r, bei denen r – 1 einen sehr großen Primteiler hat. Definition: Sei a eine natürliche Zahl. Dann bezeichne P(a) die größte Primzahl, die a teilt. Fakt 4.2.3 Es gibt ein (kleines) c > 0 und ein (großes) x0, so dass für alle x |{ r | r Primzahl, r x, P(r – 1) > x3/2}| c x0 gilt: x . log x Zusammen mit 4.2.2 besagt dieses Fakt, dass asymptotisch betrachtet für einen konstanten Bruchteil der Primzahlen r x gilt, dass der größte Primteiler größer ist als x3/2. Nun haben wir das Rüstzeug, um das Lemma zu zeigen, welches direkt impliziert, dass die while-Schleife nach O((log n)6) Durchläufen abbricht. Lemma 4.2.4 Es gibt Konstanten c1, c2 > 0 und n0 mit folgender Eigenschaft: Für jedes n n0 gibt es eine Primzahl r mit c1(log n)6 < r c2(log n)6, die entweder Teiler von n ist oder n-gut. 6 Beweis. Sei c wie in Fakt 4.2.3 gewählt. Wir rechnen zunächst mit Konstanten c2 c1 1 und bestimmen hinterher wie groß sie sein müssen. Die Zahl n sei beliebig, aber (auch bezüglich c1 und c2 und x0 aus Fakt 4.2.3) groß genug, um die folgenden Abschätzungen zu erfüllen. Definition Wir nennen eine Zahl r < n „n-speziell“, wenn r prim ist und P(r – 1) > (c2(log n)6)2/3 gilt. „n-spezielle“ Zahlen sind also gerade solche, die Elemente der in Fakt 4.2.3 beschriebenen Menge sind. Außerdem genügen n-spezielle Zahlen wie auch n-gute Zahlen (siehe Def.4.1.1) einer Mindestabschätzung. Dass die Mindestabschätzung für n-spezielle Zahlen, wie wir sie gewählt haben, für die „n-Gutheit“ genügt, zeigen wir hinterher. Zunächst betrachten wir aber die Anzahl solcher n-speziellen Zahlen im links offenen und rechts abgeschlossenen Intervall I := (c1(log n)6,c2(log n)6]. |{ r | r ist n-speziell und c1(log n)6 < r c2(log n)6 | r ist n-speziell}| – |{r c2 (log n) 6 8c1 (log n) 6 c⋅ – log(c2 (log n) 6 ) log(c1 (log n) 6 ) |{r c ⋅ c2 (log n) 6 8c (log n) 6 – 1 7 log log n 6 log log n = c2(log n)6}| c1(log n)6 | r ist Primzahl}| (Weil c1, c2 > 0 so gewählt, dass log(c1), log(c2) > 0) (log n) 6 cc2 8c1 . ⋅ − log log n 7 6 cc2 8c1 − positiv ist (wegen Fakt 4.2.3), dann ist die 7 6 c (log n) 6 Anzahl der n-speziellen Zahlen in ((4 log n)6, c2(log n)6] mindestens 3 . log log n Wähle nun c1 = 46 und c2 so, dass c3 = Jetzt müssen wir aber noch den Schritt von n-speziell nach n-gut machen. Setze dazu y = c2 (log n)6, also auf die rechte Grenze des Intervalls I, und betrachte das Produkt = ∏ (n j 1/ 3 − 1) = (n − 1) ⋅ (n 2 − 1) ⋅ ... ⋅ (n y − 1) 1≤ j ≤ y1 / 3 Woher kommt dieses Produkt? Die zweite Eigenschaft, die eine „n-gute“ Zahl haben muss ist, dass n(r-1)/q mod r nicht kongruent 1 sein darf. Wenn also ein r keines der oben aufgeführten (nj – 1) teilt, ist dieses r „n-gut“. Beachte nun, dass n! < nn für alle n > 1 gilt. Aus diesem Grund gilt die folgende Ungleichung: ( ) 1/ 3 < ny y1 / 3 2/3 Die größte Anzahl von Primfaktoren erhält man genau dann, wenn n y eine Zweierpotenz ist. Daraus folgt, dass die Anzahl der Faktoren in der Primfaktorzerlegung von kleiner ist als 7 ( )= y log n y 2/3 2/3 log n = (c2 (log n) 6 ) 2 / 3 log n < c3 (log n) 6 log log n (1) (für n genügend groß). Die letzte Ungleichung ergibt sich aus folgender Überlegung: c22 / 3 log n < c3 log log n Die rechte Seite ist eine unbeschränkte, ab n > 7 streng monoton steigende Funktion. Die linke Seite ist eine Konstante. Daraus folgt, dass es eine Stelle n gibt, ab der die Ungleichung immer gilt. Deshalb hatten wir n am Anfang groß genug gewählt. (1) Wir haben also mehr n-spezielle Zahlen in I als Teiler von 6 n) , c2(log n)6] eine n-spezielle Zahl r, die kein Teiler von ist. . Daher gibt es in ((4 log Diese Primzahl hat die gesuchten Eigenschaften: Wenn r | n, sind wir fertig. Wenn r /| n, ist r n-gut, was man wie folgt einsieht: (i) Weil r n-speziell ist, hat r – 1 einen Primfaktor q mit q > (c2(log n)6)2/3; weil r (4 log n)6 ist gilt q > r2/3 = (ii) r ⋅ r 1/6 4 r log n Und weil r das Produkt nicht teilt, gilt für jedes j, 1 r /| (nj – 1), d.h. nj ≡/ 1 mod r. Nach (i) ist aber (r – 1)/q < r / r2/3 = r1/3 j y1/3, dass y1/3; daher gilt n(r-1)/q ≡/ 1 mod r, wie gewünscht. 5. Der Korrektheitsbeweis Der Kern des Korrektheitsbeweises des Agrawal/Kayal/Saxena – Tests ist im folgenden Satz zusammengefasst, dessen Beweis hier nur skizziert wird. Hauptsatz 5.1 Es sei (i) (ii) n 2 eine natürliche Zahl; r < n eine Primzahl mit r /| n; (iii) (iv) q eine Primzahl mit q | (r – 1), und q n(r-1)/q ≡/ 1 (mod r) 4 r log n, und 8 Weiter gelte für L = 2 r log n : (v) (vi) Für alle a, 1 Für alle a, 1 a a L: a und n teilerfremd; L: (X + a)n ≡ (Xn + a) mod (n, Xr – 1). Dann ist n = pi für eine Primzahl p und ein i 1. Beweisidee: Man zeigt für alle a mit 1 ( X + a )n p i j ( a i j ≡ Xnp +a L und i,j ) 1, dass gilt: mod (n, Xr – 1) Wobei p Primfaktor von n ist (Wenn n = p gilt es offensichtlicherweise) Daraus folgt aber, dass ( X + a )n p i j i j ≡ Xnp +a in = p [x] / h(x) h(x) sei hier ein irreduzibles Polynom vom Grad d = ordr (p). Man kann beweisen, dass h(x) existiert. Daraus folgt, dass | | = pd = r gilt. Aber für 0 i,j r sind das mehr als r Kongruenzen. Also muss es modulo r zwei gleiche geben. Daraus kann man dann für Paare (i,j) und (k,l) zeigen (siehe [2]), dass folgendes gilt: nipj ≡ nkpl (mod r). Und daraus folgt, dass n eine echte Primpotenz ist. Mit Hilfe dieses Satzes lässt sich der Korrektheitsbeweis führen: Satz 5.2 Der Algorithmus gibt „prim“ aus ⇔ n ist eine Primzahl Beweis. „ ⇐ “: Sei n eine Primzahl. Dann ist n nicht von der Form ab, b > 1, also schlägt der Test in Zeile 1 immer fehl. Der Test in Zeile 3 ergibt für alle r ggt(n,r) = 1. Die beiden Möglichkeiten, wie die Schleife in Zeilen 3 – 11 terminieren könnte, nämlich erstens, weil r prim ist und die Tests in Zeilen 7 und 8 bestanden hat, oder, zweitens, weil r = n ist, können wegen Satz 2.1 für kein zu n teilerfremdes a die Bedingung in Zeile 13 erfüllen. Für n | a gilt dies auch, weil dann a ≡ 0 mod n. Also wird Zeile 15 erreicht und „PRIM“ ausgegeben. „ “: Zu zeigen:Wenn der Algorithmus „PRIM“ ausgibt, dann ist n eine Primzahl. Fall 1: Die Schleife in den Zeilen 3 – 11 wird über die Bedingung in Zeile 3 verlassen, also gilt r = n. Dann muss wegen des Tests in Zeile 3 für jedes r < n gelten, dass r und n teilerfremd sind, insbesondere, dass r /| n, also ist n eine Primzahl. Fall 2: Die Schleife in den Zeilen 3 – 11 wird über das „break“-Kommando in Zeile 9 verlassen. Der Inhalt von r in diesem Moment sei r’. Dann gilt: (i) r’ < n und r’ ist eine Primzahl (wegen Zeile 5); 9 (ii) (iii) Für alle a, 1 (iv) (v) der größte Primfaktor q von r’ – 1 erfüllt q n(r’-1)/q ≡/ 1 (mod r’) (wegen Zeile 8); a 4 r ' log n (wegen Zeile 7); L = 2 r ' log n gilt: a und n sind teilerfremd (wegen Zeile 7 ist L < 4 r ' log n q < r’, also wurde für alle diese a in den vorherigen Schleifendurchläufen in Zeile 4 getestet, ob ggt(n,a) 1 ist) und (X + a)n – (Xn + a) ≡ 0 (mod Xr’ – 1,n) (getestet in der Schleife in den Zeilen 12 – 14). Damit erfüllen n,r’ und q alle Voraussetzungen des Hauptsatzes 5.1. Nach diesem Satz ist also n = pi für eine Primzahl p. Wegen des Tests in Zeile 1 kann aber n nicht echte Potenz irgendeiner Zahl sein, also ist i = 1 und n ist selbst eine Primzahl. Literatur: [1] Manindra Agrawal, Neeraj Kayal und Nitin Saxena, PRIMES is in P, Manuscript 2002. http://www.cse.iitk.ac.in/users/manindra/primality.ps oder http://www.cse.iitk.ac.in/news/primality.pdf [2] Primzahltest in Polynomialzeit – Der Algorithmus von Agrawal, Kayal und Saxena Vorlesungsnotizen von Martin Dietzfelbinger, TU Ilmenau [3] Stefan Wehmeier: Der AKS - Primzahltest 10