《量子计算实践—Java样例》第八章:使用量子计算进行安全通信

231 阅读19分钟

本章内容包括:

  • 解决安全通信的引导问题
  • 介绍量子密钥分发
  • 理解BB84算法
  • 在两方之间安全分发共享密钥

在本章中,您将创建一个有用的量子应用程序。我们将展示量子计算可以以非常安全的方式创建一个可以在两个方之间共享的秘密密钥。这种量子密钥分发(QKD)是许多加密技术的基础,被证明是安全的——即使最好的量子计算机也无法破解这种安全性!

引导问题(The bootstrap problem)

我们在第6章开始时展示了如何使用经典网络将经典信息从一个节点(或计算机)发送到另一个节点。我们解释了不同信息的传输过程,从Java应用程序传递到低级实现,然后以位的形式发送到另一个节点并再次传回。这在图8.1中显示出来。

image.png

在通过网络发送位的过程中存在一些问题

在本章中,我们关注两个节点之间通信层面的情况。位被通过网络连接传输,例如通过光纤。

这有多安全?在许多应用程序中,安全性和隐私保护变得越来越重要,对于许多应用程序而言,重要的是物理网络之间传输的位不会被第三方截获,也不能被第三方篡改。

理想的情况如图8.2所示:位从Alice发送到Bob,没有人监听或修改这些位。Alice可以向Bob发送一条消息,而Bob将收到这条消息。没有其他人收到或修改了这条消息。

image.png

读取消息 然而,在实际应用中,存在可能有人在网络中监听,如图8.3所示。这种情况可能发生在多种情形下。这个监听者,在示例中通常被称为“伊芙(Eve)”,可能会物理上切断网络电缆,监听传入的比特位,将其记录下来,然后将相同的比特位发送到电缆的另一端。不管伊芙使用何种技术,结果是她可以读取在Alice和Bob之间通信通道上发送的比特位。

image.png

由于比特位仍然到达Bob的端口,Alice和Bob都不知道伊芙一直在监听。Alice和Bob认为他们进行了安全的通信,但伊芙听到了他们交换的一切信息。

修改消息 另一个问题是伊芙可能会在网络线上更改位的值。例如,在图8.4中,伊芙将第三位从1更改为0。

image.png

这可能导致严重的问题。例如,假设爱丽丝向鲍勃发送以下消息:“你能给我转账500欧元到账户号码AL.1234吗?”伊芙拦截了这条消息并将其更改为:“你能给我转账500欧元到账户号码EV.1234吗?”鲍勃收到了这条消息,对伊芙的篡改一无所知,结果将钱转账到了伊芙的账户,而不是爱丽丝的账户。

在许多现实世界的情况下,完全保护低级通信提供的物理通道是不可能的。我们需要一些技术来在不安全的网络通道上构建安全的通信通道。

幸运的是,有几种经典技术可以提高通信的安全性和隐私性。我们不会涵盖所有这些技术,但我们会选择一种非常流行的技术:一次性密码本(one-time pad)。

一次性密码本挺身而出

每条消息、每个对象和每个在经典计算中使用的数据的状态都可以表示为一系列比特位。一次性密码本是一个比原始消息长度至少长的比特位序列。如果消息的发送者(Alice)和接收者(Bob)都拥有相同的一次性密码本,并且Eve无法访问它,那么就可以使用它来对消息进行安全加密,以便只有Alice和Bob能够解密。 "一次性"一词意味着密钥应该只使用一次。如果这样的话,可以证明使用一次性密码本加密的消息是以安全的方式传输的。让我们来看一个例子。

注意:以下示例使用非常短的比特位序列以保持简单。但是这些原则同样适用于非常长的序列。

假设Alice想要将以下消息(一个比特位序列)发送给Bob: 0110

在Alice和Bob开始通信之前,他们约定了一个秘密密钥(一次性密码本)。我们稍后讨论他们是如何创建这个密钥的,但现在假设这是他们的秘密密钥: 1100

只有Alice和Bob知道这个密钥。在Alice将消息发送给Bob之前,她将消息与秘密密钥结合起来——原始消息中的每个位都会被XOR操作替换,该操作应用于原始位和密钥中相应位:

  • 如果原始位和密钥中相应位相等(都为0或1),则结果位为0。
  • 如果原始位和密钥中相应位相反(0和1或1和0),则结果位为1。

这种组合的结果是一个加密的位序列:

0110 (original message)
1100 (one time pad)
---- (XOR operation)
1010 (result)

