(*

The Protocol

xP - public key of A
yP - public key of B
zP - public key of C

A -> B,C: aP, a(xP), CertA
A -> B,C: bP, b(yP), CertB
A -> B,C: cP, c(zP), CertC

A checks: e(bP,yP) == e(b(yP),P), e(cP,zP) == e(c(zP),P) key_A = e(b(yP),c(zP))^a^x
B checks: e(aP,xP) == e(a(xP),P), e(cP,zP) == e(c(zP),P) key_B = e(a(xP),c(zP))^b^y
C checks: e(bP,yP) == e(b(yP),P), e(aP,xP) == e(a(xP),P) key_C = e(b(yP),a(xP))^c^z

*)

param verboseClauses = short.

(* The public channel *)

free c.

(* Symmetric cryptography *)

fun enc/2.
reduc dec(k, enc(k, m)) = m.

(* Certificates *)

private fun cert/2.
reduc readcert(cert(x,y)) = (x,y).

(* Pairing *)
fun e/2.
fun exp/3.
fun mult/2.

(* The point on elliptic curve *)

fun point/0.

(* Query *)
query attacker:secret.

(* Processes *)
let processA =

        (* Nonce generation *)
        new na;
        new nx;

        (* Public key generation *)
	let pkA = mult(point,nx) in
        let CertA = cert(A, pkA) in

        (* Send the information out into network *)
        let aP = mult(point,na) in
        let axP = mult((point,nx),na) in
	out(c, (aP, axP, CertA));

        (* A waits for the message from B *)
	in(c, (bP, byP, CertB));
        let (=B, yP) = readcert(CertB) in

        (* A waits for the message from C *)
	in(c, (cP, czP, CertC));
        let (=C, zP) = readcert(CertC) in

        if e(bP,yP) = e(byP,P) then
        if e(cP,zP) = e(czP,P) then

        let kABC = exp(e(byP,czP),na,nx) in

        (* A,B, and C start to communicate *)
        out(c, enc(kABC, secret));
        0.

let processB =

        (* Nonce generation *)
        new nb;
        new ny;

        (* Public key generation *)
	let pkB = mult(point,ny) in
        let CertB = cert(B, pkB) in

        (* Send the information out into network *)
        let bP = mult(point,nb) in
        let byP = mult((point,ny),nb) in
	out(c, (bP, byP, CertB));

        (* B waits for the message from A *)
	in(c, (aP, axP, CertA));
        let (=A, xP) = readcert(CertA) in

        (* B waits for the message from C *)
	in(c, (cP, czP, CertC));
        let (=C, zP) = readcert(CertC) in

        if e(aP,xP) = e(axP,P) then
        if e(cP,zP) = e(czP,P) then

        let kABC = exp(e(axP,czP),nb,ny) in

        (* A,B, and C start to communicate *)
        out(c, enc(kABC, secret));
        0.

let processC =

        (* Nonce generation *)
        new nc;
        new nz;

        (* Public key generation *)
	let pkC = mult(point,nz) in
        let CertC = cert(C, pkC) in

        (* Send the information out into network *)
        let cP = mult(point,nc) in
        let czP = mult((point,nz),nc) in
	out(c, (cP, czP, CertC));

        (* C waits for the message from B *)
	in(c, (bP, byP, CertB));
        let (=B, yP) = readcert(CertB) in

        (* C waits for the message from A *)
	in(c, (aP, axP, CertA));
        let (=A, xP) = readcert(CertA) in

        if e(bP,yP) = e(byP,P) then
        if e(aP,xP) = e(axP,P) then

        let kABC = exp(e(byP,axP),nc,nz) in

        (* A,B, and C start to communicate *)
        out(c, enc(kABC, secret));
        0.

let simpleCA =
	in(c, pubkey);
	new n;
	out(c, cert(n,pubkey)).

process 

    new A; new B; new C;
    new secret;
    ((!processA) | (!processB) | (!processC) | (!simpleCA))
