Verifying Stateful Programs with F*

fstar-logo

Cătălin Hriţcu, Inria Paris

(with help from Kenji Maillard)

Models and Tools for Cryptographic Proofs
Nancy, France, 10-13 July 2017

Verifying stateful programs

Variant #1: intrinsically (at definition time)

  • State in F*: mutable references

    val incr : r:ref int -> St unit
    let incr r = (r := (!r + 1))
  • Hoare logic-style pre- and post-conditions

    val incr : r:ref int -> ST unit (requires (fun h0 -> True))
                               (ensures (fun h0 _ h1 -> sel h1 r = sel h0 r + 1))
  • Beyond what can be expressed with refinements

  • Now pre-condition is relation on initial states; post-condition is relation on initial states, result values, and final states

    • the more complex the effect, the more complex the specs (and proofs)

Heap and ST operations (simplified)

module FStar.Heap

  val heap : Type
  val ref : Type -> Type

  val sel : #a:Type -> heap -> ref a -> Tot a
  val upd : #a:Type -> heap -> ref a -> a -> Tot heap

  val selUpdEq : #a:Type -> h:heap -> r:ref a -> v:a ->
        Lemma (sel (upd h r v) r  == v) [SMTPat (sel (upd h r v) r)]
                   
  val selUpdNeq : #a:Type -> h:heap -> r1:ref a -> r2:ref a -> v:a ->
        Lemma (r1 =!= r2 ==>
               sel (upd h r1 v) r2 == sel h r2) [SMTPat (sel (upd h r1 v) r2)]
module FStar.ST
  open FStar.Heap

  val (!): #a:Type -> r:ref a -> ST a
    (requires (fun (h:heap) -> True))
    (ensures (fun (h0:heap) (x:a) (h1:heap) -> h0 == h1 /\ x == sel h0 r))

  val (:=): #a:Type -> r:ref a -> v:a -> ST unit
    (requires (fun (h:heap) -> True))
    (ensures (fun (h0:heap) (x:a) (h1:heap) -> h1 == upd h0 r v))

Verifying incr (intuition)

module FStar.ST

  val (!) : #a:Type -> r:ref a -> ST a
    (requires (fun h0 -> True))
    (ensures (fun h0 x h1 -> h0 == h1 /\ x == sel h0 r))

  val (:=) : #a:Type -> r:ref a -> v:a -> ST unit
    (requires (fun h -> True))
    (ensures (fun h0 x h1 -> h1 == upd h0 r v))
val incr r:ref int -> ST unit (requires (fun h0 -> True))
            (ensures (fun h0 _ h2 -> exists h1 x. h0 == h1 /\ x == sel h0 r /\
                                                  h2 == upd h1 r (x + 1)))
let incr r = let x = !r in r := x + 1
val incr : r:ref int -> ST unit (requires (fun h0 -> True))
                           (ensures (fun h0 _ h2 -> sel h2 r = sel h0 r + 1))
sel (upd h0 r ((sel h0 r) + 1)) r = sel h0 r + 1
sel h0 r + 1 = sel h0 r + 1

Swapping two references

val swap_add_sub : r1:ref int -> r2:ref int -> St unit
let swap_add_sub r1 r2 =
  r1 := !r1 + !r2;
  r2 := !r1 - !r2;
  r1 := !r1 - !r2

let main =
  let r1 = alloc 1 in
  let r2 = alloc 2 in
  swap_add_sub r1 r2;
  print_string ("r1=" ^ string_of_int !r1 ^ "; " ^
                "r2=" ^ string_of_int !r2 ^ "\n")
...
r1=2; r2=1

Specifying reference swapping

