← e2ee · POST-QUANTUM EVOLUTION

PQXDH · Signal 的后量子升级

从 2016 年的 X3DH 到 2023 年的 PQXDH,再到 2025 年的 SPQR / Triple Ratchet—— Signal 协议是怎样在不破坏 forward secrecy 的前提下,把每一段密钥协商都"加上抗量子保险"的。

X3DH → PQXDH ML-KEM / Kyber-1024 Hybrid 安全 harvest-now-decrypt-later Triple Ratchet
01 演进驱动力 为什么 2023 年要动 X3DH

Signal 2016 年定型的 X3DH 在异步握手里做 4 次 DH,全部跑在 Curve25519 上。 安全性押在 椭圆曲线离散对数难题——Shor 算法跑在足够大的量子计算机上就能在多项式时间内打掉。

真正的威胁不是"等量子计算机来了再换",而是今天就发生的 harvest-now-decrypt-later:国家级对手现在录下所有密文,等 CRQC(密码相关规模量子计算机)问世—— 预计 10–20 年——一次性解密。Signal 主打的 forward secrecy 在这套威胁模型下失效: 虽然每条消息密钥都已删除,但首密钥能被反算出来,整段历史会话照样泄漏。

所以 PQ 升级不能等。Signal 在 2023-09-19 公告了 PQXDH (Post-Quantum Extended Diffie-Hellman),把一个后量子 KEM 拼到 X3DH 旁边,hybrid 协商首密钥。

harvest-now-decrypt-later · 调节窃听者等待的年份
今天 · 2026 Alice ↔ Bob 发送加密消息 👁 Eve · 国家级 归档密文 每条消息 + 首密钥协商记录 2026 2050 ⬇ 拖动 slider 调节窃听者等待年份 ⬇ 2026 CRQC 尚未问世 · 全栈 X25519 暂时安全
2026
:CRQC 出现年份是估计区间,业界普遍预期 2035–2045。本图采用中间值 2040 作为分界。 关键不是精确年份,而是密文今天就在被存
展开 · NIST PQ 标准化与 ML-KEM

NIST 在 2016 年发起后量子密码标准化竞赛。2022 年 7 月,CRYSTALS-Kyber 入选为唯一的 KEM 标准化候选; 2024 年 8 月,正式发布 FIPS 203 · ML-KEM(Module-Lattice-based KEM),是 Kyber 的标准化版本。

ML-KEM 基于 Module Learning With Errors (MLWE) 困难假设,参数集:

ML-KEM-512   公钥  800 B  · 密文  768 B  · 类比 AES-128
ML-KEM-768   公钥 1184 B  · 密文 1088 B  · 类比 AES-192
ML-KEM-1024  公钥 1568 B  · 密文 1568 B  · 类比 AES-256

Signal 在 PQXDH 中明确推荐用 Kyber-1024(最高安全等级),现在等价于 ML-KEM-1024。 Spec 原文:"an application could choose ... pqkem as CRYSTALS-KYBER-1024"

02 KEM ≠ DH · 心智迁移 这不是"加一次 DH"

在看 PQXDH 算法之前必须先迁移一个心智:后量子原语主流不是"DH 的替换品",而是 KEM(Key Encapsulation Mechanism)。 二者的 API 形态根本不同——这一节看不懂的话,第 03 节的算法图会一直被误读成"加了第 5 个 DH"。

DH · Diffie-Hellman

  • 对称:双方各持私钥
  • 可交换DH(a, B) = DH(b, A)
  • 对方的公钥就能算出 shared
  • 典型:X25519,公钥 32 B
  • 双向"亮公钥 → 同时算出 shared"

KEM · Key Encapsulation

  • 非对称:发起方 / 接收方角色不同
  • 不可交换:(Encap, Decap) 不对偶
  • 发起方拿对方公钥 Encap,吐 (ct, ss)
  • 典型:ML-KEM-1024,公钥 1568 B、密文 1568 B
  • 单向"密文要在网上飞"
API 对照 · 双方算同一 shared 的两种姿势
DH · 双向对称 👤 Alice (a, A) 👤 Bob (b, B) 公钥 A ↔ 公钥 B DH(a,B) = DH(b,A) = ss 双方各自本地算,无需第三方 KEM · 单向 Encap/Decap 👤 发起方 👤 接收方 (pk, sk) ① 拿公钥 pk ② 发密文 ct (1568B) (ct, ss) = Encap(pk) ss = Decap(sk, ct) 发起方先算 ss · 接收方靠 ct 还原

