Disclaimer

Das Problem mit den Primzahlen

Primzahlen sind das Fundament moderner Verschlüsselung. RSA-2048 verwendet Primzahlen mit über 600 Dezimalstellen, die täglich Billionen von Transaktionen schützen. Das eigentliche Problem liegt nicht im Finden dieser Primzahlen, sondern in ihrer Sicherheit gegen zukünftige Angriffe.

Tabelle 1 - Kryptographische Primzahlgrößen im Einsatz
Standard Bit-Größe DezimalstellenErzeugungszeitSicherheit bis
RSA-10241024~30810msGebrochen (2010)
RSA-20482048~61750ms~2030
RSA-30723072~925200ms~2050
RSA-40964096~1233800ms~2080
Post-Quantum---Quanten-resistent

/* Miller-Rabin Primzahltest - Industriestandard */ #include <random> #include <gmp.h> bool miller_rabin_test(const mpz_t n, int iterations = 40) { if (mpz_cmp_ui(n, 2) == 0) return true; if (mpz_even_p(n) || mpz_cmp_ui(n, 2) < 0) return false; mpz_t d, n_minus_1, a, x; mpz_inits(d, n_minus_1, a, x, NULL); mpz_sub_ui(n_minus_1, n, 1); mpz_set(d, n_minus_1); // d = n-1, r = 0 int r = 0; while (mpz_even_p(d)) { mpz_fdiv_q_2exp(d, d, 1); r++; } std::random_device rd; gmp_randstate_t state; gmp_randinit_default(state); gmp_randseed_ui(state, rd()); for (int i = 0; i < iterations; i++) { mpz_urandomm(a, state, n_minus_1); mpz_add_ui(a, a, 2); // a in [2, n-1] mpz_powm(x, a, d, n); if (mpz_cmp_ui(x, 1) == 0 || mpz_cmp(x, n_minus_1) == 0) continue; bool composite = true; for (int j = 0; j < r - 1; j++) { mpz_powm_ui(x, x, 2, n); if (mpz_cmp(x, n_minus_1) == 0) { composite = false; break; } } if (composite) { mpz_clears(d, n_minus_1, a, x, NULL); gmp_randclear(state); return false; } } mpz_clears(d, n_minus_1, a, x, NULL); gmp_randclear(state); return true; } // Generiert eine kryptographisch sichere Primzahl void generate_crypto_prime(mpz_t result, int bits) { gmp_randstate_t state; gmp_randinit_default(state); do { mpz_urandomb(result, state, bits); mpz_setbit(result, bits - 1); // Höchstes Bit setzen mpz_setbit(result, 0); // Ungerade machen } while (!miller_rabin_test(result)); gmp_randclear(state); } #include <iostream> int main() { // Teste bekannte Primzahlen mpz_t test_num; mpz_init(test_num); mpz_set_ui(test_num, 1009); std::cout << "1009 ist " << (miller_rabin_test(test_num) ? "prim" : "zusammengesetzt") << std::endl; mpz_set_ui(test_num, 1010); std::cout << "1010 ist " << (miller_rabin_test(test_num) ? "prim" : "zusammengesetzt") << std::endl; // Teste große Mersenne-Primzahl 2^31-1 mpz_set_ui(test_num, 2147483647UL); std::cout << "2^31-1 ist " << (miller_rabin_test(test_num) ? "prim" : "zusammengesetzt") << std::endl; // Generiere 128-Bit und 256-Bit Primzahlen mpz_t prime128, prime256; mpz_init(prime128); mpz_init(prime256); std::cout << "Generiere 128-Bit Primzahl..." << std::endl; generate_crypto_prime(prime128, 128); std::cout << "128-Bit Primzahl: "; mpz_out_str(stdout, 10, prime128); std::cout << std::endl; std::cout << "Generiere 256-Bit Primzahl..." << std::endl; generate_crypto_prime(prime256, 256); std::cout << "256-Bit Primzahl: "; mpz_out_str(stdout, 10, prime256); std::cout << std::endl; mpz_clear(test_num); mpz_clear(prime128); mpz_clear(prime256); return 0; }

