RSA
RSA
模算数 (Modular Arithmetic)
带余除法 (Division Algorithm)
定理内容
同余 (Congruence)
在模 的世界里,所有的数字都在 到 之间循环。
假设我们有两个整数 和 ,以及一个正整数 (作为模数)。
加法律推导
定理:两个数相加后的余数,等于它们各自余数相加后的余数。
推导过程:
将我们的初始条件代入 中:
提取公因数 进行重组:
当我们对等式两边同时求模 时,因为 是 的整数倍,它除以 的余数必定是 0。所以这部分被完全“抹除”了。
结果只剩下后面的部分:
因为 且 ,代回即可证得加法律。
乘法律推导
定理:两个数相乘后的余数,等于它们各自余数相乘后的余数。
推导过程:
我们将初始条件代入 并展开多项式:
接下来,我们将前三项提取公因式 :
当我们对这个表达式求模 时,前面含有 的巨大项的余数统统是 0,全部被消掉。最终只剩下:
幂模运算推导
定理:
推导过程:
幂运算其实就是连乘运算。根据上面刚刚证明的“乘法律”,既然每一次相乘都可以提前取模,那么连乘 次自然也可以在每一步都取模。
反复应用乘法律:
证毕。
乘法逆元
在模算术里,我们不用“除法”,我们用乘以它的逆元来代替除法。
如果想计算 ,我们其实是去寻找一个特殊的数字 (这就是 的乘法逆元),使得:
找到之后,除以 就变成了乘以 :
欧拉定理 (Euler's Theorem)
定理内容:如果两个正整数 和 互质,那么 的 次方除以 的余数,必定等于 1。
用严谨的数学公式表达:
欧拉函数
定义:对于任意正整数 ,欧拉函数 代表的是:在从 到 的正整数中,有多少个数字与 互质(互质即最大公约数为 1)。
让我们看几个直观的例子:
计算 :
1 到 10 之间,与 10 互质的数有:1, 3, 7, 9。一共 4 个。
所以,。
计算素数的欧拉函数:
假设 是一个素数(比如 )。因为 7 是素数,所以比它小的所有正整数 (1, 2, 3, 4, 5, 6) 都和它互质。
规律 1:如果 是素数,那么 。
计算两个素数乘积的欧拉函数:
如果 是由两个不同的素数 和 相乘得到的(即 )。欧拉函数有一个奇妙的乘法性质:。
规律 2:如果 ( 为素数),那么 。
二进制模幂算法 (Binary Exponentiation)
从左到右的二进制模幂算法(Left-to-Right Binary Exponentiation)
int modexp(int m, int e_bits[], int e_bits_len, int n)
{
int R, L;
int k = 0;
int s = 1;
while (k < e_bits_len)
{
if (e_bits[k] == 1)
R = (s * m) % n;
else
R = s;
s = R * R % n;
L = R;
k++;
}
return L;
}霍纳法则(Horner's Method)
霍纳法则(Horner's Method),在中国古代称为“秦九韶算法”,它的核心思想是通过不断提取公因式,将多项式转化为一层层的嵌套,从而消灭高次幂的计算。
假设我们要计算 。
数字 的二进制是 。在代码中,数组 e_bits[] = {1, 0, 1}(从高位到低位)。
我们可以把 用多项式展开:
那么 可以改写为:
为了方便计算,数学家提取公因式(这称为霍纳法则),将其变为一层层嵌套的形式:
推导
- 必备工具:指数的两个黄金法则
在开始推导前,我们需要复习初中代数里关于指数的两个核心定律:
- 法则 1(加法变乘法):
- 法则 2(乘法变平方):
- 第一步:对“指数”使用霍纳法则
我们先不看底数 ,单看指数 的二进制展开:
如果把它看作一个关于变量 (这里 )的多项式:。
按照传统的计算方法,你需要先算 ,再乘 ,再加后面的项。这需要多次独立的乘法。
我们对指数 进行提取公因式 的操作:
前两项 都有因子 ,我们把 提出来:
为了格式统一,我们把 直接写成 (因为它就是末位数字),此时指数变成了:
- 第二步:将指数放回底数 上
现在,我们把经过霍纳法则变形的指数,放回到 的右上角:
第一层拆解(处理最外面的 + 1):
根据法则 1 (),把尾巴上的 + 1 拆下来:
第二层拆解(处理最外面的 x 2):
根据法则 2 (),把乘 变成外面的平方:
第三层拆解(处理括号里的 + 0):
再次使用法则 1:
第四层拆解(处理最内层的 x 2):
再次使用法则 2:
代码逻辑计算(假设 初始为 1):
- 第 1 轮 (, bit=1):最内层
R = (s * m) % n此时 。s = R * R % n为下一轮做准备,将当前结果平方,。L = R。
- 第 2 轮 (, bit=0):中间层
- 由于 bit 为 0,不乘 。
R = s直接继承上一轮的平方结果,。s = R * R % n继续为下一轮平方,。L = R。
- 第 3 轮 (, bit=1):最外层
R = (s * m) % n。s = R * R % n算出 (由于循环结束,这个值被废弃)。L = R最终结果 。
代码中的 s = R * R 负责将当前的指数“左移”(即翻倍),而 if (e_bits[k] == 1) 负责在末尾加上个位数。这使得原本需要乘 次的运算,变成了只需乘 次。
RSA 算法
密钥生成
在加密之前,我们需要生成一对钥匙:公钥(公开给所有人用来加密)和私钥(自己藏好用来解密)。
第一步:寻找素数
随机选择两个不相等的巨大素数 和 。
第二步:计算公共模数
这个 的长度就是密钥长度(比如2048位)。 是公开的。
第三步:计算欧拉函数
根据欧拉函数性质,因为 和 都是素数:
代表在小于等于 的正整数中,与 互质的数的个数。这个值必须严格保密。
第四步:选择公钥指数
随机选择一个整数 ,条件是 ,且 与 互质。通常会选择 65537。
此时,公钥诞生了:
第五步:计算私钥指数
找到一个整数 ,使得 和 相乘后对 取模余数为 1。即求 在模 下的乘法逆元:
这等价于 ( 为正整数)。
此时,私钥诞生了:
数据加密与还原
假设我们要发送一条机密信息,首先我们将其转换为一个数字 (必须满足 )。
加密过程(使用公钥)
发送方使用接收方的公钥 ,计算密文 :
发送方将计算出的数字 发送出去。
解密/还原过程(使用私钥)
接收方收到密文 后,使用自己的私钥 进行计算,就能神奇地还原出 :
我们将加密公式代入解密公式:
我们在生成密钥的第五步知道:。所以:
根据欧拉定理:如果 和 互质,那么 。
因此:
