背景
RSA
不对称加密算法可是算是世界上最重要的加密算法,其中包括我们熟悉的https
的加密。为了完全弄明白他的实现原理,我们需要对数论这门学科,有一定的了解。现在我们分步来看,这个全球最重要的加密算法,都需要哪些数学知识。
第一步:获取两个不相等的质数,p=61和q=53
数学知识:质数
质数又称素数,在自然数中,除了1和自身外,不能被其他自然数整除。比如10以内的质数有:1,2,3,5,7。那么在程序中,我们如何判断一个数是不是质数呢?
方案一:
function isPrimeNum() {
let n = 7
for (let i = 2; i < n; i++) {
if (n % i === 0) {
return false
}
}
return true
}
这种方案是最直观的,也是效率最低的,因为要判断n是不是质数,我们需要运算n-2次
方案二:
...
for (let i = 2; i < n / 2; i++)
...
我们把for循环中的n改成n/2,这样运算量上能减少一半(因为$ \frac n2 $后一半的数都可以通过$ \frac n2 $前一半的数$\times 2$得到,所以没必要参加运算)
方案三:
...
for (let i = 2; i < Math.sqrt(n); i++)
...
我们把$ \frac n2 $改成 $ \sqrt n $之后,我们的运算量就不是减少一半了,而是减少一个数量级,数字越大,效果越明显。我们以1万为例,使用此方案只需要计算98次即可。
ts实现-有详细注释:是否为质数
第二步:把p和q相乘,得到n。其中n=61*53=3233,用二进制表示为:110010100001。
我们常说的RSA算法中的多少位,就是n用二进制表示后的位数,在我们例子就是12位。目前商用中一般都是2048位,比如我们的segmentfault
第三步:计算出小于n的自然数中,有多少数与n互质
数学知识1:互质
如果两个数的最大公约数为1,那么我们说这两个数互质,记:GCD(a,b)=1。其中GCD表示两个数的最大公约数。
我们来看几组互质的例子:13、14 | 7、9 | 4、7 | 6、35 | ...
我们可以得到如下结论:如果两个数是质数,那么这两个数肯定互质;两个数如果互质,那么这两个数不一定是质数。比如:6和35都不是质数,但是他们互质。
ts实现-有详细注释:取互质元素
数学知识2:欧拉函数
我们要计算10以内有多少与10互质呢,我们可以得到:1、3、7、9这4个数。如果是一个大数,我们用脑子想可能就想不出来了,所以我们需要使用欧拉函数来算出来,记作φ(n)。
欧拉函数分为几种情况:
- 情况1:如果n=1,那么与n互质的自然数只有1
$$ φ(n)=1 $$
- 情况2:如果n是质数,那么与n互质的自然数有n-1个,
$$ φ(n)=n-1 $$
$$ 例:φ(7)=6 $$
- 情况3:如果n可以因式分解为两个互质数的乘积,则
$$ φ(n)=φ(p)\times φ(q)=(p-1)\times (q-1)$$
$$ 例:φ(56)=φ(7)*φ(8) = 6 * 7 = 42 $$
- 情况4:如果n可以写成某个数的质数次幂(其中k为质数),则
$$ φ(n)=φ(p^k)=p^k-p^{k-1}=p^k(1-\frac 1p) $$
$$ 例:φ(49)=φ(7^2)=7^2 - 7^1 = 42 $$
- 情况5:根据以上规律,总结出一个通用的公式:
$ \qquad n=p_1^{k^1} \times p_2^{k^2} \ldots p_r^{k^r} \quad 注:任意一个整数,都可以写成两个质数的乘积$
$ \qquad \Downarrow $
$ \qquad φ(n)=φ(p_1^{k^1}) \times φ(p_2^{k^2})\ldots φ(p_r^{k^r})$
$ \qquad \Downarrow $
$ \qquad φ(n)= p_1^{k^1}(1- \frac 1p_1) \times p_2^{k^2}(1- \frac 1p_2) \ldots p_r^{k^r}(1- \frac 1p_r)$
$ \qquad \Downarrow $
$ \qquad φ(n)=p_1^{k^1} \times p_2^{k^2}\ldots p_r^{k^r}\times (1- \frac 1p_1)\times(1- \frac 1p_2)\ldots(1- \frac 1p_n) $
$ \qquad \Downarrow $
$ \qquad φ(n)=n\times(1- \frac 1p_1)\times(1- \frac 1p_2)\ldots(1- \frac 1p_n) $
- 总结:通过欧拉函数最后的通式,我们发现最后的结果只和n和p有关,和p的幂无关,这点很重要,在我们用程序实现时,能够大大的简化我们的逻辑代码。
回到算法中,我们需要计算与n互质的个数,也就是求φ(n),根据欧拉函数,计算过程如下:
$$ φ(n)=φ(3233)=φ(61) \times φ(53)=60\times52=3120 $$
ts实现-有详细注释:欧拉函数
第四步:在1和φ(n)之间,选取一个随机质数e,即在1~3120中选取e=17
第五步:求e和φ(n)的模反元素d
数学知识1:使用辗转相除法求最大公约数
我们先看两个例子,
例1:求47和30的最大公约数:
$ 47 = 30 \times 1 + 17 $
$ 30 = 17 \times 1 + 13 $
$ 17 = 13 \times 1 + 4 $
$ 13 = 4 \times 3 + 1 $
$ 4 = 1 \times 4 + 0 $
我们得到:GCD(47, 30) = 1
例2:求50和35的最大公约数:
$ 50 = 35 \times 1 + 15 $
$ 35 = 15 \times 2 + 5 $
$ 15 = 5 \times 3 + 0 $
我们得到:GCD(50, 35) = 5
聪明的你看完这两个例子可以知道如何计算了吧。通俗的讲,如果最后的多项式可以写成:a = bx + c。 当c=0时,b就是两数的最大公约数。
ts实现-有详细注释:求最大公约数
数学知识2:模反元素
定义:如果两个正整数a和n互质,那么一定可以找到整数b,使得a*b与n相除,余数为1,记作:$ (a \times b) \% n = 1 \Rightarrow \frac {(a \times b) - 1} n = 1 $
例:求3和11的模反元素
$$ \frac {(3 \times b) - 1} {11} = 1 $$
心算我们可以算出来其中一个值: $ b=4 $
数学知识3:裴蜀定理
- 通过上面的运算,我们可以算出一些简单数的模反元素,对于较大的数来说,我们需要引入新的计算工具:裴蜀定理,通过它,我们可以通过一个二元一次方程来得出模反元素
- 定义:如果a与b互质,即GCD(a, b) = 1,二元一次方程$ ax + by = 1 $有一对正整数解,其中x即为a、b的模反元素。同理,上面的例子我们可以化简成这样:3x + 11y = 1
- 疑惑:对于二元一次方程,好像不可解(也可以说有无穷多个解),我们之前都是解方程组。即然定理已经解决,两个互素(质)数组成的二元一次方程有一对整数解,那肯定是能解,解法我们需要引入另一个数学工具:扩展欧几里得算法
数学知识4:扩展欧几里得算法
这个算法其实就是上面我们求最大公约数时,用到的辗转相除法+它的逆运算,我们看个例子就明白是什么意思了
例1:求$ 47x + 30y = 1 $的解
解:使用辗转相除法,我们可以得到:
$ 47 = 30 \times 1 + 17 $
$ 30 = 17 \times 1 + 13 $
$ 17 = 13 \times 1 + 4 $
$ 13 = 4 \times 3 + 1 $
对最后一行,我们移项处理:
$ 1 = 13 - 4 \times 3 $
$ 4 = 17 - 13 \times 1 $
$ 13 = 30 - 17 \times 1 $
$ 17 = 47 - 30 \times 1 $
我们把第二行代入第一行中:
$ 1 = 13 - \overbrace{(17 - 13 \times 1)}^4 \times 3 $
$ \Downarrow $
$ 1 = 4 \times 13 - 3 \times 17 $
$ \Downarrow $
$ 1 = 4 \times \overbrace{(30 - 17)}^{13} - 3 \times s17 $
$ \Downarrow $
$ \ldots $
$ 1 = (-7) \times 47 + 11 \times 30 $
$ 解得:x=-7(即为我们要求的模反元素d) \quad y = 11 $
回到算法中,我们根据e=17和φ(n)=3120,得到一个二元一次方程:$ 17x + 3120y = 1 $,再根据扩展欧几里得算法,我们可以得到方程的解:$x = 2753 \quad 即:d = 2753$
ts实现-有详细注释:扩展欧几里德算法求方程的解
第六步:我们把n和e封装成公钥,n和d封装成私钥
- 公钥:$ (3233, 17) $
- 私钥:$ (3233, 2753) $
到此,我们的公私钥分配成功!
总结:RSA加密算法,虽说是一个程序问题,但终归还是一个数学问题!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。