news 2026/10/6 14:12:11

Python模拟量子密钥分发:重演墨子号BB84协议与窃听检测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python模拟量子密钥分发:重演墨子号BB84协议与窃听检测

1. 先搞清楚:我们到底在模拟什么

很多朋友一看到“量子加密通信”这六个字,第一反应就是“这东西离我太远了”。实话说,一开始我也是这么想的。但后来仔细看了一遍墨子号的公开资料,又自己动手用Python折腾了一套模拟流程,才发现这玩意儿其实没有想象中那么神秘,而且用代码去“重演”一遍跨国宣传里反复出现的量子密钥分发、窃听检测这些概念,反而比单纯看纪录片理解得透彻得多。

先说个前提:Python本身当然不可能跑出一个真正的光子出来,更不可能把量子态发射到卫星上。我们能做的,是用经典计算机去模拟“量子世界里才会发生的一些规则”。这些规则包括叠加态、测量坍缩、不可克隆,以及最关键的一点——任何偷看行为都会留下痕迹。把这四条规则写进代码里,就相当于在本地搭了一个“缩微版”的量子信道,然后在这个信道上让 Alice 和 Bob 两个人完成一次完整的密钥协商,再让 Eve(被动窃听者)尝试偷偷介入,最后通过错误率判断有没有被监听。整个过程跑完,你会非常直观地感受到一件事:量子加密之所以安全,并不是因为密钥有多长,而是因为它从根本上改变了“偷听”这个词的含义。

我知道有些朋友会问:既然叫“量子加密通信”,为什么模拟出来的核心是一场“密钥协商”,而不是直接把密文传过去?这里涉及一个很常见的误解。量子加密指的是用量子信道来共享并校验密钥,而不是用量子比特直接替代明文进行传输——至少在目前的工程体系里不是这么干的。机密内容仍然走传统网络,只是用来加密它的那把钥匙,是通过量子信道产生的。这样设计的好处是两全:量子信道的绝对隐私性保证了密钥不会泄露,传统网络的高速带宽保证了大规模数据的传输效率。所以,你理解这套模拟的第一步,就是先接受“我们只搞密钥,不搞正文”这个设定。

这个项目适合谁?我觉得三类人特别适合。第一类是学过一点点量子力学但从来没编程上手过的人,你会发现原来教科书上那堆抽象符号可以变成一行行能跑出结果的代码。第二类是熟悉Python但对量子通信只知道概念的人,这篇文章能帮你把“BB84协议”“窃听检测”这些术语落到实际函数里去。第三类是纯粹的吃瓜群众,你不需要懂量子场论,只要会最基础的Python语法,跟着把流程走一遍,你对墨子号到底做了什么,会有一种“原来如此”的踏实感。

我自己的感受是,这类模拟最大的价值并不是“跑出了一个正确的结果”,而是在调试过程中,你被迫去理解“为什么测量会改变状态”“为什么窃听必然导致错误率上升”这些底层逻辑。纸上读十遍,不如下手跑一遍。

2. 方案设计:用一个可见流程还原不可见过程

2.1 从墨子号身上提取核心流程

墨子号通信系统的核心是什么?简单说,就是星地之间进行量子密钥分发(QKD,Quantum Key Distribution)。地面站产生一个个单光子,把每光子的量子态“编码”好,发给天上的墨子号,墨子号对每个光子做一次随机基测量,然后双方通过公开信道互通“我用了什么基”,把基一致的事件留下来,作为生密钥的原料。这一套流程是公开的,涉及专家的论文和各类科普视频都在讲,但把它们的表述翻译成程序语言时,我做了三个关键抽象。

第一个抽象是“单光子序列”。现实里光子是一个一个发射、一个一个接收的,每个光子携带独立的量子态。在Python里我可以让Alice生成一个长度为 N 的偏振态序列,序列里的每个元素取值为0(水平偏振)或1(垂直偏振),这相当于准备了一串“真实的待发比特”。第二个抽象是“测量基”。现实里Bob需要随机选择光电探测器的工作模式,在Python里我让他随机选一个“基”来解读收到的信号。这里需要特别提醒:基的选择必须真随机,不能是提前算好的序列,否则窃听者可以通过统计规律猜出你的测量方式。第三个抽象是“拥有一条天然安全的公开信道”。这句话可能听着矛盾——公开信道还能安全?别误会,这里的“安全”指的是:它可以被窃听,但窃听行为很容易被双方察觉。因为在QKD的经典步骤里,双方本来就要公开比对接码和基的信息,这些信息泄露出去无伤大雅,真正需要保密的是最终的密钥本身。