这个差异决定了 PQXDH 的整体形态。不是"用 ML-KEM 替换 X25519",而是 X25519 的 4 个 DH 保持不变,旁边并联一个 ML-KEM 的 Encap/Decap, 两套各算出一段 shared secret,再用 KDF 揉到一起。

同样的原因,会话内的 Double Ratchet 也不能"直接换 KEM"——下文第 04 节会展开。

03 PQXDH 完整算法 X3DH ⊕ Kyber, hybrid

看图。左侧是 Bob 的 prekey bundle——除 X3DH 原有字段外,多了两类 ML-KEM 公钥(PQSPK 长期、PQOPK 一次性), 以及它们各自由 IK_B 做的签名。中间是 Alice 的本地计算:4 个 DH 一切照旧(沿用 X3DH), 外加一次 Encap(PQPK_B) 吐出 (CT, SS)。右侧是 共同的 KDF 输入—— DH1‖DH2‖DH3‖DH4‖SS 一起喂给 HKDF 得到首密钥 SK

PQXDH 数据流 · Bob bundle → Alice 计算 → SK
Bob's Prekey Bundle 服务器存放 · Alice 拉取 IK_B 身份长公钥 SPK_B + Sig(IK_B, SPK_B) OPK_B (one-time) 可选 — PQXDH 新增 — PQSPK_B last-resort + Sig(IK_B, PQSPK_B) PQOPK_B (one-time) 优先用 + Sig(IK_B, PQOPK_B) PQPK_B = 运行时选中 = PQOPK 若有,否则 PQSPK Alice 拿它 Encap 所有 PQ 公钥 都被 IK_B 签名 → 防 MitM ML-KEM-1024 公钥 ≈ 1568 B 是 X25519 公钥的 49 倍 Alice's Local Computation 拉到 bundle 后本地一气呵成 DH1 = DH(IK_A, SPK_B) DH2 = DH(EK_A, IK_B) DH3 = DH(EK_A, SPK_B) DH4 = DH(EK_A, OPK_B) ⓘ optional — 沿用 X3DH,无任何变化 — (CT, SS) = Encap(PQPK_B) ML-KEM-1024 · NEW SK = KDF(DH1 ‖ DH2 ‖ DH3 ‖ DH4 ‖ SS) HKDF-SHA512 · 把 4 个 DH 和 KEM shared 一起灌 Initial Message → Bob • IK_A, EK_A • CT (ML-KEM ciphertext, ≈1568 B) • prekey ids (SPK, OPK, PQPK) Bob Receives 用 sk 还原同一个 SK SS = Decap(sk, CT) 重算 DH1..4 SK = KDF(...) 与 Alice 一致 AEAD 解密 ✓ 用 SK + AD 验证 成功 → 删 OPK / PQOPK Associated Data AD = IK_A ‖ IK_B [‖ PQPK_B] 绑定身份 + PQ 公钥 → 进入 Double Ratchet 用 SK 做 root key 初始值

Hybrid 的安全论证:KDF 是密码学伪随机函数,只要任意一个输入有足够熵且无法被反算,输出 SK 就安全。 所以——

Hybrid 安全 · 点击切换"假设谁被打穿"
4 DH (X25519) ~32B × 4 = 128B 熵 ML-KEM SS 32B 熵 HKDF-SHA512 混合输入 SK ✓ 安全 两个 secret 都未被打穿 → SK 显然安全
论证4DH 安全 OR ML-KEM 安全 → SK 安全。攻击者必须同时打穿两个独立的数学假设 (离散对数 Module-LWE),才能反推 SK。Hybrid 是不让 PQ 算法"风险单点"的工程妥协。
展开 · KDF 输入顺序与 AD 拼接细节

PQXDH spec § 3.3 定义的 KDF 输入:

F   = b'\xFF' × 32       // domain separation prefix
KM  = F ‖ DH1 ‖ DH2 ‖ DH3 [‖ DH4] ‖ SS
SK  = HKDF(salt = 0×64, ikm = KM, info = "MyProtocol")

关键约束(来自 spec 原文):"If pqkem does not incorporate PQPK_B into the ciphertext, Alice must also append EncodeKEM(PQPK_B) to AD."

这是防 KEM key-substitution 攻击——若 KEM ciphertext 本身没把 pk 绑死, 需要靠 AD 在 AEAD 这层把 pk 绑定到会话身份上,否则攻击者可以替换 PQPK 重放。

04 演进尚未完成 · SPQR / Triple Ratchet 2025-10 公告

