module LabelExpr.Security where

open import Data.Nat
open import Data.Unit using (; tt)
open import Data.Bool using (true; false) renaming (Bool to 𝔹)
open import Data.List hiding ([_])
open import Data.Product renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_)
open import Data.Maybe
open import Relation.Nullary using (¬_; Dec; yes; no; recompute)
open import Relation.Nullary.Negation using (contradiction; ¬?)
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl; cong; sym; subst)
open import Function using (case_of_)

open import Common.Utils
open import Common.SecurityLabels
open import Common.BlameLabels
open import CoercionExpr.CoercionExpr
  renaming (_∎ to _∎ₗ ; _—→⟨_⟩_ to _—→ₗ⟨_⟩_)
  hiding (Progress; progress; plug-cong; ↠-trans)
open import CoercionExpr.SyntacComp
open import CoercionExpr.Precision renaming (prec→⊑ to precₗ→⊑)
open import CoercionExpr.SecurityLevel renaming (∥_∥ to ∥_∥ₗ)
open import CoercionExpr.Stamping
open import LabelExpr.LabelExpr
open import LabelExpr.Stamping


security-eqₑ :  {V₁ V₂}
   (v₁ : LVal V₁)
   (v₂ : LVal V₂)
   V₁  V₂
    --------------------------
    V₁  v₁   V₂  v₂
security-eqₑ v₁ v₂ eq rewrite eq rewrite uniq-LVal v₁ v₂ = refl


stampₑ-security :  {V } (v : LVal V)  ( V  v)     stampₑ V v   (stampₑ-LVal v)
stampₑ-security {V = l }    { = low}  v-l rewrite ℓ⋎low≡ℓ {} = refl
stampₑ-security {V = l low}  { = high} v-l = refl
stampₑ-security {V = l high} { = high} v-l = refl
stampₑ-security {V} {low}  (v-cast (ir 𝓋 _)) = stampₗ-security _ 𝓋 low
stampₑ-security {V} {high} (v-cast (ir 𝓋 _)) = stampₗ-security _ 𝓋 high

stamp!ₑ-security :  {V } (v : LVal V)  ( V  v)     stamp!ₑ V v   (stamp!ₑ-LVal v)
stamp!ₑ-security {V} {low} (v-l {}) rewrite ℓ⋎low≡ℓ {} = refl
stamp!ₑ-security {V} {high} v-l = stamp!ₗ-security _ id high
stamp!ₑ-security {V} {} (v-cast (ir v _)) = stamp!ₗ-security _ v 


cast-security :  {g g′ V V′} { : CExpr g  g′}
   (v : LVal V)
    V  g
   V    —↠ₑ V′
   (v′ : LVal V′)
    -------------------------
    V  v   V′  v′
cast-security v-l ⊢V (l _  id (l _)  —→⟨ β-id  _ ) v-l = ≼-refl
cast-security v-l ⊢V (l _  _  —→⟨ cast c̅→⁺c̅ₙ 𝓋  ↠V′) v-l =
  cast-security v-l ⊢l ↠V′ v-l
cast-security v-l ⊢V (l _  _  —→⟨ blame _  _ —→⟨ r  _) v-l =
  contradiction r (LResult⌿→ fail)
cast-security v-l ⊢V ↠V′ (v-cast (ir id x)) = contradiction refl (recompute (¬? (_ ==? _)) x)
cast-security v-l ⊢l ↠V′ (v-cast (ir (inj id) _))
  with preserve-mult (⊢cast ⊢l) ↠V′
... | ⊢cast ⊢l with cast-red-label-eq ↠V′
...   | refl = ≡→≼ refl
cast-security v-l ⊢V ↠V′ (v-cast (ir (inj (up id)) x₁)) = _ ≼high
cast-security v-l ⊢l ↠V′ (v-cast (ir (up id) x)) = _ ≼high
cast-security (v-cast i) ⊢V (_ —→⟨ ξ ℓ⟨c̅⟩→N  _) v-l =
  contradiction ℓ⟨c̅⟩→N (LVal⌿→ (v-cast i))
cast-security (v-cast (ir v _)) (⊢cast ⊢l) (_ —→⟨ comp i†  r) v-l
  with cast-to-label-inv r | preserve-mult (⊢cast ⊢l) r
... |  refl , r*  | ⊢l =
  let comp-red = cast-red-inv r* in
  comp-security v comp-red id
cast-security (v-cast i) ⊢V
              (l _  _   _  —→⟨ ξ ℓ⟨c⟩→N  ↠V′) (v-cast _) =
  contradiction ℓ⟨c⟩→N (LVal⌿→ (v-cast i))
cast-security (v-cast (ir 𝓋 _)) ⊢V
              (l _  _   _  —→⟨ comp i  ↠V′) (v-cast (ir 𝓋′ _))
  with preserve-mult (⊢cast ⊢l) ↠V′
... | ⊢cast ⊢l with cast-red-label-eq ↠V′
...   | refl = comp-security 𝓋 (cast-red-inv ↠V′) 𝓋′


stamp-cast-security :  {g g′  V V′} { : CExpr (g ⋎̃ l )  g′}
   (v : LVal V)
    V  g
   stampₑ V v     —↠ₑ V′
   (v′ : LVal V′)
    ---------------------------------
   ( V  v)     V′  v′
stamp-cast-security { = } v ⊢V ↠V′ v′ =
  let eq  = stampₑ-security { = } v in
  let leq = cast-security (stampₑ-LVal v) (stampₑ-wt v ⊢V) ↠V′ v′ in
  ≼-trans (≡→≼ eq) leq

stamp!-cast-security :  {g g′  V V′} { : CExpr   g′}
   (v : LVal V)
    V  g
   stamp!ₑ V v     —↠ₑ V′
   (v′ : LVal V′)
    ---------------------------------
   ( V  v)     V′  v′
stamp!-cast-security {g} {g′} {} {V} {V′} {} v ⊢V ↠V′ v′ =
  let eq  = stamp!ₑ-security { = } v in
  let leq = cast-security (stamp!ₑ-LVal v) (stamp!ₑ-wt v ⊢V) ↠V′ v′ in
  ≼-trans (≡→≼ eq) leq


security-prec-mono :  {g g′} {V W}
   (v : LVal V)
   (w : LVal W)
    V  W  g  g′
    -----------------------------------
    V  v   W  w
security-prec-mono v-l v-l ⊑-l = ≼-refl
security-prec-mono v-l (v-cast (ir 𝓋′ _)) (⊑-castr ⊑-l ℓ⊑c̅′) =
  ≡→≼ (security-prec-right _ 𝓋′ ℓ⊑c̅′)
security-prec-mono (v-cast (ir 𝓋 _)) v-l (⊑-castl ⊑-l c̅⊑ℓ′) =
  ≡→≼ (security-prec-left _ 𝓋 c̅⊑ℓ′)
security-prec-mono (v-cast (ir 𝓋 _)) (v-cast (ir 𝓋′ _)) V⊑W
  with prec→⊢ V⊑W
... |  ⊢cast ⊢l , ⊢cast ⊢l 
  with prec-inv V⊑W
... |  refl , c̅⊑c̅′  =
  security-prec _ _ 𝓋 𝓋′ c̅⊑c̅′