量子密钥分发
1. 简介
当Alice和Bob想要通过一个不安全的信道(比如互联网)传递一条秘密消息(比如Bob的网上银行信息)时,加密消息是至关重要的。密码学是一个很大的领域,几乎所有的内容都超出了本书的范围,因此我们必须相信Alice和Bob拥有一个别人不知道的密钥,这是有用的,可以让他们使用对称密钥加密进行通信。
如果Alice和Bob想要使用Eve的经典通信信道来共享他们的密钥,那就不可能知道Eve是否为自己复制了这个密钥——他们必须完全相信Eve没有在听。然而,如果Eve提供了一个量子通信信道,Alice和Bob就不再需要信任Eve了——他们将知道Eve是否试图在Bob的消息到达Alice之前读取它。
对于一些读者来说,给出量子信道如何在物理上实现的想法可能是有用的。经典信道的一个例子可以是电话线;我们通过代表信息(或比特)的线路发送电信号。量子通信信道的一个例子可能是某种光纤电缆,我们可以通过它发送单个光子(光的粒子)。光子有一种叫做极化的特性,这种极化可以是两种状态之一。我们可以用它来表示量子比特。
2. 协议概述
该协议利用了测量量子比特可以改变其状态这一事实。如果Alice发送给Bob一个量子比特,而窃听者Eve试图在Bob之前对其进行测量,那么Eve的测量有可能会改变量子比特的状态,Bob将无法接收到Alice发送的量子比特状态。
from qiskit import QuantumCircuit, Aer, transpile, assemble
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from numpy.random import randint
import numpy as np
print("Imports Successful")
Imports Successful
如果Alice准备一个状态为 \ket{+} (在 X 基下为0)的量子比特,并且Bob在 X 基下测量它,那么Bob的测量结果一定是0:
qc = QuantumCircuit(1,1)
# Alice prepares qubit in state |+>
qc.h(0)
qc.barrier()
# Alice now sends the qubit to Bob
# who measures it in the X-basis
qc.h(0)
qc.measure(0,0)
# Draw and simulate circuit
display(qc.draw())
aer_sim = Aer.get_backend('aer_simulator')
job = aer_sim.run(assemble(qc))
plot_histogram(job.result().get_counts())
但如果Eve试图在它到达Bob之前以 Z 基测量这个量子比特,她将使量子比特的状态从 \ket{+} 变为 \ket{0} 或 \ket{1} ,Bob不再确定测量到0:
qc = QuantumCircuit(1,1)
# Alice prepares qubit in state |+>
qc.h(0)
# Alice now sends the qubit to Bob
# but Eve intercepts and tries to read it
qc.measure(0, 0)
qc.barrier()
# Eve then passes this on to Bob
# who measures it in the X-basis
qc.h(0)
qc.measure(0,0)
# Draw and simulate circuit
display(qc.draw())
aer_sim = Aer.get_backend('aer_simulator')
job = aer_sim.run(assemble(qc))
plot_histogram(job.result().get_counts())
我们可以看到,Bob现在有50%的机会测量到1,如果他测量到1,他和Alice就会知道他们的信道有问题。
量子密钥分发协议涉及重复这个过程足够多次,以至于窃听者侥幸逃脱的机会微乎其微。大致如下:
- 步骤1
Alice选择一串随机比特,例如:
1000101011010100
并为每个比特随机选择基:
ZZXZXXXZXZXXXXXX
Alice对这两条信息保密。
- 步骤2
然后,Alice使用她选择的基将每个比特编码为一串量子比特;这意味着每个量子比特都处于随机选择的状态 \ket{0},\ket{1},\ket{+},\ket{-} 之一。在这种情况下,量子比特串看起来是这样的:
这是她发给Bob的信息。
- 步骤3
然后Bob随机测量每个量子比特,例如,他可能使用基:
XZZZXZXZXZXZZZXZ
Bob对测量结果保密。
- 步骤4
然后Bob和Alice公开分享他们用于每个量子比特的基。如果Bob在Alice准备的相同基中测量了一个量子比特,他们就用它来构成共享密钥的一部分,否则他们就丢弃该比特的信息。
- 步骤5
最后,Bob和Alice共享一个随机的密钥样本,如果样本匹配,他们就可以(在很小的误差范围内)确定传输成功。
3. Qiskit示例:无拦截
让我们先看看没有人监听时协议是如何工作的,然后看看Alice和Bob如何检测到窃听者。和往常一样,我们先导入所有需要的东西:
我们将使用numpy中的randin
函数来生成伪随机密钥。为了确保你可以在这个页面上重现结果,我们将seed设置为0:
np.random.seed(seed=0)
我们假设Alice的初始消息长度为n。在这个例子中,Alice将发送一条100量子比特长的消息:
n = 100
3.1 步骤1:
Alice生成一组随机比特:
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
print(alice_bits)
[0 1 1 0 1 1 1 1 1 1 1 0 0 1 0 0 0 0 0 1 0 1 1 0 0 1 1 1 1 0 1 0 1 0 1 1 0
1 1 0 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 0 1 0 0 1 1 0 1 0 1 0 0 0 0 0 1 1 0 0
0 1 1 0 1 0 0 1 0 1 1 1 1 1 1 0 1 1 0 0 1 0 0 1 1 0]
目前,只有Alice知道alice_bits
这组比特。我们将记录哪些信息只有Alice知道,哪些信息只有Bob知道,以及哪些信息已经通过Eve的信道发送出去了,如下所示:
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits |
3.2 步骤2:
Alice随机选择以 X 或 Z 基编码量子比特上的每个比特,并将每个量子比特的选择存储在alice_bases
中。在这种情况下,0表示“在 Z 基中准备”,1表示“在 x 基中准备”:
np.random.seed(seed=0)
n = 100
## Step 1
#Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
print(alice_bases)
[1 0 0 1 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 0 1 1 1 1 1 0 1 1 1 1 0 1 1 0 0 1 0
0 0 0 1 1 0 0 1 0 1 1 1 1 0 0 0 1 0 1 1 1 0 1 0 0 1 0 1 1 0 0 1 0 1 0 1 0
1 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0]
Alice也对这些信息保密:
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases |
下面的函数encode_message
创建一个QuantumCircuit
的列表,每个QuantumCircuit
表示Alice消息中的一个量子比特:
def encode_message(bits, bases):
message = []
for i in range(n):
qc = QuantumCircuit(1,1)
if bases[i] == 0: # Prepare qubit in Z-basis
if bits[i] == 0:
pass
else:
qc.x(0)
else: # Prepare qubit in X-basis
if bits[i] == 0:
qc.h(0)
else:
qc.x(0)
qc.h(0)
qc.barrier()
message.append(qc)
return message
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
我们可以看到,alices_bits
的第一个比特是0,她编码这个比特的基是 X 基(用1表示):
print('bit = %i' % alice_bits[0])
print('basis = %i' % alice_bases[0])
bit = 0
basis = 1
如果我们查看message
中的第一个电路(表示Alice消息中的第一个量子比特),我们可以验证Alice已经准备了一个状态为 \ket{+} 的量子比特:
message[0].draw()
另一个例子,我们可以看到alice_bits
中的第四个比特是1,它是在 Z 基中编码的,Alice准备对应的状态为 \ket{1} 的量子比特:
print('bit = %i' % alice_bits[4])
print('basis = %i' % alice_bases[4])
message[4].draw()
bit = 1
basis = 0
这条量子比特消息随后通过Eve的量子信道发送给Bob:
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
3.3 步骤3:
然后Bob在 X 或 Z 基中随机测量每个量子比特并存储这些信息:
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Step 3
# Decide which basis to measure in:
bob_bases = randint(2, size=n)
print(bob_bases)
[1 0 1 0 0 1 1 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 0 1 1 1 1 0 0 0 1 1
0 1 0 0 1 0 1 1 1 1 0 0 0 1 1 1 0 1 1 1 1 0 0 1 1 0 0 0 1 1 0 1 1 1 1 1 0
0 0 1 0 1 0 1 1 0 0 0 1 0 0 1 1 1 1 0 1 0 0 0 0 1 1]
bob_bases
存储Bob选择的测量每个量子比特的基。
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases |
下面,函数measure_message
应用相应的测量并模拟测量每个量子比特的结果。我们将测量结果存储在bob_results
中。
def measure_message(message, bases):
backend = Aer.get_backend('aer_simulator')
measurements = []
for q in range(n):
if bases[q] == 0: # measuring in Z-basis
message[q].measure(0,0)
if bases[q] == 1: # measuring in X-basis
message[q].h(0)
message[q].measure(0,0)
aer_sim = Aer.get_backend('aer_simulator')
qobj = assemble(message[q], shots=1, memory=True)
result = aer_sim.run(qobj).result()
measured_bit = int(result.get_memory()[0])
measurements.append(measured_bit)
return measurements
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Step 3
# Decide which basis to measure in:
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
我们可以看到message[0]
(表示第0个量子比特)中的电路被Bob添加了一个 X 测量值:
message[0].draw()
由于Bob碰巧选择在Alice编码量子比特的同一基中测量,Bob保证得到的结果为0。对于第6个量子比特(如下所示),Bob随机选择的测量值与Alice的不一样,Bob的结果与Alice匹配的概率只有50%。
message[6].draw()
print(bob_results)
[0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1]
Bob对他的结果保密。
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results |
3.4 步骤4:
在这之后,Alice(通过Eve的信道)揭示了哪些量子比特是以何种基编码的:
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases |
Bob展示了他在哪个基中测量每个量子比特:
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases | |
bob_bases | bob_bases |
如果Bob测量比特所用的基恰好与Alice准备比特时的基相同,这意味着bob_results
中的条目将与alice_bits
中的对应条目匹配,它们可以将该比特作为密钥的一部分。如果他们在不同的基下测量,Bob的结果是随机的,他们都将这一项丢弃。下面是remove_garbage
函数,它可以帮助我们完成这项工作:
def remove_garbage(a_bases, b_bases, bits):
good_bits = []
for q in range(n):
if a_bases[q] == b_bases[q]:
# If both used the same basis, add
# this to the list of 'good' bits
good_bits.append(bits[q])
return good_bits
Alice和Bob都丢弃了无用的比特,并使用剩余的比特来构造密钥:
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Step 3
# Decide which basis to measure in:
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
## Step 4
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
print(alice_key)
[0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0]
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases | |
bob_bases | bob_bases | |
alice_key |
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Step 3
# Decide which basis to measure in:
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
## Step 4
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
bob_key = remove_garbage(alice_bases, bob_bases, bob_results)
print(bob_key)
[0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0]
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases | |
bob_bases | bob_bases | |
alice_key | bob_key |
3.5 步骤5:
最后,Bob和Alice比较他们的密钥中的随机选择的比特,以确保协议的正确工作:
def sample_bits(bits, selection):
sample = []
for i in selection:
# use np.mod to make sure the
# bit we sample is always in
# the list range
i = np.mod(i, len(bits))
# pop(i) removes the element of the
# list at index 'i'
sample.append(bits.pop(i))
return sample
Alice和Bob都公开广播这些,并将它们从密钥中删除,因为它们不再是秘密:
np.random.seed(seed=0)
n = 100
## Step 1
# Alice generates bits
alice_bits = randint(2, size=n)
## Step 2
# Create an array to tell us which qubits
# are encoded in which bases
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Step 3
# Decide which basis to measure in:
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
## Step 4
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
bob_key = remove_garbage(alice_bases, bob_bases, bob_results)
## Step 5
sample_size = 15
bit_selection = randint(n, size=sample_size)
bob_sample = sample_bits(bob_key, bit_selection)
print(" bob_sample = " + str(bob_sample))
alice_sample = sample_bits(alice_key, bit_selection)
print("alice_sample = "+ str(alice_sample))
bob_sample = [0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
alice_sample = [0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases | |
bob_bases | bob_bases | |
alice_key | bob_key | |
bob_sample | bob_sample | bob_sample |
alice_sample | alice_sample | alice_sample |
如果协议在没有干扰的情况下正常工作,他们的样本应该匹配:
bob_sample == alice_sample
True
如果他们的样本匹配,则意味着(很有可能)alice_key == bob_key
。他们现在共享一个密钥,可以用来加密消息!
Alice知道 | 通过Eve的信道 | Bob知道 |
---|---|---|
alice_bits | ||
alice_bases | ||
message | message | message |
bob_bases | ||
bob_results | ||
alice_bases | alice_bases | |
bob_bases | bob_bases | |
alice_key | bob_key | |
bob_sample | bob_sample | bob_sample |
alice_sample | alice_sample | alice_sample |
shared_key | shared_key |
print(bob_key)
print(alice_key)
print("key length = %i" % len(alice_key))
[1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0]
[1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0]
key length = 33
4. Qiskit示例:有拦截
现在让我们看看Alice和Bob如何判断Eve是否一直在试图监听他们的量子信息。我们重复无干扰的相同步骤,但在Bob收到他的量子比特之前,Eve将尝试从中提取一些信息。让我们设置一个不同的种子,这样我们就可以得到一组特定的可重复的“随机”结果:
np.random.seed(seed=3)
4.1 步骤1:
Alice生成一组随机比特:
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
print(alice_bits)
[0 0 1 1 0 0 0 1 1 1 0 1 1 1 0 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 0 1 0 1 1 0 1
0 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 1 1 0 0 1 1
1 0 1 1 1 1 1 1 0 1 0 0 1 1 0 1 0 0 0 0 0 1 1 0 1 1]
4.2 步骤2:
Alice以 Z 和 X 基随机编码这些数据,并通过Eve的量子信道发送给Bob:
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
## Step 2
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
print(alice_bases)
[1 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 1 1 0 0
1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0 0 1 0 1 0 1 1 0 0 1 0 0 1 1 1 1
1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1 1 1]
在这种情况下,Alice消息中的第一个量子比特处于 \ket{+} 状态:
message[0].draw()
拦截!
噢,不!Eve拦截了通过她的信道传递的信息。她试图用随机选择的基来测量量子比特,Bob稍后也会用同样的方式。
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
## Step 2
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Interception!!
eve_bases = randint(2, size=n)
intercepted_message = measure_message(message, eve_bases)
print(intercepted_message)
[0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0]
下面我们可以看到量子比特0的情况;Eve对基的随机选择与Alice的不一样,这将使量子比特状态从 \ket{+} ,变成 Z 基中的一个随机状态,有50%的概率是 \ket{0} 或 \ket{1} :
message[0].draw()
4.3 步骤3:
然后Eve将量子比特传递给Bob,Bob随机测量它们。在这种情况下,Bob(偶然地)选择在Alice准备量子比特的相同基中测量。在不拦截的情况下,Bob可以保证测量到0,但由于Eve尝试读取消息,他现在有50%的机会测量到1。
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
## Step 2
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Interception!!
eve_bases = randint(2, size=n)
intercepted_message = measure_message(message, eve_bases)
## Step 3
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
message[0].draw()
4.4 步骤4:
Bob和Alice给出了他们的基的选择,并丢弃无用的比特:
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
## Step 2
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Interception!!
eve_bases = randint(2, size=n)
intercepted_message = measure_message(message, eve_bases)
## Step 3
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
## Step 4
bob_key = remove_garbage(alice_bases, bob_bases, bob_results)
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
4.5 步骤5:
Bob和Alice对同样随机选择的密钥进行比较,以查看量子比特是否被拦截:
np.random.seed(seed=3)
## Step 1
alice_bits = randint(2, size=n)
## Step 2
alice_bases = randint(2, size=n)
message = encode_message(alice_bits, alice_bases)
## Interception!!
eve_bases = randint(2, size=n)
intercepted_message = measure_message(message, eve_bases)
## Step 3
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
## Step 4
bob_key = remove_garbage(alice_bases, bob_bases, bob_results)
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
## Step 5
sample_size = 15
bit_selection = randint(n, size=sample_size)
bob_sample = sample_bits(bob_key, bit_selection)
print(" bob_sample = " + str(bob_sample))
alice_sample = sample_bits(alice_key, bit_selection)
print("alice_sample = "+ str(alice_sample))
bob_sample = [1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0]
alice_sample = [1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
bob_sample == alice_sample
False
噢,不!Bob的密钥和Alice的密钥不匹配。我们知道这是因为Eve试图在第2步和第3步之间读取消息,并改变了量子比特的状态。尽管Alice和Bob都知道,这可能是由于信道中存在噪声,但无论如何,他们都必须丢弃所有的结果,然后再试一次——Eve的拦截尝试失败了。
5. 风险分析
在这种类型的拦截中,Eve测量所有的量子比特,Bob和Alice的样本有很小的机会匹配,Alice通过Eve的信道发送有漏洞的信息。让我们计算一下这个概率,看看量子密钥分发的风险有多大。
- 对于Alice和Bob来说,要使用一个量子比特的结果,他们必须都选择相同的基。如果Eve也选择了这个基,她将成功拦截这个比特,而不会引入任何错误。发生这种情况的概率是50%。
- 如果Eve选择了错误 的基,即Alice和Bob选择了不同的基,Bob仍然有50%的机会测量Alice试图发送的值。在这种情况下,拦截也不会被发现。
- 但是如果Eve选择了错误 的基,即Alice和Bob选择了不同的基,那么Bob有50%的可能不会测量Alice想要发送的值,这将 导致密钥出错。
如果Alice和Bob比较密钥的1比特,那么匹配的概率为 0.75 ,如果是这样,他们就不会注意到Eve的拦截。如果测量的是2比特,那么有 0.75^2=0.5625 的概率不会注意到Eve的拦截。我们可以看到,Eve未被检测到的概率可以通过Alice和Bob选择比较的比特数( x )来计算:
如果我们决定像上面那样比较15比特,那么Eve未被检测到的几率为1.3%。如果这对我们来说风险太大,我们可以比较50比特,并且有0.00006%的几率在不知情的情况下被监视。
您可以通过运行以下单元格再次重试该协议。试着将sample_size
设置为较小的值,看看Eve截获Alice和Bob的密钥有多容易。
n = 100
# Step 1
alice_bits = randint(2, size=n)
alice_bases = randint(2, size=n)
# Step 2
message = encode_message(alice_bits, alice_bases)
# Interception!
eve_bases = randint(2, size=n)
intercepted_message = measure_message(message, eve_bases)
# Step 3
bob_bases = randint(2, size=n)
bob_results = measure_message(message, bob_bases)
# Step 4
bob_key = remove_garbage(alice_bases, bob_bases, bob_results)
alice_key = remove_garbage(alice_bases, bob_bases, alice_bits)
# Step 5
sample_size = 15 # Change this to something lower and see if
# Eve can intercept the message without Alice
# and Bob finding out
bit_selection = randint(n, size=sample_size)
bob_sample = sample_bits(bob_key, bit_selection)
alice_sample = sample_bits(alice_key, bit_selection)
if bob_sample != alice_sample:
print("Eve's interference was detected.")
else:
print("Eve went undetected!")
Eve’s interference was detected.
import qiskit.tools.jupyter
%qiskit_version_table
版本信息
Qiskit Software | Version |
---|---|
Qiskit | 0.27.0 |
Terra | 0.17.4 |
Aer | 0.8.2 |
Ignis | 0.6.0 |
Aqua | 0.9.2 |
IBM Q Provider | 0.14.0 |
System information | |
---|---|
Python | 3.7.7 (default, May 6 2020, 04:59:01) [Clang 4.0.1 (tags/RELEASE_401/final)] |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 32.0 |
Wed Jun 16 09:46:12 2021 BST