From “Hoare Logic” to “Dijkstra Monads”

fstar-logo

Cătălin Hriţcu, Inria Paris

MPRI 2-30, Paris, Friday, 27 January 2017

Today: verifying stateful programs

  • Verifying stateful programs in a functional language

  • Looking a bit behind the F* curtain

  • Hoare-style specifications

    • inspired by Hoare Type Theory / Ynot
  • Computing weakest preconditions

    • inspired by Dijkstra Monads in F*
    • monads of predicate transformers

core.org

  • A core syntax inspired by (Micro-)F*
  • Aimed at teaching verification of stateful programs
  • 2 variants:
    • Hoare style
    • Weakest precondition style

Verifying stateful programs

Imperative factorial

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)

Monotonic log

(* 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! *)

More basic materials: Software Foundations

More in depth reading about F*

Next steps

  • in 1-2 weeks: Verifying Crypto Implementations in F* (Karthik)

  • February 17: revisions

  • March 3: exam (material from 2nd half of the course)