[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-trail-of-bits-mermaid-to-proverif":3,"mdc--n8tbr0-key":35,"related-org-trail-of-bits-mermaid-to-proverif":2570,"related-repo-trail-of-bits-mermaid-to-proverif":2725},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":30,"sourceUrl":33,"mdContent":34},"mermaid-to-proverif","translate Mermaid diagrams to ProVerif models","Translates Mermaid sequenceDiagrams describing cryptographic protocols into ProVerif formal verification models (.pv files). Use when generating a ProVerif model, formally verifying a protocol, converting a Mermaid diagram to ProVerif, verifying protocol security properties (secrecy, authentication, forward secrecy), checking for replay attacks, or producing a .pv file from a sequence diagram.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"trail-of-bits","Trail of Bits","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Ftrail-of-bits.png","trailofbits",[13,17,20],{"name":14,"slug":15,"type":16},"Security","security","tag",{"name":18,"slug":19,"type":16},"Cryptography","cryptography",{"name":21,"slug":22,"type":16},"Code Analysis","code-analysis",6139,"https:\u002F\u002Fgithub.com\u002Ftrailofbits\u002Fskills","2026-07-18T05:47:30.927618",null,541,[29],"agent-skills",{"repoUrl":24,"stars":23,"forks":27,"topics":31,"description":32},[29],"Trail of Bits Claude Code skills for security research, vulnerability detection, and audit workflows","https:\u002F\u002Fgithub.com\u002Ftrailofbits\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Ftrailmark\u002Fskills\u002Fmermaid-to-proverif","---\nname: mermaid-to-proverif\ndescription: \"Translates Mermaid sequenceDiagrams describing cryptographic protocols into ProVerif formal verification models (.pv files). Use when generating a ProVerif model, formally verifying a protocol, converting a Mermaid diagram to ProVerif, verifying protocol security properties (secrecy, authentication, forward secrecy), checking for replay attacks, or producing a .pv file from a sequence diagram.\"\n---\n\n# Mermaid to ProVerif\n\nReads a Mermaid `sequenceDiagram` describing a cryptographic protocol and\nproduces a ProVerif model (`.pv` file) that can be passed directly to the\nProVerif verifier.\n\n**Tools used:** Read, Write, Grep, Glob.\n\nThe typical input is the output of the `crypto-protocol-diagram` skill — a\nMermaid `sequenceDiagram` annotated with cryptographic operations (`Sign`,\n`Verify`, `DH`, `HKDF`, `Enc`, `Dec`, etc.) and message arrows.\n\n## When to Use\n\n- User asks to formally verify a cryptographic protocol described as a Mermaid sequenceDiagram\n- User wants to generate a ProVerif model (.pv file) from a protocol diagram\n- User wants to prove secrecy, authentication, or forward secrecy properties\n- Input is the output of the `crypto-protocol-diagram` skill\n\n## When NOT to Use\n\n- No Mermaid sequenceDiagram exists yet — use `crypto-protocol-diagram` first to generate one\n- User wants to verify properties of non-cryptographic systems (state machines, access control)\n- User wants to run ProVerif on an existing .pv file — just run `proverif model.pv` directly\n\n## Rationalizations to Reject\n\n| Rationalization | Why It's Wrong | Required Action |\n|-----------------|----------------|-----------------|\n| \"Reachability queries are just busywork\" | If events aren't reachable, all other query results are meaningless | Always add reachability queries first as a sanity check |\n| \"Public channels are fine for all messages\" | Private channels for internal state prevent false attacks | Use private channels for intra-process state threading |\n| \"I'll skip the forward secrecy test\" | Ephemeral keys demand forward secrecy verification | Add the ForwardSecrecyTest process whenever the diagram shows ephemeral keys |\n| \"Unused declarations are harmless\" | ProVerif may report spurious results from orphan declarations | Clean up all unused types, functions, and events |\n| \"The model compiles, so it's correct\" | A compiling model can have dead receives, type mismatches, or impossible guards that make queries vacuously true | Validate reachability before trusting any security query |\n| \"I don't need to check the example first\" | The example defines the expected output quality bar | Study `examples\u002Fsimple-handshake\u002F` before working on unfamiliar protocols |\n\n---\n\n## Workflow\n\n```\nProVerif Model Progress:\n- [ ] Step 1: Parse participants and channels\n- [ ] Step 2: Inventory cryptographic operations\n- [ ] Step 3: Declare types, functions, and equations\n- [ ] Step 4: Identify and declare events\n- [ ] Step 5: Formulate security queries\n- [ ] Step 6: Write participant processes\n- [ ] Step 7: Write main process and finalize\n- [ ] Step 8: Verify and deliver\n```\n\n### Step 1: Parse Participants and Channels\n\nFrom the Mermaid diagram:\n\n1. Extract every `participant` or `actor` declaration. Each becomes a\n   ProVerif process.\n2. Count message arrows (`->>`, `-->>`, `-x`, `--x`). Each distinct\n   `A ->> B: label` creates a communication step on a channel.\n3. Decide channel model:\n   - **Public channel** for any message sent over the network before a\n     secure channel is established (e.g., ClientHello, ephemeral keys,\n     ciphertext to be decrypted by the peer).\n   - **Private channel** only for internal state threading within a single\n     party process (not for cross-party messages).\n   - Default: declare one shared public channel `c` for all cross-party\n     messages. Add per-flow channels only when two distinct parallel sessions\n     must be independent.\n\n```proverif\nfree c: channel.\n```\n\n### Step 2: Inventory Cryptographic Operations\n\nWalk through every `Note over` annotation and message label. Build a list of\nall distinct operations used. Map each to a ProVerif declaration category:\n\n| Mermaid annotation | ProVerif category |\n|--------------------|-------------------|\n| `keygen() → sk, pk` | New name (`new sk`), public key derived via function |\n| `DH(sk_A, pk_B)` | DH function or `exp` with group |\n| `Sign(sk, msg) → σ` | Signature function |\n| `Verify(pk, msg, σ)` | Equation or destructor |\n| `Enc(key, msg) → ct` | Symmetric or asymmetric encryption function |\n| `Dec(key, ct) → msg` | Destructor (equation) |\n| `HKDF(ikm, info) → k` | PRF\u002FKDF function |\n| `HMAC(key, msg) → tag` | MAC function |\n| `H(msg) → digest` | Hash function |\n| `Commit(v, r) → C` | Commitment function |\n| `Open(C, v, r)` | Commitment equation |\n\nConsult [references\u002Fcrypto-to-proverif-mapping.md](references\u002Fcrypto-to-proverif-mapping.md)\nfor exact ProVerif syntax for each.\n\n### Step 3: Declare Types, Functions, and Equations\n\nBuild the cryptographic preamble in this order:\n\n1. **Types** — declare custom types used to distinguish key material:\n\n```proverif\ntype key.\ntype pkey.   (* public key *)\ntype skey.   (* secret key *)\ntype nonce.\n```\n\n2. **Constants** — for fixed strings used as domain separators or labels:\n\n```proverif\nconst msg1_label: bitstring.\nconst msg2_label: bitstring.\nconst info_session_key: bitstring.\n```\n\n3. **Functions** — constructors and destructors. Destructors use inline `reduc`\n   so that the process aborts on verification or decryption failure:\n\n```proverif\n(* Asymmetric encryption *)\nfun aenc(bitstring, pkey): bitstring.\nfun adec(bitstring, skey): bitstring\n    reduc forall m: bitstring, k: skey;\n        adec(aenc(m, pk(k)), k) = m.\nfun pk(skey): pkey.\n\n(* Symmetric encryption \u002F AEAD *)\nfun aead_enc(bitstring, key): bitstring.\nfun aead_dec(bitstring, key): bitstring\n    reduc forall m: bitstring, k: key;\n        aead_dec(aead_enc(m, k), k) = m.\n\n(* Digital signatures — verify returns the message on success, aborts on failure *)\nfun sign(bitstring, skey): bitstring.\nfun verify(bitstring, bitstring, pkey): bitstring\n    reduc forall m: bitstring, k: skey;\n        verify(sign(m, k), m, pk(k)) = m.\n\n(* KDF — first arg is key (from DH), second is bitstring (info\u002Fcontext) *)\nfun hkdf(key, bitstring): key.\n\n(* MAC *)\nfun mac(bitstring, key): bitstring.\n\n(* Hash *)\nfun hash(bitstring): bitstring.\n\n(* DH *)\nfun dh(skey, pkey): key.\nfun dhpk(skey): pkey.\n\n(* Serialization — ProVerif is strongly typed: pkey cannot appear\n * where bitstring is expected. Use these to build signed payloads. *)\nfun pkey2bs(pkey): bitstring.\nfun concat(bitstring, bitstring): bitstring.\n```\n\n4. **Equations** — algebraic identities on constructors only (not on destructors,\n   which already have their rewrite rules inline):\n\n```proverif\nequation forall sk_a: skey, sk_b: skey;\n    dh(sk_a, dhpk(sk_b)) = dh(sk_b, dhpk(sk_a)).\n```\n\nOnly declare what the diagram actually uses. Do not add functions for\noperations not present.\n\n### Step 4: Identify and Declare Events\n\nEvents mark security-relevant moments in the protocol execution. Extract them\nby identifying:\n\n- **Begin events** (`event beginRole(params)`): triggered immediately before a\n  party sends a message that depends on a long-term identity commitment (e.g.,\n  right before sending a signed message or a MAC'd message).\n- **End events** (`event endRole(params)`): triggered immediately after a party\n  successfully verifies the peer's identity (e.g., after `Verify(...)` or MAC\n  check passes, session key confirmed).\n- **Secrecy markers**: any key or nonce that should remain unknown to the\n  attacker after the handshake.\n\n```proverif\nevent beginI(pkey, pkey).     (* pk_I, pk_R — fired before sending the signed message *)\nevent endI(pkey, pkey, key).  (* pk_I, pk_R, session_key — fired after accepting *)\nevent beginR(pkey, pkey).\nevent endR(pkey, pkey, key).\n```\n\nParameters should uniquely identify the session: the parties' public keys,\nplus the session key or a transcript hash.\n\n### Step 5: Formulate Security Queries\n\nWrite one query per security property. Choose from:\n\n**Reachability (always add first — structural sanity check):**\n\nVerify that the success events are actually reachable. If ProVerif reports any\nof these as `false`, the model has a structural bug (dead receive, type mismatch,\nimpossible guard) and no other query result should be trusted. Once the model\nis validated, comment them out if they slow down the main property checks:\n\n```proverif\n(* Sanity: both endpoints must be reachable — comment out once validated. *)\n(*\nquery pk_i: pkey, pk_r: pkey, k: key; event(endI(pk_i, pk_r, k)).\nquery pk_i: pkey, pk_r: pkey, k: key; event(endR(pk_i, pk_r, k)).\n*)\n```\n\n**Secrecy** (key not derivable by attacker):\n\nDeclare a private free name and encrypt it under the session key. The attacker\nknowing `private_I` is equivalent to breaking the session key:\n\n```proverif\nfree private_I: bitstring [private].\n\n(* In process, after deriving sk_session: *)\nout(c, aead_enc(private_I, sk_session));\n\n(* Query: *)\nquery attacker(private_I).\n```\n\n**Weak authentication** (if B accepted, A ran at some point with matching\nparams — does not prevent replay):\n\n```proverif\nquery pk_i: pkey, pk_r: pkey, k: key;\n    event(endR(pk_i, pk_r, k)) ==> event(beginI(pk_i, pk_r)).\n```\n\n**Injective authentication** (prevents replay — each B-accept corresponds to\na distinct A-run):\n\n```proverif\nquery pk_i: pkey, pk_r: pkey, k: key;\n    inj-event(endR(pk_i, pk_r, k)) ==>\n    inj-event(beginI(pk_i, pk_r)).\n```\n\n**Forward secrecy**: add a `ForwardSecrecyTest` process to the main process\nthat leaks both long-term secret keys to the attacker, then check that a past\nsession key remains secret. Pair it with a `free fs_witness: key [private]`\ndeclaration and `query attacker(fs_witness)`. See\n[references\u002Fsecurity-properties.md](references\u002Fsecurity-properties.md) →\nForward Secrecy, and the worked example in\n`examples\u002Fsimple-handshake\u002Fsample-output.pv`.\n\nChoose the strongest applicable query for each property. See\n[references\u002Fsecurity-properties.md](references\u002Fsecurity-properties.md) for\nthe full decision tree.\n\n### Step 6: Write Participant Processes\n\nWrite one `let` process per participant. Structure each process to mirror the\nMermaid diagram step-by-step, in order.\n\n**Template for a two-party protocol:**\n\n```proverif\nlet Initiator(sk_I: skey, pk_R: pkey) =\n    (* Step: generate ephemeral key *)\n    new ek_I: skey;\n    let epk_I = dhpk(ek_I) in\n    (* Step: sign and send msg1 — pkey2bs casts pkey to bitstring *)\n    let sig_I = sign(concat(msg1_label, pkey2bs(epk_I)), sk_I) in\n    event beginI(pk(sk_I), pk_R);\n    out(c, (epk_I, sig_I));\n    (* Step: receive msg2 *)\n    in(c, (epk_R: pkey, sig_R: bitstring));\n    (* Step: verify responder signature — destructor aborts on failure *)\n    let transcript = concat(pkey2bs(epk_I), pkey2bs(epk_R)) in\n    let _ = verify(sig_R, concat(msg2_label, transcript), pk_R) in\n    (* Step: derive session key *)\n    let dh_val = dh(ek_I, epk_R) in\n    let sk_session = hkdf(dh_val, concat(info_session_key, transcript)) in\n    event endI(pk(sk_I), pk_R, sk_session);\n    (* Secrecy witness: encrypt private_I under the session key.\n     * Declared as: free private_I: bitstring [private].\n     * The query attacker(private_I) checks the attacker cannot derive it. *)\n    out(c, aead_enc(private_I, sk_session)).\n```\n\n**Rules for writing processes:**\n\n- Each `A ->> B: msg_contents` in the diagram becomes:\n  - `out(c, msg_contents)` in A's process\n  - `in(c, x)` (with matching destructuring) in B's process\n- Each `Note over A: op → result` becomes a `let result = op in` binding\n- Each `Note over A: Verify(...)` becomes a `let _ = verify(...) in`\n  binding (the destructor aborts on failure — no explicit else needed,\n  modeling abort)\n- Use `alt` blocks in the diagram as `if\u002Fthen\u002Felse` in the process\n- Long-term keys are process parameters; ephemeral values use `new`\n\n**N-party or MPC protocols:** write one process per distinct role. For\nthreshold protocols, write a single role process and replicate it `!N` times\nin the main process.\n\n### Step 7: Write Main Process and Finalize\n\nThe main process:\n\n1. Generates long-term keys with `new`\n2. Publishes public keys to the attacker via `out(c, pk(sk))`\n3. Runs participant processes in parallel under replication (`!`) to allow\n   multiple sessions\n4. Optionally leaks long-term keys for forward-secrecy analysis\n\n```proverif\nprocess\n    new sk_I: skey; let pk_I = pk(sk_I) in out(c, pk_I);\n    new sk_R: skey; let pk_R = pk(sk_R) in out(c, pk_R);\n    (\n        !Initiator(sk_I, pk_R)\n      | !Responder(sk_R, pk_I)\n    )\n```\n\nPlace the full file in this order:\n\n```\n(* 1. Channel declarations (free c: channel. \u002F free ch: channel [private].) *)\n(* 2. noselect directives (if needed for termination) *)\n(* 3. Type declarations *)\n(* 4. Constants *)\n(* 5. Function declarations *)\n(* 6. Equations (algebraic identities on constructors only) *)\n(* 7. Table declarations *)\n(* 8. Events *)\n(* 9. Queries *)\n(* 10. Let processes *)\n(* 11. Main process *)\n```\n\n### Step 8: Verify and Deliver\n\nBefore writing the file:\n\n- [ ] Every participant in the diagram has a matching `let` process\n- [ ] Every `out(c, ...)` has a matching `in(c, ...)` on the other side with\n      compatible types\n- [ ] Every function used in a process is declared in the preamble\n- [ ] Every destructor uses inline `reduc` (not a separate `equation` block)\n- [ ] Every event in a query is declared and triggered in a process\n- [ ] Long-term public keys are output to channel `c` in the main process\n      (attacker can see them — that is the Dolev-Yao model)\n- [ ] No unused declarations (clean up anything added speculatively)\n- [ ] If `table` declarations are present: every `insert T(...)` has a\n      corresponding `get T(...)` with compatible column types and matching\n      pattern constraints (`=key` vs bare name)\n- [ ] If `noselect` is used: its tuple structure matches the actual message\n      shapes sent on `c` (e.g., pairs → `mess(c, (x, y))`)\n- [ ] If the Key Exposure Oracle pattern is used: `event key_exposed(sk_type)`\n      is declared, the oracle `in(c, guess: sk_type); if pk(guess) = pk_new then\n      event key_exposed(guess)` appears at the end of the process that holds the\n      secret, and the query is `query x: sk_type; event(key_exposed(x))`\n\n**Write the model to a `.pv` file.** Choose a filename from the protocol name,\ne.g. `noise-xx-handshake.pv` or `x3dh-key-agreement.pv`.\n\nAfter writing, print a brief summary:\n\n```\nProtocol:   \u003CName>\nOutput:     \u003Cfilename>\nQueries:    \u003Clist each query and what property it tests>\nAssumptions: \u003Clist modeling decisions and simplifications>\n```\n\n---\n\n## Decision Tree\n\n```\n├─ No Mermaid diagram provided?\n│  └─ Ask the user: \"Please provide the Mermaid sequenceDiagram,\n│     or run the crypto-protocol-diagram skill first.\"\n│\n├─ Diagram uses DH (not just symmetric crypto)?\n│  └─ Use dh\u002Fdhpk with commutativity equation\n│     See references\u002Fcrypto-to-proverif-mapping.md → DH section\n│\n├─ Diagram uses asymmetric signatures (Sign\u002FVerify)?\n│  └─ Use sign\u002Fverify with inline reduc (not equation)\n│     verify returns the message on success; let _ = verify(...) in to abort on failure\n│     Distinguish signing key (skey) from verification key (pkey)\n│\n├─ Diagram has an \"alt\" block (abort path)?\n│  └─ Model as if\u002Fthen only — the else branch aborts (process terminates)\n│     Do NOT add out(c, error_message) unless the diagram shows it\n│\n├─ Protocol has N > 2 parties?\n│  └─ Write one process per role, use ! for replication\n│     Pass participant index as a parameter if roles differ by index only\n│\n├─ Forward secrecy requested?\n│  └─ Add a ForwardSecrecy variant in the main process that leaks\n│     long-term sk after session; add secrecy query for past session_key\n│     See references\u002Fsecurity-properties.md → Forward Secrecy\n│\n├─ Type-checker rejects the model?\n│  └─ ProVerif is typed: check every function arg type matches declaration.\n│     bitstring is the catch-all; key\u002Fpkey\u002Fskey\u002Fnonce are stricter.\n│     Cast with explicit constructors when needed.\n│\n├─ Protocol has cross-process state coordination (e.g., one process must wait\n│  for another to record acceptance before proceeding)?\n│  └─ Use ProVerif tables (table\u002Finsert\u002Fget)\n│     See references\u002Fproverif-syntax.md → Tables\n│\n├─ Verification does not terminate after several minutes?\n│  └─ Add noselect directive matching the message tuple structure on c\n│     See references\u002Fproverif-syntax.md → noselect\n│\n├─ Protocol generates a private-type key (type sk [private]) that is never\n│  output directly but whose secrecy should be verified?\n│  └─ Use the Key Exposure Oracle pattern instead of query attacker(sk)\n│     See references\u002Fsecurity-properties.md → Key Exposure Oracle\n│\n└─ Unsure which security properties to verify?\n   └─ Default set: secrecy of session key + injective authentication\n      (both directions). Add forward secrecy if diagram shows ephemeral keys.\n```\n\n---\n\n## Example\n\n`examples\u002Fsimple-handshake\u002F` contains a worked example:\n\n- **`diagram.md`** — Mermaid sequenceDiagram for a two-party authenticated key\n  exchange (X25519 DH + Ed25519 signing + HKDF)\n- **`sample-output.pv`** — exact ProVerif model the skill should produce,\n  with secrecy and injective authentication queries\n\nStudy this before working on an unfamiliar protocol.\n\n---\n\n## Supporting Documentation\n\n- **[references\u002Fcrypto-to-proverif-mapping.md](references\u002Fcrypto-to-proverif-mapping.md)** —\n  Mapping table from Mermaid cryptographic annotations to ProVerif function\n  declarations, equations, and process patterns\n- **[references\u002Fproverif-syntax.md](references\u002Fproverif-syntax.md)** —\n  ProVerif language reference: types, functions, equations, processes, events,\n  queries, and common pitfalls\n- **[references\u002Fsecurity-properties.md](references\u002Fsecurity-properties.md)** —\n  Decision guide for choosing the right queries: secrecy, authentication\n  (weak vs injective), forward secrecy, unlinkability, and how to model them\n",{"data":36,"body":37},{"name":4,"description":6},{"type":38,"children":39},"root",[40,48,71,82,147,154,186,192,225,231,380,384,390,402,409,414,522,541,547,560,785,798,804,809,822,864,877,908,929,1250,1263,1286,1291,1297,1302,1358,1397,1402,1408,1413,1421,1434,1481,1491,1504,1565,1575,1598,1608,1638,1687,1698,1704,1717,1725,1900,1908,2020,2038,2044,2049,2091,2154,2159,2168,2174,2179,2397,2428,2433,2442,2445,2451,2460,2463,2469,2479,2510,2515,2518,2524,2564],{"type":41,"tag":42,"props":43,"children":44},"element","h1",{"id":4},[45],{"type":46,"value":47},"text","Mermaid to ProVerif",{"type":41,"tag":49,"props":50,"children":51},"p",{},[52,54,61,63,69],{"type":46,"value":53},"Reads a Mermaid ",{"type":41,"tag":55,"props":56,"children":58},"code",{"className":57},[],[59],{"type":46,"value":60},"sequenceDiagram",{"type":46,"value":62}," describing a cryptographic protocol and\nproduces a ProVerif model (",{"type":41,"tag":55,"props":64,"children":66},{"className":65},[],[67],{"type":46,"value":68},".pv",{"type":46,"value":70}," file) that can be passed directly to the\nProVerif verifier.",{"type":41,"tag":49,"props":72,"children":73},{},[74,80],{"type":41,"tag":75,"props":76,"children":77},"strong",{},[78],{"type":46,"value":79},"Tools used:",{"type":46,"value":81}," Read, Write, Grep, Glob.",{"type":41,"tag":49,"props":83,"children":84},{},[85,87,93,95,100,102,108,110,116,118,124,125,131,132,138,139,145],{"type":46,"value":86},"The typical input is the output of the ",{"type":41,"tag":55,"props":88,"children":90},{"className":89},[],[91],{"type":46,"value":92},"crypto-protocol-diagram",{"type":46,"value":94}," skill — a\nMermaid ",{"type":41,"tag":55,"props":96,"children":98},{"className":97},[],[99],{"type":46,"value":60},{"type":46,"value":101}," annotated with cryptographic operations (",{"type":41,"tag":55,"props":103,"children":105},{"className":104},[],[106],{"type":46,"value":107},"Sign",{"type":46,"value":109},",\n",{"type":41,"tag":55,"props":111,"children":113},{"className":112},[],[114],{"type":46,"value":115},"Verify",{"type":46,"value":117},", ",{"type":41,"tag":55,"props":119,"children":121},{"className":120},[],[122],{"type":46,"value":123},"DH",{"type":46,"value":117},{"type":41,"tag":55,"props":126,"children":128},{"className":127},[],[129],{"type":46,"value":130},"HKDF",{"type":46,"value":117},{"type":41,"tag":55,"props":133,"children":135},{"className":134},[],[136],{"type":46,"value":137},"Enc",{"type":46,"value":117},{"type":41,"tag":55,"props":140,"children":142},{"className":141},[],[143],{"type":46,"value":144},"Dec",{"type":46,"value":146},", etc.) and message arrows.",{"type":41,"tag":148,"props":149,"children":151},"h2",{"id":150},"when-to-use",[152],{"type":46,"value":153},"When to Use",{"type":41,"tag":155,"props":156,"children":157},"ul",{},[158,164,169,174],{"type":41,"tag":159,"props":160,"children":161},"li",{},[162],{"type":46,"value":163},"User asks to formally verify a cryptographic protocol described as a Mermaid sequenceDiagram",{"type":41,"tag":159,"props":165,"children":166},{},[167],{"type":46,"value":168},"User wants to generate a ProVerif model (.pv file) from a protocol diagram",{"type":41,"tag":159,"props":170,"children":171},{},[172],{"type":46,"value":173},"User wants to prove secrecy, authentication, or forward secrecy properties",{"type":41,"tag":159,"props":175,"children":176},{},[177,179,184],{"type":46,"value":178},"Input is the output of the ",{"type":41,"tag":55,"props":180,"children":182},{"className":181},[],[183],{"type":46,"value":92},{"type":46,"value":185}," skill",{"type":41,"tag":148,"props":187,"children":189},{"id":188},"when-not-to-use",[190],{"type":46,"value":191},"When NOT to Use",{"type":41,"tag":155,"props":193,"children":194},{},[195,207,212],{"type":41,"tag":159,"props":196,"children":197},{},[198,200,205],{"type":46,"value":199},"No Mermaid sequenceDiagram exists yet — use ",{"type":41,"tag":55,"props":201,"children":203},{"className":202},[],[204],{"type":46,"value":92},{"type":46,"value":206}," first to generate one",{"type":41,"tag":159,"props":208,"children":209},{},[210],{"type":46,"value":211},"User wants to verify properties of non-cryptographic systems (state machines, access control)",{"type":41,"tag":159,"props":213,"children":214},{},[215,217,223],{"type":46,"value":216},"User wants to run ProVerif on an existing .pv file — just run ",{"type":41,"tag":55,"props":218,"children":220},{"className":219},[],[221],{"type":46,"value":222},"proverif model.pv",{"type":46,"value":224}," directly",{"type":41,"tag":148,"props":226,"children":228},{"id":227},"rationalizations-to-reject",[229],{"type":46,"value":230},"Rationalizations to Reject",{"type":41,"tag":232,"props":233,"children":234},"table",{},[235,259],{"type":41,"tag":236,"props":237,"children":238},"thead",{},[239],{"type":41,"tag":240,"props":241,"children":242},"tr",{},[243,249,254],{"type":41,"tag":244,"props":245,"children":246},"th",{},[247],{"type":46,"value":248},"Rationalization",{"type":41,"tag":244,"props":250,"children":251},{},[252],{"type":46,"value":253},"Why It's Wrong",{"type":41,"tag":244,"props":255,"children":256},{},[257],{"type":46,"value":258},"Required Action",{"type":41,"tag":260,"props":261,"children":262},"tbody",{},[263,282,300,318,336,354],{"type":41,"tag":240,"props":264,"children":265},{},[266,272,277],{"type":41,"tag":267,"props":268,"children":269},"td",{},[270],{"type":46,"value":271},"\"Reachability queries are just busywork\"",{"type":41,"tag":267,"props":273,"children":274},{},[275],{"type":46,"value":276},"If events aren't reachable, all other query results are meaningless",{"type":41,"tag":267,"props":278,"children":279},{},[280],{"type":46,"value":281},"Always add reachability queries first as a sanity check",{"type":41,"tag":240,"props":283,"children":284},{},[285,290,295],{"type":41,"tag":267,"props":286,"children":287},{},[288],{"type":46,"value":289},"\"Public channels are fine for all messages\"",{"type":41,"tag":267,"props":291,"children":292},{},[293],{"type":46,"value":294},"Private channels for internal state prevent false attacks",{"type":41,"tag":267,"props":296,"children":297},{},[298],{"type":46,"value":299},"Use private channels for intra-process state threading",{"type":41,"tag":240,"props":301,"children":302},{},[303,308,313],{"type":41,"tag":267,"props":304,"children":305},{},[306],{"type":46,"value":307},"\"I'll skip the forward secrecy test\"",{"type":41,"tag":267,"props":309,"children":310},{},[311],{"type":46,"value":312},"Ephemeral keys demand forward secrecy verification",{"type":41,"tag":267,"props":314,"children":315},{},[316],{"type":46,"value":317},"Add the ForwardSecrecyTest process whenever the diagram shows ephemeral keys",{"type":41,"tag":240,"props":319,"children":320},{},[321,326,331],{"type":41,"tag":267,"props":322,"children":323},{},[324],{"type":46,"value":325},"\"Unused declarations are harmless\"",{"type":41,"tag":267,"props":327,"children":328},{},[329],{"type":46,"value":330},"ProVerif may report spurious results from orphan declarations",{"type":41,"tag":267,"props":332,"children":333},{},[334],{"type":46,"value":335},"Clean up all unused types, functions, and events",{"type":41,"tag":240,"props":337,"children":338},{},[339,344,349],{"type":41,"tag":267,"props":340,"children":341},{},[342],{"type":46,"value":343},"\"The model compiles, so it's correct\"",{"type":41,"tag":267,"props":345,"children":346},{},[347],{"type":46,"value":348},"A compiling model can have dead receives, type mismatches, or impossible guards that make queries vacuously true",{"type":41,"tag":267,"props":350,"children":351},{},[352],{"type":46,"value":353},"Validate reachability before trusting any security query",{"type":41,"tag":240,"props":355,"children":356},{},[357,362,367],{"type":41,"tag":267,"props":358,"children":359},{},[360],{"type":46,"value":361},"\"I don't need to check the example first\"",{"type":41,"tag":267,"props":363,"children":364},{},[365],{"type":46,"value":366},"The example defines the expected output quality bar",{"type":41,"tag":267,"props":368,"children":369},{},[370,372,378],{"type":46,"value":371},"Study ",{"type":41,"tag":55,"props":373,"children":375},{"className":374},[],[376],{"type":46,"value":377},"examples\u002Fsimple-handshake\u002F",{"type":46,"value":379}," before working on unfamiliar protocols",{"type":41,"tag":381,"props":382,"children":383},"hr",{},[],{"type":41,"tag":148,"props":385,"children":387},{"id":386},"workflow",[388],{"type":46,"value":389},"Workflow",{"type":41,"tag":391,"props":392,"children":396},"pre",{"className":393,"code":395,"language":46},[394],"language-text","ProVerif Model Progress:\n- [ ] Step 1: Parse participants and channels\n- [ ] Step 2: Inventory cryptographic operations\n- [ ] Step 3: Declare types, functions, and equations\n- [ ] Step 4: Identify and declare events\n- [ ] Step 5: Formulate security queries\n- [ ] Step 6: Write participant processes\n- [ ] Step 7: Write main process and finalize\n- [ ] Step 8: Verify and deliver\n",[397],{"type":41,"tag":55,"props":398,"children":400},{"__ignoreMap":399},"",[401],{"type":46,"value":395},{"type":41,"tag":403,"props":404,"children":406},"h3",{"id":405},"step-1-parse-participants-and-channels",[407],{"type":46,"value":408},"Step 1: Parse Participants and Channels",{"type":41,"tag":49,"props":410,"children":411},{},[412],{"type":46,"value":413},"From the Mermaid diagram:",{"type":41,"tag":415,"props":416,"children":417},"ol",{},[418,439,481],{"type":41,"tag":159,"props":419,"children":420},{},[421,423,429,431,437],{"type":46,"value":422},"Extract every ",{"type":41,"tag":55,"props":424,"children":426},{"className":425},[],[427],{"type":46,"value":428},"participant",{"type":46,"value":430}," or ",{"type":41,"tag":55,"props":432,"children":434},{"className":433},[],[435],{"type":46,"value":436},"actor",{"type":46,"value":438}," declaration. Each becomes a\nProVerif process.",{"type":41,"tag":159,"props":440,"children":441},{},[442,444,450,451,457,458,464,465,471,473,479],{"type":46,"value":443},"Count message arrows (",{"type":41,"tag":55,"props":445,"children":447},{"className":446},[],[448],{"type":46,"value":449},"->>",{"type":46,"value":117},{"type":41,"tag":55,"props":452,"children":454},{"className":453},[],[455],{"type":46,"value":456},"-->>",{"type":46,"value":117},{"type":41,"tag":55,"props":459,"children":461},{"className":460},[],[462],{"type":46,"value":463},"-x",{"type":46,"value":117},{"type":41,"tag":55,"props":466,"children":468},{"className":467},[],[469],{"type":46,"value":470},"--x",{"type":46,"value":472},"). Each distinct\n",{"type":41,"tag":55,"props":474,"children":476},{"className":475},[],[477],{"type":46,"value":478},"A ->> B: label",{"type":46,"value":480}," creates a communication step on a channel.",{"type":41,"tag":159,"props":482,"children":483},{},[484,486],{"type":46,"value":485},"Decide channel model:\n",{"type":41,"tag":155,"props":487,"children":488},{},[489,499,509],{"type":41,"tag":159,"props":490,"children":491},{},[492,497],{"type":41,"tag":75,"props":493,"children":494},{},[495],{"type":46,"value":496},"Public channel",{"type":46,"value":498}," for any message sent over the network before a\nsecure channel is established (e.g., ClientHello, ephemeral keys,\nciphertext to be decrypted by the peer).",{"type":41,"tag":159,"props":500,"children":501},{},[502,507],{"type":41,"tag":75,"props":503,"children":504},{},[505],{"type":46,"value":506},"Private channel",{"type":46,"value":508}," only for internal state threading within a single\nparty process (not for cross-party messages).",{"type":41,"tag":159,"props":510,"children":511},{},[512,514,520],{"type":46,"value":513},"Default: declare one shared public channel ",{"type":41,"tag":55,"props":515,"children":517},{"className":516},[],[518],{"type":46,"value":519},"c",{"type":46,"value":521}," for all cross-party\nmessages. Add per-flow channels only when two distinct parallel sessions\nmust be independent.",{"type":41,"tag":391,"props":523,"children":527},{"className":524,"code":525,"language":526,"meta":399,"style":399},"language-proverif shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","free c: channel.\n","proverif",[528],{"type":41,"tag":55,"props":529,"children":530},{"__ignoreMap":399},[531],{"type":41,"tag":532,"props":533,"children":536},"span",{"class":534,"line":535},"line",1,[537],{"type":41,"tag":532,"props":538,"children":539},{},[540],{"type":46,"value":525},{"type":41,"tag":403,"props":542,"children":544},{"id":543},"step-2-inventory-cryptographic-operations",[545],{"type":46,"value":546},"Step 2: Inventory Cryptographic Operations",{"type":41,"tag":49,"props":548,"children":549},{},[550,552,558],{"type":46,"value":551},"Walk through every ",{"type":41,"tag":55,"props":553,"children":555},{"className":554},[],[556],{"type":46,"value":557},"Note over",{"type":46,"value":559}," annotation and message label. Build a list of\nall distinct operations used. Map each to a ProVerif declaration category:",{"type":41,"tag":232,"props":561,"children":562},{},[563,579],{"type":41,"tag":236,"props":564,"children":565},{},[566],{"type":41,"tag":240,"props":567,"children":568},{},[569,574],{"type":41,"tag":244,"props":570,"children":571},{},[572],{"type":46,"value":573},"Mermaid annotation",{"type":41,"tag":244,"props":575,"children":576},{},[577],{"type":46,"value":578},"ProVerif category",{"type":41,"tag":260,"props":580,"children":581},{},[582,607,632,649,666,683,700,717,734,751,768],{"type":41,"tag":240,"props":583,"children":584},{},[585,594],{"type":41,"tag":267,"props":586,"children":587},{},[588],{"type":41,"tag":55,"props":589,"children":591},{"className":590},[],[592],{"type":46,"value":593},"keygen() → sk, pk",{"type":41,"tag":267,"props":595,"children":596},{},[597,599,605],{"type":46,"value":598},"New name (",{"type":41,"tag":55,"props":600,"children":602},{"className":601},[],[603],{"type":46,"value":604},"new sk",{"type":46,"value":606},"), public key derived via function",{"type":41,"tag":240,"props":608,"children":609},{},[610,619],{"type":41,"tag":267,"props":611,"children":612},{},[613],{"type":41,"tag":55,"props":614,"children":616},{"className":615},[],[617],{"type":46,"value":618},"DH(sk_A, pk_B)",{"type":41,"tag":267,"props":620,"children":621},{},[622,624,630],{"type":46,"value":623},"DH function or ",{"type":41,"tag":55,"props":625,"children":627},{"className":626},[],[628],{"type":46,"value":629},"exp",{"type":46,"value":631}," with group",{"type":41,"tag":240,"props":633,"children":634},{},[635,644],{"type":41,"tag":267,"props":636,"children":637},{},[638],{"type":41,"tag":55,"props":639,"children":641},{"className":640},[],[642],{"type":46,"value":643},"Sign(sk, msg) → σ",{"type":41,"tag":267,"props":645,"children":646},{},[647],{"type":46,"value":648},"Signature function",{"type":41,"tag":240,"props":650,"children":651},{},[652,661],{"type":41,"tag":267,"props":653,"children":654},{},[655],{"type":41,"tag":55,"props":656,"children":658},{"className":657},[],[659],{"type":46,"value":660},"Verify(pk, msg, σ)",{"type":41,"tag":267,"props":662,"children":663},{},[664],{"type":46,"value":665},"Equation or destructor",{"type":41,"tag":240,"props":667,"children":668},{},[669,678],{"type":41,"tag":267,"props":670,"children":671},{},[672],{"type":41,"tag":55,"props":673,"children":675},{"className":674},[],[676],{"type":46,"value":677},"Enc(key, msg) → ct",{"type":41,"tag":267,"props":679,"children":680},{},[681],{"type":46,"value":682},"Symmetric or asymmetric encryption function",{"type":41,"tag":240,"props":684,"children":685},{},[686,695],{"type":41,"tag":267,"props":687,"children":688},{},[689],{"type":41,"tag":55,"props":690,"children":692},{"className":691},[],[693],{"type":46,"value":694},"Dec(key, ct) → msg",{"type":41,"tag":267,"props":696,"children":697},{},[698],{"type":46,"value":699},"Destructor (equation)",{"type":41,"tag":240,"props":701,"children":702},{},[703,712],{"type":41,"tag":267,"props":704,"children":705},{},[706],{"type":41,"tag":55,"props":707,"children":709},{"className":708},[],[710],{"type":46,"value":711},"HKDF(ikm, info) → k",{"type":41,"tag":267,"props":713,"children":714},{},[715],{"type":46,"value":716},"PRF\u002FKDF function",{"type":41,"tag":240,"props":718,"children":719},{},[720,729],{"type":41,"tag":267,"props":721,"children":722},{},[723],{"type":41,"tag":55,"props":724,"children":726},{"className":725},[],[727],{"type":46,"value":728},"HMAC(key, msg) → tag",{"type":41,"tag":267,"props":730,"children":731},{},[732],{"type":46,"value":733},"MAC function",{"type":41,"tag":240,"props":735,"children":736},{},[737,746],{"type":41,"tag":267,"props":738,"children":739},{},[740],{"type":41,"tag":55,"props":741,"children":743},{"className":742},[],[744],{"type":46,"value":745},"H(msg) → digest",{"type":41,"tag":267,"props":747,"children":748},{},[749],{"type":46,"value":750},"Hash function",{"type":41,"tag":240,"props":752,"children":753},{},[754,763],{"type":41,"tag":267,"props":755,"children":756},{},[757],{"type":41,"tag":55,"props":758,"children":760},{"className":759},[],[761],{"type":46,"value":762},"Commit(v, r) → C",{"type":41,"tag":267,"props":764,"children":765},{},[766],{"type":46,"value":767},"Commitment function",{"type":41,"tag":240,"props":769,"children":770},{},[771,780],{"type":41,"tag":267,"props":772,"children":773},{},[774],{"type":41,"tag":55,"props":775,"children":777},{"className":776},[],[778],{"type":46,"value":779},"Open(C, v, r)",{"type":41,"tag":267,"props":781,"children":782},{},[783],{"type":46,"value":784},"Commitment equation",{"type":41,"tag":49,"props":786,"children":787},{},[788,790,796],{"type":46,"value":789},"Consult ",{"type":41,"tag":791,"props":792,"children":794},"a",{"href":793},"references\u002Fcrypto-to-proverif-mapping.md",[795],{"type":46,"value":793},{"type":46,"value":797},"\nfor exact ProVerif syntax for each.",{"type":41,"tag":403,"props":799,"children":801},{"id":800},"step-3-declare-types-functions-and-equations",[802],{"type":46,"value":803},"Step 3: Declare Types, Functions, and Equations",{"type":41,"tag":49,"props":805,"children":806},{},[807],{"type":46,"value":808},"Build the cryptographic preamble in this order:",{"type":41,"tag":415,"props":810,"children":811},{},[812],{"type":41,"tag":159,"props":813,"children":814},{},[815,820],{"type":41,"tag":75,"props":816,"children":817},{},[818],{"type":46,"value":819},"Types",{"type":46,"value":821}," — declare custom types used to distinguish key material:",{"type":41,"tag":391,"props":823,"children":825},{"className":524,"code":824,"language":526,"meta":399,"style":399},"type key.\ntype pkey.   (* public key *)\ntype skey.   (* secret key *)\ntype nonce.\n",[826],{"type":41,"tag":55,"props":827,"children":828},{"__ignoreMap":399},[829,837,846,855],{"type":41,"tag":532,"props":830,"children":831},{"class":534,"line":535},[832],{"type":41,"tag":532,"props":833,"children":834},{},[835],{"type":46,"value":836},"type key.\n",{"type":41,"tag":532,"props":838,"children":840},{"class":534,"line":839},2,[841],{"type":41,"tag":532,"props":842,"children":843},{},[844],{"type":46,"value":845},"type pkey.   (* public key *)\n",{"type":41,"tag":532,"props":847,"children":849},{"class":534,"line":848},3,[850],{"type":41,"tag":532,"props":851,"children":852},{},[853],{"type":46,"value":854},"type skey.   (* secret key *)\n",{"type":41,"tag":532,"props":856,"children":858},{"class":534,"line":857},4,[859],{"type":41,"tag":532,"props":860,"children":861},{},[862],{"type":46,"value":863},"type nonce.\n",{"type":41,"tag":415,"props":865,"children":866},{"start":839},[867],{"type":41,"tag":159,"props":868,"children":869},{},[870,875],{"type":41,"tag":75,"props":871,"children":872},{},[873],{"type":46,"value":874},"Constants",{"type":46,"value":876}," — for fixed strings used as domain separators or labels:",{"type":41,"tag":391,"props":878,"children":880},{"className":524,"code":879,"language":526,"meta":399,"style":399},"const msg1_label: bitstring.\nconst msg2_label: bitstring.\nconst info_session_key: bitstring.\n",[881],{"type":41,"tag":55,"props":882,"children":883},{"__ignoreMap":399},[884,892,900],{"type":41,"tag":532,"props":885,"children":886},{"class":534,"line":535},[887],{"type":41,"tag":532,"props":888,"children":889},{},[890],{"type":46,"value":891},"const msg1_label: bitstring.\n",{"type":41,"tag":532,"props":893,"children":894},{"class":534,"line":839},[895],{"type":41,"tag":532,"props":896,"children":897},{},[898],{"type":46,"value":899},"const msg2_label: bitstring.\n",{"type":41,"tag":532,"props":901,"children":902},{"class":534,"line":848},[903],{"type":41,"tag":532,"props":904,"children":905},{},[906],{"type":46,"value":907},"const info_session_key: bitstring.\n",{"type":41,"tag":415,"props":909,"children":910},{"start":848},[911],{"type":41,"tag":159,"props":912,"children":913},{},[914,919,921,927],{"type":41,"tag":75,"props":915,"children":916},{},[917],{"type":46,"value":918},"Functions",{"type":46,"value":920}," — constructors and destructors. Destructors use inline ",{"type":41,"tag":55,"props":922,"children":924},{"className":923},[],[925],{"type":46,"value":926},"reduc",{"type":46,"value":928},"\nso that the process aborts on verification or decryption failure:",{"type":41,"tag":391,"props":930,"children":932},{"className":524,"code":931,"language":526,"meta":399,"style":399},"(* Asymmetric encryption *)\nfun aenc(bitstring, pkey): bitstring.\nfun adec(bitstring, skey): bitstring\n    reduc forall m: bitstring, k: skey;\n        adec(aenc(m, pk(k)), k) = m.\nfun pk(skey): pkey.\n\n(* Symmetric encryption \u002F AEAD *)\nfun aead_enc(bitstring, key): bitstring.\nfun aead_dec(bitstring, key): bitstring\n    reduc forall m: bitstring, k: key;\n        aead_dec(aead_enc(m, k), k) = m.\n\n(* Digital signatures — verify returns the message on success, aborts on failure *)\nfun sign(bitstring, skey): bitstring.\nfun verify(bitstring, bitstring, pkey): bitstring\n    reduc forall m: bitstring, k: skey;\n        verify(sign(m, k), m, pk(k)) = m.\n\n(* KDF — first arg is key (from DH), second is bitstring (info\u002Fcontext) *)\nfun hkdf(key, bitstring): key.\n\n(* MAC *)\nfun mac(bitstring, key): bitstring.\n\n(* Hash *)\nfun hash(bitstring): bitstring.\n\n(* DH *)\nfun dh(skey, pkey): key.\nfun dhpk(skey): pkey.\n\n(* Serialization — ProVerif is strongly typed: pkey cannot appear\n * where bitstring is expected. Use these to build signed payloads. *)\nfun pkey2bs(pkey): bitstring.\nfun concat(bitstring, bitstring): bitstring.\n",[933],{"type":41,"tag":55,"props":934,"children":935},{"__ignoreMap":399},[936,944,952,960,968,977,986,996,1005,1014,1023,1032,1041,1049,1058,1067,1076,1084,1093,1101,1110,1119,1127,1136,1145,1153,1162,1171,1179,1188,1197,1206,1214,1223,1232,1241],{"type":41,"tag":532,"props":937,"children":938},{"class":534,"line":535},[939],{"type":41,"tag":532,"props":940,"children":941},{},[942],{"type":46,"value":943},"(* Asymmetric encryption *)\n",{"type":41,"tag":532,"props":945,"children":946},{"class":534,"line":839},[947],{"type":41,"tag":532,"props":948,"children":949},{},[950],{"type":46,"value":951},"fun aenc(bitstring, pkey): bitstring.\n",{"type":41,"tag":532,"props":953,"children":954},{"class":534,"line":848},[955],{"type":41,"tag":532,"props":956,"children":957},{},[958],{"type":46,"value":959},"fun adec(bitstring, skey): bitstring\n",{"type":41,"tag":532,"props":961,"children":962},{"class":534,"line":857},[963],{"type":41,"tag":532,"props":964,"children":965},{},[966],{"type":46,"value":967},"    reduc forall m: bitstring, k: skey;\n",{"type":41,"tag":532,"props":969,"children":971},{"class":534,"line":970},5,[972],{"type":41,"tag":532,"props":973,"children":974},{},[975],{"type":46,"value":976},"        adec(aenc(m, pk(k)), k) = m.\n",{"type":41,"tag":532,"props":978,"children":980},{"class":534,"line":979},6,[981],{"type":41,"tag":532,"props":982,"children":983},{},[984],{"type":46,"value":985},"fun pk(skey): pkey.\n",{"type":41,"tag":532,"props":987,"children":989},{"class":534,"line":988},7,[990],{"type":41,"tag":532,"props":991,"children":993},{"emptyLinePlaceholder":992},true,[994],{"type":46,"value":995},"\n",{"type":41,"tag":532,"props":997,"children":999},{"class":534,"line":998},8,[1000],{"type":41,"tag":532,"props":1001,"children":1002},{},[1003],{"type":46,"value":1004},"(* Symmetric encryption \u002F AEAD *)\n",{"type":41,"tag":532,"props":1006,"children":1008},{"class":534,"line":1007},9,[1009],{"type":41,"tag":532,"props":1010,"children":1011},{},[1012],{"type":46,"value":1013},"fun aead_enc(bitstring, key): bitstring.\n",{"type":41,"tag":532,"props":1015,"children":1017},{"class":534,"line":1016},10,[1018],{"type":41,"tag":532,"props":1019,"children":1020},{},[1021],{"type":46,"value":1022},"fun aead_dec(bitstring, key): bitstring\n",{"type":41,"tag":532,"props":1024,"children":1026},{"class":534,"line":1025},11,[1027],{"type":41,"tag":532,"props":1028,"children":1029},{},[1030],{"type":46,"value":1031},"    reduc forall m: bitstring, k: key;\n",{"type":41,"tag":532,"props":1033,"children":1035},{"class":534,"line":1034},12,[1036],{"type":41,"tag":532,"props":1037,"children":1038},{},[1039],{"type":46,"value":1040},"        aead_dec(aead_enc(m, k), k) = m.\n",{"type":41,"tag":532,"props":1042,"children":1044},{"class":534,"line":1043},13,[1045],{"type":41,"tag":532,"props":1046,"children":1047},{"emptyLinePlaceholder":992},[1048],{"type":46,"value":995},{"type":41,"tag":532,"props":1050,"children":1052},{"class":534,"line":1051},14,[1053],{"type":41,"tag":532,"props":1054,"children":1055},{},[1056],{"type":46,"value":1057},"(* Digital signatures — verify returns the message on success, aborts on failure *)\n",{"type":41,"tag":532,"props":1059,"children":1061},{"class":534,"line":1060},15,[1062],{"type":41,"tag":532,"props":1063,"children":1064},{},[1065],{"type":46,"value":1066},"fun sign(bitstring, skey): bitstring.\n",{"type":41,"tag":532,"props":1068,"children":1070},{"class":534,"line":1069},16,[1071],{"type":41,"tag":532,"props":1072,"children":1073},{},[1074],{"type":46,"value":1075},"fun verify(bitstring, bitstring, pkey): bitstring\n",{"type":41,"tag":532,"props":1077,"children":1079},{"class":534,"line":1078},17,[1080],{"type":41,"tag":532,"props":1081,"children":1082},{},[1083],{"type":46,"value":967},{"type":41,"tag":532,"props":1085,"children":1087},{"class":534,"line":1086},18,[1088],{"type":41,"tag":532,"props":1089,"children":1090},{},[1091],{"type":46,"value":1092},"        verify(sign(m, k), m, pk(k)) = m.\n",{"type":41,"tag":532,"props":1094,"children":1096},{"class":534,"line":1095},19,[1097],{"type":41,"tag":532,"props":1098,"children":1099},{"emptyLinePlaceholder":992},[1100],{"type":46,"value":995},{"type":41,"tag":532,"props":1102,"children":1104},{"class":534,"line":1103},20,[1105],{"type":41,"tag":532,"props":1106,"children":1107},{},[1108],{"type":46,"value":1109},"(* KDF — first arg is key (from DH), second is bitstring (info\u002Fcontext) *)\n",{"type":41,"tag":532,"props":1111,"children":1113},{"class":534,"line":1112},21,[1114],{"type":41,"tag":532,"props":1115,"children":1116},{},[1117],{"type":46,"value":1118},"fun hkdf(key, bitstring): key.\n",{"type":41,"tag":532,"props":1120,"children":1122},{"class":534,"line":1121},22,[1123],{"type":41,"tag":532,"props":1124,"children":1125},{"emptyLinePlaceholder":992},[1126],{"type":46,"value":995},{"type":41,"tag":532,"props":1128,"children":1130},{"class":534,"line":1129},23,[1131],{"type":41,"tag":532,"props":1132,"children":1133},{},[1134],{"type":46,"value":1135},"(* MAC *)\n",{"type":41,"tag":532,"props":1137,"children":1139},{"class":534,"line":1138},24,[1140],{"type":41,"tag":532,"props":1141,"children":1142},{},[1143],{"type":46,"value":1144},"fun mac(bitstring, key): bitstring.\n",{"type":41,"tag":532,"props":1146,"children":1148},{"class":534,"line":1147},25,[1149],{"type":41,"tag":532,"props":1150,"children":1151},{"emptyLinePlaceholder":992},[1152],{"type":46,"value":995},{"type":41,"tag":532,"props":1154,"children":1156},{"class":534,"line":1155},26,[1157],{"type":41,"tag":532,"props":1158,"children":1159},{},[1160],{"type":46,"value":1161},"(* Hash *)\n",{"type":41,"tag":532,"props":1163,"children":1165},{"class":534,"line":1164},27,[1166],{"type":41,"tag":532,"props":1167,"children":1168},{},[1169],{"type":46,"value":1170},"fun hash(bitstring): bitstring.\n",{"type":41,"tag":532,"props":1172,"children":1174},{"class":534,"line":1173},28,[1175],{"type":41,"tag":532,"props":1176,"children":1177},{"emptyLinePlaceholder":992},[1178],{"type":46,"value":995},{"type":41,"tag":532,"props":1180,"children":1182},{"class":534,"line":1181},29,[1183],{"type":41,"tag":532,"props":1184,"children":1185},{},[1186],{"type":46,"value":1187},"(* DH *)\n",{"type":41,"tag":532,"props":1189,"children":1191},{"class":534,"line":1190},30,[1192],{"type":41,"tag":532,"props":1193,"children":1194},{},[1195],{"type":46,"value":1196},"fun dh(skey, pkey): key.\n",{"type":41,"tag":532,"props":1198,"children":1200},{"class":534,"line":1199},31,[1201],{"type":41,"tag":532,"props":1202,"children":1203},{},[1204],{"type":46,"value":1205},"fun dhpk(skey): pkey.\n",{"type":41,"tag":532,"props":1207,"children":1209},{"class":534,"line":1208},32,[1210],{"type":41,"tag":532,"props":1211,"children":1212},{"emptyLinePlaceholder":992},[1213],{"type":46,"value":995},{"type":41,"tag":532,"props":1215,"children":1217},{"class":534,"line":1216},33,[1218],{"type":41,"tag":532,"props":1219,"children":1220},{},[1221],{"type":46,"value":1222},"(* Serialization — ProVerif is strongly typed: pkey cannot appear\n",{"type":41,"tag":532,"props":1224,"children":1226},{"class":534,"line":1225},34,[1227],{"type":41,"tag":532,"props":1228,"children":1229},{},[1230],{"type":46,"value":1231}," * where bitstring is expected. Use these to build signed payloads. *)\n",{"type":41,"tag":532,"props":1233,"children":1235},{"class":534,"line":1234},35,[1236],{"type":41,"tag":532,"props":1237,"children":1238},{},[1239],{"type":46,"value":1240},"fun pkey2bs(pkey): bitstring.\n",{"type":41,"tag":532,"props":1242,"children":1244},{"class":534,"line":1243},36,[1245],{"type":41,"tag":532,"props":1246,"children":1247},{},[1248],{"type":46,"value":1249},"fun concat(bitstring, bitstring): bitstring.\n",{"type":41,"tag":415,"props":1251,"children":1252},{"start":857},[1253],{"type":41,"tag":159,"props":1254,"children":1255},{},[1256,1261],{"type":41,"tag":75,"props":1257,"children":1258},{},[1259],{"type":46,"value":1260},"Equations",{"type":46,"value":1262}," — algebraic identities on constructors only (not on destructors,\nwhich already have their rewrite rules inline):",{"type":41,"tag":391,"props":1264,"children":1266},{"className":524,"code":1265,"language":526,"meta":399,"style":399},"equation forall sk_a: skey, sk_b: skey;\n    dh(sk_a, dhpk(sk_b)) = dh(sk_b, dhpk(sk_a)).\n",[1267],{"type":41,"tag":55,"props":1268,"children":1269},{"__ignoreMap":399},[1270,1278],{"type":41,"tag":532,"props":1271,"children":1272},{"class":534,"line":535},[1273],{"type":41,"tag":532,"props":1274,"children":1275},{},[1276],{"type":46,"value":1277},"equation forall sk_a: skey, sk_b: skey;\n",{"type":41,"tag":532,"props":1279,"children":1280},{"class":534,"line":839},[1281],{"type":41,"tag":532,"props":1282,"children":1283},{},[1284],{"type":46,"value":1285},"    dh(sk_a, dhpk(sk_b)) = dh(sk_b, dhpk(sk_a)).\n",{"type":41,"tag":49,"props":1287,"children":1288},{},[1289],{"type":46,"value":1290},"Only declare what the diagram actually uses. Do not add functions for\noperations not present.",{"type":41,"tag":403,"props":1292,"children":1294},{"id":1293},"step-4-identify-and-declare-events",[1295],{"type":46,"value":1296},"Step 4: Identify and Declare Events",{"type":41,"tag":49,"props":1298,"children":1299},{},[1300],{"type":46,"value":1301},"Events mark security-relevant moments in the protocol execution. Extract them\nby identifying:",{"type":41,"tag":155,"props":1303,"children":1304},{},[1305,1323,1348],{"type":41,"tag":159,"props":1306,"children":1307},{},[1308,1313,1315,1321],{"type":41,"tag":75,"props":1309,"children":1310},{},[1311],{"type":46,"value":1312},"Begin events",{"type":46,"value":1314}," (",{"type":41,"tag":55,"props":1316,"children":1318},{"className":1317},[],[1319],{"type":46,"value":1320},"event beginRole(params)",{"type":46,"value":1322},"): triggered immediately before a\nparty sends a message that depends on a long-term identity commitment (e.g.,\nright before sending a signed message or a MAC'd message).",{"type":41,"tag":159,"props":1324,"children":1325},{},[1326,1331,1332,1338,1340,1346],{"type":41,"tag":75,"props":1327,"children":1328},{},[1329],{"type":46,"value":1330},"End events",{"type":46,"value":1314},{"type":41,"tag":55,"props":1333,"children":1335},{"className":1334},[],[1336],{"type":46,"value":1337},"event endRole(params)",{"type":46,"value":1339},"): triggered immediately after a party\nsuccessfully verifies the peer's identity (e.g., after ",{"type":41,"tag":55,"props":1341,"children":1343},{"className":1342},[],[1344],{"type":46,"value":1345},"Verify(...)",{"type":46,"value":1347}," or MAC\ncheck passes, session key confirmed).",{"type":41,"tag":159,"props":1349,"children":1350},{},[1351,1356],{"type":41,"tag":75,"props":1352,"children":1353},{},[1354],{"type":46,"value":1355},"Secrecy markers",{"type":46,"value":1357},": any key or nonce that should remain unknown to the\nattacker after the handshake.",{"type":41,"tag":391,"props":1359,"children":1361},{"className":524,"code":1360,"language":526,"meta":399,"style":399},"event beginI(pkey, pkey).     (* pk_I, pk_R — fired before sending the signed message *)\nevent endI(pkey, pkey, key).  (* pk_I, pk_R, session_key — fired after accepting *)\nevent beginR(pkey, pkey).\nevent endR(pkey, pkey, key).\n",[1362],{"type":41,"tag":55,"props":1363,"children":1364},{"__ignoreMap":399},[1365,1373,1381,1389],{"type":41,"tag":532,"props":1366,"children":1367},{"class":534,"line":535},[1368],{"type":41,"tag":532,"props":1369,"children":1370},{},[1371],{"type":46,"value":1372},"event beginI(pkey, pkey).     (* pk_I, pk_R — fired before sending the signed message *)\n",{"type":41,"tag":532,"props":1374,"children":1375},{"class":534,"line":839},[1376],{"type":41,"tag":532,"props":1377,"children":1378},{},[1379],{"type":46,"value":1380},"event endI(pkey, pkey, key).  (* pk_I, pk_R, session_key — fired after accepting *)\n",{"type":41,"tag":532,"props":1382,"children":1383},{"class":534,"line":848},[1384],{"type":41,"tag":532,"props":1385,"children":1386},{},[1387],{"type":46,"value":1388},"event beginR(pkey, pkey).\n",{"type":41,"tag":532,"props":1390,"children":1391},{"class":534,"line":857},[1392],{"type":41,"tag":532,"props":1393,"children":1394},{},[1395],{"type":46,"value":1396},"event endR(pkey, pkey, key).\n",{"type":41,"tag":49,"props":1398,"children":1399},{},[1400],{"type":46,"value":1401},"Parameters should uniquely identify the session: the parties' public keys,\nplus the session key or a transcript hash.",{"type":41,"tag":403,"props":1403,"children":1405},{"id":1404},"step-5-formulate-security-queries",[1406],{"type":46,"value":1407},"Step 5: Formulate Security Queries",{"type":41,"tag":49,"props":1409,"children":1410},{},[1411],{"type":46,"value":1412},"Write one query per security property. Choose from:",{"type":41,"tag":49,"props":1414,"children":1415},{},[1416],{"type":41,"tag":75,"props":1417,"children":1418},{},[1419],{"type":46,"value":1420},"Reachability (always add first — structural sanity check):",{"type":41,"tag":49,"props":1422,"children":1423},{},[1424,1426,1432],{"type":46,"value":1425},"Verify that the success events are actually reachable. If ProVerif reports any\nof these as ",{"type":41,"tag":55,"props":1427,"children":1429},{"className":1428},[],[1430],{"type":46,"value":1431},"false",{"type":46,"value":1433},", the model has a structural bug (dead receive, type mismatch,\nimpossible guard) and no other query result should be trusted. Once the model\nis validated, comment them out if they slow down the main property checks:",{"type":41,"tag":391,"props":1435,"children":1437},{"className":524,"code":1436,"language":526,"meta":399,"style":399},"(* Sanity: both endpoints must be reachable — comment out once validated. *)\n(*\nquery pk_i: pkey, pk_r: pkey, k: key; event(endI(pk_i, pk_r, k)).\nquery pk_i: pkey, pk_r: pkey, k: key; event(endR(pk_i, pk_r, k)).\n*)\n",[1438],{"type":41,"tag":55,"props":1439,"children":1440},{"__ignoreMap":399},[1441,1449,1457,1465,1473],{"type":41,"tag":532,"props":1442,"children":1443},{"class":534,"line":535},[1444],{"type":41,"tag":532,"props":1445,"children":1446},{},[1447],{"type":46,"value":1448},"(* Sanity: both endpoints must be reachable — comment out once validated. *)\n",{"type":41,"tag":532,"props":1450,"children":1451},{"class":534,"line":839},[1452],{"type":41,"tag":532,"props":1453,"children":1454},{},[1455],{"type":46,"value":1456},"(*\n",{"type":41,"tag":532,"props":1458,"children":1459},{"class":534,"line":848},[1460],{"type":41,"tag":532,"props":1461,"children":1462},{},[1463],{"type":46,"value":1464},"query pk_i: pkey, pk_r: pkey, k: key; event(endI(pk_i, pk_r, k)).\n",{"type":41,"tag":532,"props":1466,"children":1467},{"class":534,"line":857},[1468],{"type":41,"tag":532,"props":1469,"children":1470},{},[1471],{"type":46,"value":1472},"query pk_i: pkey, pk_r: pkey, k: key; event(endR(pk_i, pk_r, k)).\n",{"type":41,"tag":532,"props":1474,"children":1475},{"class":534,"line":970},[1476],{"type":41,"tag":532,"props":1477,"children":1478},{},[1479],{"type":46,"value":1480},"*)\n",{"type":41,"tag":49,"props":1482,"children":1483},{},[1484,1489],{"type":41,"tag":75,"props":1485,"children":1486},{},[1487],{"type":46,"value":1488},"Secrecy",{"type":46,"value":1490}," (key not derivable by attacker):",{"type":41,"tag":49,"props":1492,"children":1493},{},[1494,1496,1502],{"type":46,"value":1495},"Declare a private free name and encrypt it under the session key. The attacker\nknowing ",{"type":41,"tag":55,"props":1497,"children":1499},{"className":1498},[],[1500],{"type":46,"value":1501},"private_I",{"type":46,"value":1503}," is equivalent to breaking the session key:",{"type":41,"tag":391,"props":1505,"children":1507},{"className":524,"code":1506,"language":526,"meta":399,"style":399},"free private_I: bitstring [private].\n\n(* In process, after deriving sk_session: *)\nout(c, aead_enc(private_I, sk_session));\n\n(* Query: *)\nquery attacker(private_I).\n",[1508],{"type":41,"tag":55,"props":1509,"children":1510},{"__ignoreMap":399},[1511,1519,1526,1534,1542,1549,1557],{"type":41,"tag":532,"props":1512,"children":1513},{"class":534,"line":535},[1514],{"type":41,"tag":532,"props":1515,"children":1516},{},[1517],{"type":46,"value":1518},"free private_I: bitstring [private].\n",{"type":41,"tag":532,"props":1520,"children":1521},{"class":534,"line":839},[1522],{"type":41,"tag":532,"props":1523,"children":1524},{"emptyLinePlaceholder":992},[1525],{"type":46,"value":995},{"type":41,"tag":532,"props":1527,"children":1528},{"class":534,"line":848},[1529],{"type":41,"tag":532,"props":1530,"children":1531},{},[1532],{"type":46,"value":1533},"(* In process, after deriving sk_session: *)\n",{"type":41,"tag":532,"props":1535,"children":1536},{"class":534,"line":857},[1537],{"type":41,"tag":532,"props":1538,"children":1539},{},[1540],{"type":46,"value":1541},"out(c, aead_enc(private_I, sk_session));\n",{"type":41,"tag":532,"props":1543,"children":1544},{"class":534,"line":970},[1545],{"type":41,"tag":532,"props":1546,"children":1547},{"emptyLinePlaceholder":992},[1548],{"type":46,"value":995},{"type":41,"tag":532,"props":1550,"children":1551},{"class":534,"line":979},[1552],{"type":41,"tag":532,"props":1553,"children":1554},{},[1555],{"type":46,"value":1556},"(* Query: *)\n",{"type":41,"tag":532,"props":1558,"children":1559},{"class":534,"line":988},[1560],{"type":41,"tag":532,"props":1561,"children":1562},{},[1563],{"type":46,"value":1564},"query attacker(private_I).\n",{"type":41,"tag":49,"props":1566,"children":1567},{},[1568,1573],{"type":41,"tag":75,"props":1569,"children":1570},{},[1571],{"type":46,"value":1572},"Weak authentication",{"type":46,"value":1574}," (if B accepted, A ran at some point with matching\nparams — does not prevent replay):",{"type":41,"tag":391,"props":1576,"children":1578},{"className":524,"code":1577,"language":526,"meta":399,"style":399},"query pk_i: pkey, pk_r: pkey, k: key;\n    event(endR(pk_i, pk_r, k)) ==> event(beginI(pk_i, pk_r)).\n",[1579],{"type":41,"tag":55,"props":1580,"children":1581},{"__ignoreMap":399},[1582,1590],{"type":41,"tag":532,"props":1583,"children":1584},{"class":534,"line":535},[1585],{"type":41,"tag":532,"props":1586,"children":1587},{},[1588],{"type":46,"value":1589},"query pk_i: pkey, pk_r: pkey, k: key;\n",{"type":41,"tag":532,"props":1591,"children":1592},{"class":534,"line":839},[1593],{"type":41,"tag":532,"props":1594,"children":1595},{},[1596],{"type":46,"value":1597},"    event(endR(pk_i, pk_r, k)) ==> event(beginI(pk_i, pk_r)).\n",{"type":41,"tag":49,"props":1599,"children":1600},{},[1601,1606],{"type":41,"tag":75,"props":1602,"children":1603},{},[1604],{"type":46,"value":1605},"Injective authentication",{"type":46,"value":1607}," (prevents replay — each B-accept corresponds to\na distinct A-run):",{"type":41,"tag":391,"props":1609,"children":1611},{"className":524,"code":1610,"language":526,"meta":399,"style":399},"query pk_i: pkey, pk_r: pkey, k: key;\n    inj-event(endR(pk_i, pk_r, k)) ==>\n    inj-event(beginI(pk_i, pk_r)).\n",[1612],{"type":41,"tag":55,"props":1613,"children":1614},{"__ignoreMap":399},[1615,1622,1630],{"type":41,"tag":532,"props":1616,"children":1617},{"class":534,"line":535},[1618],{"type":41,"tag":532,"props":1619,"children":1620},{},[1621],{"type":46,"value":1589},{"type":41,"tag":532,"props":1623,"children":1624},{"class":534,"line":839},[1625],{"type":41,"tag":532,"props":1626,"children":1627},{},[1628],{"type":46,"value":1629},"    inj-event(endR(pk_i, pk_r, k)) ==>\n",{"type":41,"tag":532,"props":1631,"children":1632},{"class":534,"line":848},[1633],{"type":41,"tag":532,"props":1634,"children":1635},{},[1636],{"type":46,"value":1637},"    inj-event(beginI(pk_i, pk_r)).\n",{"type":41,"tag":49,"props":1639,"children":1640},{},[1641,1646,1648,1654,1656,1662,1664,1670,1672,1677,1679,1685],{"type":41,"tag":75,"props":1642,"children":1643},{},[1644],{"type":46,"value":1645},"Forward secrecy",{"type":46,"value":1647},": add a ",{"type":41,"tag":55,"props":1649,"children":1651},{"className":1650},[],[1652],{"type":46,"value":1653},"ForwardSecrecyTest",{"type":46,"value":1655}," process to the main process\nthat leaks both long-term secret keys to the attacker, then check that a past\nsession key remains secret. Pair it with a ",{"type":41,"tag":55,"props":1657,"children":1659},{"className":1658},[],[1660],{"type":46,"value":1661},"free fs_witness: key [private]",{"type":46,"value":1663},"\ndeclaration and ",{"type":41,"tag":55,"props":1665,"children":1667},{"className":1666},[],[1668],{"type":46,"value":1669},"query attacker(fs_witness)",{"type":46,"value":1671},". See\n",{"type":41,"tag":791,"props":1673,"children":1675},{"href":1674},"references\u002Fsecurity-properties.md",[1676],{"type":46,"value":1674},{"type":46,"value":1678}," →\nForward Secrecy, and the worked example in\n",{"type":41,"tag":55,"props":1680,"children":1682},{"className":1681},[],[1683],{"type":46,"value":1684},"examples\u002Fsimple-handshake\u002Fsample-output.pv",{"type":46,"value":1686},".",{"type":41,"tag":49,"props":1688,"children":1689},{},[1690,1692,1696],{"type":46,"value":1691},"Choose the strongest applicable query for each property. See\n",{"type":41,"tag":791,"props":1693,"children":1694},{"href":1674},[1695],{"type":46,"value":1674},{"type":46,"value":1697}," for\nthe full decision tree.",{"type":41,"tag":403,"props":1699,"children":1701},{"id":1700},"step-6-write-participant-processes",[1702],{"type":46,"value":1703},"Step 6: Write Participant Processes",{"type":41,"tag":49,"props":1705,"children":1706},{},[1707,1709,1715],{"type":46,"value":1708},"Write one ",{"type":41,"tag":55,"props":1710,"children":1712},{"className":1711},[],[1713],{"type":46,"value":1714},"let",{"type":46,"value":1716}," process per participant. Structure each process to mirror the\nMermaid diagram step-by-step, in order.",{"type":41,"tag":49,"props":1718,"children":1719},{},[1720],{"type":41,"tag":75,"props":1721,"children":1722},{},[1723],{"type":46,"value":1724},"Template for a two-party protocol:",{"type":41,"tag":391,"props":1726,"children":1728},{"className":524,"code":1727,"language":526,"meta":399,"style":399},"let Initiator(sk_I: skey, pk_R: pkey) =\n    (* Step: generate ephemeral key *)\n    new ek_I: skey;\n    let epk_I = dhpk(ek_I) in\n    (* Step: sign and send msg1 — pkey2bs casts pkey to bitstring *)\n    let sig_I = sign(concat(msg1_label, pkey2bs(epk_I)), sk_I) in\n    event beginI(pk(sk_I), pk_R);\n    out(c, (epk_I, sig_I));\n    (* Step: receive msg2 *)\n    in(c, (epk_R: pkey, sig_R: bitstring));\n    (* Step: verify responder signature — destructor aborts on failure *)\n    let transcript = concat(pkey2bs(epk_I), pkey2bs(epk_R)) in\n    let _ = verify(sig_R, concat(msg2_label, transcript), pk_R) in\n    (* Step: derive session key *)\n    let dh_val = dh(ek_I, epk_R) in\n    let sk_session = hkdf(dh_val, concat(info_session_key, transcript)) in\n    event endI(pk(sk_I), pk_R, sk_session);\n    (* Secrecy witness: encrypt private_I under the session key.\n     * Declared as: free private_I: bitstring [private].\n     * The query attacker(private_I) checks the attacker cannot derive it. *)\n    out(c, aead_enc(private_I, sk_session)).\n",[1729],{"type":41,"tag":55,"props":1730,"children":1731},{"__ignoreMap":399},[1732,1740,1748,1756,1764,1772,1780,1788,1796,1804,1812,1820,1828,1836,1844,1852,1860,1868,1876,1884,1892],{"type":41,"tag":532,"props":1733,"children":1734},{"class":534,"line":535},[1735],{"type":41,"tag":532,"props":1736,"children":1737},{},[1738],{"type":46,"value":1739},"let Initiator(sk_I: skey, pk_R: pkey) =\n",{"type":41,"tag":532,"props":1741,"children":1742},{"class":534,"line":839},[1743],{"type":41,"tag":532,"props":1744,"children":1745},{},[1746],{"type":46,"value":1747},"    (* Step: generate ephemeral key *)\n",{"type":41,"tag":532,"props":1749,"children":1750},{"class":534,"line":848},[1751],{"type":41,"tag":532,"props":1752,"children":1753},{},[1754],{"type":46,"value":1755},"    new ek_I: skey;\n",{"type":41,"tag":532,"props":1757,"children":1758},{"class":534,"line":857},[1759],{"type":41,"tag":532,"props":1760,"children":1761},{},[1762],{"type":46,"value":1763},"    let epk_I = dhpk(ek_I) in\n",{"type":41,"tag":532,"props":1765,"children":1766},{"class":534,"line":970},[1767],{"type":41,"tag":532,"props":1768,"children":1769},{},[1770],{"type":46,"value":1771},"    (* Step: sign and send msg1 — pkey2bs casts pkey to bitstring *)\n",{"type":41,"tag":532,"props":1773,"children":1774},{"class":534,"line":979},[1775],{"type":41,"tag":532,"props":1776,"children":1777},{},[1778],{"type":46,"value":1779},"    let sig_I = sign(concat(msg1_label, pkey2bs(epk_I)), sk_I) in\n",{"type":41,"tag":532,"props":1781,"children":1782},{"class":534,"line":988},[1783],{"type":41,"tag":532,"props":1784,"children":1785},{},[1786],{"type":46,"value":1787},"    event beginI(pk(sk_I), pk_R);\n",{"type":41,"tag":532,"props":1789,"children":1790},{"class":534,"line":998},[1791],{"type":41,"tag":532,"props":1792,"children":1793},{},[1794],{"type":46,"value":1795},"    out(c, (epk_I, sig_I));\n",{"type":41,"tag":532,"props":1797,"children":1798},{"class":534,"line":1007},[1799],{"type":41,"tag":532,"props":1800,"children":1801},{},[1802],{"type":46,"value":1803},"    (* Step: receive msg2 *)\n",{"type":41,"tag":532,"props":1805,"children":1806},{"class":534,"line":1016},[1807],{"type":41,"tag":532,"props":1808,"children":1809},{},[1810],{"type":46,"value":1811},"    in(c, (epk_R: pkey, sig_R: bitstring));\n",{"type":41,"tag":532,"props":1813,"children":1814},{"class":534,"line":1025},[1815],{"type":41,"tag":532,"props":1816,"children":1817},{},[1818],{"type":46,"value":1819},"    (* Step: verify responder signature — destructor aborts on failure *)\n",{"type":41,"tag":532,"props":1821,"children":1822},{"class":534,"line":1034},[1823],{"type":41,"tag":532,"props":1824,"children":1825},{},[1826],{"type":46,"value":1827},"    let transcript = concat(pkey2bs(epk_I), pkey2bs(epk_R)) in\n",{"type":41,"tag":532,"props":1829,"children":1830},{"class":534,"line":1043},[1831],{"type":41,"tag":532,"props":1832,"children":1833},{},[1834],{"type":46,"value":1835},"    let _ = verify(sig_R, concat(msg2_label, transcript), pk_R) in\n",{"type":41,"tag":532,"props":1837,"children":1838},{"class":534,"line":1051},[1839],{"type":41,"tag":532,"props":1840,"children":1841},{},[1842],{"type":46,"value":1843},"    (* Step: derive session key *)\n",{"type":41,"tag":532,"props":1845,"children":1846},{"class":534,"line":1060},[1847],{"type":41,"tag":532,"props":1848,"children":1849},{},[1850],{"type":46,"value":1851},"    let dh_val = dh(ek_I, epk_R) in\n",{"type":41,"tag":532,"props":1853,"children":1854},{"class":534,"line":1069},[1855],{"type":41,"tag":532,"props":1856,"children":1857},{},[1858],{"type":46,"value":1859},"    let sk_session = hkdf(dh_val, concat(info_session_key, transcript)) in\n",{"type":41,"tag":532,"props":1861,"children":1862},{"class":534,"line":1078},[1863],{"type":41,"tag":532,"props":1864,"children":1865},{},[1866],{"type":46,"value":1867},"    event endI(pk(sk_I), pk_R, sk_session);\n",{"type":41,"tag":532,"props":1869,"children":1870},{"class":534,"line":1086},[1871],{"type":41,"tag":532,"props":1872,"children":1873},{},[1874],{"type":46,"value":1875},"    (* Secrecy witness: encrypt private_I under the session key.\n",{"type":41,"tag":532,"props":1877,"children":1878},{"class":534,"line":1095},[1879],{"type":41,"tag":532,"props":1880,"children":1881},{},[1882],{"type":46,"value":1883},"     * Declared as: free private_I: bitstring [private].\n",{"type":41,"tag":532,"props":1885,"children":1886},{"class":534,"line":1103},[1887],{"type":41,"tag":532,"props":1888,"children":1889},{},[1890],{"type":46,"value":1891},"     * The query attacker(private_I) checks the attacker cannot derive it. *)\n",{"type":41,"tag":532,"props":1893,"children":1894},{"class":534,"line":1112},[1895],{"type":41,"tag":532,"props":1896,"children":1897},{},[1898],{"type":46,"value":1899},"    out(c, aead_enc(private_I, sk_session)).\n",{"type":41,"tag":49,"props":1901,"children":1902},{},[1903],{"type":41,"tag":75,"props":1904,"children":1905},{},[1906],{"type":46,"value":1907},"Rules for writing processes:",{"type":41,"tag":155,"props":1909,"children":1910},{},[1911,1949,1969,1988,2009],{"type":41,"tag":159,"props":1912,"children":1913},{},[1914,1916,1922,1924],{"type":46,"value":1915},"Each ",{"type":41,"tag":55,"props":1917,"children":1919},{"className":1918},[],[1920],{"type":46,"value":1921},"A ->> B: msg_contents",{"type":46,"value":1923}," in the diagram becomes:\n",{"type":41,"tag":155,"props":1925,"children":1926},{},[1927,1938],{"type":41,"tag":159,"props":1928,"children":1929},{},[1930,1936],{"type":41,"tag":55,"props":1931,"children":1933},{"className":1932},[],[1934],{"type":46,"value":1935},"out(c, msg_contents)",{"type":46,"value":1937}," in A's process",{"type":41,"tag":159,"props":1939,"children":1940},{},[1941,1947],{"type":41,"tag":55,"props":1942,"children":1944},{"className":1943},[],[1945],{"type":46,"value":1946},"in(c, x)",{"type":46,"value":1948}," (with matching destructuring) in B's process",{"type":41,"tag":159,"props":1950,"children":1951},{},[1952,1953,1959,1961,1967],{"type":46,"value":1915},{"type":41,"tag":55,"props":1954,"children":1956},{"className":1955},[],[1957],{"type":46,"value":1958},"Note over A: op → result",{"type":46,"value":1960}," becomes a ",{"type":41,"tag":55,"props":1962,"children":1964},{"className":1963},[],[1965],{"type":46,"value":1966},"let result = op in",{"type":46,"value":1968}," binding",{"type":41,"tag":159,"props":1970,"children":1971},{},[1972,1973,1979,1980,1986],{"type":46,"value":1915},{"type":41,"tag":55,"props":1974,"children":1976},{"className":1975},[],[1977],{"type":46,"value":1978},"Note over A: Verify(...)",{"type":46,"value":1960},{"type":41,"tag":55,"props":1981,"children":1983},{"className":1982},[],[1984],{"type":46,"value":1985},"let _ = verify(...) in",{"type":46,"value":1987},"\nbinding (the destructor aborts on failure — no explicit else needed,\nmodeling abort)",{"type":41,"tag":159,"props":1989,"children":1990},{},[1991,1993,1999,2001,2007],{"type":46,"value":1992},"Use ",{"type":41,"tag":55,"props":1994,"children":1996},{"className":1995},[],[1997],{"type":46,"value":1998},"alt",{"type":46,"value":2000}," blocks in the diagram as ",{"type":41,"tag":55,"props":2002,"children":2004},{"className":2003},[],[2005],{"type":46,"value":2006},"if\u002Fthen\u002Felse",{"type":46,"value":2008}," in the process",{"type":41,"tag":159,"props":2010,"children":2011},{},[2012,2014],{"type":46,"value":2013},"Long-term keys are process parameters; ephemeral values use ",{"type":41,"tag":55,"props":2015,"children":2017},{"className":2016},[],[2018],{"type":46,"value":2019},"new",{"type":41,"tag":49,"props":2021,"children":2022},{},[2023,2028,2030,2036],{"type":41,"tag":75,"props":2024,"children":2025},{},[2026],{"type":46,"value":2027},"N-party or MPC protocols:",{"type":46,"value":2029}," write one process per distinct role. For\nthreshold protocols, write a single role process and replicate it ",{"type":41,"tag":55,"props":2031,"children":2033},{"className":2032},[],[2034],{"type":46,"value":2035},"!N",{"type":46,"value":2037}," times\nin the main process.",{"type":41,"tag":403,"props":2039,"children":2041},{"id":2040},"step-7-write-main-process-and-finalize",[2042],{"type":46,"value":2043},"Step 7: Write Main Process and Finalize",{"type":41,"tag":49,"props":2045,"children":2046},{},[2047],{"type":46,"value":2048},"The main process:",{"type":41,"tag":415,"props":2050,"children":2051},{},[2052,2062,2073,2086],{"type":41,"tag":159,"props":2053,"children":2054},{},[2055,2057],{"type":46,"value":2056},"Generates long-term keys with ",{"type":41,"tag":55,"props":2058,"children":2060},{"className":2059},[],[2061],{"type":46,"value":2019},{"type":41,"tag":159,"props":2063,"children":2064},{},[2065,2067],{"type":46,"value":2066},"Publishes public keys to the attacker via ",{"type":41,"tag":55,"props":2068,"children":2070},{"className":2069},[],[2071],{"type":46,"value":2072},"out(c, pk(sk))",{"type":41,"tag":159,"props":2074,"children":2075},{},[2076,2078,2084],{"type":46,"value":2077},"Runs participant processes in parallel under replication (",{"type":41,"tag":55,"props":2079,"children":2081},{"className":2080},[],[2082],{"type":46,"value":2083},"!",{"type":46,"value":2085},") to allow\nmultiple sessions",{"type":41,"tag":159,"props":2087,"children":2088},{},[2089],{"type":46,"value":2090},"Optionally leaks long-term keys for forward-secrecy analysis",{"type":41,"tag":391,"props":2092,"children":2094},{"className":524,"code":2093,"language":526,"meta":399,"style":399},"process\n    new sk_I: skey; let pk_I = pk(sk_I) in out(c, pk_I);\n    new sk_R: skey; let pk_R = pk(sk_R) in out(c, pk_R);\n    (\n        !Initiator(sk_I, pk_R)\n      | !Responder(sk_R, pk_I)\n    )\n",[2095],{"type":41,"tag":55,"props":2096,"children":2097},{"__ignoreMap":399},[2098,2106,2114,2122,2130,2138,2146],{"type":41,"tag":532,"props":2099,"children":2100},{"class":534,"line":535},[2101],{"type":41,"tag":532,"props":2102,"children":2103},{},[2104],{"type":46,"value":2105},"process\n",{"type":41,"tag":532,"props":2107,"children":2108},{"class":534,"line":839},[2109],{"type":41,"tag":532,"props":2110,"children":2111},{},[2112],{"type":46,"value":2113},"    new sk_I: skey; let pk_I = pk(sk_I) in out(c, pk_I);\n",{"type":41,"tag":532,"props":2115,"children":2116},{"class":534,"line":848},[2117],{"type":41,"tag":532,"props":2118,"children":2119},{},[2120],{"type":46,"value":2121},"    new sk_R: skey; let pk_R = pk(sk_R) in out(c, pk_R);\n",{"type":41,"tag":532,"props":2123,"children":2124},{"class":534,"line":857},[2125],{"type":41,"tag":532,"props":2126,"children":2127},{},[2128],{"type":46,"value":2129},"    (\n",{"type":41,"tag":532,"props":2131,"children":2132},{"class":534,"line":970},[2133],{"type":41,"tag":532,"props":2134,"children":2135},{},[2136],{"type":46,"value":2137},"        !Initiator(sk_I, pk_R)\n",{"type":41,"tag":532,"props":2139,"children":2140},{"class":534,"line":979},[2141],{"type":41,"tag":532,"props":2142,"children":2143},{},[2144],{"type":46,"value":2145},"      | !Responder(sk_R, pk_I)\n",{"type":41,"tag":532,"props":2147,"children":2148},{"class":534,"line":988},[2149],{"type":41,"tag":532,"props":2150,"children":2151},{},[2152],{"type":46,"value":2153},"    )\n",{"type":41,"tag":49,"props":2155,"children":2156},{},[2157],{"type":46,"value":2158},"Place the full file in this order:",{"type":41,"tag":391,"props":2160,"children":2163},{"className":2161,"code":2162,"language":46},[394],"(* 1. Channel declarations (free c: channel. \u002F free ch: channel [private].) *)\n(* 2. noselect directives (if needed for termination) *)\n(* 3. Type declarations *)\n(* 4. Constants *)\n(* 5. Function declarations *)\n(* 6. Equations (algebraic identities on constructors only) *)\n(* 7. Table declarations *)\n(* 8. Events *)\n(* 9. Queries *)\n(* 10. Let processes *)\n(* 11. Main process *)\n",[2164],{"type":41,"tag":55,"props":2165,"children":2166},{"__ignoreMap":399},[2167],{"type":46,"value":2162},{"type":41,"tag":403,"props":2169,"children":2171},{"id":2170},"step-8-verify-and-deliver",[2172],{"type":46,"value":2173},"Step 8: Verify and Deliver",{"type":41,"tag":49,"props":2175,"children":2176},{},[2177],{"type":46,"value":2178},"Before writing the file:",{"type":41,"tag":155,"props":2180,"children":2183},{"className":2181},[2182],"contains-task-list",[2184,2203,2228,2237,2261,2270,2286,2295,2335,2366],{"type":41,"tag":159,"props":2185,"children":2188},{"className":2186},[2187],"task-list-item",[2189,2194,2196,2201],{"type":41,"tag":2190,"props":2191,"children":2193},"input",{"disabled":992,"type":2192},"checkbox",[],{"type":46,"value":2195}," Every participant in the diagram has a matching ",{"type":41,"tag":55,"props":2197,"children":2199},{"className":2198},[],[2200],{"type":46,"value":1714},{"type":46,"value":2202}," process",{"type":41,"tag":159,"props":2204,"children":2206},{"className":2205},[2187],[2207,2210,2212,2218,2220,2226],{"type":41,"tag":2190,"props":2208,"children":2209},{"disabled":992,"type":2192},[],{"type":46,"value":2211}," Every ",{"type":41,"tag":55,"props":2213,"children":2215},{"className":2214},[],[2216],{"type":46,"value":2217},"out(c, ...)",{"type":46,"value":2219}," has a matching ",{"type":41,"tag":55,"props":2221,"children":2223},{"className":2222},[],[2224],{"type":46,"value":2225},"in(c, ...)",{"type":46,"value":2227}," on the other side with\ncompatible types",{"type":41,"tag":159,"props":2229,"children":2231},{"className":2230},[2187],[2232,2235],{"type":41,"tag":2190,"props":2233,"children":2234},{"disabled":992,"type":2192},[],{"type":46,"value":2236}," Every function used in a process is declared in the preamble",{"type":41,"tag":159,"props":2238,"children":2240},{"className":2239},[2187],[2241,2244,2246,2251,2253,2259],{"type":41,"tag":2190,"props":2242,"children":2243},{"disabled":992,"type":2192},[],{"type":46,"value":2245}," Every destructor uses inline ",{"type":41,"tag":55,"props":2247,"children":2249},{"className":2248},[],[2250],{"type":46,"value":926},{"type":46,"value":2252}," (not a separate ",{"type":41,"tag":55,"props":2254,"children":2256},{"className":2255},[],[2257],{"type":46,"value":2258},"equation",{"type":46,"value":2260}," block)",{"type":41,"tag":159,"props":2262,"children":2264},{"className":2263},[2187],[2265,2268],{"type":41,"tag":2190,"props":2266,"children":2267},{"disabled":992,"type":2192},[],{"type":46,"value":2269}," Every event in a query is declared and triggered in a process",{"type":41,"tag":159,"props":2271,"children":2273},{"className":2272},[2187],[2274,2277,2279,2284],{"type":41,"tag":2190,"props":2275,"children":2276},{"disabled":992,"type":2192},[],{"type":46,"value":2278}," Long-term public keys are output to channel ",{"type":41,"tag":55,"props":2280,"children":2282},{"className":2281},[],[2283],{"type":46,"value":519},{"type":46,"value":2285}," in the main process\n(attacker can see them — that is the Dolev-Yao model)",{"type":41,"tag":159,"props":2287,"children":2289},{"className":2288},[2187],[2290,2293],{"type":41,"tag":2190,"props":2291,"children":2292},{"disabled":992,"type":2192},[],{"type":46,"value":2294}," No unused declarations (clean up anything added speculatively)",{"type":41,"tag":159,"props":2296,"children":2298},{"className":2297},[2187],[2299,2302,2304,2309,2311,2317,2319,2325,2327,2333],{"type":41,"tag":2190,"props":2300,"children":2301},{"disabled":992,"type":2192},[],{"type":46,"value":2303}," If ",{"type":41,"tag":55,"props":2305,"children":2307},{"className":2306},[],[2308],{"type":46,"value":232},{"type":46,"value":2310}," declarations are present: every ",{"type":41,"tag":55,"props":2312,"children":2314},{"className":2313},[],[2315],{"type":46,"value":2316},"insert T(...)",{"type":46,"value":2318}," has a\ncorresponding ",{"type":41,"tag":55,"props":2320,"children":2322},{"className":2321},[],[2323],{"type":46,"value":2324},"get T(...)",{"type":46,"value":2326}," with compatible column types and matching\npattern constraints (",{"type":41,"tag":55,"props":2328,"children":2330},{"className":2329},[],[2331],{"type":46,"value":2332},"=key",{"type":46,"value":2334}," vs bare name)",{"type":41,"tag":159,"props":2336,"children":2338},{"className":2337},[2187],[2339,2342,2343,2349,2351,2356,2358,2364],{"type":41,"tag":2190,"props":2340,"children":2341},{"disabled":992,"type":2192},[],{"type":46,"value":2303},{"type":41,"tag":55,"props":2344,"children":2346},{"className":2345},[],[2347],{"type":46,"value":2348},"noselect",{"type":46,"value":2350}," is used: its tuple structure matches the actual message\nshapes sent on ",{"type":41,"tag":55,"props":2352,"children":2354},{"className":2353},[],[2355],{"type":46,"value":519},{"type":46,"value":2357}," (e.g., pairs → ",{"type":41,"tag":55,"props":2359,"children":2361},{"className":2360},[],[2362],{"type":46,"value":2363},"mess(c, (x, y))",{"type":46,"value":2365},")",{"type":41,"tag":159,"props":2367,"children":2369},{"className":2368},[2187],[2370,2373,2375,2381,2383,2389,2391],{"type":41,"tag":2190,"props":2371,"children":2372},{"disabled":992,"type":2192},[],{"type":46,"value":2374}," If the Key Exposure Oracle pattern is used: ",{"type":41,"tag":55,"props":2376,"children":2378},{"className":2377},[],[2379],{"type":46,"value":2380},"event key_exposed(sk_type)",{"type":46,"value":2382},"\nis declared, the oracle ",{"type":41,"tag":55,"props":2384,"children":2386},{"className":2385},[],[2387],{"type":46,"value":2388},"in(c, guess: sk_type); if pk(guess) = pk_new then     event key_exposed(guess)",{"type":46,"value":2390}," appears at the end of the process that holds the\nsecret, and the query is ",{"type":41,"tag":55,"props":2392,"children":2394},{"className":2393},[],[2395],{"type":46,"value":2396},"query x: sk_type; event(key_exposed(x))",{"type":41,"tag":49,"props":2398,"children":2399},{},[2400,2412,2414,2420,2421,2427],{"type":41,"tag":75,"props":2401,"children":2402},{},[2403,2405,2410],{"type":46,"value":2404},"Write the model to a ",{"type":41,"tag":55,"props":2406,"children":2408},{"className":2407},[],[2409],{"type":46,"value":68},{"type":46,"value":2411}," file.",{"type":46,"value":2413}," Choose a filename from the protocol name,\ne.g. ",{"type":41,"tag":55,"props":2415,"children":2417},{"className":2416},[],[2418],{"type":46,"value":2419},"noise-xx-handshake.pv",{"type":46,"value":430},{"type":41,"tag":55,"props":2422,"children":2424},{"className":2423},[],[2425],{"type":46,"value":2426},"x3dh-key-agreement.pv",{"type":46,"value":1686},{"type":41,"tag":49,"props":2429,"children":2430},{},[2431],{"type":46,"value":2432},"After writing, print a brief summary:",{"type":41,"tag":391,"props":2434,"children":2437},{"className":2435,"code":2436,"language":46},[394],"Protocol:   \u003CName>\nOutput:     \u003Cfilename>\nQueries:    \u003Clist each query and what property it tests>\nAssumptions: \u003Clist modeling decisions and simplifications>\n",[2438],{"type":41,"tag":55,"props":2439,"children":2440},{"__ignoreMap":399},[2441],{"type":46,"value":2436},{"type":41,"tag":381,"props":2443,"children":2444},{},[],{"type":41,"tag":148,"props":2446,"children":2448},{"id":2447},"decision-tree",[2449],{"type":46,"value":2450},"Decision Tree",{"type":41,"tag":391,"props":2452,"children":2455},{"className":2453,"code":2454,"language":46},[394],"├─ No Mermaid diagram provided?\n│  └─ Ask the user: \"Please provide the Mermaid sequenceDiagram,\n│     or run the crypto-protocol-diagram skill first.\"\n│\n├─ Diagram uses DH (not just symmetric crypto)?\n│  └─ Use dh\u002Fdhpk with commutativity equation\n│     See references\u002Fcrypto-to-proverif-mapping.md → DH section\n│\n├─ Diagram uses asymmetric signatures (Sign\u002FVerify)?\n│  └─ Use sign\u002Fverify with inline reduc (not equation)\n│     verify returns the message on success; let _ = verify(...) in to abort on failure\n│     Distinguish signing key (skey) from verification key (pkey)\n│\n├─ Diagram has an \"alt\" block (abort path)?\n│  └─ Model as if\u002Fthen only — the else branch aborts (process terminates)\n│     Do NOT add out(c, error_message) unless the diagram shows it\n│\n├─ Protocol has N > 2 parties?\n│  └─ Write one process per role, use ! for replication\n│     Pass participant index as a parameter if roles differ by index only\n│\n├─ Forward secrecy requested?\n│  └─ Add a ForwardSecrecy variant in the main process that leaks\n│     long-term sk after session; add secrecy query for past session_key\n│     See references\u002Fsecurity-properties.md → Forward Secrecy\n│\n├─ Type-checker rejects the model?\n│  └─ ProVerif is typed: check every function arg type matches declaration.\n│     bitstring is the catch-all; key\u002Fpkey\u002Fskey\u002Fnonce are stricter.\n│     Cast with explicit constructors when needed.\n│\n├─ Protocol has cross-process state coordination (e.g., one process must wait\n│  for another to record acceptance before proceeding)?\n│  └─ Use ProVerif tables (table\u002Finsert\u002Fget)\n│     See references\u002Fproverif-syntax.md → Tables\n│\n├─ Verification does not terminate after several minutes?\n│  └─ Add noselect directive matching the message tuple structure on c\n│     See references\u002Fproverif-syntax.md → noselect\n│\n├─ Protocol generates a private-type key (type sk [private]) that is never\n│  output directly but whose secrecy should be verified?\n│  └─ Use the Key Exposure Oracle pattern instead of query attacker(sk)\n│     See references\u002Fsecurity-properties.md → Key Exposure Oracle\n│\n└─ Unsure which security properties to verify?\n   └─ Default set: secrecy of session key + injective authentication\n      (both directions). Add forward secrecy if diagram shows ephemeral keys.\n",[2456],{"type":41,"tag":55,"props":2457,"children":2458},{"__ignoreMap":399},[2459],{"type":46,"value":2454},{"type":41,"tag":381,"props":2461,"children":2462},{},[],{"type":41,"tag":148,"props":2464,"children":2466},{"id":2465},"example",[2467],{"type":46,"value":2468},"Example",{"type":41,"tag":49,"props":2470,"children":2471},{},[2472,2477],{"type":41,"tag":55,"props":2473,"children":2475},{"className":2474},[],[2476],{"type":46,"value":377},{"type":46,"value":2478}," contains a worked example:",{"type":41,"tag":155,"props":2480,"children":2481},{},[2482,2496],{"type":41,"tag":159,"props":2483,"children":2484},{},[2485,2494],{"type":41,"tag":75,"props":2486,"children":2487},{},[2488],{"type":41,"tag":55,"props":2489,"children":2491},{"className":2490},[],[2492],{"type":46,"value":2493},"diagram.md",{"type":46,"value":2495}," — Mermaid sequenceDiagram for a two-party authenticated key\nexchange (X25519 DH + Ed25519 signing + HKDF)",{"type":41,"tag":159,"props":2497,"children":2498},{},[2499,2508],{"type":41,"tag":75,"props":2500,"children":2501},{},[2502],{"type":41,"tag":55,"props":2503,"children":2505},{"className":2504},[],[2506],{"type":46,"value":2507},"sample-output.pv",{"type":46,"value":2509}," — exact ProVerif model the skill should produce,\nwith secrecy and injective authentication queries",{"type":41,"tag":49,"props":2511,"children":2512},{},[2513],{"type":46,"value":2514},"Study this before working on an unfamiliar protocol.",{"type":41,"tag":381,"props":2516,"children":2517},{},[],{"type":41,"tag":148,"props":2519,"children":2521},{"id":2520},"supporting-documentation",[2522],{"type":46,"value":2523},"Supporting Documentation",{"type":41,"tag":155,"props":2525,"children":2526},{},[2527,2539,2552],{"type":41,"tag":159,"props":2528,"children":2529},{},[2530,2537],{"type":41,"tag":75,"props":2531,"children":2532},{},[2533],{"type":41,"tag":791,"props":2534,"children":2535},{"href":793},[2536],{"type":46,"value":793},{"type":46,"value":2538}," —\nMapping table from Mermaid cryptographic annotations to ProVerif function\ndeclarations, equations, and process patterns",{"type":41,"tag":159,"props":2540,"children":2541},{},[2542,2550],{"type":41,"tag":75,"props":2543,"children":2544},{},[2545],{"type":41,"tag":791,"props":2546,"children":2548},{"href":2547},"references\u002Fproverif-syntax.md",[2549],{"type":46,"value":2547},{"type":46,"value":2551}," —\nProVerif language reference: types, functions, equations, processes, events,\nqueries, and common pitfalls",{"type":41,"tag":159,"props":2553,"children":2554},{},[2555,2562],{"type":41,"tag":75,"props":2556,"children":2557},{},[2558],{"type":41,"tag":791,"props":2559,"children":2560},{"href":1674},[2561],{"type":46,"value":1674},{"type":46,"value":2563}," —\nDecision guide for choosing the right queries: secrecy, authentication\n(weak vs injective), forward secrecy, unlinkability, and how to model them",{"type":41,"tag":2565,"props":2566,"children":2567},"style",{},[2568],{"type":46,"value":2569},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2571,"total":2724},[2572,2588,2598,2616,2631,2644,2656,2666,2679,2690,2702,2713],{"slug":2573,"name":2573,"fn":2574,"description":2575,"org":2576,"tags":2577,"stars":23,"repoUrl":24,"updatedAt":2587},"address-sanitizer","detect memory errors during fuzzing","AddressSanitizer detects memory errors during fuzzing. Use when fuzzing C\u002FC++ code to find buffer overflows and use-after-free bugs.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2578,2580,2583,2584],{"name":2579,"slug":519,"type":16},"C#",{"name":2581,"slug":2582,"type":16},"Debugging","debugging",{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},"Testing","testing","2026-07-17T06:05:14.925095",{"slug":2589,"name":2589,"fn":2590,"description":2591,"org":2592,"tags":2593,"stars":23,"repoUrl":24,"updatedAt":2597},"aflpp","perform multi-core fuzzing of C\u002FC++ projects","AFL++ is a fork of AFL with better fuzzing performance and advanced features. Use for multi-core fuzzing of C\u002FC++ projects.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2594,2595,2596],{"name":2579,"slug":519,"type":16},{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},"2026-07-17T06:05:12.433192",{"slug":2599,"name":2599,"fn":2600,"description":2601,"org":2602,"tags":2603,"stars":23,"repoUrl":24,"updatedAt":2615},"agentic-actions-auditor","audit GitHub Actions for security vulnerabilities","Audits GitHub Actions workflows for security vulnerabilities in AI agent integrations including Claude Code Action, Gemini CLI, OpenAI Codex, and GitHub AI Inference. Detects attack vectors where attacker-controlled input reaches AI agents running in CI\u002FCD pipelines, including env var intermediary patterns, direct expression injection, dangerous sandbox configurations, and wildcard user allowlists. Use when reviewing workflow files that invoke AI coding agents, auditing CI\u002FCD pipeline security for prompt injection risks, or evaluating agentic action configurations.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2604,2607,2610,2611,2614],{"name":2605,"slug":2606,"type":16},"Agents","agents",{"name":2608,"slug":2609,"type":16},"CI\u002FCD","ci-cd",{"name":21,"slug":22,"type":16},{"name":2612,"slug":2613,"type":16},"GitHub Actions","github-actions",{"name":14,"slug":15,"type":16},"2026-07-18T05:47:48.564744",{"slug":2617,"name":2617,"fn":2618,"description":2619,"org":2620,"tags":2621,"stars":23,"repoUrl":24,"updatedAt":2630},"algorand-vulnerability-scanner","scan Algorand smart contracts for vulnerabilities","Scans Algorand smart contracts for 11 common vulnerabilities including rekeying attacks, unchecked transaction fees, missing field validations, and access control issues. Use when auditing Algorand projects (TEAL\u002FPyTeal).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2622,2625,2626,2627],{"name":2623,"slug":2624,"type":16},"Audit","audit",{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":2628,"slug":2629,"type":16},"Smart Contracts","smart-contracts","2026-07-18T05:47:43.989063",{"slug":2632,"name":2632,"fn":2633,"description":2634,"org":2635,"tags":2636,"stars":23,"repoUrl":24,"updatedAt":2643},"ask-questions-if-underspecified","clarify requirements before implementation","Clarify requirements before implementing. Use when serious doubts arise.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2637,2640],{"name":2638,"slug":2639,"type":16},"Engineering","engineering",{"name":2641,"slug":2642,"type":16},"Productivity","productivity","2026-07-17T06:05:33.543262",{"slug":2645,"name":2645,"fn":2646,"description":2647,"org":2648,"tags":2649,"stars":23,"repoUrl":24,"updatedAt":2655},"atheris","fuzz Python code with Atheris","Atheris is a coverage-guided Python fuzzer based on libFuzzer. Use for fuzzing pure Python code and Python C extensions.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2650,2653,2654],{"name":2651,"slug":2652,"type":16},"Python","python",{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},"2026-07-17T06:05:14.575191",{"slug":2657,"name":2657,"fn":2658,"description":2659,"org":2660,"tags":2661,"stars":23,"repoUrl":24,"updatedAt":2665},"audit-augmentation","augment code graphs with audit findings","Augments Trailmark code graphs with external audit findings from SARIF static analysis results, weAudit annotation files, and version-gated Trailmark 0.4.x binary-analysis graph exports. Maps findings to graph nodes by file and line overlap, creates severity-based subgraphs, and enables cross-referencing findings with pre-analysis data (blast radius, taint, etc.). Use when projecting SARIF results onto a code graph, overlaying weAudit annotations, importing binary graph findings, cross-referencing Semgrep, CodeQL, or binary-analysis findings with call graph data, or visualizing audit findings in the context of code structure.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2662,2663,2664],{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},"2026-08-01T05:44:54.920542",{"slug":2667,"name":2667,"fn":2668,"description":2669,"org":2670,"tags":2671,"stars":23,"repoUrl":24,"updatedAt":2678},"audit-context-building","build architectural context for code analysis","Enables ultra-granular, line-by-line code analysis to build deep architectural context before vulnerability or bug finding.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2672,2675,2676,2677],{"name":2673,"slug":2674,"type":16},"Architecture","architecture",{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":2638,"slug":2639,"type":16},"2026-07-18T05:47:40.122449",{"slug":2680,"name":2680,"fn":2681,"description":2682,"org":2683,"tags":2684,"stars":23,"repoUrl":24,"updatedAt":2689},"audit-prep-assistant","prepare codebases for security audits","Prepares codebases for security review using Trail of Bits' checklist. Helps set review goals, runs static analysis tools, increases test coverage, removes dead code, ensures accessibility, and generates documentation (flowcharts, user stories, inline comments).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2685,2686,2687,2688],{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":2638,"slug":2639,"type":16},{"name":14,"slug":15,"type":16},"2026-07-18T05:47:39.210985",{"slug":2691,"name":2691,"fn":2692,"description":2693,"org":2694,"tags":2695,"stars":23,"repoUrl":24,"updatedAt":2701},"burpsuite-project-parser","parse Burp Suite project files","Searches and explores Burp Suite project files (.burp) from the command line. Use when searching response headers or bodies with regex patterns, extracting security audit findings, dumping proxy history or site map data, or analyzing HTTP traffic captured in a Burp project.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2696,2697,2700],{"name":2623,"slug":2624,"type":16},{"name":2698,"slug":2699,"type":16},"CLI","cli",{"name":14,"slug":15,"type":16},"2026-07-17T06:05:33.198077",{"slug":2703,"name":2703,"fn":2704,"description":2705,"org":2706,"tags":2707,"stars":23,"repoUrl":24,"updatedAt":2712},"c-review","audit C and C++ code","Performs comprehensive C\u002FC++ security review for memory corruption, integer overflows, race conditions, and platform-specific vulnerabilities. Use when auditing native C\u002FC++ applications, reviewing daemons or services for memory safety, or hunting integer overflow \u002F use-after-free \u002F race conditions in userspace code.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2708,2709,2710,2711],{"name":2623,"slug":2624,"type":16},{"name":2579,"slug":519,"type":16},{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},"2026-07-17T06:05:11.333374",{"slug":2714,"name":2714,"fn":2715,"description":2716,"org":2717,"tags":2718,"stars":23,"repoUrl":24,"updatedAt":2723},"cairo-vulnerability-scanner","scan Cairo and StarkNet contracts for vulnerabilities","Scans Cairo\u002FStarkNet smart contracts for 6 critical vulnerabilities including felt252 arithmetic overflow, L1-L2 messaging issues, address conversion problems, and signature replay. Use when auditing StarkNet projects.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2719,2720,2721,2722],{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":2628,"slug":2629,"type":16},"2026-07-18T05:47:42.84568",111,{"items":2726,"total":2772},[2727,2734,2740,2748,2755,2760,2766],{"slug":2573,"name":2573,"fn":2574,"description":2575,"org":2728,"tags":2729,"stars":23,"repoUrl":24,"updatedAt":2587},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2730,2731,2732,2733],{"name":2579,"slug":519,"type":16},{"name":2581,"slug":2582,"type":16},{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},{"slug":2589,"name":2589,"fn":2590,"description":2591,"org":2735,"tags":2736,"stars":23,"repoUrl":24,"updatedAt":2597},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2737,2738,2739],{"name":2579,"slug":519,"type":16},{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},{"slug":2599,"name":2599,"fn":2600,"description":2601,"org":2741,"tags":2742,"stars":23,"repoUrl":24,"updatedAt":2615},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2743,2744,2745,2746,2747],{"name":2605,"slug":2606,"type":16},{"name":2608,"slug":2609,"type":16},{"name":21,"slug":22,"type":16},{"name":2612,"slug":2613,"type":16},{"name":14,"slug":15,"type":16},{"slug":2617,"name":2617,"fn":2618,"description":2619,"org":2749,"tags":2750,"stars":23,"repoUrl":24,"updatedAt":2630},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2751,2752,2753,2754],{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},{"name":2628,"slug":2629,"type":16},{"slug":2632,"name":2632,"fn":2633,"description":2634,"org":2756,"tags":2757,"stars":23,"repoUrl":24,"updatedAt":2643},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2758,2759],{"name":2638,"slug":2639,"type":16},{"name":2641,"slug":2642,"type":16},{"slug":2645,"name":2645,"fn":2646,"description":2647,"org":2761,"tags":2762,"stars":23,"repoUrl":24,"updatedAt":2655},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2763,2764,2765],{"name":2651,"slug":2652,"type":16},{"name":14,"slug":15,"type":16},{"name":2585,"slug":2586,"type":16},{"slug":2657,"name":2657,"fn":2658,"description":2659,"org":2767,"tags":2768,"stars":23,"repoUrl":24,"updatedAt":2665},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2769,2770,2771],{"name":2623,"slug":2624,"type":16},{"name":21,"slug":22,"type":16},{"name":14,"slug":15,"type":16},77]