Aarhus, Denmark, 9-11 October 2017

### Functional core of F*

• Variant of dependent type theory

• , , inductives, matches, universe polymorphism
• Recursion and semantic termination check

• potential non-termination is an effect
• Refinements

• Refined value types: x:t{p}
• Refined computation types: Pure t pre post
• computationally and proof irrelevant, discharged by SMT
• Subtyping and sub-effecting

• Extensional equality

### This talk

• Verifying effectful programs extrinsically (monadic reification)

• Tactics as a user-defined, non-primitive effect (experimental)

type st (mem:Type) (a:Type) = mem -> Tot (a * mem)
total reifiable new_effect {
STATE_m (mem:Type) : a:Type -> Effect
with repr = st mem;
return = fun (a:Type) (x:a) (m:mem) -> x, m;
bind = fun (a b:Type) (f:st mem a) (g:a -> st mem b) (m:mem) ->
let z, m' = f m in g z m';
get = fun () (m:mem) -> m, m;
put = fun (m:mem) _ -> (), m  }
total reifiable new_effect STATE = STATE_m heap
• this monadic definition is the model F* uses to verify stateful code
• state can be primitively implemented under the hood or not
• for instance by ML heap or C stack+heap

let stexn a = nat -> Tot ((either a string) * nat))
new_effect {
STEXN: a:Type -> Effect with
repr    = stexn;
return  = fun (a:Type) (x:a) s -> Inl x, s;
bind    = fun (a b:Type) (f:stexn a) (g:a -> stexn b) s0 ->
let (r,s1) = f s0 in
match r with
| Inl ret -> Inl (g ret s1), s1
| Inr m -> Inr m, s1
raise   = fun (a:Type) (msg:string) s -> Inr msg, s
}
sub_effect STATE ~> STEXN {
lift = fun (a:Type) (e:st nat a) -> (fun s -> let (x,s') = e s in Inl x, s')
}

### Programming with effects, in direct style

• In F*, the programmer writes:

let incr () =
let x = STATE.get() in
STATE.put (x + 1);
let y = STATE.get() in
assert (y > x)

let incr () =
STATE.bind (STATE.get ()) (fun x ->
STATE.bind (STATE.put (x + 1)) (fun _ ->
STATE.bind (STATE.get ()) (fun y ->
STATE.return (assert (y > x)))))

### Programming with multiple effects

• Programmer writes:

  ( / ) : int -> x:int{x<>0} -> Tot int
let divide_by (x:int) : STEXN unit ...
= if x <> 0 then put (get () / x) else raise "Divide by zero"
• Elaborated to:

  let divide_by x =
if x <> 0 then STATE_STEXN.lift (STATE.bind (STATE.get())
(fun n -> STATE.put (n / x)))
else STEXN.raise "Divide by zero"
• F* infers the least effect of each sub-term

• automatically lifts computations to use the suitable effect
• ensures that reasoning isn't needlessly polluted by unused effects

### Verifying effectful programs

#### New way: extrinsically (by exposing pure monadic representation)

  STATE.reify : (St a) -> Ghost (nat -> Tot (a * nat))
• Allows us to give weak specification to an effectful function

  let incr (r:ref nat) : St unit = (r := (!r + 1))
• and prove lemmas about reification of effectful computation

  let incr_works (r:ref nat) (h:heap) :
Lemma (sel (snd (STATE.reify (incr r) h)) r = sel h r + 1) = ()

### Reification works very well

• Reducing effectful verification to pure verification

• for which F* already has good support (i.e. SMT automation)
• Recent experiments using this for “relational verification”

• Correctness of program transformations
• Information flow control
• Proofs of algorithmic optimizations (memoization, union-find)
• Simple game-based cryptographic proofs

### Tactics (New, Experimental)

• F* tactics written as effectful F* code (inspired by Lean, Idris)

• have access to F*'s proof state (and can efficiently roll it back)

• can introspect on F* terms (deep embedding, simply typed)

• can be interpreted by F*'s normalizer or compiled to OCaml

• user-defined, non-primitive effect: proof state + exceptions monad

  noeq type __result a =
| Success of a * proofstate
| Failed  of string    //error message
* proofstate //the proofstate at time of failure

let __tac (a:Type) = proofstate -> Tot (__result a)

reifiable reflectable new_effect {
TAC : a:Type -> Effect
with repr     = __tac   ... }

let tactic (a:Type) = unit -> Tac a

### Early uses of tactics

• Arithmetic expression canonizer (proof automation)

• Bitvectors in Vale (proof automation)

• Separation logic (proof automation, ongoing, ask Aseem)

• Pattern matcher (proof automation, ongoing)

• Generate code for inductive types (metaprogramming, ongoing)

• Turn F* to Low* buffer code (metaprogramming, upcoming)

• Metatheory of subsets of F* (interactive proofs, upcoming)

### Computation types indexed by predicate transformers

Pre- and post- conditions are just syntactic sugar:

Pure t (pre : Type0) (post : t->Type0)
= PURE t (fun k -> pre /\ forall y. post y ==> k y)
val factorial : x:int -> Pure int (requires (x >= 0)) (ensures (fun y -> y >= 0))
val factorial : x:int -> Pure (fun k -> x >= 0 /\ forall y. y >= 0 ==> k y)

Same for user-defined effects, like state:

ST t (pre : nat -> Type0) (post : nat -> t -> nat -> Type0)
= STATE t (fun n0 k -> pre n0 /\ forall x n1. post n0 x n1 ==> k x n1)
val incr : unit -> St unit (requires (fun n0 -> True))
(ensures (fun n0 _ n1 -> n1 = n0 + 1))
val incr : unit -> STATE unit (fun n0 k -> k () (n0 + 1))

### Computing weakest preconditions, by example

let incr () = STATE.bind (STATE.get()) (fun x -> STATE.put (x + 1))
• By inferring type for incr against following interface:
STATE.get : unit -> STATE nat (STATE.get_wp())
STATE.put : n:nat -> STATE unit (STATE.put_wp n)
STATE.bind : STATE 'a 'wa ->
(x:'a -> STATE 'b ('wb x)) ->
STATE 'b (STATE.bind_wp 'wa 'wb)
we compute the weakest precondition for incr
val incr : unit -> STATE unit
(STATE.bind_wp (STATE.get_wp()) (fun x -> STATE.put_wp (x + 1)))
= (fun n0 k -> k () (n0 + 1)) 
• Generic way of computing weakest-preconditions for all effects, provided we have a monad on predicate transformers

### Predicate transformers monad for state

let STATE.wp t = (t -> nat -> Type0) -> (nat -> Type0)
val STATE.return_wp : 'a -> Tot (STATE.wp 'a)
val STATE.bind_wp : (STATE.wp 'a) ->
('a -> Tot (STATE.wp 'b)) ->
Tot (STATE.wp 'b)
val STATE.get_wp : unit -> Tot (STATE.wp nat)
val STATE.put_wp : nat -> Tot (STATE.wp unit)
• we need to implement this Dijkstra monad:
let STATE.return_wp v = fun p -> p v
let STATE.bind_wp wp f = fun p -> wp (fun v -> f v p)
let STATE.get_wp () = fun p n0 -> p n0 n0
let STATE.put_wp n = fun p _ -> p () n
• and for a while we wrote such things by hand;
but this is quite tricky and comes with strong proof obligations
(correctness with respect to effect definition, monad laws, )

STATE.wp t  = (t -> nat -> Type0) -> (nat -> Type0)
~= nat -> (t * nat -> Type0) -> Type0
• This can be automatically derived from the state monad

STATE.repr t = nat -> t * nat

by selective continuation-passing style (CPS) returning Type0

• This works well for large class of monadic effects:
state, exceptions, continuations, etc.

• From monadic effect definition we can derive a correct-by-construction weakest-precondition calculus for this effect.

### Formalization

• Two calculi

• DMF: simply-typed with an abstract base monad, and restricted;
used to define monads, actions, lifts
• EMF*: dependently-typed, user-defined effects, reifying/reflecting
• Two translations from well-typed DMF terms to EMF*

• *-translation: gives specification (selective CPS)
• elaboration: gives implementation (essentially an identity)
• *-trans gives correct Dijkstra monad for elaborated terms

### Graphically

• PURE is the only primitive EMF* effect (F* also has DIV)

• A WP for PURE is of type

PURE.wp t = (t -> Type0) -> Type0
• Dijkstra monad for PURE is exactly the continuation monad
• Total Correctness of PURE:
If ⊢ e : PURE t wp   and   ⊢ wp p   then   e ↝* v   s.t.   ⊨ p v

• Say we have a term e : nat -> t × nat

• From logical relation, we get

• e : s₀ : nat -> PURE (t × nat) (e* s₀)
• From previous and correctness of PURE, we get
Correctness of STATE
If ⊢ e : nat -> t × nat   and  e* s₀ p
then   e s₀ ↝* (v,s)   s.t.   ⊨ p (v,s)

### Extra properties of the translations

• *-translation preserves equality

• Lifts mapped to Dijkstra lifts
• e* is monotonic: maps weaker post's to weaker pre's

• (∀x. p₁ ⇒ p₂) ⇒ e* p₁ ⇒ e* p₂
• e* is conjunctive: distributes over ∧ and ∀

• e* (fun x -> p₁ x ∧ p₂ x) ⇔ e* p₁ ∧ e* p₂
that's usable within the F* verification system

### Some dreams and ongoing work on F*

• Improve tactics, balance automation and control