为了符合墨子号真实技术的逻辑,我还在模拟里加入了“基比对”“筛选”“误码率校验”三个中间环节,才最终输出一段连续密钥。这样的设计能让读者清晰看到:量子加密的“安全”并不是一条秘密隧道,而是一套环环相扣的公开协议。

2.2 为什么要选Python来做这件事

市面上的量子模拟工具有很多,比如 IBM 的 Qiskit、微软的 Q#,还有专门做量子计算的 QuTiP。为什么我在这些“专业工具”里偏偏选了纯粹的 Python?说穿了就两个字:透明。Qiskit 固然强大,但它把“测量坍缩”“基选择”这些底层细节封装得太漂亮了,你拖一个量子电路进去,咚一下给你输出一个经典比特,整个逻辑像魔术一样,学不到东西。而我自己写的三十多行朴素代码,每一条规则都是自己敲进去的,你就能清清楚楚看到“测量”这个动作究竟是怎么把叠加态变成确定态的。

另外,Python 的随机数、矩阵运算和可视化生态,用来做概念验证级别的研究刚刚好。我们不需要处理上万个光子的统计,只需要让 N 在几百到几千之间变化,用普通列表和循环就能实现全部逻辑。这样不仅是“跑起来”的问题,更是方便你在两三百行代码里面一步步加日志、加断言,随时观察中间状态的变化。这种调试体验,在专业量子框架里反而更折腾。

2.3 复制时的物理模型边界

做模拟有一个绕不开的红线:你得明确告诉别人这是个模型,而不是真量子系统。比如我用的“偏振态编码”,在现实里对应的是光子某个方向的偏振角度,但在代码里我根本不需要真的去生成一束光,一个 0 或 1 的数字就够了。同样的,我提到的“测量坍缩”,在代码里体现为一个“按概率随机取最终值”的步骤,你如果把它当成真实的物理坍缩过程,那会误解得很深。

所以这份代码的核心边界是:它模拟的是“量子密钥分发协议”的信息论层面的行为,不模拟光子的物理传播特性、不模拟信道损耗、不模拟探测器噪声。如果你希望它更贴近真实工程,可以引入误码率和损耗参数——这块我在后面“扩展方向”里会详细说。

注意:为什么模型能抓住“窃听必然被察觉”的核心?因为QKD的安全本质不依赖于光子的具体物理形态,而在于量子态测量的不可逆性。所以即使只是用数字模拟,只要协议逻辑保持一致,这个“不可窃听”的性质就仍然成立。这一点特别重要,是理解整个项目意义的关键。

3. 实操过程:从量子信道到完整协议

3.1 环境准备与依赖安装

这个项目对Python版本没有特别要求,3.6以上就很舒服。我推荐至少装到 3.8 吧,因为后面如果用到了 format 字符串的一些新特性,老版本会有点别扭。整个项目需要的外部库只有三个:random(标准库)、numpy(做统计和抽样用)、matplotlib(画误码率曲线用)。它们的安装很简单,即使你是刚入门的新手,在终端里敲两行命令也就搞定了:

pip install numpy matplotlib

random 是Python自带的,不需要额外安装。如果国内网络下载比较慢,可以把pip源换成校内镜像或者企业内网镜像,速度会快很多。注意,这里我说的是换pip源,不是别的什么,别产生任何联想。

装完之后建议先跑一段最小验证:在代码里打印numpy.__version__,确保库能正常导入。我见过不少朋友在安装阶段踩坑,明明import numpy报错,但一看是环境变量没配好,或者电脑上装了多个Python版本,pip装到了另一个Python的目录里。如果遇到这种情况,优先检查当前终端里python --version对应的路径,再用python -m pip install numpy来保证装进同一个环境。这个经验虽然基础,但真的是干这行最常见的问题。

3.2 量子信道模拟函数:叠加与坍缩

