RSA算法的基础就是对于两个大质数的乘积进行质因数分解是非常慢的。比如对于一个300位的十进制数字进行质因数分解,普通电脑需要上百万年时间。但是如果这两个大质数比较接近,那使用费马质数分解就不需要几百万年了。
对于一个奇合数
n
=
p
⋅
q
n=p\cdot q
n=p⋅q,可以写成一个平方差:
n
=
p
⋅
q
=
(
p
+
q
2
)
2
−
(
p
−
q
2
)
2
n=p\cdot q=(\frac{p+q}{2})^2-(\frac{p-q}{2})^2
n=p⋅q=(2p+q)2−(2p−q)2
费马质因数分解算法,就是不停地循环尝试,找到两个数:
a
=
p
+
q
2
b
=
p
−
q
2
a=\frac{p+q}{2}\\ b=\frac{p-q}{2}
a=2p+qb=2p−q
找到这两个数之后
a
+
b
a+b
a+b和
a
−
b
a-b
a−b就是p和q了。我们知道
n
=
a
2
−
b
2
=
(
a
+
b
)
(
a
−
b
)
n=a^2-b^2=(a+b)(a-b)
n=a2−b2=(a+b)(a−b)。我们让a从
⌈
n
⌉
\lceil\sqrt{n}\rceil
⌈n⌉开始尝试,不断+1,直到
a
2
−
n
a^2-n
a2−n是一个平方数为止。
需要注意的是这对于奇合数才有用,因为偶数的话,分解出来的两个数如果是一奇一偶,则相加除于2不是一个整数。单次分解的复杂度是
O
(
∣
p
−
q
∣
)
O(|{p-q}|)
O(∣p−q∣),在实际应用中费马质数分解的效率其实不高,因为实际上两个质因数相近(
∣
p
−
q
∣
|{p-q}|
∣p−q∣比较小)的情况是比较少见的。
Python代码如下:
# _*_ coding:utf-8 _*_
import math
def fermat(n):
a = math.ceil(math.sqrt(n))
# b的平方
b2 = a * a - n
b = round(math.sqrt(b2))
while b * b != b2:
a += 1
b2 = a * a - n
b = round(math.sqrt(b2))
print(a, b, n)
return a - b, a + b
def factorization(n):
factors = []
stack = [n]
while len(stack) > 0:
x = stack.pop()
if x == 2:
factors.insert(0, x)
continue
p, q = fermat(x) if x & 1 == 1 else (2, x // 2)
if p == 1:
factors.insert(0, q)
else:
stack.append(p)
stack.append(q)
return factors
if __name__ == '__main__':
print(factorization(200))
测试结果为:
[2, 2, 2, 5, 5]