现在Alice将加密后的位序列1010发送给Bob,Bob需要解码这个序列。为了解码,Bob还需要对每个接收到的位与密钥中相应的位进行XOR操作:

1010 (encrypted message, received from Alice) 
1100 (one time pad)
---- (XOR) 
0110 (original message)

正如您所见,这个操作的结果是Alice发送的原始消息。可以证明这不是巧合,并且无论Alice发送什么消息,这种技术都会始终有效。下图显示了Alice和Bob之间的通信示意图(图8.5)。

image.png

如果Eve拦截了通过网络发送的消息会发生什么呢?她将读取到一个加密的消息(1010),而不是原始消息(0110)。由于她没有Alice和Bob使用的密钥,她无法解密这个消息。即使她知道Alice和Bob使用了一个秘密密钥,并通过位异或操作对消息进行了加密,没有秘密密钥本身,Eve也无法解密这个消息。

您刚刚了解到,如果Alice和Bob共享一个秘密密钥,一个与原始消息长度相同的位序列,他们的通信是无法被拦截的,或者说,它可以被拦截,但窃听者无法解密拦截的消息。

分享秘密密钥

问题在于如何让Alice和Bob共享一个秘密密钥。一种朴素的方法是通过网络发送密钥,但这又使我们陷入了困境:我们需要一个秘密密钥来以安全的方式发送我们的秘密密钥。这个递归问题在图8.6中被可视化出来。

image.png

对于真正关键的应用,秘密密钥通常不是通过互联网分享的,而是通过传统邮件或其他方式分享。在本章的剩余部分,您将学习量子计算如何解决这个引导问题。

量子密钥分发(Quantum Key Distribution,QKD)

在本节中,您将学习量子计算如何用于生成并在两个参与方,即Alice和Bob之间安全共享秘密密钥。一旦Alice和Bob拥有这样的密钥,他们就可以使用它来加密他们要发送给对方的消息。如果Alice和Bob能够以安全的方式共享一个秘密密钥,就可以解决前面一节中解释的启动问题。

使用量子技术生成和分发这样的秘密密钥称为量子密钥分发(Quantum Key Distribution,QKD),通常被视为量子计算的热门话题和主要优势之一。有几种算法可用于生成QKD。也许最著名的是BB84算法,它以其发明者Charles Bennett和Gilles Brassard的名字命名,他们在1984年创造了该算法。我们将最终创建这个算法;但我们不会从其背后的物理学出发,而是采用面向软件的方法来到达这个算法。

在接下来的部分中,我们假设我们可以以某种方式在网络上传输量子比特。在第6章中,我们讨论了量子纠缠,它允许我们将量子比特的状态通过经典网络连接发送,前提是在经典通信开始之前,两个参与方共享了一个纠缠的量子比特。在本章后面,我们将介绍一个模拟(并最终提供)真正的量子网络的项目。使用这个量子网络,我们可以将量子比特从一个节点(或计算机)发送到另一个节点。然而,在此之前,我们开发的算法将在单个节点上执行。请记住,您在单个节点上编写和执行的代码也可以在彼此相连的节点上执行。

天真的方法

在一种天真的方法中,Alice创建了一个包含值|0〉或|1〉的量子比特序列,并将其发送给Bob。然后,Bob测量这些量子比特,从而获得由Alice创建的原始位序列。由Alice创建的量子比特序列(可以使用随机位)是秘密密钥,在Bob测量这些量子比特后,他与Alice拥有相同的秘密密钥。然后,Alice和Bob可以将这个秘密密钥用作一次性密码本,如前面的部分所解释的。如图8.7所示,这在示意图中解释了。

image.png

使用你在前几章学到的技术,你可以创建一个能够实现这个功能的应用程序。下面的代码来自示例ch08/naive。

final int SIZE = 4;                               ❶
Random random = new Random();
 
boolean[] aliceBits = new boolean[SIZE];
for (int i = 0 ; i < SIZE; i++) {
    aliceBits[i] = random.nextBoolean();          ❷
}
 
QuantumExecutionEnvironment simulator =
        new SimpleQuantumExecutionEnvironment();
Program program = new Program(SIZE);              ❸
Step step1 = new Step();
Step step2 = new Step();
for (int i = 0; i < SIZE; i++) {
    if (bits[i]) step1.addGate(new X(i));         ❹
    step2.addGate(new Measurement(i));            ❺
}
 
program.addStep(step1);
program.addStep(step2);
 
