free cR:channel.
free cT:channel.
free OK:bitstring.
free ERROR:bitstring.
free cprivR:channel [private].
free cprivT:channel [private].

fun hone(bitstring):bitstring.
fun htwo(bitstring):bitstring.
fun hkey(bitstring):bitstring [private].

event Ttest(bitstring,bitstring,bitstring,bitstring,bitstring).
event Rout(bitstring,bitstring,bitstring,bitstring,bitstring).

type stamp.

free id:stamp [private].

event Counter(channel,stamp,stamp,nat).
event VCell_bitstring(channel,bitstring).

nounif x:bitstring; mess(new cprivR1,*x) [ignoreAFewTimes].
nounif x:bitstring; mess(new cprivT1,*x) [ignoreAFewTimes].

axiom kT:bitstring,nT:bitstring,nR:bitstring,m1:bitstring,m2:bitstring,m3:bitstring,i:nat,i1:nat,st:stamp,st1:stamp,st2:stamp,x:bitstring,x1:bitstring,d:channel;
  event(VCell_bitstring(d,(i,x1))) && event(VCell_bitstring(d,(i,x))) ==> x = x1;
  event(Counter(d,st2,st,i1)) && event(Counter(d,st2,st,i)) ==> i1 = i;
  event(Counter(d,st2,st,i1)) && event(Counter(d,st2,st1,i1)) ==> st = st1.

query kT:bitstring,nT:bitstring,nR:bitstring,m1:bitstring,m2:bitstring,m3:bitstring,i:nat,i1:nat,st:stamp,st1:stamp,st2:stamp,x:bitstring,x1:bitstring,d:channel;
  event(Ttest(kT,nT,m1,m2,m3)) ==>
        event(Rout(kT,nR,m1,m2,m3)).

process
  !(
  new k:bitstring;
  new cprivR1:channel;
  new cprivT1:channel;
  (
    out(cprivT1,(0,k));
    0
  ) | (
    out(cprivR1,(0,k));
    0
  ) | (
    !(
    new nR:bitstring; (* Application of the process Reader *)
    in(cprivR1,(i:nat,kR:bitstring)); (* The first nat variable has been added due to the cell parameter *)
    event VCell_bitstring(cprivR1,(i,kR));
    new st[]:stamp;
    event Counter(cprivR1,id,st,i);
    event VCell_bitstring(cprivR1,(i + 1,hkey(kR)));
    let m1:bitstring = nR in
    out(cR,m1);
    in(cR,x2:bitstring);
    let (xnT:bitstring,xhash:bitstring) = x2 in
    if xhash = hone((nR,xnT,kR)) then
    let m3:bitstring = htwo((xhash,kR,m1)) in
      event Rout(kR,nR,m1,x2,m3);
      out(cR,m3);
      out(cprivR1,(i + 1,hkey(kR)));
      0
    else
      out(cR,ERROR);
      0
    )  ) | (
    !(
    new nT:bitstring; (* Application of the process Tag *)
    in(cprivT1,(i:nat,kT:bitstring)); (* The first nat variable has been added due to the cell parameter *)
    event VCell_bitstring(cprivT1,(i,kT));
    new st[]:stamp;
    event Counter(cprivT1,id,st,i);
    event VCell_bitstring(cprivT1,(i + 1,hkey(kT)));
    in(cT,x1:bitstring);
    let m2:bitstring = (nT,hone((x1,nT,kT))) in
    out(cT,m2);
    in(cT,x3:bitstring);
    if htwo((hone((x1,nT,kT)),kT,x1)) = x3
    then
      event Ttest(kT,nT,x1,m2,x3);
      out(cT,OK);
      out(cprivT1,(i + 1,hkey(kT)));
      0
    else
      out(cT,ERROR);
      0
    )  )
  )

(* EXPECTPV
RESULT event(Ttest(kT_1,nT_1,m1_1,m2_1,m3_1)) ==> event(Rout(kT_1,nR_1,m1_1,m2_1,m3_1)) is true.
0.016s (user 0.016s + system 0.000s), max rss 9092K
END *)
