(*  This is an attempt to model GDH.1 protocol of Michael Steiner et al for 3 participants *)

(* 

	p0 send {g^n0} to p1. 
	p1 sends {g^n0, g^(n0*n1)} to p2.
	p2 sets group key to g^(n0*n1*n2).
	p2 sends {g^n2, g^(n2*n0)} to p1. p1 sets group key to g^(n0*n1*n2).
	p1 sends {g^(n1*n2)} to p0. p0 sets group key to g^(n0*n1*n2).

*)


free c01. 
free c10.
free c12.
free c21.


private free m, success, fail, honest.


(* Check if attacker can recover m*)

 query attacker:m.
 (* attacker:success.*) 
 (* query attacker:fail. *)

(* Shared key cryptography *)

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


(* Diffie-Hellman functions *)
(* Exponential and Diffie-Hellman *)

data g/0.

fun exp/2.

equation exp(exp(g,x),y) = exp(exp(g,y),x).

(* These equations seem to be the reason why ProVerif fails to prove! Reason: comment out the equation below and ProVerif succeeds in proving. *)
  equation exp(exp(exp(g,y),z),x)=exp(exp(exp(g,y),x),z). 


(* Is this last equation really neeeded?
 equation exp(exp(exp(g,y),z),x)=exp(exp(exp(g,x),y),z). *)



(* processes *)
(* honestC is a private channel on which honest principals communicate the exact messages they communicate on the public channels c01, c10, c12, and c21. Lousy way of ensuring that attacker does not behave as an "honest" participant *)

let p0 = new n0; 
	(let gn0 = exp(g,n0) in
         out(c01,gn0); out(honestC, gn0); in(c10,x1); in(honestC,val); if val = x1 then let k = exp(x1,n0) in out(c01, enc(m,k))).

let p1 = new n1; 
         ( in(c01,x0); in(honestC,valx); if valx = x0 then
                         let k = exp(x0,n1) in 
                         out(c12,(x0,k));
			 out(honestC,(x0,k));
			 in(c21,(v,w));
			 in(honestC, (val1,val2));
			 out(c10,exp(v,n1));
			 if (val1,val2) = (v,w) then  
			 out(honestC,exp(v,n1));
			 in(c21,x);
                         let comk1 =exp(w,n1) in 
			 if x = comk1 then out(c01,success) else out(c01,fail)).

let p2 = new n2;
	( in(c12,(t,u));
	in(honestC,(val2,val3));
	if (val2,val3) = (t,u) then
		 out(c21,(exp(g,n2),exp(t,n2)));
		 out(honestC,(exp(g,n2),exp(t,n2)));
		 let comk2=exp(u,n2) in
		 out(c21,comk2)).

process  new honestC;( p0 | p1 | p2)
