Pollard’s rho算法

news/2024/11/25 19:43:14/

引入

给定一正整数 N ∈ N ∗ N\in \mathbb{N} ^{*} NN,试快速找到它的一个因数。
很久很久以前,我们曾学过试除法来解决这个问题。很容易想到因数是成对称分布的:即 N N N的所有因数可以被分成两块: [ 1 , N ] [1,\sqrt{N} ] [1,N ] [ N , N ] [\sqrt{N},N ] [N ,N]。这个很容易想清楚,我们只需要把区间 [ 1 , N ] [1,\sqrt{N} ] [1,N ]扫一遍就可以了,此时试除法的时间复杂度为 O ( N ) O(\sqrt{N} ) O(N )
对于 N ≥ 1 0 18 N\ge 10^{18} N1018的数据,这个算法运行起来无疑是非常糟糕的。我们希望有更快的算法。对于这样的算法,一个比较好的想法是去设计一个随机程序,随便猜一个因数。如果你运气好,这个程序的时间复杂度下限为 O ( 1 ) O(1) O(1)。但对于一个 N ≥ 1 0 18 N\ge 10^{18} N1018的数据,这个算法给出答案的概率是 1 1000000000000000000 \frac{1}{1000000000000000000} 10000000000000000001。当然,如果在 [ 1 , N ] [1,\sqrt{N} ] [1,N ]里面猜,成功的可能性会更大。那么,有没有更好的改进算法来提高我们猜的准确率呢?那就是Pollard’s rho算法。

算法流程

Pollard’s rho算法的重要思想就是:最大公约数一定是某个数的约数。也就是说, ∀ k ∈ N ∗ \forall k\in \mathbb{N}^{*} kN g c d ( k , n ) ∣ n gcd(k,n) |n gcd(k,n)n。只要选适当的k使得 g c d ( k , n ) > 1 gcd(k,n)>1 gcd(k,n)>1就可以求得一个约数 g c d ( k , n ) gcd(k,n) gcd(k,n)。这样的k数量还是蛮多的:k有若干个质因子,而每个质因子的倍数都是可行的。

如果这样的k我们随机取的话,就体现不出Pollard’s rho算法的精妙之处了。我们不妨考虑构造一个伪随机数序列,然后取相邻的两项的差来求gcd。为了生成一串优秀的随机数,Pollard设计了这样一个函数: f ( x ) = ( x 2 + c ) m o d N f(x)=(x^{2}+c ) \mod N f(x)=(x2+c)modN,其中 c c c是一个随机的常数。

我们随便取一个 x 1 x_{1} x1,令 x 2 = f ( x 1 ) x_{2} =f(x_{1} ) x2=f(x1) x 3 = f ( x 2 ) x_{3} =f(x_{2} ) x3=f(x2),……, x i = f ( x i − 1 ) x_{i} =f(x_{i-1} ) xi=f(xi1)。在一定的范围内,这个数列是基本随机的,可以取相邻两项作差求gcd。

这样构造的数列会有一些性质:
(1)相邻两数的差会包含前面所有相邻两数差的乘积,这些乘积中可能会包含n的因子。考虑下面这个式子:
x i − x i − 1 = f ( x i − 1 ) − f ( x i − 2 ) = x i − 1 2 − x i − 2 2 = ( x i − 1 + x i − 2 ) ( x i − 1 − x i − 2 ) ( m o d n ) x_{i}-x_{i-1}= f(x_{i-1} )-f(x_{i-2})={x_{i-1}}^{2} -{x_{i-2}}^{2}=(x_{i-1}+x_{i-2})(x_{i-1}-x_{i-2}) \pmod n xixi1=f(xi1)f(xi2)=xi12xi22=(xi1+xi2)(xi1xi2)(modn)
在等式最右边 x i − 1 x_{i-1} xi1 x i − 2 x_{i-2} xi2又可以继续分解,直到 x 1 x_{1} x1。所以会有上面那个性质。

(2)序列中距离为k的两项的差,一定为前面任意距离为k的两项的差的倍数。这个性质算是上面那个性质的推广,当 k = 1 k=1 k=1时,其实和性质(1)是一样的。在序列中取 x i , x j x_{i}, x_{j} xi,xj,假设 i > j i>j i>j,则有:
x i − x j = f ( x i − 1 ) − f ( x j − 1 ) = x i − 1 2 − x j − 1 2 = ( x i − 1 + x j − 1 ) ( x i − 1 − x j − 1 ) ( m o d N ) x_{i}-x_{j}=f(x_{i-1})-f(x_{j-1})={x_{i-1}}^{2}-{x_{j-1}}^{2}=(x_{i-1}+x_{j-1})(x_{i-1}-x_{j-1}) \pmod N xixj=f(xi1)f(xj1)=xi12xj12=(xi1+xj1)(xi1xj1)(modN)
其中等式最右边 x i − 1 x_{i-1} xi1 x j − 1 x_{j-1} xj1又可以继续分解。

