Verifying stateful programs in a functional language
Looking a bit behind the F* curtain
Hoare-style specifications
Computing weakest preconditions
val factorial_tot : nat -> Tot nat
let rec factorial_tot x = if x = 0 then 1 else x * factorial_tot (x - 1)
(* TODO: write a stronger ensures clause for factorial that proves
it does the same thing as factorial_tot *)
val factorial : r1:ref nat -> r2:ref nat -> ST unit
(requires (fun h' -> True))
(ensures (fun h' a h -> True))
let rec factorial r1 r2 =
let x1 = !r1 in
if x1 = 0
then r2 := 1
else
(r1 := x1 - 1;
factorial r1 r2;
r2 := !r2 * x1)
(* global log of integers *)
val log : ref (list int)
let log = alloc []
val add_to_log : e:int -> ST unit
(requires (fun h0 -> True))
(ensures (fun h0 _ h1 ->
mem e (sel h1 log) (* p1: new element added *)
/\ (forall x. mem x (sel h0 log) ==> mem x (sel h1 log))
(* p2: all old elements preserved *)
))
let add_to_log e =
log := (e :: !log)
let main =
add_to_log 1;
let log1 = !log in
assert (mem 1 log1); (* proved by p1 *)
add_to_log 2;
let log2 = !log in
assert (mem 2 log2 (* proved by p1 *)
/\ mem 1 log2) (* proved by p2! *)
in 1-2 weeks: Verifying Crypto Implementations in F* (Karthik)
February 17: revisions
March 3: exam (material from 2nd half of the course)