from qiskit.circuit import QuantumRegister, QuantumCircuit def get_oracle(plaintext: str, ciphertext: str, insert_barriers=Trueinsert_barriers: bool = True) -> QuantumCircuit: assert len(plaintext) == len(ciphertext), "The lengths of the plaintext and ciphertext must match" n_bits = len(plaintext) # Key is n_bits-bit long qc = QuantumCircuit(n_bits) # We have to check whether the key XORed with the plaintext is equal to the ciphertext # First, we compute the key XORed with the plaintext, which is done via X gates for index, bit in enumerate(plaintext[::-1]): # [::-1] to comply with Qiskit's little-endian if bit == "1": qc.x(index) if insert_barriers: # Just for better visualization qc.barrier() # We now want to flip the state if it is equal to the ciphertext # A C^n-Z operation will flip the state if all qubits are in 1, we just have to # flip the bits of the state that should correspond to a 0 in the ciphertext for index, bit in enumerate(ciphertext[::-1]): # [::-1] to comply with Qiskit's little-endian if bit == "0": qc.x(index) if insert_barriers: # Just for better visualization qc.barrier() # Apply MCZ gate using MCX qc.h(n_bits - 1) qc.mcx(list(range(n_bits - 1)), [n_bits - 1]) qc.h(n_bits - 1) if insert_barriers: # Just for better visualization qc.barrier() # Reverse the X gates for index, bit in enumerate(ciphertext[::-1]): # [::-1] to comply with Qiskit's little-endian if bit == "0": qc.x(index) if insert_barriers: # Just for better visualization qc.barrier() for index, bit in enumerate(plaintext[::-1]): # [::-1] to comply with Qiskit's little-endian if bit == "1": qc.x(index) return qc You can convince yourself that this oracle will flip the (basis) input state if and only if it is equal to $|0001\rangle$. Note that I used Qiskit's little-endian convention, where the rightmost qubit in a tensor product is indexed $0$.
Tested with qiskit in version 1.4.2.
