威尔逊定理
数论四大定理之一
威尔逊定理是以英格兰数学家爱德华·华林的学生约翰·威尔逊命名的,尽管这对师生未能给出证明。华林于1770年提出该定理,1773年由拉格朗日首次证明。威尔逊定理是判定一个自然数是否为素数的充分必要条件,它也是数论四大定理(威尔逊定理、欧拉定理、孙子定理、费马小定理)之一。
18世纪中叶,约翰·威尔逊发现了一个极为罕见的关系:取从1到某个质数所有连续正整数的乘积,例如从1乘到11,即11的阶乘11!,除去11这个数,得10!。无疑10!不能被11整除。
然而,如果给10!加上1的话,1×2×3×4×5×6×7×8×9×10+1=3628801,怎么也不会想到,3628801却能被11整除(3628801÷11=329891)。类似地,从1到质数7的阶乘7!中略去7,再加上1,得1×2×3×4×5×6+1=721,721也能被7整除(721÷7=103)。那么其他的质数是不是也有这样的规律呢?
威尔逊定理可以简述为:
当p为质数时,(p-1)!+1能被p整除。
威尔逊定理逆定理可以简述为:
若一个数 (p-1)!+1 能被 p 整除,那么 p 为质数。
在rsa中的应用
例题:[RoarCTF2019]babyRSA
题目:
import sympy
import random
def myGetPrime():
A= getPrime(513)
print(A)
B=A-random.randint(13,15)
print(B)
return sympy.nextPrime((B!)%A)
p=myGetPrime()
#A1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467234407
#B1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467140596
q=myGetPrime()
#A2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858418927
#B2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858351026
r=myGetPrime()
n=p*q*r
#n=85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733
c=pow(flag,e,n)
#e=0x1001
#c=75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428
#so,what is the flag?
首先根据题意得:
p = sympy.nextPrime((B1!)%A1)
q = sympy.nextPrime((B2!)%A2)
又,B和A都是素数,根据威尔逊定理可得:
( A1 -1 )! ≡ -1 ( mod A1 )
( B1 -1 )! ≡ -1 ( mod B1 )
( A2 -1 )! ≡ -1 ( mod A2 )
( B2 -1 )! ≡ -1 ( mod B2 )
本题的主要部分就是(B!)%A,然后由于B很大B!不易求解,此时想到运用威尔逊定理,即(A-1)!=-1modA,那么这个式子就可以转化成B!*k=-1modA,其中k=(A-1)!/B!,等式两边同时乘上
k
−
1
k^{-1}
k−1,即
B
!
m
o
d
A
=
−
k
−
1
m
o
d
A
B! \mod A=-k^{-1} \mod A
B!modA=−k−1modA,这样就求出了(B!)%A,紧接着p和q就出来了。
也就是说威尔逊定理将原本求(B!)%A的难题,转变成了求(A-1)!/B!,而(A-1)!/B!可以理解为从B+1乘到A的乘法,当然这里A是大于B+1的,这点在题目中B等于A减去一个随机数的时候有提现到。
以下是运用威尔逊定理的脚本:
def wision(b, a):
k = 1
for i in range(b+1, a):
k = (k*i) % a
return ((-1)*gmpy2.invert(k, a))%a
通过威尔逊定理求出p,q,r,之后就是RSA密码的常规解密。
p = sympy.nextprime(wision(B1, A2))
q = sympy.nextprime(wision(B2, A2))
r = (n//p)//q
phi = (p-1)*(q-1)*(r-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
但是不知道何种原因,没有得到flag
大佬的代码放一下👇
import sympy
import gmpy2
A1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467234407
B1=21856963452461630437348278434191434000066076750419027493852463513469865262064340836613831066602300959772632397773487317560339056658299954464169264467140596
A2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858418927
B2=16466113115839228119767887899308820025749260933863446888224167169857612178664139545726340867406790754560227516013796269941438076818194617030304851858351026
e=0x1001
c=75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428
n=85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733
def mydecrypt(A,B):
ans=1
temp=gmpy2.powmod(-1,1,A)
#print(temp)
for i in range(B+1,A):
ans=(ans*gmpy2.invert(i,A))%A
return (ans*temp)%A
p=sympy.nextprime(mydecrypt(A1,B1))
q=sympy.nextprime(mydecrypt(A2,B2))
r=n//p//q
phi=(p-1)*(q-1)*(r-1)
d=gmpy2.invert(e,phi)
flag=gmpy2.powmod(c,d,n)
import binascii
print(binascii.unhexlify(hex(flag)[2:]))
目前没看明白哪里的问题
另一道例题
# -*- coding:utf-8 -*-
#Author: Lazzaro
from Crypto.Util.number import getPrime,isPrime
from math import gamma
import random
def nextPrime(n):
n += 2 if n & 1 else 1
while not isPrime(n):
n += 2
return n
def getNewPrime():
A = getPrime(512)
B = nextPrime(A - random.randint(1e4,1e5))
return nextPrime(gamma(B+2)%A)
p = getNewPrime()
q = getNewPrime()
r = getNewPrime()
n = p * q ** 2 * r ** 3
e = 0x10001
c = pow(flag,e,n)
#pA=6814157460586876042804041951834304833424062437744287469257313954502540797027261340622077218188033865281590529907571701131297782609357118357982463723982789
#pB=6814157460586876042804041951834304833424062437744287469257313954502540797027261340622077218188033865281590529907571701131297782609357118357982463723922147
#qA=7145646366857234331692232566211321498245533826533958883943688415057871253511271731661019642050252046201115975396366275083424623329930477623781348477881291
#qB=7145646366857234331692232566211321498245533826533958883943688415057871253511271731661019642050252046201115975396366275083424623329930477623781348477807457
#n=4451906216583258787166698210560165433649728830889954633721198623488802305844782492171757604711145165920462286487680020347239300947225371917344589502941576734875830871998499135120227347066586066943289430156378296665669974728569678779668142712266780949126509440672273927433367293606776081254094682033167575930701870261219046464773708974194213798032346187463443317770758989273370488582862531630356263732232300508706676725203199729764016766683870925164232508407363688370458877688991733322055785233669885166225464068579486683574954699370175267031949720967812902215635630884502987094547523361027411501285252862476410213277925430392164226297316310465146003494714018456407793759170649913180823814850170639706664167149612984905056804131124522209409607977589884632999710708045656852149371030046919242039957767777840304466948549383597755811307383659188216421501912831203089570725388153416013596114462069777713822433178099904907224119
#c=1996198968748552041728429851810599627895157160099076033250854211280074825148767841655949210593646824507865483166496070951130337321360509148527292165245205219296211294789087358959553387392928560150390604911087085313000622842025416521494799132969818997182731021267942464323979261593380113740152841984062184326431879167516288834455296913822921806893572566867611541664848820247889274979245086440402996661226884320574824077910315143756471444347386795428338020162169391827182914043434253974549636668126789355991920452920806351939782281969098470635517019120996509180703896707990501216102290302162705699788457579330150149320348175742131887213742989509004374645723471497302400169849858253644606818874098604333865973357374444445825761600866472906771935670261641342221394488068630591190697667016958881530367047928341661857241378511420562236766886349565409774340321441504290366223243635878057759623855735794209219474650425139791831374
注意,这里的gamma函数即伽马函数
另外,关于欧拉函数,如果
m
=
p
∗
q
m=p*q
m=p∗q,
φ
(
m
)
=
φ
(
p
)
∗
φ
(
q
)
\varphi(m)=\varphi(p)*\varphi(q)
φ(m)=φ(p)∗φ(q)
如果
m
=
p
e
m=p^e
m=pe,其中p是素数,e是正整数,
φ
(
m
)
=
p
e
−
p
e
−
1
\varphi(m)=p^e-p^{e-1}
φ(m)=pe−pe−1,特例e=2,
φ
(
m
)
=
p
∗
(
p
−
1
)
\varphi(m)=p*(p-1)
φ(m)=p∗(p−1)
解题跟上面那道题一样的思路,代码如下:
import sympy
import gmpy2
from Crypto.Util.number import long_to_bytes
e = 0x10001
pA=6814157460586876042804041951834304833424062437744287469257313954502540797027261340622077218188033865281590529907571701131297782609357118357982463723982789
pB=6814157460586876042804041951834304833424062437744287469257313954502540797027261340622077218188033865281590529907571701131297782609357118357982463723922147
qA=7145646366857234331692232566211321498245533826533958883943688415057871253511271731661019642050252046201115975396366275083424623329930477623781348477881291
qB=7145646366857234331692232566211321498245533826533958883943688415057871253511271731661019642050252046201115975396366275083424623329930477623781348477807457
n=4451906216583258787166698210560165433649728830889954633721198623488802305844782492171757604711145165920462286487680020347239300947225371917344589502941576734875830871998499135120227347066586066943289430156378296665669974728569678779668142712266780949126509440672273927433367293606776081254094682033167575930701870261219046464773708974194213798032346187463443317770758989273370488582862531630356263732232300508706676725203199729764016766683870925164232508407363688370458877688991733322055785233669885166225464068579486683574954699370175267031949720967812902215635630884502987094547523361027411501285252862476410213277925430392164226297316310465146003494714018456407793759170649913180823814850170639706664167149612984905056804131124522209409607977589884632999710708045656852149371030046919242039957767777840304466948549383597755811307383659188216421501912831203089570725388153416013596114462069777713822433178099904907224119
c=1996198968748552041728429851810599627895157160099076033250854211280074825148767841655949210593646824507865483166496070951130337321360509148527292165245205219296211294789087358959553387392928560150390604911087085313000622842025416521494799132969818997182731021267942464323979261593380113740152841984062184326431879167516288834455296913822921806893572566867611541664848820247889274979245086440402996661226884320574824077910315143756471444347386795428338020162169391827182914043434253974549636668126789355991920452920806351939782281969098470635517019120996509180703896707990501216102290302162705699788457579330150149320348175742131887213742989509004374645723471497302400169849858253644606818874098604333865973357374444445825761600866472906771935670261641342221394488068630591190697667016958881530367047928341661857241378511420562236766886349565409774340321441504290366223243635878057759623855735794209219474650425139791831374
def wision(a,b):
k = 1
for i in range(b+1, a):
k = (k*i) % a
return ((-1)*gmpy2.invert(k, a))%a
p = sympy.nextprime(wision(pA, pB+1))
q = sympy.nextprime(wision(qA, qB+1))
r = gmpy2.iroot(n//(p*q**2), 3)[0]
phi = (p-1)*q*(q-1)*(r**3-r**2)
d = gmpy2.invert(e, phi)
m = gmpy2.powmod(c, d, n)
print(long_to_bytes(m))
这次没问题可以得到flag
但是还是不知道上面那道错哪了