这篇文章用于研究GHCTF2025的题目

CRYPTO

EZ-Fermat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from Crypto.Util.number import getPrime, bytes_to_long
from secret import f

flag = b'NSSCTF{test_flag}'
p = getPrime(512)
q = getPrime(512)
n = p*q

m = bytes_to_long(flag)
e = 65537
c = pow(m,e,n)

R.<x> = ZZ[]
f = R(str(f))

w = pow(2,f(p),n)


print(f'{n = }\n')
print(f'{e = }\n')
print(f'{c = }\n')
print(f'{f = }\n')
print(f'{w = }\n')

'''
n = 101780569941880865465631942473186578520071435753163950944409148606282910806650879176280021512435190682009749926285674412651435782567149633130455645157688819845748439487113261739503325065997835517112163014056297017874761742768297646567397770742374004940360061700285170103292360590891188591132054903101398360047
e = 65537
c = 77538275949900942020886849496162539665323546686749270705418870515132296087721218282974435210763225488530925782158331269160555819622551413648073293857866671421886753377970220838141826468831099375757481041897142546760492813343115244448184595644585857978116766199800311200819967057790401213156560742779242511746
f = 2*x^332 - x^331 + x^329 + 3*x^328 - x^327 - 3*x^325 + x^323 - 3*x^322 - x^321 - 3*x^320 + x^319 + 2*x^318 - 4*x^317 - 3*x^315 - 2*x^314 + x^313 + x^312 + 2*x^311 + 2*x^309 + 2*x^308 + 5*x^307 + 2*x^306 + 3*x^305 + 5*x^304 + 4*x^303 + x^302 - x^301 - x^300 - 2*x^299 - 2*x^298 + x^297 + 3*x^296 - x^295 - 4*x^292 - x^290 + 4*x^289 - x^287 - 3*x^286 + x^285 - 2*x^284 + x^283 - x^282 - 2*x^281 + x^280 - 2*x^279 + x^278 + 2*x^277 - 3*x^276 - x^275 - 4*x^274 - 3*x^273 - 5*x^272 - 2*x^271 - 3*x^270 + 2*x^269 + 2*x^268 - x^267 - 2*x^266 + x^265 + x^264 - 3*x^262 - 3*x^259 + 2*x^258 - x^257 + 2*x^256 + 2*x^255 - x^254 - 2*x^253 - x^252 + 2*x^251 - x^250 + x^249 + 2*x^247 + 2*x^246 + 2*x^245 - 2*x^244 - 3*x^243 + 2*x^242 - 3*x^241 - x^240 - 3*x^239 - x^236 - 3*x^235 - 2*x^234 - x^233 - 2*x^232 - x^231 - 3*x^230 - 2*x^229 - 4*x^228 - 2*x^227 - 3*x^226 + 2*x^225 + x^224 - x^223 - 2*x^221 + 3*x^219 - x^217 - 2*x^216 + x^215 + 2*x^213 - x^212 + 3*x^211 + x^210 + 4*x^209 + x^208 - x^206 - x^205 - x^204 + 2*x^203 - 3*x^202 + 2*x^199 - x^198 + 2*x^196 - 2*x^195 + 3*x^194 + 3*x^193 - x^192 + 4*x^191 + 2*x^189 + x^186 - x^185 - x^184 + 3*x^183 + x^182 + 2*x^181 - 2*x^180 + x^177 + x^175 - x^173 + 3*x^172 + x^170 + x^169 - x^167 - 2*x^166 - x^165 - 4*x^164 - 2*x^163 + 2*x^162 + 4*x^161 - 2*x^160 - 3*x^159 - 2*x^158 - 2*x^157 + x^156 - x^155 + 3*x^154 - 4*x^153 + x^151 + 2*x^150 + x^149 - x^148 + 2*x^147 + 3*x^146 + 2*x^145 - 4*x^144 - 4*x^143 + x^142 - 2*x^140 - 2*x^139 + 2*x^138 + 3*x^137 + 3*x^136 + 3*x^135 + x^134 - x^133 + 2*x^132 + 3*x^130 - 3*x^129 - 2*x^128 - x^127 - 2*x^126 + x^125 + x^124 - 2*x^123 + x^122 - x^121 + 3*x^120 - x^119 - 2*x^118 - x^117 - x^116 - 2*x^115 + 2*x^114 + 2*x^113 - 3*x^112 - x^111 - 4*x^110 + x^109 + x^108 + x^106 - 4*x^105 + x^104 - x^103 - x^101 + x^100 - 2*x^99 + x^98 - x^97 + 3*x^96 + 3*x^94 - x^93 - x^92 + x^91 - 2*x^90 + x^89 - x^88 + x^87 - x^86 + x^85 + x^84 - x^83 + x^79 - 3*x^78 - 2*x^77 + x^74 + 3*x^73 - x^72 - 3*x^71 - 2*x^70 + x^69 - 3*x^66 + x^65 + x^64 - 4*x^62 - x^61 + x^60 - x^59 + 3*x^58 - x^57 - x^54 + 3*x^53 + x^51 - 3*x^50 - x^49 + 2*x^47 - x^46 - x^44 + x^43 - x^42 - 4*x^41 - 3*x^39 - x^37 - x^36 - 3*x^35 + x^34 + x^33 - 2*x^32 + 2*x^31 - x^30 + 2*x^29 - 2*x^28 - 2*x^27 - x^24 + x^22 - 5*x^21 + 3*x^20 + 2*x^19 - x^18 + 2*x^17 + x^16 - 2*x^15 - 2*x^14 + x^13 + x^12 + 2*x^11 - 3*x^10 + 3*x^9 + 2*x^8 - 4*x^6 - 2*x^5 - 4*x^4 + x^3 - x^2 - 1
w = 32824596080441735190523997982799829197530203904568086251690542244969244071312854874746142497647579310192994177896837383837384405062036521829088599595750902976191010000575697075792720479387771945760107268598283406893094243282498381006464103080551366587157561686900620059394693185990788592220509670478190685244

'''

