free c: channel.

type host.
type pkey.
type skey.

set preciseActions = true.
set removeEventsForLemma = true.


(* Public key encryption *)

fun pk(skey): pkey.
fun aenc(bitstring, pkey): bitstring.
reduc forall x: bitstring, y: skey; adec(aenc(x,pk(y)),y) = x.
fun pkeytostring(pkey): bitstring [typeConverter].
fun stringtopkey(bitstring): pkey [typeConverter].


(* Agents*)
free A:host.
free B:host.
free C:host.

(* Event declaration*)
event beginA(host,host,pkey).
event endB(host,host,pkey).
event beginB(host,host,pkey).
event endA(host,host,pkey).

not attacker(new truc1).
not attacker(new truc4).
not attacker(new skA).
not attacker(new skB).

(* Security properties *)

query  z:pkey; event(endB(A,B,z)) ==> event(beginA(A,B,z)).
query  z:pkey; event(endA(A,B,z)) ==> event(beginB(A,B,z)).

(*free nb: bitstring [private].
query attacker (nb).*)

let clientA(A:host, B:host,pkA:pkey,skA:skey,pkB:pkey,nA:pkey) =
    event beginA(A, B, nA);
    let (nAstring:bitstring) = pkeytostring(nA) in
    out(c,(aenc(nAstring,pkB)));
    in(c,x:bitstring);
    in(c,y:bitstring);
    let (pkBstring:bitstring) = pkeytostring(pkB) in
    let (=aenc(aenc(pkBstring,pkA),nA)) = x in
    let (nBstring:bitstring) = adec(y,skA) in
    let (nB:pkey) = stringtopkey(nBstring) in
    out(c, aenc(aenc(aenc(pkBstring,nB),nA),pkA));
    event endA(A, B, nB).


let clientB(truc:skey,A:host,B:host,pkB:pkey,skB:skey,pkA:pkey) =
    in(c,x:bitstring);
    let nB = pk(truc) in
    event beginB(A, B, nB);
    let (nBstring:bitstring) = pkeytostring(nB) in
    let (pkBstring:bitstring) = pkeytostring(pkB) in
    let (nAstring:bitstring) = adec(x,skB) in
    let (nA:pkey) = stringtopkey(nAstring) in
    out(c, aenc(aenc(pkBstring,pkA),nA));
    out(c,aenc(nBstring,pkA));

    in(c,y:bitstring);

    if aenc(aenc(aenc(pkBstring,nB),nA),pkA) = y then
    event endB(A,B,nA).



process
	new skA:skey;
	new skB:skey;
	new skC:skey;
	let pkA= pk(skA) in out(c,pkA);
	let pkB = pk(skB) in out(c,pkB);
	let pkC = pk(skC) in out(c,skC);
(
(!new nA:pkey;clientA(A,B,pkA,skA,pkB,nA)) |
 (!new nA:pkey;clientA(A,C,pkA,skA,pkC,nA)) |
 (!new nA:pkey;clientA(B,A,pkB,skB,pkA,nA)) |
 (!new nA:pkey;clientA(B,C,pkB,skB,pkC,nA)) |
 (!new truc1:skey; clientB(truc1,B,A,pkB,skB,pkA)) |
 (!new truc4:skey;clientB(truc4,A,B,pkA,skA,pkB))
 )

(* EXPECTPV
RESULT event(endB(A[],B[],z)) ==> event(beginA(A[],B[],z)) is false.
RESULT event(endA(A[],B[],z)) ==> event(beginB(A[],B[],z)) is false.
0.036s (user 0.036s + system 0.000s), max rss 9956K
END *)