val swap : r1:ref int -> r2:ref int -> ST unit
    (requires (fun h' -> True ))
    (ensures (fun h' _ h ->
                sel h r1 = sel h' r2 /\ sel h r2 = sel h' r1))
let swap r1 r2 =
  let t = !r1 in
  r1 := !r2;
  r2 := t

Hand proof sketch in code/03/SwapVerify.fst

Exercise: specify 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)

Specifying reference swap id="secin-at-defnlock pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="196" data-line-first="1924 style="display:bloc24>let r2 = alloc ->color:purple">0 then 1 1 it does the samlor:darkgreen"> TODO: write a stronger ecodt" s-2uionex/ulthe ( Prims.lue; gxam" Prims.lue">:darkgreen">*)

Specifying reference swaMoexaonicdif="para-bivbye incr alock pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="196" data-line-first="192" style="display:bloc2">val swap_add_sub n style="color:easex. n m:luer:bl"col0 = w <= me">let main = Type requires (fun h0 -> True)) (ensures (fun h' a h -> sel h r1)) ->color:purple">0 1)) (* TODO: write a stronger e2 (rde clr:darkgreen"> TODO: write a stronger (r:darkgreen"> TODO: write a stronger r:m (requirlor:easex)ue"Str:blue=---- factorDr i-> it does the same dt" st:darkgreen"> TODO: write a stronger (r:darkgreen"> TODO: write a stronger nt"- 1)">:darkgreen">*)
val swap_add_sub ed umlor:blue">-> r:ref a Type val swap_add_sub n style="cono:zero.
n:luer:bl"col0 = w &   ">->color:purple">0 let main =
  Type let r1 = alloc ->color:purple">0 then let x1 = !r1 in r := x +  TODO: write a stronger elorere">:darkgreen">*)
 TODO: write a stronger x &   "0);--- factorDr i->


*)
val swap_add_sub ed erelor:blue"x     ">->color:purple">0 

Specifying reference swaMoexaonicdif="para-b ples,faceh] =re"1block pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="107" data-line-first="10289style="display:bloc290H/span> r2 := Type -> a -> let main = Type fun h' a h fun h' a h
9(with help fro9m Kenji MaEincr ane">Type$\leq$---esc>Type$\subseteq$---esc>Type$\to^*$---esc>

Type

val factorial_tot : nat Type -> r:ref a -> a -> Tot heap

  <>val factorial_tot : nat Type -> r:ref a -> a -> v:a -> Type requires (fun h -> True))
    (requires (fun h0 x h1 -> h1 == upd h0 r v))

Specifying reference swap ibons Type -> a let main = Type let r1 = alloc
Type -> r:ref a -> a -> v:a -> Tot heap

  -> Tot heap

  Type -> r:ref a -> a -> v:a ST unit
      (requires (fun h0 -> True))
                 p ="constam)      (ensures (fun h0 _ h1 -> sel h1 r = sel h0 r +  wIme)Type -> r:ref a -> a -> v:a ST unit
      (requires (fun h0 -> True))
                  token:m p-> ensures (fun h0 _ h1 -> sel h1 r = sel h0 r + 


Specifying reference swapss="e moexaonicst-clock pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="107" data-line-first="1033 style="display:bloc33>val incr : r:ref fun h' a h let swap r1 r2 = Type let main = let main = Type requires (fun h0 -> True)) (ensures (fun h' a h -> sel h r1v:`mem` ())
val incr : r:ref ed umlor:blue">-> r:ref a Type val swap_add_sub n style="color:()ue">Type let r1 = alloc in r := x + in0 fun h' a h ST0 fun h' a h ST0 fun h' a h ST0 fun h' a h ST0 in r := x + ST0 


Specifying reference swaPrlk; sType -> ->
val incr : r:ref   Type -> v:a -> v:a -> True))
                     /co| Mpre clavl,oFrozen:ve">-> sel h2 r = sel h0 r + -> True))
                 Falsegreen">(* TODO: write a stronger e2 (revolveor:darkgreen"> TODO: write a stronger (r:darkgreen"> TODO: write a stronger a:Tcol) e"Tolor:darkgreen">*)
 TODO: write a stronger arlk;
   r:darkgreen">*)
 TODO: write a stronger   " cloa))nstevolveoa">:darkgreen">*)

(with help fr38(wyou fix it?----------ata-line="135">
H/span> r2 := Type -> v:a -> v:a -> -> sel h2 r = sel h0 r + -> True))
                 Falsegreen">(*Type Type TypeType


Specifying reference swaIlues, izpla fr:bFreezclaass="para-block pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="156" data-line-first="1540 style="display:bloc40>Type (*Type -> h1 == upd hial "color:o| Mpre clavo| Frozen:v">-> sel h2 r = sel h0 r + (*Type (*Type
val incr : r:ref ed umlor:blue">-> r:ref a Type Type let r1 = alloc ->  TODO: write a stronger eignnd pr:darkgreen">*)
 TODO: write a stronger  bluere"-- factorapVeri->


*)
in0 in0 fun h' a h let x1 = !rn style="color:darkgreen"> TODO: write a stronger e clause"7;"-- factorapVeri->


*)
fun h' a h in0  TODO: write a stronger eignnd pr:darkgreen">*)
 TODO: write a stronger  bluere;"-- factorapVeri->


*)
fun h' a h let x1 = !r1 in r := x +  TODO: write a stronger elorere">:darkgreen">*)
 TODO: write a stronger x =st0e"-- factorapVeri->


*)
fun h' a h in0 in0 


