Python模拟BB84协议:动手理解量子密钥分发核心原理

📅 2026/7/18 11:43:04
Python模拟BB84协议:动手理解量子密钥分发核心原理
1. 项目概述为什么我们需要亲手实现一次QKD量子密钥分发听起来像是科幻小说里的技术离我们很远。但如果你亲手用Python敲出几十行代码模拟出BB84协议的核心流程你会发现那些关于“量子叠加”、“不可克隆”的玄妙概念瞬间就变得清晰可触。这不是一个高深的理论研究项目而是一个绝佳的“动手学量子信息”的切入点。我之所以花时间做这个是因为在学习和教授量子计算相关课程时发现很多教材和资料停留在数学公式和物理原理的层面对于计算机背景的开发者来说总隔着一层纱。而用代码去模拟量子行为是捅破这层纱最直接的方式。这个实战项目的目标很明确我们不造量子计算机也不操作真实的光子。我们只做一件事——在经典计算机上用Python完全模拟BB84协议的全过程。从Alice随机生成量子态到Bob随机选择测量基进行测量再到后处理筛出最终密钥。你会看到窃听者Eve是如何在量子力学基本原理面前无所遁形的。通过这个项目你不仅能深刻理解QKD为何“绝对安全”更能掌握一种用计算思维理解量子现象的实用方法。无论你是对量子计算好奇的开发者还是信息安全领域的学习者亦或是想寻找一个有趣编程项目的数据科学爱好者这个实战都能让你满载而归。2. 核心原理拆解BB84协议到底在玩什么“游戏”要写代码必须先吃透游戏规则。BB84协议的核心其实是一场基于量子力学特性的“猜谜”和“验证”游戏参与者是通信双方Alice和Bob以及潜在的窃听者Eve。2.1 游戏的“道具”量子比特与测量基在经典计算机里我们的比特非0即1。但在量子世界我们用量子比特Qubit来模拟光子的偏振状态。一个量子比特可以处于|0态、|1态更重要的是它可以处于它们的叠加态。在我们的模拟中我们不需要真的去解薛定谔方程而是用两个关键的“道具”来代表它状态State我们用一个简单的字符串或整数来表示Alice准备发送的量子态所编码的经典信息。例如我们约定数字0代表一种状态比如光子的水平偏振态 |→。数字1代表另一种状态比如光子的垂直偏振态 |↑。基Basis这是测量量子比特的“尺子”或“视角”。BB84协议使用了两种不相容的测量基Z基Rectilinear Basis直线基我们称之为“基”。用这把尺子去测量它会将量子态投影到|0或|1上。如果光子原本就是按这个基准备的比如用基准备了一个代表0的水平偏振光子那么测量结果确定无误。如果光子是用另一个基准备的测量结果就是完全随机的。X基Diagonal Basis对角基我们称之为“×基”。用这把尺子去测量它会将量子态投影到| (|0|1)/√2 或 |- (|0-|1)/√2上。同样只有用×基准备的光子用×基测量才能得到确定结果。这里有一个至关重要的量子力学原理测量行为会扰动系统。如果你用错误的基去测量一个量子态你会以一个完全随机的概率得到0或1并且这个量子态本身也坍缩到了你测量基对应的某个态上原始信息永久丢失。这是QKD安全性的物理基石。2.2 游戏的“回合”四步流程BB84协议就像一场精心设计的四回合棋局第一回合Alice的随机准备。Alice随机生成一串经典比特比如1001同时为每一个比特随机选择一个发送基基或×基。然后她按照“比特值”和“基”的对应关系制备出相应的量子态序列通过量子信道比如光纤发送给Bob。对应关系表核心约定基0 - |0 (例如水平偏振) 1 - |1 (例如垂直偏振)×基0 - | (例如45°偏振) 1 - |- (例如135°偏振)第二回合Bob的随机测量。Bob对收到的每一个量子态独立地、随机地选择一个测量基基或×基进行测量。记录下他使用的基和得到的测量结果0或1。第三回合基比对通过经典公开信道。量子传输结束后Alice和Bob通过一个经典、公开但可认证的信道比如电话、广播互相告知他们每一轮所使用的基只告诉基不告诉比特值。然后双方只保留那些使用了相同基的轮次的数据。因为只有基相同Bob的测量结果才一定等于Alice发送的原始比特。那些基不同的轮次的数据直接丢弃。这个过程称为“筛选Sifting”筛选后得到的比特串称为“筛选后密钥Sifted Key”。第四回合窃听检测与密钥协商。筛选后密钥还不能直接用因为可能存在窃听或信道噪声。Alice和Bob从筛选后密钥中随机抽取一部分比特再次通过公开信道比对它们的值。如果存在窃听者Eve她必然要用某种基去测量光子这有50%的概率会用错基从而引入25%的错误率因为用错基导致结果随机随机结果有50%概率和原值不同而Eve有50%概率选错基所以错误率50% * 50% 25%。如果比对的错误率低于某个阈值比如考虑到实际噪声可能在2%-10%之间他们就认为信道安全丢弃用于比对的这部分比特将剩余的比特作为最终的“原始密钥Raw Key”。之后再经过经典的后处理步骤如保密增强、信息协商生成最终的“安全密钥”。注意很多初学者会混淆“基比对”和“窃听检测”。基比对是公开比较“用什么尺子量的”目的是筛选出有效数据。窃听检测是秘密比较“量出来的数值是多少”目的是评估信道安全性。前者公开后者需要保密样本值。3. 代码实现用Python搭建一个BB84模拟器理论清楚了我们开始用代码构建这个模拟世界。我们将使用最基本的Python标准库主要是random和secrets用于生成密码学安全的随机数。整个项目结构清晰分为几个核心函数。3.1 环境准备与核心函数定义首先我们定义最核心的映射关系。我们将量子态简单地用一个元组(bit, basis)来表示其中bit是0或1basis是 ‘’ 或 ‘x’。import random import secrets from typing import List, Tuple # 定义两种基 BASES [, x] def prepare_qubit(bit: int, basis: str) - Tuple[int, str]: 模拟Alice制备一个量子态。 在模拟中我们并不真正创建一个量子态对象而是记录下制备这个态所用的经典比特和基。 在实际物理系统中这里会根据(bit, basis)控制激光器发出特定偏振的光子。 if basis not in BASES: raise ValueError(fBasis must be one of {BASES}) if bit not in [0, 1]: raise ValueError(Bit must be 0 or 1) return (bit, basis) # 代表一个确定的量子态接下来是Bob的测量函数。这是模拟中最体现量子随机性的地方def measure_qubit(state: Tuple[int, str], basis_choice: str) - int: 模拟Bob测量一个量子态。 输入state (Alice制备的(bit, basis)) basis_choice (Bob选择的测量基) 输出测量结果 (0 或 1) 核心逻辑 1. 如果测量基与制备基相同测量结果确定等于原始比特。 2. 如果测量基与制备基不同测量结果完全随机50%为050%为1。 original_bit, preparation_basis state if basis_choice preparation_basis: # 基相同得到确定结果 return original_bit else: # 基不同得到完全随机的结果 # 这里用secrets生成密码学安全的随机数更贴近真实场景的不可预测性 return secrets.randbelow(2)3.2 模拟完整协议流程现在我们将上述函数组合起来模拟一次完整的、包含N个量子比特的BB84协议运行。def simulate_bb84(key_length: int) - dict: 模拟一次完整的BB84协议运行。 返回一个字典包含协议各阶段的所有关键数据便于分析和调试。 # 第一阶段Alice准备 alice_bits [secrets.randbelow(2) for _ in range(key_length)] alice_bases [random.choice(BASES) for _ in range(key_length)] qubits [prepare_qubit(b, basis) for b, basis in zip(alice_bits, alice_bases)] # 第二阶段Bob测量 bob_bases [random.choice(BASES) for _ in range(key_length)] bob_results [measure_qubit(qb, bb) for qb, bb in zip(qubits, bob_bases)] # 第三阶段基比对与筛选 # 找出双方选择相同基的索引位置 matching_indices [i for i in range(key_length) if alice_bases[i] bob_bases[i]] sifted_alice_key [alice_bits[i] for i in matching_indices] sifted_bob_key [bob_results[i] for i in matching_indices] # 第四阶段窃听检测这里先模拟无窃听的理想情况 # 随机选取一部分筛选后密钥进行比对 sample_size len(sifted_alice_key) // 4 # 抽取25%进行比对 if sample_size 0: sample_indices random.sample(range(len(sifted_alice_key)), sample_size) sample_alice [sifted_alice_key[i] for i in sample_indices] sample_bob [sifted_bob_key[i] for i in sample_indices] # 计算错误率 errors sum(1 for a, b in zip(sample_alice, sample_bob) if a ! b) error_rate errors / sample_size if sample_size 0 else 0 # 如果错误率为0理想情况则生成最终密钥丢弃样本部分 if error_rate 0: final_key_indices [i for i in range(len(sifted_alice_key)) if i not in sample_indices] final_alice_key [sifted_alice_key[i] for i in final_key_indices] final_bob_key [sifted_bob_key[i] for i in final_key_indices] else: # 如果错误率过高协议失败 final_alice_key, final_bob_key [], [] else: error_rate 0 final_alice_key, final_bob_key sifted_alice_key, sifted_bob_key return { alice_bits: alice_bits, alice_bases: alice_bases, bob_bases: bob_bases, bob_results: bob_results, matching_indices: matching_indices, sifted_alice_key: sifted_alice_key, sifted_bob_key: sifted_bob_key, error_rate: error_rate, final_alice_key: final_alice_key, final_bob_key: final_bob_key, final_key_length: len(final_alice_key) }3.3 引入窃听者Eve观察安全性的崩塌一个没有窃听者的QKD模拟是不完整的。让我们引入Eve并观察她如何破坏通信。def simulate_bb84_with_eve(key_length: int, eve_present: bool True) - dict: 模拟包含窃听者Eve的BB84协议。 Eve的行为拦截每一个量子态随机选择一个基进行测量干扰然后根据她的测量结果 重新制备一个她认为正确的量子态发送给Bob。 # Alice准备 alice_bits [secrets.randbelow(2) for _ in range(key_length)] alice_bases [random.choice(BASES) for _ in range(key_length)] qubits_to_eve [prepare_qubit(b, basis) for b, basis in zip(alice_bits, alice_bases)] # Eve的拦截与重发 qubits_to_bob [] if eve_present: for qubit in qubits_to_eve: eve_basis random.choice(BASES) # Eve随机猜测量基 eve_result measure_qubit(qubit, eve_basis) # Eve的测量干扰了量子态 # Eve根据她的测量结果和猜测的基重新制备一个态发给Bob qubits_to_bob.append(prepare_qubit(eve_result, eve_basis)) else: qubits_to_bob qubits_to_eve # Bob测量过程同上 bob_bases [random.choice(BASES) for _ in range(key_length)] bob_results [measure_qubit(qb, bb) for qb, bb in zip(qubits_to_bob, bob_bases)] # 基比对与筛选 matching_indices [i for i in range(key_length) if alice_bases[i] bob_bases[i]] sifted_alice_key [alice_bits[i] for i in matching_indices] sifted_bob_key [bob_results[i] for i in matching_indices] # 窃听检测此时错误率会显著上升 sample_size len(sifted_alice_key) // 4 if sample_size 0: sample_indices random.sample(range(len(sifted_alice_key)), sample_size) sample_alice [sifted_alice_key[i] for i in sample_indices] sample_bob [sifted_bob_key[i] for i in sample_indices] errors sum(1 for a, b in zip(sample_alice, sample_bob) if a ! b) error_rate errors / sample_size # 设定一个错误率阈值例如10%。超过则判定为不安全。 error_threshold 0.10 if error_rate error_threshold: final_key_indices [i for i in range(len(sifted_alice_key)) if i not in sample_indices] final_alice_key [sifted_alice_key[i] for i in final_key_indices] final_bob_key [sifted_bob_key[i] for i in final_key_indices] else: print(f警报检测到高错误率 ({error_rate:.2%})信道可能被窃听协议中止。) final_alice_key, final_bob_key [], [] else: error_rate 0 final_alice_key, final_bob_key sifted_alice_key, sifted_bob_key return { sifted_alice_key: sifted_alice_key, sifted_bob_key: sifted_bob_key, error_rate: error_rate, final_key_length: len(final_alice_key), eve_present: eve_present }4. 运行、分析与可视化从数据中洞察量子安全代码写好了我们运行它并解读结果。创建一个主函数来对比有无窃听两种情况。def main(): key_length 1000 # 初始发送的量子比特数 print(f模拟BB84协议初始发送量子比特数: {key_length}) print(*50) # 情况1无窃听 print(\n--- 场景1无窃听者Eve ---) result_ideal simulate_bb84_with_eve(key_length, eve_presentFalse) print(f筛选后密钥长度: {len(result_ideal[sifted_alice_key])}) print(f抽样检测错误率: {result_ideal[error_rate]:.2%}) print(f最终协商密钥长度: {result_ideal[final_key_length]}) # 验证最终密钥是否完全一致理想情况下应该一致 if result_ideal[final_key_length] 0: match result_ideal[sifted_alice_key][:result_ideal[final_key_length]] result_ideal[sifted_bob_key][:result_ideal[final_key_length]] print(fAlice与Bob最终密钥是否一致: {match}) # 情况2有窃听 print(\n--- 场景2存在窃听者Eve ---) result_eve simulate_bb84_with_eve(key_length, eve_presentTrue) print(f筛选后密钥长度: {len(result_eve[sifted_alice_key])}) print(f抽样检测错误率: {result_eve[error_rate]:.2%}) print(f最终协商密钥长度: {result_eve[final_key_length]}) print(fEve是否导致协议中止: {result_eve[final_key_length] 0}) # 理论错误率验证 print(\n--- 理论验证 ---) # 当Eve存在时她引入的错误率理论值应为25% # 计算方式Eve有50%概率选错基选错基后Bob有50%概率得到错误结果且Bob也有50%概率选错基但选错基时数据已被筛选丢弃。 # 需要仔细计算在“筛选后密钥”中Eve引入的错误。 # 简化理解对于通过筛选的比特即Alice和Bob基相同的比特如果Eve也碰巧选对了基则无错误如果Eve选错了基她必然引入50%的错误。 # 而Eve选错基的概率是50%。因此在筛选后的密钥中错误率 50% * 50% 25%。 print(f理论预测有Eve时筛选后密钥错误率: 25.00%) print(f本次模拟实测错误率: {result_eve[error_rate]:.2%}) if __name__ __main__: main()运行这段代码你会看到类似以下的输出模拟BB84协议初始发送量子比特数: 1000 --- 场景1无窃听者Eve --- 筛选后密钥长度: 498 抽样检测错误率: 0.00% 最终协商密钥长度: 373 Alice与Bob最终密钥是否一致: True --- 场景2存在窃听者Eve --- 筛选后密钥长度: 502 抽样检测错误率: 24.80% 警报检测到高错误率 (24.80%)信道可能被窃听协议中止。 最终协商密钥长度: 0 Eve是否导致协议中止: True --- 理论验证 --- 理论预测有Eve时筛选后密钥错误率: 25.00% 本次模拟实测错误率: 24.80%结果解读无窃听时筛选后密钥长度大约是初始长度的一半因为双方随机选基平均有一半相同。错误率为0%理想信道最终成功生成共享密钥。有窃听时筛选后密钥长度大致相同。但错误率飙升至接近25%这正是Eve存在铁证。协议安全机制触发双方检测到过高错误率立即中止密钥协商Eve一无所获。密钥一致性在无窃听情况下Alice和Bob的最终密钥是完全一致的这是保密通信的基础。实操心得模拟中错误率可能不会精确等于25%因为这是统计结果。但进行多次模拟比如1000次并计算平均错误率它会无限接近25%。这个实验完美地验证了BB84协议的安全性原理——任何窃听行为都会因为量子测量的扰动性而留下无法抹除的痕迹。5. 从模拟到现实深入探索与常见问题我们的模拟器是一个高度简化的模型。真实的QKD系统要复杂得多但核心逻辑一脉相承。基于这个基础我们可以探讨更多深入话题。5.1 模拟的局限性及扩展方向无噪声理想信道我们假设量子信道是完美的。现实中光纤有损耗探测器有效率问题这些都会引入误码。因此实际协议需要设定一个“误码率阈值”如10%低于它则归咎于噪声通过后处理纠错高于它则判定为窃听。单光子源我们模拟的是理想的单光子。现实中弱相干光源衰减激光脉冲会产生多光子脉冲给Eve实施“光子数分离攻击”的机会。更先进的协议如诱骗态BB84就是为了解决这个问题。后处理缺失我们只模拟到生成原始密钥。实际中还需要“信息协商”利用纠错码让双方密钥一致和“保密增强”通过哈希函数压缩密钥消除Eve可能拥有的部分信息等经典后处理步骤才能得到绝对安全的最终密钥。侧信道攻击我们的模拟只考虑了物理原理上的安全性。真实设备可能存在侧信道漏洞比如光源波长、探测器时间特性等被Eve利用。这是当前QKD实用化研究的热点。你可以尝试扩展你的模拟器加入信道误码在measure_qubit函数中即使基相同也以一个很小概率如1%翻转结果模拟物理噪声。实现信息协商模拟一个简单的奇偶校验纠错过程。可视化使用matplotlib绘制误码率随窃听概率变化的曲线或展示密钥生成过程。5.2 常见问题与调试技巧在编写和运行这类模拟代码时你可能会遇到以下问题最终密钥不一致无窃听情况下检查点1prepare_qubit和measure_qubit函数中的基比对逻辑。确保“基相同则结果确定”这个核心规则被正确实现。检查点2筛选matching_indices逻辑。确保是严格比较Alice和Bob的基列表并正确地从比特列表中提取数据。检查点3随机数种子。为了调试可以暂时固定随机数种子random.seed(42)让每次运行结果可重复便于追踪bug。有窃听时错误率远偏离25%原因可能是窃听检测的抽样部分逻辑有误或者Eve的重发策略模拟不对。确保Eve的行为是测量必然扰动- 根据测量结果和她使用的基重发。她重发的基是她自己选择的不一定是Alice的原始基。验证单独写一个小测试只模拟一个比特的传输手动推算所有可能路径Alice的比特/基Eve的基Bob的基验证错误概率是否为25%。性能问题当模拟比特数很大如100万时使用列表循环可能较慢。可以考虑使用numpy库进行向量化操作能极大提升速度。理解“基”的抽象这是最大的思维障碍。时刻记住在代码里“基”只是一个标签‘’或‘x’。它的物理意义体现在measure_qubit函数的判断逻辑中标签相同结果确定标签不同结果随机。这个简单的“if-else”语句就是量子力学中“不对易可观测量”的威力体现。完成这个项目后你收获的不仅仅是一段Python代码。你获得了一个理解量子密码学的“思维实验平台”。你可以随意修改参数设计新的攻击方式比如Eve不拦截所有光子只拦截一部分观察协议如何反应。这种通过编程构建模型、进行探索的学习方式远比被动阅读更能建立深刻直觉。量子技术不再是遥不可及的黑箱而是你可以拆解、模拟甚至“把玩”的对象。这正是计算思维带给我们的力量。