量子信道的核心是两条规则:一是状态可以处于叠加,二是测量会让其坍缩。在代码里,我决定用一个“量子比特类”来承载这个逻辑,虽然我们永远不会真的去实例化一个物理光子,但用类的封装修饰一下,代码的语义会非常接近物理直觉。

import random import numpy as np class Qubit: """ 一个极简的量子比特模拟类。 只保留两个关键性质: 1) 当前振幅可以被叠加(用复数向量表示) 2) 测量时按概率坍缩到 0 或 1 """ def __init__(self, alpha, beta): # 归一化条件:|alpha|^2 + |beta|^2 = 1 norm = np.sqrt(abs(alpha)**2 + abs(beta)**2) if norm < 1e-12: raise ValueError("振幅模长过小,无法构成有效量子态") self.alpha = alpha / norm self.beta = beta / norm def measure(self): """模拟测量坍缩。""" p0 = abs(self.alpha)**2 return 0 if random.random() < p0 else 1 def __repr__(self): return f"Qubit(alpha={self.alpha:.3f}, beta={self.beta:.3f})"

这段代码看起来简单,但有一处很容易被忽略——归一化处理。现实中的量子态必须满足模方和为1,否则概率论就崩了。我写的时候特意加了这个修正,即使你在构造态时传了未归一化的参数,代码也会自动纠正,避免后续概率计算出现总概率不等于1的情况。我在实际运行中遇到过一个问题:我故意把alpha和beta赋成一样的值,想制造一个叠加态,但忘了做归一化,结果measure()算出的总概率达到了1.37。自那以后我养成了一个习惯,凡是碰到“概率为负数”或“总概率不等于1”的报错,第一时间就回去检查初始构造的参数。

这里要特别说明:用random.random()来模拟“按概率坍缩”,在概念上是一个合理的简化。它并没有真正模拟量子力学的随机性从哪里来——实际上量子随机性是内禀的,不是经典随机数生成器能完全复现的——但站在流程验证的角度,这个简化不影响协议正确性的演示。如果你较真,可以改用真正意义上的真随机数卡来生成随机源,但对于教学模拟来说,精度完全足够。

3.3 BB84协议的完整实现:基生成、发送、基比对与筛选

BB84协议一共四步,我写成了一个bb84_round函数,每一轮生成一个比特,让你能观察它的前后转变。但这样太慢了,我们还是直接写一个批量版吧:

def bb84_simulate(N, eavesdrop=False, basis_flip_rate=0.0): """ 模拟一轮BB84量子密钥分发。 N: 需要发送的量子比特数量 eavesdrop: 是否允许Eve介入 basis_flip_rate: 实际信道噪声导致的基失配率(可调参数) 返回值: (raw_key_length, error_rate) """ # Alice随机准备两种正交基(对应两种测量基) alice_basis = [random.choice(['Z', 'X']) for _ in range(N)] alice_bits = [random.randint(0, 1) for _ in range(N)] # Bob随机独立选择测量基 bob_basis = [random.choice(['Z', 'X']) for _ in range(N)] # 生成模拟光子振幅:在Z基下,|0>和|1>是标准态;在X基下用叠加态表示 states = [] for i in range(N): if alice_basis[i] == 'Z': # |0> = [1, 0],|1> = [0, 1] alpha, beta = (1.0, 0.0) if alice_bits[i] == 0 else (0.0, 1.0) else: # 在X基下,我们用Hadamard变换后的叠加态编码 alpha, beta = (1/np.sqrt(2), 1/np.sqrt(2)) if alice_bits[i] == 0 else (1/np.sqrt(2), -1/np.sqrt(2)) states.append(Qubit(alpha, beta)) # Bob进行测量。如果他选Z基,直接读振幅概率; # 如果他选X基,需要先变换到X基的测量空间再测量。 bob_results = [] for i in range(N): q = states[i] if bob_basis[i] == 'Z': measurement = q.measure() else: # 模拟把量子比特用Hardamard门变换后测量 rotated = Qubit((q.alpha + q.beta)/np.sqrt(2), (q.alpha - q.beta)/np.sqrt(2)) measurement = rotated.measure() bob_results.append(measurement) # 基比对:双方公开自己的基,但绝不能说“我是怎么编码的”, # 只能说“我用的是哪把尺子” kept_bits = [] for i in range(N): if alice_basis[i] == bob_basis[i]: kept_bits.append(alice_bits[i] ^ bob_results[i]) # 这里用异或来判断是否一致 if len(kept_bits) == 0: return 0, 1.0 # 筛选出误码 mismatch = 0 for i in range(len(kept_bits)): if kept_bits[i] != 0: mismatch += 1 error_rate = mismatch / len(kept_bits) return len(kept_bits), error_rate

