题目
import sympy
import random
def myGetPrime():
A= getPrime(513)
print(A)
B=A-random.randint(1e3,1e5)
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?
解题思路
- 这里要解决的问题是先求出d
- 要求d就要知道 φ ( n ) \varphi(n) φ(n)是多少
- 题目给出的 n = p ∗ q ∗ r n = p * q * r n=p∗q∗r
- 那么 φ ( n ) = ( p − 1 ) ∗ ( q − 1 ) ∗ ( r − 1 ) \varphi(n) = (p - 1) * (q - 1) * (r - 1) φ(n)=(p−1)∗(q−1)∗(r−1)
- 题目只给出了 p q r pqr pqr的取值方法,定义了一个myGetPrime函数
def myGetPrime():
A= getPrime(513)
print(A)
B=A-random.randint(1e3,1e5)
print(B)
return sympy.nextPrime((B!)%A)
- 这里值得注意的是
B!
这里的B!应该是个伪代码,代表的是B的阶乘
由此猜测是一个有关 威尔逊定理 \textcolor{red}{威尔逊定理} 威尔逊定理的求解过程
- 威尔逊定理 ( 本题的关键所在 ) \textcolor{red}{威尔逊定理}{(本题的关键所在)} 威尔逊定理(本题的关键所在)
若 p p p为质数,则 p p p可整除 ( p − 1 ) ! + 1 (p-1)!+1 (p−1)!+1。
如: 7 7 7为质数,则 7 7 7可整除 ( 7 − 1 ) ! + 1 = 721 (7 - 1)! + 1 = 721 (7−1)!+1=721,即 721 721 % 7 == 0 721。
( p − 1 ) ! ≡ − 1 ( m o d p ) \textcolor{red}{(p - 1)! ≡ -1\pmod p} (p−1)!≡−1(modp)
- 继续解题,这时 B ! B! B!可表示为下面的式子
x = r a n d o m . r a n d i n t ( 1 e 3 , 1 e 5 ) B ! = ( A − x ) ! \begin{align}x&={random.randint(1e3, 1e5)} \\ B!&= (A - x)!\end{align} xB!=random.randint(1e3,1e5)=(A−x)!
- 再来将威尔逊定理根据本题进行套入
( A − 1 ) ! ≡ − 1 ( m o d A ) A ∣ ( ( A − 1 ) ! + 1 ) \begin{align}(A-1)!&\equiv-1\pmod{A}\\ A&\mid((A-1)!+1)\end{align} (A−1)!A≡−1(modA)∣((A−1)!+1)
- 这里 ( A − 1 ) ! (A-1)! (A−1)!可以表示为下面的式子,其中 k k k就是 B + 1 B+1 B+1到 A − 1 A-1 A−1的连乘
k = ∏ i = B + 1 A − 1 i ( A − 1 ) ! = B ! ∗ k B ! = ( A − 1 ) ! k \begin{align}k&=\prod_{i=B+1}^{A-1}i\\ (A-1)!&=B!*k\\ B!&=\frac{(A-1)!}k\end{align} k(A−1)!B!=i=B+1∏A−1i=B!∗k=k(A−1)!
- 题目中myGetPrime()函数的返回值就可以表示为
B ! % A ( A − 1 ) ! k % A \begin{align} B!\%A\\ \frac{(A-1)!}k\%A \end{align} B!%Ak(A−1)!%A
- 将式(3)进行变换出 B ! % A B!\%A B!%A的等式
( A − 1 ) ! ≡ − 1 ( m o d A ) B ! ∗ k ≡ − 1 ( m o d A ) 两边同 时乘以 k − 1 得 B ! ≡ − 1 k ( m o d A ) B ! % A = B ! m o d A = − 1 k m o d A = ( − 1 ∗ k − 1 ) m o d A \begin{align} (A-1)!&\equiv-1\pmod{A}\\ B!*k&\equiv-1\pmod{A}\\ {两边同}&{时乘以}k^{-1}{得}\\ B!&\equiv-\frac{1}{k}\pmod A\\ B!\%A&=B!\mod A=-\frac{1}{k}\mod A\\ &=(-1*k^{-1})\mod A\end{align} (A−1)!B!∗k两边同B!B!%A≡−1(modA)≡−1(modA)时乘以k−1得≡−k1(modA)=B!modA=−k1modA=(−1∗k−1)modA
- 只要求出 ( − 1 ∗ k − 1 ) m o d A (-1*k^{-1})\mod A (−1∗k−1)modA就可以求出myGetPrime()函数的值,这里 ( − 1 ∗ k − 1 ) (-1*k^{-1}) (−1∗k−1)是一个分数,就要引入 模逆元 ( m o d u l a r i n v e r s e ) \textcolor{red}{模逆元(modular{\ }inverse)} 模逆元(modular inverse)
( − 1 ∗ k − 1 ) m o d A = ( − 1 ∗ i n v ( k ) ) m o d A \begin{align} &(-1*k^{-1})\mod A\\ =&(-1*{inv}(k))\mod A \end{align} =(−1∗k−1)modA(−1∗inv(k))modA
- 构造出求 p p p、 q q q值的代码
import gmpy2
k = gmpy2.mpz(1)
b = gmpy2.mpz()
a = gmpy2.mpz()
result_prime= gmpy2.mpz()
for i in range(b + 1, a):
k *= i
result_prime = (-1) * gmpy2.invert(k, a) % a
print("this prime is : ", result_prime)
- 利用脚本依次求出 p p p、 q q q
root@1ad9c6992813:~# python w20230819.py
this prime is : 1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654630
root@1ad9c6992813:~# python w20230819.py
this prime is : 13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015568
- 计算出 r r r
root@1ad9c6992813:~# python
Python 3.10.1 (main, Dec 21 2021, 09:01:08) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gmpy2
>>> p = gmpy2.mpz(127651942439721645516079103262056939284578100561656197980940338559376161567042642303976271629192214548359656555809123127361539475238435285654630)
>>> q = gmpy2.mpz(13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015568)
>>> n = gmpy2.mpz(85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733)
>>> r = n // p // q
>>> r
mpz(50575720942372081278677540081347395037179278657503188949824042876567478955730758811860308405581211346537939162249248227360838398463672428862070344252571377492628216)
>>>
- 计算出 φ ( n ) \varphi(n) φ(n)
>>> phi_n = (p - 1) * (q - 1) * (r - 1)
>>> phi_n
mpz(85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524261662500086713189351877929249618455565341072649463764230644607817619080600720421059159778771504021733911447347587831642385970034269463665036258642670661990108390340714654831323613068264155754837019050630866773078863802891460676079678665553977228939143601763997863360656837372249250576503255785163219047647482119567877245)
- 求出 d d d
>>> int('0x1001', 16)
4097
>>> e = gmpy2.mpz(4097)
>>> d = gmpy2.invert(e, phi_n)
>>> d
mpz(3735217675797724504908434710032710235624050383541531234698627373560788563541496322929462828582446539210294604530949800841730503338350746181802010638885897403195993690343100244946594105932207472247323745374506667177820101383839297144276109321545069337373254055159162469156513057369170196982682083531706583106644670443477358852644344670692313903569722328805618920569065418174879456715138877253284040945964740433872074599125177738365336964661022584549499488076648)
>>>
- 解密 c c c
>>> int('0x1001', 16)
4097
>>> e = gmpy2.mpz(4097)
>>> d = gmpy2.invert(e, phi_n)
>>> d
mpz(3735217675797724504908434710032710235624050383541531234698627373560788563541496322929462828582446539210294604530949800841730503338350746181802010638885897403195993690343100244946594105932207472247323745374506667177820101383839297144276109321545069337373254055159162469156513057369170196982682083531706583106644670443477358852644344670692313903569722328805618920569065418174879456715138877253284040945964740433872074599125177738365336964661022584549499488076648)
>>> c = gmpy2.mpz(75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428)
>>> m = gmpy2.powmod(c, d, n)
>>> m
mpz(7426535120827887535518515508089191645957167229414058242044828723895795192208475204629270904331470577052115752123775285672711762717472240127798117839212053319418788167261002201479846869593064376798524686634903556661720094890678277179322220871064162397983551647559709380225632760807662630007810634528437845671270456650898055200813929146989097186009225619170803281599800857130636564877667682856696713697899751072173097117033031003175619429833245406221084386944159)
>>> result_flag = bytes.fromhex(hex(int(m))[2:])
>>> result_flag
b'\xc9\xed =\xfd\x00\xc4\xa8\x0e\xedf\xc5\xb5\xcb\x97\xe3\x17\xcd2\x15\x08U\xdbR\xb1\xef\x97\x97\xc8\xa7\xde\x1a\xe3I\xa8\xc6Bz@+\x04\xe3\xe5\xc05\x0e\x11\r7T`\xe7\xa0^\x99n\xb9\xb8\x93\x89\xddL\x9b\xdf\xdeu\x96\xa9\x13\xdf6wxo\x85\xd0\x1b\xb4\x84\x0c\xaf#x\xc2N\xc2\xf3{\x13\xd2\xe5\xf9\xfb\xe8c\x00\xba\xd7a<<:\x08\x1c\x87\xb6r\xe3v\x0br\xf1\x82\xb1d.\x8au\xc5\x82\x06\x89\xbbh\xee\xac\xf9\xb8:E*\xac\xf0\xaet\xc2\xe8\x0e\xc2j9\xf2\\\x95\x1a\x83\xce-\xec\xabn)\xf5\xf9O\xb1U\xfe\x9c\\\x1d\x11*,n\xf2\xc5\xd8\xf6N\xa1\xa7\xe9h\xa8\xf3:\xa1{\x1a$\x08\xa6j\xaf\xe9\xe0\xa9|d\x9f'
- 上面显示解密是乱码,于是对 p p p、 q q q、 r r r进行素数检查
>>> gmpy2.is_prime(p)
False
>>> gmpy2.is_prime(q)
False
>>> gmpy2.is_prime(r)
False
- 问题又回到阶乘那里,怀疑是 伽马函数 ( G a m m a F u c t i o n ) \textcolor{red}{伽马函数(Gamma\ Fuction)} 伽马函数(Gamma Fuction)
伽马函数是阶乘在实数集上的拓展,有以下性质
(一)递归性
Γ ( x + 1 ) = x Γ ( x ) \begin{align} \Gamma(x+1)=x\Gamma(x) \end{align} Γ(x+1)=xΓ(x)
(二)对于整数n
Γ ( n ) = ( n − 1 ) ! \begin{align} \Gamma(n)=(n-1)! \end{align} Γ(n)=(n−1)!
(三)特殊的几个伽马函数
Γ ( 1 ) = 1 Γ ( 1 2 ) = π Γ ( 1 − x ) Γ ( x ) = π sin π x { x ∣ x ∈ ( 0 , 1 ) } \begin{align} \Gamma(1)&=1\\ \Gamma(\frac{1}{2})&=\sqrt{\pi}\\ \Gamma(1-x)\Gamma(x)&=\frac{\pi}{\sin {\pi x}}\set {x |x\in(0,1)} \end{align} Γ(1)Γ(21)Γ(1−x)Γ(x)=1=π=sinπxπ{x∣x∈(0,1)}
- 感觉不像
- 再读题发现myGetPrime()函数返回的是一个sympy.nextPrime()的值,只求出B!%A就可以了
- 要再进行一次求下一个素数的步骤,为了和题目保持结果一致,还必须用sympy库求解
- 尝试求 p p p、 q q q
>>> ps = sympy.nextprime(p)
>>> ps
127651942439721645516079103262056939284578100561656197980940338559376161567042642303976271629192214548359656555809123127361539475238435285655591
>>> qs = sympy.nextprime(q)
>>> qs
13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015751
- 再求一下r
>>> rs = n // ps // qs
>>> rs
mpz(50575720942372081278677540081347395037179278657503188949824042876567478955730758811860308405581211346537939162249248227360838398463672428861689595891858733620654734)
- 一眼看出r不是素数,并且还是个大数,头大
>>> gmpy2.is_prime(rs)
False
>>> len('50575720942372081278677540081347395037179278657503188949824042876567478955730758811860308405581211346537939162249248227360838398463672428861689595891858733620654734')
164
- 以上错误,又继续检查myGetPrime()函数,发现自己犯了一个最基本的错误
- 这里要回顾一下模运算的运算规则, 基础不牢地动山摇 \textcolor{red}{基础不牢地动山摇} 基础不牢地动山摇
模运算的基本运算
( a + b ) % p = ( a % p + b % p ) % p ( a − b ) % p = ( a % p − b % p ) % p ( a ∗ b ) % p = ( a % p ∗ b % p ) % p ( a b ) % p = ( ( a % p ) b ) % p \begin{align} (a+b) \% p & = (a \% p+b \% p)\%p\\ (a-b)\%p&=(a\%p-b\%p)\%p\\ (a*b)\%p&=(a\%p*b\%p)\%p\\ (a^b)\%p&=((a\%p)^b)\%p \end{align} (a+b)%p(a−b)%p(a∗b)%p(ab)%p=(a%p+b%p)%p=(a%p−b%p)%p=(a%p∗b%p)%p=((a%p)b)%p
结合律
( ( a + b ) % p + c ) % p = ( a + ( b + c ) % p ) % p ( ( a ∗ b ) % p ∗ c ) % p = ( a ∗ ( b ∗ c ) % p ) % p \begin{align} ((a+b)\%p+c)\%p&=(a+(b+c)\%p)\%p\\ ((a*b)\%p*c)\%p&=(a*(b*c)\%p)\%p \end{align} ((a+b)%p+c)%p((a∗b)%p∗c)%p=(a+(b+c)%p)%p=(a∗(b∗c)%p)%p
交换律
( a + b ) % p = ( b + a ) % p ( a ∗ b ) % p = ( b ∗ a ) % p \begin{align} (a+b)\%p&=(b+a)\%p\\ (a*b)\%p&=(b*a)\%p \end{align} (a+b)%p(a∗b)%p=(b+a)%p=(b∗a)%p
分配律
( a + b ) % p = ( a % p + b % p ) % p ( a ∗ b ) % p = ( a % p ∗ b % p ) % p \begin{align} (a+b)\%p&=(a\%p+b\%p)\%p\\ (a*b)\%p&=(a\%p*b\%p)\%p \end{align} (a+b)%p(a∗b)%p=(a%p+b%p)%p=(a%p∗b%p)%p
- 错误出在了我求 p p p、 q q q值的代码处
- 因为 k k k在本题中是一个连续相乘的数,所以要用到分配律
( − 1 ∗ i n v ( k ) ) m o d A = ( ( − 1 ) m o d A ∗ ( i n v ( k ) m o d A ) ) m o d A k = ( B + 1 ) ∗ ( B + 2 ) ⋯ ∗ ( A − 1 ) i n v ( k ) = ( B + 1 ) ′ ∗ ( B + 2 ) ′ ⋯ ∗ ( A − 1 ) ′ \begin{align} &(-1*{inv}(k))\mod A\\ =&((-1)\mod A *(inv(k)\mod A))\mod A\\ k=&(B+1)*(B+2)\dots*(A-1)\\ inv(k)=&(B+1)\rq*(B+2)\rq\dots*(A-1)\rq\\ \end{align} =k=inv(k)=(−1∗inv(k))modA((−1)modA∗(inv(k)modA))modA(B+1)∗(B+2)⋯∗(A−1)(B+1)′∗(B+2)′⋯∗(A−1)′
- 这里的重磅炸弹要出来了
i n v ( k ) m o d A ( ( … ( ( B + 1 ) ′ m o d A ) ∗ ( ( B + 2 ) ′ ∗ m o d A ) m o d A ) ∗ ( ( B + 3 ) ′ m o d A ) … ) \\ ∗ ( A − 1 ) ′ m o d A ) m o d A \begin{align} inv(k)\mod A&\\ ((\dots((B+1)\rq\mod A)&*((B+2)\rq*\mod A)\mod A)*((B+3)\rq\mod A)\dots)\text{\textbackslash}\text{\textbackslash}\\ *(A-1)\rq\mod A)\mod A\\ \end{align} inv(k)modA((…((B+1)′modA)∗(A−1)′modA)modA∗((B+2)′∗modA)modA)∗((B+3)′modA)…)\\ - 对,您没看错,上式是一个递归,从 ( B + 1 ) 到 ( A − 1 ) 的一个递归 \textcolor{red}{对,您没看错,上式是一个递归,从(B+1)到(A-1)的一个递归} 对,您没看错,上式是一个递归,从(B+1)到(A−1)的一个递归
- 就是前两个数 m o d A \mod A modA后的值相乘后 m o d A \mod A modA再乘以第三个数 m o d A \mod A modA的值再 m o d A \mod A modA,一直到最后一个数 ( A − 1 ) (A-1) (A−1),神奇吧!这就是 模运算的乘法分配律 \textcolor{red}{模运算的乘法分配律} 模运算的乘法分配律,我不会写递归,随便写了一个for循环来求 p p p、 q q q的值,代码如下:
import gmpy2
'''
连乘:Product of a sequence
此脚本是为k^(-1) % a求解的
题目是[RoarCTF2019]babyRSA 1
用到逆元就是因为是k分之一
原题是B!% A
'''
k = gmpy2.mpz() # k是从B+1到A-1的连乘
b = gmpy2.mpz()
a = gmpy2.mpz()
solve_number = gmpy2.mpz()
k_prod_inverse = gmpy2.mpz(1) # k在连乘时的逆元取a模的值,在乘法中初始值要为1
for i in range(b + 1, a):
k = i
k_prod_inverse *= gmpy2.invert(k, a)
k_prod_inverse = k_prod_inverse % a
solve_prime = (gmpy2.powmod(-1, 1, a) * (k_prod_inverse)) % a
print("this prime is : ", solve_prime)
root@1ad9c6992813:~# python w20230820.py
this number is : 1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654630
>>> import gmpy2
>>> p = gmpy2.next_prime(1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654630)
>>> p
mpz(1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654851)
root@1ad9c6992813:~# python w20230820.py
this number is : 13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015568
>>> import gmpy2
>>> q = gmpy2.mpz(13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015568)
>>> q
mpz(13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015751)
- 求出r,并对r进行检测
>>> n = gmpy2.mpz(85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733)
>>> r = n // p // q
>>> r
mpz(5057572094237208127867754008134739503717927865750318894982404287656747895573075881186030840558129423864679886646066477437020450654848839861455661385205433)
>>> gmpy2.is_prime(r)
True
- 接下来是求RSA的常规操作
>>> import gmpy2
>>> p = gmpy2.next_prime(1276519424397216455160791032620569392845781005616561979809403385593761615670426423039762716291920053306063214548359656555809123127361539475238435285654630)
>>> q = gmpy2.next_prime(13242175493583584108411324143773780862426183382017753129633978933213674770487765387985282956574197274056162861584407275172775868763712231230219112670015568)
>>> n = gmpy2.mpz(85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659153047067908693481947121069070451562822417357656432171870951184673132554213690123308042697361969986360375060954702920656364144154145812838558365334172935931441424096270206140691814662318562696925767991937369782627908408239087358033165410020690152067715711112732252038588432896758405898709010342467882264362733)
>>> r = n // p // q
>>> r
mpz(5057572094237208127867754008134739503717927865750318894982404287656747895573075881186030840558129423864679886646066477437020450654848839861455661385205433)
>>> int('0x1001', 16)
4097
>>> e = gmpy2.mpz(4097)
>>> phi_n = (p - 1) * (q - 1) * (r - 1)
>>> phi_n
mpz(85492663786275292159831603391083876175149354309327673008716627650718160585639723100793347534649628330416631255660901307533909900431413447524262332232659062713827407933971258338819717575826393589291226891275723240854297237063167543315323410169284149454935881830514929106591884721185659799505175805833129963674096886869134897417685204723806976501422786234768583723127859660724360988007544053893841342044711333390914379772379095795795096664437102284125564036900000)
>>> gmpy2.gcd(e, phi_n)
mpz(1)
>>> d = gmpy2.invert(e, phi_n)
>>> d
mpz(23245991568931089935575398139533179902151911325504278186895368123724684132878362590745372016987963378102056924287587028702166372731411906405181410326380814220943063812165970658883369631308421395770179828382024820676516261188276456737434776404340381374859304944884947772697915445301641449023374627214573292539161320959779418043275889202421521069705878414823578781441160766914068377017428380775625886023385019623499784980822629415795884228504498888092721097658433)
>>> c = gmpy2.mpz(75700883021669577739329316795450706204502635802310731477156998834710820770245219468703245302009998932067080383977560299708060476222089630209972629755965140317526034680452483360917378812244365884527186056341888615564335560765053550155758362271622330017433403027261127561225585912484777829588501213961110690451987625502701331485141639684356427316905122995759825241133872734362716041819819948645662803292418802204430874521342108413623635150475963121220095236776428)
>>> m = gmpy2.powmod(c, d, n)
>>> m
mpz(49562188096458630410563044417358818341913265571373725266976612126526106528404944745044614126232074073813936259453)
>>> flag = bytes.fromhex(hex(int(m))[2:])
>>> flag
b'RoarCTF{wm-CongrAtu1ation4-1t4-ju4t-A-bAby-R4A}'
>>>
总结
这道题有两个考点:一、对数论四大定理之一的“威尔逊定理”的掌握,二、对模运算规律的掌握。
中间踩了很多坑,算是对基础知识的再掌握了。
这里参考了咸鱼壹号的答题思路。
- 经过尝试求解 p p p、 q q q的python代码,只能说数字太大,并且python也不适合写递归,就这样吧。
import gmpy2
import sys
sys.setrecursionlimit(100000) # 设置python的递归深度,不然只能到1000层(实际只有996)
def wilson_solve(n, a, b, k_prod_inverse = 1):
if n == a
return k_prod_inverse % a
else
k = b + 1
k_prod_inverse *= gmpy2.invert(k, a) % a
k_prod_inverse = k_prod_inverse % a
wilson_solve(n + 1, a, b, k_prod_inverse)
a = gmpy2.mpz()
b = gmpy2.mpz()
k_prod_inverse = gmpy2.mpz(1)
result_number = wilson_solve(a, a, b, k_prod_inverse)
print("this number is:", result_number)