黄河流域网络安全技能挑战赛2025
Ctypto
Lattice
task.py
from Crypto.Util.number import *
from Crypto.Cipher import AES
import os
from secret import flag
import numpy as np
def gen(q, n, N, sigma):
t = np.random.randint(0, high=q // 2, size=n)
s = np.concatenate([np.ones(1, dtype=np.int32), t])
A = np.random.randint(0, high=q // 2, size=(N, n))
e = np.round(np.random.randn(N) * sigma**2).astype(np.int32) % q
b = ((np.dot(A, t) + e).reshape(-1, 1)) % q
P = np.hstack([b, -A])
return P, s
def enc(P, M, q):
N = P.shape[0]
n = len(M)
r = np.random.randint(0, 2, (n, N))
Z = np.zeros((n, P.shape[1]), dtype=np.int32)
Z[:, 0] = 1
C = np.zeros((n, P.shape[1]), dtype=np.int32)
for i in range(n):
C[i] = (np.dot(P.T, r[i]) + (np.floor(q / 2) * Z[i] * M[i])) % q
return C
q = 127
n = 3
N = int(1.1 * n * np.log(q))
sigma = 1.0
P, s = gen(q, n, N, sigma)
def prep(s):
return np.array([int(b) for char in s for b in f"{ord(char):08b}"], dtype=np.int32)
C = enc(P, prep(hint), q)
P = P.tolist()
C = C.tolist()
print(f"{P=}")
print(f"{C=}")
'''
P=[...]
C=[...]
'''
key = os.urandom(16)
encrypted = AES.new(key=key, iv=iv, mode=AES.MODE_CBC).encrypt(b"".join([pad(i.encode(), 16) for i in flag]))
print(leak)
print(key)
print(encrypted)
'''
-3.257518803980229925210589904230583482986646342139415561576950148286382674434770529248486501793457710730252401258721482142654716015216299244487794967600132597049154513815052213387666360825101667524635777006510550117512116441539852315185793280311905620746025669520152068447372368293640072502196959919309286241
b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'
b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'
'''
一大段都是迷惑人的,其实破解就是CBC模式求iv
encrypted = AES.new(key=key, iv=iv, mode=AES.MODE_CBC).encrypt(b"".join([pad(i.encode(), 16) for i in flag]))
我们知道初始16字节一定有flag{这个开头,然后和相应的密文异或,就可以得到iv
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
key=b'\x8fj\x94\x98-\x1fd\xd5\x89\xbe\xa9*Tu\x90\xb7'
encrypted=b'\x9fT@\xbc\x82\x8esQ\x1e\xd8\x1d\xdb\x9b\xb4\xf8rU\xc8\xa0\xcb\xaf H\xa9.\x04\x1e\xd2\x92\x1f\x0fBja-\x965x\xa8@\xc9x\xf9\xaf\x87\xd1\xa5}\xfc\x1b\xe0#\xc3m\xc9\x8973\x1c\x1f\x13\x8f\xb2a\xae\xa9]\xb9\xc2\xe8\x83A\x80\x13g\xc9a\x1c<\x8a\x9c&\xd9\xbd\x06\xef\xba9\xb0\x03\x9f\x022\xc9\x13\x9a\xffXPG\xc6o\xc0\xeaV7)XG9L\x84N7U\xe3Wn0G\x8e\xd3\x04(\n\x08\xb9\x17\xe6\xf1\xaa\xb7\x8a@$\x16\x13\x06A\x00\xc9Z\xdf\x7fQ\xc9\x08\xb4\xf3P\xfcpe\xe2\xeb\x96\x0e(-\xde\x17\xd1\x01\x1c_\x82\x8b\x9fw\xc8\x86\xfbw\xb5\xf7\xd0\xc8\x1784\xe3?\x00\x0b.)\xb7\xbc\x8e{\xe0\xae\x8d$\x0f\x19\'\xb6\xee@d\x00\xd9\x84\x8c\x0e\xa3,\xc6a\xa3\xba*1\xfd<\xfd\x18\xd6\x9e\x8c4\x8e#\xfd\xbd&0R\xeddE,\xed\xb6\x1e\x00\x11\xa6K\xd3\x1dT\x8c5\x8e\x00\xea\x10\xe9\'u"B#\xa1#\xd8\xe3\xf5j\xbc\x94M\xda\xe3\xcb*\xf0W1\xa0\x80\x1d\xfc\xbfo\x01?(da\r\xb6\x86\xd0\x90\x88Z\xa1`B\x89\x89\x89\xb3v\xa5\xf0\xe0\x0c\x8e\xcc+P\xfc\xfd#\x83\xe9\x93\x96\n\xf2\xa5\xfb\xc3\xc5\xaa\x9e\x89\x93\xb6\xf5\xea\x8c%NY\xc3\x0eR\xfas\xa1\x13\xf2/*\xce\x8b_:_r\xeb\xbe\x0b\x8a\x8c\x97\x7f|m}\xae\xa9I\x95\xcc\xe7\x80\xa5yC4\x1f5\xa4P\xc5\xbf.\xf9V\xe8|\xbb\xc3\xcb\x98&\'JB\x99\x94\xc0\r$\x0b\xbe48u\xeb\xca\xa1\xfbb\xd8_R\x97\x8e\xaeI\xfc\xc2\xb2\xd2#@\xec\x16\xf1\xd7eCQ\x1cO\x13\xca\xb5\xd3\x1a\xb1\xf1_D\x80\x06\xa5\xbe\xbev\xbd\xd6\xbb\x9a\xc9x\x9cf:\xcb>\xa2\xe1\xcad\xde]aw\xa0\xdc\xb2\xb3{+\x85\x8d\x8b\xc5\rT\xcc\xd9X\xd5\x9b\r<\x99m\xb8b6s\xbfp\x0eo~\xe9&\xb2{\xbe\xee\x93\xd2N1\\\x94\x968IWO7\xcb\xb6e\x80\xf7\x9air\xb2~\x17\x1cF\x0f\x82T]RBX\xdex\x13\x85\xfa\xcd-\xce\xdc\xe4\xe5^\x99u\xb5\x01\xd0-\xc3C\xcd\xc4y6\xb7\x9d|L1\xe74\xf7\x8cH\xe9\xa9\xfav\n\xec;\xf2\xa2w\xfb\x13_b\r)z!\xa3\xc8\xa8\xc2\xd2\x10\x00\x11\x11\r\xb2&\xfb\x04&\x84">x6l[\x06n>\xa0\xbe\x9c`\xa7\x9e\xe0\xfb\x85\x91\xc4,\xcf\xac\xe11@a\xed3@\xfd}\x8e\xfaTp\xcb7\xe7\xbf\xd4\xe0~b\xd9\xe0<\xba\x81\xd4"e\xfc\x939|j#0H\x86\xf8\x0b\x03\xd2\xe8\xf5\xe55\xdc\xc8\x06\\\xb7)\xcc\x9b\'\xf12'
flag="flag{"
c = b"".join([pad(i.encode(), 16) for i in flag])
#b'f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f'
print(c[:16])
cipher = AES.new(key, AES.MODE_ECB)
decrypted_c0 = cipher.decrypt(encrypted[:16])
iv = bytes([a ^ b for a, b in zip(decrypted_c0, c[:16])])
print(iv)
#b'?\xaa =t\xbc\xddQ\xac/yq\x13\xc3\x7f\xb9'
cipher = AES.new(key, AES.MODE_CBC, iv)
flag = cipher.decrypt(encrypted)
ans=""
for k in flag:
ans+=chr(k)
print(ans)
#flag{6ef25d1e-bb76-8e53-dbc4-1e56585f9aa9}
Sandwitch
task.py
from Crypto.Util.number import *
import gmpy2
flag = b'flag{fake_flag}'
assert len(flag) == 39
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x3
pad1 = b'easy_problem'
pad2 = b'How_to_solve_it'
c = pow(bytes_to_long(pad1 + flag + pad2),e,n)
print(f'n = {n}')
print(f'c = {c}')
'''
n = 130210658110511504736422597261591182174531847806532340762131145212035478695205314931974421838392310731226415266775095601890938846830080329061111533796518633011922277343217149648494987341818402753017296362015915834670450122261511337212801488239810623226740266516836721952886027130703886460578247562781194524199
c = 58274335440051115211211273605191310114692293785750437685473044454042062899661976407492451518086227780147882738264722645944582899451063113444881286175099872016956825274378613983870549046907444680021237171113596116147511706486372974792692071549068969896395366667516390709069131700584308236332248449116109156503
'''
c ≡ ( 256 54 p a d 1 + 256 15 f l a g + p a d 2 ) m o d n c\equiv (256^{54}pad1+256^{15}flag+pad2)\ mod\ n c≡(25654pad1+25615flag+pad2) mod n
用copper打
from Crypto.Util.number import *
e = 3
n = 130210658110511504736422597261591182174531847806532340762131145212035478695205314931974421838392310731226415266775095601890938846830080329061111533796518633011922277343217149648494987341818402753017296362015915834670450122261511337212801488239810623226740266516836721952886027130703886460578247562781194524199
c = 58274335440051115211211273605191310114692293785750437685473044454042062899661976407492451518086227780147882738264722645944582899451063113444881286175099872016956825274378613983870549046907444680021237171113596116147511706486372974792692071549068969896395366667516390709069131700584308236332248449116109156503
pad1 = b'easy_problem'
pad2 = b'How_to_solve_it'
p1=bytes_to_long(pad1)
p2=bytes_to_long(pad2)
PR.<x> = PolynomialRing(Zmod(n))
f=(p1*256**54+x*256**15+p2)^e-c
f=f.monic()
ans=f.small_roots(X=256^39,beta=1,epsilon=0.04)
if(ans):
print(long_to_bytes(int(ans[0])))
因式分解
tellasecret.py
import string
from secret import hint
from secret import encrypt
import random
dicts = string.ascii_lowercase +"{=}"
key = (''.join([random.choice(dicts) for i in range(4)])) * 8
assert(len(hint) == 32)
assert(len(key) == 32)
cipher = encrypt(hint, key) #Vigenere
print(cipher)
# cp=wmaunapgimjfpopeblvup=aywqygb
因式分解.py
from Crypto.Util.number import *
from gmpy2 import*
from secret import flag,a,b,c
m = bytes_to_long(flag)
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
_q = int(bin(q)[2:][::-1] , 2)
c = pow(m,e,n)
print('n =',n)
print('c =',c)
'''
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978
'''
assert a**3+b**3+c**3 == 3*a*b*c
gift = secert**3 - 9*secert + 8
print(gift)
assert 3*(p ^ _q) == a + b + c
#16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050
应该是从tellasecret中获得secret
给了我们提示是维吉尼亚,并且key长度是32位,而且key是以4字节为一组的
但是我们不知道相应的明文,于是我们结合文件名脑洞一下,猜secret在里面
让AI写一个脚本
import string
# 已知字母表:26 个小写字母 + '{' + '=' + '}'
dicts = string.ascii_lowercase + "{=}"
# 给定的密文
cipher_target = "cp=wmaunapgimjfpopeblvup=aywqygb"
def vigenere_decrypt(ct: str, full_key: str) -> str:
"""
对给定的 ciphertext ct 用完整的 full_key 做 Vigenère 解密,
字母表使用 dicts。如果字符不在 dicts 中,则原样保留。
"""
pt_chars = []
m = len(dicts)
for i, c in enumerate(ct):
if c not in dicts:
# 不在字母表中的字符直接保留(例如标点、数字等)
pt_chars.append(c)
else:
k = full_key[i]
# plaintext_index = (cipher_index - key_index) mod m
pi = (dicts.index(c) - dicts.index(k)) % m
pt_chars.append(dicts[pi])
return "".join(pt_chars)
# 开始枚举所有 4 字符子密钥
for a in dicts:
for b in dicts:
for c in dicts:
for d in dicts:
key4 = a + b + c + d
full_key = key4 * 8 # 重复 8 次,得 32 字符完整密钥
# 用 full_key 解密密文
candidate_pt = vigenere_decrypt(cipher_target, full_key)
# 如果明文里包含 "secret",就认为找到正确密钥
if "secret" in candidate_pt:
print(f"[+] 找到子密钥(4 字符):{key4}")
print(f"[+] 完整密钥(32 字符):{full_key}")
print(f"[+] 对应明文示例:{candidate_pt}")
exit()
print("[-] 未找到包含 'secret' 的明文对应的密钥。")
‘’‘
[+] 找到子密钥(4 字符):mlql
[+] 完整密钥(32 字符):mlqlmlqlmlqlmlqlmlqlmlqlmlqlmlql
[+] 对应明文示例:tellasecret{a=secert}keepsilentt
’‘’
告诉我们a=secret
现在我们对式子进行因式分解
( a 3 + b 3 + c 3 ) − 3 a b c = ( a + b + c ) ( a 2 + b 2 + c 2 − a b − a c − b c ) = 0 (a^3+b^3+c^3)-3abc=(a+b+c)(a^2+b^2+c^2-ab-ac-bc)=0 (a3+b3+c3)−3abc=(a+b+c)(a2+b2+c2−ab−ac−bc)=0
所以第二个括号等于0
再因式分解一下
( a − b ) 2 + ( b − c ) 2 + ( c − a ) 2 = 0 (a-b)^2+(b-c)^2+(c-a)^2=0 (a−b)2+(b−c)2+(c−a)2=0
所以a=b=c
看到p^q一眼鉴定为剪枝
先用AI把secret求出来
# 在 SageMath 环境(比如 SageCell、Notebook 或者 sage -c)中运行以下代码
# 1. 声明符号变量
var('secert')
# 2. 给定 gift 的整数值;在 Sage 里,只要写成 Python 整数就会被自动当作任意精度整数处理
gift_val = 16174454302590604301534105361719250538317088773024913985896374029052621214070408075926265229111851489902642328975085914458074453963086159246933939207642987161923181946601656883349077418380372857072224674380642689142603970810010050
# 3. 构造多项式 P(secert) = secert^3 - 9*secert + 8 - gift_val
P = secert^3 - 9*secert + 8 - gift_val
# 4. 用 .roots(ring=ZZ) 找出所有在整数域 ZZ 上的根
# .roots(ZZ) 会返回一个列表,格式是 [(root1, multiplicity1), (root2, multiplicity2), …]
int_roots = P.roots(ring=ZZ)
# 5. 输出结果
print("整数根及其重数:", int_roots)
#25289672915296952421286820568694528489788342353673740247988495109991492893326
然后采用一个剪枝
from Crypto.Util.number import *
import sys
sys.setrecursionlimit(1500)
pxorq = 25289672915296952421286820568694528489788342353673740247988495109991492893326
n = 7688109450918412752403544831281002390909833419780604228031807748258766149305710928557842935597759373483911172486806200079137977020089610947423466744079981
c = 6470273779347221033316093386019083111753019159457126878637258794718443144439812725263309232245307744208957171971247518708231996986359926490571921925899978
e = 65537
pxorq = str(bin(pxorq)[2:]).zfill(256)
def find(ph,qh,pl,ql):
l = len(ph)
tmp0 = ph + (256-2*l)*"0" + pl
tmp1 = ph + (256-2*l)*"1" + pl
tmq0 = qh + (256-2*l)*"0" + ql
tmq1 = qh + (256-2*l)*"1" + ql
if(int(tmp0,2)*int(tmq0,2) > n):
return
if(int(tmp1,2)*int(tmq1,2) < n):
return
if(int(pl,2)*int(ql,2) % (2**(l-1)) != n % (2**(l-1))):
return
if(l == 128):
pp0 = int(tmp0,2)
if(n % pp0 == 0):
pf = pp0
qf = n//pp0
phi = (pf-1)*(qf-1)
d = inverse(e,phi)
m1 = pow(c,d,n)
print(long_to_bytes(m1))
exit()
else:
if(pxorq[l] == "1" and pxorq[255-l] == "1"):
find(ph+"1",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "1" and pxorq[255-l] == "0"):
find(ph+"1",qh+"0","0"+pl,"0"+ql)
find(ph+"0",qh+"0","0"+pl,"1"+ql)
find(ph+"1",qh+"1","1"+pl,"0"+ql)
find(ph+"0",qh+"1","1"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "1"):
find(ph+"0",qh+"0","1"+pl,"0"+ql)
find(ph+"0",qh+"1","0"+pl,"0"+ql)
find(ph+"1",qh+"0","1"+pl,"1"+ql)
find(ph+"1",qh+"1","0"+pl,"1"+ql)
elif(pxorq[l] == "0" and pxorq[255-l] == "0"):
find(ph+"0",qh+"0","0"+pl,"0"+ql)
find(ph+"1",qh+"0","0"+pl,"1"+ql)
find(ph+"0",qh+"1","1"+pl,"0"+ql)
find(ph+"1",qh+"1","1"+pl,"1"+ql)
find("1","1","1","1")
#b'flag{80a59062-9bbf-99a3-6af0-a24e94032163}'
Happy
task.py
#!/usr/bin/env python
# Simplify the problem by happy4321
import os, utils
from secret import flag
assert flag.startswith(b'flag{') and flag.endswith(b'}')
seed = int(os.urandom(16).hex(), 16)
gen = utils.Gen(seed)
msg = b'Happy4321: ' + flag
enc = bytes(m ^ next(gen) for m in msg).hex()
print(enc)
# cd1dd7c7a9cfe3c0067ff64694e64c38aa759c81d1c8f48cf6f7ee1df2d1e58584da52644ea56bd24dadca6bd5a6899a92b118f57de2529670264d48
utils.py
class Gen:
def __init__(self, state):
self.nbits = 128
self.state = state & ((1 << self.nbits) - 1)
self.mask = 109908700282042807039366676242995409413
def func0(self, steps=1):
for _ in range(steps):
res = self.state & self.mask
bit = sum([(res >> i) & 1 for i in range(self.nbits)]) & 1
self.state = ((self.state << 1) ^ bit) & ((1 << self.nbits) - 1)
return bit
def __next__(self):
out = 0
for _ in range(8):
bit = self.func0(2023)
out = (out << 1) ^ bit
return out
原题,已经写的很清楚了
# SageMath
class Gen:
def __init__(self, state):
self.nbits = 128
self.state = state & ((1 << self.nbits) - 1)
self.mask = 109908700282042807039366676242995409413
def func0(self, steps=1):
for _ in range(steps):
res = self.state & self.mask
bit = sum([(res >> i) & 1 for i in range(self.nbits)]) & 1
self.state = ((self.state << 1) ^ bit) & ((1 << self.nbits) - 1)
return bit
def __next__(self):
out = 0
for _ in range(8):
bit = self.func0(2023)
out = (out << 1) ^ bit
return out
n = 128
msg = b'Happy4321: flag{'
mask = 109908700282042807039366676242995409413
enc = 'cd1dd7c7a9cfe3c0067ff64694e64c38aa759c81d1c8f48cf6f7ee1df2d1e58584da52644ea56bd24dadca6bd5a6899a92b118f57de2529670264d48'
enc = bytes.fromhex(enc)
Round = 2023
# 构建M矩阵
M = matrix(GF(2), n, n)
for i in range(n):
if i+1<n:
M[i+1, i] = 1
if mask&(1<<(n-i-1)):
M[i, -1] = 1
else:
M[i, -1] = 0
# seed * M2 = output_s
M2 = matrix(GF(2), n, n)
for i in range(n):
tmp = M^(Round*(i+1))
for y in range(n):
M2[y, i] = tmp[y, -1]
# 构建output_s矩阵
output_s = []
for i in range(len(msg)):
tmp = msg[i]^^enc[i]
for x in range(8):
if tmp&(1<<(8-x-1)):
output_s.append(1)
else:
output_s.append(0)
output_s = vector(GF(2), output_s)
S = M2.solve_left(output_s)
seed = int(''.join([str(each) for each in S]), 2)
print(seed)
# 16527323701539137374460041583215952894
import os
enc = 'cd1dd7c7a9cfe3c0067ff64694e64c38aa759c81d1c8f48cf6f7ee1df2d1e58584da52644ea56bd24dadca6bd5a6899a92b118f57de2529670264d48'
enc = bytes.fromhex(enc)
seed = 16527323701539137374460041583215952894
gen = Gen(seed)
flag = bytes(c ^ next(gen) for c in enc)
print(flag)
# flag{The_matrix_is_as_charming_as_the_starry_sky}