Installation: sudo apt install libgmp-dev    Kompilieren: g++ main.cpp -lgmp -o main

Die wahren Herausforderungen:
• Quantencomputer-Bedrohung: Shor's Algorithmus kann RSA in polynomieller Zeit brechen
• Post-Quantum-Kryptographie: Übergang zu Gitter-basierten, Hash-basierten und Code-basierten Verfahren
• Hardwarebeschleunigung: Spezialisierte ASICs für Faktorisierung werden immer leistungsfähiger
• Seitenkanalangriffe: Timing-, Power- und EM-Attacken auf Primzahloperationen

Aktuelle Entwicklungen:
NIST hat 2024 neue Post-Quantum-Standards veröffentlicht. Große Tech-Konzerne migrieren bereits ihre Systeme. Die Ära der RSA-Primzahlen neigt sich dem Ende zu - nicht wegen Berechnungsproblemen, sondern wegen fundamentaler physikalischer Durchbrüche.

Fazit:
Primzahlen waren 50 Jahre lang die Basis der Internetsicherheit. Ihre Berechnung ist trivial, ihre Faktorisierung war schwer. Quantencomputer machen beides trivial. Die Zukunft gehört anderen mathematischen Strukturen.

Die Primzahlfunktion π(n)

Betrachten wir die Primzahlfunktion π(n) etwas genauer (siehe Tabelle 2 weiter unten). Die Primzahlfunktion \(\pi(n)\) gibt die Anzahl der Primzahlen bis zur Zahl n an. $$ \pi(n) = \{ p \in \mathbb{P} | p \leq n \} $$ Seit Gauss gibt es für \( \pi(x) \) eine erste Schätzung aus empirischen Daten bis \(10^6\). $$ {\pi(n)} \sim {n \over \ln(n)} $$

Tabelle 2 - Primzahlfunktion π(n) und Gauss'sche Näherung
nπ(n)n/ln(n)FehlerRel. Fehler
1002522312%
1.0001681442414%
10.0001.2291.08614312%
100.0009.5928.6869069%
1.000.00078.49872.3826.1168%
10.000.000664.579620.42144.1587%
100.000.0005.761.4555.428.681332.7746%
Implementierung der Primzahlfunktion

Das folgende Beispiel berechnet \(\pi(n)\) bis zur Million und vergleicht die Ergebnisse systematisch mit der Gauss'schen Näherung. Die Implementierung verwendet das effiziente Sieb des Eratosthenes:

#!/usr/bin/env python3 import numpy as np import math import matplotlib.pyplot as plt def sieve_of_eratosthenes(limit): """Effizientes Sieb des Eratosthenes mit NumPy""" is_prime = np.ones(limit + 1, dtype=bool) is_prime[0] = is_prime[1] = False for i in range(2, int(math.sqrt(limit)) + 1): if is_prime[i]: is_prime[i*i:limit+1:i] = False return is_prime def calculate_pi_function(limit): """Berechnet π(n) für alle n bis limit""" primes = sieve_of_eratosthenes(limit) pi_values = np.cumsum(primes) return pi_values def gauss_approximation(n): """Gauss'sche Näherung: n/ln(n)""" return n / np.log(n) if n > 1 else 0 # Berechnung und Vergleich limit = 1000000 pi_values = calculate_pi_function(limit) # Erstelle Datenpunkte für Analyse sample_points = np.logspace(2, 6, 50, dtype=int) # 100 bis 1,000,000 errors = [] print("n\t\tπ(n)\t\tn/ln(n)\t\tFehler") print("-" * 50) for n in sample_points: if n <= limit: pi_n = pi_values[n] gauss_n = gauss_approximation(n) error = pi_n - gauss_n errors.append(error) print(f"{n:8d}\t{pi_n:8d}\t{gauss_n:8.0f}\t{error:8.0f}") # Visualisierung der Fehlerverteilung plt.figure(figsize=(10, 6)) plt.loglog(sample_points[:len(errors)], np.abs(errors)) plt.xlabel('n') plt.ylabel('|π(n) - n/ln(n)|') plt.title('Fehler der Gauss-Näherung') plt.grid(True) plt.show()

