সরাসরি পর্বে যান
পর্ব ২৫ · ৮৩-এর মধ্যে · মডিউল ৪

Primality test আর factoring — Miller–Rabin থেকে কঠিনতার ধারণা

Primality Testing and Factoring — Trial Division, the Miller–Rabin Test with Proof, Error Bounds, Deterministic Bases, AKS, Pollard's Rho, and Why Factoring Is Believed Hard

Taught in Bangla, this lesson separates primality from factoring, measures the cost of trial division, and proves the Miller–Rabin test from the fact that 1 has only ±1 as square roots mod a prime, showing base 2 exposing 561. It explains the 4^−k error bound, deterministic base sets and AKS, and finds factors with Pollard's rho in in-page Python. Real desktop runs compare a Miller–Rabin implementation with sympy and gmpy2 and search for strong pseudoprimes.

এই পর্বে যা শিখবেন

  • Primality আর factoring কেন আলাদা সমস্যা, আর trial division-এর খরচ কেন অঙ্কের সংখ্যায় exponential
  • 1-এর বর্গমূলের lemma থেকে Miller–Rabin পরীক্ষার পূর্ণ প্রমাণ, আর 561-এর মতো Carmichael সংখ্যা ধরা
  • Strong liar, witness, ভুলের সম্ভাবনা 4−k, আর নির্দিষ্ট base-এর তালিকা কীভাবে যাচাই করা হয়
  • Pollard-এর rho: birthday-ভাবনা, Floyd-এর চক্র খোঁজা, আর কেন প্রায় √p ধাপ লাগে
  • ডেস্কটপে sympy আর gmpy2 দিয়ে বড় সংখ্যায় সত্যিকারের পরীক্ষা, আর factoring-এর বাস্তব রেকর্ড ও quantum প্রশ্ন

১ · দুটি আলাদা প্রশ্ন — “মৌলিক কি না” আর “উৎপাদক কী”

বাজারঘরের প্রকৌশলীরা দুটি কারণে প্রায়ই বড় মৌলিক সংখ্যা খোঁজেন। প্রথমত, গ্রাহকের id-কে বালতিতে ভাগ করার hash function h(k) = k mod m-এ m মৌলিক নিলে ছাঁচে-ঢালা id-ও ভালোভাবে ছড়ায় (পর্ব ২৬ “সংখ্যাতত্ত্বের প্রয়োগ — check digit, hashing আর pseudorandom সংখ্যা”-এ এর বিশ্লেষণ)। প্রথম খসড়ায় তাঁরা চান 106-এর ঠিক পরের মৌলিক। দ্বিতীয়ত, পেমেন্টের নিরাপত্তায় যে public-key ব্যবস্থা লাগে, তার চাবি বানাতে শত শত অঙ্কের দুটি মৌলিক সংখ্যা লাগে (গণিত পর্ব ২৮ “RSA-এর গণিত — key, encryption আর কেন কাজ করে”-এ)। দুই ক্ষেত্রেই কাজটি একই: একটি বড় বিজোড় সংখ্যা নেওয়া, মৌলিক কি না দেখা, না হলে পরেরটি।

এখানে দুটি প্রশ্ন আলাদা করা জরুরি। Primality: n কি মৌলিক? উত্তর শুধু “হ্যাঁ” বা “না”। Factoring: n যৌগিক হলে তার উৎপাদক কী? দ্বিতীয়টির উত্তর জানলে প্রথমটি জানা যায়, কিন্তু উল্টোটা নয়। এই পর্বের বড় শিক্ষা হলো, প্রথম প্রশ্নটি একটিও উৎপাদক না খুঁজে নিশ্চিতভাবে “যৌগিক” বলতে পারে। পর্ব ২৪-এ এর প্রথম ঝলক দেখেছেন: 214 mod 15 = 4 ≠ 1, তাই 15 যৌগিক। একটি primality test ঠিক এমন একটি পদ্ধতি; আর integer factorization মানে সংখ্যাটিকে মৌলিক উৎপাদকে ভেঙে দেখানো।

সবচেয়ে সরল পথ: trial division আর তার খরচ

পর্ব ২০ “বিভাজ্যতা আর মৌলিক সংখ্যা — division algorithm আর unique factorization”-এ প্রমাণ করেছেন: যৌগিক n-এর অন্তত একটি মৌলিক উৎপাদক ≤ √n. তাই 2, 3, 5, … দিয়ে √n পর্যন্ত ভাগ করে কোনো উৎপাদক না পেলে n মৌলিক। এই trial division নির্ভুল, আর ছোট উৎপাদক থাকলে দ্রুত। নিচের stepper বাজারঘরের একটি অর্ডার id 1147-এ এটি চালায়।

1n = 1147, √n ≈ 33.872ভাজক: 2, 3, 5, …, 3131147 mod 2, 3, 5 = 1, 1, 24mod 7, 11, 13, 17 = 6, 3, 3, 85mod 19, 23, 29 = 7, 20, 166mod 31 = 0 ⇒ 1147 = 31 · 377d অঙ্ক ⇒ প্রায় 10^(d/2) ভাগ
এই ধাপে কী হলো
ধাপ
ভাজক
ভাগশেষ
  1. সীমা। √1147 ≈ 33.87, তাই 33 পর্যন্ত মৌলিকগুলো দেখলেই চলে: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, মোট ১১টি।
  2. ছোট ভাজক। 1147 বিজোড় (ভাগশেষ 1), অঙ্কের যোগফল 13 বলে 3 দিয়ে ভাগশেষ 1, আর শেষ অঙ্ক 7 বলে 5 দিয়ে ভাগশেষ 2.
  3. মাঝারি ভাজক। 7 থেকে 29 পর্যন্ত সাতটি মৌলিকের ভাগশেষ 6, 3, 3, 8, 7, 20, 16; কোনোটি শূন্য নয়।
  4. উৎপাদক। 1147 = 31 · 37, ভাগশেষ 0. যৌগিক। 31 ঠিক √n-এর নিচে, তাই সীমার ঠিক আগেই ধরা পড়ল।
  5. খরচ। n মৌলিক হলে সব ভাজকই দেখতে হয়। শুধু বিজোড় ভাজক নিলেও d অঙ্কের n-এ প্রায় √n/2 ≈ 10d/2/2টি ভাগ: ১২ অঙ্কে পাঁচ লাখ, ৪০ অঙ্কে 5 · 1019.

এই খরচকে সঠিক ভাষায় বলা দরকার। একটি algorithm-এর খরচ মাপা হয় ইনপুটের দৈর্ঘ্য দিয়ে, আর n-এর দৈর্ঘ্য তার অঙ্ক বা bit-এর সংখ্যা, প্রায় log n. √n = 2(log2 n)/2, তাই trial division-এর সময় দৈর্ঘ্যের তুলনায় exponential. বিপরীতে pow(a, b, n) (binary exponentiation, পর্ব ২২ আর ১৩) মাত্র প্রায় 2 log2 b-টি গুণ করে, যা দৈর্ঘ্যের তুলনায় polynomial. এই পর্বের সব দ্রুত পরীক্ষা এই দ্বিতীয় ধরনের।

নিচের ব্লক ৬, ৮, ১০ আর ১২ অঙ্কের সবচেয়ে বড় মৌলিক সংখ্যায় trial division চালিয়ে ভাগের সংখ্যা আর সময় মাপে, তারপর সেই হার ধরে বড় সংখ্যার খরচ অনুমান করে। প্রথমবার চালালে ব্রাউজারে Python (Pyodide) নামতে কয়েক সেকেন্ড লাগে।

import time

def trial(n):                     # smallest factor of n, and how many divisions
    if n % 2 == 0:
        return 2, 1
    d, tries = 3, 1
    while d * d <= n:             # only up to sqrt(n): see lesson 20
        tries += 1
        if n % d == 0:
            return d, tries
        d += 2
    return n, tries               # no factor up to sqrt(n): n is prime

per_div = []
for n in (999983, 99999989, 9999999967, 999999999989):   # largest primes
    t = time.perf_counter()                               # with 6..12 digits
    f, tries = trial(n)
    sec = time.perf_counter() - t
    per_div.append(sec / tries)
    print(f"{len(str(n)):2d} digits  prime={f == n}  divisions={tries:>7,}"
          f"  time={sec * 1000:7.1f} ms")

c = per_div[-1]                   # seconds per division (rough)
for digits in (20, 30, 40):
    sec = 10 ** (digits / 2) / 2 * c          # sqrt(n)/2 odd divisions
    print(f"{digits} digits, worst case: about {sec:.0e} s"
          f" = {sec / 31557600:.0e} years")

for n in (1147, 2026111001):      # bazarghar order ids
    print(n, "-> smallest factor, divisions:", trial(n))

আসল আউটপুট (ব্রাউজারের Python; সময় আপনার যন্ত্রে আলাদা হবে):

 6 digits  prime=True  divisions=    500  time=    0.1 ms
 8 digits  prime=True  divisions=  5,000  time=    0.5 ms
10 digits  prime=True  divisions= 50,000  time=    7.7 ms
12 digits  prime=True  divisions=500,000  time=   67.8 ms
20 digits, worst case: about 7e+02 s = 2e-05 years
30 digits, worst case: about 7e+07 s = 2e+00 years
40 digits, worst case: about 7e+12 s = 2e+05 years
1147 -> smallest factor, divisions: (31, 16)
2026111001 -> smallest factor, divisions: (191, 96)

ভাগের সংখ্যা প্রতি দুই অঙ্কে ঠিক দশ গুণ: ৫০০, ৫,০০০, ৫০,০০০, ৫,০০,০০০. সময়ও মোটামুটি সেই হারে বাড়ে (১২ অঙ্কে প্রায় ৬৮ মিলিসেকেন্ড)। সেই হার ধরে ২০ অঙ্কের একটি মৌলিকে প্রায় ৭০০ সেকেন্ড, অর্থাৎ বারো মিনিটের মতো; ৩০ অঙ্কে প্রায় দুই বছর; ৪০ অঙ্কে প্রায় দুই লাখ বছর। Public-key কাজে সংখ্যা কয়েক শ অঙ্কের, তাই সেখানে trial division-এর প্রশ্নই ওঠে না। তবে শেষ দুই লাইন এর শক্তিও দেখায়: উৎপাদক ছোট হলে এটি দ্রুত। 1147-এ ১৬টি ভাগে 31 পাওয়া গেছে, আর ১০ অঙ্কের অর্ডার id 2026111001-এ মাত্র ৯৬টি ভাগে 191 (2026111001 = 191 · 10607911). বাস্তবের factoring প্রোগ্রামও তাই প্রথমে ছোট মৌলিক দিয়ে ভাগ করে নেয়। সময়ের সংখ্যাগুলো যন্ত্রভেদে বদলাবে, কিন্তু “দুই অঙ্কে দশ গুণ” অনুপাত বদলাবে না।

২ · Fermat-এর পরীক্ষা কোথায় আটকায়, আর 1-এর বর্গমূল

পর্ব ২৪ “Fermat-এর ছোট উপপাদ্য আর Euler-এর totient”-এর Fermat-এর পরীক্ষা এক লাইনে: an−1 mod n ≠ 1 হলে n যৌগিক। এটি দ্রুত, কিন্তু উল্টো দিকে খাটে না। সেখানে দেখেছেন, 341 base 2-এ পাস করে, আর 561 = 3 · 11 · 17 একটি Carmichael সংখ্যা: প্রতিটি সহমৌলিক base a-তে a560 ≡ 1 (mod 561). Carmichael সংখ্যা অসীম সংখ্যক, তাই base বাড়িয়ে Fermat-এর পরীক্ষাকে নির্ভরযোগ্য করা যায় না। সহমৌলিক নয় এমন base খুঁজে পাওয়া মানে আসলে একটি উৎপাদক খুঁজে পাওয়া, যা বড় সংখ্যায় ঠিক সেই কঠিন কাজ।