PQXDH 只升级了初始握手。一旦会话建立,后续靠 Double Ratchet 持续派生消息密钥; 其中 DH Ratchet 那一支——每条消息附带的临时公钥——仍然是 X25519。 意味着:

  • 初始握手抗量子:harvest-now-decrypt-later 录音机看不到首密钥 ✓
  • 会话内 Post-Compromise Security 不抗量子:CRQC 时代攻击者拿到瞬时状态后,能用 Shor 打 DH Ratchet 重新接管会话 ✗

Signal 在 2025-10-02 公告了 SPQR(Sparse Post-Quantum Ratchet),并把它与 Double Ratchet 组合成 Triple Ratchet。截至 2026-05iOS 和 Android 主分支都已在 capability 层无条件声明 spqr = true

  • Signal-iOS · AccountAttributes.swift:105 · public let spqr = true
  • Signal-Android · AppCapabilities.kt · spqr = true(硬编码)

意味着两端客户端都已经 ship 了 SPQR 支持代码,并向服务器宣告自己具备这个能力。 实际生效仍需会话双方都已升级(不然就 fallback 到老 Double Ratchet)——但既然两个主流客户端都是无条件 true, 随着自动更新覆盖到大部分用户,大部分新会话现在应该都是 Triple Ratchet 了。

Triple Ratchet · DR + SPQR 并行
DH Ratchet · X25519 Symmetric Ratchet · HKDF SPQR · ML-KEM (hybrid, sparse) RK₀ RK₁ RK₂ RK₃ RK₄ 每次回合 DH(eph_a, eph_b) CK CK CK CK CK 每条消息派生 MK(不变) SS₀ erasure-coded SS₁ ~ KB 拆分多消息 SS₂ 几条消息一次 KEM Encap 每个 RK 派生时 RK_{n+1} = KDF(RK_n, DH_n, SS_⌊n/k⌋)

SPQR 的核心工程难点是带宽:ML-KEM ciphertext ~1568 B,远大于 X25519 的 32 B。 如果每条消息都附一个完整 KEM ciphertext,移动网络成本无法接受。 SPQR 用了两个手段缓解——

  • Sparse:不是每条消息都跑 KEM,而是每隔若干条消息做一次"PQ hop"
  • Erasure-coded:把一次 KEM 输出的 ciphertext 拆成多份编码块,分摊到后续若干条消息里发送;丢一两条不影响恢复
展开 · SPQR 形式化验证与 Triple Ratchet 命名

官方公告:"Signal Protocol and Post-Quantum Ratchets" · signal.org/blog/spqr · 2025-10-02

技术亮点:

  • 使用 ProVerif(符号模型)+ F*(计算模型)双重形式化验证
  • Triple Ratchet = DH Ratchet (X25519) + KEM Ratchet (ML-KEM, sparse) + Symmetric Ratchet (HKDF),前两层 hybrid 喂给同一个 RK
  • 保持原有 forward secrecy 和 post-compromise security 在量子模型下成立

"Triple" 这个命名学界其实 2024 年就有论文用过(如 "The Triple Ratchet" by Alwen et al.),但 Signal 工程实现与论文方案在细节(erasure code 形式、状态机布局)上不完全相同。

展开 · 为什么 DR 不能直接平移到 KEM

DR 的 DH Ratchet 之所以优雅,靠的是 DH 的对称性:双方都"亮一次自己的临时公钥",对方就能算出共享。 KEM 没有这个性质:

  • 角色不对偶:谁 Encap 谁 Decap 是必须明确的,对称的 "ping-pong eph 公钥" 模式不成立
  • 带宽爆炸:每条消息一对 (pk, ct) 接近 3 KB,是 X25519 的 50 倍
  • 乱序处理复杂:DR 用 message-number + skipped-keys 处理乱序,KEM 状态机切换的乱序语义需要重新设计

所以 SPQR 选了"sparse + erasure-coded"这条折中路:保留 DH Ratchet 不变,把 KEM 作为并联的、稀疏触发的第三条链。

05 演进时间表 · Refs 2013 – 2025
版本 时间 关键变化 仍然脆弱的部分
Axolotl / DR 2013 DH Ratchet + Symmetric Ratchet 雏形 异步首握手不优雅
X3DH + DR 2016 引入 SPK + OPK 解决异步握手 全栈 X25519 → 量子来即崩
PQXDH 2023-09 X3DH ⊕ Kyber-1024, hybrid 初始握手 会话内 DH Ratchet 仍 X25519
SPQR / Triple Ratchet 2025-10 DR + sparse ML-KEM hybrid, 形式化验证 iOS + Android 双端 capability 已硬编码 spqr = true · 旧设备未升前会话仍走 DR

📚 权威 References