(* LO-Auth: Key Possession Proof (Theorem 6)
 *
 * Protocol (§6):
 *   Server → Client: c, where (c, ss) ← XWing.Encaps(pk_IK_client[XWing])
 *   Client → Server: proof = MAC(key=ss, data="lo-auth-v1")
 *   Server: accept iff proof = token, where token = MAC(key=ss, data="lo-auth-v1")
 *
 * Security claims:
 *   1. Correspondence: ServerAccepts ==> ClientResponds (Theorem 6)
 *   2. Injective correspondence: each acceptance maps to a distinct client
 *      response (single-use, matching Tamarin's Auth_Single_Use)
 *
 * Reduces to: X-Wing IND-CCA2 + HMAC-SHA3-256 SUF-CMA.
 *
 * Decaps oracle (§8.3 compositional note): In the Tamarin model, an explicit
 * DecapsOracle rule models the adversary's ability to submit arbitrary
 * ciphertexts and observe MAC(Decaps(sk_IK, c), "lo-auth-v1"). In CryptoVerif,
 * this is subsumed by the IND-CCA2 KEM assumption, which already provides the
 * adversary with a raw decapsulation oracle returning ss directly — strictly
 * more powerful than the MAC-wrapped output. The Nc parameter counts all
 * client-side decapsulation queries (both legitimate responses and adversarial
 * oracle use); the IND-CCA2 advantage bound P_kem(time, 1, Ns, Nc) accounts
 * for all such queries.
 *)

(* Session counts *)
param Ns.  (* Server challenge sessions *)
param Nc.  (* Client response sessions (includes §8.3 Decaps oracle queries) *)

(* ---------- Type declarations ---------- *)

type kem_keyseed [large, fixed].
type kem_pkey [bounded].
type kem_skey [bounded].
type kem_secret [large, fixed].
type kem_ciphertext [bounded].
type kem_encapoutput [bounded].

type macres [fixed].
type label [fixed].

(* ---------- X-Wing KEM (IND-CCA2) ---------- *)

proba P_kem.
proba P_kem_keycoll.
proba P_kem_ctxtcoll.

expand IND_CCA2_KEM(
  kem_keyseed, kem_pkey, kem_skey,
  kem_secret, kem_ciphertext, kem_encapoutput,
  kem_pkgen, kem_skgen, kem_encap, kem_pair, kem_decap,
  injbot_kem, P_kem, P_kem_keycoll, P_kem_ctxtcoll
).

(* ---------- HMAC-SHA3-256 as SUF-CMA deterministic MAC ---------- *)

proba P_mac.

expand SUF_CMA_det_mac(kem_secret, label, macres, mac_auth, mac_check, P_mac).

const lo_auth_label: label.

(* ---------- Events ---------- *)

event ServerAccepts(kem_pkey, kem_ciphertext).
event ClientResponds(kem_pkey, kem_ciphertext).

(* ---------- Security queries ---------- *)

(* Theorem 6 (Key Possession): If the server accepts for a challenge
 * ciphertext ct, then the client responded to that same ct. *)
query pk: kem_pkey, ct: kem_ciphertext;
  event(ServerAccepts(pk, ct)) ==> event(ClientResponds(pk, ct)).

(* Single-use (Tamarin: Auth_Single_Use): Each server acceptance maps to
 * a distinct client response — no replay of a single client response can
 * satisfy two server sessions. *)
query pk: kem_pkey, ct: kem_ciphertext;
  inj-event(ServerAccepts(pk, ct)) ==> inj-event(ClientResponds(pk, ct)).

(* ---------- Channels ---------- *)

channel c_start, c_srv_start, c_srv_out, c_srv_recv,
        c_cli_in, c_cli_out, c_pub.

(* ---------- Server process ---------- *)

let Server(pk_client: kem_pkey) =
  foreach i_s <= Ns do
  in(c_srv_start, ());
  let kem_pair(ss: kem_secret, ct: kem_ciphertext) = kem_encap(pk_client) in
  let token: macres = mac_auth(lo_auth_label, ss) in
  out(c_srv_out, ct);
  in(c_srv_recv, p: macres);
  if p = token then (
    event ServerAccepts(pk_client, ct)
  ).

(* ---------- Client process ---------- *)

let Client(sk_client: kem_skey, pk_client: kem_pkey) =
  foreach i_c <= Nc do
  in(c_cli_in, ct: kem_ciphertext);
  let injbot_kem(ss: kem_secret) = kem_decap(ct, sk_client) in
  let tag: macres = mac_auth(lo_auth_label, ss) in
  event ClientResponds(pk_client, ct);
  out(c_cli_out, tag).

(* ---------- Main process ---------- *)

process
  in(c_start, ());
  new kem_seed: kem_keyseed;
  let pk_client = kem_pkgen(kem_seed) in
  let sk_client = kem_skgen(kem_seed) in
  out(c_pub, pk_client);
  (Server(pk_client) | Client(sk_client, pk_client))

(* EXPECTED
All queries proved.
END *)
