Q#で量子鍵配送BB84プロトコルを実装してみる

昨日からQ#を触りはじめたのですが、面倒な線形代数を全部解いてくれてとても楽しいです！（なんで専門の言語がいるのかはまだよくわかりませんが…）

さて、一応Q#はゲート方式の量子コンピュータ用のプログラミング言語とされていますが、本質的に状態ベクトルの時間発展を追っているだけです。ですので、もちろんShorのアルゴリズムやGroverのアルゴリズムを実装するのにも使えますが、それ以外にも量子力学の"実験"をはじめいろいろな好きなことができます。そこで、本稿では、量子鍵配送方式の一つであるBB84プロトコルをQ#上に実装し、たしかにこのプロトコルが盗聴を検出できることを確認してみようとおもいます。

# 注意

筆者は量子情報を別に専門としているわけではないので、何か誤りがあるかもしれません。数学的には正しいと思うのですが。

# はじめに

鍵（=bit列）を交換するのをAliceとBobとし、盗聴者をEveとします。

# BB84プロトコルについて

[英語版wikipedia](https://en.wikipedia.org/wiki/BB84)に載ってます。ただし、光子の偏光を使っていてわかりづらいので、Qubit的なのに直したバージョンを[私のブログ](http://0x90.hatenablog.jp/entry/2018/01/30/000514)においておきます。主な違いといえば、Aliceが偏光フィルターを選ぶ代わりに、あらかじめ$x$あるいは$z$方向のspinを測り、EPR pairを決めた方向に射影していることくらいでしょうか。なお、ある向きのspinを測る方法がQ#に存在するのかどうかわからなかったので、$x$方向のspinを測る際はアダマールゲートに通してから測定することにしました。

# 実装

[github](https://github.com/hajifkd/QSharpSample/tree/master/BB84)においておきます。

BB84.qs中で

```qsharp
    operation IsIdenticalOnExchange (aliceDirection: Bool, bobDirection: Bool, withEve: Bool) : (Bool)
    {
        body
        {
            mutable identical = false;
            using (qubits = Qubit[2])
            {
                let aliceResult = Alice(qubits[0], qubits[1], aliceDirection);

                if (withEve)
                {
                    Eve(qubits[1]);
                }

                let bobResult = Bob(qubits[1], bobDirection);

                if (aliceResult == bobResult)
                {
                    set identical = true;
                }

                Set(Zero, qubits[0]);
                Set(Zero, qubits[1]);
            }

            return identical;
        }
    }
```

のような操作を定義し、これをDriver.csから

```csharp
        static (int, int) Simulation(QuantumSimulator sim, int count, bool withEve)
        {
            var random = new System.Random();

            var sameDirectionNum = 0;
            var identicalNum = 0;

            for (var i = 0; i < count; i++)
            {
                var aliceDirection = random.Next(2) == 0;
                var bobDirection = random.Next(2) == 0;

                if (aliceDirection == bobDirection)
                {
                    sameDirectionNum++;
                }

                var identical = IsIdenticalOnExchange.Run(sim, aliceDirection, bobDirection, withEve).Result;

                if (aliceDirection == bobDirection && identical)
                {
                    identicalNum++;
                }
            }

            return (sameDirectionNum, identicalNum);
        }
```

と呼んでいます。`withEve`が真のときのみ、`qubits[1]`を測定しています。なお、私はまだQ#の文法を全然理解していないばかりかC#の文法もすっかり忘れたので、上のコードはかなりトライアルアンドエラーをくりかえした結果であることを言い訳しておきます :P

# 結果
qubit交換を1, 2, 5, 10, ...と増やしたとき、AliceとBobが同じ方向を測った回数および二人の結果が一致した回数を出しました。

```
Trial: 1
Without Eve: same direction = 0 identical = 0
With Eve: same direction = 0 identical = 0
Trial: 2
Without Eve: same direction = 1 identical = 1
With Eve: same direction = 1 identical = 1
Trial: 5
Without Eve: same direction = 2 identical = 2
With Eve: same direction = 4 identical = 4
Trial: 10
Without Eve: same direction = 5 identical = 5
With Eve: same direction = 7 identical = 6
Trial: 15
Without Eve: same direction = 8 identical = 8
With Eve: same direction = 7 identical = 6
Trial: 20
Without Eve: same direction = 11 identical = 11
With Eve: same direction = 11 identical = 10
Trial: 25
Without Eve: same direction = 10 identical = 10
With Eve: same direction = 12 identical = 8
Trial: 100
Without Eve: same direction = 55 identical = 55
With Eve: same direction = 40 identical = 32
Press any key to continue...
```

たしかに、EveがいるとAliceとBobの測定結果が一致しないことが確かめられました。qubitの交換回数が少ないとわかりませんが、多くなるとわかる様子も見てとれます。