(* Version with explicit parentheses, to guarantee that replication is
   always interpreted as in ProVerif <= 1.88 *)

free c: channel.
free pcA: channel [private].
free pcB: channel [private].
free pc1: channel [private].
free pc2: channel [private].
free pc3: channel [private].
free pc4: channel [private].
free pc5: channel [private].
free pc_RP: channel [private].

event authorised(bitstring). 
event signed(channel, bitstring). 
event csigned(channel, bitstring). 


type ksh.       
type cksh.      
type publickey.


fun pk(cksh,cksh,ksh,ksh,ksh,ksh,ksh):publickey.

fun combine(bitstring, bitstring, bitstring, bitstring): bitstring.
reduc forall w:bitstring, x:bitstring, y:bitstring, z:bitstring; proj1(combine(w,x,y,z)) = w.
reduc forall w:bitstring, x:bitstring, y:bitstring, z:bitstring; proj2(combine(w,x,y,z)) = x.
reduc forall w:bitstring, x:bitstring, y:bitstring, z:bitstring; proj3(combine(w,x,y,z)) = y.
reduc forall w:bitstring, x:bitstring, y:bitstring, z:bitstring; proj4(combine(w,x,y,z)) = z.

fun sign(ksh,bitstring):bitstring.
fun csign(cksh,bitstring):bitstring.

reduc
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k2,m), sign(k3,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k2,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k2,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k3,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k3,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k1,m), sign(k4,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k2,m), sign(k3,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k2,m), sign(k3,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k2,m), sign(k4,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kA,m), sign(k3,m), sign(k4,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k2,m), sign(k3,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k2,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k2,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k3,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k3,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k1,m), sign(k4,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k2,m), sign(k3,m), sign(k4,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k2,m), sign(k3,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k2,m), sign(k4,m), sign(k5,m))) = true;
forall kA:cksh,kB:cksh,k1:ksh,k2:ksh,k3:ksh,k4:ksh,k5:ksh,m:bitstring; verify(pk(kA,kB,k1,k2,k3,k4,k5), m, combine( csign(kB,m), sign(k3,m), sign(k4,m), sign(k5,m))) = true.




query chal:bitstring; event(authorised(chal)).



let Dealer =
     new kA: cksh;
     new kB: cksh;
     new k1: ksh;
     new k2: ksh;
     new k3: ksh;
     new k4: ksh;
     new k5: ksh;
     out(c, pk(kA, kB, k1, k2, k3, k4, k5));
     out(pc_RP, pk(kA, kB, k1, k2, k3, k4, k5));
     out(pcA, kA);
     out(pcB, kB);
     out(pc1, k1);
     out(pc2, k2);
     out(pc3, k3);
     out(pc4, k4);
     out(pc5, k5).

let Signer(pc: channel) =
     in(pc, k:ksh );
     in(c, mess:bitstring);
     let s = sign(k, mess) in
     event signed(pc, mess);
     out(c, s).

let ContentfulSigner(pcc:channel) =
     in(pcc, kc:cksh);
     in(c, mess:bitstring);
     let sc = csign(kc, mess) in
     event csigned(pcc, mess);
     out(c, sc).


let RelyingParty =
     in(pc_RP, pubkey:publickey);
     new challenge: bitstring;
     out(c, challenge);
     in(c, s:bitstring);
     if verify(pubkey, challenge, s) = true then
     event authorised(challenge).
  

process !(Dealer | !(ContentfulSigner(pcA) | !(ContentfulSigner(pcB) | !(Signer(pc1) | !(Signer(pc2) | !(Signer(pc3) | !(Signer(pc4) | !(Signer(pc5) | !RelyingParty))))))))

(* EXPECTPV
RESULT not event(authorised(chal)) is false.
28.088s (user 28.028s + system 0.060s), max rss 106952K
END *)