Result result = simulator.runProgram(program);
Qubit[] qubit = result.getQubits();               ❻
 
int[] measurement = new int[SIZE];
boolean[] bobBits = new boolean[SIZE];
 
for (int i = 0; i < SIZE; i++) {
    measurement[i] = qubit[i].measure();          ❼
    bobBits[i] = measurement[i] == 1;
 
    System.err.println("Alice sent "+(bits[i] ? "1" : "0") +
            " and Bob received "+ bobBits[i] ? "1" : "0");
}
 
Renderer.renderProgram(program);                  ❽

❶ 这个示例创建了一个固定大小的密钥:4位。

❷ Alice通过为每个位分配随机值来生成密钥。

❸ 创建一个程序,为密钥中的每个位分配1个量子位。

❹ 当一个位是TRUE时,将对应的量子位应用Pauli-X门。

❺ 所有的量子位将在第2步进行测量。

❻ 执行程序,结果将保存在一个量子位数组中。

❼ 测量量子位并将其值与Alice使用的对应位的原始值打印出来。

❽ 渲染这个应用程序的量子电路。

这个程序只包含简单的量子操作。Alice首先生成秘密密钥,一个随机的经典位序列。然后,她基于这些位创建量子位。最初,一个量子位的值是|0〉。当需要创建一个对应于位1的量子位时,Alice对该量子位应用一个Pauli-X门。接下来,一个接一个地将量子位发送给Bob。Bob进行测量并逐位读取密钥。

你创建的代表算法的量子电路如图8.8所示。当你执行这个程序——例如,通过运行mvn javafx:run——你会在控制台上看到以下输出:

Alice sent 0 and Bob received 0
Alice sent 1 and Bob received 1
Alice sent 0 and Bob received 0
Alice sent 0 and Bob received 0

image.png

注意:每次运行此程序时,输出都是不同的,因为我们使用随机值来初始化Alice使用的位。

在上一节的结尾,我们解释了目前我们在单个节点上运行示例。这意味着Alice执行的部分和Bob执行的部分都在同一个节点上运行。请记住,算法中有一个隐含的点,我们假设量子位从Alice发送到Bob。如图8.9所示。

image.png

应用程序的输出显示,Alice可以创建一系列随机位,而Bob可以接收相同的随机位序列。您使用量子位将位传输到网络电缆上。

如果量子网络是可靠和安全的,这种方法应该是有效的。您之前了解到,量子位无法被复制,一旦量子位被测量,它就会回到其基本状态之一。在防止窃听的量子网络中,这种行为非常有用。

然而,目前的应用程序远非安全。假设Eve仍然位于中间,她正在测量Alice和Bob之间的所有量子位通信。我们知道,当Eve测量一个量子位时,它将具有值0或值1。如果它处于叠加状态,关于该叠加状态的信息将丢失。但在当前的算法中,没有量子位处于叠加状态。因此,Eve知道当她测量0时,原始量子位处于状态|0〉。然后,她可以在初始|0〉状态下创建一个新的量子位,并将其放回到通向Bob的电缆上。同样,当Eve测量一个量子位并获得值1时,她知道该量子位处于|1〉状态。她可以在|0〉状态下创建一个新的量子位,应用Pauli-X门将其带入|1〉状态,并将其发送给Bob。如图8.10所示。

image.png

您可以看到窃听部分发生在网络层。当Eve可以访问网络时,她可以获取Alice和Bob共享的(并不那么)秘密密钥。她测量与Alice用来生成量子位的相同值,而这些值就是秘密密钥。尤其危险的是,Alice和Bob并不知道发生了什么。Bob接收量子位,测量它们并构建秘密密钥。Bob和Alice成功交换了使用秘密密钥加密的消息,但是如果Eve截获了这条消息,她可以解密它。

使用叠加态

迄今为止,我们使用量子技术来生成仅由Alice和Bob共享的真正安全的秘密密钥并没有取得成功。但我们并没有真正充分利用量子比特与经典比特之间的差异。如果我们能保证量子比特处于|0〉状态或|1〉状态中,那么许多量子比特所提供的优势都将丧失。

在测量后,如果Eve知道原始量子比特处于|0〉或|1〉状态中,她可以轻松地重构原始量子比特(或至少创建一个与原始量子比特相同状态的新量子比特)。但如果量子比特处于叠加态,她将测量到|0〉或|1〉,而无法获取有关量子比特原始状态的任何信息。很快,您将通过使用叠加态来扩展最初的简单算法。Alice发送的量子比特将不再处于|0〉或|1〉状态,而是处于这些状态的叠加态。我们将解释Bob在收到来自Alice的量子比特后如何恢复原始量子比特的状态。