总结题目

n=p*q,n已知,p,q未知

e给定为65537(是个质数)

c=(m^e)%n

到这为止是很标准的公钥加密

但还有信息

f(x)是一个已知多项式

w=(2^f(p))%n且w已知

这部分肯定是入手的关键

模数是可以拆的

\[ 若a≡b\quad(mod\space n),n=k_1k_2...k_u\newline a-b=rn=rk_1k_2...k_u\newline 所以就有\newline \left\{ \begin{aligned} &a≡b\quad(mod\space k_1)\newline &a≡b\quad(mod\space k_2)\newline &...\newline &a≡b\quad(mod\space k_u) \end{aligned} \right. \]

我们可以把同余式模数变成它的因数

这是个很好用的技巧

回到题目 \[ w≡2^{f(p)}≡2^{2*p^{332} - p^{331} + p^{329}...- 4*p^4 + p^3 - p^2 - 1}\quad (mod\space n)\newline 把它拆开\newline w≡2^{f(p)}\quad (mod\space p)\newline w≡2^{f(p)}\quad (mod\space q)\newline \] 我们当然希望未知数少一点,所以以模p为研究对象

同余式不能同取对数,所以肯定不能直接化简

但实际上题目名字就是提示——费马小定理

我们要尽可能在指数上凑出(p-1)

这里要用一个小技巧

多项式一定能用它的根来因式分解(实际上就是高中的技巧,但我已经高中毕业了,所以失忆了😢)

xi-1一定能够分解成(x-1)(...)的形式

所以我们只需要给f(p)的每一个项减去一个系数 \[ 2*p^{332} - p^{331} + p^{329}...- 4*p^4 + p^3 - p^2 - 1\newline =2(p^{332}-1)-(p^{331}-1)+...-(p^2-1)+t\newline =(p-1)g(p)+t\newline g(p)是什么我不用管因为它一定是整数,会被消掉\newline t可以让电脑帮我算\newline 所以\newline w≡2^{f(p)}≡2^{(p-1)g(p)+t}≡2^{t}\quad (mod\space p)\newline \] 再瞪两眼可以发现,t实际上就是f(1)

1
2
3
4
5
x=polygen(ZZ,'x')
f = 2*x^332 - x^331 + x^329 + 3*x^328 - x^327 - 3*x^325 + x^323 - 3*x^322 - x^321 - 3*x^320 + x^319 + 2*x^318 - 4*x^317 - 3*x^315 - 2*x^314 + x^313 + x^312 + 2*x^311 + 2*x^309 + 2*x^308 + 5*x^307 + 2*x^306 + 3*x^305 + 5*x^304 + 4*x^303 + x^302 - x^301 - x^300 - 2*x^299 - 2*x^298 + x^297 + 3*x^296 - x^295 - 4*x^292 - x^290 + 4*x^289 - x^287 - 3*x^286 + x^285 - 2*x^284 + x^283 - x^282 - 2*x^281 + x^280 - 2*x^279 + x^278 + 2*x^277 - 3*x^276 - x^275 - 4*x^274 - 3*x^273 - 5*x^272 - 2*x^271 - 3*x^270 + 2*x^269 + 2*x^268 - x^267 - 2*x^266 + x^265 + x^264 - 3*x^262 - 3*x^259 + 2*x^258 - x^257 + 2*x^256 + 2*x^255 - x^254 - 2*x^253 - x^252 + 2*x^251 - x^250 + x^249 + 2*x^247 + 2*x^246 + 2*x^245 - 2*x^244 - 3*x^243 + 2*x^242 - 3*x^241 - x^240 - 3*x^239 - x^236 - 3*x^235 - 2*x^234 - x^233 - 2*x^232 - x^231 - 3*x^230 - 2*x^229 - 4*x^228 - 2*x^227 - 3*x^226 + 2*x^225 + x^224 - x^223 - 2*x^221 + 3*x^219 - x^217 - 2*x^216 + x^215 + 2*x^213 - x^212 + 3*x^211 + x^210 + 4*x^209 + x^208 - x^206 - x^205 - x^204 + 2*x^203 - 3*x^202 + 2*x^199 - x^198 + 2*x^196 - 2*x^195 + 3*x^194 + 3*x^193 - x^192 + 4*x^191 + 2*x^189 + x^186 - x^185 - x^184 + 3*x^183 + x^182 + 2*x^181 - 2*x^180 + x^177 + x^175 - x^173 + 3*x^172 + x^170 + x^169 - x^167 - 2*x^166 - x^165 - 4*x^164 - 2*x^163 + 2*x^162 + 4*x^161 - 2*x^160 - 3*x^159 - 2*x^158 - 2*x^157 + x^156 - x^155 + 3*x^154 - 4*x^153 + x^151 + 2*x^150 + x^149 - x^148 + 2*x^147 + 3*x^146 + 2*x^145 - 4*x^144 - 4*x^143 + x^142 - 2*x^140 - 2*x^139 + 2*x^138 + 3*x^137 + 3*x^136 + 3*x^135 + x^134 - x^133 + 2*x^132 + 3*x^130 - 3*x^129 - 2*x^128 - x^127 - 2*x^126 + x^125 + x^124 - 2*x^123 + x^122 - x^121 + 3*x^120 - x^119 - 2*x^118 - x^117 - x^116 - 2*x^115 + 2*x^114 + 2*x^113 - 3*x^112 - x^111 - 4*x^110 + x^109 + x^108 + x^106 - 4*x^105 + x^104 - x^103 - x^101 + x^100 - 2*x^99 + x^98 - x^97 + 3*x^96 + 3*x^94 - x^93 - x^92 + x^91 - 2*x^90 + x^89 - x^88 + x^87 - x^86 + x^85 + x^84 - x^83 + x^79 - 3*x^78 - 2*x^77 + x^74 + 3*x^73 - x^72 - 3*x^71 - 2*x^70 + x^69 - 3*x^66 + x^65 + x^64 - 4*x^62 - x^61 + x^60 - x^59 + 3*x^58 - x^57 - x^54 + 3*x^53 + x^51 - 3*x^50 - x^49 + 2*x^47 - x^46 - x^44 + x^43 - x^42 - 4*x^41 - 3*x^39 - x^37 - x^36 - 3*x^35 + x^34 + x^33 - 2*x^32 + 2*x^31 - x^30 + 2*x^29 - 2*x^28 - 2*x^27 - x^24 + x^22 - 5*x^21 + 3*x^20 + 2*x^19 - x^18 + 2*x^17 + x^16 - 2*x^15 - 2*x^14 + x^13 + x^12 + 2*x^11 - 3*x^10 + 3*x^9 + 2*x^8 - 4*x^6 - 2*x^5 - 4*x^4 + x^3 - x^2 - 1
t=f(1)
print(t)

这样可以得到t=-57

所以 \[ w≡2^{-57}\quad (mod\space p)\newline 也就是\newline 2^{57}w≡1\quad (mod\space p)\newline \] 看起来我们已经与p很接近了

我们要注意到,p是(257w-1)和n的公约数

由此就可以直接计算(反正用个函数就能算,管它是用欧几里得算法还是其他什么的我暂且不关心)

1
2
3
4
5
6
from gmpy2 import gcd
w = 32824596080441735190523997982799829197530203904568086251690542244969244071312854874746142497647579310192994177896837383837384405062036521829088599595750902976191010000575697075792720479387771945760107268598283406893094243282498381006464103080551366587157561686900620059394693185990788592220509670478190685244
n = 101780569941880865465631942473186578520071435753163950944409148606282910806650879176280021512435190682009749926285674412651435782567149633130455645157688819845748439487113261739503325065997835517112163014056297017874761742768297646567397770742374004940360061700285170103292360590891188591132054903101398360047
p=gcd(((2**57)*w)-1,n)
q=n//p
print("p=",p,"\n","q=",q)
1
2
p= 10369947696097707510769809078424403635336089844072313788886920079212917663690503014328582816890429888540698699892682697716174207561536836918335963753124197
q= 9814954995402888157895432394154096303205654905130720582279697302830224692863509115591058838613477077284923737126007566425022731944192591349200677124858051

这样p和q已经出来了,我们就能直接把这个RSA的底裤扒干净

所以接下来就是标准的求逆元,算明文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Util.number import long_to_bytes,inverse
from gmpy2 import gcd
w = 32824596080441735190523997982799829197530203904568086251690542244969244071312854874746142497647579310192994177896837383837384405062036521829088599595750902976191010000575697075792720479387771945760107268598283406893094243282498381006464103080551366587157561686900620059394693185990788592220509670478190685244
n = 101780569941880865465631942473186578520071435753163950944409148606282910806650879176280021512435190682009749926285674412651435782567149633130455645157688819845748439487113261739503325065997835517112163014056297017874761742768297646567397770742374004940360061700285170103292360590891188591132054903101398360047
e = 65537
c = 77538275949900942020886849496162539665323546686749270705418870515132296087721218282974435210763225488530925782158331269160555819622551413648073293857866671421886753377970220838141826468831099375757481041897142546760492813343115244448184595644585857978116766199800311200819967057790401213156560742779242511746

p=gcd(((2**57)*w)-1,n)
q=n//p
#print("p=",p,"\n","q=",q)
d=inverse(e,(p-1)*(q-1))
m=pow(c,d,n)
flag=long_to_bytes(m)
print(flag)
#b'NSSCTF{8d1e3405044a79b23a44a43084bd994b}'

MIMT_RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from Crypto.Util.number import *
from hashlib import md5
from secret import KEY, flag


assert int(KEY).bit_length() == 36
assert not isPrime(KEY)

p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 0x10001

ck = pow(KEY, e, n)


assert flag == b'NSSCTF{' + md5(str(KEY).encode()).hexdigest().encode() + b'}'

print(f"{n = }")
print(f"{e = }")
print(f"{ck = }")

'''
n = 26563847822899403123579768059987758748518109506340688366937229057385768563897579939399589878779201509595131302887212371556759550226965583832707699167542469352676806103999861576255689028708092007726895892953065618536676788020023461249303717579266840903337614272894749021562443472322941868357046500507962652585875038973455411548683247853955371839865042918531636085668780924020410159272977805762814306445393524647460775620243065858710021030314398928537847762167177417552351157872682037902372485985979513934517709478252552309280270916202653365726591219198063597536812483568301622917160509027075508471349507817295226801011
e = 65537
ck = 8371316287078036479056771367631991220353236851470185127168826270131149168993253524332451231708758763231051593801540258044681874144589595532078353953294719353350061853623495168005196486200144643168051115479293775329183635187974365652867387949378467702492757863040766745765841802577850659614528558282832995416523310220159445712674390202765601817050315773584214422244200409445854102170875265289152628311393710624256106528871400593480435083264403949059237446948467480548680533474642869718029551240453665446328781616706968352290100705279838871524562305806920722372815812982124238074246044446213460443693473663239594932076

'''

1
assert condition, message

assert的意思就是condition满足什么也不会干,condition不满足就以message的信息报错

总结题目:

p,q是1024位的大质数,n=pq,n已知,p,q未知

ck=pow(KEY,e,n),知道ck的值,KEY是36位的整数且不是质数

(ck是密文,KEY是明文)

目的是解KEY

确实,这道题的操作有点骚,要先射箭再画靶

直接爆明文看符不符合加密结果(主要原因是KEY是题目里面几个数字里看起来最好欺负的那个)

但36位直接爆还是有点瘆人

但KEY不是质数,所以按假定因数a,b拆 \[ ck≡KEY^{e}\quad(mod\space n)⇨ck≡(ab)^{e}\quad(mod\space n)\newline ⇨ck*b^{-e}≡a^{e}\quad(mod\space n) \] 为什么这样做能降低穷举量?

中间相遇攻击(MITM)

若有加密函数E和解密函数D,ED对称

未知密钥k1,k2,假设它们各有K种取值可能

对于已知密文C,P有 \[ C=E_{k_{2}}(E_{k_{1}}(P))\newline 或是\newline P=D_{k_{2}}(D_{k_{1}}(C))\newline \] 我们想要知道k1,k2

如果真的硬来,那就是每一种k1,k2的组合我们都要尝试一遍,那就得枚举K2种情况

MITM就提供了一种减少枚举时间的方式

比起尝试k1*k2,不如尝试k1+k2 \[ D_{k_{2}}(C)=E_{k_{1}}(P)=M \] 我们先尝试用K种k2对C解密,并将每种k2对M储存起来

同样尝试K种k1对P加密,并将每种k1对M储存起来

(Python里貌似管这个储存起来的配对关系称为字典)

然后在两个字典里寻找M相同的那一对k1,k2

这样子枚举情况就变成了2K,就算再加上查找,差不多也就4K,在K足够大的情况下能够大量节省枚举时间

这个东西比起技巧更像个思考方式,因为比较抽象

回到题目

\[ ck≡KEY^{e}\quad(mod\space n)⇨ck≡(ab)^{e}\quad(mod\space n)\newline ⇨ck*b^{-e}≡a^{e}\quad(mod\space n) \] 要想清楚,a,b是对称的变量

假设这么一个问题 \[ f+g=100\newline f=100-g \] 当我们寻找f,g的正整数解真的需要在f身上历遍1到99吗

显然不需要,f只需要试1到50就行了,因为f和g是对称的

我们在f身上历遍1到50的时候,g已经历遍99到50了

所以在原题目中ab=KEY,那我们只需要在a身上历遍差不多1到KEY0.5就行了

或者说 \[ ck*KEY^{-e}≡1^{e}\quad(mod\space n)\newline ck*1^{-e}≡KEY^{e}\quad(mod\space n) \] 这两个等式一定是同时成立的

所以这样子我们枚举的情况就能从235种缩减为差不多219

总之将近一半

(我猜测不能拆多个因数是因为一个是不确定KEY有几个因数,一个是等号,同余号只有两侧)

所以现在就让我们在1到219的范围内穷举a和b

嗯,本来是这么想的,但我在尝试中发现不扩到20位是找不到的,我想不出原因

反正折半找不到就扩一两位吧,差不了太多

生成器表达式

1
(expression for item in iterable if condition)

expression是它的输出值

item是它历遍的元素,可以类比for语句里的循环变量

interable是可迭代对象(如列表、字典、集合等)

condition是限制条件,只有符合条件的会被生成器选中

example:

1
2
3
4
5
6
7
8
list1=[x**2 for x in range(1,5)]
print(list1)

list2=[x for x in range(1,20) if x%3==0]
print(list2)

#[1, 4, 9, 16]
#[3, 6, 9, 12, 15, 18]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from tqdm import trange

n = 26563847822899403123579768059987758748518109506340688366937229057385768563897579939399589878779201509595131302887212371556759550226965583832707699167542469352676806103999861576255689028708092007726895892953065618536676788020023461249303717579266840903337614272894749021562443472322941868357046500507962652585875038973455411548683247853955371839865042918531636085668780924020410159272977805762814306445393524647460775620243065858710021030314398928537847762167177417552351157872682037902372485985979513934517709478252552309280270916202653365726591219198063597536812483568301622917160509027075508471349507817295226801011
e = 65537
ck = 8371316287078036479056771367631991220353236851470185127168826270131149168993253524332451231708758763231051593801540258044681874144589595532078353953294719353350061853623495168005196486200144643168051115479293775329183635187974365652867387949378467702492757863040766745765841802577850659614528558282832995416523310220159445712674390202765601817050315773584214422244200409445854102170875265289152628311393710624256106528871400593480435083264403949059237446948467480548680533474642869718029551240453665446328781616706968352290100705279838871524562305806920722372815812982124238074246044446213460443693473663239594932076

f1={}
f2={}

for a in trange(1,2**20):
f1[a]=pow(a,e,n)

for b in trange(1,2**20):
f2[b]=(ck*pow(b,-e,n))%n
#a(b (mod n)) (mod n)=ab (mod n)

inter=(set(f1.values())).intersection(set(f2.values()))
#f1.values返回f1内的值构成的列表
#同理,f1.keys返回f1内键构成的列表
#set()函数可以将括号内的内容转化为集合,集合可以计算交集,并集等
#set1.intersection(set2)会返回两个集合的交集


for i in inter:
a=next(k for k,v in f1.items() if v==i)
#f1.items()返回f1内的键值对
#k,v在f1内的键值对循环,如果找到v和i相等,则返回对应的k加入列表,最后返回列表
#这个k,v并无特别含义,,改成(g for g,h in f1.items() if h==i)也没有问题
#在这个程序内,next()仅返回列表里第一个元素的值
b=next(k for k,v in f2.items() if v==i)
KEY=a*b

print(KEY)

'''
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1048575/1048575 [01:32<00:00, 11299.88it/s]
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1048575/1048575 [03:00<00:00, 5801.39it/s]
62495925932
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#next(iterator,default)

gen = (x for x in range(3))
print(next(gen))
print(next(gen))

gen = (x for x in range(3))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen,"s"))
print(next(gen,"s"))

gen=[0,1,2]
print(next(gen)) #开始报错,因为列表不是迭代器
print(next(gen))
print(next(gen))
print(next(gen,"s"))
print(next(gen,"s"))

'''
0
1
0
1
2
s
s
'''

next就是有的输出就按顺序找一个输出,没有就按default输出,如果没得输出又没有default也报错

每一次列表更改它就会重新计数

因为生成器对象每个循环都重新生成一次

所以在解答程序中只会输出交集中第一个符合的值

1
2
3
4
from hashlib import md5
KEY=62495925932
flag=b'NSSCTF{' + md5(str(KEY).encode()).hexdigest().encode() + b'}'
print(flag) #b'NSSCTF{14369380f677abec84ed8b6d0e3a0ba9}'

完事

Sin

1
2
3
4
5
6
7
from Crypto.Util.number import bytes_to_long; print((2 * sin((m := bytes_to_long(b'NSSCTF{test_flag}'))) - 2 * ((2 * tan(m / 2)) / (1 + (tan(m / 2)) ^ 2)) * cos(2 * m)).n(1024))

'''
m的值即为flag
0.002127416739298073705574696200593072466561264659902471755875472082922378713642526659977748539883974700909790177123989603377522367935117269828845667662846262538383970611125421928502514023071134249606638896732927126986577684281168953404180429353050907281796771238578083386883803332963268109308622153680934466412
'''

m := bytes_to_long(b'NSSCTF{test_flag}'

:=叫海象运算符,可以用于在表达式中赋值

用普通赋值的话这个赋值就得单独拎出来写一行

.n(1024)表示保留1024位的精度

现在总结一下题目 \[ 2sin(m)-2(\frac{2tan\frac{m}{2}}{1+tan^{2}\frac{m}{2}})cos(2m)=c\newline c已知,求解m \] 对括号对得我脑壳疼

但不得不说,看到这题我就想起了高中狂算三角函数的日子

不知道高中的知识还够不够用呢 \[ \frac{2tan\frac{m}{2}}{1+tan^{2}\frac{m}{2}}\newline 明显的万能公式,看不出来也能上下同乘cos平方\newline \frac{2tan\frac{m}{2}}{1+tan^{2}\frac{m}{2}}=\frac{2sin\frac{m}{2}cos\frac{m}{2}}{sin^{2}\frac{m}{2}+cos^{2}\frac{m}{2}}=sin(m)\newline 代换\newline 2sin(m)-2sin(m)cos(2m)=2sin(m)(1-cos(2m))=2sin(m)(1-(1-2sin^{2}(m)))=4sin^{3}(m)=c\newline \] 嘛,到这为止还算高中内容

接下来就是其他不认识的东西了

先睡觉,慢慢写...