(* Author : Lucca Hirschi *)

free c1:channel.
free c2:channel.
free c3:channel.
free c4:channel.
free c5:channel.
free c6:channel.
free c7:channel.  (* no reuse if public channels in order to improve performance when using the Classic semantics *)
free cqRead:channel [private].
free cqWrite:channel [private].
free cqMeasure:channel [private].
free cp:channel [private].

set preciseActions = true.

fun qubit(bitstring,bitstring):bitstring.
fun bs(bitstring,bitstring,bitstring,bitstring,bitstring):bitstring.
const sampling:bitstring [private].

const three:bitstring.
const four:bitstring.
const two:bitstring.
const one:bitstring.
const zero:bitstring.
const bases:bitstring.
const bit:bitstring.
const d:bitstring.
const Alice:bitstring.
const Bob:bitstring.
const ok:bitstring.
const cheat:bitstring.

reduc forall k1:bitstring,bitstring1:bitstring,position1:bitstring,role1:bitstring,value1:bitstring,role2:bitstring;
      bsEqu( bs(k1,bitstring1,position1,role1,value1),
             bs(k1,bitstring1,position1,role2,value1)) (* We could have used position2 here *)
      = ok.
reduc forall s:bitstring, pos:bitstring,bitstring1:bitstring,role1:bitstring,val:bitstring,role2:bitstring;
      measure((pos, qubit(bit, bs(s, bitstring1, pos, role1, val))),  (* incoming qubit *)
              (pos,            bs(s, bitstring1, pos, role2, val)))   (* measurement request *)
      = bit [private].

event hasCheat.
event hasUsedEPR.
query event(hasCheat).
query event(hasCheat) ==> event(hasUsedEPR).

let Bob_proc =
  let b_n   = bs(sampling, bases,  one, Alice, zero) in (* bit revealed to the attacker *)
  let b_c   = bs(sampling, bases,  one, Alice, one ) in (* cheating bit, revealed later *)
  let b1_   = bs(sampling, bases,  one, Bob,   zero) in (* Bases used by Bob *)
  let b2_   = bs(sampling, bases,  one, Bob,   one)  in
  let b3_   = bs(sampling, bases,  one, Bob,   zero) in
  let b4_   = bs(sampling, bases,  one, Bob,   one)  in
  let baseCommit = b_c in
( out(c1, b_n);
(* Bob is willing to measure qubits in <b1_,b2_> *)
 (out(cqRead, (one,   b1_))  |
  out(cqRead, (two,   b2_))  |
  out(cqRead, (three, b3_))  |
  out(cqRead, (four,  b4_))) |
(* Bob gets the measured bits *)
( in(cqMeasure, x1:bitstring);
  let (=one, bit1:bitstring) = x1 in
  in(cqMeasure, x2:bitstring);  (* would be better to have those two in parallel, can we do that? TODO*)
  let (=two, bit2:bitstring) = x2 in
  in(cqMeasure, x3:bitstring);
  let (=three, bit3:bitstring) = x3 in
  in(cqMeasure, x4:bitstring);
  let (=four, bit4:bitstring) = x4 in
(* The attacker is given the base he was supposed to commit on in the first place *)
  out(c2, baseCommit);
(* Bob receives the commit base and the verification bits from the network *)
  in(c3, x5:bitstring);
  let (=baseCommit, (bitV1:bitstring, bitV2:bitstring, bitV3:bitstring, bitV4:bitstring)) = x5 in
  if bitV1 = bit1 then
  if bitV2 = bit2 then
  if bitV3 = bit3 then
  if bitV4 = bit4 then
  event hasCheat)).

let quantumChannelAndAttacker =
(* Attacker can send qubits *)
  in(c5, write:bitstring); (* request to send a qubit *)
  let (pos:bitstring, bitW:bitstring, baseW:bitstring) = write in
  in(cqRead,  read:bitstring); (* request by Bob to receive a qubit *)
  let (=pos, baseR:bitstring) = read in
  let res = bsEqu(baseW, baseR) in
       (* Matching base: Bob receives xbit, the attacker-chosen bit *)
    out(cqMeasure, (pos, bitW))
  else (* Non Matching base: Bob receives a random that can later be accessed by the attacker if he learnes the basis Bob used here*)
    new n:bitstring;
    out(cqMeasure, (pos, n));
    event hasUsedEPR;
    (* EPR-stateful effect: *)
    in(c6, reqEPR:bitstring);
    let (=pos,base2:bitstring) = reqEPR in
    let res = bsEqu(baseR,base2) in
    out(c7, n).  (* No attack without this line*)

process
  (Bob_proc |
   quantumChannelAndAttacker |   quantumChannelAndAttacker |   quantumChannelAndAttacker |   quantumChannelAndAttacker
   )

(* EXPECTPV
RESULT not event(hasCheat) is false.
RESULT event(hasCheat) ==> event(hasUsedEPR) is true.
3.952s (user 3.912s + system 0.040s), max rss 32776K
END *)