应用两个Hadamard门

在修改算法之前,我们需要解释一个有趣的关于Hadamard门的事实。可以证明,当一个Hadamard门作用在特定的量子比特上,并且另一个Hadamard门作用在第一个操作的结果上时,得到的量子比特将处于与它最初相同的状态。

让我们编写一些代码来验证这一点。 ch08 / haha中的代码实现了这一点,以下是相关的代码片段。

QuantumExecutionEnvironment simulator =
            new SimpleQuantumExecutionEnvironment();
 
        Program program = new Program(2);                   ❶
        Step step0 = new Step();
        step0.addGate(new X(0));                            ❷
 
        Step step1 = new Step();                            ❸
        step1.addGate(new Hadamard(0));
        step1.addGate(new Hadamard(1));
 
        Step step2 = new Step();                            ❹
        step2.addGate(new Hadamard(0));
        step2.addGate(new Hadamard(1));
 
        program.addStep(step0);                             ❺
        program.addStep(step1);
        program.addStep(step2);
 
        Result result = simulator.runProgram(program);      ❻
        Qubit[] qubit = result.getQubits();                 ❼
 
        Renderer.renderProgram(program);                    ❽

❶ 创建一个包含两个量子比特的程序

❷ 将第一个量子比特翻转为 |1〉,同时保持第二个量子比特为 |0〉

❸ 对两个量子比特应用Hadamard门

❹ 对两个量子比特再次应用Hadamard门

❺ 将所有步骤添加到程序中

❻ 执行程序

❼ 测量量子比特

❽ 图形化地呈现结果

这个应用程序的结果如图8.11所示。

image.png

这个图示表明,如果原始量子位于状态|0〉,在应用两个Hadamard门后,我们可以确定量子位将再次处于状态|0〉。同样地,如果原始量子位于状态|1〉,在应用两个Hadamard门后,量子位将再次处于状态|1〉。

注意:虽然我们只证明了这对于初始状态为|0〉或|1〉的量子位成立,但数学上可以证明对于任何状态的量子位同样适用。

从这段代码中,我们得出以下结论:如果Alice在将她的量子位发送给Bob之前应用一个Hadamard门,而Bob在对量子位进行测量之前再次应用一个Hadamard门,那么量子位将回到Alice事先准备的状态(即|0〉或|1〉)。

发送叠加态量子位

我们现在修改原始算法,利用这个叠加态的好处。Alice仍然用基于随机位的qubit创建一个密钥,但在她将qubit发送给Bob(在|0〉或|1〉状态下)之前,她会先应用一个Hadamard门。当Bob收到qubit时,他也会先应用一个Hadamard门,这应该将qubit带回到由Alice创建的原始状态。

image.png

示意图8.12显示了Alice和Bob都应用Hadamard门的情况。新的代码可以在ch08/superposition中找到,相关部分如下所示。

final int SIZE = 4;
Random random = new Random();
 
boolean[] aliceBits = new boolean[SIZE];
for (int i = 0 ; i < SIZE; i++) {
    aliceBits[i] = random.nextBoolean();                  ❶
}
 
QuantumExecutionEnvironment simulator =
         new SimpleQuantumExecutionEnvironment();
Program program = new Program(SIZE);
Step prepareStep = new Step();
Step superPositionStep = new Step();
Step superPositionStep2 = new Step();
Step measureStep = new Step();
for (int i = 0; i < SIZE; i++) {
    if (aliceBits[i]) prepareStep.addGate(new X(i));      ❷
    superPositionStep.addGate(new Hadamard(i));           ❸
    superPositionStep2.addGate(new Hadamard(i));          ❹
    measureStep.addGate(new Measurement(i));              ❺
}
 
program.addStep(prepareStep);                             ❻
program.addStep(superPositionStep);
program.addStep(superPositionStep2);
program.addStep(measureStep);
 
Result result = simulator.runProgram(program);            ❼
Qubit[] qubit = result.getQubits();
 
 
int[] measurement = new int[SIZE];
boolean[] bobBits = new boolean[SIZE];
for (int i = 0; i < SIZE; i++) {
    measurement[i] = qubit[i].measure();                  ❽
    bobBits[i] = measurement[i] == 1;
    System.err.println("Alice sent " +
          (aliceBits[i] ? "1" : "0") +
                " and Bob received " +
            (bobBits[i] ? "1" : "0"));
}

