from Crypto.Util.number import *
flag=bytes_to_long(b'Neepu{xxx}')
N = 7389313481223384214994762619823300589978423075857540712007981373887018860174846208000957230283669342186460652521580595183523706412588695116906905718440770776239313669678685198683933547601793742596023475603667
m = 1391372358062724416224243990838035874507346098208831800403257
n = 3583006200974501742604527103814726194237416368238514877166633691321127310414088215607009332255751700661232767709290883038406749484575415867828156201338536386376279995491732514052716934519151026884616917483040
l = 359786222110993880715372696002813612045630045754565831162281874392294886391569010600976425535545860799388851419768061619942493351122730748490893471593987207207967996028533058621192187630928610989765004439777
c = (110 * pow(m, flag, N) +313 * pow(n, flag, N) + 114 * pow(l, flag, N)) % N
print(c)
'''
c = 1895030805615627998889733471639619972225091175824712353587361803906002039112746104833908879918848049981737808710773335455541140252543329151696420250885361493998408542681830779056032193286985350503581777508964
'''
可以知道
m ∗ n m o d N = 1 m * n \mod N = 1 m∗nmodN=1
m 2 ∗ l m o d N = 1 m^{2} * l \bmod N = 1 m2∗lmodN=1
那么
n = m − 1 m o d N n = m ^ {-1} \mod N n=m−1modN
l = m − 2 m o d N l = m ^ {-2} \mod N l=m−2modN
得到
c = 110 ∗ m f + 313 ∗ m − f + 114 ∗ m − 2 f c = 110 * m ^ {f} + 313 * m ^ {-f} + 114 * m ^ {-2f} c=110∗mf+313∗m−f+114∗m−2f
(此处将 mod N省掉了,看起来简洁一些)
所以直接将 m f m^{f} mf看成未知数x,解方程即可得到 m f m^{f} mf,代码如下:
# sage
N = 7389313481223384214994762619823300589978423075857540712007981373887018860174846208000957230283669342186460652521580595183523706412588695116906905718440770776239313669678685198683933547601793742596023475603667
m = 1391372358062724416224243990838035874507346098208831800403257
n = 3583006200974501742604527103814726194237416368238514877166633691321127310414088215607009332255751700661232767709290883038406749484575415867828156201338536386376279995491732514052716934519151026884616917483040
l = 359786222110993880715372696002813612045630045754565831162281874392294886391569010600976425535545860799388851419768061619942493351122730748490893471593987207207967996028533058621192187630928610989765004439777
c = 1895030805615627998889733471639619972225091175824712353587361803906002039112746104833908879918848049981737808710773335455541140252543329151696420250885361493998408542681830779056032193286985350503581777508964
from Crypto.Util.number import *
P.<x> = PolynomialRing(Zmod(N))
f=110*x^3-c*x^2+313*x+114
f=f.monic()
print(f.roots())
之后发现N-1是光滑数,这样的话便可利用discrete_log()函数进行求解
- 为什么N-1光滑便能利用discrete_log()函数进行求解呢?
想知道这个那么就得先知道何为光滑数光滑数 (Smooth number):指可以分解为小素数乘积的正整数
- 此处N-1能分解为很多小素数
- 现在来聊聊discrete_log()函数的实现原理:
discrete_log()是借助Pohlig-Hellman 算法实现的
总结:Pohlig-Hellman 算法的核心思想是利用 Lagrange 定理将一个大的离散对数问题转化为多个小的离散对数问题,再利用中国剩余定理将这些小的离散对数问题合并为原问题的解。(前面部分不理解没什么大问题,说实话,我目前阶段也不太理解,但总结部分得知道)
解题代码一(繁琐版):
N =7389313481223384214994762619823300589978423075857540712007981373887018860174846208000957230283669342186460652521580595183523706412588695116906905718440770776239313669678685198683933547601793742596023475603667
m = 1391372358062724416224243990838035874507346098208831800403257
n =3583006200974501742604527103814726194237416368238514877166633691321127310414088215607009332255751700661232767709290883038406749484575415867828156201338536386376279995491732514052716934519151026884616917483040
l =359786222110993880715372696002813612045630045754565831162281874392294886391569010600976425535545860799388851419768061619942493351122730748490893471593987207207967996028533058621192187630928610989765004439777
c =1895030805615627998889733471639619972225091175824712353587361803906002039112746104833908879918848049981737808710773335455541140252543329151696420250885361493998408542681830779056032193286985350503581777508964
print(factor(N-1))
from Crypto.Util.number import *
P.<x> = PolynomialRing(Zmod(N))
f=110*x^3-c*x^2+313*x+114
f=f.monic()
print(f.roots())
a=2275123956203765363233765961297507379124236980967603145079239177208264523438555378298177602517599708533004805369986246098127863480798528206818576888655427591685534478161571717613561380234338516607855593046949
fac = [2, 136327, 169937, 313351, 321427, 323377,356887, 413783, 519733,792413, 860077, 906289, 976501]
G=Zmod(N)
m1=G(m)
c1=G(a)
oo=[]
for i in fac:
h=(N-1)//i
dlp1=discrete_log(c1**h,m1**h)
oo.append(int(dlp1))
sk=crt(oo,fac)
mod = prod(fac)
for i in range(100):
print(long_to_bytes(int(sk + i * mod)))
#Neepu{Nsmoothnumber}
m = 1391372358062724416224243990838035874507346098208831800403257
a=2275123956203765363233765961297507379124236980967603145079239177208264523438555378298177602517599708533004805369986246098127863480798528206818576888655427591685534478161571717613561380234338516607855593046949
G=Zmod(N)
m1=G(m)
c1=G(a)
print(long_to_bytes(ZZ(discrete_log(c1,m1))))
# Neepu{Nsmoothnumber}
浅记一下①②如何得出来的:
m ∗ n m o d N = 1 m * n \mod N = 1 m∗nmodN=1 ①
m 2 ∗ l m o d N = 1 m^{2} * l \bmod N = 1 m2∗lmodN=1 ②
这里通过 d i s c r e t e l o g ( ) 来求解 : 这里通过discretelog()来求解: 这里通过discretelog()来求解:
设 n 1 , l 1 , 使: 设n1,l1,使: 设n1,l1,使:
m n 1 ≡ n ( m o d N ) m^{n1} \equiv n \pmod{N} mn1≡n(modN)
m l 1 ≡ l ( m o d N ) m^{l1} \equiv l \pmod{N} ml1≡l(modN)
那么: 那么: 那么:
n 1 = d i s c r e t e _ l o g ( n , m ) n1 = discrete\_log(n,m) n1=discrete_log(n,m)
l 1 = d i s c r e t e _ l o g ( l , m ) l1 = discrete\_log(l,m) l1=discrete_log(l,m)
s a g e m e n t 中解 , 得到: sagement中解,得到: sagement中解,得到:
n 1 = N − 2 n1 = N - 2 n1=N−2
l 1 = N − 3 l1 = N - 3 l1=N−3
通过欧拉定理: 通过欧拉定理: 通过欧拉定理:
m N − 1 ≡ 1 ( m o d N ) m^{N-1} \equiv 1 \pmod{N} mN−1≡1(modN)
m N − 2 ≡ m − 1 ( m o d N ) ≡ n ( m o d N ) m^{N-2} \equiv m^{-1} \pmod{N} \equiv n \pmod{N} mN−2≡m−1(modN)≡n(modN)
m N − 3 ≡ m − 2 ( m o d N ) ≡ l ( m o d N ) m^{N-3} \equiv m^{-2} \pmod{N} \equiv l \pmod{N} mN−3≡m−2(modN)≡l(modN)
所以: 所以: 所以:
m ∗ n m o d N = 1 m * n \mod N = 1 m∗nmodN=1
m 2 ∗ l m o d N = 1 m^{2} * l \bmod N = 1 m2∗lmodN=1
还得说一下光滑数那里,遇到这题之后,就看了很多光滑数的资料,印象最深的是Pollard’s p-1光滑(后方上题)
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
- choice() :
Python 中的一个函数,它可以从一个序列中随机选择一个元素作为结果返回- choice(primes):
primes是Crypto.Util.number模块中定义的前10000个质数
import gmpy2
from Crypto.Util.number import *
e = 0x10001
N = 1224542620373200232525165378018470774334801515191193204875465445916504222883935188890019876845076388385357911730689547124547346252951158814249284724565588433721828377715469374541007756509231399263095022024229078845538543233785364809917406108015271780070196140628158427541531563472532516237632553353655535922926443707617182025475004547531104052989085765070550150028833424395972178427807901747932614235844448614858629761183210600428438018388051958214596857405813088470933109693499438012040822262549119751099008671892966082341548512112435591881692782766559736840448702039918465573051130405935280702181505538733234675792472428666968900055706926735800561218167237812066851519973807203332801575980055838563085817664973968944323258406789203078387708964307931318918136664885818917720073433998810127482159223895026085726623747340692196977140382318293090736558135980651252533606603312148824142669800602887109353065489282386215179238458743567166284295855288783740314247952124965482197632971993708775190564519250754150756867653033527903848903210074426177258586450311109023467944412194124015505951966140443860862968311560843608415723549525497729679097936310538451467530605937684408079363677707513923579164067808729408365886209340192468399685190639
c = 145742860621666495489510776707734134231023214235535481878205099324276369445463746101469487674333600296204530932386373415987357363515200117271393133347844479863240936801112306080456942844796779477817786176831015954410967693647534326733641573842953783193563678040093734579772976410574013857063137696465850300484753282472377882118892522844694078667622111244886303620349388556315704648609353412177123230438077637042880490566244740468503369707900343076369151796123461132932226563486870411965536062339169788331659119981901553536009275158600580698576110294775989992794065611215170351808698605911258789407992833170968332058255364527244293283228694886707241979238145252395651417561576433516407782575454294499521347378058366557950770592472271985004818847838711060048422015207674862177145761946560579360220239667890707135827136815780729363013864130107808776517514214310689477005999830284272130148939734935547341627208913181919190392205389452185597444280635342938046191904062547803917870268485346888653569349729643793041018550170090471310374856687407102762116819004790791936814214507908374380597027347007448114684844276041116955473180015221164545212550832233007714133699817366745648092776901013502840540012912660742166994968977400188176557657864
def Pollards_p_1(N):
n = 2
a = 2
while True:
a = pow(a,n,N)
res = gmpy2.gcd(a-1,N)
print(n)
if res != 1 and res != N:
print('n = ',n)
print('p = ',res)
return
n += 1
p = Pollards_p_1(N)
q = N // p
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,N)
print(long_to_bytes(m))
# flag{Pollard_s_p-1_&_William_s_p+1}