Processing math: 0%

密码学笔记(3)——分解因子算法

  从前面两篇的内容可以知道对于RSA密码体制,最为明显的攻击方式就是试图分解模数。对于大整数分解目前最为有效的三种算法是二次筛法、椭圆曲线分解算法以及数域筛法,其他作为先驱的著名包括Pollard的ρ算法和p-1算法、Willian的p+1算法、连分式算法,当然还有试除法,这篇文章就根据课本的介绍总结这些算法。首先假定要分解的整数n为奇数。

一、试除法

  试除法的思想是最为简单的,假设n为合数,那么它肯定有一个素因子满足\rho \leq \lfloor \sqrt{n} \rfloor,因此,只要利用\lfloor \sqrt{n} \rfloor的每个奇数去除n,这就足以判断n是素数还是合数。该算法在n < 10^{12}时还是不错的算法。

二、Pollard p-1算法

  这个算法有两个输入,待分解的奇整数以及一个预先指定的阶B,本质来源是一个简单的数学证明,我们来先看看算法。

Alg1 Pollard p-1 Factoring Algorithm(n,B)

  a \leftarrow 2 

for j \leftarrow 2 to B

  a \leftarrow a^{j} mod \, n

d \leftarrow gcd(a-1 , n)

if 1 < d < n

  then return(d)

