oadt.lang_oadt.syntax
Definitions
Expressions (e, Ļ)
This corresponds to expressions in Fig. 9 in the paper. Here we use locally nameless representation for binders.
Inductive expr :=
(* Locally bound variables, i.e. de Bruijn indices. *)
| EBVar (k : nat)
(* Free variables *)
| EFVar (x : atom)
(* Global variables, referring to global functions, ADTs and OADTs. *)
| EGVar (x : atom)
(* Simple types *)
| EUnitT
(* Oblivious Boolean if the label is high, otherwise public Boolean *)
| EBool (l : bool)
| EProd (Ļ1 Ļ2 : expr)
(* Oblivious sum if the label is high, otherwise public sum *)
| ESum (l : bool) (Ļ1 Ļ2 : expr)
(* Dependent function type *)
| EPi (Ļ1 Ļ2: expr)
(* Unit and Boolean values *)
| EUnitV
| ELit (b : bool)
(* Function abstraction *)
| EAbs (Ļ e : expr)
(* Expression and type application *)
| EApp (e1 e2 : expr)
(* Let binding *)
| ELet (e1 e2 : expr)
(* Oblivious conditional (i.e. MUX) if the label is high, otherwise public
conditional *)
| EIte (l : bool) (e0 e1 e2 : expr)
(* Pair and projection *)
| EPair (e1 e2 : expr)
| EProj (b : bool) (e : expr)
(* Oblivious injection if the label is high, otherwise public injection *)
| EInj (l : bool) (b : bool) (Ļ e : expr)
(* Oblivious sum elimination if the label is high, otherwise public sum
elimination *)
| ECase (l : bool) (e0 : expr) (e1 : expr) (e2 : expr)
(* Iso-recursive type introduction and elimination *)
| EFold (X : atom) (e : expr)
| EUnfold (X : atom) (e : expr)
(* Section for Boolean *)
| ESec (e : expr)
(* Runtime boxed values *)
| EBoxedLit (b : bool)
| EBoxedInj (b : bool) (Ļ e : expr)
.
(* Locally bound variables, i.e. de Bruijn indices. *)
| EBVar (k : nat)
(* Free variables *)
| EFVar (x : atom)
(* Global variables, referring to global functions, ADTs and OADTs. *)
| EGVar (x : atom)
(* Simple types *)
| EUnitT
(* Oblivious Boolean if the label is high, otherwise public Boolean *)
| EBool (l : bool)
| EProd (Ļ1 Ļ2 : expr)
(* Oblivious sum if the label is high, otherwise public sum *)
| ESum (l : bool) (Ļ1 Ļ2 : expr)
(* Dependent function type *)
| EPi (Ļ1 Ļ2: expr)
(* Unit and Boolean values *)
| EUnitV
| ELit (b : bool)
(* Function abstraction *)
| EAbs (Ļ e : expr)
(* Expression and type application *)
| EApp (e1 e2 : expr)
(* Let binding *)
| ELet (e1 e2 : expr)
(* Oblivious conditional (i.e. MUX) if the label is high, otherwise public
conditional *)
| EIte (l : bool) (e0 e1 e2 : expr)
(* Pair and projection *)
| EPair (e1 e2 : expr)
| EProj (b : bool) (e : expr)
(* Oblivious injection if the label is high, otherwise public injection *)
| EInj (l : bool) (b : bool) (Ļ e : expr)
(* Oblivious sum elimination if the label is high, otherwise public sum
elimination *)
| ECase (l : bool) (e0 : expr) (e1 : expr) (e2 : expr)
(* Iso-recursive type introduction and elimination *)
| EFold (X : atom) (e : expr)
| EUnfold (X : atom) (e : expr)
(* Section for Boolean *)
| ESec (e : expr)
(* Runtime boxed values *)
| EBoxedLit (b : bool)
| EBoxedInj (b : bool) (Ļ e : expr)
.
Module expr_notations.
(* Adapted from _Software Foundations_. *)
Coercion ELit : bool >-> expr.
Coercion EBVar : nat >-> expr.
(* Adapted from _Software Foundations_. *)
Coercion ELit : bool >-> expr.
Coercion EBVar : nat >-> expr.
Quote
Lispy unquote
Notation "',(' e ')'" := e (in custom oadt at level 0,
e constr at level 0).
Notation "'high'" := (true) (only parsing).
Notation "'low'" := (false) (only parsing).
Notation "( x )" := x (in custom oadt, x at level 99).
Notation "x" := x (in custom oadt at level 0, x constr at level 0).
Notation "'bvar' x" := (EBVar x) (in custom oadt at level 0, x constr at level 0,
only parsing).
Notation "'fvar' x" := (EFVar x) (in custom oadt at level 0, x constr at level 0,
only parsing).
Notation "'gvar' x" := (EGVar x) (in custom oadt at level 0, x constr at level 0).
Notation "'lit' b" := (ELit b) (in custom oadt at level 0, b constr at level 0,
only parsing).
Notation "'š'" := EUnitT (in custom oadt at level 0).
Notation "'Unit'" := EUnitT (in custom oadt at level 0, only parsing).
Notation "'š¹{' l '}'" := (EBool l) (in custom oadt at level 0,
l constr at level 0,
format "'š¹{' l '}'").
Notation "'š¹'" := (EBool low) (in custom oadt at level 0).
Notation "'Bool'" := (EBool low) (in custom oadt at level 0, only parsing).
Notation "'~š¹'" := (EBool high) (in custom oadt at level 0).
Notation "'~Bool'" := (EBool high) (in custom oadt at level 0, only parsing).
Notation "Ļ1 * Ļ2" := (EProd Ļ1 Ļ2) (in custom oadt at level 2,
Ļ1 custom oadt,
Ļ2 custom oadt at level 0).
Notation "Ļ1 '+{' l '}' Ļ2" := (ESum l Ļ1 Ļ2) (in custom oadt at level 3,
l constr at level 0,
left associativity,
format "Ļ1 '+{' l '}' Ļ2").
Notation "Ļ1 + Ļ2" := (ESum low Ļ1 Ļ2) (in custom oadt at level 3,
left associativity).
Notation "Ļ1 ~+ Ļ2" := (ESum high Ļ1 Ļ2) (in custom oadt at level 3,
left associativity).
Notation "'Ī ' : Ļ1 , Ļ2" := (EPi Ļ1 Ļ2) (in custom oadt at level 50,
right associativity,
format "Ī : Ļ1 , Ļ2").
Notation "\ : Ļ '=>' e" := (EAbs Ļ e) (in custom oadt at level 90,
Ļ custom oadt at level 99,
e custom oadt at level 99,
left associativity,
format "\ : Ļ => e").
Notation "e1 e2" := (EApp e1 e2) (in custom oadt at level 1, left associativity).
Notation "()" := EUnitV (in custom oadt at level 0).
Notation "( x , y , .. , z )" := (EPair .. (EPair x y) .. z)
(in custom oadt at level 0,
x custom oadt at level 99,
y custom oadt at level 99,
z custom oadt at level 99).
Notation "'Ļ@' b e" := (EProj b e) (in custom oadt at level 0,
b constr at level 0,
e custom oadt at level 0,
format "Ļ@ b e").
Notation "'Ļ1' e" := (EProj true e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'Ļ2' e" := (EProj false e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'sš¹' e" := (ESec e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'if{' l '}' e0 'then' e1 'else' e2" := (EIte l e0 e1 e2)
(in custom oadt at level 89,
l constr at level 0,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity,
format "'if{' l '}' e0 'then' e1 'else' e2").
Notation "'if' e0 'then' e1 'else' e2" := (EIte low e0 e1 e2)
(in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'~if' e0 'then' e1 'else' e2" := (EIte high e0 e1 e2)
(in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99).
Notation "'let' e1 'in' e2" := (ELet e1 e2)
(in custom oadt at level 0,
e1 custom oadt at level 99,
e2 custom oadt at level 99).
Notation "'inj{' l '}@' b < Ļ > e" := (EInj l b Ļ e) (in custom oadt at level 0,
l constr at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "'inj{' l '}@' b < Ļ > e").
Notation "'inj@' b < Ļ > e" := (EInj low b Ļ e) (in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inj@ b < Ļ > e").
Notation "'inl' < Ļ > e" := (EInj low true Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inl < Ļ > e").
Notation "'inr' < Ļ > e" := (EInj low false Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inr < Ļ > e").
Notation "'~inj@' b < Ļ > e" := (EInj high b Ļ e) (in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inj@ b < Ļ > e").
Notation "'~inl' < Ļ > e" := (EInj high true Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inl < Ļ > e").
Notation "'~inr' < Ļ > e" := (EInj high false Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inr < Ļ > e").
(* I still want to use high and low *)
Notation "'case{' l '}' e0 'of' e1 '|' e2" :=
(ECase l e0 e1 e2) (in custom oadt at level 89,
l constr at level 0,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity,
format "'case{' l '}' e0 'of' e1 '|' e2").
Notation "'case' e0 'of' e1 '|' e2" :=
(ECase low e0 e1 e2) (in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'~case' e0 'of' e1 '|' e2" :=
(ECase high e0 e1 e2) (in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'fold' < X > e" := (EFold X e) (in custom oadt at level 0,
X custom oadt at level 0,
e custom oadt at level 0,
format "fold < X > e").
Notation "'unfold' < X > e" := (EUnfold X e) (in custom oadt at level 0,
X custom oadt at level 0,
e custom oadt at level 0,
format "unfold < X > e").
Notation "[ b ]" := (EBoxedLit b) (in custom oadt at level 0,
b constr at level 0).
Notation "[ 'inj@' b < Ļ > e ]" := (EBoxedInj b Ļ e)
(in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inj@ b < Ļ > e ]").
Notation "[ 'inl' < Ļ > e ]" := (EBoxedInj true Ļ e)
(in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inl < Ļ > e ]").
Notation "[ 'inr' < Ļ > e ]" := (EBoxedInj false Ļ e)
(in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inr < Ļ > e ]").
Notation "D" := D (in custom oadt_def at level 0, D constr at level 0).
Notation "( D )" := D (in custom oadt_def, D at level 99).
Notation "'data' X := e" := (X, DADT e) (in custom oadt_def at level 0,
X constr at level 0,
e custom oadt at level 99).
Notation "'obliv' X ( : Ļ ) := e" := (X, DOADT Ļ e)
(in custom oadt_def at level 0,
X constr at level 0,
Ļ custom oadt at level 99,
e custom oadt at level 99,
format "obliv X ( : Ļ ) := e").
Notation "'def' x : Ļ := e" := (x, DFun Ļ e) (in custom oadt_def at level 0,
x constr at level 0,
Ļ custom oadt at level 99,
e custom oadt at level 99).
Notation "[{ x }]" := (cons x nil)
(x custom oadt_def at level 99).
Notation "[{ x ; y ; .. ; z }]" := (cons x (cons y .. (cons z nil) ..))
(x custom oadt_def at level 99,
y custom oadt_def at level 99,
z custom oadt_def at level 99,
format "[{ '[v ' '/' x ; '/' y ; '/' .. ; '/' z ']' '//' }]").
Notation "'ite' e0 e1 e2" := (if e0 then e1 else e2)
(in custom oadt at level 0,
e0 constr at level 0,
e1 custom oadt at level 0,
e2 custom oadt at level 0).
End expr_notations.
e constr at level 0).
Notation "'high'" := (true) (only parsing).
Notation "'low'" := (false) (only parsing).
Notation "( x )" := x (in custom oadt, x at level 99).
Notation "x" := x (in custom oadt at level 0, x constr at level 0).
Notation "'bvar' x" := (EBVar x) (in custom oadt at level 0, x constr at level 0,
only parsing).
Notation "'fvar' x" := (EFVar x) (in custom oadt at level 0, x constr at level 0,
only parsing).
Notation "'gvar' x" := (EGVar x) (in custom oadt at level 0, x constr at level 0).
Notation "'lit' b" := (ELit b) (in custom oadt at level 0, b constr at level 0,
only parsing).
Notation "'š'" := EUnitT (in custom oadt at level 0).
Notation "'Unit'" := EUnitT (in custom oadt at level 0, only parsing).
Notation "'š¹{' l '}'" := (EBool l) (in custom oadt at level 0,
l constr at level 0,
format "'š¹{' l '}'").
Notation "'š¹'" := (EBool low) (in custom oadt at level 0).
Notation "'Bool'" := (EBool low) (in custom oadt at level 0, only parsing).
Notation "'~š¹'" := (EBool high) (in custom oadt at level 0).
Notation "'~Bool'" := (EBool high) (in custom oadt at level 0, only parsing).
Notation "Ļ1 * Ļ2" := (EProd Ļ1 Ļ2) (in custom oadt at level 2,
Ļ1 custom oadt,
Ļ2 custom oadt at level 0).
Notation "Ļ1 '+{' l '}' Ļ2" := (ESum l Ļ1 Ļ2) (in custom oadt at level 3,
l constr at level 0,
left associativity,
format "Ļ1 '+{' l '}' Ļ2").
Notation "Ļ1 + Ļ2" := (ESum low Ļ1 Ļ2) (in custom oadt at level 3,
left associativity).
Notation "Ļ1 ~+ Ļ2" := (ESum high Ļ1 Ļ2) (in custom oadt at level 3,
left associativity).
Notation "'Ī ' : Ļ1 , Ļ2" := (EPi Ļ1 Ļ2) (in custom oadt at level 50,
right associativity,
format "Ī : Ļ1 , Ļ2").
Notation "\ : Ļ '=>' e" := (EAbs Ļ e) (in custom oadt at level 90,
Ļ custom oadt at level 99,
e custom oadt at level 99,
left associativity,
format "\ : Ļ => e").
Notation "e1 e2" := (EApp e1 e2) (in custom oadt at level 1, left associativity).
Notation "()" := EUnitV (in custom oadt at level 0).
Notation "( x , y , .. , z )" := (EPair .. (EPair x y) .. z)
(in custom oadt at level 0,
x custom oadt at level 99,
y custom oadt at level 99,
z custom oadt at level 99).
Notation "'Ļ@' b e" := (EProj b e) (in custom oadt at level 0,
b constr at level 0,
e custom oadt at level 0,
format "Ļ@ b e").
Notation "'Ļ1' e" := (EProj true e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'Ļ2' e" := (EProj false e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'sš¹' e" := (ESec e) (in custom oadt at level 0,
e custom oadt at level 0).
Notation "'if{' l '}' e0 'then' e1 'else' e2" := (EIte l e0 e1 e2)
(in custom oadt at level 89,
l constr at level 0,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity,
format "'if{' l '}' e0 'then' e1 'else' e2").
Notation "'if' e0 'then' e1 'else' e2" := (EIte low e0 e1 e2)
(in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'~if' e0 'then' e1 'else' e2" := (EIte high e0 e1 e2)
(in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99).
Notation "'let' e1 'in' e2" := (ELet e1 e2)
(in custom oadt at level 0,
e1 custom oadt at level 99,
e2 custom oadt at level 99).
Notation "'inj{' l '}@' b < Ļ > e" := (EInj l b Ļ e) (in custom oadt at level 0,
l constr at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "'inj{' l '}@' b < Ļ > e").
Notation "'inj@' b < Ļ > e" := (EInj low b Ļ e) (in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inj@ b < Ļ > e").
Notation "'inl' < Ļ > e" := (EInj low true Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inl < Ļ > e").
Notation "'inr' < Ļ > e" := (EInj low false Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "inr < Ļ > e").
Notation "'~inj@' b < Ļ > e" := (EInj high b Ļ e) (in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inj@ b < Ļ > e").
Notation "'~inl' < Ļ > e" := (EInj high true Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inl < Ļ > e").
Notation "'~inr' < Ļ > e" := (EInj high false Ļ e) (in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "~inr < Ļ > e").
(* I still want to use high and low *)
Notation "'case{' l '}' e0 'of' e1 '|' e2" :=
(ECase l e0 e1 e2) (in custom oadt at level 89,
l constr at level 0,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity,
format "'case{' l '}' e0 'of' e1 '|' e2").
Notation "'case' e0 'of' e1 '|' e2" :=
(ECase low e0 e1 e2) (in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'~case' e0 'of' e1 '|' e2" :=
(ECase high e0 e1 e2) (in custom oadt at level 89,
e0 custom oadt at level 99,
e1 custom oadt at level 99,
e2 custom oadt at level 99,
left associativity).
Notation "'fold' < X > e" := (EFold X e) (in custom oadt at level 0,
X custom oadt at level 0,
e custom oadt at level 0,
format "fold < X > e").
Notation "'unfold' < X > e" := (EUnfold X e) (in custom oadt at level 0,
X custom oadt at level 0,
e custom oadt at level 0,
format "unfold < X > e").
Notation "[ b ]" := (EBoxedLit b) (in custom oadt at level 0,
b constr at level 0).
Notation "[ 'inj@' b < Ļ > e ]" := (EBoxedInj b Ļ e)
(in custom oadt at level 0,
b constr at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inj@ b < Ļ > e ]").
Notation "[ 'inl' < Ļ > e ]" := (EBoxedInj true Ļ e)
(in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inl < Ļ > e ]").
Notation "[ 'inr' < Ļ > e ]" := (EBoxedInj false Ļ e)
(in custom oadt at level 0,
Ļ custom oadt at level 0,
e custom oadt at level 0,
format "[ inr < Ļ > e ]").
Notation "D" := D (in custom oadt_def at level 0, D constr at level 0).
Notation "( D )" := D (in custom oadt_def, D at level 99).
Notation "'data' X := e" := (X, DADT e) (in custom oadt_def at level 0,
X constr at level 0,
e custom oadt at level 99).
Notation "'obliv' X ( : Ļ ) := e" := (X, DOADT Ļ e)
(in custom oadt_def at level 0,
X constr at level 0,
Ļ custom oadt at level 99,
e custom oadt at level 99,
format "obliv X ( : Ļ ) := e").
Notation "'def' x : Ļ := e" := (x, DFun Ļ e) (in custom oadt_def at level 0,
x constr at level 0,
Ļ custom oadt at level 99,
e custom oadt at level 99).
Notation "[{ x }]" := (cons x nil)
(x custom oadt_def at level 99).
Notation "[{ x ; y ; .. ; z }]" := (cons x (cons y .. (cons z nil) ..))
(x custom oadt_def at level 99,
y custom oadt_def at level 99,
z custom oadt_def at level 99,
format "[{ '[v ' '/' x ; '/' y ; '/' .. ; '/' z ']' '//' }]").
Notation "'ite' e0 e1 e2" := (if e0 then e1 else e2)
(in custom oadt at level 0,
e0 constr at level 0,
e1 custom oadt at level 0,
e2 custom oadt at level 0).
End expr_notations.
Indistinguishability
Reserved Notation "e 'ā' e'" (at level 40).
Inductive indistinguishable : expr -> expr -> Prop :=
| IBVar k : <{ bvar k }> ā <{ bvar k }>
| IFVar x : <{ fvar x }> ā <{ fvar x }>
| IGVar x : <{ gvar x }> ā <{ gvar x }>
| IPi Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ī :Ļ1, Ļ2 }> ā <{ Ī :Ļ1', Ļ2' }>
| IAbs Ļ Ļ' e e' :
Ļ ā Ļ' ->
e ā e' ->
<{ \:Ļ => e }> ā <{ \:Ļ' => e' }>
| ILet e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ let e1 in e2 }> ā <{ let e1' in e2' }>
| ICase l e0 e0' e1 e1' e2 e2' :
e0 ā e0' ->
e1 ā e1' ->
e2 ā e2' ->
<{ case{l} e0 of e1 | e2 }> ā <{ case{l} e0' of e1' | e2' }>
| IUnitT : <{ š }> ā <{ š }>
| IBool l : <{ š¹{l} }> ā <{ š¹{l} }>
| IProd Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ļ1 * Ļ2 }> ā <{ Ļ1' * Ļ2' }>
| ISum l Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ļ1 +{l} Ļ2 }> ā <{ Ļ1' +{l} Ļ2' }>
| IApp e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ e1 e2 }> ā <{ e1' e2' }>
| IUnitV : <{ () }> ā <{ () }>
| ILit b : <{ lit b }> ā <{ lit b }>
| ISec e e' :
e ā e' ->
<{ sš¹ e }> ā <{ sš¹ e' }>
| IIte l e0 e0' e1 e1' e2 e2' :
e0 ā e0' ->
e1 ā e1' ->
e2 ā e2' ->
<{ if{l} e0 then e1 else e2 }> ā <{ if{l} e0' then e1' else e2' }>
| IPair e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ (e1, e2) }> ā <{ (e1', e2') }>
| IProj b e e' :
e ā e' ->
<{ Ļ@b e }> ā <{ Ļ@b e' }>
| IInj l b Ļ Ļ' e e' :
Ļ ā Ļ' ->
e ā e' ->
<{ inj{l}@b<Ļ> e }> ā <{ inj{l}@b<Ļ'> e' }>
| IFold X e e' :
e ā e' ->
<{ fold<X> e }> ā <{ fold<X> e' }>
| IUnfold X e e' :
e ā e' ->
<{ unfold<X> e }> ā <{ unfold<X> e' }>
(* The only interesting cases *)
| IBoxedLit b b' :
(* We can not distinguish between two encrypted boolean values. *)
<{ [b] }> ā <{ [b'] }>
| IBoxedInj b b' Ļ e e' :
(* We can not tell which branch an encrypted sum injects to nor what the
encrypted value is. But the type information is public so we need to make
sure nothing leaked from this type information. Technically we only need the
two types to be indistinguishable, but the stronger notion of equality also
works. *)
<{ [inj@b<Ļ> e] }> ā <{ [inj@b'<Ļ> e'] }>
where "e 'ā' e'" := (indistinguishable e e').
Inductive indistinguishable : expr -> expr -> Prop :=
| IBVar k : <{ bvar k }> ā <{ bvar k }>
| IFVar x : <{ fvar x }> ā <{ fvar x }>
| IGVar x : <{ gvar x }> ā <{ gvar x }>
| IPi Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ī :Ļ1, Ļ2 }> ā <{ Ī :Ļ1', Ļ2' }>
| IAbs Ļ Ļ' e e' :
Ļ ā Ļ' ->
e ā e' ->
<{ \:Ļ => e }> ā <{ \:Ļ' => e' }>
| ILet e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ let e1 in e2 }> ā <{ let e1' in e2' }>
| ICase l e0 e0' e1 e1' e2 e2' :
e0 ā e0' ->
e1 ā e1' ->
e2 ā e2' ->
<{ case{l} e0 of e1 | e2 }> ā <{ case{l} e0' of e1' | e2' }>
| IUnitT : <{ š }> ā <{ š }>
| IBool l : <{ š¹{l} }> ā <{ š¹{l} }>
| IProd Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ļ1 * Ļ2 }> ā <{ Ļ1' * Ļ2' }>
| ISum l Ļ1 Ļ1' Ļ2 Ļ2' :
Ļ1 ā Ļ1' ->
Ļ2 ā Ļ2' ->
<{ Ļ1 +{l} Ļ2 }> ā <{ Ļ1' +{l} Ļ2' }>
| IApp e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ e1 e2 }> ā <{ e1' e2' }>
| IUnitV : <{ () }> ā <{ () }>
| ILit b : <{ lit b }> ā <{ lit b }>
| ISec e e' :
e ā e' ->
<{ sš¹ e }> ā <{ sš¹ e' }>
| IIte l e0 e0' e1 e1' e2 e2' :
e0 ā e0' ->
e1 ā e1' ->
e2 ā e2' ->
<{ if{l} e0 then e1 else e2 }> ā <{ if{l} e0' then e1' else e2' }>
| IPair e1 e1' e2 e2' :
e1 ā e1' ->
e2 ā e2' ->
<{ (e1, e2) }> ā <{ (e1', e2') }>
| IProj b e e' :
e ā e' ->
<{ Ļ@b e }> ā <{ Ļ@b e' }>
| IInj l b Ļ Ļ' e e' :
Ļ ā Ļ' ->
e ā e' ->
<{ inj{l}@b<Ļ> e }> ā <{ inj{l}@b<Ļ'> e' }>
| IFold X e e' :
e ā e' ->
<{ fold<X> e }> ā <{ fold<X> e' }>
| IUnfold X e e' :
e ā e' ->
<{ unfold<X> e }> ā <{ unfold<X> e' }>
(* The only interesting cases *)
| IBoxedLit b b' :
(* We can not distinguish between two encrypted boolean values. *)
<{ [b] }> ā <{ [b'] }>
| IBoxedInj b b' Ļ e e' :
(* We can not tell which branch an encrypted sum injects to nor what the
encrypted value is. But the type information is public so we need to make
sure nothing leaked from this type information. Technically we only need the
two types to be indistinguishable, but the stronger notion of equality also
works. *)
<{ [inj@b<Ļ> e] }> ā <{ [inj@b'<Ļ> e'] }>
where "e 'ā' e'" := (indistinguishable e e').
Reserved Notation "'{' k '~>' s '}' e" (in custom oadt at level 20, k constr).
Fixpoint open_ (k : nat) (s : expr) (e : expr) : expr :=
match e with
| <{ bvar n }> => if decide (k = n) then s else e
| <{ Ī :Ļ1, Ļ2 }> => <{ Ī :{k~>s}Ļ1, {S k~>s}Ļ2 }>
| <{ \:Ļ => e }> => <{ \:{k~>s}Ļ => {S k~>s}e }>
| <{ let e1 in e2 }> => <{ let {k~>s}e1 in {S k~>s}e2 }>
| <{ case{l} e0 of e1 | e2 }> => <{ case{l} {k~>s}e0 of {S k~>s}e1 | {S k~>s}e2 }>
(* Congruence rules *)
| <{ Ļ1 * Ļ2 }> => <{ ({k~>s}Ļ1) * ({k~>s}Ļ2) }>
| <{ Ļ1 +{l} Ļ2 }> => <{ ({k~>s}Ļ1) +{l} ({k~>s}Ļ2) }>
| <{ e1 e2 }> => <{ ({k~>s}e1) ({k~>s}e2) }>
| <{ sš¹ e }> => <{ sš¹ ({k~>s}e) }>
| <{ if{l} e0 then e1 else e2 }> => <{ if{l} {k~>s}e0 then {k~>s}e1 else {k~>s}e2 }>
| <{ (e1, e2) }> => <{ ({k~>s}e1, {k~>s}e2) }>
| <{ Ļ@b e }> => <{ Ļ@b ({k~>s}e) }>
| <{ inj{l}@b<Ļ> e }> => <{ inj{l}@b<({k~>s}Ļ)> ({k~>s}e) }>
| <{ fold<X> e }> => <{ fold<X> ({k~>s}e) }>
| <{ unfold<X> e }> => <{ unfold<X> ({k~>s}e) }>
| _ => e
end
where "'{' k '~>' s '}' e" := (open_ k s e) (in custom oadt).
Definition open s e := open_ 0 s e.
Notation "e ^ s" := (open s e) (in custom oadt at level 20).
Fixpoint open_ (k : nat) (s : expr) (e : expr) : expr :=
match e with
| <{ bvar n }> => if decide (k = n) then s else e
| <{ Ī :Ļ1, Ļ2 }> => <{ Ī :{k~>s}Ļ1, {S k~>s}Ļ2 }>
| <{ \:Ļ => e }> => <{ \:{k~>s}Ļ => {S k~>s}e }>
| <{ let e1 in e2 }> => <{ let {k~>s}e1 in {S k~>s}e2 }>
| <{ case{l} e0 of e1 | e2 }> => <{ case{l} {k~>s}e0 of {S k~>s}e1 | {S k~>s}e2 }>
(* Congruence rules *)
| <{ Ļ1 * Ļ2 }> => <{ ({k~>s}Ļ1) * ({k~>s}Ļ2) }>
| <{ Ļ1 +{l} Ļ2 }> => <{ ({k~>s}Ļ1) +{l} ({k~>s}Ļ2) }>
| <{ e1 e2 }> => <{ ({k~>s}e1) ({k~>s}e2) }>
| <{ sš¹ e }> => <{ sš¹ ({k~>s}e) }>
| <{ if{l} e0 then e1 else e2 }> => <{ if{l} {k~>s}e0 then {k~>s}e1 else {k~>s}e2 }>
| <{ (e1, e2) }> => <{ ({k~>s}e1, {k~>s}e2) }>
| <{ Ļ@b e }> => <{ Ļ@b ({k~>s}e) }>
| <{ inj{l}@b<Ļ> e }> => <{ inj{l}@b<({k~>s}Ļ)> ({k~>s}e) }>
| <{ fold<X> e }> => <{ fold<X> ({k~>s}e) }>
| <{ unfold<X> e }> => <{ unfold<X> ({k~>s}e) }>
| _ => e
end
where "'{' k '~>' s '}' e" := (open_ k s e) (in custom oadt).
Definition open s e := open_ 0 s e.
Notation "e ^ s" := (open s e) (in custom oadt at level 20).
Reserved Notation "'{' x 'ā¦' s '}' e" (in custom oadt at level 20, x constr).
Fixpoint subst (x : atom) (s : expr) (e : expr) : expr :=
match e with
| <{ fvar y }> => if decide (x = y) then s else e
(* Congruence rules *)
| <{ Ī :Ļ1, Ļ2 }> => <{ Ī :{xā¦s}Ļ1, {xā¦s}Ļ2 }>
| <{ \:Ļ => e }> => <{ \:{xā¦s}Ļ => {xā¦s}e }>
| <{ let e1 in e2 }> => <{ let {xā¦s}e1 in {xā¦s}e2 }>
| <{ case{l} e0 of e1 | e2 }> => <{ case{l} {xā¦s}e0 of {xā¦s}e1 | {xā¦s}e2 }>
| <{ Ļ1 * Ļ2 }> => <{ ({xā¦s}Ļ1) * ({xā¦s}Ļ2) }>
| <{ Ļ1 +{l} Ļ2 }> => <{ ({xā¦s}Ļ1) +{l} ({xā¦s}Ļ2) }>
| <{ e1 e2 }> => <{ ({xā¦s}e1) ({xā¦s}e2) }>
| <{ sš¹ e }> => <{ sš¹ ({xā¦s}e) }>
| <{ if{l} e0 then e1 else e2 }> => <{ if{l} {xā¦s}e0 then {xā¦s}e1 else {xā¦s}e2 }>
| <{ (e1, e2) }> => <{ ({xā¦s}e1, {xā¦s}e2) }>
| <{ Ļ@b e }> => <{ Ļ@b ({xā¦s}e) }>
| <{ inj{l}@b<Ļ> e }> => <{ inj{l}@b<({xā¦s}Ļ)> ({xā¦s}e) }>
| <{ fold<X> e }> => <{ fold<X> ({xā¦s}e) }>
| <{ unfold<X> e }> => <{ unfold<X> ({xā¦s}e) }>
| _ => e
end
where "'{' x 'ā¦' s '}' e" := (subst x s e) (in custom oadt).
Fixpoint subst (x : atom) (s : expr) (e : expr) : expr :=
match e with
| <{ fvar y }> => if decide (x = y) then s else e
(* Congruence rules *)
| <{ Ī :Ļ1, Ļ2 }> => <{ Ī :{xā¦s}Ļ1, {xā¦s}Ļ2 }>
| <{ \:Ļ => e }> => <{ \:{xā¦s}Ļ => {xā¦s}e }>
| <{ let e1 in e2 }> => <{ let {xā¦s}e1 in {xā¦s}e2 }>
| <{ case{l} e0 of e1 | e2 }> => <{ case{l} {xā¦s}e0 of {xā¦s}e1 | {xā¦s}e2 }>
| <{ Ļ1 * Ļ2 }> => <{ ({xā¦s}Ļ1) * ({xā¦s}Ļ2) }>
| <{ Ļ1 +{l} Ļ2 }> => <{ ({xā¦s}Ļ1) +{l} ({xā¦s}Ļ2) }>
| <{ e1 e2 }> => <{ ({xā¦s}e1) ({xā¦s}e2) }>
| <{ sš¹ e }> => <{ sš¹ ({xā¦s}e) }>
| <{ if{l} e0 then e1 else e2 }> => <{ if{l} {xā¦s}e0 then {xā¦s}e1 else {xā¦s}e2 }>
| <{ (e1, e2) }> => <{ ({xā¦s}e1, {xā¦s}e2) }>
| <{ Ļ@b e }> => <{ Ļ@b ({xā¦s}e) }>
| <{ inj{l}@b<Ļ> e }> => <{ inj{l}@b<({xā¦s}Ļ)> ({xā¦s}e) }>
| <{ fold<X> e }> => <{ fold<X> ({xā¦s}e) }>
| <{ unfold<X> e }> => <{ unfold<X> ({xā¦s}e) }>
| _ => e
end
where "'{' x 'ā¦' s '}' e" := (subst x s e) (in custom oadt).
Inductive otval : expr -> Prop :=
| OVUnitT : otval <{ š }>
| OVOBool : otval <{ ~š¹ }>
| OVProd Ļ1 Ļ2 : otval Ļ1 -> otval Ļ2 -> otval <{ Ļ1 * Ļ2 }>
| OVOSum Ļ1 Ļ2 : otval Ļ1 -> otval Ļ2 -> otval <{ Ļ1 ~+ Ļ2 }>
.
| OVUnitT : otval <{ š }>
| OVOBool : otval <{ ~š¹ }>
| OVProd Ļ1 Ļ2 : otval Ļ1 -> otval Ļ2 -> otval <{ Ļ1 * Ļ2 }>
| OVOSum Ļ1 Ļ2 : otval Ļ1 -> otval Ļ2 -> otval <{ Ļ1 ~+ Ļ2 }>
.
Inductive oval : expr -> Prop :=
| OVUnitV : oval <{ () }>
| OVBoxedLit b : oval <{ [b] }>
| OVPair v1 v2 : oval v1 -> oval v2 -> oval <{ (v1, v2) }>
| OVBoxedInj b Ļ v : otval Ļ -> oval v -> oval <{ [inj@b<Ļ> v] }>
.
| OVUnitV : oval <{ () }>
| OVBoxedLit b : oval <{ [b] }>
| OVPair v1 v2 : oval v1 -> oval v2 -> oval <{ (v1, v2) }>
| OVBoxedInj b Ļ v : otval Ļ -> oval v -> oval <{ [inj@b<Ļ> v] }>
.
Inductive val : expr -> Prop :=
| VUnitV : val <{ () }>
| VLit b : val <{ lit b }>
| VPair v1 v2 : val v1 -> val v2 -> val <{ (v1, v2) }>
| VAbs Ļ e : val <{ \:Ļ => e }>
| VInj b Ļ v : val v -> val <{ inj@b<Ļ> v }>
| VFold X v : val v -> val <{ fold<X> v }>
| VBoxedLit b : val <{ [b] }>
| VBoxedInj b Ļ v : otval Ļ -> oval v -> val <{ [inj@b<Ļ> v] }>
.
| VUnitV : val <{ () }>
| VLit b : val <{ lit b }>
| VPair v1 v2 : val v1 -> val v2 -> val <{ (v1, v2) }>
| VAbs Ļ e : val <{ \:Ļ => e }>
| VInj b Ļ v : val v -> val <{ inj@b<Ļ> v }>
| VFold X v : val v -> val <{ fold<X> v }>
| VBoxedLit b : val <{ [b] }>
| VBoxedInj b Ļ v : otval Ļ -> oval v -> val <{ [inj@b<Ļ> v] }>
.
Inductive lc : expr -> Prop :=
| LCFVar x : lc <{ fvar x }>
| LCGVar x : lc <{ gvar x }>
| LCPi Ļ1 Ļ2 L :
(forall x, x ā L -> lc <{ Ļ2^x }>) ->
lc Ļ1 -> lc <{ Ī :Ļ1, Ļ2 }>
| LCAbs Ļ e L :
(forall x, x ā L -> lc <{ e^x }>) ->
lc Ļ -> lc <{ \:Ļ => e }>
| LCLet e1 e2 L :
(forall x, x ā L -> lc <{ e2^x }>) ->
lc e1 -> lc <{ let e1 in e2 }>
| LCCase l e0 e1 e2 L1 L2 :
(forall x, x ā L1 -> lc <{ e1^x }>) ->
(forall x, x ā L2 -> lc <{ e2^x }>) ->
lc e0 -> lc <{ case{l} e0 of e1 | e2 }>
(* Congruence rules *)
| LCUnitT : lc <{ š }>
| LCBool l : lc <{ š¹{l} }>
| LCProd Ļ1 Ļ2 : lc Ļ1 -> lc Ļ2 -> lc <{ Ļ1 * Ļ2 }>
| LCSum l Ļ1 Ļ2 : lc Ļ1 -> lc Ļ2 -> lc <{ Ļ1 +{l} Ļ2 }>
| LCApp e1 e2 : lc e1 -> lc e2 -> lc <{ e1 e2 }>
| LCUnitV : lc <{ () }>
| LCLit b : lc <{ lit b }>
| LCSec e : lc e -> lc <{ sš¹ e }>
| LCIte l e0 e1 e2 : lc e0 -> lc e1 -> lc e2 -> lc <{ if{l} e0 then e1 else e2 }>
| LCPair e1 e2 : lc e1 -> lc e2 -> lc <{ (e1, e2) }>
| LCProj b e : lc e -> lc <{ Ļ@b e }>
| LCInj l b Ļ e : lc Ļ -> lc e -> lc <{ inj{l}@b<Ļ> e }>
| LCFold X e : lc e -> lc <{ fold<X> e }>
| LCUnfold X e : lc e -> lc <{ unfold<X> e }>
| LCBoxedLit b : lc <{ [b] }>
(* Techincally this is not only locally closed, but more about
well-formedness. *)
| LCBoxedInj b Ļ v : otval Ļ -> oval v -> lc <{ [inj@b<Ļ> v] }>
.
End definitions.
| LCFVar x : lc <{ fvar x }>
| LCGVar x : lc <{ gvar x }>
| LCPi Ļ1 Ļ2 L :
(forall x, x ā L -> lc <{ Ļ2^x }>) ->
lc Ļ1 -> lc <{ Ī :Ļ1, Ļ2 }>
| LCAbs Ļ e L :
(forall x, x ā L -> lc <{ e^x }>) ->
lc Ļ -> lc <{ \:Ļ => e }>
| LCLet e1 e2 L :
(forall x, x ā L -> lc <{ e2^x }>) ->
lc e1 -> lc <{ let e1 in e2 }>
| LCCase l e0 e1 e2 L1 L2 :
(forall x, x ā L1 -> lc <{ e1^x }>) ->
(forall x, x ā L2 -> lc <{ e2^x }>) ->
lc e0 -> lc <{ case{l} e0 of e1 | e2 }>
(* Congruence rules *)
| LCUnitT : lc <{ š }>
| LCBool l : lc <{ š¹{l} }>
| LCProd Ļ1 Ļ2 : lc Ļ1 -> lc Ļ2 -> lc <{ Ļ1 * Ļ2 }>
| LCSum l Ļ1 Ļ2 : lc Ļ1 -> lc Ļ2 -> lc <{ Ļ1 +{l} Ļ2 }>
| LCApp e1 e2 : lc e1 -> lc e2 -> lc <{ e1 e2 }>
| LCUnitV : lc <{ () }>
| LCLit b : lc <{ lit b }>
| LCSec e : lc e -> lc <{ sš¹ e }>
| LCIte l e0 e1 e2 : lc e0 -> lc e1 -> lc e2 -> lc <{ if{l} e0 then e1 else e2 }>
| LCPair e1 e2 : lc e1 -> lc e2 -> lc <{ (e1, e2) }>
| LCProj b e : lc e -> lc <{ Ļ@b e }>
| LCInj l b Ļ e : lc Ļ -> lc e -> lc <{ inj{l}@b<Ļ> e }>
| LCFold X e : lc e -> lc <{ fold<X> e }>
| LCUnfold X e : lc e -> lc <{ unfold<X> e }>
| LCBoxedLit b : lc <{ [b] }>
(* Techincally this is not only locally closed, but more about
well-formedness. *)
| LCBoxedInj b Ļ v : otval Ļ -> oval v -> lc <{ [inj@b<Ļ> v] }>
.
End definitions.
Module notations.
Export expr_notations.
Notation "e 'ā' e'" := (indistinguishable e e') (at level 40).
Notation "'{' k '~>' s '}' e" := (open_ k s e)
(in custom oadt at level 20, k constr).
Notation "e ^ s" := (open s e) (in custom oadt at level 20).
Notation "'{' x 'ā¦' s '}' e" := (subst x s e)
(in custom oadt at level 20, x constr).
Notation "{ x 'ā¦' s }" := (subst x s) (at level 20).
Notation "x # s" := (x ā stale s) (at level 40).
End notations.
Export expr_notations.
Notation "e 'ā' e'" := (indistinguishable e e') (at level 40).
Notation "'{' k '~>' s '}' e" := (open_ k s e)
(in custom oadt at level 20, k constr).
Notation "e ^ s" := (open s e) (in custom oadt at level 20).
Notation "'{' x 'ā¦' s '}' e" := (subst x s e)
(in custom oadt at level 20, x constr).
Notation "{ x 'ā¦' s }" := (subst x s) (at level 20).
Notation "x # s" := (x ā stale s) (at level 40).
End notations.