❶ Alice创建包含随机比特的密钥。

❷ 根据这些随机比特初始化她的量子比特。随机比特为0将导致一个|0〉比特;随机比特为1将导致一个|1〉比特。

❸ Alice执行Hadamard变换,将比特带入叠加态并通过网络发送。

❹ Bob接收比特并执行第二次Hadamard变换。

❺ Bob测量比特。

❻ 将这些步骤添加到量子程序中

❼ 执行程序

❽ Bob的比特被测量,并且打印Alice和Bob的比特。它们应该在位上是相等的。

当您执行此应用程序,例如使用 mvn javafx:run 命令,您将看到以下输出(再次注意,实际值可能因为我们基于随机值生成比特而不同):

Alice sent 0 and Bob received 0
Alice sent 1 and Bob received 1
Alice sent 0 and Bob received 0
Alice sent 0 and Bob received 0

该应用程序还显示了所创建的电路图(图 8.13)。

image.png

正如预期的那样,Bob测量的量子比特得到的值与在应用双Hadamard门之前由Alice用来准备量子比特的原始比特相同。因此,从功能角度来看,该算法仍然为Alice和Bob提供了相同的密钥。但这是否安全呢?

如果Eve仍然可以监听网络线路,她可以测量由Alice发送的量子比特。然而,无论Alice用来创建量子比特的原始比特是0还是1,Eve总是有50%的机会测量到0,有50%的机会测量到1。因此,她将无法重建传入的量子比特并发送给Bob,至少不是以前的方式。这在图8.14中显示。

image.png

正如您所看到的,Eve的情况将会非常糟糕。当她测量Alice的量子比特时,她随机地得到0或1的值。由Alice发送的量子比特要么处于|+〉状态,要么处于|–〉状态。这两种状态在测量时,都有50%的机会得到值0,有50%的机会得到值1。真正的信息在超position组合中某种程度上被隐藏起来。Eve不知道这一点,她读到的值可能是正确的,也可能是错误的。例如,在图8.14中的第一个量子比特,最初处于|0〉状态,被Eve测量为|0〉,所以她是正确的。然而,第二个量子比特,最初处于|1〉状态,被Eve测量为|0〉。因此,Eve将无法通过这种方法获得正确的共享密钥。

更糟糕的是,当Eve试图隐藏自己的痕迹时,她会根据自己的测量结果创建一个新的量子比特,并将其发送给Bob。在第一个量子比特的情况下,她足够幸运地测量到0,她构建一个新的|0〉量子比特并将其发送给Bob。Bob并没有意识到发生了什么,他假设Alice向他发送了一个处于叠加状态的量子比特,然后他应用了一个Hadamard门。这将会将Eve发送的量子比特带回到叠加状态。当Bob测量这个量子比特时,他可以测量到|0〉或|1〉。在图中,Bob测量到了一个1,这不是Alice发送的内容。

在典型的加密算法中,Alice和Bob使用部分传输的比特来检查是否一切正常。他们共享这些比特的值(这使得这些特定的比特不再安全)。如果这些比特的值不同,Alice和Bob就知道出了问题,整个密钥就不再被认为是安全的。因此,很明显,使用这种方法,Eve无法在不出现错误或被检测到的情况下获得密钥。

但是Eve可以学习。如果Eve知道Alice在将量子比特发送到线路之前应用了一个Hadamard门,Eve在测量之前可能也会应用一个Hadamard门-就像Bob正在做的那样。这将为她提供Bob本来会得到的信息:Alice用来准备量子比特的相同比特。

然而,这对Eve没有帮助,因为Bob不会收到量子比特。通过测量它们,Eve会破坏叠加态。然而,现在Eve知道Alice在做什么,她可以通过做与Alice相同的事情来创建新的量子比特。因此,Bob将会收到与从Alice那里接收到的相同状态的量子比特。他应用Hadamard门,然后测量量子比特,得到的将是Alice用来准备量子比特的相同比特。这在图8.15中以示意图形式展示。

image.png

因此,使用这种方法,不仅Alice和Bob分享了他们的密钥比特,Eve也分享了。因此,这种方法也不安全。

BB84

前面的方法失败了,因为Eve事先知道Alice做了什么,以及Bob打算做什么。在本节中,我们让Eve更难,或者说是不可能。

混淆Eve

