(* Author : Steve Kremer *)

set verboseCompleted = true.

free c:channel.  (* declaring a free channel name *)

type id.
type pkey.
type skey.


free a, b, d: id. (* declaring identities as free names*)

(* Public key cryptography *)

fun pk(id):pkey.			(* public key*)
fun aenc(bitstring, pkey):bitstring. 	(* asymmetric encryption *)
fun adec(bitstring, skey):bitstring.	(* asymmetric decryption *)

fun sk(id):skey [private]. (* sk is a private function, i.e. cannot be applied by the adversary *)

equation forall x:bitstring, y:id; adec(aenc(x,pk(y)),sk(y)) = x.

event corrupt(id).
event sec(id, id, bitstring).
event startI(id, id, bitstring).
event acceptI(id, id).
event startR(id, id).
event acceptR(id, id, bitstring).

(* queries should be added here *)

query xa:id, xb:id, x:bitstring; event(sec(xa, xb, x)) && attacker(x) ==> event(corrupt(xa)) || event(corrupt(xb)).
(* query x:bitstring; inj-event(acceptR(a, b, x)) ==> inj-event(startI(a, b, x)). *)


(* initiator process *)
let Pi(i1:id, r1:id) =
       	 new na:bitstring;
	 event startI(i1, r1, na);
	 event sec(i1,r1,na);
       	 out(c, aenc( (i1,na) , pk(r1)));
	 in(c, x:bitstring);
	 let (=na, nr:bitstring) = adec(x, sk(i1)) in
	 out(c, aenc(nr,pk(r1))).


(* responder process *)
let Pr (r2:id)=
         in(c, y1:bitstring);
       	 let (i2:id, ni:bitstring) = adec(y1, sk(r2)) in (* '=i2' checks that the received value is equal to i2 *)
	 new nb:bitstring;
(*	 event sec(i2,r2,nb); *)
       	 out(c, aenc( (ni, nb) , pk(i2)));
	 in (c, y2:bitstring);
	 if nb = adec(y2, sk(r2)) then
	 event acceptR(i2, r2, ni).

(* main process *)
process  ( ! in (c, xa:id); in(c,xb:id); Pi(xa,xb) ) | ( ! in(c,xb:id); Pr(xb) ) | ! in(c, xd:id); event corrupt(xd); out(c,sk(xd))

(* EXPECTPV
RESULT event(sec(xa_1,xb_2,x_1)) && attacker(x_1) ==> event(corrupt(xa_1)) || event(corrupt(xb_2)) is false.
0.016s (user 0.008s + system 0.008s), max rss 8644K
END *)
