大整数分解算法 之 Pollard's p-1 算法原理

"一切以解题为目的的抄代码都是耍流氓!!!"

前置知识

smooth与powersmooth

光滑数(smooth number),或译脆数,是一个可以因数分解为小质数乘积的正整数
如果一个整数的所有素因子都不大于B,我们称这个整数是B-Smooth数
如果一个整数的所有素因子的对应指数次幂不大于B,我们称这个整数是B-powersmooth数
720(243251) 是一个5-smooth数,6-smooth数,7-smooth数
51<32<24=16,所以它也是一个16-powersmooth数

费马小定理

当a是一个整数,p是一个质数时,有费马小定理:

ap11(modp)

算法详解

1、我们的目的是分解出整数n的因子
2、如果我们可以找到一个与 n 不互质的整数 s,则可直接通过求gcd(s,n) 求得 n 的一个因子
证明: 因为 n与s不互质,那么n与s之间必然存在公因子,又因为n是质数相乘得到的,那么 gcd(n,s)一定是n的因子
3、我们的思路转化成如何求这样的s
4、假设p为n的一个未知的素数,单独的p是难以求出的,我们可以构造出含有因子p的数s,从而得到 gcd(s,n),即得到n的因子
5、如何求这种s?
6、我们构造 x,x 满足x1(modp),那么就有 gcd(x1,n) 为n的因子
7、那如何得到这样的x?
8、转化 Fermat 小定理,则有2p11(modp),对比x1(modp),显然只要求出p-1,就能得到 x 的值,但p未知!!!,但我们可以构造(p1)的倍数,进而达到相同的效果
9、如何构造(p-1)的倍数?
10、其实(p-1)的B-powersmooth数(设为B)的阶乘就是(p-1)的倍数
证明如下:
因为p1=q1q2q3...qm,且 q1q2q3...qmB 并且这些质数幂互不相等,那么B的阶乘一定会整除(p-1)
11、所以,我们只需要找到一个合适大小的B,就可以在多项式时间计算出结果

12、找到B后,回溯:

x2B!(modp)

s=x1

d=gcd(s,n)

此时,求出的d即为整数n的一个因数

13、在一些其他文案中,我发现对于(p-1)的倍数的选取,他们并没有使用B!
而是选取了一个类似这样的结构:
image

不是很懂这个结构...不过无所谓,其他地方还是一样的

对抗Pollard's p-1的方法

B必须满足"大于p-1的所有因子",如果p−1的因子很大,选择小的B会造成算法求解失败,选择足够大的B会增加算法成功的概率,但那样的话算法的复杂度不比试除法好
为了抵抗Pollard的p-1因子攻击,我们通常选取两个大素数p1q1,令p=2p1+1q=2q1+1,这样得到的模数n=pq能够抵抗攻击
14、Pollard's p-1 算法:

# python 脚本 x = 2 B = 2 while True: x = pow(x, B, N) s = gmpy2.gcd(x-1, N) if s != 1 and s != N: q = N // s print("n=",B) print("p=",s) print("q=",q) break B += 1

一些小知识

什么是多项式时间:
几类复杂度被分为两种级别,其中后者的复杂度无论如何都远远大于前者:一种是O(1),O(log(n)),O(na)等,我们把它叫做多项式级的复杂度,因为它的规模n出现在底数的位置;另一种是O(an)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。
参考 https://www.zhihu.com/question/24653072

参考:
https://blog.csdn.net/weixin_46395886/article/details/114434642
https://blog.csdn.net/weixin_42251364/article/details/95462358

例题

题目描述:
from random import choice from Crypto.Util.number import isPrime, sieve_base as primes from flag import flag def myPrime(bits): while True: n = 2 while n.bit_length() < bits: n *= choice(primes) if isPrime(n + 1): return n + 1 e = 0x10001 m = int.from_bytes(flag.encode(), 'big') p = myPrime(2048) q = getPrime(2048) n = p * q c = pow(m, e, n) # n = 1224542620373200232525165378018470774334801515191193204875465445916504222883935188890019876845076388385357911730689547124547346252951158814249284724565588433721828377715469374541007756509231399263095022024229078845538543233785364809917406108015271780070196140628158427541531563472532516237632553353655535922926443707617182025475004547531104052989085765070550150028833424395972178427807901747932614235844448614858629761183210600428438018388051958214596857405813088470933109693499438012040822262549119751099008671892966082341548512112435591881692782766559736840448702039918465573051130405935280702181505538733234675792472428666968900055706926735800561218167237812066851519973807203332801575980055838563085817664973968944323258406789203078387708964307931318918136664885818917720073433998810127482159223895026085726623747340692196977140382318293090736558135980651252533606603312148824142669800602887109353065489282386215179238458743567166284295855288783740314247952124965482197632971993708775190564519250754150756867653033527903848903210074426177258586450311109023467944412194124015505951966140443860862968311560843608415723549525497729679097936310538451467530605937684408079363677707513923579164067808729408365886209340192468399685190639 # c = 145742860621666495489510776707734134231023214235535481878205099324276369445463746101469487674333600296204530932386373415987357363515200117271393133347844479863240936801112306080456942844796779477817786176831015954410967693647534326733641573842953783193563678040093734579772976410574013857063137696465850300484753282472377882118892522844694078667622111244886303620349388556315704648609353412177123230438077637042880490566244740468503369707900343076369151796123461132932226563486870411965536062339169788331659119981901553536009275158600580698576110294775989992794065611215170351808698605911258789407992833170968332058255364527244293283228694886707241979238145252395651417561576433516407782575454294499521347378058366557950770592472271985004818847838711060048422015207674862177145761946560579360220239667890707135827136815780729363013864130107808776517514214310689477005999830284272130148939734935547341627208913181919190392205389452185597444280635342938046191904062547803917870268485346888653569349729643793041018550170090471310374856687407102762116819004790791936814214507908374380597027347007448114684844276041116955473180015221164545212550832233007714133699817366745648092776901013502840540012912660742166994968977400188176557657864
思路

