(* Symmetric key encryption *)

type key.
fun senc(bitstring, key): bitstring.
reduc forall m: bitstring, k: key; sdec(senc(m,k),k) = m.


(* Asymmetric key encryption *)

type skey.
type pkey.

fun pk(skey): pkey.
fun aenc(bitstring, pkey): bitstring.

reduc forall m: bitstring, sk: skey; adec(aenc(m,pk(sk)),sk) = m.


(* Digital signatures *)

type sskey.
type spkey.

fun spk(sskey): spkey.
fun sign(bitstring, sskey): bitstring.

reduc forall m: bitstring, ssk: sskey; getmess(sign(m,ssk)) = m.
reduc forall m: bitstring, ssk: sskey; checksign(sign(m,ssk),spk(ssk)) = m.


free c:channel.

let clientA(pkA:pkey,skA:skey,pkB:spkey) = 
	out(c,pkA);
	in(c,x:bitstring); 
	let y = adec(x,skA) in
	let (=pkA,=pkB,k:key) = checksign(y,pkB) in
	new random:key;
	out(c, choice[k,random]).

let serverB(pkB:spkey,skB:sskey,pkA:pkey) = 
	in(c,pkX:pkey);
	new k:key; 
	out(c,aenc(sign((pkX,pkB,k),skB),pkX)).

process 
	new skA:skey; 
	new skB:sskey;
	let pkA = pk(skA) in out(c,pkA);
	let pkB = spk(skB) in out(c,pkB);
	( (!clientA(pkA,skA,pkB)) | (!serverB(pkB,skB,pkA)) )