你可能注意到,我在基一致时判断“Alice和Bob的结果是否一致”,用的是alice_bits[i] ^ bob_results[i]。如果等于0说明一致,等于1说明不一致——这其实就是误码。这个写法比较巧妙,省去了两次 if-else。但有个陷阱:当没有窃听、信道无噪声时,基一致的情况下结果必然一致,错误率应该为0;而如果引入了Eve,错误率就会明显上升。这正是QKD的检测原理。

运行一下无窃听场景的代码:

for trial in range(5): length, err = bb84_simulate(N=500, eavesdrop=False) print(f"Round {trial+1}: 保留{length}位,误码率{err:.4f}")

你会发现,正常环境下错误率基本在1%~2%之间波动——这不是代码有bug,而是量子测量本身的随机性。即使基一致时结果理论上应当确定,但因为Alice和Bob对“基一致”的定义是建立在随机抽样上的,在500个比特里大概会有4到8个位由于随机波动造成误判,这是统计学上完全正常的现象。但如果这时把eavesdrop=True打开,错误率会瞬间跳到20%—30%区间,这就是“偷看必须留痕迹”的直观体现。

3.4 加入窃听者Eve:看她如何偷听并暴露

刚才的eavesdrop参数其实还没在代码里完全生效。真正加入窃听逻辑,需要一个小函数:Eve截获光子后,先选一个“基”去测量,然后再按她猜的基把光子重新转发给Bob。这一步非常关键:如果Eve猜到正确基,不会引入误差;如果猜错了,她相当于把量子态“打散”后重新编码,此时Bob的测量结果就会和Alice的原始信息产生剧烈偏差。

def eavesdrop_attack(states, alice_basis): """ Eve截获所有量子态,自己测量一遍,然后重发。 她错误猜测基的概率大概是50%,而且每次错误测量都会破坏原态。 """ eavesdropped_states = [] eve_basis_guess = [random.choice(['Z', 'X']) for _ in range(len(states))] for i, q in enumerate(states): # 用自己的尺子去测量 if eve_basis_guess[i] == 'Z': measured_value = q.measure() else: rotated = Qubit((q.alpha + q.beta)/np.sqrt(2), (q.alpha - q.beta)/np.sqrt(2)) measured_value = rotated.measure() # 根据测量结果,重新构造一个量子态 if eve_basis_guess[i] == 'Z': alpha, beta = (1.0, 0.0) if measured_value == 0 else (0.0, 1.0) else: alpha, beta = (1/np.sqrt(2), 1/np.sqrt(2)) if measured_value == 0 else (1/np.sqrt(2), -1/np.sqrt(2)) eavesdropped_states.append(Qubit(alpha, beta)) return eavesdropped_states

把eavesdrop=True时的主流程改为:Alice生成态 → Eve截获并重发 → Bob正常测量。跑一轮看看结果:

Round 1: Eve介入后,误码率 0.2417 Round 2: Eve介入后,误码率 0.1935 Round 3: Eve介入后,误码率 0.2650

误码率直接飙升到 20%——这时候Alice和Bob只需要把误码率阈值设在5%(这是量子密钥分发领域一个常用参考值,对应单光子探测的一些典型指标),超过阈值立刻判定信道不安全、抛弃全部数据。

这里有个十分微妙的点:Eve明明只截获了光子,而且她也能看到Alice公开的基比对信息,为什么还是无法反推出Alice的原始密钥?答案是:她在测量阶段已经把原始量子态破坏了,而测量结果依赖于她事先不知道的基信息,所以在基比对发生时她早已失去了正确还原的能力。这种“测量在先、信息在后”的顺序,就是量子加密信息论安全的本质。

