{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "290dd4cc-b40a-4d36-9bba-3deda83df5c2",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"量子鍵分配\"\n",
        "description: \"このモジュールでは、量子状態を用いて暗号化用の鍵を安全に共有し、潜在的な盗聴者を検出する方法を探求します。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore cryptoquote WVXRWVW GSZG YVGGVI NZPV GSRH KIVGGB KVLKOV DROO SZEV VZHRVI GRNV HLOERMT  SLKV NZWV HRNKOV carrat URYYP JIGGY EDGRPOJNCUWQZVMK */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eee1912d-afc9-40bc-be44-a1748492d753",
      "metadata": {},
      "source": [
        "<span id=\"quantum-key-distribution\" />\n",
        "\n",
        "# 量子鍵分配\n",
        "\n",
        "このQiskit in Classroomsモジュールでは、以下のパッケージがインストールされた Python 環境が必要です：\n",
        "\n",
        "* `qiskit` v2.1.0 または新しい\n",
        "* `qiskit-ibm-runtime` v0.40.1 または新しい\n",
        "* `qiskit-aer` v0.17.0 または新しい\n",
        "* `qiskit.visualization`\n",
        "* `numpy`\n",
        "* `pylatexenc`\n",
        "\n",
        "上記のパッケージをセットアップしてインストールするには、 [Qiskitのインストール](/docs/guides/install-qiskit)ガイドをご覧ください。\n",
        "実際の量子コンピュータでジョブを実行するには、 IBM Quantum® のアカウントを設定する必要があります。 [IBM Cloud アカウントの設定](/docs/guides/cloud-setup)ガイドの手順に従ってください。\n",
        "\n",
        "このモジュールはテストされ、5秒のQPU時間を使用した。 これはあくまでも目安である。 実際の使用方法は異なる場合があります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "434034b6-22ab-484a-b4fd-8aab34d2b30a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Uncomment and modify this line as needed to install dependencies\n",
        "#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6e0f0185-e80b-4560-84ae-c24ea7d5ab8a",
      "metadata": {},
      "source": [
        "ケイティ博士（ McCormick ）によるモジュールのウォークスルーを以下でご覧いただくか、 [こちらを](https://youtu.be/R0SOqLwLOR0?si=a0AujghPklDN4iBb)クリックして YouTube でご覧ください。\n",
        "\n",
        "***\n",
        "\n",
        "<IBMVideo id=\"134413658\" title=\"ケイティ McCormick、量子鍵配布と、それがより安全な通信を可能にする方法について説明する。\" />\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f431a6f8-4c58-4549-9d32-fc4e2ba777aa",
      "metadata": {},
      "source": [
        "<span id=\"introduction-and-motivation\" />\n",
        "\n",
        "## はじめにおよび動機\n",
        "\n",
        "情報を暗号化・復号化する方法は無限にあり、文字通り何千通りもの方法が研究されてきた。 ここでは、このプロトコルの量子的な部分に焦点を当てるため、「単純置換」と呼ばれる非常に初期の、非常に単純な暗号化方法に限定する。 量子の部分は、比較的少ない変更で他の多くのプロトコルに適応できるだろう。\n",
        "\n",
        "<span id=\"simple-replacement\" />\n",
        "\n",
        "### 単純な置換\n",
        "\n",
        "単純な置き換え暗号化とは、ある文字や数字が別の文字や数字に置き換えられるもので、メッセージ内の文字や数字と暗号化されたシーケンスで使われる文字や数字が1対1に対応するようなものである。 このようなポップカルチャーの例として、クリプトクオートやクリプトグラム・パズルがある。このパズルでは、引用文やフレーズが単純な置き換えを使って暗号化されており、プレイヤーはそれを解読するのが仕事である。 これらの問題は、十分な長さがあれば簡単に解決できる。 例を考えてみよう：\n",
        "\n",
        "r wvxrwvw gszg r'w yvggvi nzpv gsrh kivggb OLMT  gszg dzb, kvlkov droo szev zm vzhrvi grnv hloermt rg.  R SLKV R NZWV RG HRNKOV VMLFTS\n",
        "\n",
        "これらを手作業で解く人は、たいてい元のメッセージの言語構造に精通したトリックを使う。 たとえば英語では、暗号化された \"R \"のような一文字の単語は \"a \"と \"I \"しかない。 例えば \"KIVGGB \"で暗号化された二重文字は、ある特定の値しか取ることができない。 例えば、「GSZG」のパターンに当てはまる最も一般的な単語は「that」である。 この問題を解決するためにコードを使う人には、英単語が見つかるまで可能性をスキャンし、その単語を保持したまま更新するなど、より多くの選択肢がある。 シンプルだが強力な方法のひとつが、文字の頻度を利用することである。特に、英語の代表的なサンプルを構成するのに十分な長さのメッセージの場合。\n",
        "\n",
        "<span id=\"check-in-question\" />\n",
        "\n",
        "### チェックインに関する質問\n",
        "\n",
        "もしよければ、これを解読してみてください。ただし、このモジュールの残りの部分を進める上で必須ではありません。 下の「回答」をクリックしてメッセージを表示してください。\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"回答\">\n",
        "    これはかなり長くした方がいいと思ったんだ。 そうすれば、人々は解決しやすくなる。 簡単に説明できたと思う。\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e73c7eb5-6bf7-40d9-ab7b-cd407d737f23",
      "metadata": {},
      "source": [
        "上記の例では、暗号化された文字から復号化された文字へのマッピングである「キー」が関連付けられている。 この場合、重要なのは\n",
        "\n",
        "* A（使わないのでZとする）\n",
        "* B->Y\n",
        "* C（使わないのでXとする）\n",
        "* D->W\n",
        "* E->V\n",
        "* F->U\n",
        "* ...\n",
        "\n",
        "その他も同様です。 控えめに言っても、これは良いキーではない。 暗号化された文字と復号化された文字が単純にアルファベットをシフトしたもの（A->B、B->Cのように）である鍵は「シーザー・シフト」暗号と呼ばれる。\n",
        "\n",
        "これらは短いと非常に難しいことに注意してほしい。 実際、非常に短い場合は不定愁訴となる。 以下について考えてください。\n",
        "\n",
        "URYYP\n",
        "\n",
        "さまざまなキーを使って、多くの解読が可能だ：hello、petty、happy、jiggy、stool。 他に思い当たることはありますか？\n",
        "\n",
        "しかし、このようなメッセージを何通も送れば、いずれ暗号は解読されてしまう。 だから、同じ「キー」を頻繁に使うべきではない。 実際、ある代替案を一度だけ使うのがベストだ。 たった1つのメッセージではなく、 *たった1つのキャラクターに対してだ！* これは、メッセージで使用される各文字の暗号化スキームやキーを順番に用意することを意味する。 このメッセージを使って友人にメッセージを送りたい場合、あなたと友人は、この刻々と変化するキーが書かれたパッド（昔でいう紙）が必要になる。 これは一度しか使わない。 これは「ワンタイムパッド」と呼ばれる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c890314b-7eb2-48f0-87af-63ffca346c58",
      "metadata": {},
      "source": [
        "<span id=\"the-one-time-pad\" />\n",
        "\n",
        "### ワンタイムパッド\n",
        "\n",
        "これがどのように機能するか、例で見てみよう。 これをすべて文字で行うこともできるが、文字から数字に変換するのが一般的で、例えば、 A=0、 B=1、 C=2…。\n",
        "私たちが秘密活動をしている友人で、パッドを共有していたとする。 理想を言えば、多くのパッドを共有することだが、今日はそれだ：\n",
        "\n",
        "edgrpojncuwqzvmk..\n",
        "\n",
        "あるいは、アルファベット順の数字に変換する：\n",
        "\n",
        "4,3,6,17,15, 14, 9, 13, 2, 20, 22, 16, 25, 21, 12, 10..\n",
        "\n",
        "仮定の話だが、私はこのメッセージを共有したい：\n",
        "\n",
        "\"量子大好き！\"\n",
        "\n",
        "または、次の指定でも等価\n",
        "\n",
        "8, 11, 14, 21, 4, 16, 20, 0, 13, 19, 20, 12\n",
        "\n",
        "これは単純な置換であり、まったく安全ではない。 これを何らかの方法でキーと組み合わせたい。 一般的な方法は加算モジュロ26である。 メッセージの末尾に達するまで、メッセージの値をキーの値に加算していく。 というわけで、私たちは\n",
        "\n",
        "8+4 (mod 26) = 12, 11+3 (mod 26) = 14, 14+6 (mod 26) = 20, 21+17 (mod 26) = 12...\n",
        "\n",
        "\\= 12, 14, 20, 12, 19, 4, 3, 13, 15, 13, 16, 2\n",
        "\n",
        "もし誰かがこの暗号を傍受し、鍵を持っていない場合、解読は完全に絶望的である！ quantum \"の2つの \"u \"が同じ数字でエンコードされているわけでもない！ 1つ目は3で、2つ目は16...同じ単語だ！\n",
        "\n",
        "だから、これをあなたに送ります。あなたも私と同じ鍵を持っているはずです。 私が行ったと知っている26モジュロの足し算を元に戻すのだ：\n",
        "\n",
        "12, 14, 20, 12, 19, 4, 3, 13, 15, 13, 16, 2\n",
        "\n",
        "\\=( 4+x1 ) (mod 26), ( 3+x2 ) (mod 26), ( 6+x3 ) (mod 26), ( 17+x4 ) (mod 26),..\n",
        "\n",
        "メッセージ x1, x2, x3, x4… は、以下のようでなければならない\n",
        "\n",
        "8, 11, 14, 21..\n",
        "\n",
        "最後に、これをテキストに変換すると次のようになる\n",
        "\n",
        "「量子を愛している」。\n",
        "\n",
        "これは1回限りのパッドだ。\n",
        "\n",
        "キーがメッセージより短い場合は、エンコードを繰り返すことになる。 それでも解読は難しいが、何度も繰り返せば不可能ではない。 だから、長いキー（または \"パッド\"）が必要なのだ。\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  多くの文脈では、生徒はすでにこの暗号化に慣れているので、この活動は省略できる。 しかし、比較的短時間で簡単にリフレッシュできる。\n",
        "\n",
        "  ステップ1：パートナーを見つけ、キーとなる4文字の並びを共有する。 クラスにふさわしい4文字の並びであれば何でもよい。 \\ ステップ2: パートナーに送りたい4文字の秘密の単語を選ぶ(両方のパートナーがこれを行うので、お互いに異なる秘密の単語を送ることになる) \\ ステップ3: 4文字のキー/パッドと4文字の秘密の単語を、A = 1、B = 2というように数字に変換する。 \\ ステップ4：モジュロ26の加算を使って、4文字の単語とワンタイムパッドを組み合わせる。 \\ ステップ5: あなたの秘密の言葉を暗号化した数列をパートナーに手渡し、パートナーもあなたの秘密の言葉を暗号化した数列を手渡す。 \\ ステップ6：モジュロ26の引き算を使って、お互いの言葉を解読する。 \\ ステップ7：検証 うまくいったのか？\n",
        "\n",
        "  <span id=\"follow-up\" />\n",
        "\n",
        "  #### ファローアップ\n",
        "\n",
        "  暗号化された単語を、ワンタイムパッドにアクセスできない別のグループと交換する。 解読できるか？ その理由を説明してほしい\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7959630e-aa0a-4a40-bfa9-af2cb58803f7",
      "metadata": {},
      "source": [
        "上記の活動で、ワンタイムパッドが解読不可能な暗号化であることが明らかになっただろう：\n",
        "\n",
        "* キーは送信されるメッセージと同じ長さか、それ以上である\n",
        "* 鍵は本当にランダム\n",
        "* キーは一度だけ使用され、その後破棄される\n",
        "\n",
        "だからこれは素晴らしいことだ。 私たちは解読不可能な暗号を持っている... 誰かが私たちの鍵を盗まない限り。 もし誰かが私たちの鍵を手に入れたら、すべてが解読されてしまう。 解読不可能な暗号化と、すべての秘密が暴露されることのこの違いが、安全な鍵の共有を極めて重要なものにしている。 量子鍵配布の目的は、自然が量子情報に課した制約を利用して、共有鍵／ワンタイムパッドを安全にすることである。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d772bbcf-ed71-4ff3-8eca-06095ec430db",
      "metadata": {},
      "source": [
        "<span id=\"using-quantum-states-as-a-key\" />\n",
        "\n",
        "## 量子状態を鍵として利用する\n",
        "\n",
        "量子ビットを扱っていると仮定しよう（量子ビットには2つの固有状態があることを強調しておく）。 より多くの量子状態を持つ量子システムを使うこともできるが、 IBM® にある最先端の量子コンピューターは量子ビットを使っている。 A、B、Cを 0’s と 1’s のシーケンスにエンコードするのは問題ない。 従って、 0’s と 1’s の鍵を共有し、文字を格納する各ビットに対して2のモジュロ加算を行えば十分である。\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### 理解度チェック\n",
        "\n",
        "本当に英字だけにこだわるなら、何ビット必要なのか？\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"回答\">\n",
        "    $$\n",
        "    2^4=16\\\\\n",
        "    2^5 = 32 \\rightarrow 5 \\text{ bits}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "私たちの友人であるアリスとボブは、他の誰にも傍受されないように（少なくとも彼らが知らないうちに）量子鍵を共有したいと考えています。 互いに量子状態を送り合う方法が必要なのだ。 これを忠実に、ノイズやエラーなく行うことは、決して簡単なことではない。 しかし、現時点では2つのアプローチがある：\n",
        "\n",
        "1. 光ファイバーケーブルは光を送ることができる...これは非常に量子力学的なものだ。 単一光子は、何キロメートルもの光ファイバーケーブルで忠実に検出することができる。 これは完璧でエラーのない量子チャンネルではないが、非常に優れたものである可能性はある。\n",
        "2. 前のモジュールで説明したように、量子テレポーテーションを使うこともできる。 つまり、アリスとボブはもつれた量子ビットを共有し、テレポーテーション・プロトコルを使ってアリスからボブに状態を送ることができる。\n",
        "\n",
        "このモジュールでは、光子を共有するための忠実度の高い光学系のセットアップを要求したくないので、量子状態を共有するための2番目の方法を使う。 しかし、これは量子鍵の長距離共有が最も現実的であるということではない。\n",
        "\n",
        "ここでは、 [1984年にチャールズ・ベネットとジル・ブラッサールによって](https://www.sciencedirect.com/science/article/pii/S0304397514004241?via%3Dihub)初めて考案された、アリスからボブへ異なるベースで測定された状態を共有するためのプロトコルを探求する。 巧妙な測定法を用いて、後の暗号化で使用するキーを構築する。 言い換えれば、私たちは通信を望む2つの当事者間で量子鍵を配布しているのであり、それゆえ「量子鍵配布」（QKD）なのである。\n",
        "\n",
        "<span id=\"qkd-step-1-alices-random-bits-and-random-bases\" />\n",
        "\n",
        "### QKDステップ1：アリスによるランダムビットとランダムベース\n",
        "\n",
        "アリスはまず0と1のランダムなシーケンスを生成する。 そして彼女は、各ランダムビットに基づき、量子状態を準備するための基底を、以下の表（ボブも持っている表）を使ってランダムに選択する：\n",
        "\n",
        "| ベース | ビット = 0          | ビット = 1          |\n",
        "| --- | ---------------- | ---------------- |\n",
        "| Z   | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ |\n",
        "| X   | $\\vert +\\rangle$ | $\\vert -\\rangle$ |\n",
        "\n",
        "例えば、アリスがランダムに0を生成し、ランダムにXの基底を選択したとしよう。 そして、量子状態 $|\\psi\\rangle = |+\\rangle_x = \\frac{1}{\\sqrt{2}}(|0\\rangle+|1\\rangle)$。量子のランダム性を利用して、0と1のランダムなセットと、ランダムな基底選択を生成することができるのは確かだ。 とりあえず、以下のようにランダムなセットが生成されたと仮定しよう：\n",
        "\n",
        "| アリスのビット | 0                | 1                | 0                | 0                | 1                | 1                | 0                | 1                | 0                | ... |\n",
        "| ------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- |\n",
        "| アリスのベース | X                | X                | Z                | Z                | Z                | X                | Z                | Z                | X                | ... |\n",
        "| アリスの州   | $\\vert +\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "\n",
        "このランダムなビット、ベース、そしてその結果の状態のセットは、十分な長さのキーを与えるために、長いシーケンスで続くだろう。\n",
        "\n",
        "<span id=\"qkd-step-2-bobs-random-bases\" />\n",
        "\n",
        "### QKDステップ2：ボブのランダムベース\n",
        "\n",
        "ボブもランダムにベースを選ぶ。 しかし、アリスが自分の状態を準備するために基底の選択を使っていたのに対し、ボブはこれらの基底で実際に測定を行う。 もしボブが、アリスが状態を準備したのと同じ基準で測定をすれば、ボブの測定結果を予測することができる。 アリスが準備に使った基底と違う基底をボブが選んだ場合、ボブの測定結果を知ることはできない。\n",
        "\n",
        "| アリスのビット      | 0                | 1                | 0                | 0                | 1                | 1                | 0                | 1                | 0                | ... |\n",
        "| ------------ | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- |\n",
        "| アリスのベース      | X                | X                | Z                | Z                | Z                | X                | Z                | Z                | X                | ... |\n",
        "| アリスの州        | $\\vert +\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブのベース       | X                | Z                | X                | Z                | X                | X                | Z                | X                | X                | ... |\n",
        "| ボブの状態（アプリオリ） | $\\vert +\\rangle$ | ?                | ?                | $\\vert 0\\rangle$ | ?                | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | ?                | $\\vert +\\rangle$ | ... |\n",
        "| ボブの状態（測定値）   | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2a414fb1-1f9a-47f1-aa1e-6f586539b5d4",
      "metadata": {},
      "source": [
        "下の表で、最初の列を考えてみよう。 アリスはXの固有状態である状態 $\\vert +\\rangle,$。ボブもX基底で測定することをランダムに選んだので、ボブの測定状態には1つの結果しかありえない： $\\vert +\\rangle.$ しかし2番目の列では、2人は異なる基底を選んでいる。 アリスが送った状態は、 $\\vert -\\rangle = \\frac{1}{\\sqrt{2}}(\\vert 0\\rangle-\\vert 1 \\rangle).$ これは、ボブが $\\vert 0\\rangle$ の状態で測定する確率は50％で、 $\\vert 1\\rangle.$ の状態で測定する確率は50％である。したがって、ボブの測定について先験的にわかっていることを示す行は、列2については埋めることができない。 しかし、ボブは測定を行い、（その列の）Zの固有状態を得る。 下段には、これらの測定で得られた結果を記入した。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f097d83-7489-4427-9f5e-a8955589c47c",
      "metadata": {},
      "source": [
        "<span id=\"qkd-step-3-public-discussion-of-bases\" />\n",
        "\n",
        "### QKDステップ3：基盤に関する公開討論\n",
        "\n",
        "アリスとボブは今、それぞれのケースでどのような根拠を選んだかを互いに共有することができる。 偶然に同じ根拠を選択したすべての列について、彼らはそれぞれ相手がどのような状態であったかを確実に知っている。 ボブは、両者が共有する慣習に従って、状態と基底を0か1に変換することができる。 上の表は、アリスとボブのベースが一致した例だけを示すように書き直すことができる：\n",
        "\n",
        "| アリスのビット      | 0                | 0                | 1                | 0                | 0                | ... |     |\n",
        "| ------------ | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- | --- |\n",
        "| アリスのベース      | X                | Z                | X                | Z                | X                | ... |     |\n",
        "| アリスの州        | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |     |\n",
        "| ボブのベース       | X                | Z                | X                | Z                | X                | X   | ... |\n",
        "| ボブの状態（アプリオリ） | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |     |\n",
        "| ボブの状態（測定値）   | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |     |\n",
        "| ボブのビット       | 0                | 0                | 1                | 0                | 0                | ... |     |\n",
        "\n",
        "アリスはビット列00100の送信に成功した。 ボブへ もし友人たちが前もって、ワンタイムパッドの数字として5ビットの文字列を使うことに合意していたとしたら、最初の5ビットが数字になる。 $4 = 0\\times2^4+0\\times2^3+1\\times2^2+0\\times2^1+0\\times2^0.$\n",
        "\n",
        "<span id=\"qkd-step-4-verify-and-send-secret\" />\n",
        "\n",
        "### QKDステップ4：秘密鍵の確認と送信\n",
        "\n",
        "アリスとボブは先に進む前に、古典的なビットのサブセットを選んで比較する。 同じ基準で準備され測定された量子ビットの測定値しか保持していないので、すべての測定値は一致するはずである。 一致しない割合が非常に少なかった場合、これは量子ノイズやエラーに起因する可能性がある。 しかし、多くの人が同意しないのであれば、何かが間違っている！\n",
        "\n",
        "ここでは、鍵の何分の1を検証に使うかについては触れない。 今のところ、このチェックがうまくいったと仮定する。この点については、後述の盗聴のセクションで再確認する。\n",
        "\n",
        "その後、友人たちは古典的なチャンネルを使って暗号化されたメッセージを送り合う。 そして、ワンタイムパッドの数字を使って秘密のメッセージを暗号化／復号化する。 盗聴に関する次のセクションでは、暗号化された秘密が古典的なチャネルを通じて暴露される前に、このような鍵の共有がすべて行われることに留意してほしい。\n",
        "\n",
        "アリスとボブは古典的なチャンネルを使って選択の根拠を伝えた そのとおりです! しかし、彼らがどのような基準で計測したかを知るだけでは、彼らがどのようなビットを送ったのか、あるいは入手したのかはわからない。 それが可能なのは、アリスのスタートビットを知っている場合だけだ。 しかし、その場合、あなたは秘密が保存されているアリスのコンピュータの中にいることになり、秘密の通信は無意味になる。 そのため、古典的な通信を傍受しても、暗号が破られることはない。 しかし、量子チャンネルで情報を傍受するのはどうだろう？\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6a57eebd-2525-4613-a4a0-2e40e507c4c7",
      "metadata": {},
      "source": [
        "<span id=\"resistance-of-qkd-to-eavesdropping\" />\n",
        "\n",
        "## 量子鍵配送（QKD）の盗聴に対する耐性\n",
        "\n",
        "アリスとボブには盗聴で有名な友人イブがいる。 EveはAliceとBobの量子鍵を傍受し、2人の間で送信されるメッセージの解読に使いたい。 アリスが状態を準備してからボブが状態を測定するまでの間に、測定が量子状態を崩壊させるので、これは必然的に起こる。 特に、盗聴は基地の共有や比較が行われる*前に*行われなければならないということだ。\n",
        "\n",
        "イヴは、各ビットのエンコードにどのベースが使われたかを推測しなければならない。 繰り返すが、もし彼女がアリスのコンピューターにアクセスできなければ、この推測の根拠となるものは何もない。 アリスのスタートが以前と同じであると仮定し、さらにボブの測定基準のランダムな選択が以前と同じであると仮定しよう。 イヴが量子チャンネルを測定した場合、何が得られるかを埋めてみよう。 先ほどと同じように、イヴがたまたまアリスと同じベースを選択した場合、彼女が何を得るかはわかっている。 そうでない場合、彼女は2つの結果のどちらかを得る可能性があり、それぞれの確率は50％である。\n",
        "\n",
        "| アリスのビット      | 0                | 1                | 0                | 0                | 1                | 1                | 0                | 1                | 0                | ... |\n",
        "| ------------ | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- |\n",
        "| アリスのベース      | X                | X                | Z                | Z                | Z                | X                | Z                | Z                | X                | ... |\n",
        "| アリスの州        | $\\vert +\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イヴの推測ベース     | Z                | X                | X                | Z                | X                | Z                | Z                | X                | X                | ... |\n",
        "| イブの状態（アプリオリ） | ?                | $\\vert -\\rangle$ | ?                | $\\vert 0\\rangle$ | ?                | ?                | $\\vert 0\\rangle$ | ?                | $\\vert +\\rangle$ | ... |\n",
        "| イブの状態（測定値）   | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブのベース       | X                | Z                | X                | Z                | X                | X                | Z                | X                | X                | ... |\n",
        "\n",
        "今、イブはアリスの基礎と一致したかどうかを知らないので、アリスの元の状態と一致させるためにボブに何を送信すればいいのかわからない。 例えば、イヴが $|0\\rangle,$、彼女が確実に知っているのは、 *アリスが*その量子ビットの状態 $|1\\rangle$。 しかし、アリスは $|0\\rangle,$ $|+\\rangle,$、または $|-\\rangle.$ すべてがイヴの測定と一致する可能性がある。 だから、イブは選択しなければならない。 彼女は自分が測定した状態を正確に送るかもしれないし、自分の測定がアリスから送られた固有状態でない例を推測しようとするかもしれない。 私たちのテーブルにはミックスを入れる：\n",
        "\n",
        "| アリスのビット      | 0                | 1                | 0                | 0                | 1                | 1                | 0                | 1                | 0                | ... |\n",
        "| ------------ | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- |\n",
        "| アリスのベース      | X                | X                | Z                | Z                | Z                | X                | Z                | Z                | X                | ... |\n",
        "| アリスの州        | $\\vert +\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イヴの推測ベース     | Z                | X                | X                | Z                | X                | Z                | Z                | X                | X                | ... |\n",
        "| イブの状態（アプリオリ） | ?                | $\\vert -\\rangle$ | ?                | $\\vert 0\\rangle$ | ?                | ?                | $\\vert 0\\rangle$ | ?                | $\\vert +\\rangle$ | ... |\n",
        "| イブの状態（測定値）   | $\\vert 1\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イブの状態（送信済み）  | $\\vert 1\\rangle$ | $\\vert 0\\rangle$ | $\\vert 1\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | ... |\n",
        "| ボブのベース       | X                | Z                | X                | Z                | X                | X                | Z                | X                | X                | ... |\n",
        "| ボブの状態（アプリオリ） | ?                | $\\vert 0\\rangle$ | ?                | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブの状態（測定値）   | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブのビット       | 1                | 0                | 0                | 0                | 1                | 0                | 0                | 1                | 0                | ... |\n",
        "\n",
        "この時点で、\"なぜイヴはアリスの量子状態のコピーを作り、一方を測定用に保存しておき、もう一方をボブに送信しないのか？\"と問うのが妥当だろう 答えは [「ノー・クローン」の定理](https://en.wikipedia.org/wiki/No-cloning_theorem)である。 非公式に言えば、任意の量子状態の2つ目のコピーを、1つ目のコピーを保持したまま作ることのできるユニタリー（量子力学的）操作は存在しない、ということである。 証明は比較的簡単なので、ガイド付きの練習問題として残しておく。 しかし今は、イヴが量子状態のコピーを作ることは自然界の基本法則によって禁じられており、これがQKDの原則的な強みであることを理解してほしい。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df2fef68-8192-4cc3-90b4-16c22ab52299",
      "metadata": {},
      "source": [
        "以前と同じように、アリスとボブはお互いに電話をかけ、ベースを比較する。 この表を、2人の友人が同じベースを選択したケースに縮小する：\n",
        "\n",
        "| アリスのビット      | 0                | 0                | 1                | 0                | 0                | ... |\n",
        "| ------------ | ---------------- | ---------------- | ---------------- | ---------------- | ---------------- | --- |\n",
        "| アリスのベース      | X                | Z                | X                | Z                | X                | ... |\n",
        "| アリスの州        | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イヴの推測ベース     | Z                | Z                | Z                | Z                | X                | ... |\n",
        "| イブの状態（アプリオリ） | ?                | $\\vert 0\\rangle$ | ?                | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イブの状態（測定値）   | $\\vert 1\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| イブの状態（送信済み）  | $\\vert 1\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert 0\\rangle$ | ... |\n",
        "| ボブのベース       | X                | Z                | X                | Z                | X                | ... |\n",
        "| ボブの状態（アプリオリ） | ?                | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブの状態（測定値）   | $\\vert -\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | $\\vert 0\\rangle$ | $\\vert +\\rangle$ | ... |\n",
        "| ボブのビット       | 1                | 0                | 0                | 0                | 0                | ... |\n",
        "\n",
        "アリスとボブは再びビット列を通信した。 しかし、文字列は一致しない。 左端と中央のビットが反転している。 先ほどの表を見ると、このミスマッチはイブからの妨害に起因していることがわかる。 重要なのは、暗号化された秘密を共有するずっと前に、鍵をセットアップしている間に、ビット列のマッチングを統計することができるということだ。 アリスとボブは、自分たちのチャネルの安全性を確認するために、ワンタイムパッドのビットを好きなだけ自由に使うことができる。 1ビット、あるいはごく一部のビットが一致しなかった場合、これはノイズやエラーに起因する可能性がある。 しかし、ミスマッチのかなりの部分が盗聴であることを示している。 ここでの \"実質的 \"の意味は、使用されるセットアップのノイズに少し依存する。 IBM® 量子コンピュータが何を意味するかは、このプロトコルを実装する際に後述する。 過剰なエラーが検出された場合、アリスとボブは秘密を共有せず、盗聴者を探し始めることができる。\n",
        "\n",
        "<span id=\"caveats\" />\n",
        "\n",
        "### 警告\n",
        "\n",
        "安全性を証明するのは非常に難しい。 実際、ここで大まかに説明したプロトコルは1984年に提案されたもので、安全性が証明されたのはそれから16年後のことである[。](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.85.441) この紹介の範囲を超えている微妙な点がたくさんある。 しかし、このトピックがここで説明されている以上に複雑であることを示すために、いくつか簡単に挙げておこう。\n",
        "\n",
        "* **安全なチャンネル**アリスが量子セットアップ（チャネル）を通して量子ビットを送信し、特に誰かから古典的な応答を聞くとき、我々はその誰かが実際にボブであると仮定した。 もしイヴがこのセットアップに潜入し、アリスの通信が**すべて**イヴとの間で実際に行われ、ボブの通信が**すべて**イヴとの間で実際に行われたとしたら、イヴは事実上鍵を手に入れたことになり、秘密を知ることができる。 まず「安全なチャンネル」を確保しなければならないが、このプロセスには別のプロトコルが必要であり、ここでは扱わない。\n",
        "* **イヴについての仮定：** イブは常に我々の予想を裏切る可能性がある。 ここでは具体的な例を挙げると、私たちは仮定を立てている。 例えば、イヴがボブに送信する状態は、常にイヴが測定時に得た状態そのものであると仮定することができる。 あるいは、彼女が実験的に自分の測定と一致する状態をランダムに選ぶと仮定するかもしれない。 より基本的なことを言えば、ここではイヴが、別の量子系に状態を保存してボブにランダムな量子ビットを送るのとは対照的に、実際に測定を行うことを前提としている。 これらの仮定はプロトコルを理解する上では問題ないが、完全な一般性を証明するものではないことを意味する。\n",
        "* **プライバシーの増幅：** アリスとボブは送信された量子鍵を正確に使う必要はない。 例えば、共有鍵にハッシュ関数を適用することができる。 これは、盗聴者が鍵について不完全な知識を持っていることを利用し、より短いが安全な共有鍵を生成するものである。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ff2a010-6c55-475e-84e8-e57e832ff47c",
      "metadata": {},
      "source": [
        "<span id=\"experiment-1-qkd-with-no-eavesdropper\" />\n",
        "\n",
        "## 実験1：盗聴者なしの量子鍵配送（QKD）\n",
        "\n",
        "盗聴者がいない場合の上記のプロトコルを実装してみよう。 まずはシミュレーターを使って、単純にワークフローを理解する。\n",
        "\n",
        "まず、量子シミュレーターについて：30量子ビットを超える量子問題は、ほとんどのコンピュータではシミュレートできません。 古典的なコンピュータ、スーパーコンピュータ、GPUでは、127量子ビットの量子コンピュータのすべての動作をシミュレートすることはできない。 通常、本物の量子コンピュータを使う動機は、多数のもつれた量子ビットをシミュレートできないからである。 この場合、テレポーテーション方式で情報を移動させない限り、量子ビットのもつれは生じない。 この場合、本物の量子コンピューターを使う動機は異なる。 量子ビットをシミュレートした古典的なコンピューターは、量子状態に関する情報をアリスからボブに送ることができるが、この古典的な情報が傍受された場合、簡単に複製することができ、イブは完全なコピーを保持しながら、別の情報をボブに送ることができる。 これは現実の量子状態では不可能だ。\n",
        "\n",
        "IBM Quantumは、我々が「Qiskitパターン」と呼ぶフレームワークを使って量子コンピューティングの問題に取り組むことを推奨している。 以下のステップで構成される。\n",
        "\n",
        "* ステップ1：問題を量子回路にマップする\n",
        "* ステップ2：実際の量子ハードウェア上で動作するように回路を最適化する\n",
        "* ステップ 3: ランタイム・プリミティブを使って、 IBM 量子コンピュータ上でジョブを実行する\n",
        "* ステップ4：結果の後処理\n",
        "\n",
        "<span id=\"qiskit-patterns-step-1-map-your-problem-to-a-quantum-circuit\" />\n",
        "\n",
        "### Qiskitパターン ステップ1: 問題を量子回路にマッピングする\n",
        "\n",
        "この場合、我々の問題を量子回路にマッピングすることは、単にアリスの状態を準備し、次にボブの測定値を含めることになる。 まず、ランダムビットとランダム基底の選択から始める。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "23a8a5c3-8f59-4130-8f2c-8b2bd50ee698",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit patterns step 1: Map your problem to quantum circuit\n",
        "# Import some generic packages\n",
        "\n",
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "\n",
        "# Set up a random number generator and a quantum circuit. We choose to start with 20 bits, though\n",
        "# any number <30 should be fine.\n",
        "\n",
        "rng = np.random.default_rng()\n",
        "bit_num = 20\n",
        "qc = QuantumCircuit(bit_num, bit_num)\n",
        "\n",
        "# QKD step 1: Random bits and bases for Alice\n",
        "# generate Alice's random bits\n",
        "\n",
        "abits = np.round(rng.random(bit_num))\n",
        "\n",
        "# generate Alice's random measurement bases. Here we will associate a \"0\" with the Z basis, and a\n",
        "# \"1\" with the X basis.\n",
        "\n",
        "abase = np.round(rng.random(bit_num))\n",
        "\n",
        "# Alice's state preparation. Check that this creates states according to table 1\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if abits[n] == 0:\n",
        "        if abase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if abits[n] == 1:\n",
        "        if abase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if abase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# QKD step 2: Random bases for Bob\n",
        "# generate Bob's random measurement bases.\n",
        "\n",
        "bbase = np.round(rng.random(bit_num))\n",
        "\n",
        "# Note that if Bob measures in Z no gates are necessary, since IBM Quantum computers\n",
        "# measure in Z by default.\n",
        "# If Bob measures in the X basis, we implement a hadamard gate qc.h to facilitate the measurement.\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if bbase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(m, m)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3965ff1b-65ed-42d3-8063-470233225660",
      "metadata": {},
      "source": [
        "ビット、ベース、回路を視覚化してみよう。 ベースが一致することもあれば、一致しないこともある。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "2b538952-9e01-43a0-a1e6-a798683f93f0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Alice's bits are  [1. 1. 0. 1. 0. 1. 1. 0. 0. 1. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0.]\n",
            "Alice's bases are  [0. 0. 0. 1. 1. 0. 0. 0. 0. 1. 1. 1. 1. 1. 0. 1. 1. 0. 1. 0.]\n",
            "Bob's bases are  [0. 1. 1. 0. 1. 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 0. 1. 1. 0. 0.]\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/modules/computer-science/quantum-key-distribution/extracted-outputs/2b538952-9e01-43a0-a1e6-a798683f93f0-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "print(\"Alice's bits are \", abits)\n",
        "print(\"Alice's bases are \", abase)\n",
        "print(\"Bob's bases are \", bbase)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03e23821-4bf8-48eb-9b95-46be2d8d6cc8",
      "metadata": {},
      "source": [
        "<span id=\"qiskit-patterns-step-2-optimize-problem-for-quantum-execution\" />\n",
        "\n",
        "### Qiskitパターンステップ2：量子実行のための問題最適化\n",
        "\n",
        "このステップでは、私たちが実行したいオペレーションを、特定の量子コンピュータの機能の観点から表現する。 また、我々の問題を量子コンピューターのレイアウトにマッピングすることもできる。\n",
        "\n",
        "まず、 IBM 量子コンピューターと通信するために必要なパッケージをいくつかロードする。 また、実行するバックエンドも選択しなければならない。 最も忙しくないバックエンドを選ぶか、プロパティがわかっている特定のバックエンドを選ぶことができる。 一時的にシミュレータを使用しますが、シミュレーションでは合理的なノイズモデルを使用することが重要であり、後に実際の量子コンピュータで使用するワークフローにできるだけ近づけることが望ましいです。\n",
        "\n",
        "初回使用時に認証情報を保存するためのコードが以下にあります。 ノートブックを自分の環境に保存した後、必ずこの情報をノートブックから削除してください。そうすれば、ノートブックを共有するときにあなたの認証情報が誤って共有されることはありません。 詳しいガイダンスについては、 [IBM Cloud アカウントの設定](/docs/guides/initialize-account)および[信頼できない環境でのサービスの初期](/docs/guides/cloud-setup-untrusted)化を参照してください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8dd83eea-3fae-4ec8-b2d9-22128c6abb93",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_brisbane\n"
          ]
        }
      ],
      "source": [
        "# Load IBM Quantum Compute Service\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "\n",
        "# Load IBM Quantum Compute Service\n",
        "\n",
        "# Syntax for first saving your token.  Delete these lines after saving your credentials.\n",
        "# QiskitRuntimeService.save_account(channel='ibm_quantum_platform',\n",
        "# instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)\n",
        "# service = QiskitRuntimeService(channel='ibm_quantum_platform')\n",
        "\n",
        "# Load saved credentials\n",
        "service = QiskitRuntimeService()\n",
        "\n",
        "\n",
        "# Use the least busy backend, or uncomment the loading of a specific backend like \"ibm_brisbane\".\n",
        "# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)\n",
        "backend = service.backend(\"ibm_brisbane\")\n",
        "print(backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ce76c75-23c0-48ff-ac22-3f22a19bf1e3",
      "metadata": {},
      "source": [
        "以下では、シミュレーターとノイズモデルを選択する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9032820e-bf2c-4e3c-b61c-d83779121fa3",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Load the backend sampler\n",
        "from qiskit.primitives import BackendSamplerV2\n",
        "\n",
        "# Load the Aer simulator and generate a noise model based on the currently-selected backend.\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel\n",
        "\n",
        "# Load the qiskit runtime sampler\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "\n",
        "noise_model = NoiseModel.from_backend(backend)\n",
        "\n",
        "# Define a simulator using Aer, and use it in Sampler.\n",
        "backend_sim = AerSimulator(noise_model=noise_model)\n",
        "sampler_sim = BackendSamplerV2(backend=backend_sim)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "c21e3999-dedf-4577-b675-0ee57cef41a9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit patterns step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bf22ac2d-e91c-49c7-bbea-751267929235",
      "metadata": {},
      "source": [
        "<span id=\"qiskit-patterns-step-3-execute\" />\n",
        "\n",
        "### Qiskit パターン ステップ 3: 実行\n",
        "\n",
        "サンプラーを使用して、回路を引数としてジョブを実行する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "9e41f310-6ae8-4a99-bd8b-5f70ad9d9ec4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# This required 5 s to run on a Heron r2 processor on 10-28-24\n",
        "sampler = Sampler(mode=backend)\n",
        "job = sampler.run([qc_isa], shots=1)\n",
        "# job = sampler_sim.run([qc], shots = 1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9877e564-3218-45ad-9c9a-c4cdf3cace4b",
      "metadata": {},
      "source": [
        "<span id=\"qiskit-patterns-step-4-post-processing\" />\n",
        "\n",
        "### Qiskitパターン ステップ4: 後処理\n",
        "\n",
        "ここでは結果を解釈し、有益な情報を抽出する。 サンプラーの出力を視覚化してみるのもいいかもしれないが、私たちはサンプラーを型破りな方法で使っている。 私たちの回路を何度も測定し、その状態を統計するのではなく、たった1回（ボブの）測定しただけです。 同じ基準で準備され測定された状態を持つどの量子ビットも、決定論的な結果を持つはずであり、そのような場合、必要な測定は1回だけである。 異なるベースで準備され測定された状態の量子ビット（これは確率的な結果を持ち、解釈するために多くの測定を必要とする）は、ワンタイムパッド／キーの構築に使われることはない。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84b34a33-a399-4cad-ab56-50b05e11801a",
      "metadata": {},
      "source": [
        "このビット列から測定結果のリストを取り出してみよう。 回路の生成に使ったアリスのビット配列と比較する場合は、順序を逆にするように注意すること。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "30ecc2db-65cf-433e-b0c7-962a725df013",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0]\n"
          ]
        }
      ],
      "source": [
        "# Get an array of bits\n",
        "\n",
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "bmeas = list(key)\n",
        "bmeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    bmeas_ints.append(int(bmeas[n]))\n",
        "\n",
        "# Reverse the order to match our input. See \"little endian\" notation.\n",
        "\n",
        "bbits = bmeas_ints[::-1]\n",
        "\n",
        "print(bbits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f60a50c5-7c4f-4da1-94a3-a1507b3753dd",
      "metadata": {},
      "source": [
        "アリスとボブがランダムに選んだ測定ベースを比較してみよう。 これが私たちのQKDプロトコルのステップ3（ベースの公開ディスカッション）だった。 量子ビットに同じ基底を選んだ場合はいつでも、その量子ビットに関連するビットを、ワンタイムパッドの数字を生成するためのビットリストに追加する。 ベースが一致しない場合、結果は破棄される。 また、2つのビットのリストが一致しているか、ノイズやその他の要因によるロスがなかったかも確認しよう。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "a8dddc11-d4b9-4cf9-8944-be111f68c070",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[1, 0, 1, 0, 0, 0, 1, 0]\n",
            "[1, 0, 1, 0, 0, 0, 1, 0]\n",
            "fidelity =  1.0\n",
            "loss =  0.0\n"
          ]
        }
      ],
      "source": [
        "# QKD step 3: Public discussion of bases\n",
        "\n",
        "agoodbits = []\n",
        "bgoodbits = []\n",
        "match_count = 0\n",
        "for n in range(bit_num):\n",
        "    # Check whether bases matched.\n",
        "    if abase[n] == bbase[n]:\n",
        "        agoodbits.append(int(abits[n]))\n",
        "        bgoodbits.append(bbits[n])\n",
        "        # If bits match when bases matched, increase count of matching bits\n",
        "        if int(abits[n]) == bbits[n]:\n",
        "            match_count += 1\n",
        "\n",
        "print(agoodbits)\n",
        "print(bgoodbits)\n",
        "print(\"fidelity = \", match_count / len(agoodbits))\n",
        "print(\"loss = \", 1 - match_count / len(agoodbits))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3842f053-a5c1-42c1-97e0-e64ac2e7364d",
      "metadata": {},
      "source": [
        "アリスとボブはそれぞれビットのリストを持っており、100％の忠実度で一致する。 これらを使ってワンタイムパッドの数字を生成することができる。 そして、QKDのステップ4である秘密の送信と復号に使うことができる。 現在のビット配列は、解読するには短すぎる。 これについては、盗聴を含めてからまた触れたい。\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### 理解度チェック\n",
        "\n",
        "英語アルファベットの文字をアルファベット全長分、あるいはそれ以上ずらすのに十分な大きさの数字が必要だと仮定する。\n",
        "(a) 上記の鍵のビットを使って解読できるメッセージの長さは何文字か？ (b) あなたの答えはクラスメートの答えと一致しなければなりませんか？ その理由は何か?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"回答\">\n",
        "    (a) その答えは、アリスとボブの間で、ランダムに選ばれた塩基のうちいくつが一致したかによって決まる。 どの量子ビットについても、ベースが一致する確率はおよそ50％であるため、10ビット近くが有用であると予想されます。 9や11はごく一般的になるでしょう。 4や15でさえ、あり得ないことではない。 英字アルファベットの文字数以上の桁数だけシフトするには5ビットが必要です。つまり、5ビットごとに1文字のシフト処理を行うことができます。 アリスとボブが共有するビットが5ビット以上あれば、1文字を符号化することができます。 10以上あれば2文字を符号化でき、以下同様です。\n",
        "\n",
        "    (b) (a)で述べた理由により、一致する必要はない。\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "00a56f30-6b75-4f8d-b67a-47671063218b",
      "metadata": {},
      "source": [
        "<span id=\"experiment-2-qkd-with-an-eavesdropper\" />\n",
        "\n",
        "## 実験2：盗聴者を伴う量子鍵配送（QKD）\n",
        "\n",
        "以前とまったく同じプロトコルを実装する。 今度は、アリスとボブの間に、イヴによる別の測定セットを挿入する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "bfe1e1a9-c723-4bda-81f6-e5e3caf0efbf",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister\n",
        "\n",
        "# Qiskit patterns step 1: Mapping your problem to a quantum circuit\n",
        "# QKD step 1: Random bits and bases for Alice\n",
        "\n",
        "bit_num = 20\n",
        "qr = QuantumRegister(bit_num, \"q\")\n",
        "cr = ClassicalRegister(bit_num, \"c\")\n",
        "qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "# Alice's random bits and bases, as before\n",
        "\n",
        "abits = np.round(rng.random(bit_num))\n",
        "abase = np.round(rng.random(bit_num))\n",
        "\n",
        "# Alice's state preparation, as before\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if abits[n] == 0:\n",
        "        if abase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if abits[n] == 1:\n",
        "        if abase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if abase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# Eavesdropping happens here!\n",
        "# Generate Eve's random measurement bases\n",
        "\n",
        "ebase = np.round(rng.random(bit_num))\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if ebase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(qr[m], cr[m])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "e20dd109-d1a2-4bec-86df-4b70c5b76cc4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit patterns step 2: Transpile\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "cfb2f614-8730-47ee-85c7-686b638e0def",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit patterns step 3: Execute\n",
        "job = sampler_sim.run([qc_isa], shots=1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ba084b8-9a71-4b20-a13f-59ba3fba67cf",
      "metadata": {},
      "source": [
        "この場合、Qiskitパターンのステップ4（後処理）は簡単です。 測定は1回だけなので、測定値の分布を可視化する必要はない。 イブには以下のビットがある：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "57dc8ffa-70aa-4a2b-9fdc-42a22bf9f52e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1]\n"
          ]
        }
      ],
      "source": [
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "emeas = list(key)\n",
        "emeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    emeas_ints.append(int(emeas[n]))\n",
        "ebits = emeas_ints[::-1]\n",
        "\n",
        "print(ebits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fc91fcf-3704-498e-8291-58fe07fd3433",
      "metadata": {},
      "source": [
        "さて、イヴはボブに送る状態を再構築しなければならない。 冒頭で述べたように、彼女はエンコーディングのベースを正しく推測したかどうかを知る術がないので、送信されたものとまったく同じ状態を準備することはできない。 彼女はすべての基底の選択が正しいと仮定し、測定したものを正確に符号化することもできるし、基底の選択が間違っていたと仮定し、反対の基底の固有状態のいずれかを選択することもできる。 ここでは簡単のため、前者を仮定する。 私たちは、以前と同じようにQiskitパターンのステップを繰り返しながら、まったく新しい量子回路を構築することでこれを達成する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "7feadfe3-c63e-41e0-9d51-a1b98b5ce67d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1]\n"
          ]
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "# Qiskit patterns step 1: Mapping your problem onto a quantum circuit\n",
        "# QKD step 1: Eve uses her measurements to prepare best guess states to send on to Bob\n",
        "\n",
        "qr = QuantumRegister(bit_num, \"q\")\n",
        "cr = ClassicalRegister(bit_num, \"c\")\n",
        "qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "# Eve's state preparation\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if ebits[n] == 0:\n",
        "        if ebase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if ebits[n] == 1:\n",
        "        if ebase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if ebase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "qc.barrier()\n",
        "\n",
        "# QKD step 2: Random bases for Bob\n",
        "\n",
        "bbase = np.round(rng.random(bit_num))\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if bbase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(qr[m], cr[m])\n",
        "\n",
        "# Qiskit patterns step 2: Transpile\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "\n",
        "# Qiskit patterns step 3: Execute\n",
        "\n",
        "job = sampler_sim.run([qc_isa], shots=1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()\n",
        "\n",
        "# Qiskit patterns step 4: Post-processing\n",
        "\n",
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "bmeas = list(key)\n",
        "bmeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    bmeas_ints.append(int(bmeas[n]))\n",
        "bbits = bmeas_ints[::-1]\n",
        "\n",
        "print(bbits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "211519fb-9f0e-4542-8ec6-49a8fc4032a3",
      "metadata": {},
      "source": [
        "ここでアリスとボブのビットを比較してみよう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "d973b397-d67c-4d54-9a78-cb6606ca65aa",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[1, 1, 0, 0, 0, 1, 1]\n",
            "[1, 1, 0, 0, 0, 0, 1]\n",
            "fidelity =  0.8571428571428571\n",
            "loss =  0.1428571428571429\n"
          ]
        }
      ],
      "source": [
        "agoodbits = []\n",
        "bgoodbits = []\n",
        "match_count = 0\n",
        "for n in range(bit_num):\n",
        "    if abase[n] == bbase[n]:\n",
        "        agoodbits.append(int(abits[n]))\n",
        "        bgoodbits.append(bbits[n])\n",
        "        if int(abits[n]) == bbits[n]:\n",
        "            match_count += 1\n",
        "print(agoodbits)\n",
        "print(bgoodbits)\n",
        "print(\"fidelity = \", match_count / len(agoodbits))\n",
        "print(\"loss = \", 1 - match_count / len(agoodbits))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5783dd96-2fc3-4f9f-a822-51b7782121f5",
      "metadata": {},
      "source": [
        "以前は、アリスとボブの鍵のビットは完全に一致していた。 さて、イヴの妨害から、アリスとボブが同じベースを選択したために、一致するはずの14%のケースで、アリスとボブのビットが異なっていることがわかる。 これはアリスとボブにとって簡単に発見できるはずだ。 しかし、このような誤差の割合に頼るということは、量子チャンネルで許容できるノイズの量に限界があることを意味する。\n",
        "\n",
        "<span id=\"experiment-3-compare-qkd-with-and-without-eavesdropping-on-a-real-quantum-computer\" />\n",
        "\n",
        "## 実験3：実際の量子コンピュータにおける盗聴の有無によるQKDの比較\n",
        "\n",
        "これを実際の量子コンピューターで動かしてみよう。 そうすれば、ノー・クローンの定理を活用できる。 同時に、実際の量子コンピューターにはノイズがあり、古典的なコンピューターよりもエラー率が高い。 そこで、盗聴の有無による鍵ビットの忠実度の損失を比較し、実際の量子コンピュータを使用した場合にその違いが検出可能かどうかを確認してみよう。 盗聴のないところから始めよう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2697eace-2faf-49cc-99f2-d8d7bda28588",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Alice's bits =  [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1]\n",
            "Bob's bits =  [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1]\n",
            "fidelity =  0.9682539682539683\n",
            "loss =  0.031746031746031744\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "# This calculation was run on an Eagle r3 processor on 11-7-24 and\n",
        "# required 3 sec to run, with 127 qubits.\n",
        "# Qiskit patterns step 1: Mapping your problem to a quantum circuit\n",
        "\n",
        "bit_num = 127\n",
        "qc = QuantumCircuit(bit_num, bit_num)\n",
        "\n",
        "# QKD step 1: Generate Alice's random bits and bases\n",
        "\n",
        "abits = np.round(rng.random(bit_num))\n",
        "abase = np.round(rng.random(bit_num))\n",
        "\n",
        "# Alice's state preparation\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if abits[n] == 0:\n",
        "        if abase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if abits[n] == 1:\n",
        "        if abase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if abase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "# QKD step 2: Random bases for Bob\n",
        "\n",
        "bbase = np.round(rng.random(bit_num))\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if bbase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(m, m)\n",
        "\n",
        "\n",
        "# Qiskit patterns step 2: Transpilation\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "# Load the Runtime primitive and session\n",
        "sampler = Sampler(mode=backend)\n",
        "\n",
        "# Qiskit patterns step 3: Execute\n",
        "\n",
        "job = sampler.run([qc_isa], shots=1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()\n",
        "\n",
        "# Qiskit patterns step 4: Post-processing\n",
        "# Extract Bob's bits\n",
        "\n",
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "bmeas = list(key)\n",
        "bmeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    bmeas_ints.append(int(bmeas[n]))\n",
        "bbits = bmeas_ints[::-1]\n",
        "\n",
        "# Compare Alice's and Bob's measurement bases and collect usable bits\n",
        "\n",
        "agoodbits = []\n",
        "bgoodbits = []\n",
        "match_count = 0\n",
        "for n in range(bit_num):\n",
        "    if abase[n] == bbase[n]:\n",
        "        agoodbits.append(int(abits[n]))\n",
        "        bgoodbits.append(bbits[n])\n",
        "        if int(abits[n]) == bbits[n]:\n",
        "            match_count += 1\n",
        "\n",
        "# Print some results\n",
        "\n",
        "print(\"Alice's bits = \", agoodbits)\n",
        "print(\"Bob's bits = \", bgoodbits)\n",
        "print(\"fidelity = \", match_count / len(agoodbits))\n",
        "print(\"loss = \", 1 - match_count / len(agoodbits))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "22813855-8077-4598-bcf2-33bd7c2c37f8",
      "metadata": {},
      "source": [
        "盗聴されることなく、この127の試行ビットセットに対して100％の忠実度が得られ、55の一致したベースと使用可能なキービットが得られた。\n",
        "では、この実験をイヴに聴かせて繰り返してみよう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b311cf3a-ccea-43fe-8bcd-a054296e113e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Alice's bits =  [1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]\n",
            "Bob's bits =  [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1]\n",
            "fidelity =  0.7619047619047619\n",
            "loss =  0.23809523809523814\n"
          ]
        }
      ],
      "source": [
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "# This calculation was run on an Eagle r3 processor on 11-7-24 and\n",
        "# required 2 s to run, with 127 qubits.\n",
        "# Qiskit patterns step 1: Mapping your problem to a quantum circuit\n",
        "\n",
        "bit_num = 127\n",
        "qr = QuantumRegister(bit_num, \"q\")\n",
        "cr = ClassicalRegister(bit_num, \"c\")\n",
        "qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "# QKD step 1: Generate Alice's random bits and bases\n",
        "\n",
        "abits = np.round(rng.random(bit_num))\n",
        "abase = np.round(rng.random(bit_num))\n",
        "\n",
        "# Alice's state preparation\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if abits[n] == 0:\n",
        "        if abase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if abits[n] == 1:\n",
        "        if abase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if abase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "\n",
        "# Eavesdropping happens here!\n",
        "# Generate Eve's random measurement bases\n",
        "\n",
        "ebase = np.round(rng.random(bit_num))\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if ebase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(qr[m], cr[m])\n",
        "\n",
        "# Qiskit patterns step 2: Transpile\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "\n",
        "# Qiskit patterns step 3: Execute\n",
        "\n",
        "job = sampler.run([qc_isa], shots=1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()\n",
        "\n",
        "# Qiskit patterns step 4: Post-processing\n",
        "# Extract Eve's bits\n",
        "\n",
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "emeas = list(key)\n",
        "emeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    emeas_ints.append(int(emeas[n]))\n",
        "ebits = emeas_ints[::-1]\n",
        "\n",
        "# print(ebits)\n",
        "\n",
        "# Restart process\n",
        "# Qiskit patterns step 1: Mapping your problem to a quantum circuit\n",
        "\n",
        "# QKD step 1: Eve uses her measurements above to prepare best guess states to send on to Bob\n",
        "\n",
        "qr = QuantumRegister(bit_num, \"q\")\n",
        "cr = ClassicalRegister(bit_num, \"c\")\n",
        "qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "\n",
        "# Eve's state preparation\n",
        "\n",
        "for n in range(bit_num):\n",
        "    if ebits[n] == 0:\n",
        "        if ebase[n] == 1:\n",
        "            qc.h(n)\n",
        "    if ebits[n] == 1:\n",
        "        if ebase[n] == 0:\n",
        "            qc.x(n)\n",
        "        if ebase[n] == 1:\n",
        "            qc.x(n)\n",
        "            qc.h(n)\n",
        "\n",
        "# QKD step 2: Random bases for Bob\n",
        "\n",
        "bbase = np.round(rng.random(bit_num))\n",
        "\n",
        "for m in range(bit_num):\n",
        "    if bbase[m] == 1:\n",
        "        qc.h(m)\n",
        "    qc.measure(qr[m], cr[m])\n",
        "\n",
        "# Qiskit patterns step 2: Transpile\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "qc_isa = pm.run(qc)\n",
        "\n",
        "# Qiskit patterns step 3: Execute\n",
        "\n",
        "job = sampler.run([qc_isa], shots=1)\n",
        "counts = job.result()[0].data.c.get_counts()\n",
        "countsint = job.result()[0].data.c.get_int_counts()\n",
        "\n",
        "# Qiskit Patterns step 4: Post-processing\n",
        "# Extract Bob's bits\n",
        "\n",
        "keys = counts.keys()\n",
        "key = list(keys)[0]\n",
        "bmeas = list(key)\n",
        "bmeas_ints = []\n",
        "for n in range(bit_num):\n",
        "    bmeas_ints.append(int(bmeas[n]))\n",
        "bbits = bmeas_ints[::-1]\n",
        "\n",
        "# Compare Alice's and Bob's bases, when they are the same, keep the bits.\n",
        "\n",
        "agoodbits = []\n",
        "bgoodbits = []\n",
        "match_count = 0\n",
        "for n in range(bit_num):\n",
        "    if abase[n] == bbase[n]:\n",
        "        agoodbits.append(int(abits[n]))\n",
        "        bgoodbits.append(bbits[n])\n",
        "        if int(abits[n]) == bbits[n]:\n",
        "            match_count += 1\n",
        "\n",
        "# Print some results\n",
        "\n",
        "print(\"Alice's bits = \", agoodbits)\n",
        "print(\"Bob's bits = \", bgoodbits)\n",
        "print(\"fidelity = \", match_count / len(agoodbits))\n",
        "print(\"loss = \", 1 - match_count / len(agoodbits))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1d3fc14a-00e2-476e-a7a2-711c0c9ea6ff",
      "metadata": {},
      "source": [
        "ここでは、盗聴による共有ビットの忠実度の損失がほぼ23％であることがわかった！ これは非常にわかりやすい！ 量子情報を長距離伝送する場合、さらなるノイズやエラーが発生する可能性がある。 ノイズがあっても、イヴがあらゆるトリックを駆使しても、盗聴が検知されることを保証することは、この紹介の域を出ない複雑な分野である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4bb09e34-a249-4ab8-be2b-0205fe1ffefb",
      "metadata": {},
      "source": [
        "<span id=\"questions\" />\n",
        "\n",
        "## 質問\n",
        "\n",
        "指導者は、このノートがどのように使用されているかについての[簡単なアンケートに](https://ibm.biz/classrooms_instructor_key_request)答えることで、解答と一般的なカリキュラムにおける配置についてのガイダンスが付いたバージョンのノートを要求することができる。\n",
        "\n",
        "<span id=\"critical-concepts\" />\n",
        "\n",
        "### 重要な概念\n",
        "\n",
        "* 量子情報はコピーも「クローン」もできない。\n",
        "* 同じ準備プロセスを繰り返すことで、すべて同じ、あるいはほぼ同じ量子状態のアンサンブルを作る*ことが*できる。\n",
        "* 暗号化／復号化キー（ワンタイムパッド）は、量子状態を用いて2人の友人間で共有することができる。\n",
        "* 2人の友人がランダムに測定基準を選ぶということは、半分の時間は異なる選択をし、それらの量子ビットの情報を捨てなければならないことを意味する。\n",
        "* 測定基準をランダムに選択することで、盗聴者は準備された初期状態を知ることができず、したがって送信された状態を再現できないことも保証される。 これにより、盗聴は確実に検知される。\n",
        "\n",
        "<span id=\"t/f-questions\" />\n",
        "\n",
        "### 正誤問題\n",
        "\n",
        "1. T/F 量子鍵配布では、通信を行う2人のパートナーは、それぞれの量子ビットを同じ基底で測定する。\n",
        "2. T/F QKDで量子情報を傍受する盗聴者は、自然の法則によって、傍受した量子状態をコピーすることができない。\n",
        "3. T/F ワンタイムパッドとは、安全なメッセージを暗号化／復号化するための鍵で、特定の符号化方式が1つの情報（アルファベットの1文字など）に対して1度だけ使われる。\n",
        "\n",
        "<span id=\"mc-questions\" />\n",
        "\n",
        "### MCの質問\n",
        "\n",
        "1. 最も適切な選択肢を選んでください。 このモジュールで説明するように、ワンタイムパッドとは、暗号化／復号化キーのセットである。\n",
        "\n",
        "* a. 一文字のような単一の情報に対して一度だけ。\n",
        "* b. 一つのメッセージに対して一度だけ。\n",
        "* c. 1日など決まった期間に1回だけ。\n",
        "* d. 盗聴の証拠が出るまでは。\n",
        "\n",
        "2. アリスとボブが測定ベースをランダムに選ぶと仮定する。 彼らは測定する。 そして、測定ベースを共有し、同じベースを使用したケースの情報の断片だけを保管する。 あるランダムな揺らぎがあるとして、その量子ビットのおよそ何パーセントが使用可能な情報ビットになるのだろうか？\n",
        "\n",
        "* a. 100％\n",
        "* b. 50％\n",
        "* c. 25％\n",
        "* d. 12.5%\n",
        "* e. 0％\n",
        "\n",
        "3. アリスとボブが同じ測定ベースを使用したケースを選択した後、量子ノイズと誤差が無視できるものであれば、それらの情報の何パーセントが一致するはずだろうか？\n",
        "\n",
        "* a. 100％\n",
        "* b. 50％\n",
        "* c. 25％\n",
        "* d. 12.5%\n",
        "* e. 0％\n",
        "\n",
        "4. アリスが測定ベースをランダムに選んだと仮定する。 イヴもランダムにベースを選び、（小節を）聞き込む。 彼女は自分の測定値と一致する状態をボブに送る。 アリスとボブは基底の選択を比較し、同じ基底で測定/準備された量子ビットだけを保持する。 アリスとボブによれば、あるランダムな揺らぎまでは、これらの保持された量子ビットの測定値のうち、およそ何パーセントが一致するのだろうか？\n",
        "\n",
        "* a. 100％\n",
        "* b. 75％\n",
        "* c. 50％\n",
        "* d. 25％\n",
        "* e. 12.5%\n",
        "* f. 0％\n",
        "\n",
        "<span id=\"discussion-questions\" />\n",
        "\n",
        "### 議論における疑問点:\n",
        "\n",
        "1. すべての参加者（アリス、ボブ、イヴ）にとって、すべての基礎選択はランダムであると仮定する。 イヴが盗聴した後、自分が測定したのと同じベースで準備され、その測定と一致する状態をボブに送ると仮定する。 アリスによって初期化された全ての量子ビットのうち、 12.5 %がアリスとボブの間で測定の不一致を引き起こし、盗聴を示すことをパートナーに納得させる(量子エラーやノイズは無視する)。\n",
        "   ヒント1：優先順位がないので、アリスの最初の選択肢を1つだけ考えれば、その1つの選択肢の比率は、すべての選択肢の合計の比率と同じになるはずである。\n",
        "   ヒント2：何かが起こる可能性の数を数えるだけでは十分ではないかもしれない。\n",
        "\n",
        "2. アリス、ボブ、イヴのすべての参加者について、すべての基礎の選択がランダムであると再び仮定する。 しかし今、イブは測定後に好きな状態を自由に送ることができると考えてみよう。 彼女自身の測定値と矛盾する状態を送ってみることだってできる。 アリスとボブが盗聴していることを示す量子ビットの平均的なパーセンテージを下げるような基底の選択があると思うかどうか、パートナーや隣人と議論しなさい。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "in_page_toc_max_heading_level": 2,
    "in_page_toc_min_heading_level": 2,
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}