(* Protocol using a secure device.
   Found "Statverif: Verification of stateful processes" by Myrto Arapinis, Eike Ritter, and Mark Ryan in Proc. 24th IEEE Computer Security Foundations Symposium (CSF’11), pages 33–47. IEEE Press, 2011.

	 I believe the third query should be true. In any case, the attack trace given by ProVerif does not contradicts the query
*)

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.

const initE,nextE:bitstring.

event OutputE(channel,bitstring,nat,bitstring).
event InputE(channel,nat,bitstring).

set preciseActions = true.


query event(Attack).
query cell:channel,x:bitstring,i:nat,i':nat,occ:bitstring,occ':bitstring;
  inj-event(OutputE(cell,nextE,i,occ)) ==> inj-event(InputE(cell,i',occ')).
  (*event(InputE(cell)) ==> event(OutputE(cell,x)) && (x = initE || x = nextE).*)

query cell:channel,x:bitstring,i:nat,i':nat,t:time,t':time,t'':time,occ:bitstring,occ':bitstring;
  event(OutputE(cell,nextE,2,occ))@t && event(InputE(cell,i,occ'))@t' ==>
    (i,occ') = (1,occ) && t' < t
    || event(InputE(cell,1,occ))@t'' && t'' < t && (t' > t || t' < t'').


let Conf(cell:channel) =
  ! new occ:bitstring;
    new sk :bitstring;
    (in(c,x:bitstring);
    in(cell,y:bitstring);
    event InputE(cell,1,occ);
    let test:bool = (y = init && (x = left || x = right)) in
    if test
    then out(c,aenc(x,pk(sk))); in(cell,z:bitstring); event InputE(cell,1,occ); event OutputE(cell,nextE,1,occ);  out(cell,z)
    else out(c,aenc(y,pk(sk))))
    | (in(c,x:bitstring); let y = adec(x,sk) in event OutputE(cell,nextE,2,occ); out(cell,y)).

let Decrypt(cell:channel,k:bitstring) =
  ! new occ:bitstring;
    in(c,x:bitstring);
    let (xl:bitstring,xr:bitstring) = adec(x,k) in
    in(cell,y:bitstring);
    event InputE(cell,2,occ);
    if y = left then out(c,xl); event OutputE(cell,nextE,3,occ);out(cell,y)
    else if y = right then out(c,xr); event OutputE(cell,nextE,4,occ);out(cell,y)
    else event OutputE(cell,nextE,5,occ);out(cell,y).

let Device =
  new cell:channel;
  new k:bitstring; (* Key of the device *)
    out(c,pk(k)) (* Output of the public key *)
  | new occ:bitstring; event OutputE(cell,initE,6,occ); out(cell,init) (* Initialisation of the cell *)
  | 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 (* Alice sends her encrypted pairs. *)
    ).

process ! Device

(* EXPECTPV
RESULT not event(Attack) cannot be proved.
RESULT inj-event(OutputE(cell_3,nextE,i,occ_3)) ==> inj-event(InputE(cell_3,i',occ')) is true.
RESULT event(OutputE(cell_3,nextE,2,occ_3))@t && event(InputE(cell_3,i,occ'))@t' ==> ((i,occ') = (1,occ_3) && t > t') || (event(InputE(cell_3,1,occ_3))@t'' && t > t'' && (t' > t || t'' > t')) cannot be proved.
RESULT (query encoded as event(v,OutputE(cell_3,nextE,2,occ_3))@i && event(v_1,InputE(cell_3,i_1,occ'))@i_2 ==> (event(v_1,InputE(cell_3,i_1,occ'))@i_3 && i > i_3 && (i_1,occ') = (1,occ_3)) || (event(InputE(cell_3,1,occ_3))@i_4 && i > i_4 && event(v,OutputE(cell_3,nextE,2,occ_3))@i_5 && i_2 > i_5) || ((event(v_2,InputE(cell_3,1,occ_3))@i_6 ==> event(v_1,InputE(cell_3,i_1,occ'))) && i > i_6 && v_2 ≠ v_1))
RESULT (but event(v,OutputE(cell_3,nextE,2,occ_3))@i && event(v_1,InputE(cell_3,i_1,occ'))@i_2 ==> (event(v_1,InputE(cell_3,i_1,occ'))@i_3 && i > i_3 && (i_1,occ') = (1,occ_3)) || (event(InputE(cell_3,1,occ_3))@i_4 && i > i_4 && event(v,OutputE(cell_3,nextE,2,occ_3))@i_5 && i_2 > i_5) || (event(v_2,InputE(cell_3,1,occ_3))@i_6 && i > i_6 && event(v_1,InputE(cell_3,i_1,occ')) && v_2 ≠ v_1) is true.)
0.082s (user 0.058s + system 0.024s), max rss 8560K
END *)