Mit diesen Mitteln kann mann nun eine Fehlerfunktion definieren und zumindest einige der Fehler ausrechnen. $$ err(n) = \pi(n) - {n \over \ln(n)} $$

      
Tabelle 3 - Fehleranalyse der Gauss'schen Näherung
nπ(n)n/ln(n)err(n)
...  
1.00016814424
2.00030326340
...  
11.0001.3351182153
12.0001.4381277161
...  
101.0009.6738765908
102.0009.7668844922
...  
1.001.00078.573724496124
1.002.00078.650725166134
...  
5.001.000348.57632421024366
5.002.000348.64132427124370
...  
15.485.9171.000.000935.39764.604
32.452.8832.000.0001.876.398123.602
49.979.7373.000.0002.819.392180.608
67.867.9994.000.0003.763.528236.472
86.028.2215.000.0004.708.666291.334
104.395.3376.000.0005.654.086345.914
122.949.8397.000.0006.600.523399.477
141.650.9818.000.0007.547.120452.880
160.481.2219.000.0008.493.906506.094
179.424.69710.000.0009.440.788559.212
198.491.36911.000.00010.388.815611.185
217.645.20112.000.00011.336.645663.355

Aus der Fehlerfunktion \(err(n) = \pi(n) - {n \over \ln(n)}\) lassen sich weitere wichtige Eigenschaften ablesen:

  • Der Fehler wächst systematisch mit \(n\), was zeigt, dass die Gauss'sche Näherung strukturell zu klein ist
  • Das Verhältnis \({err(n) \over \pi(n)}\) wird jedoch mit steigendem \(n\) kleiner - die relative Genauigkeit verbessert sich
  • Legendre versuchte 1808 eine Verbesserung mit \({\pi(n) \sim {n \over {\ln(n) - 1.08366}}}\), was für mittlere Bereiche besser funktionierte, aber für sehr große n wieder schlechter wird
  • Gauss erkannte 1849, dass die Integrallogarithmus-Funktion \(Li(n) = \int_2^n {dt \over \ln(t)}\) eine deutlich bessere Approximation liefert als alle bisherigen Ansätze
Diese Verbesserungen führten schließlich zum Primzahlsatz, der besagt: \(\lim_{n \to \infty} {\pi(n) \over {n / \ln(n)}} = 1\).

Der Primzahlsatz wurde 1896 unabhängig von Hadamard und de la Vallée-Poussin bewiesen und stellt einen Höhepunkt der analytischen Zahlentheorie dar. Er bestätigt, dass Gauss' ursprüngliche Intuition asymptotisch exakt war.

Der Primzahlsatz zeigt, dass Primzahlen zwar immer seltener werden, aber nach einem klaren Gesetz: Die Wahrscheinlichkeit, dass eine zufällige Zahl um n prim ist, beträgt etwa \(1 / \ln(n)\). Bei einer Milliarde ist etwa jede 20. Zahl prim, bei einer Billion nur noch jede 28. Zahl.

Anzahl der Primzahlen

Wieviele Primzahlen gibt es? Diese Frage wurde bereits in verschiedenen Varianten beantwortet. Der Erste, der eine Antwort herleiten konnte war Euklid. Angenommen es gäbe nur endlich viele Primzahlen \({p_1, p_2, p_3, ..., p_n}\). Dann kann man eine neue Zahl Z = \(p_1\cdot p_2 \cdot... \cdot p_n + 1\) bilden die durch keine der \(p_i\) teilbar ist. Es ist verlockend zu denken, Z sei automatisch Prim, doch dem ist nicht so. Vielmehr braucht man einen Hauptsatz der Zahlentheorie der ebenfalls seit Euklid bekannt ist, indem es heisst, dass jede Zahl aus Primfaktoren zusammengesetzt ist - so auch Z. Aber die Faktoren von Z sind nicht in unserer Liste \(p_i\) enthalten. Das ist aber ein Widerspruch zur Annahme, das \(p_i\) alle existierenden Primzahlen wären.

