(* Corrected query of Avik-plutus30, so that ProVerif can now prove it 

Avik-plutus30:
query let mx = m; attacker:mx ==> 
      (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, vy) & ev:iswriter(gx, wx) & x <> revokedreader) 
    | (ev:isreader(gx, revokedreader, v) & ev:corrupt(revokedreader) & ev:writem(wx, mx, zero) & ev:iswriter(gv, wx)).

This file:
query let mx = m; attacker:mx ==> 
      (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, vy) & ev:iswriter(gx, wx) & x <> revokedreader) 
    | (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, zero) & ev:iswriter(gv, wx)).

These two queries are in fact equivalent, because when x <> revokereader
in the second part of |, it is in fact also handled by the first part 
of |. However, the clause:

begin:writem(v_1255,m[pkgen(zero(),sk[v_1256,sid_1257]),zero(),v_1255,v_1258],zero()) & 
begin:iswriter(v_1256,v_1255) & attacker:v_1255 & begin: corrupt(v_1259) &
begin:isreader(v_1256,v_1259,zero()) & attacker:v_1256 & attacker:v_1259 ->
attacker_p1:m[pkgen(zero(),sk[v_1256,sid_1257]),zero(),v_1255,v_1258]

cannot be discharged by either of the options of the query of Avik-plutus30.
It can be discharged only by discharging the case v_1259 <> revokereader
in the first part of | and the case v_1259 = revokereader in the second part,
which ProVerif currently cannot do.
The version of the query in this file avoids this problem. The clause
above is simply discharged by the second part of | in the query 
given in this file.
*)

(* Plutus *)

fun skgen/3.
fun pkgen/2.

data zero/0.
data succ/1.

data r12/0.
data r1/0.

fun larger/3.

equation larger(r12,r1,x) = x.

reduc unwind(skgen(w,succ(x),y)) = skgen(w,x,y).

fun write/3.

reduc read(z,write(z,u,pkgen(x,y)),skgen(w,x,y)) = u.

free c.
free f, newgroup, newreader, newwriter.
free corrupt.
free revokedreader.

query ev:gets(x, y, v) ==> ev:isreader(gx, x, v) & ev:iswriter(gx, wx) & ev:writem(wx, y, vy).
query let mx = m; attacker:mx ==> ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, vy) & ev:iswriter(gx, wx).
query attacker:m1 ==> ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, m1, vy) & ev:iswriter(gx, wx).
query ev:gets(revokedreader, y, succ(zero)).
query let mx = m; attacker:mx ==> 
      (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, vy) & ev:iswriter(gx, wx) & x <> revokedreader) 
    | (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, zero) & ev:iswriter(gv, wx)).
query let mx = m1; attacker:mx ==> 
      (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, vy) & ev:iswriter(gx, wx) & x <> revokedreader) 
    | (ev:isreader(gx, x, v) & ev:corrupt(x) & ev:writem(wx, mx, zero) & ev:iswriter(gv, wx)).

private fun rprivchannel/1.
private fun wprivchannel/1.

let process0 =
    in(newgroup, g); 
    new sk;
    (
    !
    in(newreader, (=g, r));
    event isreader(g,r,zero);
    out(rprivchannel(r), (skgen(g, zero, sk), zero));
    phase 1;
    if r <> revokedreader then
    event isreader(g,r,succ(zero));
    out(rprivchannel(r), (skgen(g, succ(zero), sk), succ(zero)))
    )
    |
    (
    !
    in(newwriter, (=g, w));
    event iswriter(g,w);
    out(wprivchannel(w), (pkgen(zero, sk), zero));
    phase 1;
    out(wprivchannel(w), (pkgen(succ(zero), sk), succ(zero)))
    ).


let process1 = 
    in(c,r);
    in(rprivchannel(r),(rkey,v));
    in(f,(v2,crypt));
    if v2 = v then
    (
    let m2 = read(f,crypt,rkey) in
    event gets(r, m2, v)
    )
    else 
    (
    let rkey2 = unwind(rkey) in
    let m2 = read(f,crypt,rkey2) in
    event gets(r, m2, v)
    ).

let process2 =
    in(c,r);
    in(rprivchannel(r), (rkey,v));
    in(corrupt, =r);
    event corrupt(r);
    out(c, rkey).

let process3 =
    in(c, w); 
    in(wprivchannel(w),(wkey,v));
    new m; 
    event writem(w, m, v);
    out(f,(v,write(f,m,wkey))).
 
let process31 =
    in(c, w); 
    in(wprivchannel(w),(wkey,v));
    new m1; 
    event writem(w, m1, v);
    out(f,(v,write(f,m1,wkey))).
 

process
	((!process0) | (! process1) | (!process2)  | (! process3) |
	phase 1; ((!process1) | (!process2) | (!process31))) 
	

(* EXPECTPV
RESULT ev:gets(x,y,v_6) ==> ev:isreader(gx,x,v_6) & ev:iswriter(gx,wx) & ev:writem(wx,y,vy) is true.
RESULT attacker_p1:m[v_2 = v_6,wkey = v_7,w_1 = v_8,!1 = v_9] ==> ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m[v_2 = v_6,wkey = v_7,w_1 = v_8,!1 = v_9],vy) & ev:iswriter(gx,wx) is true.
RESULT attacker_p1:m1[v_5 = v_6,wkey_1 = v_7,w_2 = v_8,!1 = v_9] ==> ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m1[v_5 = v_11,wkey_1 = v_12,w_2 = v_13,!1 = v_14],vy) & ev:iswriter(gx,wx) is true.
RESULT not ev:gets(revokedreader[],y,succ(zero())) is true.
RESULT attacker_p1:m[v_2 = v_6,wkey = v_7,w_1 = v_8,!1 = v_9] ==> (ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m[v_2 = v_6,wkey = v_7,w_1 = v_8,!1 = v_9],vy) & ev:iswriter(gx,wx) & x ≠ revokedreader[]) | (ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m[v_2 = v_6,wkey = v_7,w_1 = v_8,!1 = v_9],zero()) & ev:iswriter(gv,wx)) is true.
RESULT attacker_p1:m1[v_5 = v_6,wkey_1 = v_7,w_2 = v_8,!1 = v_9] ==> (ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m1[v_5 = v_6,wkey_1 = v_7,w_2 = v_8,!1 = v_9],vy) & ev:iswriter(gx,wx) & x ≠ revokedreader[]) | (ev:isreader(gx,x,v_10) & ev:corrupt(x) & ev:writem(wx,m1[v_5 = v_6,wkey_1 = v_7,w_2 = v_8,!1 = v_9],zero()) & ev:iswriter(gv,wx)) is true.
0.140s (user 0.092s + system 0.048s), max rss 10348K
END *)