তাহলে an−1 ≡ 1-এর চেয়ে বেশি তথ্য কোথায় পাওয়া যায়? উত্তর: সেই 1-এ পৌঁছানোর পথে। n − 1 জোড় হলে an−1 হলো a(n−1)/2-এর বর্গ। তাই a(n−1)/2 হলো 1-এর একটি বর্গমূল mod n. মৌলিক modulus-এ 1-এর বর্গমূল মাত্র দুটি।

Lemma ২.১ (1-এর বর্গমূল)

p মৌলিক আর x একটি পূর্ণসংখ্যা হলে, x2 ≡ 1 (mod p) ⇔ x ≡ 1 বা x ≡ −1 (mod p).

প্রমাণ:

  1. (⇐) x ≡ ±1 হলে x2 ≡ (±1)2 = 1. — গুণ congruence মানে, পর্ব ২২
  2. (⇒) x2 ≡ 1 মানে p ∣ x2 − 1 = (x − 1)(x + 1). — congruence-এর সংজ্ঞা
  3. p মৌলিক, তাই Euclid-এর lemma অনুযায়ী p ∣ (x − 1) বা p ∣ (x + 1), অর্থাৎ x ≡ 1 বা x ≡ −1 (mod p). ∎ — Euclid-এর lemma, পর্ব ২১

ধাপ ৩-এ মৌলিকতা অপরিহার্য। যৌগিক modulus-এ 1-এর আরও বর্গমূল থাকতে পারে: mod 15-এ 42 = 16 ≡ 1, অথচ 4 ≢ ±1 (−1 ≡ 14). কারণ 15 ∣ (4 − 1)(4 + 1) = 3 · 5, কিন্তু 15 কোনো একটি উৎপাদককে আলাদাভাবে ভাগ করে না। এমন x-কে বলে 1-এর অদ্ভুত বর্গমূল (nontrivial square root of 1). আর এর একটি দারুণ পার্শ্বফল আছে: n ∣ (x − 1)(x + 1) অথচ n কোনোটিকে ভাগ করে না, তাই gcd(x − 1, n) হলো n-এর একটি প্রকৃত উৎপাদক। mod 15-এ gcd(3, 15) = 3, gcd(5, 15) = 5. অর্থাৎ অদ্ভুত বর্গমূল খুঁজে পাওয়া মানে শুধু “যৌগিক” জানা নয়, উৎপাদকও হাতে পাওয়া।

একটি তুলনা ভাবুন। ঢাকা থেকে ট্রেন চট্টগ্রাম পৌঁছেছে কি না, শুধু শেষ স্টেশন দেখে বলা যায়। কিন্তু টিকিট পরীক্ষক যদি মাঝের স্টেশনগুলোও দেখেন, তাহলে এমন একটি স্টেশন ধরা পড়তে পারে যা এই রুটে থাকারই কথা নয়। Fermat-এর পরীক্ষা শুধু শেষ স্টেশন (an−1 = 1) দেখে। Miller–Rabin মাঝের স্টেশনগুলো দেখে, আর “অসম্ভব স্টেশন” মানে 1-এর এমন বর্গমূল যা ±1 নয়।

৩ · Miller–Rabin পরীক্ষা — বিবৃতি, প্রমাণ আর 561

বিজোড় n > 2-এ n − 1 জোড়। তাকে যতবার পারা যায় 2 দিয়ে ভাগ করুন: n − 1 = 2s · d, যেখানে s ≥ 1 আর d বিজোড়। যেমন 560 = 24 · 35, 96 = 25 · 3. এবার ad থেকে শুরু করে s বার বর্গ করলে an−1 পাওয়া যায়:

ad, a2d, a4d, …, a2s−1d, a2sd = an−1 (সব mod n)

উপপাদ্য ৩.১ (Miller–Rabin-এর ভিত্তি)

p একটি বিজোড় মৌলিক, p − 1 = 2s · d (d বিজোড়), আর p ∤ a. তাহলে নিচের দুটির অন্তত একটি সত্য:

ad ≡ 1 (mod p), অথবা কোনো r-এ (0 ≤ r ≤ s − 1) a2rd ≡ −1 (mod p)

প্রমাণ: xr = a2rd mod p লিখুন, r = 0, 1, …, s. তাহলে xr+1 ≡ xr2.

  1. xs = ap−1 ≡ 1 (mod p). — Fermat-এর ছোট উপপাদ্য, p মৌলিক আর p ∤ a
  2. x0 ≡ 1 হলে প্রথম বিকল্পটি সত্য, প্রমাণ শেষ। — case ১
  3. নাহলে ক্রমে অন্তত একটি পদ (x0) 1 নয়, আর শেষ পদ 1. r নিন সবচেয়ে বড় সূচক যেখানে xr ≢ 1; তাহলে r ≤ s − 1 আর xr+1 ≡ 1. — well-ordering, সসীম সেটে সবচেয়ে বড় সদস্য
  4. xr2 ≡ xr+1 ≡ 1, তাই Lemma ২.১-এ xr ≡ ±1. xr ≢ 1 বলে xr ≡ −1, অর্থাৎ দ্বিতীয় বিকল্পটি সত্য। ∎ — Lemma ২.১

উপপাদ্যটিকে contrapositive আকারে পড়লেই পরীক্ষা। বিজোড় n আর 1 < a < n − 1 নিন। যদি ad ≢ 1 আর প্রতিটি 0 ≤ r ≤ s − 1-এ a2rd ≢ −1 (mod n), তবে n নিশ্চিতভাবে যৌগিক।

সংজ্ঞা ৩.২

বিজোড় n > 2, n − 1 = 2s · d. যদি ad ≡ 1 অথবা কোনো 0 ≤ r ≤ s − 1-এ a2rd ≡ −1 (mod n), তবে n হলো base-a strong probable prime. এমন n যৌগিক হলে তাকে base-a strong pseudoprime বলে, আর a হলো n-এর একটি strong liar. যে a শর্তটি ভাঙে, সে n-এর যৌগিকতার একটি witness.

লক্ষ করুন, strong probable prime সবসময় Fermat-এর পরীক্ষাতেও পাস করে: শর্তের দুই ক্ষেত্রেই বর্গ করতে করতে শেষে an−1 ≡ 1 আসে। তাই নতুন পরীক্ষা পুরোনোটির চেয়ে কখনো দুর্বল নয়। আর এটি কতটা শক্তিশালী, 561-এ দেখুন। Fermat base 2-এ 561 পাস করে, কিন্তু চেইনের মাঝখানে কী হয়?

1n = 561, a = 22560 = 2⁴ · 35 (s = 4, d = 35)3x₀ = 2³⁵ mod 561 = 2634x₁ = 263² mod 561 = 1665x₂ = 166² mod 561 = 676x₃ = 67² mod 561 = 1767 ≢ ±1 ⇒ 561 যৌগিক8gcd(66, 561) = 33, gcd(68, 561) = 17
চেইনের অবস্থা
পদ
মান
যাচাই
  1. ভাঙা। 560-কে চারবার 2 দিয়ে ভাগ করলে 35 থাকে: 560 = 24 · 35. তাই চেইনে x0 = 235, তারপর তিনবার বর্গ করে x3 = 2280 পর্যন্ত দেখতে হবে।
  2. প্রথম পদ। 235 mod 561 = 263 (repeated squaring-এ)। এটি 1 নয়, আর −1 ≡ 560-ও নয়। তাই পরের পদে যেতে হবে।
  3. প্রথম বর্গ। 2632 = 69169 = 123 · 561 + 166, তাই x1 = 166. এখনো 560 আসেনি।
  4. দ্বিতীয় বর্গ। 1662 = 27556 = 49 · 561 + 67, তাই x2 = 67.
  5. ধরা পড়া। 672 = 4489 = 8 · 561 + 1. অর্থাৎ 67 হলো 1-এর একটি বর্গমূল, অথচ 67 ≢ ±1. Lemma ২.১ বলে মৌলিক modulus-এ এটি অসম্ভব, তাই 561 যৌগিক, আর 2 একটি witness. (পরের বর্গ 2560 ≡ 1, তাই Fermat-এর পরীক্ষা এখানে কিছুই ধরত না।)
  6. বোনাস: উৎপাদক। 561 ∣ (67 − 1)(67 + 1) = 66 · 68, কিন্তু কোনোটিকে একা ভাগ করে না। gcd(66, 561) = 33 আর gcd(68, 561) = 17, তাই 561 = 33 · 17 = 3 · 11 · 17.

ইতিহাস: Gary Miller ১৯৭৬ সালে এই ধাঁচের একটি নির্ণায়ক (deterministic) পরীক্ষা দেন, যার সঠিকতা একটি অপ্রমাণিত অনুমান, generalized Riemann hypothesis-এর ওপর নির্ভর করে। Michael Rabin ১৯৮০ সালে প্রকাশিত কাজে base এলোমেলোভাবে বেছে পরীক্ষাটিকে একটি randomized algorithm বানান, যার ভুলের সম্ভাবনা কোনো অনুমান ছাড়াই প্রমাণ করা যায়। তাই নামটি দুজনের। একই সময়ে Louis Monier-ও স্বাধীনভাবে ভুলের সীমাটি প্রমাণ করেন বলে উল্লেখ পাওয়া যায়।

এবার পরীক্ষাটি নিজে লিখুন। নিচের strong_test পুরো চেইন ছাপে, অদ্ভুত বর্গমূল পেলে gcd দিয়ে উৎপাদক দেখায়, আর miller_rabin নির্দিষ্ট seed থেকে ২০টি এলোমেলো base নেয়।

from math import gcd
import random

def strong_test(n, a, show=False):    # n odd, n > 3, 1 < a < n - 1
    s, d = 0, n - 1
    while d % 2 == 0:                  # n - 1 = 2^s * d, d odd
        s, d = s + 1, d // 2
    chain = [pow(a, d, n)]
    for _ in range(s):                 # a^d, a^2d, a^4d, ..., a^(n-1)
        chain.append(chain[-1] ** 2 % n)
    passed = chain[0] == 1 or (n - 1) in chain[:s]
    if show:
        print(f"n={n}, a={a}: n-1 = 2^{s}*{d}, chain {chain}")
        for x, y in zip(chain, chain[1:]):
            if y == 1 and x not in (1, n - 1):        # x^2 = 1, x != +-1
                print(f"   {x}^2 = 1 (mod n): gcd({x}-1, n) =", gcd(x - 1, n))
                break
        print("   ->", "probable prime" if passed else "COMPOSITE, a is a witness")
    return passed

def miller_rabin(n, k=20, rng=random.Random(25)):
    if n < 4:
        return n in (2, 3)
    if n % 2 == 0:
        return False
    return all(strong_test(n, rng.randrange(2, n - 1)) for _ in range(k))

strong_test(561, 2, show=True)        # Carmichael: Fermat says 1 for a = 2
strong_test(2047, 2, show=True)       # 23 * 89 fools base 2 ...
strong_test(2047, 3, show=True)       # ... but not base 3
print("Fermat base 2 on 561:", pow(2, 560, 561))
for n in (561, 1105, 1729, 2**61 - 1, 2**67 - 1, 10**18 + 9):
    print(n, "->", "prime" if miller_rabin(n) else "composite")

আসল আউটপুট (ব্রাউজারের Python):

n=561, a=2: n-1 = 2^4*35, chain [263, 166, 67, 1, 1]
   67^2 = 1 (mod n): gcd(67-1, n) = 33
   -> COMPOSITE, a is a witness
n=2047, a=2: n-1 = 2^1*1023, chain [1, 1]
   -> probable prime
n=2047, a=3: n-1 = 2^1*1023, chain [1565, 1013]
   -> COMPOSITE, a is a witness
Fermat base 2 on 561: 1
561 -> composite
1105 -> composite
1729 -> composite
2305843009213693951 -> prime
147573952589676412927 -> composite
1000000000000000009 -> prime

