From 1a6ff3fb660a13a84c2eb174c110c64ee225ee49 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 26 Aug 2021 14:16:55 +0300 Subject: [PATCH 01/11] Setup project structure and add the initial tasks for E91 protocol --- .../KeyDistribution_E91.csproj | 24 +++ KeyDistribution_E91/README.md | 0 KeyDistribution_E91/Tasks.qs | 155 ++++++++++++++++++ KeyDistribution_E91/Tests.qs | 46 ++++++ 4 files changed, 225 insertions(+) create mode 100644 KeyDistribution_E91/KeyDistribution_E91.csproj create mode 100644 KeyDistribution_E91/README.md create mode 100644 KeyDistribution_E91/Tasks.qs create mode 100644 KeyDistribution_E91/Tests.qs diff --git a/KeyDistribution_E91/KeyDistribution_E91.csproj b/KeyDistribution_E91/KeyDistribution_E91.csproj new file mode 100644 index 00000000000..d370c66a9eb --- /dev/null +++ b/KeyDistribution_E91/KeyDistribution_E91.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.1 + false + Quantum.Kata.KeyDistributionE91 + true + x64 + + + + + + + + + + + + + + + + diff --git a/KeyDistribution_E91/README.md b/KeyDistribution_E91/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs new file mode 100644 index 00000000000..22b41160ca2 --- /dev/null +++ b/KeyDistribution_E91/Tasks.qs @@ -0,0 +1,155 @@ +// 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 + // Inputs: + // 1) "qsAlice": an array of N qubits in the |0⟩ states, + // 2) "qsBob": an array of N qubits in the |0⟩ states, + // Goal: Create entangled pairs |Ψ⟩ = 1/√2 (|01⟩ + |10⟩) out of corresponding qubits of + // Alice's and Bob's qubits. + operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit { + // ... + Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits"); + + for i in 0 .. Length(qsAlice) - 1 { + H(qsAlice[i]); + CNOT(qsAlice[i], qsBob[i]); + X(qsAlice[i]); + } + } + + + ////////////////////////////////////////////////////////////////// + // Part II. E91 Protocol + ////////////////////////////////////////////////////////////////// + + + // Task 2.1 Rotate and Measure + // Inputs: + // 1) "q": the qubit to be measured, + // 2) "rotationMultiplier": an integer to me multiplied by π/4 to calculate + // the rotation angle, + // Goal: Rotate PauliZ basis and measure q in that new basis. + operation RotateAndMeasure(q : Qubit, rotationMultiplier: Int) : Result { + + // Bases obtained for the different values of rotation multiplier are: + // 0 -> X + // 1 -> X+Z + // 2 -> Z + // 3 -> Z-X + + if rotationMultiplier == 0 { + H(q); + } elif rotationMultiplier == 1 { + within { + H(q); + } apply { + T(q); + } + } elif rotationMultiplier == 2 { + I(q); + } elif rotationMultiplier == 3 { + within { + H(q); + } apply { + Adjoint T(q); + } + } + return M(q); + } + + // Task 2.2 Measure Qubit Arrays + // Inputs: + // 1) "qs": An array of qubits to be measured, + // 2) "basisDist": A DiscreteDistribution of possible rotation mutlipliers. + // Goal: Measure qubits from qs in bases constructed with rotation multipliers that + // are choosen randomly from basisDist. + operation MeasureQubitArray (qs: Qubit[], basisDist: DiscreteDistribution) : (Int[], Result[]) { + mutable results = new Result[0]; + mutable bases = new Int[0]; + + for i in 0 .. Length(qs) - 1 { + let basis = basisDist::Sample(); + + set bases += [basis]; + set results += [RotateAndMeasure(qs[i], basis)]; + } + + return (bases, results); + + } + + // Task 2.3 Generate the shared key + // Inputs: + // 1) "basesAlice": Alice's measurement bases multipliers, + // 2) "basesBob": Bob's measurement bases multipliers, + // 3) "results": Either Alice's or Bob's measurement outcomes + // Goal: Using both Alice's and Bob's bases of measurement, construct the shared key that + // will be used by either one of them. + function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { + mutable key = new Bool[0]; + for (a, b, r) in Zipped3(basesAlice, basesBob, results) { + if a == b { + set key += [ResultAsBool(r)]; + } + } + + return key; + } + + + // Task 2.4 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 E91_Protocol () : Unit { + + // Basis distributions for Alice and Bob + let basisDistAlice = DiscreteUniformDistribution(0, 2); + let basisDistBob = DiscreteUniformDistribution(1, 3); + + use (qsAlice, qsBob) = (Qubit[10] ,Qubit[10]) { + + // Entangled pair preparation + EntangledPairs(qsAlice, qsBob); + + // Measurements by Alice and Bob + let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisDistAlice); + let (basesBob, resBob) = MeasureQubitArray(qsBob, basisDistBob); + + // Keys generated by Alice and Bob + let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); + let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); + + // TODO: Add correlation check + + } + } + + // TODO: Simulate eavesdropper case +} \ No newline at end of file diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs new file mode 100644 index 00000000000..04764e18ccd --- /dev/null +++ b/KeyDistribution_E91/Tests.qs @@ -0,0 +1,46 @@ +// 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 { + // ... + } + + @Test("QuantumSimulator") + operation T21_RotateAndMeasure() : Unit { + // ... + } + + + @Test("QuantumSimulator") + operation T22_MeasureQubitArray() : Unit { + // ... + } + + @Test("QuantumSimulator") + operation T23_GenerateSharedKey() : Unit { + // ... + } + + +} From 73c202d4542737db59ae77e95e0737a5f6451753 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Fri, 10 Sep 2021 11:25:44 +0300 Subject: [PATCH 02/11] Create tasks and their reference implementations --- .../ReferenceImplementation.qs | 199 ++++++++++++++++++ KeyDistribution_E91/Tasks.qs | 189 +++++++++-------- 2 files changed, 305 insertions(+), 83 deletions(-) create mode 100644 KeyDistribution_E91/ReferenceImplementation.qs diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs new file mode 100644 index 00000000000..1783150eb22 --- /dev/null +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -0,0 +1,199 @@ +// 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 { + Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits"); + + for i in IndexRange(qsAlice) { + H(qsAlice[i]); + CNOT(qsAlice[i], qsBob[i]); + } + } + + + ////////////////////////////////////////////////////////////////// + // Part II. E91 Protocol + ////////////////////////////////////////////////////////////////// + + // Task 2.1 Rotate and Measure + operation RotateAndMeasure_Reference (q : Qubit, rotationMultiplier: Int) : Result { + mutable result = Zero; + let rotationAngle = PI() * IntAsDouble(rotationMultiplier) / 4.0; + + within { + Ry(rotationAngle, q); + } apply { + set result = M(q); + } + + return result; + } + + // Task 2.2 Measure Qubit Arrays + operation MeasureQubitArray_Reference (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) { + mutable results = new Result[0]; + mutable bases = new Int[0]; + + for q in qs { + let basis = basisList[DrawRandomInt(0,2)]; + let res = RotateAndMeasure(q, basis); + + set bases += [basis]; + set results += [res]; + } + + return (bases, results); + + } + + // Task 2.3 Generate the shared key + function GenerateSharedKey_Reference (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { + mutable key = new Bool[0]; + + for (a, b, r) in Zipped3(basesAlice, basesBob, results) { + if a == b { + set key += [ResultAsBool(r)]; + } + } + + return key; + } + + // Task 2.4 CHSH Correlation Check + function CorrelationCheck_Reference (basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: Result[]) : Double { + mutable expectationValues = new Double[0]; + + for (i, j) in [(0,1), (0, 3), (2, 1), (2, 3)] { + mutable sum = 0; + mutable counter = 0; + + for idx in IndexRange(basesAlice) { + if basesAlice[idx] == i and basesBob[idx] == j { + if resAlice[idx] == resBob[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 2.5 Putting it all together + @Test("QuantumSimulator") + operation T25_E91Protocol_Reference () : Unit { + // 1. Alice and Bob choose basis multipliers + let basisListAlice = [0, 1, 2]; + let basisListBob = [1, 2, 3]; + + // 2. Alice and Bob are distributed arrays of entangled pairs + let N = 13; + use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); + EntangledPairs(qsAlice, qsBob); + + // 3. Measurements by Alice and Bob + let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisListAlice); + let (basesBob, resBob) = MeasureQubitArray(qsBob, basisListBob); + + // 4. Keys generated by Alice and Bob + let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); + let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); + Message($"Alice's Key: {keyAlice}"); + Message($"Bob's Key: {keyBob}\n"); + + // 5. Compute the CHSH correlation value + let s = CorrelationCheck(basesAlice, basesBob, resAlice, resBob); + Message($"S = {s}"); + + // Reset all qubits to |0⟩ + ResetAll(qsAlice + qsBob); + + } + + ////////////////////////////////////////////////////////////////// + // Part III. Eavesdropping + ////////////////////////////////////////////////////////////////// + + // Task 3.1. Eavesdrop! + operation Eavesdrop_Reference (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) { + Fact(basis == 1 or basis == 2, "Eve should measure in one of Alice's and Bob's compatible basis"); + + let resAlice = RotateAndMeasure(qAlice, basis); + let resBob = RotateAndMeasure(qBob, basis); + + return (resAlice, resBob); + } + + // Task 3.2. Catch the eavesdropper + @Test("QuantumSimulator") + operation T32_E91ProtocolWithEavesdropper_Reference () : Unit { + // 1. Alice and Bob choose basis multipliers + let basisListAlice = [0, 1, 2]; + let basisListBob = [1, 2, 3]; + + // 2. Alice and Bob are distributed arrays of entangled pairs + let N = 13; + use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); + EntangledPairs(qsAlice, qsBob); + + // Eve eavesdrops on all qubits, guessing the basis at random + for (qAlice, qBob) in Zipped(qsAlice, qsBob) { + let n = Eavesdrop(qAlice, qBob, DrawRandomInt(1,2)); + } + + // 3. Measurements by Alice and Bob + let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisListAlice); + let (basesBob, resBob) = MeasureQubitArray(qsBob, basisListBob); + + // 4. Keys generated by Alice and Bob + let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); + let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); + Message($"Alice's Key: {keyAlice}"); + Message($"Bob's Key: {keyBob}\n"); + + // 5. Compute the CHSH correlation value + let s = CorrelationCheck(basesAlice, basesBob, resAlice, resBob); + 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 index 22b41160ca2..d2d838998fb 100644 --- a/KeyDistribution_E91/Tasks.qs +++ b/KeyDistribution_E91/Tasks.qs @@ -1,12 +1,6 @@ // 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; @@ -17,7 +11,9 @@ namespace Quantum.Kata.KeyDistributionE91 { open Microsoft.Quantum.Convert; open Microsoft.Quantum.Math; open Microsoft.Quantum.Random; - + + + ////////////////////////////////////////////////////////////////// // Part I. Preparation ////////////////////////////////////////////////////////////////// @@ -26,17 +22,12 @@ namespace Quantum.Kata.KeyDistributionE91 { // Inputs: // 1) "qsAlice": an array of N qubits in the |0⟩ states, // 2) "qsBob": an array of N qubits in the |0⟩ states, - // Goal: Create entangled pairs |Ψ⟩ = 1/√2 (|01⟩ + |10⟩) out of corresponding qubits of + // Goal: Create entangled pairs |Ψ⟩ = 1/√2 (|00⟩ + |11⟩) out of corresponding qubits of // Alice's and Bob's qubits. operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit { - // ... Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits"); + // ... - for i in 0 .. Length(qsAlice) - 1 { - H(qsAlice[i]); - CNOT(qsAlice[i], qsBob[i]); - X(qsAlice[i]); - } } @@ -44,112 +35,144 @@ namespace Quantum.Kata.KeyDistributionE91 { // Part II. E91 Protocol ////////////////////////////////////////////////////////////////// - // Task 2.1 Rotate and Measure + // One of the essential steps of E91 protocol is conducting measurement operations. + // In Z-X plane, Alice measures her qubit in either one of Z, (Z+X)/√2 or X basis whereas + // Bob measures his qubit in either one of (Z+X)/√2, X or (X-Z)/√2 basis. // Inputs: // 1) "q": the qubit to be measured, - // 2) "rotationMultiplier": an integer to me multiplied by π/4 to calculate - // the rotation angle, + // 2) "rotationMultiplier": an integer to me multiplied by π/4 to + // compute the rotation angle in Z-X plane, + // Output: Result of the measurement // Goal: Rotate PauliZ basis and measure q in that new basis. operation RotateAndMeasure(q : Qubit, rotationMultiplier: Int) : Result { + // ... - // Bases obtained for the different values of rotation multiplier are: - // 0 -> X - // 1 -> X+Z - // 2 -> Z - // 3 -> Z-X - - if rotationMultiplier == 0 { - H(q); - } elif rotationMultiplier == 1 { - within { - H(q); - } apply { - T(q); - } - } elif rotationMultiplier == 2 { - I(q); - } elif rotationMultiplier == 3 { - within { - H(q); - } apply { - Adjoint T(q); - } - } - return M(q); + return Zero; } // Task 2.2 Measure Qubit Arrays + // Now that you have a way of measuring a qubit in a given direction, it's time to + // measure either Alice's or Bob's qubits in random bases selected from their respective + // basis sets. // Inputs: // 1) "qs": An array of qubits to be measured, - // 2) "basisDist": A DiscreteDistribution of possible rotation mutlipliers. - // Goal: Measure qubits from qs in bases constructed with rotation multipliers that - // are choosen randomly from basisDist. - operation MeasureQubitArray (qs: Qubit[], basisDist: DiscreteDistribution) : (Int[], Result[]) { - mutable results = new Result[0]; - mutable bases = new Int[0]; - - for i in 0 .. Length(qs) - 1 { - let basis = basisDist::Sample(); - - set bases += [basis]; - set results += [RotateAndMeasure(qs[i], basis)]; - } + // 2) "basisListt": A list of 3 possible rotation mutlipliers. + // Outputs: + // 1) List of generated basis choices, + // 2) List of measurement results. + // Goal: Measure qubits from qs in bases constructed using rotation multipliers that + // are choosen randomly from basisList. + operation MeasureQubitArray (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) { + let results = new Result[0]; + let bases = new Int[0]; + // ... return (bases, results); } // Task 2.3 Generate the shared key + // 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. // Inputs: // 1) "basesAlice": Alice's measurement bases multipliers, // 2) "basesBob": Bob's measurement bases multipliers, - // 3) "results": Either Alice's or Bob's measurement outcomes - // Goal: Using both Alice's and Bob's bases of measurement, construct the shared key that - // will be used by either one of them. + // 3) "results": Either Alice's or Bob's measurement outcomes. + // Output: A Bool array whose elements are the bits of shared key. function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { - mutable key = new Bool[0]; - for (a, b, r) in Zipped3(basesAlice, basesBob, results) { - if a == b { - set key += [ResultAsBool(r)]; - } - } - + let key = new Bool[0]; + // ... + return key; } + // Task 2.4 CHSH Correlation Check + // Non-compatible measurements were not useful for creating secret keys, but they are very + // for detecting an eavesdropper. Quantum mechanics tells us that the CHSH correlation value + // S = E(0, 1) - E(0, 3) + E(2, 1) + E(2, 3) + // should be 2√2 when there is no eavesdropper and is less than √2 when someone is manipulating + // the communication. The expectation value E(i, j) is the average value of outcomes when Alice + // measures on a basis with rotation multiplier i and Bob measures on a basis with rotation + // multiplier j. You should remember that when computing measurement outcomes, you should + // use actual eigenvalues which are +1 for Zero and -1 for One. + // + // Inputs: + // 1) "basesAlice": Alice's measurement bases multipliers, + // 2) "basesBob": Bob's measurement bases multipliers, + // 3) "resAlice": Alice's measurement outcomes, + // 4) "resBob": Bob's measurement outcomes. + // Output: CHSH correlation value. + function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: Result[]) : Double { + // ... + + return 0.0; + } - // Task 2.4 Putting it all together + // 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 E91_Protocol () : Unit { + operation T25_E91Protocol () : Unit { + + // 1. Alice and Bob choose basis multipliers + + // 2. Alice and Bob are distributed arrays of entangled pairs - // Basis distributions for Alice and Bob - let basisDistAlice = DiscreteUniformDistribution(0, 2); - let basisDistBob = DiscreteUniformDistribution(1, 3); + // 3. Measurements by Alice and Bob - use (qsAlice, qsBob) = (Qubit[10] ,Qubit[10]) { - - // Entangled pair preparation - EntangledPairs(qsAlice, qsBob); + // 4. Keys generated by Alice and Bob + + // 5. Compute the CHSH correlation value + + } - // Measurements by Alice and Bob - let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisDistAlice); - let (basesBob, resBob) = MeasureQubitArray(qsBob, basisDistBob); - // Keys generated by Alice and Bob - let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); - let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); + ////////////////////////////////////////////////////////////////// + // Part III. Eavesdropping + ////////////////////////////////////////////////////////////////// - // TODO: Add correlation check + // Task 3.1. Eavesdrop! + // In this task you will try to implement an eavesdropper, Eve. + // Eave will intercept the qubits before they are measured by Alice or Bob. Eve uses + // one of Alice's and Bob's compatible basis, (Z+X)/√2 and X, for her measurement. This + // way, she might be able to place some known values into Bob's and Alice's keys. + // + // Inputs: + // 1) "qAlice": a qubit that Alice will use, + // 2) "qAlice": Bob's corresponding qubit, + // 3) "basis": Eve's guess of the basis she should use for measuring. + // Output: the bits encoded in given qubits. + operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) { + Fact(basis == 1 or basis == 2, "Eve should measure in one of Alice's and Bob's compatible basis"); + // ... - } + return (Zero, Zero); } - // TODO: Simulate eavesdropper case + // Task 3.2. Catch the eavesdropper + // Add an eavesdropper into the BB84 protocol from task 2.5. + // Note that we should be able to detect Eve with a CHSH correlation check. + // + // This is an open-ended task and is not covered by a test; + // you can run T32_E91ProtocolWithEavesdropper() to run your code. + @Test("QuantumSimulator") + operation T32_E91ProtocolWithEavesdropper() : Unit { + // 1. Alice and Bob choose basis multipliers + + // 2. Alice and Bob are distributed arrays of entangled pairs + + // Eve eavesdrops on all qubits, guessing the basis at random + + // 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 From 881b88b3b8d0051013332257074d00150e069218 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Fri, 10 Sep 2021 11:27:25 +0300 Subject: [PATCH 03/11] Create tests for the first few tasks --- KeyDistribution_E91/Tests.qs | 62 ++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index 04764e18ccd..991efd63890 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -23,18 +23,64 @@ namespace Quantum.Kata.KeyDistributionE91 { @Test("QuantumSimulator") operation T11_EntangledPairst() : Unit { - // ... + use qsAlice = Qubit[2]; + use qsBob = Qubit[2]; + + EntangledPairs(qsAlice, qsBob); + + for (i, j) in Zipped(qsAlice, qsBob) { + CNOT(i, j); + H(i); + } + + AssertAllZero(qsAlice + qsBob); } @Test("QuantumSimulator") operation T21_RotateAndMeasure() : Unit { - // ... + use q = Qubit(); + + for mutliplier in 0 .. 3 { + let res = RotateAndMeasure_Reference(q, mutliplier); + within { + Ry(IntAsDouble(mutliplier) * PI() / 4.0, q); + } apply { + AssertQubitWithinTolerance(res, q, 1e-5); + } + Reset(q); + } + } + operation randomList<'T>(values: 'T[], count : Int) : 'T[] { + let dist = DiscreteUniformDistribution(0,Length(values)-1); + mutable outList = new 'T[0]; + + for _ in 1 .. count { + set outList += [values[dist::Sample()]]; + } + return outList; + } + @Test("QuantumSimulator") operation T22_MeasureQubitArray() : Unit { - // ... + let basisList = [0, 1, 2, 3]; + use qs = Qubit[5]; + + let (bs, rs) = MeasureQubitArray_Reference(qs, basisList); + + for (q, b, r) in Zipped3(qs, bs, rs) { + Message($"b = {b}, m = {r}"); + DumpMachine(); + within { + Ry(IntAsDouble(b) * PI() / 4.0, q); + } apply { + AssertQubitWithinTolerance(r, q, 1e-5); + } + Reset(q); + } + } @Test("QuantumSimulator") @@ -43,4 +89,14 @@ namespace Quantum.Kata.KeyDistributionE91 { } + @Test("QuantumSimulator") + operation T24_CorrelationCheck() : Unit { + // ... + } + + @Test("QuantumSimulator") + operation T31_Eavesdrop() : Unit { + // ... + } + } From 697d8a4fc0f049a64eded6905bd26bec4918d95c Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 23 Sep 2021 18:02:30 +0300 Subject: [PATCH 04/11] Add Jupyter Notebook file --- KeyDistribution_E91/KeyDistribution_E91.ipynb | 369 ++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 KeyDistribution_E91/KeyDistribution_E91.ipynb diff --git a/KeyDistribution_E91/KeyDistribution_E91.ipynb b/KeyDistribution_E91/KeyDistribution_E91.ipynb new file mode 100644 index 00000000000..a646da6c8ea --- /dev/null +++ b/KeyDistribution_E91/KeyDistribution_E91.ipynb @@ -0,0 +1,369 @@ +{ + "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": [ + "operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit {\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) `basis_index`: The index of measurement operator to be used\n", + "\n", + "**Output:** The result of the measurement." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "operation RotateAndMeasure(q : Qubit, rotationMultiplier: 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 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) `basisList`: A list of possible basis indices for choosing measurement operators.\n", + "\n", + "**Outputs:**\n", + "1) The list of basis choices,\n", + "2) The list of measurement results." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "operation MeasureQubitArray (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) {\n", + " let results = new Result[0];\n", + " let bases = new Int[0];\n", + " // ...\n", + "\n", + " return (bases, results);\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": [ + "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.4 Putting it all together \n", + "\n", + "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." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "operation T24_E91Protocol () : Unit {\n", + " // 1. Alice and Bob choose basis multipliers\n", + "\n", + " // 2. Alice and Bob are distributed arrays of entangled pairs\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 T24_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 Check\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": [ + "function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: 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) `basis`: 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": [ + "operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) {\n", + " Fact(basis == 2 or basis == 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.4, 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 choose basis multipliers\n", + "\n", + " // 2. Alice and Bob are distributed arrays of entangled pairs\n", + "\n", + " // Eve eavesdrops on all qubits, guessing the basis at random\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 From 3adb862206e5a7abd33c225935a39875f3c3df7e Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 23 Sep 2021 18:21:14 +0300 Subject: [PATCH 05/11] Some requested changes --- KeyDistribution_E91/ReferenceImplementation.qs | 10 ++++------ KeyDistribution_E91/Tasks.qs | 4 ++-- KeyDistribution_E91/Tests.qs | 10 +++------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs index 1783150eb22..20490f7c8aa 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -24,12 +24,12 @@ namespace Quantum.Kata.KeyDistributionE91 { ////////////////////////////////////////////////////////////////// // Task 1.1. Entangled Pairs - operation EntangledPairs_Reference (qsAlice : Qubit[], qsBob : Qubit[]) : Unit { + 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 in IndexRange(qsAlice) { - H(qsAlice[i]); - CNOT(qsAlice[i], qsBob[i]); + for (i, j) in Zipped(qsAlice, qsBob) { + H(i); + CNOT(i, j); } } @@ -117,7 +117,6 @@ namespace Quantum.Kata.KeyDistributionE91 { // Task 2.5 Putting it all together - @Test("QuantumSimulator") operation T25_E91Protocol_Reference () : Unit { // 1. Alice and Bob choose basis multipliers let basisListAlice = [0, 1, 2]; @@ -162,7 +161,6 @@ namespace Quantum.Kata.KeyDistributionE91 { } // Task 3.2. Catch the eavesdropper - @Test("QuantumSimulator") operation T32_E91ProtocolWithEavesdropper_Reference () : Unit { // 1. Alice and Bob choose basis multipliers let basisListAlice = [0, 1, 2]; diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs index d2d838998fb..52a7c669cc7 100644 --- a/KeyDistribution_E91/Tasks.qs +++ b/KeyDistribution_E91/Tasks.qs @@ -24,7 +24,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // 2) "qsBob": an array of N qubits in the |0⟩ states, // Goal: Create entangled pairs |Ψ⟩ = 1/√2 (|00⟩ + |11⟩) out of corresponding qubits of // Alice's and Bob's qubits. - operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit { + operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit is Adj{ Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits"); // ... @@ -155,7 +155,7 @@ namespace Quantum.Kata.KeyDistributionE91 { } // Task 3.2. Catch the eavesdropper - // Add an eavesdropper into the BB84 protocol from task 2.5. + // Add an eavesdropper into the E91 protocol from task 2.5. // Note that we should be able to detect Eve with a CHSH correlation check. // // This is an open-ended task and is not covered by a test; diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index 991efd63890..2661eaa2b9a 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -27,11 +27,7 @@ namespace Quantum.Kata.KeyDistributionE91 { use qsBob = Qubit[2]; EntangledPairs(qsAlice, qsBob); - - for (i, j) in Zipped(qsAlice, qsBob) { - CNOT(i, j); - H(i); - } + Adjoint EntangledPairs_Reference(qsAlice, qsBob); AssertAllZero(qsAlice + qsBob); } @@ -84,13 +80,13 @@ namespace Quantum.Kata.KeyDistributionE91 { } @Test("QuantumSimulator") - operation T23_GenerateSharedKey() : Unit { + function T23_GenerateSharedKey() : Unit { // ... } @Test("QuantumSimulator") - operation T24_CorrelationCheck() : Unit { + function T24_CorrelationCheck() : Unit { // ... } From 55a4a66d56d109fef4261ca956bd5d60f81bd097 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Wed, 29 Sep 2021 12:41:43 +0300 Subject: [PATCH 06/11] Split the MeasureQubitArray task into two MeasureQubitArray used to implement both the random basis selection and measurement processes. Now there are two separate tasks for these: RandomBasesArray and MeasureQubitArray. --- KeyDistribution_E91/KeyDistribution_E91.ipynb | 74 ++++++--- .../ReferenceImplementation.qs | 142 +++++++++--------- KeyDistribution_E91/Tasks.qs | 124 ++++----------- KeyDistribution_E91/Tests.qs | 67 ++++++--- 4 files changed, 197 insertions(+), 210 deletions(-) diff --git a/KeyDistribution_E91/KeyDistribution_E91.ipynb b/KeyDistribution_E91/KeyDistribution_E91.ipynb index a646da6c8ea..7dff1991dd6 100644 --- a/KeyDistribution_E91/KeyDistribution_E91.ipynb +++ b/KeyDistribution_E91/KeyDistribution_E91.ipynb @@ -31,7 +31,7 @@ "cell_type": "code", "execution_count": null, "source": [ - "operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit {\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", @@ -97,7 +97,7 @@ "\n", "**Inputs:** \n", "1) `q`: the qubit to be measured\n", - "2) `basis_index`: The index of measurement operator to be used\n", + "2) `basisIndex`: The index of measurement operator to be used\n", "\n", "**Output:** The result of the measurement." ], @@ -107,7 +107,7 @@ "cell_type": "code", "execution_count": null, "source": [ - "operation RotateAndMeasure(q : Qubit, rotationMultiplier: Int) : Result {\n", + "operation RotateAndMeasure(q : Qubit, basisIndex: Int) : Result {\n", " // ...\n", "\n", " return Zero;\n", @@ -131,16 +131,42 @@ { "cell_type": "markdown", "source": [ - "#### Task 2.2 Measure Qubit Arrays\n", + "#### 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": [ + "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) `basisList`: A list of possible basis indices for choosing measurement operators.\n", + "2) `basesIndices`: An array of random bases indices.\n", "\n", - "**Outputs:**\n", - "1) The list of basis choices,\n", - "2) The list of measurement results." + "**Outputs:** The list of measurement results." ], "metadata": {} }, @@ -148,12 +174,10 @@ "cell_type": "code", "execution_count": null, "source": [ - "operation MeasureQubitArray (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) {\n", - " let results = new Result[0];\n", - " let bases = new Int[0];\n", + "operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] {\n", " // ...\n", "\n", - " return (bases, results);\n", + " return new Result[0];\n", "\n", "}" ], @@ -192,9 +216,9 @@ { "cell_type": "markdown", "source": [ - "#### Task 2.4 Putting it all together \n", + "#### Task 2.5 Putting it all together \n", "\n", - "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." + "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": {} }, @@ -203,9 +227,9 @@ "execution_count": null, "source": [ "operation T24_E91Protocol () : Unit {\n", - " // 1. Alice and Bob choose basis multipliers\n", + " // 1. Alice and Bob are distributed arrays of entangled pairs\n", "\n", - " // 2. Alice and Bob are distributed arrays of entangled pairs\n", + " // 2. Alice and Bob choose random measurement bases\n", "\n", " // 3. Measurements by Alice and Bob\n", "\n", @@ -259,7 +283,7 @@ "cell_type": "code", "execution_count": null, "source": [ - "function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: Result[]) : Double {\n", + "function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {\n", " // ...\n", "\n", " return 0.0;\n", @@ -289,7 +313,7 @@ "**Inputs:** \n", "1) `qAlice`: a qubit that Alice will use,\n", "2) `qBob`: Bob's corresponding qubit,\n", - "3) `basis`: Eve's guess of the basis she should use for measuring.\n", + "3) `basisIndex`: Eve's guess of the basis she should use for measuring.\n", "\n", "**Output:** the bits encoded in given qubits." ], @@ -299,8 +323,8 @@ "cell_type": "code", "execution_count": null, "source": [ - "operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) {\n", - " Fact(basis == 2 or basis == 3, \"Eve should measure in one of Alice's and Bob's compatible basis\");\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", @@ -314,7 +338,7 @@ "source": [ "#### Task 3.3. Catch the Eavesdropper\n", "\n", - "Add an eavesdropper into Task 2.4, then try to detect them using a CHSH correlation check. This is an open-ended task and is not covered by a test." + "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": {} }, @@ -323,12 +347,12 @@ "execution_count": null, "source": [ "operation T33_E91ProtocolWithEavesdropper() : Unit {\n", - " // 1. Alice and Bob choose basis multipliers\n", - "\n", - " // 2. Alice and Bob are distributed arrays of entangled pairs\n", - "\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", diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs index 20490f7c8aa..fd2067e778e 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -39,9 +39,9 @@ namespace Quantum.Kata.KeyDistributionE91 { ////////////////////////////////////////////////////////////////// // Task 2.1 Rotate and Measure - operation RotateAndMeasure_Reference (q : Qubit, rotationMultiplier: Int) : Result { + operation RotateAndMeasure_Reference (q : Qubit, basisIndex: Int) : Result { mutable result = Zero; - let rotationAngle = PI() * IntAsDouble(rotationMultiplier) / 4.0; + let rotationAngle = PI() * IntAsDouble(basisIndex - 1) / 4.0; within { Ry(rotationAngle, q); @@ -52,20 +52,31 @@ namespace Quantum.Kata.KeyDistributionE91 { return result; } - // Task 2.2 Measure Qubit Arrays - operation MeasureQubitArray_Reference (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) { - mutable results = new Result[0]; + // Task 2.2. Random Bases Array + operation RandomBasesArray_Reference (basesIndices: Int[], N: Int) : Int[] { + // ... mutable bases = new Int[0]; - for q in qs { - let basis = basisList[DrawRandomInt(0,2)]; - let res = RotateAndMeasure(q, basis); + for _ in 1..N { + let randomIndex = DrawRandomInt(0, Length(basesIndices) - 1); + set bases += [basesIndices[randomIndex]]; + } + + return bases; + } + + + // Task 2.2 Measure Qubit Arrays + operation MeasureQubitArray_Reference (qs: Qubit[], basesIndices: Int[]) : Result[] { + // ... - set bases += [basis]; - set results += [res]; + mutable results = new Result[0]; + + for (q, b) in Zipped(qs, basesIndices) { + set results += [RotateAndMeasure(q,b)]; } - return (bases, results); + return results; } @@ -82,17 +93,47 @@ namespace Quantum.Kata.KeyDistributionE91 { return key; } - // Task 2.4 CHSH Correlation Check - function CorrelationCheck_Reference (basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: Result[]) : Double { + // 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(qsAlice, qsBob); + + // 2. Alice and Bob choose random measurement bases + let basesAlice = RandomBasesArray([1,2,3], N); + let basesBob = RandomBasesArray([2,3,4], N); + + // 3. Measurements by Alice and Bob + let resultsAlice = MeasureQubitArray(qsAlice, basesAlice); + let resultsBob = MeasureQubitArray(qsBob, basesBob); + + // 4. Keys generated by Alice and Bob + let keyAlice = GenerateSharedKey(basesAlice, basesBob, resultsAlice); + let keyBob = GenerateSharedKey(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 Check + function CorrelationCheck_Reference (basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { mutable expectationValues = new Double[0]; - for (i, j) in [(0,1), (0, 3), (2, 1), (2, 3)] { + 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 resAlice[idx] == resBob[idx] { + if resultsAlice[idx] == resultsBob[idx] { set sum += 1; } else { set sum -= 1; @@ -115,79 +156,44 @@ namespace Quantum.Kata.KeyDistributionE91 { return s; } - - // Task 2.5 Putting it all together - operation T25_E91Protocol_Reference () : Unit { - // 1. Alice and Bob choose basis multipliers - let basisListAlice = [0, 1, 2]; - let basisListBob = [1, 2, 3]; - - // 2. Alice and Bob are distributed arrays of entangled pairs - let N = 13; - use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); - EntangledPairs(qsAlice, qsBob); - - // 3. Measurements by Alice and Bob - let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisListAlice); - let (basesBob, resBob) = MeasureQubitArray(qsBob, basisListBob); - - // 4. Keys generated by Alice and Bob - let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); - let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); - Message($"Alice's Key: {keyAlice}"); - Message($"Bob's Key: {keyBob}\n"); - - // 5. Compute the CHSH correlation value - let s = CorrelationCheck(basesAlice, basesBob, resAlice, resBob); - Message($"S = {s}"); - - // Reset all qubits to |0⟩ - ResetAll(qsAlice + qsBob); - - } - - ////////////////////////////////////////////////////////////////// - // Part III. Eavesdropping - ////////////////////////////////////////////////////////////////// - - // Task 3.1. Eavesdrop! + // Task 3.2. Eavesdrop! operation Eavesdrop_Reference (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) { - Fact(basis == 1 or basis == 2, "Eve should measure in one of Alice's and Bob's compatible basis"); + Fact(basis == 2 or basis == 3, "Eve should measure in one of Alice's and Bob's compatible basis"); - let resAlice = RotateAndMeasure(qAlice, basis); - let resBob = RotateAndMeasure(qBob, basis); + let resultsAlice = RotateAndMeasure(qAlice, basis); + let resultsBob = RotateAndMeasure(qBob, basis); - return (resAlice, resBob); + return (resultsAlice, resultsBob); } - // Task 3.2. Catch the eavesdropper + // Task 3.3. Catch the eavesdropper operation T32_E91ProtocolWithEavesdropper_Reference () : Unit { - // 1. Alice and Bob choose basis multipliers - let basisListAlice = [0, 1, 2]; - let basisListBob = [1, 2, 3]; - - // 2. Alice and Bob are distributed arrays of entangled pairs - let N = 13; + // 1. Alice and Bob are distributed arrays of entangled pairs + let N = 10; use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); EntangledPairs(qsAlice, qsBob); // Eve eavesdrops on all qubits, guessing the basis at random for (qAlice, qBob) in Zipped(qsAlice, qsBob) { - let n = Eavesdrop(qAlice, qBob, DrawRandomInt(1,2)); + let _ = Eavesdrop(qAlice, qBob, DrawRandomInt(1,2)); } + // 2. Alice and Bob choose random measurement bases + let basesAlice = RandomBasesArray([1,2,3], N); + let basesBob = RandomBasesArray([2,3,4], N); + // 3. Measurements by Alice and Bob - let (basesAlice, resAlice) = MeasureQubitArray(qsAlice, basisListAlice); - let (basesBob, resBob) = MeasureQubitArray(qsBob, basisListBob); + let resultsAlice = MeasureQubitArray(qsAlice, basesAlice); + let resultsBob = MeasureQubitArray(qsBob, basesBob); // 4. Keys generated by Alice and Bob - let keyAlice = GenerateSharedKey(basesAlice, basesBob, resAlice); - let keyBob = GenerateSharedKey(basesAlice, basesBob, resBob); + let keyAlice = GenerateSharedKey(basesAlice, basesBob, resultsAlice); + let keyBob = GenerateSharedKey(basesAlice, basesBob, resultsBob); Message($"Alice's Key: {keyAlice}"); Message($"Bob's Key: {keyBob}\n"); // 5. Compute the CHSH correlation value - let s = CorrelationCheck(basesAlice, basesBob, resAlice, resBob); + let s = CorrelationCheck(basesAlice, basesBob, resultsAlice, resultsBob); Message($"S = {s}"); // Reset all qubits to |0⟩ diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs index 52a7c669cc7..56417d85f5f 100644 --- a/KeyDistribution_E91/Tasks.qs +++ b/KeyDistribution_E91/Tasks.qs @@ -19,11 +19,7 @@ namespace Quantum.Kata.KeyDistributionE91 { ////////////////////////////////////////////////////////////////// // Task 1.1. Entangled Pairs - // Inputs: - // 1) "qsAlice": an array of N qubits in the |0⟩ states, - // 2) "qsBob": an array of N qubits in the |0⟩ states, - // Goal: Create entangled pairs |Ψ⟩ = 1/√2 (|00⟩ + |11⟩) out of corresponding qubits of - // Alice's and Bob's qubits. + operation EntangledPairs (qsAlice : Qubit[], qsBob : Qubit[]) : Unit is Adj{ Fact(Length(qsAlice) == Length(qsBob), "Alice and Bob should have the same number of qubits"); // ... @@ -35,52 +31,29 @@ namespace Quantum.Kata.KeyDistributionE91 { // Part II. E91 Protocol ////////////////////////////////////////////////////////////////// - // Task 2.1 Rotate and Measure - // One of the essential steps of E91 protocol is conducting measurement operations. - // In Z-X plane, Alice measures her qubit in either one of Z, (Z+X)/√2 or X basis whereas - // Bob measures his qubit in either one of (Z+X)/√2, X or (X-Z)/√2 basis. - // Inputs: - // 1) "q": the qubit to be measured, - // 2) "rotationMultiplier": an integer to me multiplied by π/4 to - // compute the rotation angle in Z-X plane, - // Output: Result of the measurement - // Goal: Rotate PauliZ basis and measure q in that new basis. - operation RotateAndMeasure(q : Qubit, rotationMultiplier: Int) : Result { + // 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 new Int[N]; + } - // Task 2.2 Measure Qubit Arrays - // Now that you have a way of measuring a qubit in a given direction, it's time to - // measure either Alice's or Bob's qubits in random bases selected from their respective - // basis sets. - // Inputs: - // 1) "qs": An array of qubits to be measured, - // 2) "basisListt": A list of 3 possible rotation mutlipliers. - // Outputs: - // 1) List of generated basis choices, - // 2) List of measurement results. - // Goal: Measure qubits from qs in bases constructed using rotation multipliers that - // are choosen randomly from basisList. - operation MeasureQubitArray (qs: Qubit[], basisList: Int[]) : (Int[], Result[]) { - let results = new Result[0]; - let bases = new Int[0]; + // Task 2.3 Measure Qubit Arrays + operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] { // ... - return (bases, results); + return new Result[0]; } - // Task 2.3 Generate the shared key - // 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. - // Inputs: - // 1) "basesAlice": Alice's measurement bases multipliers, - // 2) "basesBob": Bob's measurement bases multipliers, - // 3) "results": Either Alice's or Bob's measurement outcomes. - // Output: A Bool array whose elements are the bits of shared key. + // Task 2.4 Generate the shared key function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { let key = new Bool[0]; // ... @@ -88,28 +61,6 @@ namespace Quantum.Kata.KeyDistributionE91 { return key; } - // Task 2.4 CHSH Correlation Check - // Non-compatible measurements were not useful for creating secret keys, but they are very - // for detecting an eavesdropper. Quantum mechanics tells us that the CHSH correlation value - // S = E(0, 1) - E(0, 3) + E(2, 1) + E(2, 3) - // should be 2√2 when there is no eavesdropper and is less than √2 when someone is manipulating - // the communication. The expectation value E(i, j) is the average value of outcomes when Alice - // measures on a basis with rotation multiplier i and Bob measures on a basis with rotation - // multiplier j. You should remember that when computing measurement outcomes, you should - // use actual eigenvalues which are +1 for Zero and -1 for One. - // - // Inputs: - // 1) "basesAlice": Alice's measurement bases multipliers, - // 2) "basesBob": Bob's measurement bases multipliers, - // 3) "resAlice": Alice's measurement outcomes, - // 4) "resBob": Bob's measurement outcomes. - // Output: CHSH correlation value. - function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resAlice: Result[], resBob: Result[]) : Double { - // ... - - return 0.0; - } - // 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. @@ -119,15 +70,13 @@ namespace Quantum.Kata.KeyDistributionE91 { @Test("QuantumSimulator") operation T25_E91Protocol () : Unit { - // 1. Alice and Bob choose basis multipliers + // 1. Alice and Bob are distributed arrays of entangled pairs - // 2. 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 - - // 5. Compute the CHSH correlation value } @@ -136,43 +85,34 @@ namespace Quantum.Kata.KeyDistributionE91 { // Part III. Eavesdropping ////////////////////////////////////////////////////////////////// - // Task 3.1. Eavesdrop! - // In this task you will try to implement an eavesdropper, Eve. - // Eave will intercept the qubits before they are measured by Alice or Bob. Eve uses - // one of Alice's and Bob's compatible basis, (Z+X)/√2 and X, for her measurement. This - // way, she might be able to place some known values into Bob's and Alice's keys. - // - // Inputs: - // 1) "qAlice": a qubit that Alice will use, - // 2) "qAlice": Bob's corresponding qubit, - // 3) "basis": Eve's guess of the basis she should use for measuring. - // Output: the bits encoded in given qubits. - operation Eavesdrop (qAlice : Qubit, qBob : Qubit, basis : Int) : (Result, Result) { - Fact(basis == 1 or basis == 2, "Eve should measure in one of Alice's and Bob's compatible basis"); + // Task 3.1. CHSH Correlation Check + function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { // ... - return (Zero, Zero); + return 0.0; } - // Task 3.2. Catch the eavesdropper - // Add an eavesdropper into the E91 protocol from task 2.5. - // Note that we should be able to detect Eve with a CHSH correlation check. - // - // This is an open-ended task and is not covered by a test; - // you can run T32_E91ProtocolWithEavesdropper() to run your code. - @Test("QuantumSimulator") - operation T32_E91ProtocolWithEavesdropper() : Unit { - // 1. Alice and Bob choose basis multipliers + // 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"); + // ... - // 2. Alice and Bob are distributed arrays of entangled pairs + 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 index 2661eaa2b9a..2a067c88a40 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -36,10 +36,11 @@ namespace Quantum.Kata.KeyDistributionE91 { operation T21_RotateAndMeasure() : Unit { use q = Qubit(); - for mutliplier in 0 .. 3 { - let res = RotateAndMeasure_Reference(q, mutliplier); + for basisIndex in 1..4 { + let res = RotateAndMeasure(q, basisIndex); + let rotationAngle = PI() * IntAsDouble(basisIndex - 1) / 4.0; within { - Ry(IntAsDouble(mutliplier) * PI() / 4.0, q); + Ry(rotationAngle, q); } apply { AssertQubitWithinTolerance(res, q, 1e-5); } @@ -48,50 +49,66 @@ namespace Quantum.Kata.KeyDistributionE91 { } - - operation randomList<'T>(values: 'T[], count : Int) : 'T[] { - let dist = DiscreteUniformDistribution(0,Length(values)-1); - mutable outList = new 'T[0]; - - for _ in 1 .. count { - set outList += [values[dist::Sample()]]; + @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 length does not match the input length" + ); + + 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}" + ); } - return outList; } @Test("QuantumSimulator") - operation T22_MeasureQubitArray() : Unit { - let basisList = [0, 1, 2, 3]; - use qs = Qubit[5]; + operation T23_MeasureQubitArray() : Unit { + let N = 5; + let basesArray = RandomBasesArray_Reference([1, 2, 3, 4], N); - let (bs, rs) = MeasureQubitArray_Reference(qs, basisList); + use qs = Qubit[N]; + let results = MeasureQubitArray_Reference(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; - for (q, b, r) in Zipped3(qs, bs, rs) { - Message($"b = {b}, m = {r}"); - DumpMachine(); within { - Ry(IntAsDouble(b) * PI() / 4.0, q); + Ry(rotationAngle, q); } apply { - AssertQubitWithinTolerance(r, q, 1e-5); + AssertQubitWithinTolerance(r, q, 1e-4); } - Reset(q); } - + ResetAll(qs); } @Test("QuantumSimulator") - function T23_GenerateSharedKey() : Unit { + function T24_GenerateSharedKey() : Unit { // ... } @Test("QuantumSimulator") - function T24_CorrelationCheck() : Unit { + function T31_CorrelationCheck() : Unit { // ... } @Test("QuantumSimulator") - operation T31_Eavesdrop() : Unit { + operation T32_Eavesdrop() : Unit { // ... } From 6476abe9c1c87fb0bd5b2bfd461eb5c824e8108f Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 30 Sep 2021 15:18:05 +0300 Subject: [PATCH 07/11] Make reference implementations refer to each other --- .../ReferenceImplementation.qs | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs index fd2067e778e..9893f21c3fc 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -65,22 +65,19 @@ namespace Quantum.Kata.KeyDistributionE91 { return bases; } - - // Task 2.2 Measure Qubit Arrays + // Task 2.3 Measure Qubit Arrays operation MeasureQubitArray_Reference (qs: Qubit[], basesIndices: Int[]) : Result[] { - // ... - mutable results = new Result[0]; for (q, b) in Zipped(qs, basesIndices) { - set results += [RotateAndMeasure(q,b)]; + let outcome = RotateAndMeasure_Reference(q,b); + set results += [outcome]; } return results; - } - // Task 2.3 Generate the shared key + // Task 2.4 Generate the shared key function GenerateSharedKey_Reference (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { mutable key = new Bool[0]; @@ -98,19 +95,19 @@ namespace Quantum.Kata.KeyDistributionE91 { // 1. Alice and Bob are distributed arrays of entangled pairs let N = 10; use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); - EntangledPairs(qsAlice, qsBob); + EntangledPairs_Reference(qsAlice, qsBob); // 2. Alice and Bob choose random measurement bases - let basesAlice = RandomBasesArray([1,2,3], N); - let basesBob = RandomBasesArray([2,3,4], N); + 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(qsAlice, basesAlice); - let resultsBob = MeasureQubitArray(qsBob, basesBob); + let resultsAlice = MeasureQubitArray_Reference(qsAlice, basesAlice); + let resultsBob = MeasureQubitArray_Reference(qsBob, basesBob); // 4. Keys generated by Alice and Bob - let keyAlice = GenerateSharedKey(basesAlice, basesBob, resultsAlice); - let keyBob = GenerateSharedKey(basesAlice, basesBob, resultsBob); + 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"); @@ -160,8 +157,8 @@ namespace Quantum.Kata.KeyDistributionE91 { 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(qAlice, basis); - let resultsBob = RotateAndMeasure(qBob, basis); + let resultsAlice = RotateAndMeasure_Reference(qAlice, basis); + let resultsBob = RotateAndMeasure_Reference(qBob, basis); return (resultsAlice, resultsBob); } @@ -171,29 +168,29 @@ namespace Quantum.Kata.KeyDistributionE91 { // 1. Alice and Bob are distributed arrays of entangled pairs let N = 10; use (qsAlice, qsBob) = (Qubit[N] ,Qubit[N]); - EntangledPairs(qsAlice, qsBob); + EntangledPairs_Reference(qsAlice, qsBob); // Eve eavesdrops on all qubits, guessing the basis at random for (qAlice, qBob) in Zipped(qsAlice, qsBob) { - let _ = Eavesdrop(qAlice, qBob, DrawRandomInt(1,2)); + let _ = Eavesdrop_Reference(qAlice, qBob, DrawRandomInt(1,2)); } // 2. Alice and Bob choose random measurement bases - let basesAlice = RandomBasesArray([1,2,3], N); - let basesBob = RandomBasesArray([2,3,4], N); + 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(qsAlice, basesAlice); - let resultsBob = MeasureQubitArray(qsBob, basesBob); + let resultsAlice = MeasureQubitArray_Reference(qsAlice, basesAlice); + let resultsBob = MeasureQubitArray_Reference(qsBob, basesBob); // 4. Keys generated by Alice and Bob - let keyAlice = GenerateSharedKey(basesAlice, basesBob, resultsAlice); - let keyBob = GenerateSharedKey(basesAlice, basesBob, resultsBob); + 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 = CorrelationCheck(basesAlice, basesBob, resultsAlice, resultsBob); + let s = CorrelationCheck_Reference(basesAlice, basesBob, resultsAlice, resultsBob); Message($"S = {s}"); // Reset all qubits to |0⟩ From d19da4b08ec670874018b7ebd1ac1cb150643795 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 30 Sep 2021 15:19:15 +0300 Subject: [PATCH 08/11] Complete tests for parts 1 and 2 --- KeyDistribution_E91/Tests.qs | 38 +++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index 2a067c88a40..30837f2f77a 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -32,6 +32,10 @@ namespace Quantum.Kata.KeyDistributionE91 { AssertAllZero(qsAlice + qsBob); } + ////////////////////////////////////////////////////////////////// + // Part II. E91 Protocol + ////////////////////////////////////////////////////////////////// + @Test("QuantumSimulator") operation T21_RotateAndMeasure() : Unit { use q = Qubit(); @@ -76,11 +80,12 @@ namespace Quantum.Kata.KeyDistributionE91 { @Test("QuantumSimulator") operation T23_MeasureQubitArray() : Unit { - let N = 5; - let basesArray = RandomBasesArray_Reference([1, 2, 3, 4], N); + let N = 10; + let basesArray = RandomBasesArray_Reference([1, 2, 3, 4], N); use qs = Qubit[N]; - let results = MeasureQubitArray_Reference(qs, basesArray); + + let results = MeasureQubitArray(qs, basesArray); for (q, b, r) in Zipped3(qs, basesArray, results) { // At this point, qubit should be projected onto an @@ -97,10 +102,33 @@ namespace Quantum.Kata.KeyDistributionE91 { } @Test("QuantumSimulator") - function T24_GenerateSharedKey() : Unit { - // ... + operation T24_GenerateSharedKey() : Unit { + let N = 10; + + mutable basesAlice = new Int[0]; + mutable basesBob = new Int[0]; + mutable results = new Result[0]; + + 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") function T31_CorrelationCheck() : Unit { From b2b8dbb5113513b2f1efd9b7dea01072961fc3cb Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Thu, 30 Sep 2021 15:33:08 +0300 Subject: [PATCH 09/11] Fix task numbers and add kata magic commands to the Jupyter notebook --- KeyDistribution_E91/KeyDistribution_E91.ipynb | 18 ++++++++++++++++-- KeyDistribution_E91/ReferenceImplementation.qs | 2 +- KeyDistribution_E91/Tests.qs | 6 +++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/KeyDistribution_E91/KeyDistribution_E91.ipynb b/KeyDistribution_E91/KeyDistribution_E91.ipynb index 7dff1991dd6..2c689d13152 100644 --- a/KeyDistribution_E91/KeyDistribution_E91.ipynb +++ b/KeyDistribution_E91/KeyDistribution_E91.ipynb @@ -31,6 +31,8 @@ "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", @@ -107,6 +109,8 @@ "cell_type": "code", "execution_count": null, "source": [ + "%kata T21_RotateAndMeasure\n", + "\n", "operation RotateAndMeasure(q : Qubit, basisIndex: Int) : Result {\n", " // ...\n", "\n", @@ -147,6 +151,8 @@ "cell_type": "code", "execution_count": null, "source": [ + "%kata T22_RandomBasesArray\n", + "\n", "operation RandomBasesArray (basesIndices: Int[], N: Int) : Int[] {\n", " // ...\n", "\n", @@ -174,6 +180,8 @@ "cell_type": "code", "execution_count": null, "source": [ + "%kata T23_MeasureQubitArray\n", + "\n", "operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] {\n", " // ...\n", "\n", @@ -203,6 +211,8 @@ "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", @@ -226,7 +236,7 @@ "cell_type": "code", "execution_count": null, "source": [ - "operation T24_E91Protocol () : Unit {\n", + "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", @@ -244,7 +254,7 @@ "cell_type": "code", "execution_count": null, "source": [ - "%simulate T24_E91Protocol" + "%simulate T25_E91Protocol" ], "outputs": [], "metadata": {} @@ -283,6 +293,8 @@ "cell_type": "code", "execution_count": null, "source": [ + "%kata T31_CorrelationCheck\n", + "\n", "function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {\n", " // ...\n", "\n", @@ -323,6 +335,8 @@ "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", diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs index 9893f21c3fc..a126a34acba 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -164,7 +164,7 @@ namespace Quantum.Kata.KeyDistributionE91 { } // Task 3.3. Catch the eavesdropper - operation T32_E91ProtocolWithEavesdropper_Reference () : Unit { + 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]); diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index 30837f2f77a..864ae8da5d8 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -31,6 +31,7 @@ namespace Quantum.Kata.KeyDistributionE91 { AssertAllZero(qsAlice + qsBob); } + ////////////////////////////////////////////////////////////////// // Part II. E91 Protocol @@ -50,7 +51,6 @@ namespace Quantum.Kata.KeyDistributionE91 { } Reset(q); } - } @Test("QuantumSimulator") @@ -61,7 +61,7 @@ namespace Quantum.Kata.KeyDistributionE91 { let basesArray = RandomBasesArray(basesIndices, N); EqualityFactI( Length(basesArray), N, - "Generated array length does not match the input length" + $"Generated array should be of length {N}" ); for i in basesArray { @@ -125,11 +125,11 @@ namespace Quantum.Kata.KeyDistributionE91 { ); } + ////////////////////////////////////////////////////////////////// // Part III. Eavesdropping ////////////////////////////////////////////////////////////////// - @Test("QuantumSimulator") function T31_CorrelationCheck() : Unit { // ... From e23931b66b0559f49ffab60a9bfd27b9647666d3 Mon Sep 17 00:00:00 2001 From: Utku Birkan Date: Mon, 11 Oct 2021 16:30:36 +0300 Subject: [PATCH 10/11] Add tests for the last two tasks. --- KeyDistribution_E91/KeyDistribution_E91.ipynb | 6 +-- .../ReferenceImplementation.qs | 8 ++-- KeyDistribution_E91/Tasks.qs | 4 +- KeyDistribution_E91/Tests.qs | 46 +++++++++++++++++-- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/KeyDistribution_E91/KeyDistribution_E91.ipynb b/KeyDistribution_E91/KeyDistribution_E91.ipynb index 2c689d13152..d3370381447 100644 --- a/KeyDistribution_E91/KeyDistribution_E91.ipynb +++ b/KeyDistribution_E91/KeyDistribution_E91.ipynb @@ -277,7 +277,7 @@ { "cell_type": "markdown", "source": [ - "#### Task 3.1 CHSH Correlation Check\n", + "#### Task 3.1 CHSH Correlation Value\n", "\n", "**Inputs:**\n", "1) `basesAlice`: Alice's measurement bases indices,\n", @@ -293,9 +293,9 @@ "cell_type": "code", "execution_count": null, "source": [ - "%kata T31_CorrelationCheck\n", + "%kata T31_CorrelationValue\n", "\n", - "function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {\n", + "function CorrelationValue(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double {\n", " // ...\n", "\n", " return 0.0;\n", diff --git a/KeyDistribution_E91/ReferenceImplementation.qs b/KeyDistribution_E91/ReferenceImplementation.qs index a126a34acba..2578eeea567 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -120,8 +120,8 @@ namespace Quantum.Kata.KeyDistributionE91 { // Part III. Eavesdropping ////////////////////////////////////////////////////////////////// - // Task 3.1 CHSH Correlation Check - function CorrelationCheck_Reference (basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { + // Task 3.1 CHSH Correlation Value + function CorrelationValue_Reference (basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { mutable expectationValues = new Double[0]; for (i, j) in [(1,2), (1, 4), (3, 2), (3, 4)] { @@ -172,7 +172,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // Eve eavesdrops on all qubits, guessing the basis at random for (qAlice, qBob) in Zipped(qsAlice, qsBob) { - let _ = Eavesdrop_Reference(qAlice, qBob, DrawRandomInt(1,2)); + let _ = Eavesdrop_Reference(qAlice, qBob, DrawRandomInt(2,3)); } // 2. Alice and Bob choose random measurement bases @@ -190,7 +190,7 @@ namespace Quantum.Kata.KeyDistributionE91 { Message($"Bob's Key: {keyBob}\n"); // 5. Compute the CHSH correlation value - let s = CorrelationCheck_Reference(basesAlice, basesBob, resultsAlice, resultsBob); + let s = CorrelationValue_Reference(basesAlice, basesBob, resultsAlice, resultsBob); Message($"S = {s}"); // Reset all qubits to |0⟩ diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs index 56417d85f5f..4494b0a6b5e 100644 --- a/KeyDistribution_E91/Tasks.qs +++ b/KeyDistribution_E91/Tasks.qs @@ -85,8 +85,8 @@ namespace Quantum.Kata.KeyDistributionE91 { // Part III. Eavesdropping ////////////////////////////////////////////////////////////////// - // Task 3.1. CHSH Correlation Check - function CorrelationCheck(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { + // Task 3.1. CHSH Correlation Value + function CorrelationValue(basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { // ... return 0.0; diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index 864ae8da5d8..fb343b32eea 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -131,13 +131,53 @@ namespace Quantum.Kata.KeyDistributionE91 { ////////////////////////////////////////////////////////////////// @Test("QuantumSimulator") - function T31_CorrelationCheck() : Unit { - // ... + 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]); + } } } From 65ba9e9709d94d76cec15182483d82dd8b1dd43f Mon Sep 17 00:00:00 2001 From: Mariia Mykhailova Date: Wed, 8 Jun 2022 12:02:44 -0700 Subject: [PATCH 11/11] Update the project to the latest QDK * Updates QDK version and .NET version * Update to latest syntax * Add README * Add new kata to the index --- .../KeyDistribution_E91.csproj | 14 +++++------ KeyDistribution_E91/KeyDistribution_E91.sln | 25 +++++++++++++++++++ KeyDistribution_E91/README.md | 11 ++++++++ .../ReferenceImplementation.qs | 8 +++--- KeyDistribution_E91/Tasks.qs | 6 ++--- KeyDistribution_E91/Tests.qs | 6 ++--- index.ipynb | 2 ++ 7 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 KeyDistribution_E91/KeyDistribution_E91.sln diff --git a/KeyDistribution_E91/KeyDistribution_E91.csproj b/KeyDistribution_E91/KeyDistribution_E91.csproj index d370c66a9eb..d249c13f433 100644 --- a/KeyDistribution_E91/KeyDistribution_E91.csproj +++ b/KeyDistribution_E91/KeyDistribution_E91.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.1 + net6.0 false Quantum.Kata.KeyDistributionE91 true @@ -9,11 +9,11 @@ - - - - - + + + + + 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 index e69de29bb2d..f17bec73ade 100644 --- a/KeyDistribution_E91/README.md +++ 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 index 2578eeea567..ed6a274af9b 100644 --- a/KeyDistribution_E91/ReferenceImplementation.qs +++ b/KeyDistribution_E91/ReferenceImplementation.qs @@ -55,7 +55,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // Task 2.2. Random Bases Array operation RandomBasesArray_Reference (basesIndices: Int[], N: Int) : Int[] { // ... - mutable bases = new Int[0]; + mutable bases = []; for _ in 1..N { let randomIndex = DrawRandomInt(0, Length(basesIndices) - 1); @@ -67,7 +67,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // Task 2.3 Measure Qubit Arrays operation MeasureQubitArray_Reference (qs: Qubit[], basesIndices: Int[]) : Result[] { - mutable results = new Result[0]; + mutable results = []; for (q, b) in Zipped(qs, basesIndices) { let outcome = RotateAndMeasure_Reference(q,b); @@ -79,7 +79,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // Task 2.4 Generate the shared key function GenerateSharedKey_Reference (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { - mutable key = new Bool[0]; + mutable key = []; for (a, b, r) in Zipped3(basesAlice, basesBob, results) { if a == b { @@ -122,7 +122,7 @@ namespace Quantum.Kata.KeyDistributionE91 { // Task 3.1 CHSH Correlation Value function CorrelationValue_Reference (basesAlice: Int[], basesBob: Int[], resultsAlice: Result[], resultsBob: Result[]) : Double { - mutable expectationValues = new Double[0]; + mutable expectationValues = []; for (i, j) in [(1,2), (1, 4), (3, 2), (3, 4)] { mutable sum = 0; diff --git a/KeyDistribution_E91/Tasks.qs b/KeyDistribution_E91/Tasks.qs index 4494b0a6b5e..a204cf3d303 100644 --- a/KeyDistribution_E91/Tasks.qs +++ b/KeyDistribution_E91/Tasks.qs @@ -42,20 +42,20 @@ namespace Quantum.Kata.KeyDistributionE91 { operation RandomBasesArray (basesIndices: Int[], N: Int) : Int[] { // ... - return new Int[N]; + return []; } // Task 2.3 Measure Qubit Arrays operation MeasureQubitArray (qs: Qubit[], basesIndices: Int[]) : Result[] { // ... - return new Result[0]; + return []; } // Task 2.4 Generate the shared key function GenerateSharedKey (basesAlice: Int[], basesBob: Int[], results: Result[]) : Bool[] { - let key = new Bool[0]; + let key = []; // ... return key; diff --git a/KeyDistribution_E91/Tests.qs b/KeyDistribution_E91/Tests.qs index fb343b32eea..c75f7045d6c 100644 --- a/KeyDistribution_E91/Tests.qs +++ b/KeyDistribution_E91/Tests.qs @@ -105,9 +105,9 @@ namespace Quantum.Kata.KeyDistributionE91 { operation T24_GenerateSharedKey() : Unit { let N = 10; - mutable basesAlice = new Int[0]; - mutable basesBob = new Int[0]; - mutable results = new Result[0]; + mutable basesAlice = []; + mutable basesBob = []; + mutable results = []; for _ in 1..N { set basesAlice += [DrawRandomInt(1,3)]; 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",