05

Double Ratchet 状态机 · Alice 视角

FSM · 状态演进

三层状态 (RootKey · SendChain · RecvChain) 在 send/recv 事件下如何切换、何时 reset

🎛️ Double Ratchet 状态 = 1× 跨轮主键 (RootKey) + 2× 单轮子链 (SendChain · RecvChain) RootKey · 跨轮状态 范围: 整个 Session 持续翻新 触发: 每次 DH 翻转 (send fresh / recv fresh) 作用: 生成下一对 (RK', ChainKey) SendChain · 单轮发送链 范围: 自上次"我翻"到下一次"我翻" 触发推进: 每次 send 一条消息 作用: 派生 MK 加密 RecvChain · 单轮接收链 范围: 自上次"对方翻"到下一次"对方翻" 触发推进: 每次 recv 一条消息 作用: 派生 MK 解密 📈 状态演进 (沿时间轴展开 Alice 的 5 步操作) time t=0 init t=1 send #1 t=2 recv (新 key) t=3 send #2 t=4 recv (新 key) RootKey: RK₁ DH flip RK₂ DH flip RK₃ DH flip RK₄ DH flip RK₅ SendChain: (空 / 等首次发) SK₁ (chain advances: idx 0 → 1 → 2 → ...) ⚡ RESET SK₂ (重新派生 · idx 0 → 1 → ...) ↑ 触发: 在 recv 后第一次 send 时, Alice 生成新 ratchet key RecvChain: (空 / 等对方第一条) RK₁ (idx 0 → 1 → 2 → ...) ⚡ RESET RK₂ (重派生) ↑ 触发: 收到的 msg.ratchet_key 与上次不同 📋 4 种事件 — 各自影响哪些状态 事件 触发条件 RootKey SendChain RecvChain ① send fresh recv 后第一次 send + KDF 翻一次 ⚡ RESET 重派生 不变 ② send continue 同会话连续 send 不变 → advance idx +1 不变 ③ recv fresh msg.ratchet_key 与上次不同 + KDF 翻一次 不变 ⚡ RESET 重派生 ④ recv continue msg.ratchet_key 与上次相同 不变 不变 → advance idx +1 💡 双棘轮 = 1 条 DH 主链 (RootKey) + 2 条按需重置的对称子链 (Send/Recv) · 子链 reset 由"对方密钥变化"驱动
RK

RootKey · 跨轮主键

  • • 整个 Session 唯一存在的"线索",跨越所有翻转
  • • 每次 DH 翻转都喂入 KDF, 出新 RK + 新 ChainKey
  • • send/recv 两个方向的 flip 都会推进它
  • • 如果 Session 被 pickle 持久化, 必须保存 RK
SK

SendChain · 我发送的链

  • • 仅在"我已收到对方新 key"后才会更新
  • • 触发更新的是"我的下一次 send", 不是 recv 本身
  • • 同一个 SK 可发任意条消息(chain_index 递增)
  • • 旧 SK 立即丢弃,节省存储
RK*

RecvChain · 我接收的链

  • • 镜像对方的 SendChain(Alice 的 RecvChain = Bob 的 SendChain)
  • • 收到 ratchet_key 变化的 msg 时立即 reset
  • • 同 ratchet_key 的多条消息推进同一条 RecvChain
  • • 旧 RecvChain 可保留少量 skipped MK 处理乱序(详见 #06)
💡 一句话理解: Double Ratchet 的"双" = 外层一根 DH 主链(RootKey, 跨轮持续翻新, 提供后向安全) + 内层两根对称子链(SendChain/RecvChain, 各自按对方密钥变化重置, 链内每步派生消息密钥提供前向安全)。 子链的 reset 才是"双棘轮"的关键 — 它把"前向安全"和"后向安全"焊在一起。

📚 基础知识速查 · Reference

不熟悉以下底层概念? 这里是 30 秒回顾。

设计模式有限状态机 (FSM)

由"状态 + 事件 + 转移函数"组成的模型。Signal 的"棘轮翻转"可建模为 FSM, 转移由 send / recv 事件驱动。

state' = transition(state, event)

工程不可变状态 (Immutable State)

每次"翻转"产生新状态对象, 旧状态直接丢弃 (zeroize)。便于推理、测试与并发安全。

let new_state = ratchet.flip();
old_state.zeroize();

协议Double Ratchet 三层状态

RootKey (跨轮持久) + SendChain (单轮发送) + RecvChain (单轮接收)。这是 Signal 最核心的状态空间设计。

{ rk, send_chain, recv_chain, dh_pair }

概念持久化 (Pickle)

把内存里的 Session 状态序列化到磁盘, 重启后恢复。Olm/vodozemac 的 pickle 必须保护 RootKey 等敏感字段。

session.pickle(passphrase) → bytes