图35-6:交互式素性测试实验室比较费马测试与 Miller–Rabin 测试对同一个数的判断,并逐步查看计算过程。
费马测试结果
通过
2^(560) mod 561 = 1Miller–Rabin 结果
确定为合数
当前底数已经找到证据指数分解561−1=24×35 逐步查看模平方过程已展示 1/4 步
本次实验的数学解释发现非平凡平方根:67² mod 561 = 1,但 67 并非 ±1(模 561)。因此可严格断言 561 是合数。
教学验证:561 实际是合数,可被 3 整除。该信息通过独立的试除法核实,不作为 Miller–Rabin 判断的输入。python
def miller_rabin_round(n: int, a: int) -> bool:
"""
返回 True:通过这一轮测试,不代表已经证明是素数。
返回 False:确定是合数。
要求 n 为大于3的奇数,且 2 <= a <= n-2。
"""
if n <= 3 or n % 2 == 0:
raise ValueError("n 必须是大于3的奇数")
if not 2 <= a <= n - 2:
raise ValueError("底数超出允许范围")
d = n - 1
s = 0
while d % 2 == 0:
d //= 2
s += 1
x = pow(a, d, n)
if x == 1 or x == n - 1:
return True
for _ in range(s - 1):
x = pow(x, 2, n)
if x == n - 1:
return True
return False
print(miller_rabin_round(561, 2))
print(miller_rabin_round(561, 50))
print(miller_rabin_round(2047, 2))
print(miller_rabin_round(2047, 3))
print(miller_rabin_round(97, 2))
python
import secrets
def is_probable_prime(n: int, rounds: int = 20) -> bool:
"""
False:确定是合数(或小于2)。
True:通过测试;对于一般大整数,属于概率性结论。
"""
if rounds < 1:
raise ValueError("测试轮数必须至少为1")
if n < 2:
return False
small_primes = [
2, 3, 5, 7, 11, 13,
17, 19, 23, 29, 31, 37
]
if n in small_primes:
return True
for p in small_primes:
if n % p == 0:
return False
d = n - 1
s = 0
while d % 2 == 0:
d //= 2
s += 1
for _ in range(rounds):
a = secrets.randbelow(n - 3) + 2
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(s - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
numbers = [
17,
97,
341,
561,
2047,
1000000007,
1000000009
]
for n in numbers:
result = is_probable_prime(n, 20)
print(
n,
"通过测试" if result else "确定是合数"
)