BB84におけるノイズの影響

BB84でノイズが入ると，結果にどんな影響が現れるのか，qiskitを用いて実験してみました．

# BB84について
AliceとBobで乱数を共有したい状況を考えます．Aliceは送りたいビットが$0$ならば$|0\rangle,|+\rangle$を，$1$ならば$|1\rangle,|-\rangle$をランダムに準備し，Bobに送ります．Bobは$Z$測定か$X$測定をランダムに行い，その結果から$0$か$1$かを判定します．この後に，Aliceが準備した状態が固有状態となる演算子[^1]と，Bobが測定した演算子を公開し，これらが一致したタイミングの結果のみを保存します．

詳細は[BB84をQiskitで実装してみた](https://qiita.com/Kumezawa/items/fde80e3c3a776817036f)に記載されていますので，参考にしてみてください．

# ノイズについて
Aliceが状態を作る段階で，ゲート操作が入ります．そこに自作の[量子ノイズ](https://qiita.com/tare_/items/60e4bdc402391840b577)を追加します．

# 実験
コードは[BB84をQiskitで実装してみた](https://qiita.com/Kumezawa/items/fde80e3c3a776817036f)を現在のQiskitに対応するように作り直し，またノイズを追加するように変更しました．

```python
class Person(object):

    def __init__(self, message_length):
        self.message_length = message_length

    # 任意の2進数を生成する。
    def generate_bit(self):
        bits_list =  [random.randint(0, 1) for _ in range(self.message_length)]
        return ''.join(map(str, bits_list))

    # キーを生成する
    def generate_key(self, bits1, bits2, target):
        key = []
        x = format(int(bits1, 2) ^ int(bits2, 2), 'b').zfill(self.message_length)
        for i in range(self.message_length):
            if '0' == x[i]:
                key.append(int(target[i]))
            else:
                key.append(2)
        return key


class Alice(Person):

    # 初期化
    def __init__(self, message_length, error_prob, error_type):
        self.error_prob = error_prob
        self.error_type = error_type
        super().__init__(message_length)

    # Aliceのaを生成する (Aliceの準備 準備1 2つの2進数の生成)
    def generate_message_and_basis(self):
        self.message = super().generate_bit()
        self.basis = super().generate_bit()

    # Aliceはa,bをもとに量子状態を生成する (Aliceの準備 準備2 量子状態の生成)
    def make_quantum_circuit(self):
        # 量子回路を準備
        self.quantum_register = QuantumRegister(self.message_length, 'q_a')
        self.quantum_circuit = QuantumCircuit(self.quantum_register)
        self.quantum_circuit = self._generate_qubit(self.quantum_circuit, self.quantum_register, self.message, self.basis, self.message_length, self.error_prob)
        return self.quantum_circuit

    # 量子状態を生成する
    def _generate_qubit(self, quantum_circuit, quantum_register, message, basis, message_length, error_prob):
        if self.error_type == "amp_damp":
            error = amp_damp_noise(error_prob)
        elif self.error_type == "dephase":
            error = dephasing_noise(error_prob)
        elif self.error_type == "depolar":
            error = depolarizing_noise(error_prob)

        for i in range(message_length):
            if '0' == message[message_length - 1 - i]:
                if '1' == basis[message_length - 1 - i]:
                    # |+>
                    quantum_circuit.h(quantum_register[i])
                    quantum_circuit.append(error, [quantum_register[i]])
            else:
                if '0' == basis[message_length - 1 - i]:
                    # |1>
                    quantum_circuit.x(quantum_register[i])
                    quantum_circuit.append(error, [quantum_register[i]])
                else:
                    # |->
                    quantum_circuit.x(quantum_register[i])
                    quantum_circuit.append(error, [quantum_register[i]])
                    quantum_circuit.h(quantum_register[i])
                    quantum_circuit.append(error, [quantum_register[i]])
        quantum_circuit.barrier(quantum_register)
        return quantum_circuit


class Bob(Person):

    # 初期化
    def __init__(self, message_length):
        super().__init__(message_length)

    # Bobのbを生成する (Bobによる測定 準備 1つの2進数を生成)
    def generate_basis(self):
        self.basis = super().generate_bit()

    # 量子状態を受信する (AliceからBobへ量子状態の送信)
    def recieve_alice_circuit(self, alice_quantum_circuit):
        # 量子回路を準備
        self.classical_register = ClassicalRegister(self.message_length, 'c_b')
        self.quantum_register = QuantumRegister(self.message_length, 'q_b')
        self.quantum_circuit = QuantumCircuit(self.quantum_register, self.classical_register)
        self.quantum_circuit = alice_quantum_circuit.compose(self.quantum_circuit)

    # Bobによる測定 (Bobによる測定 測定)
    def measure_qubit(self):
        for i in range(self.message_length):
            if '0' == self.basis[self.message_length - 1 - i]:
                self._z_measure(self.quantum_circuit, i, self.classical_register[i])
            else:
                self._x_measure(self.quantum_circuit, i, self.classical_register[i])
        result = execute(self.quantum_circuit, Aer.get_backend('qasm_simulator')).result()
        result_count = result.get_counts()
        self.result_bob = random.choice(list(result_count.keys()))
        return self.result_bob

    # Z測定を行う
    def _z_measure(self, qc, qr, cr):
        qc.measure(qr, cr)

    # X測定を行う
    def _x_measure(self, qc, qr, cr):
        qc.h(qr)
        qc.measure(qr, cr)
```
実際に各ノイズが入るとどの程度エラーが入るか見てみます．今回は4000量子ビット用意し，それをAliceからBobに送っています[^2]．基底照合で25%のシフト鍵が残るので，平均1000ビットの乱数が共有されているという状況です．

![amp_damp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/887541/9573aa4c-6905-1de0-7b83-27f183025868.png)


![dephase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/887541/1cfc294a-dcc0-0415-d318-4513686a1856.png)


![depolar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/887541/3614e9e3-2405-142d-99da-25dc91d16adf.png)


実際のBB84では，ノイズもしくは盗聴者がいる場合，このように共有した乱数が一致しないため，誤り訂正，秘匿性増強を行うプロセスが入ります[^3]．また，鍵エラー率が11%以下であれば誤り訂正・秘匿性増強を用いることで，情報理論的安全な通信が可能となることが知られています[^3]．これより，どのノイズの種類に対しても，ノイズの大きさが十分小さくなくてはならないことが分かります．

鍵エラー率が単調に増加すると思っていましたが，そうなっていないのは，鍵長が短いからだと思われます[^4]．


# 最後に
今回はノイズを含むBB84について計算してみました．


#### Version Information
|Software|Version|
|---|---|
|qiskit|0.45.0|


||System information|
|---|---|
|Python version	|3.10.12|



[^1]:つまり，Aliceが$|0\rangle,|1\rangle$を準備した場合は$Z$，$|+\rangle,|-\rangle$を準備した場合は$X$が対応する．どちらの演算子に対応する状態をBobに送ったかを公開する．

[^2]:また，ノイズによってAliceとBobの共有した乱数がどの程度異なるか調べたいので，乱数の長さは長くしました．Qiskitでは１量子ビットゲートしか使わなくても，量子ビット数が増えるとシミュレーション時間が膨大になるみたいなので，10量子ビットでの実験を何回も繰り返すようにしました．

[^3]:[量子通信と量子鍵配布](https://www.ieice-hbkb.org/files/S2/S2gun_05hen_01.pdf)(PDF)．この誤り訂正や秘匿性増強のコードか，それに関する記事などあれば教えてください．

[^4]:本当は分散も表示したほうが良いです．気が向いたら更新します．