(* Verification of Condition 3 in the definition of coercion-resistance 

This script has been obtained by transforming a similar script by 
Backes, Hritcu and Maffei available at 
http://www.infsec.cs.uni-sb.de/~maffei/ev.zip
We removed the swapping and used synchronisations (sync) instead.
We removed private channel communications, to simplify the script.
That helps both the understanding and the tool ProVerif.
We made other minor changes.  *)


(* Equational theory for cryptography + autogenerated ZK-theory *)

fun public1/1.
fun blindsign/2.
fun false/0.
fun sigver/3.
fun fakezk1/3. (* autogenerated ZK-theory *)
fun sk/1.
fun fakezk0/2. (* autogenerated ZK-theory *)
fun beta1/0. (* autogenerated ZK-theory *)
fun hash/1.
fun blindmessage/1.
fun or/2.
fun sign/2.
fun fakever/3. (* autogenerated ZK-theory *)
fun pk/1.
fun fakepublic/2. (* autogenerated ZK-theory *)
fun land/2.
fun alpha1/0. (* autogenerated ZK-theory *)
fun zkver0/1. 
fun zk0/2.
fun penc/3.
fun g/2. (* autogenerated ZK-theory *)
fun blindver/3.
fun true/0.
fun message/1.
fun unblind/2.
fun blind/2.
fun formula/1. (* autogenerated ZK-theory *)
fun eq/2.
reduc dec(penc(x,pk(y),z),sk(y)) = x.
fun petfalse/0.
reduc pet(penc(x,pk(y),z1),penc(x,pk(y),z2),sk(y)) = true.
reduc equals(x,x)=x.
equation eq(x,x) = true.
equation message(sign(x,y)) = x.
equation sigver(sign(x,sk(y)),x,pk(y)) = true.
equation blindver(unblind(blindsign(blind(x,z),sk(y)),z),x,pk(y)) = true.
equation blindmessage(unblind(blindsign(blind(x,z),y),z)) = x.

equation public1(zk0(xalpha1x0,xbeta1x1)) = xbeta1x1. (* autogenerated ZK-theory for ZK(1;1;true) *)
equation formula(zk0(xalpha1x0,xbeta1x1)) = true. (* autogenerated ZK-theory for ZK(1;1;true) *)
equation public1(fakezk1(x3,xbeta1x1,y4)) = xbeta1x1. (* autogenerated ZK-theory *)
equation formula(fakezk0(x3,y4)) = y4. (* autogenerated ZK-theory *)
equation formula(fakezk1(x3,xbeta1x1,y4)) = y4. (* autogenerated ZK-theory *)
equation zkver0(zk0((cred,r2,vote,r1),(penc(vote,pk(y),r1),penc(cred,pk(y),r2),pk(y),vote,z1,z2))) = true. (* replaced by AlternativeZKVer for zk type ZK(1;1;true) *)
equation zkver0(zk0((cred,r2,vote,r1),(penc(vote,pk(y),r1),penc(cred,pk(y),r2),pk(y),z1,vote,z2))) = true. (* replaced by AlternativeZKVer for zk type ZK(1;1;true) *)
equation zkver0(zk0((cred,r2,vote,r1),(penc(vote,pk(y),r1),penc(cred,pk(y),r2),pk(y),z1,z2,vote))) = true. (* replaced by AlternativeZKVer for zk type ZK(1;1;true) *)


(* private channels *)

private free chvote.

(* public channels *)

free res,comm,c.

(* votes *)

free va,vb,vc.

(* Non-deterministic choice of the vote *)

let votechooser = 
    out(chvote,va) | out(chvote,vb) | out(chvote,vc).

(* Tallying authority accepting a bulletin with encrypted credential enccred' *)

let tallier = 
    in(comm,zkp); 
    if zkver0(zkp) = true then 
    let (encvote,enccred,=pk(kT),=va,=vb,=vc)=public1(zkp) in 
    let x = pet(enccred,enccred',sk(kT)) in 
    let vote = dec(encvote,sk(kT)) in 
    out(res,vote).

(* Other voters *)

let othervoters =
    (* Registration: create credential *)
    new cred; 
    new r; 
    let enccred = penc(cred,pk(kT),r) in 
    (* The other voters are considered dishonest,
        we leak their credentials *)
    out(comm,(cred, sign(enccred,sk(kR))));
    (* Tallier for that voter *)
    let enccred' = enccred in tallier.

(* Tested voters *)

(* Voter that votes vote, with credential cred *)
let voter =
    new r1; 
    new r2; 
    out(comm,zk0((cred,r2,vote,r1),(penc(vote,pk(kT),r1),penc(cred,pk(kT),r2),pk(kT),va,vb,vc))).


let testedvoters = 
    new cred1; 
    new r1; 
    new cred2; 
    new r2; 
    let enccred1 = penc(cred1,pk(kT),r1) in 
    let enccred2 = penc(cred2,pk(kT),r2) in 
    out(comm,sign(enccred1,sk(kR)));
    out(comm,sign(enccred2,sk(kR))); 

    (* Coerced voter *)
    new fakecred;
    (* Credential to give to the coercer (fake credential) *)
    let coercercred = fakecred in
    new r4;
    let enccoercercred = penc(coercercred,pk(kT),r4) in
    (
    (* Coerced voter gives a credential to the coercer.
        Here, the coercer abstains. That's equivalent to removing the output
	of  coercercred. *)
    0 (* (out(c, coercercred)) *)
    |
    (* Voter that votes va, with credential cred2 (LHS) or cred1 (RHS) *)
    (let cred = cred1 in let vote = va in voter)
    |
    (let enccred' = enccred1 in tallier) |
    (let enccred' = enccred2 in tallier) |
    (let enccred' = choice[enccoercercred, petfalse] in tallier)
    ).

(* In the left-hand side (1st component of choice):
The voter with credential cred1 is coerced, 
he gives a fake credential, but the coercer abstains.
This voter also votes va
(line let cred = cred1 in let vote = va in voter)

We have a tallier that accepts a ballot with encrypted credential enccred1
(line let enccred' = enccred1 in tallier)
and one that accepts a ballot with encrypted credential enccred2
(line let enccred' = enccred2 in tallier)
The line  let enccred' = choice[enccoercercred, petfalse] in tallier
is the extractor.

In the right-hand side (2nd component of choice):
The voter with credential cred1 votes va
(line let cred = cred1 in let vote = va in voter)

We have a tallier that accepts a ballot with encrypted credential enccred1
(line let enccred' = enccred1 in tallier)
one that accepts a ballot with encrypted credential enccred2
(line let enccred' = enccred2 in tallier)
The extractor let enccred' = choice[enccoercercred, petfalse] in tallier
always abstains due to the constant petfalse.
*)

process 
	new kT; 
	new kR; 
	out(comm,(pk(kT),pk(kR))); 
	testedvoters | 
	! othervoters | 
	! votechooser 

(* EXPECTPV
RESULT Observational equivalence is true.
0.348s (user 0.344s + system 0.004s), max rss 15272K
END *)
