26. الگوریتم شور (Shor)
26.1تجزیهٔ اعداد صحیح
با عدد مرکب فرد N، عامل نابدیهی پیدا کنید (بعد بازگشتی ادامه دهید). مسئلهٔ پشت RSA است: ضرب دو عدد اول بزرگ آنی است و تجزیهٔ حاصل، تا جایی که میدانیم، سخت؛ و هر تبادل کلید اینترنتی چهار دههٔ گذشته روی این عدمتقارن شرط بسته است. الگوریتم شور (Shor) در ۱۹۹۴ عدد N را در زمان چندجملهای تجزیه میکند — از مرتبهٔ O(n³) گیت برای n بیت روی رایانهٔ کوانتومی — و همچنان تعیینکنندهترین نتیجهٔ حوزه است: محاسبات کوانتومی را از کنجکاوی به ضربالاجل رمزنگارانه تبدیل کرد. توجه کنید که شور چه نمیکند: دنبال عامل نمیگردد؛ دوره پیدا میکند و عاملها میافتند بیرون.
26.2سختی کلاسیک
بهترین الگوریتم کلاسیک، غربال میدان اعداد عمومی، در exp(((64/9)^{1/3} + o(1))·(ln N)^{1/3}·(ln ln N)^{2/3}) اجرا میشود — زیرنمایی، فراتر از چندجملهای. RSA-2048 با فاصلهای عظیم فراتر از آن است (رکورد: RSA-250 در ۲۰۲۰ با ~۲۷۰۰ سال-هسته). الگوریتم تجزیهٔ چندجملهایِ کلاسیک با وجود قرنها کار شناخته نشده و برای همین مسئله فرض سختیِ قابلاعتمادی است — و الگوریتم کوانتومیِ چندجملهایِ شور یک رویداد واقعی نظریهٔ پیچیدگی است، نه شتابی افزایشی. میانبُر نظریهٔ اعداد از طریق دورهها است که کار میکند: تجزیه و یافتن دوره، معلوم میشود، یک مسئلهاند با لباسهای متفاوت.
26.3حساب پیمانهای
یک a تصادفی با gcd(a, N) = 1 بردارید (اگر gcd بزرگتر باشد، از قبل عامل پیدا کردهاید — شانس آوردید). در گروه ضربی Z*_N از باقیماندههای هماول با N کار کنید که اندازهاش φ(N) است (تابع اویلر). بنا به قضیهٔ لاگرانژ، هر عنصر مرتبه متناهی دارد: کوچکترین r با a^r ≡ 1 (mod N)، و r مقسومعلیهٔ φ(N) است. پس توانهای a^0, a^1, a^2, … با دورهٔ r سیکل میزنند. برای N = pq با دو عدد اول فرد متمایز، a تصادفی با احتمال ≥ 1/2 مرتبهای زوج دارد که a^{r/2} ≢ −1 (mod N) — شرطی که گام نهایی gcd را برای شکستن N به کار میاندازد.
26.4یافتن دوره
کاهش: اگر بتوانید مرتبهٔ r یک a تصادفی به پیمانهٔ N را پیدا کنید، میتوانید تجزیه کنید. وقتی r زوج است و a^{r/2} ≢ −1 (mod N)، بنویسید x = a^{r/2}؛ آنگاه x² ≡ 1 (mod N) ولی x ≢ ±1، پس N شمارندهٔ x²−1 = (x−1)(x+1) است بدون اینکه شمارندهٔ هر عامل باشد — و gcd(x−1, N) و gcd(x+1, N) عوامل نابدیهیاند. کلاسیکاً، یافتن r یعنی محاسبهٔ توانها تا برخورد با ۱: O(r) ≤ O(N) ضرب، یا O(√r) با گامکوچک-گامبزرگ. برای N در مقیاس RSA، r نجومی بزرگ است — یافتن دوره همان دیوار نمایی است و دقیقاً همان دیواری که QFT منفجر میکند.
26.5یافتن دورهٔ کوانتومی
هستهٔ کوانتومی. Q = 2^t را با N² ≤ Q < 2N² انتخاب کنید (t ≈ 2n+1). (1/√Q)·Σ_{x=0}^{Q−1}|x⟩|1⟩ را آماده کنید و یکانیِ توانرسانی پیمانهای |x⟩|y⟩ ↦ |x⟩|y·a^x mod N⟩ را اعمال کنید — ساختهشده از مربعکردن مکرر روی ارقام دودویی x، هیولای O(n³) گیت:
reg 1 (t ≈ 2n qubits): |0> ──H^⊗t────────[QFT over Q]──measure y
│
reg 2 (n qubits): |1> ──────U_pow── U_pow: |y> ↦ |y·a^x mod N>
حالا ثبات ۲ a^x mod N را نگه میدارد — دورهای با دورهٔ r — درهمتنیده با ثبات ۱. درهمتنیدگی نکته است: ثبات ۱ برهمنهی همدوس همهٔ xهاست، برچسبخورده با ساختار دورهای تصاویرشان.
26.6پیوند با QFT
QFT روی Q را به ثبات ۱ اعمال کنید. قطار دورهایِ درون حالت درهمتنیده پراش میکند: دامنه روی اعداد صحیح y با |y/Q − k/r| ≤ 1/(2Q) برای k متناسبی متمرکز میشود — مضارب Q/r، تا گردکردن. اندازه بگیرید: y/Q کسری است در فاصلهٔ 1/(2Q) از k/r. حالا گام کلاسیک — بسط کسر مسلسل (continued fraction) y/Q با مخرجهای محدود به N، هر وقت gcd(k, r) = 1 باشد k/r را بازیابی میکند؛ و این برای کسری ثابت از shotها رخ میدهد (قلهها در مجموع احتمال ≥ 4/π²·φ(r)/r حمل میکنند). a^r ≡ 1 (mod N) را راستیآزمایی کنید؛ اگر راستیآزمایی شکست خورد (r/gcd(k,r) را گرفتهاید یا r فرد بود)، دوباره نمونهبرداری کنید — تعداد ثابتی دور بهطور مورد انتظار. این اسکلت سایمون است با (Z, +) بهجای (Z₂)ⁿ.
26.7الگوریتم کامل
همهچیز سرهم — بخش کوانتومی یک خط جعبهشده است:
import math, random
def shor(N): # رانندهٔ کلاسیک
if N % 2 == 0:
return 2
while True:
a = random.randrange(2, N - 1)
g = math.gcd(a, N)
if g > 1:
return g # شانس آوردید: عامل مجانی
r = quantum_order(a, N) # یافتن دوره با QFT (26.5-26.6)
if r % 2 != 0:
continue # مرتبهٔ فرد: با a تازه تکرار کنید
x = pow(a, r // 2, N)
if x == N - 1:
continue # a^(r/2) = -1: تکرار کنید
f1, f2 = math.gcd(x - 1, N), math.gcd(x + 1, N)
if 1 < f1 < N:
return f1 # بازگشتی روی f1 و N // f1
quantum_order(a, N) مدار ۲۶.۵–۲۶.۶ را تعداد ثابتی بار اجرا میکند. هزینهٔ کل: O(n³) گیت بهطور ساده (O(n²·polylog n) با حساب سریع)، تعداد ثابتی تکرار مورد انتظار — هر تکرار با احتمال ≥ 1/2 عدد N را تجزیه میکند.
26.8پیادهسازی اسباببازی
N = 15 و a = 7 — مثال استاندارد سرتاسری. توانها با دورهٔ ۴ سیکل میزنند؛ نسخهٔ اسباببازی از Q = 16 استفاده میکند (کوچکتر از Q ≥ N² لازم، اما اینجا دقیق چون r = 4 مقسومعلیهٔ ۱۶ است):
x : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
7^x mod 15 : 1 7 4 13 1 7 4 13 1 7 4 13 1 7 4 13
└── period r = 4 ──┘
QFT over Q = 16 → peaks at y ∈ {0, 4, 8, 12} (each with probability 1/4)
y/Q = 4/16, 8/16, 12/16 = 1/4, 1/2, 3/4 → continued fractions → r = 4
7^(r/2) = 7^2 = 49 ≡ 4 (mod 15), 4 ≢ −1 ≡ 14 → condition satisfied
gcd(4 − 1, 15) = 3 and gcd(4 + 1, 15) = 5 → 15 = 3 × 5
و شبیهسازی کامل — اورکل، QFT، اندازهگیری، کسر مسلسل، gcd:
import numpy as np
from fractions import Fraction
rng = np.random.default_rng(3)
N, a, Q = 15, 7, 16
f = np.array([pow(a, x, N) for x in range(Q)]) # 7^x mod 15
psi = np.zeros(Q * N, dtype=complex)
for x in range(Q):
psi[x * N + f[x]] = 1 # |x>|a^x mod N>
H = np.exp(2j * np.pi * np.outer(np.arange(Q), np.arange(Q)) / Q) / np.sqrt(Q)
psi = np.kron(H, np.eye(N)) @ psi # QFT روی Q برای ثبات ۱
p = (np.abs(psi.reshape(Q, N)) ** 2).sum(axis=1)
y = rng.choice(Q, p=p) # اندازهگیری ثبات ۱
r = Fraction(y, Q).limit_denominator(N).denominator # کسر مسلسل
print("y =", y, " r candidate =", r)
if r % 2 == 0 and pow(a, r, N) == 1:
print("factors:", np.gcd(pow(a, r // 2, N) - 1, N), np.gcd(pow(a, r // 2, N) + 1, N))
else:
print("unusable shot (y=0 or k shares a factor with r) — rerun")
شاخهٔ else تزئین نیست: y = 0 (با احتمال ¼) و y = 8 (که 1/2 میدهد؛ یعنی r/gcd(k,r) = 2) هر دو به همانجا میافتند — دقیقاً همانطور که ۲۶.۶ وعده داده بود.
from fractions import Fraction
for y in (4, 8, 12): # قلههای اندازهگیریشده، Q = 16، r واقعی = 4
fr = Fraction(y, 16).limit_denominator(15)
print(f"{y}/16 -> {fr} r-candidate = {fr.denominator}")
26.9منابع لازم
مدار منطقی: t ≈ 2n+1 کیوبیت شمارش، ثباتهای حساب n-بیتی، QFT با O(n²) گیت، و توانرسانی پیمانهای غالب با O(n³) گیت ساده — O(n²·polylog n) با مدارهای ضرب پیشرفته. تخمینهای سرتاسری برای RSA-2048: گیدنی–اکرا (Gidney–Ekerå، ۲۰۱۹) — حدود ۲۰ میلیون کیوبیت فیزیکی نویزی در ۸ ساعت؛ گیدنی (۲۰۲۵) — کمتر از ۱ میلیون کیوبیت نویزی در کمتر از یک هفته، به لطف حساب بهتر و چیدمانهای تصحیح خطا. هر دو تحمل خطای surface code با نرخ خطای فیزیکی نزدیک 10⁻³ را فرض میکنند. در برابر ماشینهای امروز — صدها تا چند هزار کیوبیت فیزیکی — شکاف حدود سه مرتبه بزرگی در شمار کیوبیت است. این افق برنامهریزی صادقانه است: دستیافتنی اما نه قریبالوقوع؛ این مهندسی است، نه خیال.
26.10پیامدها برای رمزنگاری
شور، RSA و Diffie–Hellman میدان متناهی و رمزنگاری منحنی بیضوی را میشکند، به شرط موجودبودن ماشینهای تحملپذیر خطا در مقیاس ۲۶.۹. Primitiveهای متقارن جان میدهند: گروور فقط ضریب ۲ در طول کلید مؤثر هزینه دارد، پس AES-256 سالم میماند. تهدید عملیاتی، اکنون برداشت کن، بعداً رمزگشایی کن (harvest now, decrypt later) است — حریفانی که امروز ترافیک رمزشده را ضبط میکنند تا پس از موجودشدن رایانهٔ کوانتومی رمزشکن، رمزگشایی کنند — و همین مهاجرت را برای رازهای طولانیعمر فوری میکند. NIST در ۲۰۲۴ جایگزینها را استاندارد کرد: ML-KEM (FIPS 203، شبکهها)، ML-DSA (FIPS 204)، SLH-DSA (FIPS 205، مبتنی بر هش). مهاجرت برنامهای دهساله است که هر پروتکلی را که روزی منتشر کردهاید لمس میکند — و نزدیکتر به خانه، نقطهٔ تلاقی مشاغل تحلیل رمز و محاسبات کوانتومی است (۵۱.۹). الگوریتم ۳۰ سال دارد؛ پیامدهایش هنوز در حال ساختهشدناند.