else return("failure")

  算法的证明过程如下,关键是在for循环中的操作以及之后的求最大公约数。假定p是n的一个素因子,又假定对每一个素数幂q | (p-1),有q \leq B,那么在这种情形下必须有 (p-1) | B! \quad (因为B!包含有q)

  在for循环结束时,我们有a \equiv 2^{B!} (mod \, n)

  由于p | n,一定有a \equiv 2^{B!} (mod \, p)

  现在,由Fermat定理可知2^{p-1} \equiv 1 (mod \, p)

  由于(p-1) | B!可知,得a \equiv 1 (mod \, p)

  因此有p|(a-1),由于已经有p|n,可以看到p | d,其中d = gcd(a-1 , n),因此整数d就是n的一个非平凡因子。

  接下来要讨论的是B值,这个算法中,一共有B-1个模指数,利用“平方-乘”算法计算每一个模指数需要至多2lbB个模乘法,gcd的计算可以利用Euclidean算法在时间o((logn)^{3})内完成,因此整个算法的时间复杂度是o(BlogB(logn)^{2}+(logn)^{3})。如果B也是o((logn)^{i}),那么该算法就是关于logn的多项式时间算法,只是这样子选择的B,算法想要得到的d的概率是很小的。另一方面,如果B迅速增大,算法的执行效率不会比试除法快。

  对于B值还要讨论的一个问题是,我们不能使B值太大,否则B!会是一个很可观的数字,换言之它要求对于p值不仅为n的素因子,而且p-1只有小的素因子。因此很容易构造出RSA模n=pq使得p-1分解算法失效。一般的方法是选择两个大素数p_{1}q_{1},使得p = 2p_{1}+1q=2q_{1}+1也是素数,此时,RSA模n=pq将能抵抗p-1方法的分解。

 三、Pollard ρ算法

  设p为n的最小素因子,假定存在两个整数x,x^{'} \in Z_{n},使得x \neq x^{'}x \equiv x^{'} (mod \, p),那么有p \leq gcd(x-x^{'} , n) < n,所以,我们通过计算最大公因子得到n的一个非平凡因子,注意到并不需要事先知道p的值。

  由于不知道p值,那么我们怎么选择这两个值呢,可以通过先选择一个随机子集X \subseteq Z_{n}来分解n,然后对所有不同的x , x^{'} \in X计算gcd(x-x^{'},n),这个方法能够成功当且仅当映射x \longrightarrow x (mod \, p)对于x \in X得到至少一个碰撞,利用生日悖论,我们可以发现当X达到一定程度时,发生碰撞的概率还是非常大的。然而为了寻找这个碰撞,我们要计算gcd(x-x^{'} , n),这就陷入了一个死循环,意味着,在找到p因子之前,至少要做\binom{|x|}{2} > \frac{p}{2} 次的gcd。

   Pollard \rho算法集成了这个技巧的一个变形,仅仅需要较少的gcd计算,假定f为一个具有整系数的多项式,比如f(x) = x^{2} + a,其中a为一个小常数,假定映射x \longrightarrow f(x) mod \, p类似于一个随机映射,考虑序列x_{1},x_{2},…,x_{n},…… \in Z_{n}其中有x_{j} = f(x_{j-1}) mod \, n对于所有的j \geq 2,令m为一个整数,且定义X=\{ x_{1},x_{2},…,x_{m} \},为了简单起见,假定X直接包含了m个不同的模n剩余,希望X为Z_{n}的m个元素的随机子集。

  我们来寻找两个不同的值x_{i},x_{j} \in X使得gcd(x_{j} - x_{i} , n) > 1,每次计算序列中的一个新项x_{j},对所有的i < j计算gcd(x_{j} - x_{i},n),这样子就做到了大大减少gcd计算的次数,但是要证明一下为什么可以这么做。

  假定x_{i} \equiv x_{j} (mod \, p),利用f为整系数多项式这个事实,有f(x_{i}) \equiv f(x_{j}) (mod \, p),由于x_{i+1} = f(x_{i}) (mod \, n)x_{j+1} = f(x_{j}) (mod \, n),那么有x_{i+1} mod \, p = (f(x_{i}) mod \, n)mod \, p = f(x_{i}) mod \, p因为p | n,类似的x_{j+1} mod \, p = f(x_{j}) mod \, p因此有x_{i+1} \equiv x_{j+1} (mod \, p)。重复上述过程就可以得到结论:

  如果x_{i} \equiv x_{j} (mod \, p),那么有x_{i+ \delta} \equiv x_{j + \delta} (mod \, p),对于所有的整数\delta \geq 0,记l = j - i,得到x_{i^{'}} \equiv x_{j^{'}} (mod \, p)如果 j^{'} > i^{'} \geq ij^{'} - i^{'} \equiv 0 (mod \, l)

  假定我们利用顶点集Z_{p}构造一个图G,其中对于 i \geq 1,从点x_{i} (mod \, p)向点x_{i+1} (mod \, p)做一条边,存在第一个点对x_{i},x_{p}i < j使得x_{i} \equiv x_{j} (mod \, p),因此可以构造出这样子的一个图x_{1} (mod \, p) \rightarrow x_{2} (mod \, p) \rightarrow x_{3} (mod \, p) \rightarrow … \rightarrow x_{i} (mod \, p)  x_{i} (mod \, p) \rightarrow x_{i+1} (mod \, p) \rightarrow x_{i+2} (mod \, p) \rightarrow …… \rightarrow x_{j} (mod \, p) \rightarrow x_{i} (mod \, p)

  从而这条链看上去就是一个字母\rho

  

 

  通常在算法中会取j  = 2i来寻找碰撞,算法如下所示。

Alg2 Pollard \rho Factoring Algorithm(n,x_{1})

external f

x \leftarrow x_{1}

x^{'} \leftarrow f(x) mod \, n

p \leftarrow gcd(x - x^{'} , n)

while p = 1

  // in the ith iteration, x = x_{i} and x^{'} = x_{2i}

  x \leftarrow f(x) (mod \, n)

  x^{'} \leftarrow f(x^{'}) (mod \, n)

  p \leftarrow gcd(x - x^{'} , n)

if p = n

  then return ("failure")

  else return (p)

  前面有l = j - i,如果x_{i} \equiv x_{j} (mod \, p),那么对于所有满足i^{'} \equiv 0 (mod \, l),i^{'} \geq ix_{i^{'}} \equiv x_{(2i)^{'}} (mod \, l),在l个连续整数i,i+1,…,j-1,必然存在一个数可以被l整除,满足上面两个最小值i^{'}不超过j-1,因此找到一个因子p的循环次数最多为j,而j的值最大为\sqrt{p}。换言之,对于很大的数,只要找到那个圈,就意味着成功。

  算法可能因为没有找到n的非平凡因子而失败,当且仅当找到x \equiv x^{'} (mod \, n),这等价于x = x^{'},这种情况发生的概率大致为\frac {p}{n},当n很大时这种情况概率变得很小,这时候可以选择一个不同的初值重新运行或者选择一个不同的函数f。

四、Dixon的随机平方算法

  这个分解因子算法的理论是基于如下的简单事实,假定我们可以找到x \neq \pm y (mod \, n)使得x^{2} \equiv y^{2} (mod \, n),那么有 n | (x+y)(x-y),但是x-yx+y均不能被n整除,换言之,这两个式子中必然至少有一个使得gcd(f , n) > 1 f=x+y 或者f =x-y

  随机平方算法使用一个因子基B,它是b个最小素数的集合(b是适当选取的数值),首先得到几个整数z,使得z^{2} (mod \, n)的所有素因子都在B中,将某些z相乘使得每一个在B中的素数出现偶数次,这样就建立起了一个所期望的类型的同余方程x^{2} \equiv y^{2}(mod \, n),这个方程可能导出n的一个分解。

  说起来很复杂,需要举一个被仔细设计的例子来配合说明。

Exm3 假定n=15770708441,令b=6,那么B=\{ 2,3,5,7,11,13 \},考虑如下三个同余方程$$ \begin{align} 8340934156^{2} & \equiv 3×7(mod \, n) \\ 12044942944^{2} & \equiv 2×7×13(mod \, n) \\ 2773700011^{2} & \equiv 2×3×13(mod \, n) \\ \end{align} 

如果取上面同余方程两边的乘积,有(8340934156×12044942944×2773700011)^{2} \equiv (2×3×7×13)^{2}(mod \, n)

在两边表达式的括号模n约化,有9503435785^{2} \equiv 546^{2}(mod \, n)

利用Euclidean算法,计算gcd(9503435785-546,15770708441) = 115759得出n的因子115759。

  下面来说明当已经有这些整数z的时候,怎么构造相乘式子使得因子基中的素数出现偶数次,假定B=\{ p_{1},…,p_{b} \}为因子基,设c为稍大于b的整数,且假定已经得到了c个同余方程:z_{j}^{2} \equiv p_{1}^{\alpha_{1j}} × p_{2}^{\alpha_{2j}}× p_{3}^{\alpha_{3j}} ×… × p_{b}^{\alpha_{bj}} (mod \, n)

   其中1 \leq j \leq c,对于每一个j,考虑向量a_{j} = (\alpha_{1j} mod \, 2,…,\alpha_{bj} mod \, 2) \in (Z_{2})^{b}

  如果我们可以找到a_{j}的子集使得其模2的和为向量(0,…,0),那么对应的z_{j}的乘积将会使得B中的每个因子偶数次。

  于是,问题就转化成寻找c个向量a_{1},…,a_{c}的一个子集使得其和模2为零向量,即找一个线性相关,当c>b时,这样的线性相关一定存在,我们选取c>b+1(c为稍大于b的整数)的原因是,不能保证任一给定的同余方程x^{2} \equiv y^{2} (mod \, n)一定能得到n的分解。从上一篇的定理告诉我们,假定x^{2} \equiv y^{2} \equiv a (mod \, n),其中gcd(a,n) = 1,那么a2^{l}个模n的平方根,其中ln的素因子的个数,如果l \geq 2,那么a至少有4个平方根,如果x和y随机选取,那么x \equiv \pm y(mod \, n)出现的概率最多为\frac {1}{2}

  有了这个估计,我们希望根据这些形如x^{2} \equiv y^{2} (mod \, n)并且x \neq \pm y(mod \, n),得到n的一个非平凡因子,这根本的来源是要如何选取整数z,一种方法是简单随机选择z,另一种是试用形如j + \lceil \sqrt{kn} \rceil和形如\lfloor \sqrt{kn} \rfloor的整数,其中j = 0 , 1 ,2 , …,k =1,2,…

   最后一个问题就是,因子基要选取多大,显然,当b越大时,似乎更有可能找到B上的分解,但是带来的问题是同余式会很多,我们需要一些数论中的结果帮助选取b的值。

Def4 (m-光滑)假定n和m为正整数,我们称n是m光滑的,如果n的任何一个素因子都小于等于m,并且同时定义\psi (n,m)定义为小于等于n且是m光滑的正整数的个数。

  数论当中有一个重要的结果列举如下。

Thm5 如果n >> m,那么有\frac {\psi (n,m)}{n} \approx \frac{1}{u^{u}}其中有u = \frac {log n}{log m},注意到\frac {\psi (n,m)}{n}表示从集合\{ 1,…, n \}中随机选取一个整数为m-光滑的概率。

  假定n \approx 2^{r}m \approx 2^{s},那么有u= \frac{logn}{logm} \approx \frac{r}{s}一个r比特的整数除以一个s比特的整数的执行时间为o(rs),如果假定了r<m,可以在时间o(rsm)内判断集合\{ 1,2,…,n \}中一个整数是否为m光滑的。

  因子基B可以选取为包含了所有小于等于m的素数,应用素数定理,我们有|B| = b = π(m) \approx \frac{m}{ln m}为了算法成功,需要找出略多于b个的m光滑的模n平方数,我们期望测试bu^{u}个整数就可以得到bm光滑的整数,因此,找到所需m光滑的平方数的期望时间为o(bu^{u}×rsm),我们已经有bo(\frac{m}{s}),算法的第一部分运行时间为o(rm^{2}u^{u})

  在算法的第二部分,需要化简模2的系列矩阵,构造出形如x^{2} \equiv y^{2} (mod \, n)的同余式,再应用欧几里得算法,这几步所需的时间是rm的多项式,即o(r^{i}m^{j})

  现在,我们给定了n \approx 2^{r}m \approx 2^{s},上面是针对n进行的优化,下面对m进行优化,一个好的选择是取s \approx \sqrt{rlbr},那么有u \approx \frac{r}{s} \approx \sqrt{\frac{r}{lbr}}现在开始估计

  \begin{align} lbu^{u} =& ulbu \\ \approx & \sqrt{\frac{r}{lbr}} lb \lgroup \sqrt{\frac{r}{lbr}} \rgroup \\ < &  \sqrt{\frac{r}{lbr}} lb \sqrt{r} \\ = & \sqrt{\frac{r}{lbr}} × \frac{lbr}{2} \\ = & \frac{\sqrt{rlbr}}{2} \\ \end{align}

  于是有u^{u} \leq 2^{0.5 \sqrt{rlbr}}

  因此,所有的运行时间可以写成如下形式o(2^{c \sqrt{rlbr}})其中c为一个常数,再利用r \approx lb n,最终可以导出如下通常的期望时间为o(e^{(1+o(1))\sqrt{lnn lnlnn}})

五、实际中的分解因子算法

  二次筛法的来源于判断z^2 (mod \, n)在B上的分解的一个筛法过程,数域筛法是构造同余式x^{2} \equiv y^{2} (mod \, n)来分解n,但这是在代数整数环中进行计算的,二次筛法、椭圆筛法和数域筛法的渐进运行时间均有上面讨论的形式,详细可以寻找更多的参考文献。

  在下一篇文章中,我们讨论除了分解n以外是否有其他体制对RSA密码体制进行攻击。

posted @   JCChan  阅读(4562)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
阅读排行:
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· DeepSeek本地性能调优
· 一文掌握DeepSeek本地部署+Page Assist浏览器插件+C#接口调用+局域网访问!全攻略
点击右上角即可分享
微信分享提示