প্রথম অংশ stepper-এর হিসাবই: 561-এর চেইন 263, 166, 67, 1, 1, আর 67 থেকে gcd 33. দ্বিতীয় অংশে 2047 = 23 · 89: 2046 = 2 · 1023, তাই s = 1, আর 21023 ≡ 1, ফলে base 2-এ পাস। 2047 হলো সবচেয়ে ছোট base-2 strong pseudoprime. Base 3-এ চেইন 1565, 1013: প্রথম পদ ±1 নয়, তাই যৌগিক; এমনকি শেষ পদ 32046 ≡ 1013 ≠ 1, তাই Fermat base 3-ও এটি ধরত। কিন্তু এখানে কোনো অদ্ভুত বর্গমূল ছাপা হয়নি: witness পাওয়া গেছে, উৎপাদক নয়। শেষ ছয় লাইনে ২০-base পরীক্ষা। তিনটি Carmichael সংখ্যা 561, 1105, 1729 যৌগিক বলে ধরা পড়েছে; 261 − 1 (একটি Mersenne মৌলিক) আর 1018 + 9 মৌলিক বলে এসেছে; আর 267 − 1 যৌগিক, যার উৎপাদক 193707721 · 761838257287 (এর ইতিহাস ভাবনার প্রশ্ন ১-এ)। প্রতিটি উত্তর ডেস্কটপে sympy দিয়েও মেলানো হয়েছে।

৪ · ভুলের সম্ভাবনা, নির্দিষ্ট base আর AKS

Miller–Rabin-এর “যৌগিক” উত্তর সবসময় সঠিক, কারণ তার পেছনে একটি witness আছে। ভুল হতে পারে শুধু উল্টো দিকে: যৌগিক n-এর জন্য এমন base বাছা, যে strong liar. তাহলে প্রশ্ন, একটি যৌগিক সংখ্যার কতগুলো strong liar থাকতে পারে?

উপপাদ্য ৪.১ (Monier আর Rabin, ১৯৮০)

n বিজোড় যৌগিক আর n > 9 হলে {1, 2, …, n − 1}-এ strong liar-এর সংখ্যা ≤ φ(n)/4. তাই 2 থেকে n − 2-এর মধ্যে স্বাধীনভাবে k-টি base বাছলে, যৌগিক n সবগুলোয় পার পাওয়ার সম্ভাবনা ≤ 4−k.

প্রমাণটি এখানে বাদ দেওয়া হলো: এতে mod n-এর সহমৌলিক ভাগশেষের group-গঠন আর CRT-এর সূক্ষ্ম গণনা লাগে (group-এর ভাষা পর্ব ৭০ “Group — symmetry, cyclic group আর Lagrange-এর উপপাদ্য”-এ আসবে)। তবে মূল ধারণাটি অনুশীলন ১-এ নিজে প্রমাণ করবেন: n-এর দুটি ভিন্ন বিজোড় মৌলিক উৎপাদক থাকলে 1-এর অদ্ভুত বর্গমূল থাকতেই হবে, আর বেশিরভাগ base চেইনের কোথাও সেটিকে বা অন্য কোনো অসংগতিকে সামনে আনে। একই সীমায় 9 বাদ, কারণ সেখানে 8টি base-এর মধ্যে 2টি (1 আর 8) liar, আর φ(9)/4 = 1.5.

সীমাটি পড়ার সময় একটি সূক্ষ্মতা মনে রাখুন। 4−k হলো একটি নির্দিষ্ট যৌগিক n-এর জন্য, base বাছাইয়ের এলোমেলোতার ওপর সম্ভাবনা। এটি “পাস করা সংখ্যাটি যৌগিক হওয়ার সম্ভাবনা” নয়; সেটি নির্ভর করে কোন সংখ্যা থেকে n এসেছে তার ওপর (Bayes-এর উপপাদ্য, পর্ব ৩৯)। বাস্তবে এলোমেলো বড় বিজোড় সংখ্যায় liar-এর অনুপাত সীমার চেয়ে অনেক কম, তাই কয়েকটি base-ই যথেষ্ট। k = 20-এ সীমা 4−20 ≈ 9 · 10−13. এমন algorithm, যা নির্দিষ্ট সময়ে শেষ হয় কিন্তু খুব ছোট সম্ভাবনায় ভুল বলতে পারে, তাকে Monte Carlo algorithm বলে, আর বারবার চালিয়ে ভুল কমানো হলো amplification (DSA কোর্সের পর্ব ৬১).

নিচের ব্লক 800-এর নিচে প্রতিটি বিজোড় যৌগিক n-এ সব base গুনে Fermat liar আর strong liar তুলনা করে, Monier–Rabin-এর অনুপাত দেখে, তারপর 105-এর নিচে কোন যৌগিক সংখ্যা base 2-কে, আর কোনটি একসঙ্গে 2 আর 3-কে ঠকায়, তা খোঁজে।

from math import gcd

def strong_test(n, a):                 # same test as before, no printing
    s, d = 0, n - 1
    while d % 2 == 0:
        s, d = s + 1, d // 2
    x = pow(a, d, n)
    if x in (1, n - 1):
        return True
    for _ in range(s - 1):
        x = x * x % n
        if x == n - 1:
            return True
    return False

N = 10**5
prime = [False, False] + [True] * (N - 2)     # sieve of Eratosthenes
for i in range(2, int(N ** 0.5) + 1):
    if prime[i]:
        prime[i * i::i] = [False] * len(range(i * i, N, i))

worst = (0, None)
for n in (n for n in range(11, 800, 2) if not prime[n]):   # odd composites, n > 9
    strong = sum(strong_test(n, a) for a in range(1, n))
    phi = sum(gcd(a, n) == 1 for a in range(1, n))
    worst = max(worst, (strong / phi, n))
    if n in (91, 341, 561):
        fermat = sum(pow(a, n - 1, n) == 1 for a in range(1, n))
        print(f"n={n}: phi={phi}, Fermat liars {fermat}, strong liars {strong}")
print(f"largest strong liars / phi(n) for 9 < n < 800: {worst[0]:.3f} at n = {worst[1]}")

fool2 = [n for n in range(9, N, 2) if not prime[n] and strong_test(n, 2)]
print("odd composites below 10^5 passing base 2:", len(fool2), fool2[:5], "...")
print("passing bases 2 and 3:", [n for n in fool2 if strong_test(n, 3)])
print("1373653 = 829*1657, bases 2, 3, 5:", [strong_test(1373653, a) for a in (2, 3, 5)])

আসল আউটপুট (ব্রাউজারের Python):

n=91: phi=72, Fermat liars 36, strong liars 18
n=341: phi=300, Fermat liars 100, strong liars 50
n=561: phi=320, Fermat liars 320, strong liars 10
largest strong liars / phi(n) for 9 < n < 800: 0.250 at n = 703
odd composites below 10^5 passing base 2: 16 [2047, 3277, 4033, 4681, 8321] ...
passing bases 2 and 3: []
1373653 = 829*1657, bases 2, 3, 5: [True, True, False]

91 = 7 · 13-এ φ = 72, Fermat liar 36টি, আর strong liar ঠিক 18 = 72/4: Monier–Rabin-এর সীমা এখানে হুবহু ছুঁয়েছে। 341-এ strong liar 50টি, Fermat liar-এর অর্ধেক। সবচেয়ে নাটকীয় 561: সব 320টি সহমৌলিক base Fermat-এর কাছে মিথ্যা বলে (Carmichael-এর সংজ্ঞা), কিন্তু strong liar মাত্র 10টি। ৫৬০টি base থেকে এলোমেলো একটি বাছলে ধরা পড়ার সম্ভাবনা তাই প্রায় ৯৮%. চতুর্থ লাইন: 9-এর বড় আর 800-এর ছোট সব বিজোড় যৌগিকে অনুপাত কখনো 0.25 ছাড়ায়নি; সর্বোচ্চ 0.250 পাওয়া গেছে 703 = 19 · 37-এ (91-এও সমান)। এটি উপপাদ্য ৪.১-এর পরীক্ষা, প্রমাণ নয়। শেষ অংশে 105-এর নিচে ১৬টি যৌগিক সংখ্যা base 2-কে ঠকায়, প্রথমটি 2047, কিন্তু একটিও 2 আর 3 দুটোকে একসঙ্গে নয়। প্রথম এমন সংখ্যা 1373653 = 829 · 1657, আর সেটি base 5-এ ধরা পড়ে।

এলোমেলো base ছাড়া: নির্দিষ্ট base-এর তালিকা

শেষ লাইনগুলো একটি কৌশলের ইঙ্গিত দেয়। যদি জানা থাকে যে একটি সীমার নিচে কোনো যৌগিক সংখ্যা একসঙ্গে কয়েকটি নির্দিষ্ট base-কে ঠকায় না, তাহলে সেই সীমার নিচে পরীক্ষাটি পুরোপুরি deterministic, কোনো ভুলের সম্ভাবনা নেই। এমন সীমা বের করা হয়েছে বিশাল কম্পিউটার-অনুসন্ধানে। নিচের তালিকার প্রতিটি “সবচেয়ে ছোট যৌগিক” সংখ্যা প্রকাশিত গবেষণা থেকে নেওয়া; এই পর্বের জন্য ডেস্কটপে (§৬) প্রতিটির উৎপাদক, তালিকার সব base-এ পাস করা আর পরের মৌলিক base-এ ধরা পড়া যাচাই করা হয়েছে, আর 2 · 106 পর্যন্ত সম্পূর্ণ খুঁজে দ্বিতীয় সারির দাবিটি মেলানো হয়েছে।

Baseসবগুলোকে ঠকানো সবচেয়ে ছোট যৌগিকউৎপাদক
22,04723 · 89
2, 31,373,653829 · 1657
2, 3, 525,326,0012251 · 11251
2, 3, 5, 73,215,031,751151 · 751 · 28351
2 থেকে 37 (প্রথম ১২টি মৌলিক)প্রায় 3.19 · 1023দুটি ১২ অঙ্কের মৌলিক
2 থেকে 41 (প্রথম ১৩টি মৌলিক)প্রায় 3.32 · 1024দুটি ১৩ অঙ্কের মৌলিক

অর্থাৎ n < 3,215,031,751 হলে base 2, 3, 5, 7-এ পাস করা মানেই মৌলিক, আর 64-bit পূর্ণসংখ্যার (n < 264 ≈ 1.8 · 1019) পুরো পরিসর প্রথম ১২টি মৌলিক base-এ নিশ্চিতভাবে ঢাকা পড়ে। প্রথম চারটি সারির সীমা Carl Pomerance, John Selfridge আর Samuel Wagstaff-এর ১৯৮০ সালের হিসাব বলে পরিচিত; শেষ দুটি Jonathan Sorenson আর Jonathan Webster-এর ২০১৫ সালের দিকের কাজ। সংখ্যাগুলো উদ্ধৃতি; এই পর্বের script সীমার নিচের সব সংখ্যা পরীক্ষা করেনি, শুধু উপরের দাবিগুলো।

AKS — মৌলিকতা polynomial সময়ে

Miller–Rabin দ্রুত কিন্তু randomized; নির্দিষ্ট base-এর তালিকা শুধু একটি সীমা পর্যন্ত। সব n-এর জন্য deterministic আর polynomial-সময়ের পরীক্ষা কি আছে? ২০০২ সালে কানপুরের IIT-এর Manindra Agrawal আর তাঁর দুই ছাত্র Neeraj Kayal ও Nitin Saxena হ্যাঁ বলে প্রমাণ দেন; শিরোনাম ছিল “PRIMES is in P”, আর প্রকাশ ২০০৪ সালে। ভিত্তিটি Fermat-এরই একটি polynomial রূপ: gcd(a, n) = 1 হলে

n মৌলিক ⇔ (x + a)n ≡ xn + a (mod n), polynomial হিসেবে

