(* Secure Device.

  This example was originally generated by GSVerif from the following processes:

      let Conf(cell:channel) =
        ! in(c,x:bitstring);
          in(cell,y:bitstring);
          let test:bool = (y = init && (x = left || x = right)) in
          if test
          then out(cell,x)
          else out(cell,y).

      let Decrypt(cell:channel,k:bitstring) =
        ! in(c,x:bitstring);
          let (xl:bitstring,xr:bitstring) = adec(x,k) in
          in(cell,y:bitstring);
          if y = left then out(c,xl); out(cell,y)
          else if y = right then out(c,xr); out(cell,y)
          else out(cell,y).

      let Device =
        new cell:channel [precise];
        new k:bitstring;
          out(c,pk(k))
        | out(cell,init)
        | Conf(cell) | Decrypt(cell,k)
        | (! in(cell,x:bitstring); out(cell,x))
        | (
          !
          new sl:bitstring;
          new sr:bitstring;
          out(c,aenc((sl,sr),pk(k))) | in(c,(=sl,=sr)); event Attack
          ).

      process ! Device

  GSVerif modifies a query F => \phi with F => \phi || \phi' where \phi' is a property
  that is always false. Instead of using this transformed query, we can declare the
  negation of \phi' as an axiom. See the paper on GSVerif (CSF'18) for more details
  on these properties.
*)

free c:channel.

fun pk(bitstring):bitstring.
fun aenc(bitstring,bitstring):bitstring.

fun adec(bitstring,bitstring):bitstring
reduc forall x:bitstring,y:bitstring; adec(aenc(x,pk(y)),y) = x.

const init:bitstring.
const left:bitstring.
const right:bitstring.

event Attack.

type stamp.

free id:stamp [private].

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

axiom 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))) ==> x1 = x;
  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 event(Attack).

process
  !
  new cell:channel; (* Application of the process Device *)
  new k:bitstring;
  (
      out(c,pk(k))
    | out(cell,(0,init))
    | (
      !  (* Application of the process Conf *)
      in(c,x:bitstring);
      in(cell,(i:nat,y:bitstring)); (* The first nat variable has been added due to the cell parameter *)
      event VCell_bitstring(cell,(i,y));
      let test:bool = (y = init && (x = left || x = right)) in
      if test
      then
        new st[]:stamp;
        event Counter(cell,id,st,i);
        event VCell_bitstring(cell,(i + 1,x));
        out(cell,(i + 1,x))
      else out(cell,(i,y))
    ) | (
      !  (* Application of the process Decrypt *)
      in(c,x:bitstring);
      let (xl:bitstring,xr:bitstring) = adec(x,k) in
      in(cell,(i:nat,y:bitstring)); (* The first nat variable has been added due to the cell parameter *)
      event VCell_bitstring(cell,(i,y));
      if y = left
      then
        out(c,xl);
        out(cell,(i,y))
      else
        if y = right
        then
          out(c,xr);
          out(cell,(i,y))
        else out(cell,(i,y))
    ) | (
      !
      in(cell,(i:nat,x:bitstring)); (* The first nat variable has been added due to the cell parameter *)
      event VCell_bitstring(cell,(i,x));
      out(cell,(i,x))
    ) | (
      !
      new sl:bitstring;
      new sr:bitstring;
      ( out(c,aenc((sl,sr),pk(k))) | in(c,(= sl,= sr)); event Attack())
    )
  )
