{
  "all_consistent": true,
  "general_rule": "A hybrid-KEM combiner is MAL-BIND-K-PK only if, for every component KEM that is not itself MAL-BIND-K-PK, the combiner binds that component's public key into the KDF (or derives its key material from a hashed single seed, as X-Wing does).",
  "matrix": [
    {
      "combiner": "X-Wing (draft-connolly-cfrg-xwing)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "composite_kem_xwing_control_hunt.pv",
      "note": "z is SHAKE-derived from a single seed (bound to the public key) -> secure; the proven sibling",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "Composite ML-KEM (LAMPS draft, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "composite_kem_kct_control_hunt.pv",
      "note": "seed format + C2PRI: holds (mlkemCT can safely be omitted, as in X-Wing)",
      "notion": "MAL-BIND-K-CT",
      "proverif": "RESIST"
    },
    {
      "combiner": "Composite ML-KEM (LAMPS draft, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "composite_kem_leak_kpk_hunt.pv",
      "note": "honest keys (key-bound z): holds -> the composite sits AT LEAK-BIND-K-PK",
      "notion": "LEAK-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "Composite ML-KEM (LAMPS draft, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "BREAK",
      "model": "composite_kem_kpk_hunt.pv",
      "note": "raw d||z seed (settable z) + mlkemPK omitted from KDF -> only LEAK-BIND-K-PK  [FINDING]",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "Composite ML-KEM + fix (bind mlkemPK)",
      "consistent": true,
      "deployed": false,
      "expect": "RESIST",
      "model": "composite_kem_kpk_fixed_hunt.pv",
      "note": "the one-line remediation: binding mlkemPK restores MAL-BIND-K-PK",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "OpenPGP PQC (RFC 9980, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "BREAK",
      "model": "openpgp_pqc_kpk_hunt.pv",
      "note": "RFC 9980 \u00a74.2.1 OpenPGPCompositeKDFv1 omits mlkemPK+mlkemCT (binds only ecdhPK+ecdhCT); \u00a74.3.2.2 stores the ML-KEM secret as raw d||z (settable z) -> only LEAK-BIND-K-PK. Copies X-Wing's combiner but adopts the expanded key format X-Wing WARNS voids the property; RFC is silent on it. No transcript (PKESK key-transport). SECOND finding, same shape as the composite. [FINDING #2]  (class result: Binding Security of Combined KEMs, ePrint 2025/1416)",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "OpenPGP PQC + fix (bind mlkemPK)",
      "consistent": true,
      "deployed": false,
      "expect": "RESIST",
      "model": "openpgp_pqc_kpk_fixed_hunt.pv",
      "note": "remediation: bind mlkemPublicKey/fingerprint into the KDF (or mandate a single-seed key format)",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "CMS KEMRecipientInfo (RFC 9629 / cms-kyber, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "BREAK",
      "model": "cms_kyber_rfc9629_kpk_hunt.pv",
      "note": "PUBLISHED Proposed Standard. RFC 9629 \u00a75 CMSORIforKEMOtherInfo = {wrap, kekLength, ukm?} -> the KDF info binds NEITHER the recipient ML-KEM public key NOR the ciphertext (kemct is outside info; ukm optional+disclaimed by cms-kyber \u00a72.1). Raw ML-KEM (settable z), no transcript. Widest reuse (PKCS#11 v3.2 + S/MIME inherit it). [FINDING #3] (class: ePrint 2025/1416)",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "CMS KEMRecipientInfo + fix (bind mlkemPK)",
      "consistent": true,
      "deployed": false,
      "expect": "RESIST",
      "model": "cms_kyber_rfc9629_kpk_fixed_hunt.pv",
      "note": "remediation: bind the recipient ML-KEM public key (or cert hash) into CMSORIforKEMOtherInfo",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "JOSE/COSE PQ-KEM (draft-ietf-jose-pqc-kem-05, SPEC)",
      "consistent": true,
      "deployed": true,
      "expect": "BREAK",
      "model": "jose_cose_pqc_kem_kpk_hunt.pv",
      "note": "KMAC KDF (SP800-108) over AlgorithmID||SuppPubInfo||SuppPrivInfo; PartyUInfo+PartyVInfo EXPLICITLY excluded -> ML-KEM public key NOT bound (ct in the 'ek' header, not the KDF). Raw ML-KEM, no transcript. The draft's own rationale ('recipient's identity is already bound to the public key used for encapsulation') is exactly the property a MAL adversary defeats. [FINDING #4]",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "JOSE/COSE PQ-KEM + fix (bind mlkemPK)",
      "consistent": true,
      "deployed": false,
      "expect": "RESIST",
      "model": "jose_cose_pqc_kem_kpk_fixed_hunt.pv",
      "note": "remediation: put the recipient ML-KEM public key (or JWK thumbprint) into the KDF context (e.g. restore PartyVInfo / SuppPubInfo)",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "HPKE-ML-KEM (draft-connolly, DOCUMENTED)",
      "consistent": true,
      "deployed": true,
      "documented": true,
      "expect": "BREAK",
      "model": "hpke_mlkem_kpk_documented_hunt.pv",
      "note": "raw ML-KEM ss, no kem_context KDF -> LEAK-BIND-K-PK; SELF-DISCLOSED in its own \u00a74.4 (not a finding). Contrast: the composite draft is SILENT on this gap.",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "CFRG UniversalCombiner (draft-irtf-cfrg-hybrid-kems-12)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "kem_combiner_cfrg_generic_hunt.pv",
      "note": "the 'bind-everything' combiner: folds both ciphertexts AND both encapsulation keys (incl. ek_PQ=mlkemPK) into the KDF -> RESIST. HONEST: the draft PROVES only LEAK-BIND (\u00a76.4.2) and puts MAL out-of-scope (\u00a76.2.2); MAL-BIND here is a sound STRUCTURAL inference (the KDF-collision argument doesn't use key honesty), not a stated draft theorem.",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "TLS X25519MLKEM768 KEM-LEVEL (draft-ietf-tls-ecdhe-mlkem)",
      "consistent": true,
      "deployed": true,
      "documented": true,
      "expect": "BREAK",
      "model": "tls_hybrid_kemlevel_kpk_hunt.pv",
      "note": "raw combiner = concat(mlkemSS,x25519SS), binds no pk -> K-PK gap AT THE KEM LEVEL; but TLS binds key_shares via the transcript hash, so the TLS handshake is fine (composition note, NOT a TLS break). A non-TLS reuse of the raw combiner would inherit the gap.",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    },
    {
      "combiner": "PQXDH / Signal (ML-KEM-1024)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "pqxdh_signal_kpk_hunt.pv",
      "note": "binds the PQ prekey public key (PQPK=mlkemPK) + ciphertext into the KDF (the deployed pk+ct-bound variant) -> MAL-BIND-K-PK. Model generated (binds-mlkem-pk); basis: the published PQXDH binding analysis (Bhargavan+ / Fiedler-G\u00fcnther) + Sprint-137 pqxdh model.",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "Apple PQ3 / iMessage (ML-KEM-1024)",
      "consistent": true,
      "deployed": true,
      "expect": "RESIST",
      "model": "apple_pq3_kpk_hunt.pv",
      "note": "folds the ML-KEM encapsulation key + ciphertext into the HKDF-Expand label -> MAL-BIND-K-PK. Model generated (binds-mlkem-pk); basis: Apple PQ3 design + D. Connolly 'How to Hold KEMs' (PQ3 'includes the ML-KEM ciphertext and encapsulation key in the label').",
      "notion": "MAL-BIND-K-PK",
      "proverif": "RESIST"
    },
    {
      "combiner": "Naive combiner (binds neither pk)",
      "consistent": true,
      "deployed": false,
      "expect": "BREAK",
      "model": "kem_combiner_naive_pkbind_hunt.pv",
      "note": "teeth: the general K-PK failure a naive combiner exhibits",
      "notion": "MAL-BIND-K-PK",
      "proverif": "BREAK"
    }
  ],
  "module": "kem_combiner_binding_audit",
  "n_red_candidates": 4,
  "n_rows": 17,
  "prover": "ProVerif (real binary, via make outward-provers)",
  "red_candidates": [
    "Composite ML-KEM (LAMPS draft, SPEC) :: MAL-BIND-K-PK",
    "OpenPGP PQC (RFC 9980, SPEC) :: MAL-BIND-K-PK",
    "CMS KEMRecipientInfo (RFC 9629 / cms-kyber, SPEC) :: MAL-BIND-K-PK",
    "JOSE/COSE PQ-KEM (draft-ietf-jose-pqc-kem-05, SPEC) :: MAL-BIND-K-PK"
  ],
  "sprint": 140,
  "status": "Reusable machine-checked binding auditor. A deployed combiner failing a MAL notion is a RED candidate (human+counsel + independent re-verification; NEVER auto-promoted). No legal/novelty/FTO/essentiality/price conclusion."
}