Specifying reference swaGivereiType Type let main = Type Type Type fun h0 -> True)) (ensures (fun h' a h -> sel h r1Empty?"()) (*Type Type requires (fun h -> True)) (ensures (fun h' a h -> True)) (fun h' a h -> h1 == upd hial "color:o| Mpre clavo| Frozen:v">-> sel h2 r = sel h0 r + (*Type requires (fun h0 -> True)) (ensures (fun h' a h -> sel h r1)) (*Type Type < nstconstFrozen:(Mpre cl?.v !rs="block console" data-line">
(with help fr463/sp="colotive facto clause "    sreezusblue""colt
   :e (reeres (fun h'ue))
      (ensur0res Mpre cl? ="constant' a h -> exists x.
     r:blue"es Mpre cl? ="constant                              h2 =="cons1aa/\
 Frozen:(Mpre cl?.v ="constant' )
2 (r>reezus#a"cnstconstFrozen:(Mpre cl?.v !rs--------" data-line">
(with help fr473/sp="colotive facto clause     var l styl claus fr arbitraryono:-frozen
ss="para-ufr:b>reezur i->atrial_tot 


Specifying reference swaata-lierei< id="secprogramnlock (with help fr4lue">="coloVat-def">Type="colo#>Type="colo2: ex stysme)Typerequires (Type -> ST unit (requires ( ensures (fun h0 _ h1 in r := x +
Hand proof s4-----------Ant"ws uores gclasweakorialHeffne="sec    var 
----pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="156" data-line-first="1549 style="display:bloc49>...
r1=2; r2=1<>e">let r2 = alloc Type requires (fun h -> True))
                       e">ensures (fun h' a h -> True))
                           (=o>fun h' a h -> h1 == upd h class="co>fun h' a h 1))
  • (with help fr49m Kenji Ma…-an>(with help fr49m Kenji Marialnle="coh2 mmas><     atifme)t"36ps isffne="secroofud)t"36
    ----pre-fenced pre-fenced3 language-fstarlang lang-fstarlang fstarlang colorized" data-line="156" data-line-first="1549style="display:block49>let r2 = alloc Type fun h' a h requires (1))
  • 
    
    s
    
    
    
  • Specifying reference swapome d:eamsufr:bongopla but uonsF*lock prsec data-ssec datnc ir loose"heading-stat510 datlic data-sliculng-c datnc irng-c ooseng-"heading-stat510 datpheading-stat510 d-an>(with help fr51ode code1 lfor fa" data-seor fanc ir><>Fir:bbe---bal>(with help fr51ode code1 ----prsec data-ssec datndashcroofati"heading-stat511 datlic data-sliculng-c datndashng-croofating-"heading-stat511 d-an>(with help fr511 d-i> F-an>(with help fr511 d-i> Type
  • s --lidatlic data-sliculng-c datnc irng-c ooseng- ">
    <>Fu(with help fr513de code1 
    ----prsec data-ssec datndashcroofati"heading-stat514 datlic data-sliculng-c datndashng-croofating-"heading-stat514 d>TypeTypeTypeType1icsmaral;="cof-cerem/h3>
    <2 mn d)t"36
    --lid
    --lidatlic data-sliculng-c datnc irng-c ooseng- ">
    
    <>ata-lioar:b:blloylnew,isffici-linHTTPSs " 3 l(Ectre--(with help fr517de code1 
    ----prsec data-ssec datndashcroofati"heading-stat518 datlic data-sliculng-c datndashng-croofating-"heading-stat518 d>TypeTypeTypeTypeType
    --lidatlic data-sliculng-c datnc irng-c ooseng- ">
    
    <>Opportn h's vebroughtoinvbye irks w claeffne= system=" or fad-an>(with help fr521de code1 
    ----prsec data-ssec datndashcroofati"heading-stat522 datlic data-sliculng-c datndashng-croofating-"heading-stat522 d-an>(with help fr522de code1 beyo clMLaeffne=s: extensiry iet,o0">curparay,">Type(with help fr522de code1 
    --lidatlic data-sliculng-c datndashng-croofating-"heading-stat523 d>Type<     `DIV`?dn id=----"- cpe
    --lid
    -------------------------------------------------------->
    
    
    
  • Specifying reference swaF*:shout ie)t"36ps isffne="secprogramnlock prsec data-ssec datnc ir loose"heading-stat531 datlic data-sliculng-c datnc irng-c ooseng-"heading-stat531 datpheading-stat531 d-an>(with help fr531de code1 lfor fa" data-seor fanc ir><>>requires ((with help fr531de code1 ------lidatlic data-sliculng-c datnc irng-c ooseng-"heading-stat533 datpheading-stat533 d>Type<>>requires (SMT code1 l" or fad-an>(with help fr533de code1 ------lidatlic data-sliculng-c datnc irng-c ooseng-"heading-stat535 datpheading-stat535 d>Type<>>requires (1-base:bonb:bleta-lintcols code1 l" or fad-an>(with help fr535de code1 ------lidatlic data-sliculng-c datnc irng-c ooseng-"heading-stat537 datpheading-stat537 d>Type<>Olet source, n styonbGitHub(with help fr537de code1 ------lidatlic data-sliculng-c datnc irng-c ooseng-"heading-stat539 datpheading-stat539/span>(with help fr539/spcode1 lfor fa" data-seor fanc ir><>Tu)) ,s-apert,oslians at fc irngsta.org(with help fr539de code1 ------lidatlic data-sliculng-c datnc irng-c ooseng-"heading-stat541 datpheading-stat541 d-an>(with help fr541de code1 lfor fa" data-seor fanc ir><>PhD ples,nships at Microsoft Research stor fad-an>(with help fr541de code1 (Cambridge, Redmoed, Bstaa> (e);pcpplie)t"36pinvDec 2017-an>(with help fr542de code1 ">Type
    <>N" d: C st-Base:bCryptographmeyVout ie)t"36piniF*.
    Markulf =" or fad-an>(with help fr544de code1 
    ------lidsec-swappi-------------an>(with help frde code1 l-----atsvg --s' dat-svg-pdats'ires