(⇒) দিকটি আপনি এখনই দেখতে পারেন: p মৌলিক হলে 0 < k < p-এ binomial coefficient C(p, k) = p!/(k!(p − k)!)-এর লবে p আছে কিন্তু হরে নেই, তাই p ∣ C(p, k); মাঝের সব পদ মুছে যায় আর ap ≡ a (Fermat). পুরো polynomial যাচাই করতে n-টি সহগ লাগে, যা আবার exponential; AKS-এর আসল কৌশল হলো এটিকে একটি ছোট polynomial xr − 1-এর modulus-এ কয়েকটি a-তে পরীক্ষা করা। মূল সংস্করণের সময় মোটামুটি (log n)12-এর মতো, পরে Hendrik Lenstra আর Carl Pomerance-এর উন্নত রূপে প্রায় (log n)6. তত্ত্বে এটি যুগান্তকারী, কিন্তু বাস্তবে Miller–Rabin আর তার আত্মীয়রা অনেক দ্রুত, তাই সফটওয়্যারে প্রায় সবসময় সেগুলোই চলে।

৫ · Factoring কেন কঠিন — Pollard-এর rho

Miller–Rabin বলল 561 যৌগিক, আর ভাগ্যক্রমে উৎপাদকও দিল। কিন্তু সাধারণভাবে Miller–Rabin উৎপাদক দেয় না: 2047 base 3-এ ধরা পড়েছে, অথচ চেইনে কোনো অদ্ভুত বর্গমূল আসেনি। “যৌগিক” জানা আর “কীভাবে ভাঙে” জানা দুটি আলাদা কাজ। Trial division-এর চেয়ে অনেক ভালো কিন্তু তবু সহজ একটি পদ্ধতি হলো John Pollard-এর ১৯৭৫ সালের rho algorithm.

ধারণাটি birthday paradox থেকে (পর্ব ৪২ “Birthday paradox, hash collision আর balls-into-bins”-এ গণিত): p-টি ঘরে এলোমেলো বল ফেললে মাত্র প্রায় √p বলেই দুটি একই ঘরে পড়ার ভালো সম্ভাবনা। ধরুন n-এর একটি অজানা মৌলিক উৎপাদক p. একটি ক্রম চালান x0 = 2, xi+1 = f(xi) = xi2 + 1 mod n. এই ক্রমকে mod p দেখলে (যা আমরা সরাসরি দেখতে পাই না) সেটিও একই নিয়মে চলে, কারণ যোগ-গুণ congruence মানে: xi+1 mod p = (xi mod p)2 + 1 mod p. মাত্র p-টি সম্ভাব্য মান, তাই pigeonhole নীতিতে কোনো এক সময় মান পুনরাবৃত্ত হয়, আর তারপর থেকে ক্রমটি চক্রে ঘোরে। লেজ আর চক্র মিলে আকারটি গ্রিক অক্ষর ρ (rho)-এর মতো।

8051-এর ক্রম, mod 97-এ দেখলে — ρ আকার

x ↦ x² + 1 (mod 8051), x₀ = 2. প্রতিটি বৃত্তে mod 97-এর মান, পাশে mod 8051-এর যে পদগুলো সেখানে পড়ে।

Pollard rho sequence for 8051 seen modulo 97 2 5 26 95 x₀ = 2 x₁ = 5 x₄ = 7474 x₂ = 26 x₅ = 2839 x₃ = 677 x₆ = 871 চক্র (cycle) দৈর্ঘ্য λ = 3 লেজ (tail) x₃ ≡ x₆ (mod 97) ⇒ gcd(194, 8051) = 97

ছবিতে x3 = 677 আর x6 = 871, mod 8051-এ আলাদা কিন্তু mod 97-এ দুটিই 95. তাই 97 ∣ (871 − 677) = 194, অথচ 8051 ∤ 194. ফলে gcd(194, 8051) = 97, একটি প্রকৃত উৎপাদক, আর আমরা 97 আগে থেকে না জেনেই সেটি পেলাম। বাকি প্রশ্ন: দুই পদ যে mod p-এ মিলেছে, সেটা জানব কীভাবে, যখন p-ই অজানা? উত্তর: প্রতিটি সম্ভাব্য জোড়ার gcd দেখা ব্যয়বহুল, তাই Floyd-এর cycle detection (কচ্ছপ আর খরগোশ) দিয়ে শুধু xi আর x2i জোড়া দেখা হয় (DSA কোর্সের পর্ব ১২-এ linked list-এ একই কৌশল)।

Lemma ৫.১ (Floyd)

একটি সসীম সেটে xi+1 = g(xi) ক্রমের লেজের দৈর্ঘ্য μ আর চক্রের দৈর্ঘ্য λ হলে (অর্থাৎ xμ চক্রের প্রথম পদ, আর i ≥ μ-এ xi+λ = xi), তাহলে এমন একটি i আছে যেখানে 1 ≤ i ≤ μ + λ আর xi = x2i.

প্রমাণ:

  1. চক্রে ঢোকার পর ক্রম প্রতি λ ধাপে নিজেকে পুনরাবৃত্তি করে, তাই i, j ≥ μ হলে xi = xj ⇔ λ ∣ (j − i). — চক্রের সংজ্ঞা, ভাগশেষ mod λ
  2. j = 2i নিলে শর্তটি হয় λ ∣ i. তাই এমন i চাই যা λ-এর গুণিতক আর ≥ μ (এবং ≥ 1). — ধাপ ১
  3. λ, 2λ, 3λ, … এর মধ্যে প্রথম যে গুণিতকটি ≥ max(μ, 1), সেটি তার আগের গুণিতক থেকে ঠিক λ বড়, আর আগেরটি μ-এর ছোট (বা শূন্য)। তাই সেটি ≤ μ + λ. ∎ — division algorithm, পর্ব ২০

Lemma-টি mod p-এর ক্রমে লাগালে Pollard-এর algorithm পাওয়া যায়: x = y = 2 থেকে শুরু, প্রতি ধাপে x এক পা (x ← f(x)), y দুই পা (y ← f(f(y))), আর d = gcd(|x − y|, n) দেখা। d = 1 হলে চলতে থাকুন; 1 < d < n হলে একটি উৎপাদক পাওয়া গেল; d = n হলে এই f-এ ব্যর্থ, অন্য c নিয়ে f(x) = x2 + c দিয়ে আবার চেষ্টা। mod p-এর চক্রে μ + λ ধাপের মধ্যে মিল হবেই। যদি f এলোমেলো ফাংশনের মতো আচরণ করে, তাহলে birthday-যুক্তিতে μ + λ গড়ে প্রায় √(πp/2) ≈ 1.25√p. এটি একটি heuristic, প্রমাণিত উপপাদ্য নয়: x2 + c সত্যিই এলোমেলো নয়, তবে অভিজ্ঞতায় অনুমানটি ভালো খাটে। ফলে সবচেয়ে ছোট মৌলিক উৎপাদক p হলে খরচ প্রায় √p ≤ n1/4 ধাপ, trial division-এর p ধাপের তুলনায় নাটকীয়ভাবে কম।

1n = 8051, x = y = 22i=1: x = 5, y = 263    gcd(21, 8051) = 14i=2: x = 26, y = 74745    gcd(7448, 8051) = 16i=3: x = 677, y = 8717    gcd(194, 8051) = 9788051 = 97 · 83
কচ্ছপ আর খরগোশ
x (১ পা)
y (২ পা)
পার্থক্য
mod 97
  1. শুরু। n = 8051, f(x) = x2 + 1 mod n. কচ্ছপ x আর খরগোশ y দুজনেই 2-এ।
  2. i = 1. x = f(2) = 5; y = f(f(2)) = f(5) = 26. পার্থক্য 21, আর gcd(21, 8051) = 1. কোনো উৎপাদক নেই।
  3. i = 2. x = f(5) = 26; y = f(f(26)) = f(677) = 7474. পার্থক্য 7448 = 23 · 72 · 19, আর gcd(7448, 8051) = 1.
  4. i = 3. x = f(26) = 677; y = f(f(7474)) = f(2839) = 871. পার্থক্য 194 = 2 · 97, আর gcd(194, 8051) = 97. উৎপাদক পাওয়া গেল: 8051 = 97 · 83.
  5. কেন এখানে। mod 97-এ ক্রমটি 2, 5, 26, 95, 5, 26, 95, …: লেজ μ = 1, চক্র λ = 3. Lemma ৫.১ বলে মিল i ≤ μ + λ = 4-এর মধ্যে, আর প্রথম λ-গুণিতক ≥ 1 হলো i = 3. ঠিক তাই হয়েছে।

এবার একটি বড় পরীক্ষা। নিচের ব্লক ছোট উদাহরণগুলো চালায়, তারপর ১০,০০০তম মৌলিক 104729 আর ১,০০,০০০তম মৌলিক 1299709-এর গুণফল (১২ অঙ্কের একটি semiprime) ভাঙে, ৪০টি এমন সংখ্যায় গড় ধাপ মাপে, আর একটি ব্যর্থতার উদাহরণ দেখায়।

from math import gcd, isqrt

def rho(n, c=1, x0=2):
    f = lambda v: (v * v + c) % n     # x -> x^2 + c (mod n)
    x = y = x0
    steps = 0
    while True:
        x, y = f(x), f(f(y))          # tortoise: 1 step, hare: 2 steps
        steps += 1
        d = gcd(abs(x - y), n)
        if d != 1:
            return d, steps           # d == n means this c failed

for n in (8051, 10403, 2026111001):
    d, steps = rho(n)
    print(f"n={n}: factor {d} = n/{n // d}, steps {steps}")

