代码分析server.py 首先,拿到了一个server.py文件,我们先来分析代码:
这次引用的包和之前的不太一样
from qutip.qip.operations.gates import cnot, snot, x_gate, z_gate
from qutip.measurement import measure_povm
from qutip import basis, tensor, qeye 类QuantumProcessor 量子门 这个类先定义了很多量子操作门,Z,X,H,CNOT具体的量子电路效果前两篇文章有过相关解释
def __init__(self):
pass
def Z(self, n, target):
return z_gate(n, target)
def X(self, n, target):
return x_gate(n, target)
def H(self, qubits, target):
return snot(qubits, target)
def CNOT(self, qubits, control, target):
return cnot(qubits, control, target) single_projector 接下来定义了单比特投影测量,投影测量分为了两个基,X基和Z基,简单来讲的话:
X基:+态测得0,-态测得1
Z基:0态测得0,1态测得1
其中+为0经过H门变成的叠加态(|0>+|1>)/根号2
-为0经过H门变成的叠加态(|0>-|1>)/根号2
这个函数就是输入不同的基态可以获得不同的投影算符
def single_projector(self, _basis):
if _basis == "Z":
return basis(2, 0).proj(), basis(2, 1).proj()
elif _basis == "X":
plus = (basis(2, 0) + basis(2, 1)).unit()
minus = (basis(2, 0) - basis(2, 1)).unit()
return plus.proj(), minus.proj()
else:
print(f"Basis '{_basis}' is invalid or unexpected.")
return () projector 从上面的函数中按照要求获取投影算符然后用张量积连接起来(即为不同的线路)
def projector(self, basis, qubits, target):
single_projector = self.single_projector(basis)
projectors = []
for projector in single_projector:
operators = [qeye(2)] * qubits
operators[target] = projector
projectors.append(tensor(operators))
return projectors measure 调用上面的projector函数获取连接好的投影算符对量子态进行测量
def measure(self, basis, qubits, target, state):
projectors = self.projector(basis, qubits, target)
if not projectors:
return (None, state)
return measure_povm(state, projectors) 类Teleporter __init__ 里面有个encoder,用来映射的。
其中basis(d, k)中d表示维度,k为基态索引。
那么也就是说basis(2,0)就表示0态
所以映射关系为:
00 -- |0>态和Z基
01 -- |1>态和Z基
10 -- |+>态和X基
11 -- |->态和X基
def __init__(self):
self.proc = QuantumProcessor()
self.encoder = {
"00": [basis(2, 0), "Z"],#0
"01": [basis(2, 1), "Z"],#1
"10": [(basis(2, 0) + basis(2, 1)).unit(), "X"],#0+1/2
"11": [(basis(2, 0) - basis(2, 1)).unit(), "X"]#0-1/2
} bytes_to_bitpairs 把每个字节转为8位二进制串,然后再把二进制串2个2个分组
比如输入:b'\x02'
则转化为00000010
再分组为['00','00','00','10']
def bytes_to_bitpairs(self, data: bytes):
bits = ''.join(f"{byte:08b}" for byte in data)
return [bits[i : i + 2] for i in range(0, len(bits), 2)] prepare 输入bits使用刚才的encoder进行映射编码,给q0线路
q1线路和q2线路初始态都是0态
再使用张量积tensor三条线路表示整个3qbit电路的初始状态
然后再使用如下几个门后状态如下:
只不过下图的q0不一定是0态作为初态而是编码后得到的
def prepare(self, bits: str):
q0, _basis = self.encoder[bits]#把bit按照encoder办法编码
q1 = basis(2, 0)
q2 = basis(2, 0)
state = tensor(q0, q1, q2)
state = self.proc.H(3, 1) * state
state = self.proc.CNOT(3, 1, 2) * state
state = self.proc.CNOT(3, 0, 1) * state
state = self.proc.H(3, 0) * state'
return state, _basis apply_instructions 这个是往电路里面添加门的函数,我们这次可以使用三种门Z,X,H
def apply_instructions(self, instructions, state):
instructions = instructions.split(";")
for instr in instructions:
parts = instr.split(":")
if len(parts) != 2:
print(f"Invalid instruction: {instr}. Expected format: <gate>:<params>")
print("Examples: H:<target> | RX:<phase>,<target>")
return None
gate, params = parts
try:
params = [ int(p) for p in params.split(",") ]
except:
print("Quantum gate input parameters must be integers.")
print("Examples: Z:0 | X:1")
return None
if gate == "Z": state = self.proc.Z(3, params[0]) * state
elif gate == "X": state = self.proc.X(3, params[0]) * state
elif gate == "H": state = self.proc.H(3, params[0]) * state
else:
print(f"Quantum gate '{gate}' is invalid or unexpected.")
return None
return state main 把flag.txt文件转化为bit,对于每一个bit搞一个刚才的电路,也就是encode之后给q0,会给我们encode的基是Z或者X,然后施加电路 并且对q0和q1进行以Z基测量告诉我们测量结果。接下来我们可以加门然后对q2指定测量基并且测量。
所以如果我们可以通过他给出的信息: 1.encode的基是Z或者X
2.q0和q1进行以Z基测量
3.我们的操作和对q2的指定基测量
通过上面三个信息逆向出来flag最初的bit是00到11中的哪一个即可还原flag
def main():
print("""
╔═════════════════════════════╗
║ Qubitrix's Teleporter ║
║ Terminal (QTT) ║
╠═════════════════════════════╣
║ Every 24 hours, Qubitrix ║
║ will release a secret ║
║ message to our partners. ║
║ Please follow the ║
║ instructions we sent you ║
║ by email from ║
║ info@qubitrix.com. ║
╚═════════════════════════════╝
""")
tp = Teleporter()
bitpairs = tp.bytes_to_bitpairs(open('flag.txt', 'rb').read())
print("bitpairs",bitpairs)
for i, bits in enumerate(bitpairs):
print(f"Qubit {i + 1}/{len(bitpairs)}")
state, basis = tp.prepare(bits)
'''
'''
print(f"Basis : {basis}")
result, state = tp.proc.measure("Z", 3, 0, state)
print(f"Measurement of qubit 0 : {result}")
result, state = tp.proc.measure("Z", 3, 1, state)
print(f"Measurement of qubit 1 : {result}")
'''print("result",result)
print("state",state)'''
instructions = input('Specify the instructions : ')
state = tp.apply_instructions(instructions, state)
if not state:
print("Closing QTT...")
return
basis = input("Specify the measurement basis : ")
result, state = tp.proc.measure(basis, 3, 2, state)
if result is None:
print("Closing QTT...")
return
print(f"Measurement of qubit 2 : {result}") 量子计算相关知识 X和H门往期见过了,这次介绍一下Z门
它用来做相位反转,
然后+和-两个态分别对应:
同样的如果带入到+和-态中可以知道
Z|+>=|->
Z|->=|+>
解题 先把电路分为四段拆解来分析:
我们再明确一下已知条件:
1.encode的基是Z或者X
2.q0和q1进行以Z基测量
3.我们的操作和对q2的指定基测量
所以在决定条件3的测量操作和指定的基之前,我们可以根据1和2进行分类
encode为:Z 00的情况 01的情况
在已知encode为Z的时候,只用区分是01还是00即可
此时看条件2还没有用,q0和q1进行以Z基测量:
而q0此时是+或是-,处于0和1的叠加态,对于这两个状态使用Z基测得0和1的概率相等,无法区分+还是-
但是对于q1和q2来说,00对应的q1和q2是相等的都是00或者11,对于01来说q1和q2都是相反的10或者01
所以可以通过q1和q2来区分即可,对q2使用Z基测量,不用额外施加电路
encode为:X 10的情况
11的情况
同理这里在已知encode为X的时候,只用区分是10还是11即可
这里条件2还没有用, q0和q1进行以Z基测量:
这次q0和q1都没有+或者-都可以测出来,但他们的组合无法区分是10还是11,而q2则都是+或者-是叠加态,所以我们采用X基进行测量,根据前文有
X基:+态测得0,-态测得1
所以我们就可以对测量得到的状态进行归类:
10:000,010,101,111
11:001,011,100,110
这样没有重复的状态可以完美分类。
综上我们针对每次测得的结果都反向映射回00到11即可复原出来flag.txt
最后附上exp脚本,仍然使用pwntools进行交互:
from pwn import *
context(log_level="debug",os="linux")
io = process(['python', 'server.py'])
#io = remote("83.136.251.67",56224)
bits_str = b""
'''io.recvuntil(b'bitpairs')
init=io.recvuntil(b']')
io.success(init)'''
io.recvuntil(b"Qubit 1/")
num=int(io.recv(2))
print("num",num)
for i in range(num):
io.recvuntil(b"Basis : ")
basic=io.recv(1)
print(basic)
io.recvuntil(b"Measurement of qubit 0 : ")
q0=io.recv(1)
print(q0)
io.recvuntil(b"Measurement of qubit 1 : ")
q1=io.recv(1)
print(q1)
if(basic==b"Z"):
if(q0==b"0"):
if(q1==b"0"):
io.recvuntil(b"instructions :")
io.sendline(b"X:1")
io.recvuntil("Specify the measurement basis :")
io.sendline("Z")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"0"):
bits_str+=b"00"
if(q2==b"1"):
bits_str+=b"01"
if(q1==b"1"):
io.recvuntil(b"instructions :")
io.sendline(b"X:1")
io.recvuntil("Specify the measurement basis :")
io.sendline("Z")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"1"):
bits_str+=b"00"
if(q2==b"0"):
bits_str+=b"01"
if(q0==b"1"):
if(q1==b"0"):
io.recvuntil(b"instructions :")
io.sendline(b"X:1")
io.recvuntil("Specify the measurement basis :")
io.sendline("Z")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"0"):
bits_str+=b"00"
if(q2==b"1"):
bits_str+=b"01"
if(q1==b"1"):
io.recvuntil(b"instructions :")
io.sendline(b"X:1")
io.recvuntil("Specify the measurement basis :")
io.sendline("Z")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"1"):
bits_str+=b"00"
if(q2==b"0"):
bits_str+=b"01"
if(basic==b"X"):
if(q0==b"0"):
if(q1==b"0"):
io.recvuntil(b"instructions :")
io.sendline(b"H:2;H:2")
io.recvuntil("Specify the measurement basis :")
io.sendline("X")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"0"):
bits_str+=b"10"
if(q2==b"1"):
bits_str+=b"11"
if(q1==b"1"):
io.recvuntil(b"instructions :")
io.sendline(b"H:2;H:2")
io.recvuntil("Specify the measurement basis :")
io.sendline("X")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"1"):
bits_str+=b"11"
if(q2==b"0"):
bits_str+=b"10"
if(q0==b"1"):
if(q1==b"0"):
io.recvuntil(b"instructions :")
io.sendline(b"H:2;H:2")
io.recvuntil("Specify the measurement basis :")
io.sendline("X")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"0"):
bits_str+=b"11"
if(q2==b"1"):
bits_str+=b"10"
if(q1==b"1"):
io.recvuntil(b"instructions :")
io.sendline(b"H:2;H:2")
io.recvuntil("Specify the measurement basis :")
io.sendline("X")
io.recvuntil("Measurement of qubit 2 : ")
q2=io.recv(1)
print("q2",q2)
if(q2==b"1"):
bits_str+=b"10"
if(q2==b"0"):
bits_str+=b"11"
print("bit_str",bits_str)
binary_string = bits_str.decode('ascii')
bytes_list = [binary_string[i: i + 8] for i in range(0, len(binary_string), 8)]
chars = [chr(int(byte, 2)) for byte in bytes_list]
result_string = ''.join(chars)
print("转换后的字符串:", result_string)
io.interactive()
最后于 10小时前
被枫林路大砍刀编辑
,原因: