从源代码、RFC、学术论文、伪代码、非正式描述、ProVerif (.pv) 或 Tamarin (.spthy) 模型中提取协议消息流,并生成带有密码学注释的 Mermaid 序列图。适用于绘制加密协议图、可视化握手或密钥交换流程、从规范或 RFC 中提取消息流、绘制 ProVerif 或 Tamarin 模型图,或为 TLS、Noise、Signal、X3DH、Double Ratchet、FROST、DH 或 ECDH 协议绘制序列图。
加密协议图
生成一个 Mermaid sequenceDiagram(写入文件)和一个 ASCII 序列图(内联打印),输入可以是:
- 源代码:实现加密协议的代码,或
- 规范:RFC、学术论文、伪代码、非正式描述、ProVerif (
.pv) 或 Tamarin (.spthy) 模型。
使用的工具: Read、Write、Grep、Glob、Bash、WebFetch(用于 URL 规范)。
与 diagramming-code 技能(可视化代码结构)不同,本技能提取的是协议语义:谁向谁发送了什么,每一步执行了什么密码学变换,以及存在哪些协议阶段。
如需调用图、类层次结构或模块依赖关系图,请改用 diagramming-code 技能。
何时使用
- 用户要求绘制、可视化或提取加密协议
- 输入是实现握手、密钥交换或多方协议的源代码
- 输入是 RFC、学术论文、伪代码或形式化模型(ProVerif/Tamarin)
- 用户指定了特定协议(TLS、Noise、Signal、X3DH、FROST)
何时不使用
- 用户想要调用图、类层次结构或模块依赖关系图——请使用
diagramming-code - 用户想要形式化验证协议——请使用
mermaid-to-proverif(在生成图之后) - 输入没有加密协议语义(没有参与方,没有消息交换)
拒绝理由
| 理由 | 错误原因 | 正确操作 |
|---|---|---|
| "协议很简单,我可以凭记忆画图" | 基于记忆的图会遗漏步骤并颠倒箭头方向 | 系统地阅读源代码或规范 |
| "既然有代码,我就跳过规范路径" | 代码可能与规范不一致——两条路径能发现不同的错误 | 当两者都存在时,先运行规范工作流,然后注释代码差异 |
| "密码学注释是可选的装饰" | 没有密码学注释,图就只是消息流——对安全审查无用 | 注释每一个密码学操作 |
| "中止路径很明显,不需要 alt 块" | 隐式的中止处理会隐藏缺失的错误检查 | 使用 alt 块显示每个中止/错误路径 |
| "我不需要先检查示例" | 示例定义了预期的输出质量标准 | 在处理不熟悉的输入之前,先研究相关示例 |
| "ProVerif/Tamarin 模型是代码,不是规范" | 形式化模型是规范——它们描述的是预期行为,而非实现 | 对 .pv 和 .spthy 文件使用规范工作流(S1–S5) |
工作流
协议图进度:
- [ ] 步骤 0:确定输入类型(代码/规范/两者)
- [ ] 步骤 1(代码)或 S1–S5(规范):提取协议结构
- [ ] 步骤 6:生成 sequenceDiagram
- [ ] 步骤 7:验证并交付
步骤 0:确定输入类型
在执行任何其他操作之前,对输入进行分类:
| 信号 | 输入类型 |
|---|---|
源文件扩展名(.py、.rs、.go、.ts、.js、.cpp、.c) |
代码 |
| 函数/类定义、导入语句 | 代码 |
RFC 风格的章节标题(§、Section X.Y、MUST/SHALL 关键词) |
规范 |
Algorithm/Protocol/Figure 标签、数学符号 |
规范 |
ProVerif 文件(.pv),包含 process、let、in/out |
规范 |
Tamarin 文件(.spthy),包含 rule、--[...]-> |
规范 |
| 描述协议的纯文本或编号步骤 | 规范 |
| 同时包含源文件和规范文档 | 两者(用 ⚠️ 注释差异) |
- 仅代码 → 跳转到下面的步骤 1
- 仅规范 → 跳转到下面的规范工作流(S1–S5)
- 两者 → 先运行规范工作流,然后使用代码阅读步骤验证实现是否与规范图一致,并用
⚠️注释任何差异 - 不明确 → 询问用户:“这是源代码文件、规范文档,还是两者都有?”
步骤 1:定位协议入口点
使用 Grep 搜索函数名、类型名和注释,以揭示协议:
# 查找握手、会话、轮次、阶段入口点
rg -l "handshake|session_init|round[_0-9]|setup|keygen|send_msg|recv_msg" {targetDir}
# 查找使用的密码学原语
rg "sign|verify|encrypt|decrypt|dh|ecdh|kdf|hkdf|hmac|hash|commit|reveal|share" \
{targetDir} --type-add 'src:*.{py,rs,go,ts,js,cpp,c}' -t src -l
从最高层的编排函数开始阅读——即调用握手阶段或主协议循环的函数。
步骤 2:识别参与方和角色
从以下内容中提取参与者名称:
- 结构体/类名:
Client、Server、Initiator、Responder、Prover、Verifier、Dealer、Party、Coordinator - 携带角色状态的函数参数名
- 声明协议角色的注释
- 设置两方或多方场景的测试夹具
将这些映射到 Mermaid participant 声明。使用简短、可读的别名:
participant I as Initiator
participant R as Responder
步骤 3:追踪消息流
跟踪状态转换和网络发送/接收。查找以下模式:
| 模式 | 含义 |
|---|---|
send(msg) / recv() |
直接消息交换 |
serialize + transmit |
发送结构化消息 |
| 返回值传递给另一方的函数 | 逻辑消息(进程内) |
round1_output → round2_input |
基于轮次的 MPC 步骤 |
结构体字段名为 ephemeral_key、ciphertext、mac、tag |
消息内容 |
对于进程内协议实现(双方在同一进程中运行),当函数调用边界代表部署中本应是网络边界时,将其视为逻辑消息发送。
步骤 4:注释密码学操作
在每个协议步骤中,识别并标记:
| 操作 | 图注释 |
|---|---|
| 密钥生成 | Note over A: keygen(params) → pk, sk |
| DH / ECDH | Note over A,B: DH(sk_A, pk_B) |
| KDF / HKDF | Note over A: HKDF(ikm, salt, info) |
| 签名 | Note over A: Sign(sk, msg) → σ |
| 验证 | Note over B: Verify(pk, msg, σ) |
| 加密 | Note over A: Enc(key, plaintext) → ct |
| 解密 | Note over B: Dec(key, ct) → plaintext |
| 承诺 | Note over A: Commit(value, rand) → C |
| 哈希 | Note over A: H(data) → digest |
| 秘密共享 | Note over D: Share(secret, t, n) → {s_i} |
| 阈值组合 | Note over C: Combine({s_i}) → secret |
保持注释简洁——使用数学简写,而非代码。
步骤 5:识别协议阶段
使用 rect 或 Note 块将消息步骤分组为命名阶段:
常见需要检测的阶段:
- 设置/密钥生成:参与方密钥创建、可信设置、参数生成
- 握手/初始化:临时密钥交换、随机数交换、版本协商
- 认证:身份证明、证书交换、签名验证
- 密钥派生:从共享秘密派生会话密钥
- 数据传输/主协议:加密的应用数据交换
- 终结/拆除:会话关闭、MAC 验证、中止处理
检测中止/错误路径,并使用 alt 块显示它们。
规范工作流(S1–S5)
当输入是规范文档而非源代码时,使用此路径。完成 S1–S5 后,继续执行上面代码工作流中的步骤 6(生成 sequenceDiagram)和步骤 7(验证并交付)。
步骤 S1:摄取规范
获取完整的规范文本:
- 提供了文件路径 → 使用 Read 工具读取
- 提供了 URL → 使用 WebFetch 获取
- 内联粘贴 → 直接从对话上下文中处理
然后识别规范格式,并阅读
references/spec-parsing-patterns.md
以获取针对特定格式的提取指南:
| 格式 | 信号 |
|---|---|
| RFC | RFC XXXX、MUST/SHALL/SHOULD、ABNF 语法、带编号的章节文本 |
| 学术论文/伪代码 | Algorithm X、Protocol X、Figure X、编号步骤、数学模式中的 ←/→ |
| 非正式描述 | 编号列表、“A sends B ...”、纯英文描述 |
ProVerif (.pv) |
process、let、in(ch, x)、out(ch, msg)、!(复制) |
Tamarin (.spthy) |
rule、--[ ]->、Fr(~x)、!Pk(A, pk)、In(m)、Out(m) |
如果规范引用了已知的命名协议(TLS、Noise、Signal、X3DH、Double Ratchet、FROST),也请阅读
references/protocol-patterns.md
以使用其规范流程作为骨架,并填充规范特定的细节。
步骤 S2:提取参与方和角色
识别所有协议参与者。查找:
- 命名角色:在文本或伪代码中:
Alice、Bob、Client、Server、Initiator、Responder、Prover、Verifier、Dealer、Party_i、Coordinator、Signer - 章节标题:“Parties”、“Roles”、“Participants”、“Setup”、“Notation”
- ProVerif:顶层进程名(
let ClientProc(...)、let ServerProc(...)) - Tamarin:规则名和事实参数(例如
!Pk($A, pk)—$A是一个参与方)
将每个角色映射到 Mermaid participant 声明。使用短 ID 和描述性别名(参见
references/mermaid-sequence-syntax.md 中的命名约定)。
步骤 S3:提取消息流
追踪每个参与方发送给谁以及顺序。按格式的提取模式:
RFC / 非正式描述:
- 箭头符号:
A → B: msg、A -> B - 句子模式:“A sends B ...”、“B responds with ...”、“A transmits ...”、“upon receiving X, B sends Y”
- 编号步骤:按顺序提取,从上下文中推断发送者/接收者
伪代码:
- 带有显式
sender/receiver参数的函数签名 send(party, msg)/receive(party)调用- 返回值作为下一步中另一方函数的输入
ProVerif (.pv):
out(ch, msg)— 在通道ch上发送in(ch, x)— 在通道ch上接收,绑定到x- 匹配同一通道上的
out/in对以识别消息流 !(复制)表示处理多个会话的角色
Tamarin (.spthy):
In(m)前提 — 接收消息mOut(m)结论 — 发送消息m- 规则名和规则顺序揭示协议轮次
Fr(~x)— 参与方生成的新鲜随机值--[ Label ]->事实 — 安全注释,而非消息
保留顺序和轮次结构。在最终图中使用 par 块对并发发送(广播)进行分组。
步骤 S4:提取密码学操作
对于每个协议步骤,识别执行的密码学操作以及执行这些操作的参与方:
| 规范符号 | 操作 | 图注释 |
|---|---|---|
keygen()、Gen(1^λ) |
密钥生成 | Note over A: keygen() → pk, sk |
DH(a, B)、g^ab |
DH / ECDH | Note over A,B: DH(sk_A, pk_B) |
KDF(ikm)、HKDF(...) |
密钥派生 | Note over A: HKDF(ikm, salt, info) → k |
Sign(sk, m)、σ ← Sign |
签名 | Note over A: Sign(sk, msg) → σ |
Verify(pk, m, σ) |
验证 | Note over B: Verify(pk, msg, σ) |
Enc(k, m)、{m}_k |
加密 | Note over A: Enc(k, plaintext) → ct |
Dec(k, c) |
解密 | Note over B: Dec(k, ct) → plaintext |
H(m)、hash(m) |
哈希 | Note over A: H(data) → digest |
Commit(v, r)、com |
承诺 | Note over A: Commit(value, rand) → C |
ProVerif senc(m, k) |
对称加密 | Note over A: Enc(k, m) → ct |
ProVerif pk(sk) |
公钥派生 | Note over A: pk = pk(sk) |
ProVerif sign(m, sk) |
签名 | Note over A: Sign(sk, m) → σ |
识别安全条件和中止路径:
- 文本:“if verification fails, abort”、“only if ...”、“reject if ...”
- 伪代码:
assert、require、if ... abort - ProVerif:
if m = expected then ... else 0 - Tamarin:矛盾事实或限制引理
这些在最终图中变为 alt 块。
步骤 S5:标记规范歧义
在进入步骤 6 之前,检查是否存在空白:
- 不明确的消息顺序:从轮次结构或章节顺序推断;用
⚠️ ordering inferred from spec structure注释 - 隐含的参与方:如果某个参与方的角色是隐含的但未命名,给它一个描述性名称并注明推断
- 缺失的步骤:如果规范省略了该协议规范模式所需的步骤,注释:
⚠️ spec omits [step] — canonical protocol requires it - 未指定的密码学:如果规范说“encrypt”但没有指定方案,注释:
⚠️ encryption scheme not specified - ProVerif/Tamarin:私有通道(用
new c声明或作为私有自由名称的c)表示带外通道——请注明
<!-- 代码路径(步骤 1–5)和规范路径(步骤 S1–S5)都从这里继续 -->
步骤 6:生成 sequenceDiagram
按照
references/mermaid-sequence-syntax.md
中的规则生成 Mermaid 语法。
完整性优于简洁性。 显示每种不同的消息类型。省略重复的循环迭代(改用 loop 块),但绝不省略不同的协议步骤。
正确性优于美观性。 图必须与代码实际执行的操作一致。如果代码与已知规范不一致,注释差异:
Note over A,B: ⚠️ spec requires MAC here — implementation omits it
步骤 7:验证并交付
在交付之前:
- [ ] 每个声明的参与者实际发送或接收至少一条消息
- [ ] 箭头指向正确的方向(发送者 → 接收者)
- [ ] 密码学操作位于正确的参与方(执行该操作的参与方)
- [ ] 如果使用了协议阶段,没有箭头出现在阶段块之外
- [ ]
alt块覆盖了已知的中止/错误路径 - [ ] 图渲染没有语法错误(检查
references/mermaid-sequence-syntax.md
中的常见陷阱) - [ ] 如果发现规范差异,用
⚠️注释
将图写入文件。 选择从协议名称派生的文件名,例如 noise-xx-handshake.md 或 x3dh-key-agreement.md。写入具有以下结构的 Markdown 文件:
# <协议名称> 序列图
\`\`\`mermaid
sequenceDiagram
...
\`\`\`
## 协议摘要
- **参与方:** ...
- **轮次复杂度:** ...
- **关键原语:** ...
- **认证:** ...
- **前向保密性:** ...
- **注意:** [规范偏差或安全观察,或“无”]
写入文件后,在响应中内联打印一个 ASCII 序列图,后跟协议摘要。说明输出文件名,以便用户知道在哪里找到 Mermaid 源文件。
遵循
references/ascii-sequence-diagram.md
中的所有绘图约定,包括内联输出格式。
决策树
── 输入是规范文档(不是代码)?
│ └─ 步骤 S1:识别格式,阅读 references/spec-parsing-patterns.md
│
── 输入是源代码(不是规范)?
│ └─ 步骤 1:grep 搜索握手/轮次/发送/接收入口点
│
── 同时提供了规范和代码?
│ └─ 先运行规范工作流(S1–S5)构建规范图,
│ 然后阅读代码并用 ⚠️ 注释差异
│
── 规范是已知协议(TLS、Noise、Signal、X3DH、FROST)?
│ └─ 阅读 references/protocol-patterns.md 并使用规范流程作为骨架
│
── 规范是 ProVerif (.pv) 或 Tamarin (.spthy)?
│ └─ 阅读 references/spec-parsing-patterns.md → 形式化模型部分
│
── 规范消息顺序不明确?
│ └─ 从轮次/章节结构推断,用 ⚠️ 注释
│
── 无法从规范中识别参与方?
│ └─ 检查“Parties”/“Notation”部分;对于 ProVerif 读取进程名;
│ 对于 Tamarin 读取规则名和事实参数
│
── 不知道哪些代码文件实现了协议?
│ └─ 步骤 1:grep 搜索握手/轮次/发送/接收入口点
│
── 无法从结构体名称中识别参与方?
│ └─ 读取测试文件——测试设置揭示了角色
│
── 协议在进程内运行(没有网络调用)?
│ └─ 将角色边界处的函数参数传递视为消息
│
── MPC / 阈值协议,有 N 个参与方?
│ └─ 阅读 references/protocol-patterns.md → MPC 部分
│
── Mermaid 语法错误?
│ └─ 阅读 references/mermaid-sequence-syntax.md → 常见陷阱
│
└─ ASCII 绘图约定?
└─ 阅读 references/ascii-sequence-diagram.md
示例
代码路径 — examples/simple-handshake/:
protocol.py— 两方认证密钥交换(X25519 DH + Ed25519 签名 + HKDF + ChaCha20-Poly1305)expected-output.md— 该技能应为该协议生成的精确 ASCII 图和 Mermaid 文件
规范路径(ProVerif) — examples/simple-proverif/:
model.pv— 在 ProVerif 中建模的 HMAC 挑战-响应认证expected-output.md— 逐步提取演练(参与方、消息流、密码学操作)以及该技能应生成的精确 ASCII 图和 Mermaid 文件
在处理不熟悉的输入之前,先研究相关示例。
支持文档
- references/spec-parsing-patterns.md —
RFC、学术论文/伪代码、非正式描述、ProVerif 和 Tamarin 输入格式的提取规则;在步骤 S1 期间阅读 - references/mermaid-sequence-syntax.md —
参与者语法、箭头类型、激活、分组块、转义规则和常见渲染陷阱 - references/protocol-patterns.md —
TLS 1.3、Noise、X3DH、Double Ratchet、Shamir 秘密共享、承诺-揭示和通用 MPC 轮次的规范消息流;在将实现与规范进行比较时用作参考 - references/ascii-sequence-diagram.md —
列布局、箭头约定、自循环、阶段标签和 ASCII 图的内联输出格式






