Quantum Key Distribution: BB84 scheme​
​by Mads Bahrami
In this short computational essay, we implemented the Bennett-Brassard scheme (BB84) in the Wolfram Quantum Computation Framework. BB84 is a quantum method for establishing a shared secret key. In fact, it is an example of Quantum Key Distribution (QKD), and the first quantum cryptography protocol.

One-time pad encryption

In this section, we briefly review the one-time pad encryption by using a secret key, securely shared between two parties (e.g., Alice and Bob).
Define a function that returns the ASCII bits of a string:
In[]:=
ascii[st_String]:=IntegerDigits[#,2]&/@ToCharacterCode[st]
Select a secret key (shared securely between Alice and bob):
In[]:=
key=ascii["Wolfram"]
Out[]=
{{1,0,1,0,1,1,1},{1,1,0,1,1,1,1},{1,1,0,1,1,0,0},{1,1,0,0,1,1,0},{1,1,1,0,0,1,0},{1,1,0,0,0,0,1},{1,1,0,1,1,0,1}}
Select a message (Alice wants to send it to Bob):
In[]:=
message=ascii["Quantum"]
Out[]=
{{1,0,1,0,0,0,1},{1,1,1,0,1,0,1},{1,1,0,0,0,0,1},{1,1,0,1,1,1,0},{1,1,1,0,1,0,0},{1,1,1,0,1,0,1},{1,1,0,1,1,0,1}}
Generate a ciphertext by taking the XOR of each bit of the message with each bit of the secret key (Alice does this, and send the ciphertext to Bob):
In[]:=
ciphertext=MapThread[BitXor,{message,key}]
Out[]=
{{0,0,0,0,1,1,0},{0,0,1,1,0,1,0},{0,0,0,1,1,0,1},{0,0,0,1,0,0,0},{0,0,0,0,1,1,0},{0,0,1,0,1,0,0},{0,0,0,0,0,0,0}}
Decode the ciphertext by taking the XOR of each bit of it with each bit of the secret key (Given Alice message, Bob does this step):
In[]:=
decodedtext=MapThread[BitXor,{ciphertext,key}]
Out[]=
{{1,0,1,0,0,0,1},{1,1,1,0,1,0,1},{1,1,0,0,0,0,1},{1,1,0,1,1,1,0},{1,1,1,0,1,0,0},{1,1,1,0,1,0,1},{1,1,0,1,1,0,1}}
Show the text of the decoded text:
In[]:=
StringJoin[FromCharacterCode[FromDigits[#,2]]&/@decodedtext]
Out[]=
Quantum

Bennett-Brassard quantum solution (BB84)

As an example of a quantum key distribution (QKD), we consider BB84 protocol.
Alice generate a random bit and for each one, she randomly choose either Z-basis or X-basis of measurement. Let we consider a sequence of 9 bits:
In[]:=
aliceBits=RandomChoice[{0,1},9]​​aliceBases=RandomChoice[{"Z","X"},9]
Out[]=
{0,0,1,0,0,1,0,0,0}
Out[]=
{X,X,Z,Z,X,X,X,Z,X}
Depending on what bit and what base, she follows the following protocol for sending a qubit to Bob:
In[]:=
aliceProtocol=<|{0,"Z"}->QuantumState["0"],{0,"X"}->QuantumState[{0,1},"PauliX"],{1,"Z"}->QuantumState["1"],{1,"X"}->QuantumState[{1,0},"PauliX"]|>;​​#["Formula"]&/@aliceProtocol//Normal//Column
Out[]=
{0,Z}|0〉
{0,X}
ψ
x
+

{1,Z}|1〉
{1,X}
ψ
x
-

Therefore, given Alice’s bit and bases generated randomly, she will send Bob these qubits:
In[]:=
aliceQubits=aliceProtocol/@Thread[List[aliceBits,aliceBases]];​​#["Formula"]&/@aliceQubits
Out[]=

ψ
x
+
,
ψ
x
+
,1,0,
ψ
x
+
,
ψ
x
-
,
ψ
x
+
,0,
ψ
x
+

Bob randomly generate a sequence of either Z-basis or X-basis of measurement:
In[]:=
bobBases=RandomChoice[{"Z","X"},9]
Out[]=
{Z,Z,Z,X,X,X,Z,Z,Z}
It means, Bob applies the following measurement operators on qubits he relieved from Alice:
In[]:=
QuantumMeasurementOperator/@bobBases
Out[]=
QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1
,QuantumMeasurementOperator
Measurement Type: Projection
Target: {1}
Dimension: 2→2
Qudits: 1→1

Now let’s look at post-measurement situation. As once can see, whenever Bob’s measurement basis is not the same as Alice’s, Bob gets two results randomly:
In[]:=
MapThread[#1[#2]&,{QuantumMeasurementOperator/@bobBases,aliceQubits}]
Out[]=
QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2
,QuantumMeasurement
Target: {1}
Measurement Outcomes: 2

Return one possible realization of Bob' s series of measurements (note some will always return the same result, some randomly, depending on what Alice' s qubit is and what direction Bob measures):
In[]:=
bobRealization=#["SimulatedMeasurement"]&/@MapThread[#1[#2]&,{QuantumMeasurementOperator/@bobBases,aliceQubits}]
Out[]=

ψ
z
-
,
ψ
z
+
,
ψ
z
-
,
ψ
x
-
,
ψ
x
+
,
ψ
x
-
,
ψ
z
+
,
ψ
z
+
,
ψ
z
+

Bob assigns the bit 0 whenever he gets
|
ψ
z
+
〉
or
|
ψ
x
+
〉
, and the bit 1 for
|
ψ
z
-
〉
or
|
ψ
x
-
〉
In[]:=
bobBits=bobRealization/.
"ψ"
"z"
"+"

"ψ"
"x"
"+"
:>0,
"ψ"
"z"
"-"

"ψ"
"x"
"-"
:>1
Out[]=
{1,0,1,1,0,1,0,0,0}
Now they call each other and publicly share what measurement basis they used; in other word a classical communication. If the same, they keep the bit, if not, they disregard the corresponding bit. Note that they do it separately, and each one obtains a secret key, which will be the same, of course.
In[]:=
aliceSecretKey=Select[Transpose[{aliceBits,aliceBases,bobBases}],#[[2]]==#[[3]]&][[All,1]]
Out[]=
{1,0,1,0}
In[]:=
bobSecretKey=Select[Transpose[{bobBits,aliceBases,bobBases}],#[[2]]==#[[3]]&][[All,1]]
Out[]=
{1,0,1,0}
In[]:=
bobSecretKey==aliceSecretKey
Out[]=
True
As one can see, Alice and Bob now share a secret key. Note the key length is less than the number of qubits Alice sent to Bob (because Bob picks the measurement basis randomly, and he might not get the same outcome as Alice’s). Alice can keep sending Bob qubits until they reach a desired length. This can be implemented as follows.
In[]:=
add[{x_,y_}]:=Module{aliceBit,aliceBase,aliceQubit,bobBase,bobBit},​​aliceBit=RandomChoice[{0,1}];​​aliceBase=RandomChoice[{"Z","X"}];​​aliceQubit=aliceProtocol[{aliceBit,aliceBase}];​​bobBase=RandomChoice[{"Z","X"}];​​bobBit=QuantumMeasurementOperator[bobBase][aliceQubit]["SimulatedMeasurement"]/.
"ψ"
"z"
"+"

"ψ"
"x"
"+"
:>0,
"ψ"
"z"
"-"

"ψ"
"x"
"-"
:>1;​​If[aliceBase==bobBase,{Append[x,aliceBit],Append[y,bobBit]},{x,y}]
For example, the key length is set as 5 bits in the following:

Paclet installation