Eve可以不被察觉的原因在于她成功地将一个量子比特以与从Alice拦截的相同状态发送给了Bob。如果Alice在将她的量子比特传输给Bob之前仅使用了Pauli-X门或根本没有操作,Eve可以测量该比特,从中获取原始信息。如果Alice还应用了Hadamard门,Eve在测量该比特之前需要自己应用Hadamard门。

但是,如果Eve不知道Alice是否使用了Hadamard门,她应该自己应用Hadamard门还是不应用呢?让我们来分析这种情况。我们有三个变量,每个变量都有两个选项,共有八种情况:

  1. Alice发送0或1。
  2. Alice应用Hadamard门或不应用。
  3. Eve应用Hadamard门或不应用。

在ch08/guess示例中,我们模拟了这八种不同情况的可能结果。以下是该算法的相关部分。

final int SIZE = 8;                                     ❶
 
...
 
for (int i = 0; i < SIZE; i++) {
    if (i > (SIZE/2-1)) {
        prepareStep.addGate(new X(i));                  ❷
    }
    if ((i/2) % 2 == 1) {
        superPositionStep.addGate(new Hadamard(i));     ❸
    }
    if (i%2 ==1) {
        superPositionStep2.addGate(new Hadamard(i));    ❹
    }
    measureStep.addGate(new Measurement(i));            ❺
}

❶ 考虑八种可能的情况(编号从0到7)。

❷ 在前四种情况下,Alice应用Pauli-X门。

❸ 在第2、3、6和7种情况下,Alice应用Hadamard门。

❹ 在第1、3、5和7种情况下,Eve应用Hadamard门。

❺ 进行测量。

for循环中的代码创建了八种情况。应用程序的视觉输出如图8.16所示,更加清晰明了。

image.png

前四个量子比特没有应用Pauli-X门,因此它们表示位值为0。让我们更详细地看一下这四种情况(见图8.17)。我们在这里进行的分析也适用于后四个量子比特,只是在这种情况下,初始值为1。

image.png

如果Alice和Eve都应用了Hadamard操作或都没有应用Hadamard操作,Eve将测量到0值。但是,如果其中一方应用了Hadamard操作而另一方没有,Eve测量到0的概率为50%,测量到1的概率也为50%。这些情况在图8.17中用圈圈标出。对于Eve来说,问题在于她无法确定她的测量结果是否正确。她不知道Alice是否应用了Hadamard门,因此无法确定应该采用哪种情况。更糟糕的是,她也无法创建与原始量子比特相同状态的量子比特。

例如,假设Eve将量子比特测量为0。从图8.16中可以看出,有六种可能的情况会导致测量结果为0。其中情况q[0]和q[3]将绝对导致测量结果为0,但是情况q[1]、q[2]、q[5]和q[6]的测量结果也有50%的可能性为0。在情况q[5]和q[6]中,原始位值为1;而在其他情况中,原始位值为0。由于Eve知道自己是否应用了Hadamard门,她可以排除一半的情况,但始终存在原始位值为0和原始位值为1的可能性。由于Eve不知道原始情况,她只能猜测并准备一个符合有效情况的量子比特,但很有可能是错误的情况,Bob将会收到一个与Alice发送的量子比特不同状态的量子比特。我们很快将看到如何检测到这一点。

Bob也感到困惑

如果Eve无法重建原始场景,那么Bob也是如此。我们假设Alice和Bob都没有事先的了解——否则,我们早就解决了引导问题。

在我们的算法中,我们将指示Bob在测量传入的量子比特之前随机选择是否应用Hadamard门。对于Bob来说,情况与Eve非常相似。如果Alice和Bob都应用Hadamard门,或者两者都不应用Hadamard门,Bob的测量结果保证与Alice的初始值相对应。从图8.16和8.17中,我们可以看出如果我们假设Bob执行第二部分而不是Eve的话,这一点是成立的。但是,如果Alice应用Hadamard变换而Bob没有,或者Alice没有应用Hadamard变换而Bob却应用了,结果可能是错误的。

看起来,通过使Eve的情况复杂化,我们同样使Bob的情况变得复杂了。Alice和Bob都随机决定是否应用Hadamard门。但从前面应用的输出中可以清楚地看出,如果Alice和Bob都决定应用Hadamard门,或者都决定不使用Hadamard门,他们可以共享一个密钥。在这种情况下,Alice使用的初始值保证与Bob测量的相同值相对应。

Alice和Bob正在交谈

从前面的讨论中,我们可以看出,如果Alice和Bob都使用Hadamard门,或者他们都不使用Hadamard门,那么Alice使用的初始位和Bob测得的位是确保相同并可用于秘密密钥的。但是,他们怎么知道呢?答案很简单:他们彼此告知是否应用了Hadamard门。