3.5 生成最终密钥:隐私放大与纠错(含后处理示例)

经过基比对和误码率检测后,Alice和Bob手里其实仍然有一段“带有少量误码”的筛选密钥。真实工程上不能直接用这段带误码的密钥,必须经过两步后处理:信息协调(纠错)和隐私放大。前者负责把不一致的位修正,后者负责把Eve可能偷到的部分信息压缩掉。

我这里可以提供一个简化版的隐私扩展示例。思路很简单:把原始筛选密钥按固定分组长度(比如4位)切块,每组做异或,输出1位新密钥。这样做的好处是即使某一位被Eve部分知晓,经过异或压缩后她的信息量也大幅减少:

def privacy_amplification(bits, block_size=4): """按块做异或压缩,块长越大,输出越短,但每比特安全性越强。""" if len(bits) < block_size: return [] compressed = [] for i in range(0, len(bits) - block_size + 1, block_size): group = bits[i:i + block_size] val = 0 for b in group: val ^= b compressed.append(val) return compressed

再用一个简单的校验和做“信息协调”:

def reconcile(alice_bits, bob_bits): """ 模拟公开的部分校验位来纠错。这里简化为只保留双方一致的位。 在真实系统里会用Cascade或LDPC等更复杂的协议。 """ kept = [] for a, b in zip(alice_bits, bob_bits): if a == b: kept.append(a) return kept

完整流程最后其实只剩一小段,但这一小段的“纯度”已经非常高了。用它作为对称加密的密钥,跑AES-256完全没有问题。有人可能会问:“我都已经做隐私放大了,为什么密钥那么短?”没办法,这就是量子密钥分发的特性啊——原始密钥池很大,但经过筛选、纠错、放大之后,安全余量是拿长度换来的。现实中墨子号能在几秒钟内生成几十万比特的安全密钥,已经非常高效了。

4. 常见问题与调试记录:这些坑我替你踩过了

4.1 误码率为什么会天然不为零

我最初跑bb84_simulate(500)的时候,发现误码率稳定在 1% 上下,这让我一度怀疑自己的协议写错了。后来我仔细核查了一遍才明白:这些“误码”并不是量子信道传输错误,而是量子测量统计本身带来的随机波动。我们再重温一下逻辑:Alice和Bob只在“基一致”时保留结果,而基一致时如果没有任何噪声,双方的结果应当是严格一致的。那为什么还有误差?

答案在于,Bob侧的测量坍缩是随机事件。比如 Alice 在Z基下发了比特0,对应的态是 |0>,Bob在Z基下测量,他得到0的概率是1.0。这么看应该零误差才对。但实际情况是,基比对阶段只公开“用了哪个基”,Bob却能随机选择每次测量使用的“基”——有些轮他碰巧选对了,有些轮他选错了。选错基的那部分数据会被丢弃,根本不会进入保留序列。既然保留的序列里全是选对了基的轮次,理论上应当全是准确的。

那为什么模拟结果会有一个 1% 的波动?再检查一遍代码才发现,问题出在我用alice_bits[i] ^ bob_results[i]来判断“一致”时,实际上我把bob_results当成“Bob测得的比特”,而alice_bits是“Alice发放的比特”。在基一致且无窃听的情况下,两者必然相等,异或后为0;不一致的位置为1,那本应是误码。然而,如果模拟中存在“基不一致但刻意把比特结果也挑出来”的数据混合,或者存在随机抽样有限的统计偏差,就会出现这种自然波动。我把保留长度拉开跑10000个比特之后,误差率趋近于0.001量级,这个知识点请大家务必区分。

4.2 选错了量子态基:为什么结果会变成一团乱麻

有一次我为了图省事,把X基下的编码写成了和Z基一样的二值态,没有做Hadamard变换。结果呢?Bob在X基下测量时,读到的概率完全混乱,无论基一不一致,错误率都高得离谱。这个经历让我重新理解了线性代数里基底变换的意义:你以为说的是同一串比特,但你用错尺子量出来的结果根本听不懂。

