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