free c:channel.

const SIGN:bitstring.

fun hmac(bitstring,bitstring):bitstring.

event Received(bitstring,bitstring,nat).

fun QReceived(bitstring,bitstring,nat):bitstring [private].

event Sent(bitstring,bitstring,nat).
event Value(channel,nat,nat).

fun QValue(channel,nat,nat):bitstring [private].

event Interval(channel,nat,nat,nat).

fun QInterval(channel,nat,nat,nat):bitstring [private].

type stamp.

free id:stamp [private].
free id1:stamp [private].

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

axiom i1:nat,i2:nat,i3:nat,i4:nat,st:stamp,st1:stamp,st2:stamp,x:bitstring,x1:bitstring,d:channel;
  event(UAction_bitstring(st2,x1)) && event(UAction_bitstring(st2,x)) ==> x1 = x;
  event(VCell_bitstring(d,(i4,i1))) && event(VCell_bitstring(d,(i2,i1))) ==> i2 = i4;
  event(VCell_bitstring(d,(i4,i1))) && event(VCell_bitstring(d,(i4,i3))) ==> i1 = i3;
  event(Counter(d,st2,st,i4)) && event(Counter(d,st2,st,i1)) ==> i4 = i1;
  event(Counter(d,st2,st,i4)) && event(Counter(d,st2,st1,i4)) ==> st = st1.

query sk:bitstring,msg:bitstring,i:nat;
  event(Received(sk,msg,i)) ==> event(Sent(sk,msg,i)).

query sk:bitstring,msg:bitstring,i:nat,msg':bitstring,i':nat;
  attacker((QReceived(sk,msg,i),QReceived(sk,msg',i'))) ==>
        msg = msg' && i = i'
    ||  msg <> msg' && i <> i'.

process
  !(
  new sk:bitstring;
  new cell_A:channel;
  new cell_B:channel;
  (
    out(cell_A,(0,0));
    0
  ) | (
    out(cell_B,(0,0));
    0
  ) | (
    !(
    (
      in(cell_A,(clock:nat,i:nat));
      event VCell_bitstring(cell_A,(clock,i));
      in(c,(msg:bitstring,= SIGN,j:nat,h:bitstring));
      new st[]:stamp;
      event UAction_bitstring(st,(msg,SIGN,j,h));
      if i < j
      then
        if h = hmac(sk,(j,msg))
        then
          new st1[]:stamp;
          event Counter(cell_A,id1,st1,i);
          event Counter(cell_A,id,st1,clock);
          event VCell_bitstring(cell_A,(clock + 1,j));
          event Received(sk,msg,j);
          out(c,QReceived(sk,msg,j));
          out(cell_A,(clock + 1,j));
          0
        else
          out(cell_A,(clock,i));
          0
      else
        out(cell_A,(clock,i));
        0
    ) | (
      in(cell_A,(clock:nat,i:nat));
      event VCell_bitstring(cell_A,(clock,i));
      new st[]:stamp;
      event Counter(cell_A,id1,st,i);
      event Counter(cell_A,id,st,clock);
      event VCell_bitstring(cell_A,(clock + 1,i + 1));
      new msg:bitstring;
      event Sent(sk,msg,i + 1);
      out(c,(msg,SIGN,i + 1,hmac(sk,(i + 1,msg))));
      out(cell_A,(clock + 1,i + 1));
      0
    ) | (
      in(cell_B,(clock:nat,i:nat));
      event VCell_bitstring(cell_B,(clock,i));
      in(c,(msg:bitstring,= SIGN,j:nat,h:bitstring));
      new st[]:stamp;
      event UAction_bitstring(st,(msg,SIGN,j,h));
      if i < j
      then
        if h = hmac(sk,(j,msg))
        then
          new st1[]:stamp;
          event Counter(cell_B,id1,st1,i);
          event Counter(cell_B,id,st1,clock);
          event VCell_bitstring(cell_B,(clock + 1,j));
          event Received(sk,msg,j);
          out(c,QReceived(sk,msg,j));
          out(cell_B,(clock + 1,j));
          0
        else
          out(cell_B,(clock,i));
          0
      else
        out(cell_B,(clock,i));
        0
    ) | (
      in(cell_B,(clock:nat,i:nat));
      event VCell_bitstring(cell_B,(clock,i));
      new st[]:stamp;
      event Counter(cell_B,id1,st,i);
      event Counter(cell_B,id,st,clock);
      event VCell_bitstring(cell_B,(clock + 1,i + 1));
      new msg:bitstring;
      event Sent(sk,msg,i + 1);
      out(c,(msg,SIGN,i + 1,hmac(sk,(i + 1,msg))));
      out(cell_B,(clock + 1,i + 1));
      0
    )
    )  )
  )

(* EXPECTPV
RESULT event(Received(sk_1,msg_4,i_4)) ==> event(Sent(sk_1,msg_4,i_4)) is true.
RESULT attacker((QReceived(sk_1,msg_4,i_4),QReceived(sk_1,msg',i'))) ==> (msg_4 = msg' && i_4 = i') || (msg_4 ≠ msg' && i_4 ≠ i') is true.
0.064s (user 0.044s + system 0.020s), max rss 9660K
END *)