n = 104729 * 1299709                  # 10,000th prime * 100,000th prime
d, steps = rho(n)
p = min(d, n // d)
print(f"n={n} ({len(str(n))} digits): {d} * {n // d}")
print(f"   rho steps {steps}, sqrt(p) = {isqrt(p)}, trial division ~ {p // 2} divisions")

total = 0                             # average over many 12-digit semiprimes
ps = [p for p in range(100003, 101000, 2) if all(p % q for q in range(3, 320, 2))]
qs = [q for q in range(10**6 + 3, 10**6 + 2000, 2) if all(q % r for r in range(3, 1001, 2))]
pairs = list(zip(ps[:40], qs[:40]))
for p, q in pairs:
    d, steps = rho(p * q)
    total += steps
print(f"average rho steps over {len(pairs)} semiprimes (p ~ 10^5): {total / len(pairs):.0f}",
      f"| sqrt(p) ~ {isqrt(100000)}")

print("rho on 25 = 5*5:", rho(25), "  with c = 2:", rho(25, c=2))

আসল আউটপুট (ব্রাউজারের Python):

n=8051: factor 97 = n/83, steps 3
n=10403: factor 101 = n/103, steps 9
n=2026111001: factor 191 = n/10607911, steps 15
n=136117223861 (12 digits): 104729 * 1299709
   rho steps 278, sqrt(p) = 323, trial division ~ 52364 divisions
average rho steps over 40 semiprimes (p ~ 10^5): 332 | sqrt(p) ~ 316
rho on 25 = 5*5: (25, 3)   with c = 2: (5, 2)

প্রথম তিন লাইন: 8051 stepper-এর মতোই তিন ধাপে 97 দেয়, 10403 = 101 · 103 নয় ধাপে (অনুশীলন ২), আর অর্ডার id 2026111001 পনেরো ধাপে 191. ১২ অঙ্কের 136117223861-এ rho ২৭৮ ধাপে 104729 পেয়েছে, যেখানে √p = 323; trial division-এ লাগত প্রায় ৫২,৩৬৪টি ভাগ, অর্থাৎ প্রায় ১৯০ গুণ বেশি কাজ। ৪০টি semiprime-এ গড় ৩৩২ ধাপ, √p ≈ 316-এর একই মাপের, ঠিক যেমন birthday-ভাবনা পূর্বাভাস দেয়। শেষ লাইনটি সতর্কতা: 25 = 5 · 5-এ c = 1 নিলে rho 25 ফেরত দেয়, অর্থাৎ ব্যর্থ, কারণ mod 5 আর mod 25 দুটিতেই একই ধাপে মিল হয়েছে; c = 2 নিলে দুই ধাপে 5. তাই d = n মানে “আবার চেষ্টা করুন”, “মৌলিক” নয় (অনুশীলন ৪)।

৬ · ডেস্কটপে সত্যিকারের run — sympy, gmpy2 আর বড় সংখ্যা

ব্রাউজারের ব্লকগুলো ছোট সংখ্যায় সীমিত। বড় সংখ্যায় আমাদের হাতে লেখা পরীক্ষা পেশাদার লাইব্রেরির সঙ্গে কেমন পাল্লা দেয়, তা দেখতে এই কোর্সের লেখার সময় একটি সাধারণ Windows ডেস্কটপে সত্যিকারের run করা হয়েছে: Python 3.12.13, sympy 1.14.0 (BSD লাইসেন্স) আর gmpy2 2.3.2 (GMP লাইব্রেরির Python সংযোগ, LGPL লাইসেন্স), uv দিয়ে বানানো একটি ছোট প্রজেক্টে। নিজে চালাতে চাইলে:

cd ~/bazarghar-dm
uv add sympy gmpy2
uv run python bench.py
uv run python verify.py

bench.py-এর মূল অংশ নিচে। is_sprp (strong test), mr আর rho ফাংশন তিনটি §৩ আর §৫-এর ব্রাউজার-ব্লকের ফাংশনের হুবহু সমতুল্য, তাই এখানে বাদ দেওয়া হলো। প্রতিটি পরীক্ষা ২০০ বার চালিয়ে এক বারের গড় সময় মাপা হয়েছে (us মানে মাইক্রোসেকেন্ড)।

import sys, time, random
import sympy, gmpy2
# is_sprp, mr and rho: same as the in-page blocks

def per_call(fn, arg, reps):
    t = time.perf_counter()
    for _ in range(reps):
        r = fn(arg)
    return r, (time.perf_counter() - t) / reps * 1e6

print("Python", sys.version.split()[0], "| sympy", sympy.__version__, "| gmpy2", gmpy2.version())
p20, p40, p60 = (sympy.nextprime(10**k) for k in (19, 39, 59))
# Chernick form (6k+1)(12k+1)(18k+1): a Carmichael number when all three are prime
k = next(k for k in range(10**19, 10**19 + 10**6)
         if all(sympy.isprime(m * k + 1) for m in (6, 12, 18)))
car = (6*k + 1) * (12*k + 1) * (18*k + 1)
tests = [("prime 20d", p20), ("prime 40d", p40), ("prime 60d", p60),
         ("p40*q20 (60d)", p40 * sympy.nextprime(10**20)),
         ("Carmichael %dd" % len(str(car)), car)]
print("%-16s %-6s %-6s %-6s %10s %10s %10s" % ("number", "MR20", "sympy", "gmpy2", "MR us", "sympy us", "gmpy2 us"))
for name, n in tests:
    a, t1 = per_call(mr, n, 200)
    b, t2 = per_call(sympy.isprime, n, 200)
    c, t3 = per_call(lambda v: gmpy2.is_prime(v, 25), n, 200)
    print("%-16s %-6s %-6s %-6s %10.1f %10.1f %10.1f" % (name, a, b, c, t1, t2, t3))
print("Carmichael: 2^(n-1) mod n == 1 ?", pow(2, car - 1, car) == 1, "| strong base 2 ?", is_sprp(car, 2))

rng = random.Random(2026)
p = sympy.nextprime(rng.randrange(10**10, 10**11))
q = sympy.nextprime(rng.randrange(10**12, 10**13))
n = p * q
t = time.perf_counter(); d, steps = rho(n); t_rho = time.perf_counter() - t
t = time.perf_counter(); fi = sympy.factorint(n); t_f = time.perf_counter() - t
# ... four print lines for these results (see the output)
$ uv run python bench.py
Python 3.12.13 | sympy 1.14.0 | gmpy2 2.3.2
number           MR20   sympy  gmpy2       MR us   sympy us   gmpy2 us
prime 20d        True   True   True        168.5        9.5        4.7
prime 40d        True   True   True        433.7       33.9       20.1
prime 60d        True   True   True        880.6       68.8       51.9
p40*q20 (60d)    False  False  False        47.0        8.7        7.7
Carmichael 61d   False  False  False        55.2        9.7        7.8
Carmichael: 2^(n-1) mod n == 1 ? True | strong base 2 ? False
semiprime n = 448985231080606748777401 (24 digits)
our rho : factor 53461288997 steps 122067 sqrt(p) ~ 231216 time 0.09 s
factorint: {53461288997: 1, 8398324086533: 1} time 0.12 s
trial division would need about 2.7e+10 odd divisions

ফলগুলো পড়ুন। প্রথমত, তিনটি পদ্ধতির উত্তর প্রতিটি সারিতে এক। ৬০ অঙ্কের একটি মৌলিক সংখ্যায় আমাদের ২০-base Miller–Rabin এক মিলিসেকেন্ডেরও কম সময় নেয়; trial division-এ একই কাজে মহাবিশ্বের বয়সের চেয়েও বেশি লাগত। মৌলিক সংখ্যায় সময় বেশি, কারণ ২০টি base-ই পুরো চলে; যৌগিক সংখ্যায় প্রথম base-ই সাধারণত ধরে ফেলে, তাই প্রায় এক base-এর সময়। দ্বিতীয়ত, sympy আর gmpy2 আমাদের চেয়ে অনেক দ্রুত: মৌলিক সংখ্যায় প্রায় ১৩ থেকে ৩৬ গুণ, যৌগিকে প্রায় ৫ থেকে ৭ গুণ। sympy কম রাউন্ড চালায়, আর gmpy2 ২৫ রাউন্ড চালিয়েও দ্রুত, কারণ বড় সংখ্যার গুণ হয় GMP-র অপ্টিমাইজ করা C কোডে। sympy-র নিজের বিবরণ অনুযায়ী 264-এর নিচে এটি নির্দিষ্ট base-এ deterministic Miller–Rabin চালায়, আর তার ওপরে strong BPSW পরীক্ষা, যার কোনো counterexample এখনো জানা নেই। তৃতীয়ত, Chernick-এর সূত্রে বানানো ৬১ অঙ্কের একটি Carmichael সংখ্যা Fermat base 2-এ পাস করে, কিন্তু strong test-এ base 2-এই ধরা পড়ে।

শেষ অংশ factoring. ২৪ অঙ্কের semiprime-এর ছোট উৎপাদক p ≈ 5.3 · 1010, আর আমাদের rho ১,২২,০৬৭ ধাপে, ০.০৯ সেকেন্ডে সেটি পেয়েছে; √p ≈ ২,৩১,২১৬, তাই ধাপের সংখ্যা √p-এর একই মাপের। একই সংখ্যায় trial division-এ প্রায় 2.7 · 1010টি ভাগ লাগত। sympy.factorint একই উত্তর দিয়েছে; তার ভেতরে trial division, Pollard rho, Pollard-এর p − 1 আর elliptic curve পদ্ধতি পরপর চেষ্টা করা হয়।

$ uv run python verify.py
odd composites below 2*10^6 that pass base 2: 73 [2047, 3277, 4033, 4681, 8321, 15841] ...
... that pass bases 2 and 3: [1373653, 1530787, 1987021]
search time 0.7 s
1373653 {829: 1, 1657: 1} passes [2, 3, 17, 19, 29, 31, 43, 47] first witness 5
25326001 {2251: 1, 11251: 1} passes 5 first witness 7
3215031751 {151: 1, 751: 1, 28351: 1} passes [2, 3, 5, 7, 19, 37, 47] first witness 11
318665857834031151167461 {399165290221: 1, 798330580441: 1} passes 37 first witness 41
3317044064679887385961981 {1287836182261: 1, 2575672364521: 1} passes 41 first witness 43

verify.py §৪-এর তালিকা যাচাই করে। প্রথম অংশ 2 · 106-এর নিচের প্রতিটি বিজোড় যৌগিক সংখ্যা দেখে: base 2-কে ৭৩টি ঠকায়, আর 2 ও 3 দুটোকেই মাত্র তিনটি, যার সবচেয়ে ছোটটি 1373653. তারপর তালিকার প্রতিটি সংখ্যার জন্য: sympy-র উৎপাদক, কোন মৌলিক base-এ (50-এর নিচে) পাস করে, আর প্রথম কোন base তাকে ধরে। একটি তালিকা ছাপা হলে তা সব পাস করা base; শুধু একটি সংখ্যা ছাপা হলে 2 থেকে সেই মৌলিক পর্যন্ত সব base-এ পাস। লক্ষ করুন, 3215031751 base 2, 3, 5, 7-এ পাস করে কিন্তু 11-এ ধরা পড়ে, আর শেষ সংখ্যাটি 2 থেকে 41 পর্যন্ত ১৩টি base-এ পাস করে, 43-এ ধরা পড়ে।

৭ · বাস্তবের আকার, রেকর্ড আর quantum প্রশ্ন

Pollard-এর rho ছোট উৎপাদক থাকলে দারুণ, কিন্তু দুটি সমান-আকারের বড় মৌলিকের গুণফলে √p নিজেই বিশাল: ৬০০ অঙ্কের n-এ p প্রায় ৩০০ অঙ্কের, √p প্রায় 10150. এমন সংখ্যার জন্য আরও উন্নত পদ্ধতি আছে: quadratic sieve, elliptic curve method, আর সবচেয়ে শক্তিশালী number field sieve. এদের সময় exponential-এর চেয়ে কম কিন্তু polynomial-এর চেয়ে বেশি (“sub-exponential”); আজ পর্যন্ত সাধারণ কম্পিউটারে polynomial-সময়ের কোনো factoring algorithm জানা নেই।

রেকর্ডগুলো এই ধীর অগ্রগতি দেখায়। RSA Laboratories-এর factoring challenge-এর সংখ্যা RSA-250 (২৫০ দশমিক অঙ্ক, ৮২৯ bit) ২০২০ সালের ফেব্রুয়ারিতে Fabrice Boudot, Pierrick Gaudry, Aurore Guillevic, Nadia Heninger, Emmanuel Thomé আর Paul Zimmermann-এর দল number field sieve দিয়ে ভাঙে; প্রকাশিত হিসাবে মোট কাজ ছিল কয়েক হাজার CPU core-বছরের সমান। তার আগে RSA-129 (১২৯ অঙ্ক) ১৯৯৪ সালে ইন্টারনেটে শত শত স্বেচ্ছাসেবকের কম্পিউটারে quadratic sieve দিয়ে ভাঙা হয়েছিল। ছোট অঙ্কের এই রেকর্ডগুলো থেকে কোনো নির্দিষ্ট key-আকার “এখন ভাঙা যায়” বলে ধরে নেবেন না; নিরাপদ key-আকারের সিদ্ধান্ত মানদণ্ড-সংস্থার সুপারিশ আর যাচাই-করা লাইব্রেরির ওপর ছেড়ে দিন (Cybersecurity কোর্সের পর্ব ১০).

সতর্কতা: “factoring কঠিন” একটি বিশ্বাস, প্রমাণ নয়। কেউ প্রমাণ করেননি যে polynomial-সময়ের algorithm থাকতে পারে না; factoring-কে NP-complete বলেও জানা যায় না (DSA কোর্সের পর্ব ৬৪-এ P বনাম NP). RSA-এর মতো ব্যবস্থার নিরাপত্তা এই বিশ্বাস আর কয়েক দশকের ব্যর্থ আক্রমণের অভিজ্ঞতার ওপর দাঁড়িয়ে। আর পাঠ্যবইয়ের ছোট সংখ্যার RSA শুধু বোঝার জন্য; বাস্তবে padding, বড় key আর যাচাই-করা লাইব্রেরি ছাড়া এটি নিরাপদ নয়।

Quantum কম্পিউটার গল্পটি বদলাতে পারে। Peter Shor ১৯৯৪ সালে দেখান, একটি যথেষ্ট বড় ও নির্ভুল quantum কম্পিউটারে Shor-এর algorithm polynomial সময়ে factoring করতে পারে। মূল ধারণা এই কোর্সেরই গণিত: একটি এলোমেলো a-এর order mod n (পর্ব ২৪) বের করা, আর order জোড় হলে aorder/2 প্রায়ই 1-এর একটি অদ্ভুত বর্গমূল, যার gcd থেকে উৎপাদক বেরোয়, ঠিক §২-এর মতো। Quantum অংশটি শুধু order দ্রুত খুঁজে দেয়। এখন পর্যন্ত প্রকাশিত পরীক্ষাগুলোতে quantum যন্ত্রে এই পদ্ধতিতে খুব ছোট সংখ্যাই (যেমন 15) ভাঙা গেছে বলে জানা যায়, তবে সতর্কতা হিসেবে নতুন “post-quantum” মানদণ্ড ইতিমধ্যে তৈরি হচ্ছে।

আরও গভীরে: Miller–Rabin-এর ছোট base-এর তালিকার একটি গভীর রূপ আছে: generalized Riemann hypothesis সত্য হলে, Eric Bach-এর ১৯৯০ সালের ফল অনুযায়ী 2(ln n)2-এর নিচের সব base পরীক্ষা করলেই deterministic উত্তর মেলে। Baillie–PSW পরীক্ষা (১৯৮০) একটি strong base-2 পরীক্ষার সঙ্গে একটি ভিন্ন ধরনের Lucas পরীক্ষা জোড়ে; কোনো counterexample জানা নেই, যদিও অসীম সংখ্যক থাকার কথা বলে অনুমান। আর মৌলিকতার “সার্টিফিকেট” (যেমন elliptic curve primality proving) একটি ছোট প্রমাণপত্র দেয়, যা অন্য যে কেউ দ্রুত যাচাই করতে পারে।

৮ · পরীক্ষার অঙ্ক আর একটি ভুল প্রমাণ

বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর লিখিত পরীক্ষায় এই বিষয়ের যে ধাঁচের অঙ্ক আসে, তার তিনটি পূর্ণ সমাধান। প্রতিটি সংখ্যা scratch-এ Python দিয়ে মেলানো।

অঙ্ক ১: Miller–Rabin দিয়ে base 2-এ 341 পরীক্ষা করুন

  1. 340 = 22 · 85, তাই s = 2, d = 85. দেখতে হবে 285 আর 2170 mod 341.
  2. 210 = 1024 = 3 · 341 + 1 ≡ 1, তাই 285 = (210)8 · 25 ≡ 32. এটি 1 বা 340 নয়।
  3. 322 = 1024 ≡ 1. অর্থাৎ 32 হলো 1-এর অদ্ভুত বর্গমূল, আর চেইনে −1 আসেনি। 341 যৌগিক; 2 একটি witness.
  4. উৎপাদক: gcd(31, 341) = 31 আর gcd(33, 341) = 11, তাই 341 = 11 · 31. (Fermat base 2-এ 341 পাস করত, কারণ 2340 ≡ 1.)

অঙ্ক ২: base 5-এ 97 পরীক্ষা করুন

  1. 96 = 25 · 3, তাই s = 5, d = 3. 53 = 125 ≡ 28 (mod 97).
  2. বর্গ করতে থাকুন: 282 = 784 ≡ 8, 82 = 64, 642 = 4096 ≡ 22, 222 = 484 ≡ 96 ≡ −1.
  3. r = 4-এ −1 এসেছে, তাই 97 base 5-এ strong probable prime. এটি একা প্রমাণ নয়; তবে 97 < 2047, আর §৪-এর তালিকা অনুযায়ী 2047-এর নিচে base 2-ই যথেষ্ট, তাই base 2 দিয়ে মিলিয়ে নিলে (96 = 25 · 3, 23 = 8, 64, 22, 96: আবার −1) 97 নিশ্চিতভাবে মৌলিক।

অঙ্ক ৩: ভুলের সম্ভাবনা 10−12-এর নিচে নামাতে কয়টি এলোমেলো base লাগবে?

  1. Monier–Rabin সীমায় k base-এ ভুলের সম্ভাবনা ≤ 4−k. চাই 4−k ≤ 10−12, অর্থাৎ k ≥ 12 · log 10 / log 4 ≈ 19.93.
  2. তাই k = 20 যথেষ্ট (4−20 ≈ 9.1 · 10−13). যদি কেউ Fermat-এর মতো 1/2 সীমা ভুল করে ধরেন, তাহলে 40টি লাগত বলে ভাববেন।

প্রমাণের ভুল ধরুন: “Miller–Rabin-এ পাস মানেই মৌলিক”

একজন লিখলেন: “দাবি: বিজোড় n আর কোনো base a-তে n যদি strong probable prime হয়, তবে n মৌলিক। প্রমাণ: চেইনটি ad, a2d, …, an−1. শর্ত অনুযায়ী 1-এর ঠিক আগে −1 এসেছে, অর্থাৎ চেইনে 1-এর কোনো অদ্ভুত বর্গমূল নেই। Lemma ২.১ বলে 1-এর বর্গমূল শুধু ±1, তাই সব শর্ত মেলে, আর n মৌলিক। ∎” পড়ে ভুলটি নিজে খুঁজুন।

ভুল কোথায়: Lemma ২.১-এর শর্তই মৌলিক modulus. প্রমাণটি যা প্রমাণ করতে চায় (n মৌলিক), সেটিকেই Lemma লাগানোর সময় ধরে নিয়েছে: এটি চক্রাকার যুক্তি। তার ওপর, “চেইনে অদ্ভুত বর্গমূল দেখা যায়নি” মানে “অদ্ভুত বর্গমূল নেই” নয়; যৌগিক n-এ এরা থাকে, শুধু এই a-এর চেইন তাদের পার করেনি। একটি counterexample-ই যথেষ্ট: 2047 = 23 · 89, আর 2046 = 2 · 1023, 21023 ≡ 1 (mod 2047), তাই 2047 base 2-এ strong probable prime অথচ যৌগিক। সঠিক বক্তব্য এক দিকেই: strong test-এ ব্যর্থ হলে n যৌগিক।

পরীক্ষা ও ইন্টারভিউতে: বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এই ধরনের প্রশ্ন প্রায়ই আসে:

  • n − 1 = 2s · d লিখুন, n = 1105. 1104 = 24 · 69.
  • Fermat-এর পরীক্ষার তুলনায় Miller–Rabin কেন ভালো? Carmichael সংখ্যাসহ প্রতিটি বিজোড় যৌগিক n > 9-এর অন্তত তিন-চতুর্থাংশ base witness.
  • k রাউন্ডে ভুলের সম্ভাবনা? যৌগিক n-এর জন্য ≤ 4−k.
  • Trial division-এর সময় কেন exponential? √n = 2(bit সংখ্যা)/2.
  • Pollard rho-এর প্রত্যাশিত ধাপ? প্রায় √p, যেখানে p সবচেয়ে ছোট মৌলিক উৎপাদক (heuristic).

৯ · AI-এর যুগে — মৌলিকতা আর factoring-এর দাবি যাচাই

“এই সংখ্যাটি কি মৌলিক?” প্রশ্নে AI সহকারী প্রায়ই আত্মবিশ্বাসী উত্তর দেয়, কিন্তু বড় সংখ্যায় মাথার হিসাবে আর পরীক্ষার শর্তে নিয়মিত ভুল করে। কয়েকটি ধরন, আর কীভাবে ধরবেন:

AI-এর ভুলকীভাবে ধরবেন
বড় সংখ্যাকে “মৌলিক” বা ভুল উৎপাদক বলা (যেমন 267 − 1-কে মৌলিক বলা)উৎপাদকগুলো গুণ করে মূল সংখ্যা ফেরে কি না দেখুন; pow(2, n - 1, n) আর strong test নিজে চালান
Fermat আর Miller–Rabin গুলিয়ে ফেলা, বা ভুলের সীমা 1/2 বলা561-এ দুটি পরীক্ষা চালিয়ে পার্থক্য দেখুন; সীমার বিবৃতি আর শর্ত (n > 9, বিজোড়) জিজ্ঞেস করুন
“পাস করেছে, তাই প্রমাণিত মৌলিক” বলাকোন base, কয়টি, আর n কোন deterministic সীমার নিচে, তা জানতে চান; 2047, 1373653-এর মতো counterexample দিয়ে পরীক্ষা করুন
Off-by-one: চেইনে r = s পর্যন্ত −1 খোঁজা, বা d জোড় রেখে দেওয়াকোড ছোট সব n-এ trial division-এর সঙ্গে মেলান (ব্লক ৩-এর মতো)
Factoring-এর রেকর্ড, key-আকার বা quantum অগ্রগতি নিয়ে বানানো দাবিপ্রকাশিত উৎসে সাল আর দল মিলিয়ে নিন; নিশ্চিত না হলে দাবিটি বাদ দিন

AI-এর কাছে মৌলিকতা বা factoring নিয়ে সাহায্য চাইলে এমন কাঠামো দিন, যাতে প্রতিটি ধাপ আলাদা করে যাচাই করা যায়:

নিচের সংখ্যাটি নিয়ে ধাপে ধাপে কাজ করো: সংখ্যা: [যেমন 1105 বা 3215031751] ১. n − 1 = 2^s · d আকারে লেখো, s আর d আলাদা করে দাও (d বিজোড় কি না দেখাও)। ২. প্রতিটি base a-এর জন্য পুরো চেইন a^d, a^(2d), … mod n আলাদা লাইনে দাও। ৩. কোন ধাপে সিদ্ধান্ত নিলে আর কোন উপপাদ্য বা lemma-র কোন শর্তে, তা লেখো। ৪. "মৌলিক" বললে বলো এটি probable prime নাকি প্রমাণিত, আর প্রমাণিত হলে কোন deterministic সীমা ব্যবহার করলে। ৫. যৌগিক হলে কোনো উৎপাদক পেলে গুণ করে মূল সংখ্যা ফেরত দেখাও। ৬. শেষে যাচাইয়ের একটি ছোট Python কোড দাও (শুধু standard library, pow(a, d, n) আর math.gcd দিয়ে)।

AI-এর উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট

এই বিষয়ে যাচাই প্রায় বিনা খরচে হয়: একটি উৎপাদক গুণ করা বা একটি pow চালানো এক সেকেন্ডের কাজ। খোঁজা কঠিন, যাচাই সহজ, factoring-এর এই অসমতাই AI-এর উত্তর পরীক্ষা করার সবচেয়ে বড় সুবিধা।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১মৌলিক কি না বলা সহজ, অথচ উৎপাদক বের করা কঠিন, এটা কি অদ্ভুত নয়? দুটি প্রশ্ন তো একই সংখ্যা নিয়ে।

প্রথম দেখায় অদ্ভুত লাগে, কারণ স্কুলে আমরা মৌলিকতা যাচাই করি উৎপাদক খুঁজেই। কিন্তু Fermat আর Miller–Rabin অন্য পথে চলে: তারা দেখে সংখ্যাটি মৌলিক সংখ্যার একটি ধর্ম মানে কি না। ধর্মটি ভাঙলে সংখ্যাটি যৌগিক, অথচ কোন জায়গায় ভাঙল তা থেকে সাধারণত উৎপাদক বেরোয় না। 2047 base 3-এ ধরা পড়ে, কিন্তু চেইনের মান 1565 আর 1013 থেকে 23 বা 89 কোনোটিই সরাসরি আসে না। তুলনা করুন বাজারের ওজন যাচাইয়ের সঙ্গে: দাঁড়িপাল্লায় চালের বস্তা কম হলে আপনি নিশ্চিত যে কিছু চাল সরানো হয়েছে, কিন্তু কে সরিয়েছে, কোথা থেকে, তা জানেন না।

এই অসমতা দীর্ঘ দিনের গণিত-ইতিহাসেরও অংশ। Frank Nelson Cole ১৯০৩ সালে আমেরিকান গণিত সমাজের একটি সভায় প্রায় নিঃশব্দে বোর্ডে 267 − 1 আর 193707721 × 761838257287 হিসাব করে দেখান যে দুটি সমান, এমন গল্প প্রচলিত; সংখ্যাটি যে যৌগিক, তা Édouard Lucas-এর একটি পরীক্ষা থেকে আগেই জানা ছিল, কিন্তু উৎপাদক বের করতে Cole-এর নাকি বহু বছরের রবিবার লেগেছিল। এই পর্বের ব্লক ২ সেই সংখ্যাকেই মুহূর্তে যৌগিক বলে, কিন্তু উৎপাদক বলে না।

কম্পিউটার বিজ্ঞানের ভাষায়, primality এখন জানা মতে P-তে (AKS), আর factoring-এর জন্য কোনো polynomial algorithm জানা নেই। তবু কেউ প্রমাণ করেননি যে factoring কঠিন। পরের মডিউলের RSA (পর্ব ২৮) ঠিক এই ফাঁকের ওপর দাঁড়িয়ে: চাবি বানাতে মৌলিক খোঁজা সহজ হতে হবে, আর ভাঙতে factoring কঠিন।

মূল উপলব্ধি: কোনো ধর্ম ভাঙা দেখানো আর ভাঙার কারণ খুঁজে বের করা আলাদা কাজ; প্রথমটি দ্রুত হতে পারে যখন দ্বিতীয়টি কঠিন।

প্র ০২AKS তিনজন ভারতীয় গবেষকের কাজ, যাঁদের দুজন তখন স্নাতক পর্যায়ের ছাত্র। তত্ত্বে এত বড় একটি ফল বাস্তবের সফটওয়্যারে প্রায় ব্যবহৃত হয় না কেন?

২০০২ সালের আগস্টে Manindra Agrawal, Neeraj Kayal আর Nitin Saxena তাঁদের প্রবন্ধ “PRIMES is in P” ইন্টারনেটে প্রকাশ করলে গণিত আর কম্পিউটার বিজ্ঞানের জগতে সাড়া পড়ে যায়। বহু দশকের প্রশ্ন ছিল: কোনো অনুমান বা এলোমেলোতা ছাড়া, সব সংখ্যার জন্য polynomial সময়ে মৌলিকতা নির্ধারণ করা যায় কি? Miller-এর পরীক্ষা এটি করত, কিন্তু অপ্রমাণিত Riemann-অনুমানের ওপর ভর করে; Rabin-এর পরীক্ষা করত, কিন্তু এলোমেলোতার ওপর। AKS দুটো শর্তই সরিয়ে দেয়, আর প্রমাণটি তুলনামূলক প্রাথমিক বীজগণিতে, যা বিশেষজ্ঞদের আরও অবাক করে। কাজটি ২০০৪ সালে Annals of Mathematics-এ প্রকাশিত হয়, আর ২০০৬ সালে Gödel Prize-সহ একাধিক বড় পুরস্কার পায় বলে উল্লেখিত।

তবু বাস্তবে এটি কম চলে, তার কারণ ধ্রুবক আর ঘাত। মূল সংস্করণের সময় (log n)-এর প্রায় দ্বাদশ ঘাত, উন্নত রূপেও প্রায় ষষ্ঠ ঘাত; Miller–Rabin-এর একটি রাউন্ড প্রায় (log n)3 (সাধারণ গুণে)। ১,০০০ bit-এর সংখ্যায় এই পার্থক্য বিশাল। আর Miller–Rabin-এর ভুলের সম্ভাবনা ইচ্ছামতো ছোট করা যায়: 4−40 একটি সংখ্যা যা যন্ত্রাংশের এলোমেলো ত্রুটির সম্ভাবনার চেয়েও অনেক ছোট বলে ধরা হয়। যেখানে সত্যিকারের প্রমাণ লাগে, সেখানে মানুষ ECPP-এর মতো সার্টিফিকেট-ভিত্তিক পদ্ধতি নেন, যা বাস্তবে AKS-এর চেয়ে দ্রুত।

তাহলে AKS-এর মূল্য কোথায়? এটি একটি মৌলিক প্রশ্নের চূড়ান্ত উত্তর দিয়েছে, আর দেখিয়েছে যে মৌলিকতা “সহজ” সমস্যার শ্রেণিতে। জটিলতা-তত্ত্বে এমন ফল বাস্তবের algorithm-এর চেয়ে আলাদা কাজ করে: সীমা টানে, কী সম্ভব তা বলে।

মূল উপলব্ধি: “polynomial” মানে তত্ত্বে দক্ষ, কিন্তু বাস্তবে ঘাত আর ধ্রুবকই ঠিক করে কোন algorithm চলবে।

প্র ০৩যদি কেউ ইচ্ছা করে এমন যৌগিক সংখ্যা বানায় যা কয়েকটি নির্দিষ্ট base-কে ঠকায়, তাহলে Miller–Rabin কি বিপদে পড়ে?

হ্যাঁ, যদি base এলোমেলো না হয়ে নির্দিষ্ট হয় আর সংখ্যাটি deterministic সীমার বাইরে হয়। Monier–Rabin-এর সীমা বলে প্রতিটি যৌগিক n-এর জন্য বেশিরভাগ base witness; কিন্তু “বেশিরভাগ” মানে “এই নির্দিষ্ট ১০টি” নয়। গণিতবিদরা দেখিয়েছেন, CRT আর Korselt-এর ধাঁচের শর্ত মিলিয়ে এমন বড় যৌগিক সংখ্যা বানানো যায় যা আগে থেকে জানা কয়েকটি base-এ strong pseudoprime. François Arnault ১৯৯০-এর দশকে এমন একটি নির্মাণ দেখান বলে উল্লেখিত, যা সেই সময়ের একটি জনপ্রিয় গণিত সফটওয়্যারের পরীক্ষাকে ঠকায়।

২০১৮ সালে “Prime and Prejudice” নামের একটি গবেষণা আরও ব্যবহারিক প্রশ্ন তোলে: কয়েকটি প্রচলিত cryptography লাইব্রেরি নির্দিষ্ট বা অনুমানযোগ্য base, বা খুব কম রাউন্ড ব্যবহার করত। আক্রমণকারী যদি সংখ্যাটি নিজে বেছে দিতে পারে (যেমন একটি key-বিনিময়ের প্যারামিটার), তবে সে এমন যৌগিক সংখ্যা পাঠাতে পারে যা পরীক্ষায় “মৌলিক” বলে পাস করে। লাইব্রেরিগুলো পরে base এলোমেলো করা বা রাউন্ড বাড়ানোর মতো সংশোধন করে বলে জানা যায়।

শিক্ষাটি algorithm বিশ্লেষণের একটি মৌলিক পার্থক্য: গড় ইনপুট বনাম প্রতিপক্ষের বাছা ইনপুট। 4−k সীমা প্রতিপক্ষের বাছা n-এও খাটে, কারণ এলোমেলোতা আসে base বাছাই থেকে, n থেকে নয়; তবে শর্ত হলো base সত্যিই এলোমেলো আর প্রতিপক্ষের কাছে অনুমানযোগ্য নয়। বাজারঘরের hash table-এর আকার বাছার মতো কাজে নিজের বানানো সংখ্যায় নির্দিষ্ট base নিরাপদ; বাইরের কারও দেওয়া সংখ্যায় এলোমেলো base আর যথেষ্ট রাউন্ড, বা BPSW-এর মতো সমন্বিত পরীক্ষা নিন।

মূল উপলব্ধি: randomized algorithm-এর নিশ্চয়তা আসে তার নিজের এলোমেলোতা থেকে; সেই এলোমেলোতা অনুমানযোগ্য হলে নিশ্চয়তাও হারায়।

প্র ০৪Pollard-এর rho √p ধাপে কাজ করে বলে আমরা বলি, অথচ সেটি প্রমাণিত নয়। প্রমাণ ছাড়া একটি algorithm-এর সময় নিয়ে কথা বলা কতটা ঠিক?

এটি সৎ প্রশ্ন, আর উত্তরটি দুই স্তরের। যা প্রমাণিত: mod p-এর ক্রম সসীম সেটে চলে, তাই pigeonhole নীতিতে বড়জোর p ধাপে চক্রে ঢোকে, আর Floyd-এর lemma বলে μ + λ ধাপের মধ্যে কচ্ছপ-খরগোশ মিলবেই। অর্থাৎ সবচেয়ে খারাপ ক্ষেত্রেও p ধাপের বেশি লাগে না, যা trial division-এর সমান। যা প্রমাণিত নয়: x2 + c একটি “এলোমেলো” ফাংশনের মতো আচরণ করে, তাই birthday-যুক্তিতে প্রায় √p ধাপে মিল হয়। এটি একটি heuristic, অর্থাৎ যুক্তিসংগত অনুমান যা প্রমাণ নয়।

তাহলে কেন আমরা এর ওপর ভরসা করি? কারণ অভিজ্ঞতা। ব্লক ৪-এ ৪০টি semiprime-এ গড় ধাপ √p-এর খুব কাছে এসেছে, আর §৬-এর ২৪ অঙ্কের পরীক্ষাতেও। Richard Brent ১৯৮০ সালে rho-এর একটি দ্রুততর রূপ দেন, আর তিনি ও Pollard সেই রূপ দিয়ে অষ্টম Fermat সংখ্যা F8 = 2256 + 1-এর একটি ১৬ অঙ্কের উৎপাদক খুঁজে পান বলে উল্লেখিত। এমন সাফল্য heuristic-কে বিশ্বাসযোগ্য করে।

তবে পার্থক্যটি মনে রাখা জরুরি, বিশেষ করে যখন নিরাপত্তা জড়িত। প্রমাণিত সীমা নিশ্চয়তা দেয়; heuristic শুধু প্রত্যাশা দেয়, আর বিশেষ গঠনের ইনপুটে ভেঙে যেতে পারে। ব্লক ৪-এর শেষ লাইনে 25 = 5 · 5-এ c = 1 নিয়ে rho ব্যর্থ হয়, কারণ mod 5 আর mod 25-এর চক্র একই সঙ্গে মেলে; c বদলালে কাজ করে। গণিতে “প্রত্যাশিত সময়” বললে বলতে হয়, প্রত্যাশা কিসের ওপর: ইনপুটের এলোমেলোতা, algorithm-এর নিজের এলোমেলোতা, নাকি একটি অপ্রমাণিত মডেল।

মূল উপলব্ধি: প্রমাণিত সীমা, প্রত্যাশিত সময় আর heuristic অনুমান তিনটি আলাদা দাবি; প্রতিটি ব্যবহারের সময় কোনটি বলছেন তা স্পষ্ট রাখুন।

প্র ০৫Shor-এর algorithm যদি factoring সহজ করে দেয়, তাহলে মৌলিক সংখ্যা-ভিত্তিক cryptography-র কী হবে, আর গণিতের এই পর্বটি কি তখন অপ্রয়োজনীয়?

Peter Shor ১৯৯৪ সালে দেখান, quantum কম্পিউটারে factoring আর discrete logarithm দুটোই polynomial সময়ে করা যায়। এর হৃদয়ে আছে এই কোর্সের গণিত: একটি এলোমেলো a বেছে mod n-এ তার order r বের করা (পর্ব ২৪); r জোড় আর ar/2 ≢ −1 হলে ar/2 হলো 1-এর একটি অদ্ভুত বর্গমূল, আর gcd(ar/2 − 1, n) একটি উৎপাদক। ঠিক §২-এর কৌশল। Quantum অংশটি শুধু order বের করার কাজটি দ্রুত করে, quantum Fourier transform-এর সাহায্যে।

বাস্তবের অবস্থা সাবধানে বলা দরকার। প্রকাশিত পরীক্ষায় Shor-এর পদ্ধতিতে খুব ছোট সংখ্যা ভাঙা গেছে, যেমন ২০০১ সালে IBM-এর একটি দল NMR-ভিত্তিক যন্ত্রে 15 ভাঙে বলে প্রতিবেদন আছে। বড় RSA সংখ্যা ভাঙতে যে পরিমাণ নির্ভুল, ত্রুটি-সংশোধিত qubit লাগবে, তা এখনকার যন্ত্রের সামর্থ্যের অনেক বাইরে বলে সাধারণভাবে মনে করা হয়; কবে সম্ভব হবে, তার নির্ভরযোগ্য সময়রেখা কেউ দিতে পারেন না। তবে আজ রেকর্ড করা গোপন তথ্য ভবিষ্যতে খোলা যেতে পারে, এই আশঙ্কায় NIST ২০২৪ সালে প্রথম post-quantum মানদণ্ডগুলো প্রকাশ করে, যেগুলো factoring-এর বদলে lattice-এর মতো অন্য কঠিন সমস্যার ওপর দাঁড়ানো।

তাহলে এই পর্ব কি অপ্রয়োজনীয় হয়ে যাবে? না। মৌলিক সংখ্যা খোঁজা লাগবে hashing, pseudorandom সংখ্যা, error-correcting code আর বহু algorithm-এ; Miller–Rabin কোথাও যাচ্ছে না। আর Shor-এর algorithm বুঝতেই order, CRT আর অদ্ভুত বর্গমূলের গণিত লাগে। নতুন যন্ত্র পুরোনো গণিতকে বাতিল করে না, নতুন প্রশ্ন যোগ করে।

মূল উপলব্ধি: নিরাপত্তা কোনো সমস্যার “কঠিনতা” আর সেই সময়ের যন্ত্রের ওপর নির্ভর করে; গণিত টিকে থাকে, কোন সমস্যাকে কঠিন ধরা হবে তা বদলায়।

অনুশীলন

আগে খাতায় করুন, তারপর উত্তর খুলে মেলান।

  1. প্রমাণ: p আর q দুটি ভিন্ন বিজোড় মৌলিক, n = pq. প্রমাণ করুন, এমন x আছে যাতে x2 ≡ 1 (mod n) কিন্তু x ≢ ±1 (mod n). n = 15-এ এমন x বের করুন।
    1. gcd(p, q) = 1, তাই Chinese Remainder Theorem (পর্ব ২৩) অনুযায়ী এমন x আছে যাতে x ≡ 1 (mod p) আর x ≡ −1 (mod q). — CRT
    2. তাহলে x2 ≡ 1 (mod p) আর x2 ≡ 1 (mod q), তাই p ∣ x2 − 1 আর q ∣ x2 − 1; সহমৌলিক বলে pq ∣ x2 − 1. — সহমৌলিক ভাজকের গুণফলও ভাজক
    3. x ≡ 1 (mod n) হলে x ≡ 1 (mod q) হতো; তখন 1 ≡ −1 (mod q), অর্থাৎ q ∣ 2, অসম্ভব কারণ q বিজোড়। — contradiction
    4. x ≡ −1 (mod n) হলে x ≡ −1 (mod p), আবার p ∣ 2, অসম্ভব। তাই x ≢ ±1. ∎

    n = 15: x ≡ 1 (mod 3), x ≡ −1 ≡ 4 (mod 5) থেকে x = 4; উল্টো ভূমিকায় x = 11. যাচাই: 42 = 16 ≡ 1 আর 112 = 121 = 8 · 15 + 1. এই কারণেই দুটি ভিন্ন বিজোড় মৌলিক উৎপাদকের যেকোনো n-এ Lemma ২.১ ভাঙে, আর Miller–Rabin সেই ফাঁক খোঁজে।

  2. হিসাব: (ক) n = 1105 = 5 · 13 · 17-এ base 2 দিয়ে Miller–Rabin চালান: s, d, পুরো চেইন, সিদ্ধান্ত, আর অদ্ভুত বর্গমূল থেকে gcd. (খ) 8051-এ Pollard rho-এর মতো 10403-এ f(x) = x2 + 1, x0 = 2 নিয়ে কোন ধাপে উৎপাদক মেলে?

    (ক) 1104 = 24 · 69, তাই s = 4, d = 69. চেইন: 269 ≡ 967, 9672 ≡ 259, 2592 ≡ 781, 7812 ≡ 1 (mod 1105). প্রথম পদ 1 নয়, আর প্রথম চারটি পদে 1104 (−1) নেই, তাই 1105 যৌগিক। 781 হলো 1-এর অদ্ভুত বর্গমূল: gcd(780, 1105) = 65 = 5 · 13 আর gcd(782, 1105) = 17. Fermat base 2-এ 1105 পাস করত (একটি Carmichael সংখ্যা)।

    (খ) ধাপে ধাপে (x, y, gcd): i = 1-এ (5, 26, 1), i = 2-এ (26, 598, 1), i = 3-এ (677, 3418, 1), …, i = 8-এ (3531, 3682, 1), আর i = 9-এ x = 5168, y = 7087, gcd(1919, 10403) = 101. তাই 10403 = 101 · 103, নয় ধাপে। সব মান scratch-এ Python দিয়ে যাচাই করা; ব্লক ৪-এর আউটপুটেও “steps 9” দেখা যায়।

  3. আউটপুট অনুমান: কোড না চালিয়ে বলুন কী ছাপা হবে। তারপর যেকোনো Python-এ চালিয়ে মেলান।
    from math import gcd
    n = 561
    print((n - 1) // 2**4, pow(2, 35, n), pow(2, 70, n))
    print(pow(67, 2, n), gcd(67 - 1, n), gcd(67 + 1, n))
    print(pow(2, n - 1, n) == 1, pow(2, 140, n))
    35 263 166
    1 33 17
    True 67

    প্রথম লাইন: 560 = 24 · 35, তারপর চেইনের প্রথম দুই পদ 235 ≡ 263 আর 270 ≡ 166. দ্বিতীয় লাইন: 672 ≡ 1, আর 67 ± 1-এর gcd থেকে 33 আর 17. তৃতীয় লাইন: Fermat base 2-এ 561 পাস করে (True), আর 2140 চেইনের তৃতীয় পদ, অর্থাৎ সেই অদ্ভুত বর্গমূল 67.

  4. ভুল ধরুন: একজন লিখলেন: “Pollard rho যদি d = n ফেরত দেয়, অর্থাৎ কোনো প্রকৃত উৎপাদক না পায়, তবে n মৌলিক। কারণ n যৌগিক হলে কোনো মৌলিক p ∣ n আছে, আর mod p-এর চক্রে কচ্ছপ-খরগোশ মিলবেই, তখন gcd-তে p আসবে।” ভুল কোথায়, আর সঠিক নিয়ম কী?
    • ভুল: mod p-এ মিল হলে p ∣ (x − y), ঠিক। কিন্তু একই ধাপে mod n-এর সব মৌলিক উৎপাদকেও মিল হতে পারে; তখন n ∣ (x − y), আর gcd = n, প্রকৃত উৎপাদক নয়। “p ভাগ করে” থেকে “gcd = p” আসে না।
    • Counterexample: 25 = 5 · 5, c = 1, x0 = 2-এ rho তিন ধাপে d = 25 দেয় (ব্লক ৪-এর শেষ লাইন), অথচ 25 যৌগিক। c = 2 নিলে দুই ধাপে 5 পাওয়া যায়।
    • সঠিক নিয়ম: আগে Miller–Rabin দিয়ে দেখুন n মৌলিক কি না; যৌগিক হলে rho চালান, আর d = n হলে অন্য c (বা অন্য x0) নিয়ে আবার চেষ্টা করুন। rho একটি factoring পদ্ধতি, primality test নয়।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমবিজোড় n > 3-এ Miller–Rabin পরীক্ষার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. n − 1-কে 2 দিয়ে যতবার পারা যায় ভাগ করে n − 1 = 2s · d লেখা
  2. 2 থেকে n − 2-এর মধ্যে এলোমেলোভাবে একটি base a বাছা
  3. x = ad mod n বের করা; 1 বা n − 1 হলে এই রাউন্ডে পাস
  4. বড়জোর s − 1 বার x বর্গ করে n − 1 খোঁজা; না পেলে n যৌগিক
  5. k-টি রাউন্ডে পাস করলে n-কে probable prime বলা

n = 97-এর জন্য n − 1 = 2s · d (d বিজোড়) লিখলে s আর d কত?

  • s = 4, d = 6
  • s = 5, d = 3
  • s = 3, d = 12
  • s = 6, d = 1

561-এ base 2 দিয়ে Miller–Rabin-এর চেইন 263, 166, 67, 1 (mod 561). কোন পর্যবেক্ষণ থেকে 561 যৌগিক প্রমাণ হয়?

  • শেষ পদ 1, তাই 2560 ≡ 1
  • প্রথম পদ 263, 1 নয়
  • 672 ≡ 1 কিন্তু 67 ≢ ±1 (mod 561)
  • চেইনের একটি পদ 166 জোড়

একটি বিজোড় যৌগিক n > 9-এ স্বাধীনভাবে বাছা k-টি এলোমেলো base-এ Miller–Rabin চালালে n “probable prime” বলে পার পাওয়ার সম্ভাবনার প্রমাণিত সীমা কোনটি?

  • ≤ 2−k
  • ≤ 4−k
  • ≤ 1/k
  • ঠিক 0

Pollard-এর rho algorithm-এ n-এর সবচেয়ে ছোট মৌলিক উৎপাদক p হলে প্রত্যাশিত ধাপের সংখ্যা (heuristic) প্রায় কত?

  • p
  • √n
  • log p
  • √p

মৌলিকতা আর factoring সম্পর্কে কোন বক্তব্যটি সঠিক?

  • মৌলিকতা deterministic polynomial সময়ে নির্ধারণযোগ্য; factoring-এর এমন কোনো algorithm জানা নেই
  • Factoring NP-complete বলে প্রমাণিত
  • Miller–Rabin সবসময় একটি উৎপাদকও দেয়
  • Trial division অঙ্কের সংখ্যায় polynomial সময় নেয়

x2 ≡ 1 (mod 15)-এর সমাধান 0 ≤ x ≤ 14-এ কোনগুলো?

  • শুধু 1 আর 14
  • শুধু 1
  • 1, 4, 11, 14
  • 1, 2, 7, 14

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. দুই প্রশ্ন: primality (হ্যাঁ/না) দ্রুত; factoring কঠিন বলে বিশ্বাস। Trial division √n ভাগ নেয়, যা অঙ্কের সংখ্যায় exponential.
  2. 1-এর বর্গমূল: মৌলিক p-এ x2 ≡ 1 ⇔ x ≡ ±1. যৌগিক n-এ অদ্ভুত বর্গমূল x থাকলে gcd(x − 1, n) একটি প্রকৃত উৎপাদক।
  3. Miller–Rabin: n − 1 = 2s · d; ad ≡ 1, বা চেইনে কোথাও −1, না হলে n যৌগিক। “যৌগিক” সবসময় সঠিক; যৌগিক n > 9-এ k রাউন্ডে ভুল ≤ 4−k.
  4. Deterministic: n < 3,215,031,751-এ base 2, 3, 5, 7 যথেষ্ট; প্রথম ১২টি মৌলিক base পুরো 64-bit পরিসর ঢাকে। AKS (২০০২) সব n-এ polynomial, কিন্তু বাস্তবে ধীর।
  5. Pollard rho: x ↦ x2 + c, কচ্ছপ-খরগোশ আর gcd(|x − y|, n); প্রায় √p ধাপ (heuristic). d = n হলে c বদলান; rho primality test নয়।

পরের পর্বে: পর্ব ২৬ “সংখ্যাতত্ত্বের প্রয়োগ — check digit, hashing আর pseudorandom সংখ্যা”: ISBN আর Luhn-এর check digit কোন ভুল ধরে আর কেন, hash table-এ মৌলিক আকার বাছার গণিত, আর linear congruential generator দিয়ে pseudorandom সংখ্যা তৈরি।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান