host = 'chall.polygl0ts.ch' port = 6001 context.log_level = 'error'
known_flag = "" charset = string.digits
# flag is 32 digits long for i inrange(32): found_char = False for char in charset: r = remote(host, port) test_payload = known_flag + char r.sendlineafter(b"digits long!", test_payload.encode()) response = r.recvall(timeout=2).decode() if"Correct flag!"in response: known_flag += char print(f"index : {i}, current flag: {known_flag}") found_char = True r.close() break r.close() ifnot found_char: break
print(f"Flag: EPFL{{{known_flag}}}")
# index : 0, current flag: 1 # index : 1, current flag: 15 # index : 2, current flag: 153 # index : 3, current flag: 1539 # index : 4, current flag: 15392 # index : 5, current flag: 153929 # index : 6, current flag: 1539294 # index : 7, current flag: 15392948 # index : 8, current flag: 153929482 # index : 9, current flag: 1539294829 # index : 10, current flag: 15392948299 # index : 11, current flag: 153929482999 # index : 12, current flag: 1539294829992 # index : 13, current flag: 15392948299929 # index : 14, current flag: 153929482999293 # index : 15, current flag: 1539294829992932 # index : 16, current flag: 15392948299929328 # index : 17, current flag: 153929482999293283 # index : 18, current flag: 1539294829992932838 # index : 19, current flag: 15392948299929328383 # index : 20, current flag: 153929482999293283838 # index : 21, current flag: 1539294829992932838382 # index : 22, current flag: 15392948299929328383828 # index : 23, current flag: 153929482999293283838283 # index : 24, current flag: 1539294829992932838382839 # index : 25, current flag: 15392948299929328383828399 # index : 26, current flag: 153929482999293283838283999 # index : 27, current flag: 1539294829992932838382839992 # index : 28, current flag: 15392948299929328383828399923 # index : 29, current flag: 153929482999293283838283999239 # index : 30, current flag: 1539294829992932838382839992399 # index : 31, current flag: 15392948299929328383828399923990 # Flag: EPFL{15392948299929328383828399923990}
def_vec_poly_mul(v0, v1): def_poly_mul(a, b): res = np.convolve(a, b) for i inrange(n, len(res)): res[i - n] = (res[i - n] - res[i]) % q return res[:n] % q returnsum((_poly_mul(a, b) for a, b inzip(v0, v1))) % q
defencrypt(A, t, m_b, r, e_1, e_2): A_T = list(map(list, zip(*A))) u = np.array([(mat + err) % q for mat, err in zip([_vec_poly_mul(row, r) for row in A_T], e_1) ]) tr = _vec_poly_mul(t, r) m = (m_b * ((q + 1)//2)) % q v = (tr + e_2 + m) % q return u, v
# ---------- Key generation ---------- A = np.array([np.array([np.random.randint(0, q, n) for _ inrange(k)]) for _ inrange(k)]) s = np.array([_small_noise(n, n*2//3) for _ inrange(k)]) e = np.array([_small_noise(n) for _ inrange(k)]) t = np.array([(_vec_poly_mul(row, s) + err) % q for row, err inzip(A, e)])
# ---------- Encryption ------------- r = [_small_noise(n) for _ inrange(k)] e_1 = [_small_noise(n) for _ inrange(k)] e_2 = _small_noise(n)
withopen("keys.json", "r") as f: data = json.load(f)
s = np.array(data['s']) # 私钥 u = np.array(data['u']) v = np.array(data['v'])
# 直接从题里复制过来 def_vec_poly_mul(v0, v1): def_poly_mul(a, b): res = np.convolve(a, b) for i inrange(n, len(res)): res[i - n] = (res[i - n] - res[i]) % q return res[:n] % q returnsum((_poly_mul(a, b) for a, b inzip(v0, v1))) % q
def_vec_poly_mul(v0, v1): def_poly_mul(a, b): res = np.convolve(a, b) for i inrange(n, len(res)): res[i - n] = (res[i - n] - res[i]) % q return res[:n] % q returnsum((_poly_mul(a, b) for a, b inzip(v0, v1))) % q
defencrypt(A, t, m_b_batch, r_batch, e_1_batch, e_2_batch): A_T = list(map(list, zip(*A))) u_list = [] v_list = [] for b inrange(batch_size): r = r_batch[b] e_1 = e_1_batch[b] e_2 = e_2_batch[b] m_b = m_b_batch[b] u = np.array([(mat + err) % q for mat, err in zip([_vec_poly_mul(row, r) for row in A_T], e_1) ]) tr = _vec_poly_mul(t, r)
m = (m_b * ((q + 1)//2)) % q v = (tr + e_2 + m) % q u_list.append(u) v_list.append(v) return np.array(u_list), np.array(v_list)
# ---------- Key generation ---------- A = np.array([np.array([np.random.randint(0, q, n) for _ inrange(k)]) for _ inrange(k)]) s = np.array([_small_noise(n, n//2) for _ inrange(k)]) e = np.array([_small_noise(n) for _ inrange(k)]) t = np.array([(_vec_poly_mul(row, s) + err) % q for row, err inzip(A, e)])
# ---------- Encryption ---------- r_batch = np.array([[_small_noise(n) for _ inrange(k)] for _ inrange(batch_size)]) e_1_batch = np.array([[_small_noise(n) for _ inrange(k)] for _ inrange(batch_size)]) e_2_batch = np.array([_small_noise(n) for _ inrange(batch_size)])
u, v = encrypt(A, t, m_b, r_batch, e_1_batch, e_2_batch)
#!/usr/bin/env -S python3 -u import os import numpy as np from math import sqrt # no need quantum libraries here, only linear algebra. from scipy.stats import unitary_group
defstring_to_bits(s): bits = [] for byte in s: for i inrange(8): bits.append((byte >> (7 - i)) & 1) return bits
defbit_to_qubit(bit): if bit == 0: return np.array([1,0]) # |0> else: return np.array([0, 1]) # |1>
defmeasurement(cipher): measured_bits = [] for qubit in cipher: prob_0 = qubit[0]*qubit[0].conjugate()
if np.random.rand() < prob_0: measured_bits.append(0) else: measured_bits.append(1) return measured_bits
defbits_to_string(bits): bytes_list = [] for i inrange(0, len(bits), 8): byte = 0 for j inrange(8): byte = (byte << 1) | bits[i + j] bytes_list.append(byte) returnbytes(bytes_list) ####################################################################################
FLAG = b"EPFL{FAKEFLAAAAAAAG}}" n = len(FLAG) key = os.urandom(n) x = unitary_group.rvs(2)
print("Welcome to the Quantum Vernam Cipher Encryption! Key and flag have same length, try to break perfect secrecy if you can.") print("\n") print('The qubits will be encrypted with the matrix x = ',x) print("\n") print("You can apply any gate you want to the qubits before and after measurement as a 2X2 matrix, choose your favorite one :)") print("\n") print("Also pls remember that in python, j is the imaginary unit, not i.") print('\n') print('Enter coefficients for the first matrix that will be applied BEFORE encryption:') print('Enter first matrix element:') a1 = complex(input()) print('Enter second matrix element:') b1 = complex(input()) print('Enter third matrix element:') c1 = complex(input()) print('Enter fourth matrix element:') d1 = complex(input())
gate1 = np.array([(a1,b1),(c1,d1)])
print('\n') print('Enter coefficients for the second matrix that will be applied AFTER encryption:') print('Enter first matrix element:') a2 = complex(input()) print('Enter second matrix element:') b2 = complex(input()) print('Enter third matrix element:') c2 = complex(input()) print('Enter fourth matrix element:') d2 = complex(input())
gate2 = np.array([(a2,b2),(c2,d2)])
# vérifie que les matrices sont unitaires defis_unitary(matrix): identity = np.eye(matrix.shape[0]) return np.allclose(matrix.conj().T @ matrix, identity)
assert is_unitary(gate1), "Gate 1 is not unitary!" assert is_unitary(gate2), "Gate 2 is not unitary!"
clean_str = x_str.replace('[', '').replace(']', '').replace('\n', ' ') elements = clean_str.split()
matrix_elements = [] for el in elements: if el: matrix_elements.append(complex(el)) X = np.array(matrix_elements).reshape(2, 2) print(f"Matrix X:\n{X}")
# 计算特征值和特征向量 # w 是特征值, v 是特征向量矩阵 w, v = np.linalg.eig(X)
def_vec_poly_mul(v0, v1): def_poly_mul(a, b): res = np.convolve(a, b) for i inrange(n, len(res)): res[i - n] = (res[i - n] - res[i]) % q return res[:n] % q returnsum((_poly_mul(a, b) for a, b inzip(v0, v1))) % q
defencrypt(A, t, m_b, r, e_1, e_2): u = np.array([(mat + err) % q for mat, err in zip([_vec_poly_mul(row, r) for row in A.T], e_1) ]) tr = _vec_poly_mul(t, r) m = (m_b * ((q + 1)//2)) % q v = (tr + e_2 + m) % q return u, v
# ---------- Key generation ---------- A_1 = np.array([np.array([np.random.randint(0, q, n) for _ inrange(k)]) for _ inrange(k)]) A_2 = np.array([np.array([np.random.randint(0, q, n) for _ inrange(k)]) for _ inrange(k)]) s_1 = np.array([_small_noise(n, n*2//3) for _ inrange(k)]) s_2 = np.array([_small_noise(n, n*2//3) for _ inrange(k)]) e = np.array([_small_noise(n) for _ inrange(k)]) t_1 = np.array([(_vec_poly_mul(row, s_1) + err) % q for row, err inzip(A_1, e)]) t_2 = np.array([(_vec_poly_mul(row, s_2) + err) % q for row, err inzip(A_2, e)])
# ---------- Encryption ---------- r = [_small_noise(n) for _ inrange(k)] e_1 = [_small_noise(n) for _ inrange(k)] e_2 = _small_noise(n)
defget_negacyclic_matrix(coeffs): """ 创建多项式的负循环矩阵。 如果系数少于 n,则填充 0。 """ c = list(coeffs) iflen(c) < n: c = c + [0]*(n - len(c)) M = Matrix(F, n, n) current = vector(F, c) for i inrange(n): M.set_column(i, current) # 计算下一列:右移,溢出部分取反移到头部 last = current[n-1] current = vector(F, [-last] + list(current[:-1])) return M
print("[*] Loading data...") withopen("keys.json", "r") as f: data = json.load(f)
# 1. 构建线性方程组 M * r = b # 方程来源: (u1[i] - u2[i]) = Sum_j ( P_A1_ij - P_A2_ij ) * r[j] # 其中 P_A_ij 是由切片 A[0..3][j][i] 构成的“小”多项式
print("[*] Building the large linear system (2048x2048)...") M_big = Matrix(F, k*n, k*n) b_big = vector(F, k*n)
# 构建目标向量 b = u1 - u2 # 只需要前 k=4 个多项式 (因为 encrypt 只输出了前4个) for i inrange(k): poly_diff = vector(F, u1_data[i]) - vector(F, u2_data[i]) for j inrange(n): b_big[i*n + j] = poly_diff[j]
# 构建大矩阵 M # i 是方程组的行块索引 (对应 u 的下标) # j 是方程组的列块索引 (对应 r 的下标) for i inrange(k): for j inrange(k): # 提取切片数据: A[x][j][i] for x in 0..3 # 这对应于 keys.json 中的 A_1[x][j][i] # 注意: JSON 中的 A 是 list[row][col][coeff] slice1 = [A1_data[x][j][i] for x inrange(k)] slice2 = [A2_data[x][j][i] for x inrange(k)] poly1 = vector(F, slice1) poly2 = vector(F, slice2) diff_poly = poly1 - poly2 # 将这个小多项式转换为 n*n 的负循环矩阵块 block = get_negacyclic_matrix(list(diff_poly)) M_big.set_block(i*n, j*n, block)
# 2. 求解 r print("[*] Solving linear system...") try: # M_big * r_vec = b_big r_solution_vec = M_big.solve_right(b_big) print("[+] System solved!") except ValueError: print("[-] System is inconsistent or singular.") exit()
# 将解向量重组为多项式列表 r_polys = [] for i inrange(k): r_polys.append(r_solution_vec[i*n : (i+1)*n])
# 3. 解密 # v1 = t1 . r + e2 + m # m_approx = v1 - t1 . r print("[*] Decrypting...")
# 计算点积 t1 . r dot_product = vector(F, n) for i inrange(k): # t1 和 r 都是正常长度的多项式,正常相乘 M_t = get_negacyclic_matrix(t1_data[i]) r_vec = vector(F, r_polys[i]) dot_product += M_t * r_vec