diff --git a/KeyDistribution_E91/KeyDistribution_E91.csproj b/KeyDistribution_E91/KeyDistribution_E91.csproj
new file mode 100644
index 00000000000..d249c13f433
--- /dev/null
+++ b/KeyDistribution_E91/KeyDistribution_E91.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net6.0
+ false
+ Quantum.Kata.KeyDistributionE91
+ true
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/KeyDistribution_E91/KeyDistribution_E91.ipynb b/KeyDistribution_E91/KeyDistribution_E91.ipynb
new file mode 100644
index 00000000000..d3370381447
--- /dev/null
+++ b/KeyDistribution_E91/KeyDistribution_E91.ipynb
@@ -0,0 +1,407 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# E91 Key Distribution Protocol\n",
+ "\n",
+ "**E91 protocol** is a quantum key distribution protocol proposed by Artur Ekert in 1991. It uses entenglement and projective measurements to improve BB84 on a major aspect, the qubits used can now be distrubted from a central source. \n",
+ "\n",
+ "> _TODO:_ Add more exposition, refer to BB84 and Measurement katas. Add sources for further reading. Polish"
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Part I. Distributing Qubits\n",
+ "\n",
+ "E91 uses a central source to dispatch qubits to both Alice and Bob. The source will entange qubits in such a way that $i$th qubits of Alice and Bob will be in the first Bell state $$\\left\\lvert\\Phi^+\\right\\rangle = \\frac{1}{\\sqrt{2}}(\\lvert0_\\text{Alice}\\rangle \\otimes \\lvert0_\\text{Bob}\\rangle + \\lvert1_\\text{Alice}\\rangle \\otimes \\lvert1_\\text{Bob}\\rangle)$$\n",
+ "\n",
+ "#### Task 1.1. Entangles Pairs\n",
+ "Create entangled pairs $\\frac{1}{√2} (|00⟩ + |11⟩)$ out of corresponding qubits of Alice's and Bob's qubits.\n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `qsAlice`: an array of $n$ qubits in the $|0⟩$ state\n",
+ "2) `qsBob`: an array of $n$ qubits in the $|0⟩$ state\n"
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T11_EntangledPairst\n",
+ "\n",
+ "operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit is Adj{\n",
+ " Fact(Length(qsAlice) == Length(qsBob), \"Alice and Bob should have the same number of qubits\");\n",
+ " // ...\n",
+ "\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Part II. Measurement\n",
+ "\n",
+ "### Choice of Measurement Bases\n",
+ "\n",
+ "Alice and Bob agree on 4 incompatible bases $P_1$, $P_2$, $P_3$ and $P_4$ for their measurements . Alice will use either one of $P_1$, $P_2$ and $P_3$, while Bob will use one of $P_2$, $P_3$ and $P_4$ for their measurements. \n",
+ "\n",
+ "> **Example**:\n",
+ ">\n",
+ "> $Z$ and $X$ are an example of incompatible bases. If some information is encoded into a qubit in $X$ basis, making a measurement on $Z$ basis will destroy that information. \n",
+ "> Furthermore, the information encoded will not be distingued reliably by such a measurement.\n",
+ ">\n",
+ "> If a qubit $q$ is encoded $0$ in $X$ basis, it will have the following quantum state. $$\\lvert q\\rangle = \\lvert+\\rangle =\\frac{1}{\\sqrt2}(\\lvert0\\rangle + \\lvert1\\rangle).$$ Measuring $q$ in $Z$ basis will yield either $0$ or $1$ with equal probabilities and the state function of $q$ will collapse to the respective eigenvector. So the information will also be lost.\n",
+ "\n",
+ "To have such 4 bases, E91 protocol uses Pauli measurements in different directions. The Pauli vector is defined as $$\\vec{\\sigma} = X \\hat{e}_x + Y \\hat{e}_y + Z \\hat{e}_z,$$ where $\\hat{e}_i$ is the unit vector along the direction $i$. A Pauli measurement operator along the unit vector $\\hat{n}$ can be found by its dot product with $\\vec{\\sigma}$. \n",
+ "\n",
+ "> **Example**\n",
+ "> \n",
+ "> _TODO_: Add a plot \n",
+ "> To find the Pauli measurement operator on the $X$-$Y$ plane with a $45^\\circ$ angle, choose $$\\hat{n} = \\cos{\\frac{\\pi}{4}}\\hat{e}_x+ \\sin{\\frac{\\pi}{4}}\\hat{e}_y = \\frac{1}{\\sqrt{2}}\\hat{e}_x + \\frac{1}{\\sqrt2}\\hat{e}_y.$$\n",
+ "> Pauli operator along this direction is $$\n",
+ "> \\vec\\sigma\\cdot\\hat{n} \n",
+ "> = \\frac{1}{\\sqrt2}X + \\frac{1}{\\sqrt2}Y \n",
+ "> = \\frac{1}{\\sqrt2} \\begin{bmatrix}\n",
+ "> 0 & 1-i \\\\\n",
+ "> 1+i & 0 \\\\\n",
+ "> \\end{bmatrix}.$$\n",
+ "> The operator has two normalized eigenvectors:\n",
+ "> - $\\dfrac{1}{2}\\begin{bmatrix} 1-i \\\\ \\sqrt2\\end{bmatrix}$ with eigenvalue $1$\n",
+ "> - $\\dfrac{1}{2}\\begin{bmatrix} -1+i \\\\ \\sqrt2\\end{bmatrix}$ with eigenvalue $-1$\n",
+ ">\n",
+ "> The new operator is incompatible with both $X$ and $Y$.\n",
+ "\n",
+ "For simplicirty, E91 chooses $\\hat{n}$ to be along the $Z-X$ plane with an angle $\\theta$, and defines it as $\\hat{n}(\\theta)=\\cos{\\theta}\\hat{e}_z + \\sin{\\theta} \\hat{e}_x$. A Pauli operator with the same parameter can be written as $$\n",
+ " P(\\theta) \n",
+ " = \\vec\\sigma\\cdot\\hat{n}(\\theta) \n",
+ " = \\cos(\\theta) Z + \\sin(\\theta) X.$$\n",
+ "\n",
+ "Since the protocol requires 4 measurement operators, choose\n",
+ " - $P_1 = P(0 \\cdot \\pi/4) = Z$\n",
+ " - $P_2 = P(1 \\cdot \\pi/4) = \\dfrac{Z+X}{\\sqrt2}$\n",
+ " - $P_3 = P(2 \\cdot \\pi/4) = X$\n",
+ " - $P_4 = P(3 \\cdot \\pi/4) = \\dfrac{X-Z}{\\sqrt2}$"
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 2.1. Rotate and Measure\n",
+ "\n",
+ "Given a basis index $i$, make a measurement in the basis $P_i$. \n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `q`: the qubit to be measured\n",
+ "2) `basisIndex`: The index of measurement operator to be used\n",
+ "\n",
+ "**Output:** The result of the measurement."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T21_RotateAndMeasure\n",
+ "\n",
+ "operation RotateAndMeasure(q : Qubit, basisIndex: Int) : Result {\n",
+ " // ...\n",
+ "\n",
+ " return Zero;\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### The Protocol\n",
+ "\n",
+ "After they recieve their qubits, Alice and Bob will maasure all of their qubits. The protocol follows thee following steps.\n",
+ "- Alice will randomly choose one of $P_1$, $P_2$ or $P_3$ for each of her qubits. Similarly, Bob will randomly choose one of $P_2$, $P_3$ or $P_4$ for each of his qubits.\n",
+ "- Both Alice and Bob will announce their bases. \n",
+ "- Due to entanglemenet, only the qubits they measured on the same basis will be guaranteed to yield the same information. So they will use those to generate a shared key."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 2.2. Random Bases Array\n",
+ "\n",
+ "Using a list of possible measurement basis indices, create a random array of $N$ measurement bases.\n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `basesIndices`: An array of possible bases indices,\n",
+ "2) `N`: The length of the output aray.\n",
+ "\n",
+ "**Outputs:** An array of random bases indices."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T22_RandomBasesArray\n",
+ "\n",
+ "operation RandomBasesArray (basesIndices: Int[], N: Int) : Int[] {\n",
+ " // ...\n",
+ "\n",
+ " return new Int[N];\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 2.3 Measure Qubit Arrays\n",
+ "Measure either Alice's or Bob's qubits in bases constructed using randomly selected bases.\n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `qs`: An array of qubits to be measured,\n",
+ "2) `basesIndices`: An array of random bases indices.\n",
+ "\n",
+ "**Outputs:** The list of measurement results."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T23_MeasureQubitArray\n",
+ "\n",
+ "operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] {\n",
+ " // ...\n",
+ "\n",
+ " return new Result[0];\n",
+ "\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 2.3 Generate the shared key\n",
+ "After both Alice and Bob make their measurements and share their choices of bases, it is possible to select compatible measurements and create a key out of these. You should compute that key for either Alice or Bob.\n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `basesAlice`: Alice's measurement bases indices, \n",
+ "2) `basesBob`: Bob's measurement bases indices, \n",
+ "3) `results`: Either Alice's or Bob's measurement outcomes. Since key generation procedure is the same for both Alice and Bob, this function can be used by both of them with their respective results.\n",
+ " \n",
+ "**Output:** A `Bool` array whose elements are the bits of shared key. \n"
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T24_GenerateSharedKey\n",
+ "\n",
+ "function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] {\n",
+ " let key = new Bool[0];\n",
+ " // ...\n",
+ "\n",
+ " return key;\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 2.5 Putting it all together \n",
+ "\n",
+ "Implement the entire E91 protocol using tasks 1.1 - 2.4 and following the comments in the operation template. This is an open ended task."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "operation T25_E91Protocol () : Unit {\n",
+ " // 1. Alice and Bob are distributed arrays of entangled pairs\n",
+ "\n",
+ " // 2. Alice and Bob choose random measurement bases\n",
+ "\n",
+ " // 3. Measurements by Alice and Bob\n",
+ "\n",
+ " // 4. Keys generated by Alice and Bob\n",
+ "\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%simulate T25_E91Protocol"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "## Part III. Eavesdropper\n",
+ "\n",
+ "An important feature of E91 protocol is how it allows checking for an eavesdropper. In BB84, Alice or Bob release a part of their generated keys to compair against each others. With E91, Bell's Theorem can be used for this purpose as Alice's and Bob's qubits are correlated.\n",
+ "\n",
+ "### CHSH Inequality\n",
+ "\n",
+ "There are 9 possible bases choices that Alice and Bob can make. Among these, only the choices where both Alice and Bob choses either one of $P_2$ or $P_3$ can be used to construct a key. This doesn't mean that all other outcomes are useless though. They can be used to measure the correlation between Alice and Bob's qubits. The famous CHSH inequality provides an easy way to compute this correlation. The CHSH coefficient $S$ is given by $$S = E(P_1, P_2) - E(P_1, P_4) + E(P_3, P_2) + E(P_3, P_4),$$ where $E(P_i, P_j)$ is the expectation value of the ocurrences when Alice measures in $P_i$ and Bob measures in $P_j$. These expectation values can be computed using the realtion $$E(P_i, P_j) = \\frac{N_{00}(P_i, P_j) - N_{01}(P_i, P_j) - N_{10}(P_i, P_j) + N_{11}(P_i, P_j)}{N_{00}(P_i, P_j) + N_{01}(P_i, P_j) + N_{10}(P_i, P_j) + N_{11}(P_i, P_j)},$$ where $N_{m n}(P_i, P_j)$ is the number of observaitions where Alice observes $m$ using $P_i$ and Bob observes $n$ using $P_j$.\n",
+ "\n",
+ "The rules of quantum mechanics tells us that if Alice and Bob's qubit are correlated, $S$ should be equal to $2\\sqrt2$. However if there is no entenglement, $S$ should be no larger than $2$. "
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 3.1 CHSH Correlation Value\n",
+ "\n",
+ "**Inputs:**\n",
+ "1) `basesAlice`: Alice's measurement bases indices,\n",
+ "2) `basesBob`: Bob's measurement bases indices,\n",
+ "3) `resAlice`: Alice's measurement results,\n",
+ "4) `resBob`: Bob's measurement results.\n",
+ "\n",
+ "**Output:** CHSH correlation value $S$."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T31_CorrelationValue\n",
+ "\n",
+ "function CorrelationValue(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {\n",
+ " // ...\n",
+ "\n",
+ " return 0.0;\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "### Eavesdropper\n",
+ "\n",
+ "Since the only point in this protocol where qubits or generated keys travel through a classical channel is when enatangled qubits are being sent to Alice and Bob, an eavesdropper would attack during that phase. It is also possible for the source to be compromised but a manipulation by the source still occurs during the same phase. Since Alice and Bob share $P_2$ and $P_3$, the eavesdropper will also use these bases and measure each qubit in one of these. If the eavesdropper is lucky, they along with Alice and Bob will choose the same basis and that digit will be compromised. If not however, the measurement done by them will destroy the correlation. Due to this destruction of quantum state we expect $S$ to be smaller than $2\\sqrt2$ in case of an eavesdropper.\n",
+ "\n",
+ "After publicly announcing their measurement bases, Alice and Bob can also publicly announce the outcomes of their measurements in incompatible basis. This way, both of them can calculate the CHSH inequality and find out if there is any interception to their communication."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "\n",
+ "#### Task 3.2. Eavesdrop!\n",
+ "In this task you will try to implement an eavesdropper, Eve. Eave will intercept the qubits before they are measured by Alice or Bob.\n",
+ "\n",
+ "**Inputs:** \n",
+ "1) `qAlice`: a qubit that Alice will use,\n",
+ "2) `qBob`: Bob's corresponding qubit,\n",
+ "3) `basisIndex`: Eve's guess of the basis she should use for measuring.\n",
+ "\n",
+ "**Output:** the bits encoded in given qubits."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%kata T32_Eavesdrop\n",
+ "\n",
+ "operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basisIndex : Int) : (Result, Result) {\n",
+ " Fact(basisIndex == 2 or basisIndex == 3, \"Eve should measure in one of Alice's and Bob's compatible basis\");\n",
+ " // ...\n",
+ "\n",
+ " return (Zero, Zero);\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#### Task 3.3. Catch the Eavesdropper\n",
+ "\n",
+ "Add an eavesdropper into Task 2.5, then try to detect them using a CHSH correlation check. This is an open-ended task and is not covered by a test."
+ ],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "operation T33_E91ProtocolWithEavesdropper() : Unit {\n",
+ " // 1. Alice and Bob are distributed arrays of entangled pairs\n",
+ " \n",
+ " // Eve eavesdrops on all qubits, guessing the basis at random\n",
+ "\n",
+ " // 2. Alice and Bob choose random measurement bases\n",
+ "\n",
+ " // 3. Measurements by Alice and Bob\n",
+ "\n",
+ " // 4. Keys generated by Alice and Bob\n",
+ "\n",
+ " // 5. Compute the CHSH correlation value\n",
+ "\n",
+ "}"
+ ],
+ "outputs": [],
+ "metadata": {}
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "source": [
+ "%simulate T33_E91ProtocolWithEavesdropper"
+ ],
+ "outputs": [],
+ "metadata": {}
+ }
+ ],
+ "metadata": {
+ "orig_nbformat": 4,
+ "language_info": {
+ "name": "qsharp",
+ "version": "0.14",
+ "mimetype": "text/x-qsharp",
+ "file_extension": ".qs"
+ },
+ "kernelspec": {
+ "name": "iqsharp",
+ "display_name": "Q#",
+ "language": "qsharp"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
\ No newline at end of file
diff --git a/KeyDistribution_E91/KeyDistribution_E91.sln b/KeyDistribution_E91/KeyDistribution_E91.sln
new file mode 100644
index 00000000000..71b0929790f
--- /dev/null
+++ b/KeyDistribution_E91/KeyDistribution_E91.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31613.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeyDistribution_E91", "KeyDistribution_E91.csproj", "{0FCA178A-40E8-47AB-AC4F-A5273C6BE40F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0FCA178A-40E8-47AB-AC4F-A5273C6BE40F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0FCA178A-40E8-47AB-AC4F-A5273C6BE40F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FCA178A-40E8-47AB-AC4F-A5273C6BE40F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0FCA178A-40E8-47AB-AC4F-A5273C6BE40F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {77C65F6D-0508-410A-94B3-853148BF52E1}
+ EndGlobalSection
+EndGlobal
diff --git a/KeyDistribution_E91/README.md b/KeyDistribution_E91/README.md
new file mode 100644
index 00000000000..f17bec73ade
--- /dev/null
+++ b/KeyDistribution_E91/README.md
@@ -0,0 +1,11 @@
+# Welcome!
+
+The **E91 Quantum Key Distribution** kata is a series of exercises designed to teach you about a quantum key distribution protocol called [E91](https://en.wikipedia.org/wiki/Quantum_key_distribution#E91_protocol:_Artur_Ekert_.281991.29).
+
+You can [run the KeyDistribution_E91 kata as a Jupyter Notebook](https://mybinder.org/v2/gh/Microsoft/QuantumKatas/main?urlpath=/notebooks/KeyDistribution_E91%2FKeyDistribution_E91.ipynb)!
+
+#### For more information:
+
+* [Quantum cryptography based on Bell's theorem](http://www.physics.drexel.edu/~bob/Entanglement/Ekert_keydistribution.pdf) by Arthur K. Ekert.
+* [The Ekert Protocol](https://ux1.eiu.edu/~nilic/Nina's-article.pdf) by Nikolina Ilic.
+* [Lecture 12: Quantum key distribution.](https://www.mpl.mpg.de/fileadmin/user_upload/Chekhova_Research_Group/Lecture_4_12.pdf) by Chekhova Research Group.
diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs
new file mode 100644
index 00000000000..ed6a274af9b
--- /dev/null
+++ b/KeyDistribution_E91/ReferenceImplementation.qs
@@ -0,0 +1,200 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+//////////////////////////////////////////////////////////////////////
+// This file contains reference solutions to all tasks.
+// The tasks themselves can be found in Tasks.qs file.
+// but feel free to look up the solution if you get stuck.
+//////////////////////////////////////////////////////////////////////
+
+namespace Quantum.Kata.KeyDistributionE91 {
+
+ open Microsoft.Quantum.Arrays;
+ open Microsoft.Quantum.Measurement;
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Intrinsic;
+ open Microsoft.Quantum.Diagnostics;
+ open Microsoft.Quantum.Convert;
+ open Microsoft.Quantum.Math;
+ open Microsoft.Quantum.Random;
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part I. Preparation
+ //////////////////////////////////////////////////////////////////
+
+ // Task 1.1. Entangled Pairs
+ operation EntangledPairs_Reference (qsAlice : Qubit[], qsBob : Qubit[]) : Unit is Adj{
+ Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits");
+
+ for (i, j) in Zipped(qsAlice, qsBob) {
+ H(i);
+ CNOT(i, j);
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part II. E91 Protocol
+ //////////////////////////////////////////////////////////////////
+
+ // Task 2.1 Rotate and Measure
+ operation RotateAndMeasure_Reference (q : Qubit, basisIndex: Int) : Result {
+ mutable result = Zero;
+ let rotationAngle = PI() * IntAsDouble(basisIndex - 1) / 4.0;
+
+ within {
+ Ry(rotationAngle, q);
+ } apply {
+ set result = M(q);
+ }
+
+ return result;
+ }
+
+ // Task 2.2. Random Bases Array
+ operation RandomBasesArray_Reference (basesIndices: Int[], N: Int) : Int[] {
+ // ...
+ mutable bases = [];
+
+ for _ in 1..N {
+ let randomIndex = DrawRandomInt(0, Length(basesIndices) - 1);
+ set bases += [basesIndices[randomIndex]];
+ }
+
+ return bases;
+ }
+
+ // Task 2.3 Measure Qubit Arrays
+ operation MeasureQubitArray_Reference (qs: Qubit[], basesIndices: Int[]) : Result[] {
+ mutable results = [];
+
+ for (q, b) in Zipped(qs, basesIndices) {
+ let outcome = RotateAndMeasure_Reference(q,b);
+ set results += [outcome];
+ }
+
+ return results;
+ }
+
+ // Task 2.4 Generate the shared key
+ function GenerateSharedKey_Reference (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] {
+ mutable key = [];
+
+ for (a, b, r) in Zipped3(basesAlice, basesBob, results) {
+ if a == b {
+ set key += [ResultAsBool(r)];
+ }
+ }
+
+ return key;
+ }
+
+ // Task 2.5 Putting it all together
+ operation T25_E91Protocol_Reference () : Unit {
+ // 1. Alice and Bob are distributed arrays of entangled pairs
+ let N = 10;
+ use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]);
+ EntangledPairs_Reference(qsAlice, qsBob);
+
+ // 2. Alice and Bob choose random measurement bases
+ let basesAlice = RandomBasesArray_Reference([1,2,3], N);
+ let basesBob = RandomBasesArray_Reference([2,3,4], N);
+
+ // 3. Measurements by Alice and Bob
+ let resultsAlice = MeasureQubitArray_Reference(qsAlice, basesAlice);
+ let resultsBob = MeasureQubitArray_Reference(qsBob, basesBob);
+
+ // 4. Keys generated by Alice and Bob
+ let keyAlice = GenerateSharedKey_Reference(basesAlice, basesBob, resultsAlice);
+ let keyBob = GenerateSharedKey_Reference(basesAlice, basesBob, resultsBob);
+ Message($"Alice's Key: {keyAlice}");
+ Message($"Bob's Key: {keyBob}\n");
+
+ // Reset all qubits to |0⟩
+ ResetAll(qsAlice + qsBob);
+
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // Part III. Eavesdropping
+ //////////////////////////////////////////////////////////////////
+
+ // Task 3.1 CHSH Correlation Value
+ function CorrelationValue_Reference (basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {
+ mutable expectationValues = [];
+
+ for (i, j) in [(1,2), (1, 4), (3, 2), (3, 4)] {
+ mutable sum = 0;
+ mutable counter = 0;
+
+ for idx in IndexRange(basesAlice) {
+ if basesAlice[idx] == i and basesBob[idx] == j {
+ if resultsAlice[idx] == resultsBob[idx] {
+ set sum += 1;
+ } else {
+ set sum -= 1;
+ }
+ set counter += 1;
+ }
+ }
+ if counter == 0 {
+ set expectationValues += [0.0];
+ } else {
+ set expectationValues += [IntAsDouble(sum)/IntAsDouble(counter)];
+ }
+ }
+
+ let s = expectationValues[0]
+ - expectationValues[1]
+ + expectationValues[2]
+ + expectationValues[3];
+
+ return s;
+ }
+
+ // Task 3.2. Eavesdrop!
+ operation Eavesdrop_Reference (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) {
+ Fact(basis == 2 or basis == 3, "Eve should measure in one of Alice's and Bob's compatible basis");
+
+ let resultsAlice = RotateAndMeasure_Reference(qAlice, basis);
+ let resultsBob = RotateAndMeasure_Reference(qBob, basis);
+
+ return (resultsAlice, resultsBob);
+ }
+
+ // Task 3.3. Catch the eavesdropper
+ operation T33_E91ProtocolWithEavesdropper_Reference () : Unit {
+ // 1. Alice and Bob are distributed arrays of entangled pairs
+ let N = 10;
+ use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]);
+ EntangledPairs_Reference(qsAlice, qsBob);
+
+ // Eve eavesdrops on all qubits, guessing the basis at random
+ for (qAlice, qBob) in Zipped(qsAlice, qsBob) {
+ let _ = Eavesdrop_Reference(qAlice, qBob, DrawRandomInt(2,3));
+ }
+
+ // 2. Alice and Bob choose random measurement bases
+ let basesAlice = RandomBasesArray_Reference([1,2,3], N);
+ let basesBob = RandomBasesArray_Reference([2,3,4], N);
+
+ // 3. Measurements by Alice and Bob
+ let resultsAlice = MeasureQubitArray_Reference(qsAlice, basesAlice);
+ let resultsBob = MeasureQubitArray_Reference(qsBob, basesBob);
+
+ // 4. Keys generated by Alice and Bob
+ let keyAlice = GenerateSharedKey_Reference(basesAlice, basesBob, resultsAlice);
+ let keyBob = GenerateSharedKey_Reference(basesAlice, basesBob, resultsBob);
+ Message($"Alice's Key: {keyAlice}");
+ Message($"Bob's Key: {keyBob}\n");
+
+ // 5. Compute the CHSH correlation value
+ let s = CorrelationValue_Reference(basesAlice, basesBob, resultsAlice, resultsBob);
+ Message($"S = {s}");
+
+ // Reset all qubits to |0⟩
+ ResetAll(qsAlice + qsBob);
+
+ }
+}
\ No newline at end of file
diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs
new file mode 100644
index 00000000000..a204cf3d303
--- /dev/null
+++ b/KeyDistribution_E91/Tasks.qs
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace Quantum.Kata.KeyDistributionE91 {
+
+ open Microsoft.Quantum.Arrays;
+ open Microsoft.Quantum.Measurement;
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Intrinsic;
+ open Microsoft.Quantum.Diagnostics;
+ open Microsoft.Quantum.Convert;
+ open Microsoft.Quantum.Math;
+ open Microsoft.Quantum.Random;
+
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part I. Preparation
+ //////////////////////////////////////////////////////////////////
+
+ // Task 1.1. Entangled Pairs
+
+ operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit is Adj{
+ Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits");
+ // ...
+
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part II. E91 Protocol
+ //////////////////////////////////////////////////////////////////
+
+ // Task 2.1. Rotate and Measure
+ operation RotateAndMeasure (q : Qubit, basisIndex: Int) : Result {
+ // ...
+
+ return Zero;
+ }
+
+ // Task 2.2. Random Bases Array
+ operation RandomBasesArray (basesIndices: Int[], N: Int) : Int[] {
+ // ...
+
+ return [];
+ }
+
+ // Task 2.3 Measure Qubit Arrays
+ operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] {
+ // ...
+
+ return [];
+
+ }
+
+ // Task 2.4 Generate the shared key
+ function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] {
+ let key = [];
+ // ...
+
+ return key;
+ }
+
+ // Task 2.5 Putting it all together
+ // Goal: Implement the entire BB84 protocol using tasks 1.1 - 2.3
+ // and following the comments in the operation template.
+ //
+ // This is an open-ended task and is not covered by a test;
+ // you can run T26_BB84Protocol to run your code.
+ @Test("QuantumSimulator")
+ operation T25_E91Protocol () : Unit {
+
+ // 1. Alice and Bob are distributed arrays of entangled pairs
+
+ // 2. Alice and Bob choose random measurement bases
+
+ // 3. Measurements by Alice and Bob
+
+ // 4. Keys generated by Alice and Bob
+
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part III. Eavesdropping
+ //////////////////////////////////////////////////////////////////
+
+ // Task 3.1. CHSH Correlation Value
+ function CorrelationValue(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {
+ // ...
+
+ return 0.0;
+ }
+
+ // Task 3.2. Eavesdrop!
+ operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basisIndex : Int) : (Result, Result) {
+ Fact(basisIndex == 2 or basisIndex == 3, "Eve should measure in one of Alice's and Bob's compatible basis");
+ // ...
+
+ return (Zero, Zero);
+ }
+
+ // Task 3.3. Catch the eavesdropper
+ operation T33_E91ProtocolWithEavesdropper() : Unit {
+ // 1. Alice and Bob are distributed arrays of entangled pairs
+
+ // Eve eavesdrops on all qubits, guessing the basis at random
+
+ // 2. Alice and Bob choose random measurement bases
+
+ // 3. Measurements by Alice and Bob
+
+ // 4. Keys generated by Alice and Bob
+
+ // 5. Compute the CHSH correlation value
+
+}
+}
\ No newline at end of file
diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs
new file mode 100644
index 00000000000..c75f7045d6c
--- /dev/null
+++ b/KeyDistribution_E91/Tests.qs
@@ -0,0 +1,183 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+//////////////////////////////////////////////////////////////////////
+// This file contains testing harness for all tasks.
+// You should not modify anything in this file.
+// The tasks themselves can be found in Tasks.qs file.
+//////////////////////////////////////////////////////////////////////
+
+namespace Quantum.Kata.KeyDistributionE91 {
+
+ open Microsoft.Quantum.Arrays;
+ open Microsoft.Quantum.Intrinsic;
+ open Microsoft.Quantum.Diagnostics;
+ open Microsoft.Quantum.Math;
+ open Microsoft.Quantum.Convert;
+ open Microsoft.Quantum.Random;
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part I. Preparation
+ //////////////////////////////////////////////////////////////////
+
+ @Test("QuantumSimulator")
+ operation T11_EntangledPairst() : Unit {
+ use qsAlice = Qubit[2];
+ use qsBob = Qubit[2];
+
+ EntangledPairs(qsAlice, qsBob);
+ Adjoint EntangledPairs_Reference(qsAlice, qsBob);
+
+ AssertAllZero(qsAlice + qsBob);
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part II. E91 Protocol
+ //////////////////////////////////////////////////////////////////
+
+ @Test("QuantumSimulator")
+ operation T21_RotateAndMeasure() : Unit {
+ use q = Qubit();
+
+ for basisIndex in 1..4 {
+ let res = RotateAndMeasure(q, basisIndex);
+ let rotationAngle = PI() * IntAsDouble(basisIndex - 1) / 4.0;
+ within {
+ Ry(rotationAngle, q);
+ } apply {
+ AssertQubitWithinTolerance(res, q, 1e-5);
+ }
+ Reset(q);
+ }
+ }
+
+ @Test("QuantumSimulator")
+ operation T22_RandomBasesArray() : Unit {
+ let N = 5;
+ let basesIndices = [1,2,3];
+
+ let basesArray = RandomBasesArray(basesIndices, N);
+ EqualityFactI(
+ Length(basesArray), N,
+ $"Generated array should be of length {N}"
+ );
+
+ for i in basesArray {
+ mutable indexInRange = false;
+ for j in basesIndices {
+ if i == j {
+ set indexInRange = true;
+ }
+ }
+ Fact(
+ indexInRange,
+ $"element {i} is not a member of bases array {basesIndices}"
+ );
+ }
+ }
+
+ @Test("QuantumSimulator")
+ operation T23_MeasureQubitArray() : Unit {
+ let N = 10;
+
+ let basesArray = RandomBasesArray_Reference([1, 2, 3, 4], N);
+ use qs = Qubit[N];
+
+ let results = MeasureQubitArray(qs, basesArray);
+
+ for (q, b, r) in Zipped3(qs, basesArray, results) {
+ // At this point, qubit should be projected onto an
+ // eigenstate of b.
+ let rotationAngle = PI() * IntAsDouble(b - 1) / 4.0;
+
+ within {
+ Ry(rotationAngle, q);
+ } apply {
+ AssertQubitWithinTolerance(r, q, 1e-4);
+ }
+ }
+ ResetAll(qs);
+ }
+
+ @Test("QuantumSimulator")
+ operation T24_GenerateSharedKey() : Unit {
+ let N = 10;
+
+ mutable basesAlice = [];
+ mutable basesBob = [];
+ mutable results = [];
+
+ for _ in 1..N {
+ set basesAlice += [DrawRandomInt(1,3)];
+ set basesBob += [DrawRandomInt(2,4)];
+ set results += [BoolAsResult(DrawRandomBool(0.5))];
+ }
+
+ let actual = GenerateSharedKey(basesAlice, basesBob, results);
+ let expected = GenerateSharedKey_Reference(basesAlice, basesBob, results);
+
+
+ AllEqualityFactB(
+ actual, expected,
+ $"Generated key {actual} does not match the expected value {expected}."
+ );
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // Part III. Eavesdropping
+ //////////////////////////////////////////////////////////////////
+
+ @Test("QuantumSimulator")
+ operation T31_CorrelationValue() : Unit {
+ let N = 10;
+ use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]);
+ EntangledPairs_Reference(qsAlice, qsBob);
+
+ for (qAlice, qBob) in Zipped(qsAlice, qsBob) {
+ let _ = Eavesdrop_Reference(qAlice, qBob, DrawRandomInt(2,3));
+ }
+
+ let basesAlice = RandomBasesArray_Reference([1,2,3], N);
+ let basesBob = RandomBasesArray_Reference([2,3,4], N);
+
+ let resultsAlice = MeasureQubitArray_Reference(qsAlice, basesAlice);
+ let resultsBob = MeasureQubitArray_Reference(qsBob, basesBob);
+
+ let actual = CorrelationValue(basesAlice, basesBob, resultsAlice, resultsBob);
+ let expected = CorrelationValue_Reference(basesAlice, basesBob, resultsAlice, resultsBob);
+
+ Fact(actual == expected, $"Correlation value {actual} does not match the expected value {expected}.");
+
+ ResetAll(qsAlice + qsBob);
+ }
+
+ @Test("QuantumSimulator")
+ operation T32_Eavesdrop() : Unit {
+ for basisIndex in 2..3 {
+ use (qAlice, qBob) = (Qubit(), Qubit());
+ EntangledPairs_Reference([qAlice], [qBob]);
+
+ let (r1, r2) = Eavesdrop(qAlice, qBob, basisIndex);
+
+ // Make sure entanglement was not disturbed until measurement
+ Fact(r1 == r2, "Measurement outcomes do not match for given qubits.");
+
+ for q in [qAlice, qBob] {
+ let rotationAngle = PI() * IntAsDouble(basisIndex - 1) / 4.0;
+
+ // Make sure of the wavefunction collapse
+ within {
+ Ry(rotationAngle, q);
+ } apply {
+ AssertQubitWithinTolerance(r1, q, 1e-5);
+ }
+ }
+
+ ResetAll([qAlice, qBob]);
+ }
+ }
+
+}
diff --git a/index.ipynb b/index.ipynb
index be9450d45d0..13e248abede 100644
--- a/index.ipynb
+++ b/index.ipynb
@@ -116,6 +116,8 @@
"\n",
"* **[BB84 protocol](./KeyDistribution_BB84/KeyDistribution_BB84.ipynb)**.\n",
" Implement the BB84 key distribution algorithm.\n",
+ "* **[E91 protocol](./KeyDistribution_E91/KeyDistribution_E91.ipynb)**.\n",
+ " Implement the E91 key distribution algorithm.\n",
"* **[Bit-flip error correcting code](./QEC_BitFlipCode/QEC_BitFlipCode.ipynb)**.\n",
" Learn about a 3-qubit error correcting code for protecting against bit-flip errors.\n",
"* **[Unitary patterns](./UnitaryPatterns/UnitaryPatterns.ipynb)**.\n",