97 lines
1.7 KiB
Python
97 lines
1.7 KiB
Python
import random
|
|
|
|
|
|
def miller_rabin(n, k=5):
|
|
if n == 2 or n == 3:
|
|
return True
|
|
if n <= 1 or n % 2 == 0:
|
|
return False
|
|
|
|
# Write n-1 as d * 2^r
|
|
r = 0
|
|
d = n - 1
|
|
while d % 2 == 0:
|
|
d //= 2
|
|
r += 1
|
|
|
|
# Perform the test k times
|
|
for _ in range(k):
|
|
a = random.randint(2, n - 2)
|
|
x = pow(a, d, n) # x = a^d % n
|
|
if x == 1 or x == n - 1:
|
|
continue
|
|
|
|
# Keep squaring x and check for n-1
|
|
for _ in range(r - 1):
|
|
x = pow(x, 2, n)
|
|
if x == n - 1:
|
|
break
|
|
else:
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
assert miller_rabin(0) == False
|
|
assert miller_rabin(1) == False
|
|
assert miller_rabin(2) == True
|
|
assert miller_rabin(3) == True
|
|
assert miller_rabin(4) == False
|
|
|
|
|
|
def primitive_isprime(num):
|
|
for n in range(2, int(num**0.5) + 1):
|
|
if num % n == 0:
|
|
return False
|
|
return True
|
|
|
|
|
|
assert not miller_rabin(8)
|
|
assert miller_rabin(11)
|
|
|
|
|
|
def mod_inverse(a, m):
|
|
return pow(a, -1, m)
|
|
|
|
|
|
assert mod_inverse(3, 7) == 5
|
|
assert mod_inverse(10, 17) == 12
|
|
assert mod_inverse(7, 13) == 2
|
|
assert mod_inverse(65537, 3445361432) is not None
|
|
|
|
|
|
def gcd(x, y):
|
|
while y:
|
|
x, y = y, x % y
|
|
return abs(x)
|
|
|
|
|
|
assert gcd(3, 9) == 3
|
|
assert gcd(3, 4) == 1
|
|
|
|
p = 60737
|
|
q = 56713
|
|
assert miller_rabin(p)
|
|
assert miller_rabin(q)
|
|
|
|
n = p * q
|
|
phi_n = (p - 1) * (q - 1)
|
|
assert not miller_rabin(n)
|
|
assert not miller_rabin(phi_n)
|
|
|
|
e = 65537
|
|
assert e == (1 << 16) | 0x1
|
|
assert gcd(e, phi_n) == 1
|
|
|
|
d = mod_inverse(e, phi_n)
|
|
assert d is not None and (e * d) % phi_n == 1
|
|
|
|
m = 69
|
|
|
|
c = pow(69, e, n)
|
|
dec = pow(c, d, n)
|
|
|
|
print("Ciphertext: ", c)
|
|
print("Decrypted: ", dec)
|
|
|
|
assert dec == m
|