Harmonische Reihe

Ein Ausgangspunkt vieler Überlegungen ist die sogenannte harmonische Reihe $$ \sum_{n=1}^{\infty} \frac{1}{n} = \frac{1}{1} + \frac{1}{2} + \frac{1}{3} + \frac{1}{4} + \cdots $$ Die harmonische Reihe divergiert, obwohl ihre Glieder gegen Null gehen. Dies lässt sich einfach durch Umsortierung zeigen: $$ 1 + \frac{1}{2} + \left(\frac{1}{3} + \frac{1}{4}\right) + \left(\frac{1}{5} + \frac{1}{6} + \frac{1}{7} + \frac{1}{8}\right) + \cdots > 1 + \frac{1}{2} + \frac{1}{2} + \frac{1}{2} + \cdots $$ Während die harmonische Reihe divergiert, konvergiert bereits \(\sum_{n=1}^{\infty} \frac{1}{n^2}\). Das Basler Problem - die Bestimmung dieser Summe - beschäftigte Mathematiker über 90 Jahre, bis Euler 1735 (im Alter von 28 Jahren) das verblüffende Ergebnis \(\frac{\pi^2}{6}\) fand.

Die interessante Frage ist: Wieviele Glieder kann man aus der harmonischen Reihe entfernen, sodass sie gerade noch divergiert? Ersetzt man die Glieder \(\frac{1}{n}\) durch \(\frac{1}{n^{1+\epsilon}}\) mit beliebig kleinem \(\epsilon > 0\), konvergiert die Reihe bereits. Die kritische Grenze liegt genau bei \(s = 1\) - jede noch so kleine Erhöhung des Exponenten führt zur Konvergenz.

Gamma-Funktion

Die Gamma-Funktion ist eine Verallgemeinerung der Fakultät auf reelle und komplexe Zahlen. Während \(n!\) nur für natürliche Zahlen definiert ist, ermöglicht \(\Gamma(s)\) Berechnungen wie \(1.5!\) oder \((2+3i)!\). $$ \Gamma(s) = \int_0^\infty {t^{s-1} e^{-t}}dt, \quad \text{mit } Re(s) > 0 $$ $$ \Gamma(s+1) = \int_0^\infty {t^{(s+1)-1} e^{-t}}dt = \int_0^{\infty}t^s e^{-t} dt $$ $$ = -e^{-t}t^s|_0^{\infty} - \int_0^{\infty}{{dt^s \over dt}e^{-t}}dt $$ $$ = \int_0^{\infty} st^{s-1}e^{-t}dt = s\cdot\int_0^{\infty} t^{s-1}e^{-t}dt = s \cdot \Gamma(s) $$ also $$ \Gamma(s+1) = s \cdot \Gamma(s) $$ Substituiere und setze in ursprüngliche Form ein: $$ e^{-t} = \lim\limits_{n \to \infty}\left(1+\frac{-t}{n}\right)^n $$ $$ \Gamma(s) = \int_0^{\infty}t^{s-1}e^{-t}dt $$ $$ = \int_0^{\infty}t^{s-1}\lim\limits_{n \to \infty}\left(1+\frac{-t}{n}\right)^n dt $$ $$ = \lim\limits_{n \to \infty} \int_0^n t^{s-1}\left(1-\frac{t}{n}\right)^n dt $$ Nun kann man partiell integrieren: $$ \int_0^n t^{s-1}\left( 1 - \frac{t}{n}\right)^n dt = \frac{1}{s} t^s\left(1-\frac{t}{n}\right)^n\bigg|_0^n - \int_0^n \frac{1}{s}t^s n\left(1- \frac{t}{n}\right)^{n-1}\left(-\frac{1}{n}\right)dt $$ $$ = \frac{n}{s \cdot n} \int_0^n t^s\left(1- \frac{t}{n} \right)^{n-1}dt $$ $$ = \frac{n}{s \cdot n} \cdot \frac{(n-1)}{n(s+1)} \int_0^n t^{s+1}\left(1-\frac{t}{n}\right)^{n-2}dt $$ $$ = \frac{n}{s \cdot n} \cdot \frac{(n-1)}{n(s+1)} \cdot \frac{(n-2)}{n(s+2)} \int_0^n t^{s+2}\left(1-\frac{t}{n}\right)^{n-3}dt $$ $$ = \frac{n}{s \cdot n} \cdot \frac{(n-1)}{n(s+1)} \cdot \frac{(n-2)}{n(s+2)} \cdots \frac{1}{n(s+n-1)} \int_0^n t^{s+n-1}dt $$ $$ = \frac{n}{s \cdot n} \cdot \frac{(n-1)}{n(s+1)} \cdot \frac{(n-2)}{n(s+2)} \cdots \frac{1}{n(s+n-1)} \frac{t^{s+n}}{(s+n)} \bigg|_0^n $$ $$ = \frac{n!}{n^n} n^{s+n} \prod_{i=0}^n (s+i)^{-1} $$ $$ = \frac{n! n^s}{\prod_{i=0}^n(s+i)} $$ Also $$ \Gamma(s) = \lim\limits_{n \to \infty} ( {n^s \over s} \prod_{i=1}^n {i \over {(s+i)}}) $$

Wenn man in dieser Weise fortfährt, kann man zeigen, dass die Gamma-Funktion eng mit der Riemann-Zeta-Funktion verknüpft ist: $$ \zeta(s) = \sum_{n=1}^{\infty} \frac{1}{n^s} = \frac{1}{\Gamma(s)} \int_0^{\infty} \frac{t^{s-1}}{e^t - 1} dt $$ Bereits 1737 entdeckte Euler die fundamentale Beziehung zwischen der Zeta-Funktion und den Primzahlen, die als Euler-Produktformel bekannt wurde:

$$ \prod_{\text{$p$ prim}} {1 \over {1 - {1 \over {p^s}}}} = {\sum_{n\ge1} {1 \over n^s}} = \zeta(s) $$ Und das ist nun wirklich erstaunlich: Das unendliche Produkt aus lauter Primzahl-Inversen ergibt dasselbe wie die Summe aus lauter Inversen natürlicher Zahlen.

Die Riemann-Hypothese und moderne Primzahlforschung

Die Euler'sche Produktformel verbindet die Riemann-Zeta-Funktion direkt mit den Primzahlen und zeigt deren fundamentale Rolle in der Zahlentheorie. Die berühmte Riemann-Hypothese besagt, dass alle nichttrivialen Nullstellen von ζ(s) den Realteil 1/2 haben - ein Beweis würde präzise Aussagen über die Verteilung der Primzahlen ermöglichen.

Heute stehen wir an einem Wendepunkt: Während die klassische Primzahltheorie durch Quantencomputer bedroht wird, eröffnen sich neue Forschungsfelder in der Post-Quantum-Kryptographie. Die jahrtausendealten Primzahlen bleiben ein zentrales Element sowohl der reinen Mathematik als auch der angewandten Informatik.


Griechisches Alphabet
Α αAlpha
Β βBeta
Γ γGamma
Δ δDelta
Ε εEpsilon
Ζ ζZeta
Η ηEta
Θ θTheta
Ι ιIota
Κ κKappa
Λ λLambda
Μ μMu
Ν νNu
Ξ ξXi
Ο οOmikron
Π πPi
Ρ ρRho
Σ σSigma
Τ τTau
Υ υUpsilon
Φ φPhi
Χ χChi
Ψ ψPsi
Ω ωOmega