free c.
(* 

? -> A : pkB
A -> B : { N_A, pkA }_pkB
B -> A : { N_A, N_B, pkB }_pkA
A -> B : { N_B }_pkB

*)

(* Public key cryptography *)

fun pk/1.
fun encrypt/2.
reduc decrypt(encrypt(x,pk(y)),y) = x.

authquery Bparam/1.
authquery Bfull/4.
authquery Aparam/1.
authquery Afull/4.

let processA = in(c,pkX); begin Bparam(pkX); new Na; 
               out(c, encrypt((Na, pkA), pkX));
                in(c, m); let (Na2, NX2, pkX2) = decrypt(m, skA) in
                          if Na2 = Na then
                             if pkX2 = pkX then
			       begin Bfull(Na, pkA, pkX, NX2);
                               out(c, encrypt(NX2, pkX));
			       if pkX = pkB then
				 end Aparam(pkA);
				 end Afull(Na, pkA, pkX, NX2).

let processB = in(c, m); let (NY, pkY) = decrypt(m, skB) in
			 begin Aparam(pkY);
			 new Nb;
			 begin Afull(NY, pkY, pkB, Nb);
			 out(c, encrypt((NY, Nb, pkB), pkY));
			  in(c, m3);
                          let Nb2 = decrypt(m3, skB) in
                          if Nb2 = Nb then 
			  (* OK *)
                            if pkY = pkA then
			      end Bparam(pkB);
			      end Bfull(NY, pkY, pkB, Nb).


process new skA; let pkA = pk(skA) in
        out(c, pkA);
        new skB; let pkB = pk(skB) in
        out(c, pkB);
	((!processA) | (!processB))