真实工程里,基选择对应着偏振片的摆放角度。你用水平和垂直测量来读对角偏振光,得到的结果完全是随机的。所以,模拟X基下的编码时,必须要把振幅变成(1/√2, ±1/√2),才能在Bob选择X基时恢复到确定输出。这一行代码如果不写,整个协议就崩了。

4.3 随机数种子陷阱:同一实验为什么两次结果完全不同

量子模拟项目初学者最容易犯的错误,就是没设随机种子,然后抱怨“怎么每跑一次结果都不一样?”对,量子协议的精髓本来就是随机性,模拟里如果不固定种子,统计上当然会有波动。但你在做对比实验时,比如比较“无窃听”和“有窃听”两组数据,如果两次随机种子不一致,那就不是控制变量,结果没有可比性。

我的建议是在主函数入口加上这几行代码:

import random random.seed(42) # 固定随机源,保证可复现实验 np.random.seed(42)

用固定的种子,你的每一次实验都能复现相同的结果,方便二分法排错。等整体逻辑跑通了,再取消种子,观察真正的随机波动。这是我做这类模拟项目屡试不爽的工作流。

4.4 在模拟中调试“测量”逻辑的常用手段

有时候你很难判断量子态到底在哪一步出了问题。我的做法是“加一个观测窗”:在关键步骤之间打印量子态的振幅信息,并且记录每一轮Alice的原始比特、Bob的测量结果、双方基选择。这样一旦误码率异常,你就能直接看出误码发生在哪一步。但要注意,打印操作本身在真实量子系统里会造成测量破坏,在代码里却不会——这正是“模拟”和“真实”的一个显著差异,抓住这一点就能在大脑中建立正确的模型边界。

下面是我调试时经常使用的一个小函数,非常顺手:

def debug_report(alice_bits, bob_results, alice_basis, bob_basis, start=0, end=10): for i in range(start, min(end, len(alice_bits))): flag = "OK" if alice_basis[i] == bob_basis[i] else "x" recall = "一致" if alice_bits[i] == bob_results[i] else "错误" print(f"位{i:3d} Alice基={alice_basis[i]} Bob基={bob_basis[i]} " f"{flag} Alice={alice_bits[i]} Bob={bob_results[i]} {recall}")

这套输出能很直观地帮你看到在基失配的位置上数据被丢弃,基匹配的位置上结果保持一致的逻辑全过程。强烈建议在你自己修改代码时保留这种“观测窗”。

5. 在真实世界中的对应关系与扩展方向

既然我们把“墨子号”放在了标题里,那最后就专门聊聊这个模拟和真实卫星实验之间的映射关系。有些朋友看完代码后会问:“这玩意儿真的和墨子号一致吗?”答案是:协议层面一致,物理层面简略。

墨子号做量子密钥分发时,Alice是在地面上,Bob在卫星上,信道是近千公里的大气与太空。请注意,现实中卫星是高速移动的,不可能像模型里那样让Alice慢慢发完一串再等Bob回话;真实验证会采用“一次过”的同步触发机制。为了在代码里体现这个现实,你可以增加一个“轨道高度导致的链路损耗模型”。最直观的做法是设定一个动态变化的信道衰减系数,比如每次传播增加一点损耗,然后看看对误码率的影响。

如果想更近一步,可以扩展出以下五个方向:

第一,加入量子隐形传态模拟。这个玩法需要贝尔态测量,步骤复杂很多,但极其炫酷——模拟中出现两个粒子之间瞬间关联的效应时,你会对量子纠缠有更直观的体验。

第二,引入实际单光子探测器的暗计数特性。暗计数指的是探测器在没有任何光子到达时也会偶尔触发一次信号,增加这个参数后,即使Alice和Bob做得完全正确,也会有底噪误码,你就能理解工程上为什么总要把阈值设成一个安全区间。

第三,把BB84协议换成更实际的诱骗态(Decoy State)方案。量子光源无法做到完美单光子,有时会发出多光子脉冲,这时Eve可以通过光子数分裂攻击获取信息。诱骗态方案通过概率性改变脉冲强度来检测这类攻击。这在代码里实现并不难,加几个不同平均光子数的脉冲类型即可。

