(****************************************************)
(*  			  BDPv2 protocol     				*)
(*    			       	   							*)
(*	1. A → S : A,{<B,K>}AS							*)
(*	2. S → B : {<A,K>}BS							*)
(*	3. B → A : {{NB}K}pkA							*)
(*	4. A → B : {NB}pkB								*)
(*	5. A → B : {{NA}K}pkB							*)
(*	6. B → A : {NA}pkA                         		*)
(*    			       	   							*)
(****************************************************)

set preciseActions = true.
set removeEventsForLemma = true.

free ab,sa,sb,c:channel.  (* declaring a free channel name *)

type id.
type symkey.
type pkey.
type skey.

free a, b, s, 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 *)

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

(* Symetric key cryptography *)

fun getsymkey(id):symkey [private].			(* symetric key from id*)
fun symenc(bitstring, symkey):bitstring. 	(* symmetric encryption *)
(*fun symdec(bitstring, symkey):bitstring.	*)(* symmetric decryption *)
fun keytobit(symkey):bitstring [typeConverter].

reduc forall x:bitstring, key:symkey ; symdec(symenc(x,key),key) = x.

event start(id,id,bitstring,bitstring,symkey).
event end(id,id,bitstring,bitstring,symkey).
event honestsession(bitstring,id,id).
event reach.

(* queries should be added here *)
(*query noncea:bitstring,nonceb:bitstring,key:symkey; inj-event(end(a,b,noncea,nonceb,key))==> inj-event(start(a,b,noncea,nonceb,key)).*)
(*query x:bitstring, y:id, z:id ; event (honestsession(x,y,z)) && attacker(x) ==> ( z=d || y=d  ). *)
(*query attacker(new Kab). *)
query event(reach).

(* initiator process *)
let Pa(i1:id, r1:id) =

	 (* Step 1 *)
		new Kab:symkey;
		out(sa, (i1,symenc((r1,Kab),getsymkey(i1))));

	event honestsession(keytobit(Kab),i1,r1);
	 (* Step 4 *)
		in(ab,x:bitstring);
		let (y:bitstring) = adec(x,sk(i1)) in
		let (nb:bitstring) = symdec(y,Kab) in
		out(ab,aenc(nb,pk(r1)));

	(* Step 5 *)
		new na:bitstring;
	event start(i1,r1,na,nb,Kab);
		out(ab,aenc(symenc(na,Kab),pk(r1)));

	event honestsession(na,i1,r1);
	(* Step 5bis *)
		in (ab,z:bitstring);

		let (=na) = adec(z,sk(i1)) in
	event end(i1,r1,na,nb,Kab);
		event reach;
	 0.

let Ps(rS:id) =

	(* Step 2 *)
		in(sb,(i1:id,x:bitstring));
		let (r2:id,Kab:symkey) = symdec(x,getsymkey(i1)) in
		out(sb, symenc((i1,Kab),getsymkey(r2)));

		0.

let Pb (r2:id) =

	(* Step 3 *)
		in(sb,x:bitstring);
		let (i1:id,Kab:symkey) = symdec(x, getsymkey(r2)) in
		new nb:bitstring;
		out(ab,aenc(symenc(nb,Kab),pk(i1)));

	(* Step 4bis *)
		in (ab,y:bitstring);
		let (=nb) = adec(y,sk(r2)) in

	(* Step 5 *)
		in(ab,z:bitstring);
		let (w:bitstring) = adec(z,sk(r2)) in
		let (na:bitstring) = symdec(w,Kab) in
		out(ab,aenc(na,pk(i1)));
	event honestsession(nb,i1,r2);
		0.

(* main process *)
process (! in(c,xa:id); in(c,xb:id) ; Pa(xa,xb) )|(! in(c,xb:id) ; Pb(xb) )|(! in(c,xs:id) ; Ps(xs) )| out(c,sk(d))

(* EXPECTPV
RESULT not event(reach) is false.
0.040s (user 0.040s + system 0.000s), max rss 9712K
END *)
