Skip to content

Commit e335db0

Browse files
authored
Module Tweaks: Allow for fine grain editing of existing modules.
This commit introduces a new mechanism that permits the user to create a new module by slightly tweaking an existing module definition. It has the following operations: - Introduce new module variables. - Introduce new local variables. - Delete/Modify/Add statements at particular code positions - Delete branches (match support is not currently working fully) - Modify branch conditions - Insert new branches around a chunk of code - Modify the return expression Syntax: ``` module N = M with { var x : t (* add new module variable *) proc f [ var y : s (* add new local variable *) cp +/-/~ { s } (* insert after/insert before/modify a statement *) cp - (* delete a statement *) cp + ( e ) (* insert new if statement with condition `e` surrounding the suffix code block *) cp - ./?/#cstr (* delete all other branches except true/false/cstr *) ] res ~ ( e ) (* change the return expression *) } ```
1 parent 1f33371 commit e335db0

File tree

10 files changed

+479
-95
lines changed

10 files changed

+479
-95
lines changed

examples/br93.ec

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ import H.Lazy.
8383
(* BR93 is a module that, given access to an oracle H from type *)
8484
(* `from` to type `rand` (see `print Oracle.`), implements procedures *)
8585
(* `keygen`, `enc` and `dec` as follows described below. *)
86-
module BR93 (H:Oracle) = {
86+
module BR93 (H : Oracle) = {
8787
(* `keygen` simply samples a key pair in `dkeys` *)
8888
proc keygen() = {
8989
var kp;
@@ -183,14 +183,14 @@ qed.
183183

184184
(* But we can't do it (yet) for IND-CPA because of the random oracle *)
185185
(* Instead, we define CPA for BR93 with that particular RO. *)
186-
module type Adv (ARO: POracle) = {
186+
module type Adv (ARO : POracle) = {
187187
proc a1(p:pkey): (ptxt * ptxt)
188188
proc a2(c:ctxt): bool
189189
}.
190190
191191
(* We need to log the random oracle queries made to the adversary *)
192192
(* in order to express the final theorem. *)
193-
module Log (H:Oracle) = {
193+
module Log (H : Oracle) = {
194194
var qs: rand list
195195
196196
proc init() = {
@@ -251,23 +251,17 @@ declare axiom A_a1_ll (O <: POracle {-A}): islossless O.o => islossless A(O).a1.
251251
declare axiom A_a2_ll (O <: POracle {-A}): islossless O.o => islossless A(O).a2.
252252

253253
(* Step 1: replace RO call with random sampling *)
254-
local module Game1 = {
255-
var r: rand
256-
257-
proc main() = {
258-
var pk, sk, m0, m1, b, h, c, b';
259-
Log(LRO).init();
260-
(pk,sk) <$ dkeys;
261-
(m0,m1) <@ A(Log(LRO)).a1(pk);
262-
b <$ {0,1};
263-
264-
r <$ drand;
265-
h <$ dptxt;
266-
c <- ((f pk r),h +^ (b?m0:m1));
267-
268-
b' <@ A(Log(LRO)).a2(c);
269-
return b' = b;
270-
}
254+
local module Game1 = BR93_CPA(A) with {
255+
var r : rand
256+
257+
proc main [
258+
(* new local variable to store the sampled ptxt *)
259+
var h : ptxt
260+
(* inline key generation *)
261+
^ <@ {2} ~ { (pk, sk) <$ dkeys; }
262+
(* inline challenge encryption and idealize RO call *)
263+
^ c<@ ~ { r <$ drand; h <$ dptxt; c <- (f pk r, h +^ (b ? m0 : m1)); }
264+
]
271265
}.
272266

273267
local lemma pr_Game0_Game1 &m:
@@ -327,23 +321,11 @@ by move=> _ rR aL mL aR qsR mR h /h [] ->.
327321
qed.
328322

329323
(* Step 2: replace h ^ m with h in the challenge encryption *)
330-
local module Game2 = {
331-
var r: rand
332-
333-
proc main() = {
334-
var pk, sk, m0, m1, b, h, c, b';
335-
Log(LRO).init();
336-
(pk,sk) <$ dkeys;
337-
(m0,m1) <@ A(Log(LRO)).a1(pk);
338-
b <$ {0,1};
339-
340-
r <$ drand;
341-
h <$ dptxt;
342-
c <- ((f pk r),h);
343-
344-
b' <@ A(Log(LRO)).a2(c);
345-
return b' = b;
346-
}
324+
local module Game2 = Game1 with {
325+
proc main [
326+
(* Challenge ciphertext is now produced uniformly at random *)
327+
^ c<- ~ { c <- (f pk r, h); }
328+
]
347329
}.
348330

349331
local equiv eq_Game1_Game2: Game1.main ~ Game2.main:
@@ -402,12 +384,12 @@ local module OWr (I : Inverter) = {
402384

403385
(* We can easily prove that it is strictly equivalent to OW *)
404386
local lemma OW_OWr &m (I <: Inverter {-OWr}):
405-
Pr[OW(I).main() @ &m: res]
387+
Pr[OW(I).main() @ &m: res]
406388
= Pr[OWr(I).main() @ &m: res].
407389
proof. by byequiv=> //=; sim. qed.
408390

409391
local lemma pr_Game2_OW &m:
410-
Pr[Game2.main() @ &m: Game2.r \in Log.qs]
392+
Pr[Game2.main() @ &m: Game2.r \in Log.qs]
411393
<= Pr[OW(I(A)).main() @ &m: res].
412394
proof.
413395
rewrite (OW_OWr &m (I(A))). (* Note: we proved it forall (abstract) I *)
@@ -431,7 +413,7 @@ by auto=> /> [pk sk] ->.
431413
qed.
432414

433415
lemma Reduction &m:
434-
Pr[BR93_CPA(A).main() @ &m : res] - 1%r/2%r
416+
Pr[BR93_CPA(A).main() @ &m : res] - 1%r/2%r
435417
<= Pr[OW(I(A)).main() @ &m: res].
436418
proof.
437419
smt(pr_Game0_Game1 pr_Game1_Game2 pr_bad_Game1_Game2 pr_Game2 pr_Game2_OW).
@@ -675,4 +657,3 @@ by move=> O O_o_ll; proc; call (A_a2_ll O O_o_ll).
675657
qed.
676658

677659
end section.
678-

src/ecLowPhlGoal.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ type 'a zip_t =
578578
let t_fold f (cenv : code_txenv) (cpos : codepos) (_ : form * form) (state, s) =
579579
try
580580
let env = EcEnv.LDecl.toenv (snd cenv) in
581-
let (me, f) = Zpr.fold env cenv cpos f state s in
581+
let (me, f) = Zpr.fold env cenv cpos (fun _ -> f) state s in
582582
((me, f, []) : memenv * _ * form list)
583583
with Zpr.InvalidCPos -> tc_error (fst cenv) "invalid code position"
584584

src/ecMatching.ml

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ module Zipper = struct
5757
module P = EcPath
5858

5959
type ('a, 'state) folder =
60-
'a -> 'state -> instr -> 'state * instr list
60+
env -> 'a -> 'state -> instr -> 'state * instr list
61+
62+
type ('a, 'state) folder_tl =
63+
env -> 'a -> 'state -> instr -> instr list -> 'state * instr list
6164

6265
type spath_match_ctxt = {
6366
locals : (EcIdent.t * ty) list;
@@ -71,18 +74,19 @@ module Zipper = struct
7174
| ZIfThen of expr * spath * stmt
7275
| ZIfElse of expr * stmt * spath
7376
| ZMatch of expr * spath * spath_match_ctxt
74-
77+
7578
and spath = (instr list * instr list) * ipath
7679

7780
type zipper = {
7881
z_head : instr list; (* instructions on my left (rev) *)
7982
z_tail : instr list; (* instructions on my right (me incl.) *)
8083
z_path : ipath; (* path (zipper) leading to me *)
84+
z_env : env option;
8185
}
8286

8387
let cpos (i : int) : codepos1 = (0, `ByPos i)
8488

85-
let zipper hd tl zpr = { z_head = hd; z_tail = tl; z_path = zpr; }
89+
let zipper ?env hd tl zpr = { z_head = hd; z_tail = tl; z_path = zpr; z_env = env; }
8690

8791
let find_by_cp_match
8892
(env : EcEnv.env)
@@ -193,19 +197,19 @@ module Zipper = struct
193197
((cp1, sub) : codepos1 * codepos_brsel)
194198
(s : stmt)
195199
(zpr : ipath)
196-
: (ipath * stmt) * (codepos1 * codepos_brsel)
200+
: (ipath * stmt) * (codepos1 * codepos_brsel) * env
197201
=
198202
let (s1, i, s2) = find_by_cpos1 env cp1 s in
199-
let zpr =
203+
let zpr, env =
200204
match i.i_node, sub with
201205
| Swhile (e, sw), `Cond true ->
202-
(ZWhile (e, ((s1, s2), zpr)), sw)
206+
(ZWhile (e, ((s1, s2), zpr)), sw), env
203207

204208
| Sif (e, ifs1, ifs2), `Cond true ->
205-
(ZIfThen (e, ((s1, s2), zpr), ifs2), ifs1)
209+
(ZIfThen (e, ((s1, s2), zpr), ifs2), ifs1), env
206210

207211
| Sif (e, ifs1, ifs2), `Cond false ->
208-
(ZIfElse (e, ifs1, ((s1, s2), zpr)), ifs2)
212+
(ZIfElse (e, ifs1, ((s1, s2), zpr)), ifs2), env
209213

210214
| Smatch (e, bs), `Match cn ->
211215
let _, indt, _ = oget (EcEnv.Ty.get_top_decl e.e_ty env) in
@@ -216,19 +220,20 @@ module Zipper = struct
216220
with Not_found -> raise InvalidCPos
217221
in
218222
let prebr, (locals, body), postbr = List.pivot_at ix bs in
219-
(ZMatch (e, ((s1, s2), zpr), { locals; prebr; postbr; }), body)
223+
let env = EcEnv.Var.bind_locals locals env in
224+
(ZMatch (e, ((s1, s2), zpr), { locals; prebr; postbr; }), body), env
220225

221226
| _ -> raise InvalidCPos
222-
in zpr, ((0, `ByPos (1 + List.length s1)), sub)
227+
in zpr, ((0, `ByPos (1 + List.length s1)), sub), env
223228

224229
let zipper_of_cpos_r (env : EcEnv.env) ((nm, cp1) : codepos) (s : stmt) =
225-
let (zpr, s), nm =
230+
let ((zpr, s), env), nm =
226231
List.fold_left_map
227-
(fun (zpr, s) nm1 -> zipper_at_nm_cpos1 env nm1 s zpr)
228-
(ZTop, s) nm in
232+
(fun ((zpr, s), env) nm1 -> let zpr, s, env = zipper_at_nm_cpos1 env nm1 s zpr in (zpr, env), s)
233+
((ZTop, s), env) nm in
229234

230235
let s1, i, s2 = find_by_cpos1 env cp1 s in
231-
let zpr = zipper s1 (i :: s2) zpr in
236+
let zpr = zipper ~env s1 (i :: s2) zpr in
232237

233238
(zpr, (nm, (0, `ByPos (1 + List.length s1))))
234239

@@ -274,21 +279,28 @@ module Zipper = struct
274279
in
275280
List.rev after
276281

277-
let fold env cenv cpos f state s =
282+
let fold_tl env cenv cpos f state s =
278283
let zpr = zipper_of_cpos env cpos s in
279284

280285
match zpr.z_tail with
281286
| [] -> raise InvalidCPos
282287
| i :: tl -> begin
283-
match f cenv state i with
288+
match f (odfl env zpr.z_env) cenv state i tl with
284289
| (state', [i']) when i == i' && state == state' -> (state, s)
285-
| (state', si ) -> (state', zip { zpr with z_tail = si @ tl })
290+
| (state', si ) -> (state', zip { zpr with z_tail = si })
286291
end
287292

293+
let fold env cenv cpos f state s =
294+
let f e ce st i tl =
295+
let state', si = f e ce st i in
296+
state', si @ tl
297+
in
298+
fold_tl env cenv cpos f state s
299+
288300
let map env cpos f s =
289301
fst_map
290302
Option.get
291-
(fold env () cpos (fun () _ i -> fst_map some (f i)) None s)
303+
(fold env () cpos (fun _ () _ i -> fst_map some (f i)) None s)
292304
end
293305

294306
(* -------------------------------------------------------------------- *)

src/ecMatching.mli

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ module Zipper : sig
6161
z_head : instr list; (* instructions on my left (rev) *)
6262
z_tail : instr list; (* instructions on my right (me incl.) *)
6363
z_path : ipath ; (* path (zipper) leading to me *)
64+
z_env : env option; (* env with local vars from previous instructions *)
6465
}
6566

6667
exception InvalidCPos
@@ -79,7 +80,7 @@ module Zipper : sig
7980
val offset_of_position : env -> codepos1 -> stmt -> int
8081

8182
(* [zipper] soft constructor *)
82-
val zipper : instr list -> instr list -> ipath -> zipper
83+
val zipper : ?env : env -> instr list -> instr list -> ipath -> zipper
8384

8485
(* Return the zipper for the stmt [stmt] at code position [codepos].
8586
* Raise [InvalidCPos] if [codepos] is not valid for [stmt]. It also
@@ -101,7 +102,8 @@ module Zipper : sig
101102
*)
102103
val after : strict:bool -> zipper -> instr list list
103104

104-
type ('a, 'state) folder = 'a -> 'state -> instr -> 'state * instr list
105+
type ('a, 'state) folder = env -> 'a -> 'state -> instr -> 'state * instr list
106+
type ('a, 'state) folder_tl = env -> 'a -> 'state -> instr -> instr list -> 'state * instr list
105107

106108
(* [fold env v cpos f state s] create the zipper for [s] at [cpos], and apply
107109
* [f] to it, along with [v] and the state [state]. [f] must return the
@@ -112,6 +114,9 @@ module Zipper : sig
112114
*)
113115
val fold : env -> 'a -> codepos -> ('a, 'state) folder -> 'state -> stmt -> 'state * stmt
114116

117+
(* Same as above but using [folder_tl]. *)
118+
val fold_tl : env -> 'a -> codepos -> ('a, 'state) folder_tl -> 'state -> stmt -> 'state * stmt
119+
115120
(* [map cpos env f s] is a special case of [fold] where the state and the
116121
* out-of-band data are absent
117122
*)

src/ecParser.mly

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,30 @@ mod_item:
14431443
| IMPORT VAR ms=loc(mod_qident)+
14441444
{ Pst_import ms }
14451445

1446+
mod_update_var:
1447+
| v=var_decl { v }
1448+
1449+
mod_update_fun:
1450+
| PROC x=lident LBRACKET lvs=var_decl* fups=fun_update+ RBRACKET res_up=option(RES TILD e=sexpr {e})
1451+
{ (x, lvs, (List.flatten fups, res_up)) }
1452+
1453+
update_stmt:
1454+
| PLUS s=brace(stmt){ [Pups_add (s, true)] }
1455+
| MINUS s=brace(stmt){ [Pups_add (s, false)] }
1456+
| TILD s=brace(stmt) { [Pups_del; Pups_add (s, true)] }
1457+
| MINUS { [Pups_del] }
1458+
1459+
update_cond:
1460+
| PLUS e=sexpr { Pupc_add e }
1461+
| TILD e=sexpr { Pupc_mod e }
1462+
| MINUS bs=branch_select { Pupc_del bs }
1463+
1464+
fun_update:
1465+
| cp=loc(codepos) sup=update_stmt
1466+
{ List.map (fun v -> (cp, Pup_stmt v)) sup }
1467+
| cp=loc(codepos) cup=update_cond
1468+
{ [(cp, Pup_cond cup)] }
1469+
14461470
(* -------------------------------------------------------------------- *)
14471471
(* Modules *)
14481472

@@ -1453,6 +1477,9 @@ mod_body:
14531477
| LBRACE stt=loc(mod_item)* RBRACE
14541478
{ Pm_struct stt }
14551479

1480+
| m=mod_qident WITH LBRACE vs=mod_update_var* fs=mod_update_fun* RBRACE
1481+
{ Pm_update (m, vs, fs) }
1482+
14561483
mod_def_or_decl:
14571484
| locality=locality MODULE header=mod_header c=mod_cast? EQ ptm_body=loc(mod_body)
14581485
{ let ptm_header = match c with None -> header | Some c -> Pmh_cast(header,c) in

0 commit comments

Comments
 (0)