feat(q-solved): better explanations, add circtuit drawings
Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
This commit is contained in:
parent
d4b4d1df2e
commit
68086057fb
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: "Reversing quantum algorithms ~~for ctf points~~ | q-solved - zer0pts 2022"
|
title: "Reversing quantum algorithms ~~for ctf points~~ | q-solved @ zer0pts 2022"
|
||||||
date: "2022-03-25 18:00:00"
|
date: "2022-03-25 18:00:00"
|
||||||
author: "Juju"
|
author: "Juju"
|
||||||
tags: ["Reverse", "Quantum", "Writeup", "zer0pts"]
|
tags: ["Reverse", "Quantum", "Writeup", "zer0pts"]
|
||||||
@ -17,6 +17,7 @@ show the flag forever :thinking:
|
|||||||
|
|
||||||
## Given files
|
## Given files
|
||||||
|
|
||||||
|
[solve.py](/q-solved/solve.py)
|
||||||
{{< code file="/static/q-solved/solve.py" language="py" >}}
|
{{< code file="/static/q-solved/solve.py" language="py" >}}
|
||||||
|
|
||||||
[circuit.json](/q-solved/circuit.json)
|
[circuit.json](/q-solved/circuit.json)
|
||||||
@ -47,26 +48,122 @@ All that remains to do for us is to understand what that criteria is.
|
|||||||
|
|
||||||
We can see that the oracle is built using the `circuit.json`.
|
We can see that the oracle is built using the `circuit.json`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"memory": 560,
|
||||||
|
"ancilla": 1408,
|
||||||
|
"circuit": [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
280
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
280
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
280
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
8
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
280
|
||||||
|
]
|
||||||
|
],
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
The oracle is composed of 1408 multi-controlled X (MCX) gates, each controlled by 1
|
The oracle is composed of 1408 multi-controlled X (MCX) gates, each controlled by 1
|
||||||
or 3 input qubits with a control state given in the json. Each MCX gate
|
or 3 input qubits with a control state given in the json. Each MCX gate
|
||||||
acts on a dedicated ancilla qubit.
|
acts on a dedicated ancilla qubit.
|
||||||
|
|
||||||
|
On the sample above, we can see that the `circuit` key of the json is an array
|
||||||
|
of 1408 elements. On all examples, we will work on the 5 first elements which
|
||||||
|
are enough to understand what is going on.
|
||||||
|
|
||||||
|
So each element of the `circuit` array corresponds to a MCX, those MCX are
|
||||||
|
themselves array of 1 or 3 elements representing the control qubits of the said
|
||||||
|
gate. Control qubits are represented with an integer and a boolean. The integer
|
||||||
|
is simply the index of the qubit, and the boolean is the opposite of the
|
||||||
|
control state of the qubit. For example `False`, means that the qubit will have
|
||||||
|
control state 1.
|
||||||
|
|
||||||
|
If we take the fist 2 MCX described in the json, it means that we will have the
|
||||||
|
first MCX on the first ancilla qubit controlled by the first input qubit with a
|
||||||
|
control state of 1. The second MCX will act on the second ancilla and will be
|
||||||
|
controlled by the 1st, 9th and 281st input qubits with control states 0, 1 and
|
||||||
|
1 respectively
|
||||||
|
|
||||||
|
Below is a simplified view of the circuit described by the 5 first gates above,
|
||||||
|
where the ancilla qubits are from `q3` to `q7` and where `q0`, `q1` and `q2`
|
||||||
|
correspond to the 1st, 9th and 281st input qubits of the real circuit
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
{{< image src="/q-solved/ancillas.png" style="border-radius: 8px;" >}}
|
||||||
|
|
||||||
After all 1408 MCX, the circuit adds an other MCX on the target qubit
|
After all 1408 MCX, the circuit adds an other MCX on the target qubit
|
||||||
controlled by all ancillas with all control states set to 0. The target qubit
|
controlled by all ancillas with all control states set to 0. The target qubit
|
||||||
is therefore introduced a phase shift when all ancillas are in `|0>`.
|
is therefore introduced a phase shift when all ancillas are in `|0>`.
|
||||||
|
|
||||||
|
Here, the target qubit is represented by `q8`, see how the `q8`'s gate is active
|
||||||
|
only if all ancillas are `|0>`:
|
||||||
|
|
||||||
|
{{< image src="/q-solved/oracle.png" style="border-radius: 8px;" >}}
|
||||||
|
|
||||||
So we want all ancillas to be `|0>` but it is also their original state. We
|
So we want all ancillas to be `|0>` but it is also their original state. We
|
||||||
therfore have to influence the control qubits of each MCX so that none actually
|
therfore have to influence the control qubits of each MCX so that none actually
|
||||||
performs the X gate on any ancilla. This means that among all control qubits of
|
performs the X gate on any ancilla. This means that among all control qubits of
|
||||||
a MCX, at least one must have a state different from its control state, thus
|
a MCX, at least one must have a state different from its control state, thus
|
||||||
deactivating the gate.
|
deactivating the gate.
|
||||||
|
|
||||||
If we look closely, we can see that the control state of a control qubit is `1`
|
|
||||||
when the json specifies `False`, and `0` when `True`.
|
|
||||||
|
|
||||||
Remember, inputs must be different from their control state specified on the
|
Remember, inputs must be different from their control state specified on the
|
||||||
gate. Therefore a qubit marked as `False`, must take value `|0>` to deactivate
|
gate. Therefore a qubit marked as `False`, must take value `|0>` to deactivate
|
||||||
the gate. Similarly, a qubit marked `True` must take value `|1>`.
|
the gate since `False`, gives the qubit a control state of 1. Similarly, a qubit marked `True` must take value `|1>`.
|
||||||
|
|
||||||
So we said earlier that the MCX have either 3 or 1 control bits and that at
|
So we said earlier that the MCX have either 3 or 1 control bits and that at
|
||||||
least 1 of the control qubits must mismatch from their control state.
|
least 1 of the control qubits must mismatch from their control state.
|
||||||
@ -79,6 +176,12 @@ only the obvious qubits: the ones controlling an ancilla by themselves.
|
|||||||
Indeed if an ancilla is controlled by a single input qubit then this qubit MUST
|
Indeed if an ancilla is controlled by a single input qubit then this qubit MUST
|
||||||
be different from his control state so the X gate stays disabled. Therefore, any input qubit marked as `False` and as the only control of a gate MUST be set to `|0>` to match the oracle. Same is true for qubits marked as `True` that must be in state `|1>`.
|
be different from his control state so the X gate stays disabled. Therefore, any input qubit marked as `False` and as the only control of a gate MUST be set to `|0>` to match the oracle. Same is true for qubits marked as `True` that must be in state `|1>`.
|
||||||
|
|
||||||
|
We can illustrate this with the circuit below: `q3` MUST be set to `|0>` so the
|
||||||
|
gate must be deactivated, so `q0` MUST be `|0>` (control state 1) to deactivate
|
||||||
|
the gate.
|
||||||
|
|
||||||
|
{{< image src="/q-solved/oracle.png" style="border-radius: 8px;" >}}
|
||||||
|
|
||||||
So let's try to set all obvious qubits:
|
So let's try to set all obvious qubits:
|
||||||
|
|
||||||
{{< code file="/static/q-solved/poc_flag.py" language="py" >}}
|
{{< code file="/static/q-solved/poc_flag.py" language="py" >}}
|
||||||
@ -99,6 +202,24 @@ We will have a total of 1408 equations, 1 for each MCX, each equation basically
|
|||||||
saying that at least 1 qubit must be different from its control state, and
|
saying that at least 1 qubit must be different from its control state, and
|
||||||
therefore equal to its assigned boolean in the json.
|
therefore equal to its assigned boolean in the json.
|
||||||
|
|
||||||
|
Let's take the same circuit again, we will have the following system:
|
||||||
|
|
||||||
|
```
|
||||||
|
q0 == 0
|
||||||
|
q0 == 1 OR q1 == 0 OR q2 == 0
|
||||||
|
q0 == 0 OR q1 == 1 OR q2 == 0
|
||||||
|
q0 == 0 OR q1 == 0 OR q2 == 1
|
||||||
|
q0 == 1 OR q1 == 1 OR q2 == 1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
{{< image src="/q-solved/oracle.png" style="border-radius: 8px;" >}}
|
||||||
|
|
||||||
|
```
|
||||||
|
note: The above system does not have a unique solution, but adding the rest of
|
||||||
|
the circuit will make the solution unique.
|
||||||
|
```
|
||||||
|
|
||||||
Once the system is solved, we will know the state of all qubits that match the
|
Once the system is solved, we will know the state of all qubits that match the
|
||||||
oracle, which is the one outputed by the quantum circuit. We will then be able
|
oracle, which is the one outputed by the quantum circuit. We will then be able
|
||||||
to decode it to get the flag.
|
to decode it to get the flag.
|
||||||
@ -109,7 +230,7 @@ I used z3 to build and solve the equation system:
|
|||||||
|
|
||||||
{{< code file="/static/q-solved/flag.py" language="py" >}}
|
{{< code file="/static/q-solved/flag.py" language="py" >}}
|
||||||
|
|
||||||
Running the script outputs us the equation system, sat indicating that z3 found
|
Running the script outputs us the equation system, `sat` indicating that z3 found
|
||||||
a solution to the system and the decoded solution of the system with the flag:
|
a solution to the system and the decoded solution of the system with the flag:
|
||||||
`zer0pts{FLAG_by_Gr0v3r's_4lg0r1thm}`
|
`zer0pts{FLAG_by_Gr0v3r's_4lg0r1thm}`
|
||||||
|
|
||||||
|
BIN
jujure/static/q-solved/ancillas.png
Executable file
BIN
jujure/static/q-solved/ancillas.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
jujure/static/q-solved/oracle.png
Executable file
BIN
jujure/static/q-solved/oracle.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Loading…
Reference in New Issue
Block a user