(3)序列中任意两数的差,也一定可以转换为相邻两个数的差的倍数。在序列中取 x i , x j x_{i}, x_{j} xi,xj,假设 i > j i>j i>j,则有:
x i − x j = x i − x i − 1 + x i − 1 − ⋯ − x j + x j − x j − 1 = b ∗ ( x j − x j − 1 ) ( m o d N ) x_{i}-x_{j}=x_{i}-x_{i-1}+x_{i-1}-\dots -x_{j}+x_{j}-x_{j-1}=b*(x_{j}-x_{j-1}) \pmod N xixj=xixi1+xi1xj+xjxj1=b(xjxj1)(modN)
根据性质(1),相邻两数的差会包含前面所有相邻两数差的乘积。所以, x i − x i − 1 x_{i}-x_{i-1} xixi1一直到 x j + 1 − x j x_{j+1}-x_{j} xj+1xj会包含 x j − x j − 1 x_{j}-x_{j-1} xjxj1,将所有的无关项提取出来形成一个b就得到了上面等式的最右边。

根据前面的分析,序列有一些特殊的性质,即下标距离为k的两个数之差,是前面的下标距离为k的某两个数之差的倍数。所以,对于距离为k的两个数的差,我们只需要检测最后那一对即可。这样,每一个距离都只需要检测一次。

为了判断环的存在,可以用一个简单的Floyd判圈算法,也就是"龟兔赛跑"。假设乌龟为 t t t,兔子为 r r r,初始时 t = r = 1 t=r=1 t=r=1。假设兔子的速度是乌龟的二倍。过了时间 i i i后, t = i , r = 2 i t=i,r=2i t=i,r=2i。此时两者得到的数列值 x t = x i , x r = x 2 i x_{t}=x_{i},x_{r}=x_{2i} xt=xi,xr=x2i。假设环的长度为 c c c,在环内恒有: x i = x i + c x_{i}=x_{i+c} xi=xi+c。 如果龟兔"相遇",此时有: x r = x t x_{r}=x_{t} xr=xt,也就是 x i = x 2 i = x i + k c x_{i}=x_{2i}=x_{i+kc} xi=x2i=xi+kc。此时两者路径之差正好是环长度的整数倍。

出现这种乌龟被套圈的情况,再继续下去只会一直重复,所以需要通过调整函数 f ( x ) f(x) f(x)里常数项的值来继续“碰运气”。

这样一来,我们得到了一套基于Floyd判圈算法的Pollard Rho 算法。Python实现如下

import random
from math import *
from Crypto.Util.number import isPrimedef f(x, c, n):return (x * x + c) % ndef Pollard_rho(n):if isPrime(n):return nwhile True:c = random.randint(1, n - 1)t = f(0, c, n)r = f(t, c, n)while t != r:d = gcd(abs(t - r), n)if d > 1:return dt = f(t, c, n)r = f(r, c, n)r = f(r, c, n)n = int(input())
fac = Pollard_rho(n)
print(fac)

椭圆曲线上的Pollard’s rho算法

设椭圆曲线为 G G G P , Q P,Q P,Q为椭圆曲线上两点,欲求出满足 d P = Q dP=Q dP=Q d d d

选择哈希函数将 G G G分成尺寸大致相同的三部分 S 1 , S 2 , S 3 S_{1},S_{2} ,S_{3} S1,S2,S3,其中 O ∉ S 2 O\notin S_{2} O/S2;定义一个随机步数的迭代函数 f f f
R i + 1 = f ( R i ) = { Q + R i , R i ∈ S 1 2 R i , R i ∈ S 2 P + R i , R i ∈ S 3 R_{i+1}=f(R_{i})=\left\{\begin{matrix} Q+R_{i}, & R_{i} \in S_{1}\\ 2R_{i}, & R_{i} \in S_{2} \\ P+R_{i}, & R_{i} \in S_{3} \end{matrix}\right. Ri+1=f(Ri)= Q+Ri,2Ri,P+Ri,RiS1RiS2RiS3
R i = a i ∗ P + b i ∗ Q R_{i}=a_{i}*P+b_{i}*Q Ri=aiP+biQ,则:
a i + 1 = { a i , R i ∈ S 1 2 a i m o d N , R i ∈ S 2 a i + 1 , R i ∈ S 3 a_{i+1}=\left\{\begin{matrix} a_{i}, & R_{i} \in S_{1}\\ 2a_{i} \mod N, & R_{i} \in S_{2} \\ a_{i}+1, & R_{i} \in S_{3} \end{matrix}\right. ai+1= ai,2aimodN,ai+1,RiS1RiS2RiS3
b i + 1 = { b i + 1 , R i ∈ S 1 2 b i m o d N , R i ∈ S 2 b i , R i ∈ S 3 b_{i+1}=\left\{\begin{matrix} b_{i}+1, & R_{i} \in S_{1}\\ 2b_{i} \mod N, & R_{i} \in S_{2} \\ b_{i}, & R_{i} \in S_{3} \end{matrix}\right. bi+1= bi+1,2bimodN,bi,RiS1RiS2RiS3
初始化参数 R 0 = P , a 0 = 1 , b 0 = 0 R_{0}=P,a_{0}=1,b_{0}=0 R0=P,a0=1,b0=0,产生配对 ( R i , R 2 i ) (R_{i},R_{2i}) (Ri,R2i) ,直到对某个 m m m R m = R 2 m R_{m}=R_{2m} Rm=R2m,此时有:
R m = a m P + b m Q R_{m}=a_{m}P+b_{m}Q Rm=amP+bmQ
R 2 m = a 2 m P + b 2 m Q R_{2m}=a_{2m}P+b_{2m}Q R2m=a2mP+b2mQ
所以有 d = a 2 m − a m b m − b 2 m m o d N d=\frac{a_{2m}-a_{m}}{b_{m}-b_{2m}} \mod N d=bmb2ma2mammodN


http://www.ppmy.cn/news/287843.html

相关文章

Linux编译器-gcc/g++(动静态链接)

目录 一、Linux编译器-gcc/g的使用1.1 背景知识1.2 预处理,编译,汇编,链接1.3 动静态链接 二、补充sudo设置 一、Linux编译器-gcc/g的使用 1.1 背景知识 我们为什么能在windows或者linux下进行C/C或者其它形式的开发呢?前提条件…

Python 入门教程

前言 Python 是一门优雅、简洁、易读易写的编程语言。它被广泛地应用于科学计算、 Web 开发、自动化运维等领域,并且拥有强大的社区支持和生态系统。 安装 Python 在开始学习 Python 前,需要先安装 Python。可以前往 Python 的官方网站 https://www.p…

TypeScript核心基础

前言 为了方便我们直接使用脚手架让他帮我们直接编译就完事了 创建一个 Vue 应用 前提条件 熟悉命令行已安装 16.0 或更高版本的 Node.js npm init vuelatest 这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测…

JavaSSM笔记(一)

**建议:**对Java开发还不是很熟悉的同学,最好先花费半个月到一个月时间大量地去编写小项目,不推荐一口气学完,后面的内容相比前面的内容几乎是降维打击,一口气学完很容易忘记之前所学的基础知识,尤其是Java…

智慧消防-液位设备告警功能

设计智慧消防液位功能时,主要的报警功能有: status.put("10", "设备自检");status.put("02", "电量不足");status.put("03", "低水位报警");status.put("13", "低水位报警恢…

无线风力报警仪预警和报警设置

无线风力报警仪预警和报警 它的预警和报警参数默认值分别为:预警值门限0.8m/s和报警值门限1.3m/s。在退出预警报警值门限设置,进入实时采集数据后预警值门限和报警值门限会自动保存且掉电不丢失,重新启动后自动调出原值。 当实时采集到的风…

当湿度达到70蜂鸣器警报

1.编写设备树&#xff0c;添加蜂鸣器等设备 驱动代码&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/device.h> #include …

预警仪产品上市增加曝光量如何使用新闻来打造

新闻宣传是一种把产品推广到更大范围的方法&#xff0c;它利用新闻媒体把产品和服务传播给大众&#xff0c;从而提高公司的知名度和美誉度&#xff0c;增加产品的销售量。预警仪是安全领域的重要产品&#xff0c;在今天的社会中&#xff0c;安全是重中之重&#xff0c;预警仪得…