Qiskit-汉化 3.13 Quantum Key Distribution

量子密钥分发

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{-} 之一。在这种情况下,量子比特串看起来是这样的:

|1\rangle|0\rangle|+\rangle|0\rangle|-\rangle|+\rangle|-\rangle|0\rangle|-\rangle|1\rangle|+\rangle|-\rangle|+\rangle|-\rangle|+\rangle|+\rangle

这是她发给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随机选择以 XZ 基编码量子比特上的每个比特,并将每个量子比特的选择存储在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()

3

另一个例子,我们可以看到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
 

4

这条量子比特消息随后通过Eve的量子信道发送给Bob:

Alice知道 通过Eve的信道 Bob知道
alice_bits
alice_bases
message message message

3.3 步骤3:

然后Bob在 XZ 基中随机测量每个量子比特并存储这些信息:

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()

5

由于Bob碰巧选择在Alice编码量子比特的同一基中测量,Bob保证得到的结果为0。对于第6个量子比特(如下所示),Bob随机选择的测量值与Alice的不一样,Bob的结果与Alice匹配的概率只有50%。

message[6].draw()

6

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以 ZX 基随机编码这些数据,并通过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()

7

拦截!

噢,不!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()

8

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()

9

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想要发送的值,这 导致密钥出错。

10

如果Alice和Bob比较密钥的1比特,那么匹配的概率为 0.75 ,如果是这样,他们就不会注意到Eve的拦截。如果测量的是2比特,那么有 0.75^2=0.5625 的概率不会注意到Eve的拦截。我们可以看到,Eve未被检测到的概率可以通过Alice和Bob选择比较的比特数( x )来计算:

P(\text{undetected}) = 0.75^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