(* Bellovin, Merritt, Oakland 92, section 2.1
   Version in which A and B talk to anybody *)

free c.

(* Symmetric cryptography
   One does not know whether decryption succeeds or not
   For use with weak secrets *)

fun enc/2.
fun dec/2.
equation dec(enc(x,y),y) = x.
equation enc(dec(x,y),y) = x.

(* Symmetric cryptography
   One knows whether decryption succeeds or not *)

fun senc/2.
reduc sdec(senc(x,y),y) = x.

(* Public key cryptography *)

fun penc/2.
fun pk/1.
reduc pdec(penc(x,pk(y)),y) = x.

(* Host name -> password *)

fun passwdA/1. (* passwdA(hostX) = the password that X shares with A *)
fun passwdB/1. (* passwdB(hostX) = the password that X shares with B *)

free hostA, hostB.
private free P.

(* query ev:Asays(x,y,z) ==> ev:Bsays(x,y,z). *)

let processA =
	new sEA;
	let EA = pk(sEA) in
	out(c, (hostA, enc(EA, P)));
	in(c,m2);
	let R = pdec(dec(m2,P),sEA) in
	new challengeA;
	out(c, senc((challengeA), R));
	in(c, m4);
	let (=challengeA, challengeB) = sdec(m4, R) in
	out(c, senc((challengeB), R)) (*;
	if hostX = hostB then
	event Asays(hostA, hostX, R)*).


let processB =
	in(c, (=hostX, m));
	let EA = dec(m, P) in
	new R;
	(* event Bsays(hostX, hostB, R); *)
	out(c, enc(penc(R, EA), P));
	in(c,m3);
	let (challengeA) = sdec(m3, R) in
	new challengeB;
	out(c, senc((challengeA, challengeB), R));
	in(c, m5);
	if sdec(m5, R) = (challengeB) then
	0.

let processAtalkingX =
	in(c, hostX);
	(* if hostX = hostB then 0 else *)
	let P = passwdA(hostX) in
	processA.

let processBtalkingX =
	in(c, hostX);
	(* if hostX = hostA then 0 else *)
	let P = passwdB(hostX) in
	processB.

process 

	(!let hostX = hostB in processA) |
	(!let hostX = hostA in processB) |
	(!processAtalkingX) |
	(!processBtalkingX) |
	(phase 1;
	new w;
	out(c, choice[w,P]))

(* EXPECTPV
RESULT Observational equivalence is true.
0.092s (user 0.080s + system 0.012s), max rss 10556K
END *)