p-1光滑

exp
from Crypto.Util.number import long_to_bytes import gmpy2 N = 1224542620373200232525165378018470774334801515191193204875465445916504222883935188890019876845076388385357911730689547124547346252951158814249284724565588433721828377715469374541007756509231399263095022024229078845538543233785364809917406108015271780070196140628158427541531563472532516237632553353655535922926443707617182025475004547531104052989085765070550150028833424395972178427807901747932614235844448614858629761183210600428438018388051958214596857405813088470933109693499438012040822262549119751099008671892966082341548512112435591881692782766559736840448702039918465573051130405935280702181505538733234675792472428666968900055706926735800561218167237812066851519973807203332801575980055838563085817664973968944323258406789203078387708964307931318918136664885818917720073433998810127482159223895026085726623747340692196977140382318293090736558135980651252533606603312148824142669800602887109353065489282386215179238458743567166284295855288783740314247952124965482197632971993708775190564519250754150756867653033527903848903210074426177258586450311109023467944412194124015505951966140443860862968311560843608415723549525497729679097936310538451467530605937684408079363677707513923579164067808729408365886209340192468399685190639 c = 145742860621666495489510776707734134231023214235535481878205099324276369445463746101469487674333600296204530932386373415987357363515200117271393133347844479863240936801112306080456942844796779477817786176831015954410967693647534326733641573842953783193563678040093734579772976410574013857063137696465850300484753282472377882118892522844694078667622111244886303620349388556315704648609353412177123230438077637042880490566244740468503369707900343076369151796123461132932226563486870411965536062339169788331659119981901553536009275158600580698576110294775989992794065611215170351808698605911258789407992833170968332058255364527244293283228694886707241979238145252395651417561576433516407782575454294499521347378058366557950770592472271985004818847838711060048422015207674862177145761946560579360220239667890707135827136815780729363013864130107808776517514214310689477005999830284272130148939734935547341627208913181919190392205389452185597444280635342938046191904062547803917870268485346888653569349729643793041018550170090471310374856687407102762116819004790791936814214507908374380597027347007448114684844276041116955473180015221164545212550832233007714133699817366745648092776901013502840540012912660742166994968977400188176557657864 e=0x10001 a = 2 n = 2 while True: a = pow(a, n, N) res = gmpy2.gcd(a-1, N) if res != 1 and res != N: q = N // res print("n=",n) print("p=",res) print("q=",q) break n += 1 d=gmpy2.invert(e,(res-1)*(q-1)) m=pow(c,d,N) print(long_to_bytes(m)) ''' n= 133886 p= 45130782138821231634664822924606644347274161463663927387578931639175223286413378324882645031302403289842551326638702711998962760517679897418281467484531163375644705075213662848721478455926415639437965574871053673938130437463383431907231224801316309790287364751279984404056565040242248326224648040650860211493169850992812996172453840449200075853777085801648416876006333273306936825124410389797307488083056497244608773881660250930270420195391832629035158125925203262309579280388854014294622011159984832956422300816768157089660974628522818677622546453173413252374696944407138466146678080076210538578674319834619518810099 q= 27133201826782787338788885538563732050067785079196618026454235897868264402536516245031880579740961666763959642172487828749683336174380429423638470124438236289474493719405224666020742788644342891080103170383682053753402350082067755810829483788323620956892138666182312174530858835841714425340710526533871025880128823919369953750404747716502172704317611363408005100341125496504953860605809981344626170471389827352246933616925177049855240555455043739991896470800410920936392150801239780661549213774648281839513367454139627656727660863790999536886172951067182613041659292395816579186408742407756713839335479437749412765461 b'flag{Pollard_s_p-1_&_William_s_p+1}' '''

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/17069448.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(2466)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示