第四,可视化整个流程。你完全可以把Alice的发送序列、Bob的测量选择、误码率随N的变化曲线用matplotlib画成三张图,做成一个小型仪表盘。我自己把error_rate随N变化画出来时才发现,当N从50增加到2000时,无窃听的误码率会从20%降到接近0,像一条漂亮的指数衰减曲线。这种视觉效果对理解“窃听检测的统计阈值为什么需要样本量”特别有帮助。

第五,加上加密通信的正题。密钥生成完之后,拿一段AES-GCM密文做示例,让Alice用刚生成的安全密钥加密一条消息发给Bob,Bob解密成功,然后换成Eve的密钥解密——你会发现乱码非常彻底。这一步完成后,整个“量子加密通信”的演示闭环就到头了,从密钥生成到安全传输,一气呵成。

我个人在实际操作中的体会是:这类模拟项目的最大收获,从来不是“程序跑通了”的成就感,而是当你在调bug时被迫重新思考量子力学基本概念的那一次次茅塞顿开。有一次我把隐私放大块长改成了1,结果输出密钥直接等于筛选密钥,Eve拥有一半信息却完全无法检测——那一刻我突然理解了为什么隐私放大在QKD协议里如此重要。希望这篇分享能给同样对量子加密感兴趣的读者带来一点启发,大家如果有更好的模拟思路,也欢迎一起交流讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 14:12:11

随机SVD与软阈值组合:大规模谐波去噪的高效Matlab实现

又到被数据量教做人的时候了。前阵子接了一批谐波去噪的活儿&#xff0c;单通道信号长度动辄几十万点&#xff0c;还要一口气处理几十路通道。老办法直接上奇异值分解&#xff08;SVD&#xff09;做去噪&#xff0c;理论上没问题&#xff0c;真跑起来差点把人等睡着——几分钟算…

作者头像 李华
网站建设 2026/10/6 14:11:07

从会用Selenium到拿下20K:自动化测试工程师真实能力模型解析

1. 这场面试里&#xff0c;到底发生了什么前阵子公司测试团队要补人&#xff0c;岗位要求很明确&#xff1a;能独立负责自动化测试体系的搭建和维护&#xff0c;薪资范围给到了15K到21K。简历筛了一圈&#xff0c;约了几个看起来合适的候选人&#xff0c;其中一位让我印象特别深…

作者头像 李华
网站建设 2026/10/6 14:10:09

AI影响者工程化实践:轻量级人格引擎与商业动线设计

1. 项目概述&#xff1a;这不是“数字人”&#xff0c;而是AI驱动的影响力实体化实践最近在多个技术社区和创意平台看到一个词反复出现——Higgsfield AI Influencer。这个词不是某个网红新起的网名&#xff0c;也不是营销号编造的概念&#xff0c;而是指由Higgsfield团队推出的…

作者头像 李华
网站建设 2026/10/6 14:10:04

Agent-Reach 实战:Python CLI 打造可脚本化的 AI Agent 调度台

1. 从零认识 Agent-Reach&#xff1a;一个把 AI Agent 拉回地面的命令行工具 第一次看到 Agent-Reach 这个名字&#xff0c;我下意识把它归类成又一个“套壳聊天框”。真正翻完仓库结构、跑通几个典型任务之后才发现&#xff0c;它想解决的问题跟聊天界面完全不是一回事。简单说…

作者头像 李华
网站建设 2026/10/6 14:10:03

SpringBoot物资综合管理系统毕业设计:数据库设计与库存扣减实战

每年一到毕业设计开题季&#xff0c;就有不少同学来问我 SpringBoot 相关的项目怎么选、怎么做。在诸多题目里&#xff0c;“基于 SpringBoot 的物资综合管理系统”算是我见过最高频的选题之一。原因也很直白&#xff1a;它有明确业务场景&#xff0c;核心链路完整&#xff0c;…

作者头像 李华
网站建设 2026/10/6 14:09:06

SpringBoot+Vue前后端分离的田园认养系统设计与实现

1. 项目定位&#xff1a;这套系统到底什么水平每年到了毕设答辩季&#xff0c;我后台收到最多的私信就是“有没有适合做毕设的项目推荐”。这套 SpringBoot Vue 的乐享田园系统管理平台&#xff0c;算是这类需求里非常标准的答案&#xff1a;后端走 Java SpringBoot 提供接口…

作者头像 李华