(* Delaune, Kremer, & Ryan (2009) variant of the Lee et al. election
   scheme. 
   Proof of receipt-freeness. We model that the collector
   checks that ballots are different, by manually modifying the
   swapping process generated by our compiler. (This point is 
   different from the model by Delaune, Kremer, & Ryan.) 

   See file Lee.DKR.ballotsecrecy.pv for further comparison with the
   code given by Delaune, Kremer, & Ryan in their paper. *)

free ch, chc: channel.
free a,b: bitstring.

type pkey.
type skey.
type seed.
type dvp_t.
type check_t.

(* Signature *)
fun penc(bitstring, pkey, seed): bitstring. (* probabilistic encryption *)
fun rencrypt(bitstring, seed): bitstring. (* re-encryption *)
fun f(seed, seed): seed. (* function combining random coins*)
fun sign(bitstring, skey): bitstring. (* digital signature *)
fun dvp(bitstring, bitstring, seed, pkey): dvp_t. (* designated verifier proof *)
fun fake_dvp(bitstring, bitstring, seed, skey): dvp_t.

const ok: check_t. (* check dvp ok *)
fun pk(skey):pkey.        (* get public key from private key *)

(* Equational theory *)
reduc forall m: bitstring, sk: skey, r: seed; 
      decrypt(penc(m,pk(sk),r),sk)=m.
equation forall m: bitstring, sk: skey, r1: seed, r2: seed; 
	 rencrypt(penc(m,pk(sk),r1),r2) = penc(m,pk(sk),f(r1,r2)). 
reduc forall m: bitstring, sk: skey; 
      checksign(sign(m,sk),pk(sk))= m.
reduc forall x: bitstring, r: seed, pkv: pkey; 
      checkdvp(dvp(x,rencrypt(x,r),r,pkv), x,rencrypt(x,r),pkv)=ok;
      forall x: bitstring, y: bitstring, z: seed, skv: skey;
      checkdvp(fake_dvp(x,y,z,skv),x,y,pk(skv))=ok.

(* Voter with secret key skv, vote v, talking to the adminstrator on private channel chA *)
let processV(chA1: channel, chA2: channel, pkc: pkey, pka: pkey, skv: skey, v: bitstring) =
    new r: seed;
    let e = penc(v,pkc,r) in
    out(chA1,(pk(skv),e,sign(e,skv)));
    in(chA2,(re: bitstring,sa: bitstring,dvpV: dvp_t));
    if checkdvp(dvpV,e,re,pk(skv)) = ok then
    if checksign(sa,pka) = re then
    out(ch,sa).

(* First component of the next process is V^chc, voting fst(v),
   second component is V' voting snd(v), and trying to make it look like vfake 
   (we have vfake = fst(v)) *)

let processVchcV'(chA1: channel, chA2: channel, pkc: pkey, pka: pkey, skv: skey, v: bitstring, vfake: bitstring) =
    out(chc, (pkc, pka, skv));
    new r: seed;
    out(chc, r);
    let e = penc(v,pkc,r) in
    out(chA1,(pk(skv),e,sign(e,skv)));
    in(chA2,(re: bitstring,sa: bitstring,dvpV: dvp_t));
    new r': seed;
    let fkdvp = fake_dvp(penc(vfake, pkc, r), re, r', skv) in
    out(chc, (re, sa, diff[dvpV, fkdvp])); 
    if checkdvp(dvpV,e,re,pk(skv)) = ok then
    if checksign(sa,pka) = re then
    out(ch,sa).

(* Administrator talking to voter with public key pubkv, on private channel chA *)
let processA(chA1: channel, chA2: channel, ska: skey, pubkv: pkey) =
    (* register a legimitate voter *)
    in(chA1,(=pubkv,enc: bitstring,sig: bitstring));
    if checksign(sig,pubkv)= enc then
    new r1: seed;
    let reAd=rencrypt(enc,r1) in
    let signAd=sign(reAd,ska) in	
    let dvpAd=dvp(enc,reAd,r1,pubkv) in
    out(chA2,(reAd,signAd,dvpAd)).


(* Collector *)
let processC(pka: pkey, skc: skey, synccha: channel, syncchc: channel) =
    (*sync 1 [noswap];*)
    in(ch,sev: bitstring);
    let ev = checksign(sev,pka) in
    let voteV = decrypt(ev,skc) in
    (* sync 2; 
    Manually implement synchronization plus 
    check that the ballots are distinct *)
    out(synccha, (sev, voteV));
    in(syncchc, voteV': bitstring);
    out(ch,voteV').


(* Swapper written manually: same as the one produced by our
   implementation, except that it additionally checks that the
   ballots are distinct. *)
let swapper(synccha1: channel, synccha2: channel, syncchc1: channel, syncchc2: channel) =
    in(synccha1, (ballot1: bitstring, vote1: bitstring));
    in(synccha2, (ballot2: bitstring, vote2: bitstring));
    if ballot1 <> ballot2 then
    out(syncchc1, diff[vote1, vote2]);
    out(syncchc2, diff[vote2, vote1]).

process 
    (* private keys *)
    new ska: skey; new skc: skey; new skva: skey; new skvb: skey;
    (* corresponding public keys *)
    let pka = pk(ska) in
    let pkc = pk(skc) in
    let pkva = pk(skva) in
    let pkvb = pk(skvb) in
    (* public keys disclosure *)
    out(ch,pka); out(ch,pkc); out(ch,pkva); out(ch,pkvb);
    (* private channels *)
    new chA1: channel; new chA2: channel;
    new chA1': channel; new chA2': channel;
    new synccha1: channel; new synccha2: channel; 
    new syncchc1: channel; new syncchc2: channel; 
    (* collector *) 
    (processC(pka, skc, synccha1, syncchc1) | 
     processC(pka, skc, synccha2, syncchc2) | 
     swapper(synccha1, synccha2, syncchc1, syncchc2) |
    (* voters & administrator *)
     processA(chA1, chA1', ska, pkva) | 
     processV(chA1, chA1', pkc, pka, skva, choice[a,b]) |
     processA(chA2, chA2', ska, pkvb) | 
     processVchcV'(chA2, chA2', pkc, pka, skvb, choice[b,a], b))

(* EXPECTPV
RESULT Observational equivalence is true.
0.184s (user 0.180s + system 0.004s), max rss 13724K
END *)