注意:这可能听起来令人惊讶。如果Alice和Bob通过公共通道告诉对方是否应用了Hadamard门,那么Eve可能会监听!诀窍在于:Alice和Bob仅在Bob收到并测量其量子比特后才彼此分享这些信息。此时,Eve无法再做任何事情。如果Eve事先知道这些信息,她可能会操纵系统,因为她可以轻松地从Alice那里复制量子比特,如果她知道Alice是否应用了Hadamard门。但是她必须在将量子比特发送给Bob之前做出决定,而这个决定是基于她从Alice那里拦截的量子比特的测量结果。因此,该量子比特中的所有信息都被破坏。这对于Eve来说是可惜的,但是公共信息是无用的。

当Alice和Bob彼此了解了关于Hadamard门的信息后,他们只需移除具有不匹配Hadamard门的量子比特上测得的值。剩下的值保证是正确的。

注意:Alice和Bob仅分享有关Hadamard门的信息。他们不分享初始值(在Alice的情况下)或测得值(在Bob的情况下)。但是,他们知道这些值是相等的,并且可以将它们用作共享秘密密钥的一部分。

通常,Alice和Bob使用他们的一部分秘密密钥来检查连接是否被窃听,例如通过保留一些空间来添加校验和。如果Eve对于无法在不被察觉的情况下获得原始密钥并不气馁,她可能仍然会尝试获取密钥,但是她将不得不猜测是否应用Hadamard门。如果她猜错了,她将向Bob发送一个处于与Alice发送给Bob的量子比特不同状态的量子比特。因此,Bob测得的值可能与Alice使用的值不同。如果Alice和Bob都应用或都不应用Hadamard门,并且Alice的初始值与Bob测得的值不同,Alice和Bob就知道连接受到了干扰。

Java实现QKD

前面几节中获取的综合知识使您能够在Java中创建一个量子密钥分发(QKD)应用程序。在示例ch08/bb84中,正是这样实现的。

代码

我们不会在此处包含所有示例代码,但我们将突出一些重要的片段。

初始化变量 首先,我们初始化一些数组:

final int SIZE = 8;                         ❶
Random random = new Random();               ❷
 
boolean[] aliceBits = new boolean[SIZE];    ❸
 
boolean[] bobBits = new boolean[SIZE];      ❹
 
boolean[] aliceBase = new boolean[SIZE];    ❺
 
boolean[] bobBase = new boolean[SIZE];      ❻

❶ 创建一个最多包含8位的密钥。请记住,我们必须移除那些Alice和Bob使用了不同策略(Hadamard或非Hadamard)的位,因此实际上,密钥的真实长度平均只有指定大小的一半。

❷ 创建java.util.Random的实例,稍后将用于生成随机的布尔值。

❸ 在这个数组中,Alice保存她生成的随机位,并且这些位是用于确定她使用的基础的:如果这些随机位的特定位是1,她将对具有相同索引的量子比特应用Hadamard门。

❹ 在这个数组中,Bob存储他测量到的位。

❺ 当Alice决定对特定量子比特应用Hadamard门时,对应的值在这个数组中被设置为true。

❻ 当Bob决定对特定量子比特应用Hadamard门时,对应的值在这个数组中被设置为true。

准备步骤

我们创建的量子应用包含不同的步骤。前两步由Alice执行,第三步和第四步由Bob执行:

Step prepareStep = new Step();           ❶
Step superPositionStep = new Step();     ❷
Step superPositionStep2 = new Step();    ❸
Step measureStep = new Step();           ❹

❶ Alice在考虑的随机位是1的情况下应用Pauli-X门。

❷ Alice应用Hadamard门(或不应用)。

❸ Bob应用Hadamard门(或不应用)。

❹ Bob进行测量。

填充这些步骤 所有的步骤都是为可能构成密钥的每个比特创建的。其中三个步骤依赖于随机值。

基于第一个随机值,在"prepareStep"中应用了一个Pauli-X门。有50%的概率应用Pauli-X门,使得量子比特处于|1〉状态,另外50%的概率不应用门,使得量子比特保持在|0〉状态。

第二个随机值决定了是否在由Alice执行的"superPositionStep"中应用Hadamard门。接下来的步骤"superPositionStep2"使用一个随机值来决定Bob是否应用Hadamard门:

for (int i = 0; i < SIZE; i++) {                   ❶
 
       aliceBits[i] = random.nextBoolean();        ❷
       if (aliceBits[i]) {
           prepareStep.addGate(new X(i));          ❸
       }
 
       aliceBase[i] = random.nextBoolean();        ❹
       if (aliceBase[i]) {
           superPositionStep.addGate(new Hadamard(i));
       }
 
       bobBase[i] = random.nextBoolean();          ❺
       if (bobBase[i]) {
           superPositionStep2.addGate(new Hadamard(i));
       }
 
       // Finally, Bob measures the result
       measureStep.addGate(new Measurement(i));    ❻
 }

❶ 对于每个可能用于构建秘密密钥的比特,执行以下步骤。

❷ 一个随机值决定Alice的比特是0还是1。

❸ 如果Alice的比特是1,则对|0〉状态应用X门。

❹ 一个随机值(存储在aliceBase数组中)决定是否应用Hadamard门。

❺ 一个随机值(存储在bobBase数组中)决定是否应用Hadamard门。

❻ Bob测量量子比特。

执行应用程序 现在我们需要在我们的量子模拟器中执行这个应用程序。这可以通过使用你在前面章节中学到的技术来实现:

QuantumExecutionEnvironment simulator =
           new SimpleQuantumExecutionEnvironment();    ❶
    program.addStep(prepareStep);                      ❷
    program.addStep(superPositionStep);
    program.addStep(superPositionStep2);
    program.addStep(measureStep);
 
    Result result = simulator.runProgram(program);     ❸
    Qubit[] qubit = result.getQubits();                ❹

❶ 创建一个量子执行环境(QuantumExecutionEnvironment)

❷ 添加之前阶段创建的步骤(steps)

❸ 在模拟器上运行量子程序

❹ 将结果分配给一个量子比特(qubit)数组

处理结果 现在程序已经执行并获得了结果,我们可以处理这些结果。在这个阶段,我们决定哪些特定的位应该成为密钥的一部分,既适用于Alice,也适用于Bob:

int[] measurement = new int[SIZE];
    for (int i = 0; i < SIZE; i++) {                    ❶
        measurement[i] = qubit[i].measure();
        bobBits[i] = measurement[i] == 1;               ❷
        if (aliceBase[i] != bobBase[i]) {               ❸
            System.err.println("Different bases used,
              ignore values "+aliceBits[i]+
              " and "+ bobBits[i]);
        } else {                                        ❹
            System.err.println("Same bases used.
              Alice sent " + (aliceBits[i] ? "1" : "0")
              + " and Bob received "
              + (bobBits[i] ? "1" : "0"));
            key.append(aliceBits[i] ? "1" : "0");       ❺
        }
    }

❶ 对于每个候选位,我们运行以下步骤来评估是否应该将该位作为密钥的一部分。

❷ 将bobBits数组中的位设置为量子比特的测量值。

❸ 如果Alice和Bob为此位选择的随机基不同,忽略这些值并打印一条消息。

❹ 否则,Alice和Bob使用了相同的Hadamard策略。 Alice的初始值与Bob的测量值相匹配。

❺ 现在,这个位成为密钥的一部分。

运行应用程序

你可以在ch08/bb84目录下使用命令mvn clean javafx:run来运行该应用程序。每次运行该应用程序的结果都会有所不同;下面的输出只是众多可能性中的一个示例(见图8.18):

Same bases used. Alice sent 1 and Bob received 1
Same bases used. Alice sent 0 and Bob received 0
Same bases used. Alice sent 1 and Bob received 1
Different bases used, ignore values false and true
Same bases used. Alice sent 1 and Bob received 1
Different bases used, ignore values false and true
Same bases used. Alice sent 1 and Bob received 1
Different bases used, ignore values true and true
Secret key = 10111

image.png

从文本输出和图形输出中可以明确看出,Alice和Bob在位0、1、2、4和6上采用了相同的Hadamard策略。这五位因此成为秘密密钥的一部分。其他位是无用的,因为Alice和Bob采用了不同的Hadamard策略(要么Alice应用了Hadamard门,Bob没有,要么反过来)。

总结

  • 安全通信是当今IT领域的重要方面,黑客渴望截取消息和安全密钥。
  • 使用一次性密码本,可以使用不再重复使用的密钥加密消息。每个消息都使用一个新的密钥,使得黑客更难截取。
  • BB84算法是一个著名的量子算法,它生成一次性密码本。
  • 使用Strange,您可以在Java中实现BB84算法。