Source code on Github
------------------------------------------------------------------------
-- Utilities for constructing configurations.
------------------------------------------------------------------------
open import Prelude.Init; open SetAsType
open L.Mem hiding (_∈_)
open L.Perm using (∈-resp-↭; map⁺)
open import Prelude.Lists.PermutationsMeta
open import Prelude.DecEq
open import Prelude.Lists
open import Prelude.Lists.Dec
open import Prelude.Membership
open import Prelude.Lists.Collections
open import Prelude.Applicative
open import Prelude.Semigroup
open import Prelude.Nary
open import Prelude.Decidable
open import Prelude.General
open import Prelude.Setoid
open import Prelude.Traces
open import Prelude.Bifunctor
open import Prelude.Irrelevance.Core
open import Prelude.Coercions
open import Prelude.Split renaming (split to mkSplit)
open import Prelude.Null

open import BitML.BasicTypes

module BitML.Semantics.Configurations.Helpers ( : ) (let open  ) where

open import BitML.Contracts 
open import BitML.Semantics.Action 
open import BitML.Semantics.Configurations.Types 

instance
  Setoid-Cfg′ : ISetoid Cfg′
  Setoid-Cfg′ = λ where
    .relℓ  0ℓ
    ._≈_  _↭_

  SetoidLaws-Cfg′ : SetoidLaws Cfg′
  SetoidLaws-Cfg′ .isEquivalence = record {IsEquivalence L.Perm.↭-isEquivalence}

  Setoid-Cfg : ISetoid Cfg
  Setoid-Cfg = λ where
    .relℓ  0ℓ
    ._≈_  _≈_ on to[ Cfg′ ]

  SetoidLaws-Cfg : SetoidLaws Cfg
  SetoidLaws-Cfg .isEquivalence = record {IsEquivalence L.Perm.↭-isEquivalence}

  Setoid-Cfgᵗ : ISetoid Cfgᵗ
  Setoid-Cfgᵗ = λ where
    .relℓ  0ℓ
    ._≈_ (Γ at t) (Γ′ at t′)  (t  t′) × (Γ  Γ′)

  SetoidLaws-Cfgᵗ : SetoidLaws Cfgᵗ
  SetoidLaws-Cfgᵗ .isEquivalence = record
    { refl  = refl , ↭-refl
    ; sym   = λ where (t≡ , Γ≈)  sym t≡ , ↭-sym Γ≈
    ; trans = λ where (t≡ , Γ≈) (≡t , ≈Γ)  trans t≡ ≡t , ↭-trans Γ≈ ≈Γ
    }

  -- ** Initiality (for constructing traces)
  Initial-Cfg : HasInitial Cfg
  Initial-Cfg .Initial = λ where
    ∅ᶜ                 
    ( _ has _ ⟩at _)  
    (l  r)            Initial l × Initial r
    _                  

  Initial-Cfgᵗ : HasInitial Cfgᵗ
  Initial-Cfgᵗ .Initial (Γ at t) = Initial Γ × (t  0)

≈ᵗ-refl : Γₜ  Γₜ
≈ᵗ-refl = refl , ↭-refl

-- T0D0: find general scheme
-- ∙ list-like things + map-commuting ~> membership lemmas
cfgToList : Cfg  List Cfg
cfgToList = map to[ Cfg ]  to[ Cfg′ ]

cfgToList-++ :  l r  cfgToList (l  r)  cfgToList l ++ cfgToList r
cfgToList-++ l r = L.map-++-commute to[ Cfg ] (to[ Cfg′ ] l) (to[ Cfg′ ] r)

{-
cfgToList-++² : ∀ l c r → cfgToList (l ∣ c ∣ r) ≡ cfgToList l ++ cfgToList c ++ cfgToList r
cfgToList-++² l c r
  rewrite cfgToList-++ (l ∣ c) r | cfgToList-++ l c
        = L.++-assoc (cfgToList l) (cfgToList c) (cfgToList r)

cfgToList-++²′ : ∀ l c r → cfgToList (l ∣ (c ∣ r)) ≡ cfgToList l ++ cfgToList c ++ cfgToList r
cfgToList-++²′ l c r
  rewrite cfgToList-++ l (c ∣ r) | cfgToList-++ c r
        = refl
-}

cfgToList-assoc :  l c r  cfgToList (l  c  r)  cfgToList (l  (c  r))
cfgToList-assoc l c r
  rewrite cfgToList-++ (l  c) r | cfgToList-++ l c
        | cfgToList-++ l (c  r) | cfgToList-++ c r
        = L.++-assoc (cfgToList l) (cfgToList c) (cfgToList r)

toCfg-injective : Injective≡ {A = BaseCfg} to[ Cfg ]
toCfg-injective {x = `` _}             {`` _}             refl = refl
toCfg-injective {x = `⟨ _ , _ ⟩at _}   {`⟨ _ , _ ⟩at _}   refl = refl
toCfg-injective {x = `⟨ _ has _ ⟩at _} {`⟨ _ has _ ⟩at _} refl = refl
toCfg-injective {x = _ `auth[ _ ]}     {_ `auth[ _ ]}     refl = refl
toCfg-injective {x = `⟨ _  _  _ }   {`⟨ _  _  _ }   refl = refl
toCfg-injective {x = _ `∶ _  _}       {_ `∶ _  _}       refl = refl

toCfg′-assoc :  l c r  to[ Cfg′ ] (l  c  r)  to[ Cfg′ ] (l  (c  r))
toCfg′-assoc l c r = L.map-injective toCfg-injective (cfgToList-assoc l c r)

≈ᶜ-assoc :  l c r  l  (c  r)  l  c  r
≈ᶜ-assoc l c r = ↭-reflexive (sym $ toCfg′-assoc l c r)

infix 4 _∈ᶜ_ _∉ᶜ_
_∈ᶜ_ _∉ᶜ_ : Rel₀ Cfg
c ∈ᶜ c′ = c  cfgToList c′
c ∉ᶜ c′ = ¬ c ∈ᶜ c′

∈ᶜ-++⁻ :  l r  Γ₀ ∈ᶜ (l  r)  Γ₀ ∈ᶜ l  Γ₀ ∈ᶜ r
∈ᶜ-++⁻ l r rewrite cfgToList-++ l r = ∈-++⁻ (cfgToList l)

∈ᶜ-++⁺ˡ :  l r  Γ₀ ∈ᶜ l  Γ₀ ∈ᶜ (l  r)
∈ᶜ-++⁺ˡ l r rewrite cfgToList-++ l r = ∈-++⁺ˡ

∈ᶜ-++⁺ʳ :  l r  Γ₀ ∈ᶜ r  Γ₀ ∈ᶜ (l  r)
∈ᶜ-++⁺ʳ l r rewrite cfgToList-++ l r = ∈-++⁺ʳ (cfgToList l)

destruct-∈ᶜ-++ :  Γ Γ′ {x}
   (x∈ : x ∈ᶜ (Γ  Γ′))
    --——————————————————
   ( λ (x∈ˡ : x ∈ᶜ Γ)   x∈  ∈ᶜ-++⁺ˡ Γ Γ′ x∈ˡ)
   ( λ (x∈ʳ : x ∈ᶜ Γ′)  x∈  ∈ᶜ-++⁺ʳ Γ Γ′ x∈ʳ)
destruct-∈ᶜ-++ Γ Γ′ x∈ rewrite cfgToList-++ Γ Γ′ = destruct-∈-++ x∈

-- destruct-∈ᶜ-++² : ∀ Γ Γ′ Γ″ {x}
--   → (x∈ : x ∈ᶜ (Γ ∣ Γ′ ∣ Γ″))
--     --————————————————————————————————————
--   → (∃ λ (x∈Γ  : x ∈ᶜ Γ)  → x∈ ≡ (∈ᶜ-++⁺ˡ (Γ ∣ Γ′) Γ″ $ ∈ᶜ-++⁺ˡ Γ Γ′ x∈Γ))
--   ⊎ (∃ λ (x∈Γ′ : x ∈ᶜ Γ′) → x∈ ≡ (∈ᶜ-++⁺ˡ (Γ ∣ Γ′) Γ″ $ ∈ᶜ-++⁺ʳ Γ Γ′ x∈Γ′))
--   ⊎ (∃ λ (x∈Γ″ : x ∈ᶜ Γ″) → x∈ ≡ (∈ᶜ-++⁺ʳ (Γ ∣ Γ′) Γ″ x∈Γ″))

infix 4 _⊆ᶜ_ _⊈ᶜ_
_⊆ᶜ_ _⊈ᶜ_ : Rel₀ Cfg
c ⊆ᶜ c′ = cfgToList c  cfgToList c′
c ⊈ᶜ c′ = ¬ c ⊆ᶜ c′

⊆ᶜ-refl : Reflexive _⊆ᶜ_
⊆ᶜ-refl = id

⊆ᶜ-trans : Transitive _⊆ᶜ_
⊆ᶜ-trans Γ⊆ Γ⊆′ = Γ⊆′  Γ⊆

⊆ᶜ-++⁺ˡ :  l r  Δ ⊆ᶜ l  Δ ⊆ᶜ l  r
⊆ᶜ-++⁺ˡ l r = ∈ᶜ-++⁺ˡ l r ∘_

⊆ᶜ-++⁺ʳ :  l r  Δ ⊆ᶜ r  Δ ⊆ᶜ l  r
⊆ᶜ-++⁺ʳ l r = ∈ᶜ-++⁺ʳ l r ∘_

_≢deposit : Pred₀ Cfg
_≢deposit = λ where
  ( _ has _ ⟩at _)  
  _                  

Initial⇒∉ :  Γ₀ ≢deposit   Initial Γ  Γ₀ ∉ᶜ Γ
Initial⇒∉ {Γ =  _ has _ ⟩at _}  ()  _ (here refl)
Initial⇒∉ {Γ = l  r}  ≢dep  ( , ) =
  ∈ᶜ-++⁻ l r >≡>
  Sum.[ Initial⇒∉  ≢dep  
      , Initial⇒∉  ≢dep   ]

∈ᶜ-resp-≈ : Γ  Γ′  Γ₀ ∈ᶜ Γ  Γ₀ ∈ᶜ Γ′
∈ᶜ-resp-≈ Γ≈ = ∈-map-resp-↭ to[ Cfg ] Γ≈

∉ᶜ-resp-≈ : Γ  Γ′  Γ₀ ∉ᶜ Γ  Γ₀ ∉ᶜ Γ′
∉ᶜ-resp-≈ {Γ}{Γ′}{Γ₀} Γ≈ c∉ = c∉  ∈ᶜ-resp-≈ {Γ′}{Γ} (↭-sym Γ≈)

-- ∈ᶜ-||⁺ : ∀ {A : Type} {f : A → Cfg} xs
--   → (∃ λ x → (x ∈ xs) × (Γ ∈ᶜ f x))
--     --———————————————————————————
--   → Γ ∈ᶜ || map f xs
-- ∈ᶜ-||⁺ {f = f} []                (_ , ()        , _)
-- ∈ᶜ-||⁺ {f = f} (.x ∷ [])         (x , here refl , Γ∈) = Γ∈
-- ∈ᶜ-||⁺ {f = f} (.x ∷ xs@(_ ∷ _)) (x , here refl , Γ∈) = ∈ᶜ-++⁺ˡ (f x) (|| map f xs) Γ∈
-- ∈ᶜ-||⁺ {f = f} (x  ∷ xs@(_ ∷ _)) (y , there y∈  , Γ∈) = ∈ᶜ-++⁺ʳ (f x) (|| map f xs) (∈ᶜ-||⁺ xs (y , y∈ , Γ∈))

∈ᶜ-||⇒⊆ᶜ :  {A : Type} {f : A  Cfg} {x} xs
   x  xs
   || map f xs ⊆ᶜ Γ
    --———————————————————————————
   f x ⊆ᶜ Γ
∈ᶜ-||⇒⊆ᶜ                 []               ()          _
∈ᶜ-||⇒⊆ᶜ                 (x  [])         (here refl) Γ⊆ = Γ⊆
∈ᶜ-||⇒⊆ᶜ {Γ = Γ} {f = f} (x  xs@(_  _)) x∈ Γ⊆ =
  case x∈ of λ where
    (here refl)  Γ⊆  ∈ᶜ-++⁺ˡ (f x) (|| map f xs)
    (there x∈)   ∈ᶜ-||⇒⊆ᶜ {Γ = Γ} xs x∈ (Γ⊆  ∈ᶜ-++⁺ʳ (f x) (|| map f xs))

∉ᶜ-|| :  {A : Type} {f : A  Cfg}
   (∀ {x}  Γ ∉ᶜ f x)
    --———————————————————————————
    xs  Γ ∉ᶜ || map f xs
∉ᶜ-|| Γ≢ [] ()
∉ᶜ-|| Γ∉ (_  []) Γ∈ = Γ∉ Γ∈
∉ᶜ-|| {f = f} Γ≢ (x  xs@(_  _)) =
  ∈ᶜ-++⁻ (f x) (|| map f xs) >≡>
  Sum.[ Γ≢
      , ∉ᶜ-|| Γ≢ xs ]

private variable X Y : Type

collectFromBase : (BaseCfg  List X)  (Cfg  List X)
collectFromBase f = collectFromList f  to[ Cfg′ ]

collectFromBase-++ :  I : BaseCfg has X    l r  let f = collectFromBase (collect  I ⦄) in
    f (l  r)  f l ++ f r
collectFromBase-++ l r rewrite cfgToList-++ l r | concatMap-++ collect (to[ Cfg′ ] l) (to[ Cfg′ ] r) = refl

mapMaybe∘collectFromBase-++ :   I : BaseCfg has X  (g : X  Maybe Y) l r 
  let f = collectFromBase (collect  I ⦄) in
    mapMaybe g (f (l  r))  mapMaybe g (f l) ++ mapMaybe g (f r)
mapMaybe∘collectFromBase-++  I  g l r = begin
    mapMaybe g (f $ l  r)
  ≡⟨ cong (mapMaybe g) (collectFromBase-++ l r) 
    mapMaybe g (f l ++ f r)
  ≡⟨ mapMaybe-++ g (f l) (f r) 
    mapMaybe g (f l) ++ mapMaybe g (f r)
   where open ≡-Reasoning
          f = collectFromBase (collect  I ⦄)

∈-collect-++⁻ :  l r {x : X}   I : BaseCfg has X   let f = collectFromBase (collect  I ⦄) in
    x  f (l  r)  x  f l  x  f r
∈-collect-++⁻ {X = X} l r rewrite collectFromBase-++ {X = X} l r = ∈-++⁻ _

∈-collect-++⁺ˡ :  l r {x : X}   I : BaseCfg has X   let f = collectFromBase (collect  I ⦄) in
    x  f l  x  f (l  r)
∈-collect-++⁺ˡ {X = X} l r rewrite collectFromBase-++ {X = X} l r = ∈-++⁺ˡ

∈-collect-++⁺ʳ :  l r {x : X}   I : BaseCfg has X   let f = collectFromBase (collect  I ⦄) in
    x  f r  x  f (l  r)
∈-collect-++⁺ʳ {X = X} l r rewrite collectFromBase-++ {X = X} l r = ∈-++⁺ʳ _

instance
  HNᵃᶜ : Action has Name
  HNᵃᶜ .collect ac with ac
  ... | ♯▷ ad            = collect ad
  ... | x ▷ˢ ad          = inj₁ x  collect ad
  ... | x  c            = inj₁ x  collect c
  ... | x  y ▷⟨ _ , _  = map inj₁ [ x  y ]
  ... | x ▷⟨ _ , _ , _  = [ inj₁ x ]
  ... | x ▷ᵈ _           = [ inj₁ x ]
  ... | xs , _ ▷ᵈˢ x     = map inj₁ (x  xs)

  HBC⇒HC′ :  BaseCfg has X   Cfg′ has X
  HBC⇒HC′ .collect = collectFromList (collect  it ⦄)

  HC′⇒HC :  Cfg′ has X   Cfg has X
  HC′⇒HC  i  .collect = collect  i   to[ Cfg′ ]

  HDᶜᶠ : BaseCfg has DepositRef
  HDᶜᶠ .collect = λ where
    (`⟨ A has v ⟩at x)  [ A , v , x ]
    _                   []

  HNᶜᶠ : BaseCfg has Name
  HNᶜᶠ .collect = λ where
    -- secrets
    (`⟨ _  s  _ )    [ inj₁ s ]
    (_ `∶ s  _)        [ inj₁ s ]
    -- names
    (`⟨ _ ,   _ ⟩at x)  [ inj₂ x ]
    (`⟨ _ has _ ⟩at x)  [ inj₂ x ]
    _                   []

  HAᶜᶠ : BaseCfg has Action
  HAᶜᶠ .collect = λ where
    (_ `auth[ a ])  [ a ]
    _               []

  -- ** See `authorizedHonAds` below
  HAᵇᶜᶠ : BaseCfg has Ad
  HAᵇᶜᶠ .collect = λ where
    (A `auth[ ♯▷ ad ])  if does (A ∈? Hon) then [ ad ] else []
    _                   []

  Hᶜᶠ⇒Hᵗᶜᶠ :  Cfg has X   Cfgᵗ has X
  Hᶜᶠ⇒Hᵗᶜᶠ  hx  .collect = collect  hx   cfg

authorizedActions :  _ :  X has Action   X  List Action
authorizedActions = collect

advertisements :  _ :  X has Ad   X  List Ad
advertisements = collect
authorizedHonAds = advertisements

-- authorizedAds : ⦃ _ :  X has Action ⦄ → X → List Ad
-- authorizedAds = mapMaybe (λ where (♯▷ ad) → just ad; _ → nothing)
--               ∘ authorizedActions

ids-++ :  l r  ids (l  r)  ids l ++ ids r
ids-++ = mapMaybe∘collectFromBase-++ isInj₂

∈-ids-++⁻ :  l r {x : Id}  x  ids (l  r)  (x  ids l)  (x  ids r)
∈-ids-++⁻ l r rewrite ids-++ l r = ∈-++⁻ (ids l)

∈-ids-++⁺ˡ :  l r  ids l  ids (l  r)
∈-ids-++⁺ˡ l r rewrite ids-++ l r = ∈-++⁺ˡ

∈-ids-++⁺ʳ :  l r  ids r  ids (l  r)
∈-ids-++⁺ʳ l r rewrite ids-++ l r = ∈-++⁺ʳ (ids l)

destruct-∈-ids-++ :  l r (x∈ : x  ids (l  r)) 
    ( λ (x∈ˡ : x  ids l)  x∈  ∈-ids-++⁺ˡ l r x∈ˡ)
   ( λ (x∈ʳ : x  ids r)  x∈  ∈-ids-++⁺ʳ l r x∈ʳ)
destruct-∈-ids-++ l r x∈ rewrite ids-++ l r = destruct-∈-++ x∈

secrets-++ :  l r  secrets (l  r)  secrets l ++ secrets r
secrets-++ = mapMaybe∘collectFromBase-++ isInj₁

∈-secrets-++⁻ :  l r {x : Id}  x  secrets (l  r)  (x  secrets l)  (x  secrets r)
∈-secrets-++⁻ l r rewrite secrets-++ l r = ∈-++⁻ (secrets l)

∈-secrets-++⁺ˡ :  l r  secrets l  secrets (l  r)
∈-secrets-++⁺ˡ l r rewrite secrets-++ l r = ∈-++⁺ˡ

∈-secrets-++⁺ʳ :  l r  secrets r  secrets (l  r)
∈-secrets-++⁺ʳ l r rewrite secrets-++ l r = ∈-++⁺ʳ (secrets l)

secretsOfᶜᶠ : Participant  Cfg  Secrets
secretsOfᶜᶠ A = {- Set'.nub ∘-} go
  where
    go : Cfg  Secrets
    go ( B  a  _ ) = if A == B then [ a ] else []
    go (l  r)         = go l ++ go r
    go _               = []

committedParticipants : Ad  Cfg  List Participant
committedParticipants ad = collect
  module ∣committedParticipants∣ where
    instance
      go : BaseCfg has Participant
      go .collect = λ where
        (p `auth[ (♯▷ ad′) ])  if ad == ad′ then [ p ] else []
        _                      []

committed⇒authCommit :
   A  committedParticipants ad Γ
   --—————————————————————————————
  A auth[ ♯▷ ad ] ∈ᶜ Γ
committed⇒authCommit {ad = ad} {Γ = _ auth[ ♯▷ ad′ ]} A∈
  with ad  ad′ | A∈
... | yes refl | here refl = here refl
committed⇒authCommit {A}{ad} {Γ = l  r} A∈
  with ∈-collect-++⁻ l r  ∣committedParticipants∣.go ad  A∈
... | inj₁ A∈ˡ = ∈ᶜ-++⁺ˡ l r (committed⇒authCommit {Γ = l} A∈ˡ)
... | inj₂ A∈ʳ = ∈ᶜ-++⁺ʳ l r (committed⇒authCommit {Γ = r} A∈ʳ)

module _ (A∈ : A  Hon) where
  committed⇒authAd :
      A  committedParticipants ad Γ
     ad  authorizedHonAds Γ
  -- committed⇒authAd {Γ} {ad} P
  committed⇒authAd {ad} {p auth[ ♯▷ ad′ ]} P
    with ad  ad′ | P
  ... | no _    | ()
  ... | yes ad≡ | here refl
    rewrite dec-true (A ∈? Hon) A∈
    = here ad≡
  committed⇒authAd {ad} {l  r} P
    with ∈-collect-++⁻ l r  ∣committedParticipants∣.go ad   P
  ... | inj₁ ∈l = ∈-collect-++⁺ˡ l r (committed⇒authAd {Γ = l} ∈l)
  ... | inj₂ ∈r = ∈-collect-++⁺ʳ l r (committed⇒authAd {Γ = r} ∈r)

committedSingle≡ : committedParticipants ad (A auth[ ♯▷ ad ])  [ A ]
committedSingle≡ {ad} rewrite ≟-refl ad = refl

committedPartG≡ :  ps  committedParticipants ad (|| map (_auth[ ♯▷ ad ]) ps)  ps
committedPartG≡ [] = refl
committedPartG≡ (_  []) = committedSingle≡
committedPartG≡ {ad} (p  ps@(_  _)) =
  begin
    committedParticipants ad (|| (p auth[ ♯▷ ad ]  map (_auth[ ♯▷ ad ]) ps))
  ≡⟨⟩
    committedParticipants ad (|| (p auth[ ♯▷ ad ]  map (_auth[ ♯▷ ad ]) ps))
  ≡⟨ collectFromBase-++  ∣committedParticipants∣.go ad  (p auth[ ♯▷ ad ]) (|| map (_auth[ ♯▷ ad ]) ps) 
    committedParticipants ad (p auth[ ♯▷ ad ]) ++ committedParticipants ad (|| map (_auth[ ♯▷ ad ]) ps)
  ≡⟨ cong (_++ committedParticipants ad (|| map (_auth[ ♯▷ ad ]) ps)) committedSingle≡ 
    p  committedParticipants ad (|| map (_auth[ ♯▷ ad ]) ps)
  ≡⟨ cong (p ∷_) (committedPartG≡ ps) 
    p  ps
   where open ≡-Reasoning

-- ** Collections of equivalent configurations.

-- ≈⇒names↭ : _≈_ {A = Cfg} ⇒² _↭⦅ names ⦆_
≈⇒names↭ : Γ  Γ′  Γ ↭⦅ names  Γ′
≈⇒names↭ = collectFromList↭ (collect  it ⦄)

≈⇒ads↭ : Γ  Γ′  Γ ↭⦅ advertisements  Γ′
≈⇒ads↭ = collectFromList↭ (collect  it ⦄)

≈⇒namesʳ↭ : Γ  Γ′  Γ ↭⦅ namesʳ  Γ′
≈⇒namesʳ↭ {Γ}{Γ′} eq = mapMaybe-↭ isInj₂ $ ≈⇒names↭ {Γ}{Γ′} eq

≈⇒namesˡ↭ : Γ  Γ′  Γ ↭⦅ namesˡ  Γ′
≈⇒namesˡ↭ {Γ}{Γ′} eq = mapMaybe-↭ isInj₁ $ ≈⇒names↭ {Γ}{Γ′} eq

≈⇒deposits↭ : Γ  Γ′  Γ ↭⦅ deposits  Γ′
≈⇒deposits↭ = collectFromList↭ (collect  it ⦄)

∈-resp-≈ :  {Z Z′ A : Type}   _ : A has Z    _ : ISetoid A 
   (f :  {X}   X has Z   X  List Z′)
   (∀ {a a′ : A}  a  a′  a ↭⦅ f  a′)
    (z : Z′)     z  f ) Respects _≈_
∈-resp-≈ _ ≈⇒↭ x = ∈-resp-↭  ≈⇒↭

∈ads-resp-≈      = ∈-resp-≈ advertisements  {Γ}{Γ′}  ≈⇒ads↭      {Γ}{Γ′})
∈names-resp-≈    = ∈-resp-≈ names           {Γ}{Γ′}  ≈⇒names↭    {Γ}{Γ′})
∈namesˡ-resp-≈   = ∈-resp-≈ namesˡ          {Γ}{Γ′}  ≈⇒namesˡ↭   {Γ}{Γ′})
∈namesʳ-resp-≈   = ∈-resp-≈ namesʳ          {Γ}{Γ′}  ≈⇒namesʳ↭   {Γ}{Γ′})
∈deposits-resp-≈ = ∈-resp-≈ deposits        {Γ}{Γ′}  ≈⇒deposits↭ {Γ}{Γ′})

--- ** name helpers

↭-sym∘≈⇒names↭ :
    (Γ≈ : Γ  Γ′)
    --——————————————————————————
   ↭-sym (≈⇒names↭ {Γ}{Γ′} Γ≈)
   ≈⇒names↭ {Γ′}{Γ} (↭-sym Γ≈)
↭-sym∘≈⇒names↭ = ↭-sym∘concatMap⁺ names

↭-sym∘≈⇒namesʳ↭ :
    (Γ≈ : Γ  Γ′)
    --——————————————————————————
   ↭-sym (≈⇒namesʳ↭ {Γ}{Γ′} Γ≈)
   ≈⇒namesʳ↭ {Γ′}{Γ} (↭-sym Γ≈)
↭-sym∘≈⇒namesʳ↭ {Γ}{Γ′} Γ≈ =
  begin
    ↭-sym (≈⇒namesʳ↭ {Γ}{Γ′} Γ≈)
  ≡⟨ ↭-sym∘mapMaybe⁺ isInj₂ $ ≈⇒names↭ {Γ}{Γ′} Γ≈ 
    mapMaybe-↭ isInj₂ (↭-sym $ ≈⇒names↭ {Γ}{Γ′} Γ≈)
  ≡⟨ cong (mapMaybe-↭ isInj₂) $ ↭-sym∘≈⇒names↭ {Γ}{Γ′} Γ≈ 
    ≈⇒namesʳ↭ {Γ′}{Γ} (↭-sym Γ≈)
   where open ≡-Reasoning

deposit∈Γ⇒namesʳ :  {Γ}
    A has v ⟩at x ∈ᶜ Γ
   x  namesʳ Γ
deposit∈Γ⇒namesʳ {A} {v} {x} {` _} (here ())
deposit∈Γ⇒namesʳ {A} {v} {x} { _ , _ ⟩at _} (here ())
deposit∈Γ⇒namesʳ {A} {v} {x} { _ has _ ⟩at .x} (here refl) = here refl
deposit∈Γ⇒namesʳ {A} {v} {x} {_ auth[ _ ]} (here ())
deposit∈Γ⇒namesʳ {A} {v} {x} { _  _  _ } (here ())
deposit∈Γ⇒namesʳ {A} {v} {x} {_  _  _} (here ())
deposit∈Γ⇒namesʳ {A} {v} {x} {l  r} d∈
  with ∈ᶜ-++⁻ l r d∈
... | inj₁ d∈ˡ = let _ , x∈ , d≡ = ∈-mapMaybe⁻ isInj₂ (deposit∈Γ⇒namesʳ {Γ = l} d∈ˡ)
                 in ∈-mapMaybe⁺ isInj₂ (∈-collect-++⁺ˡ l r x∈) d≡
... | inj₂ d∈ʳ = let _ , x∈ , d≡ = ∈-mapMaybe⁻ isInj₂ (deposit∈Γ⇒namesʳ {Γ = r} d∈ʳ)
                 in ∈-mapMaybe⁺ isInj₂ (∈-collect-++⁺ʳ l r x∈) d≡

namesʳ-∥map-authDestroy :  (ds : DepositRefs)
   map (proj₂  proj₂) ds  namesʳ (|| map (uncurry₃ ⟨_has_⟩at_) ds)
namesʳ-∥map-authDestroy (_  []) (here refl) = here refl
namesʳ-∥map-authDestroy (_  _  _) (here refl) = here refl
namesʳ-∥map-authDestroy ((Bᵢ , vᵢ , xᵢ)  ds@(_  _)) (there d∈) = there $ (namesʳ-∥map-authDestroy ds) d∈

private
  n≡ :  {A : Type} {P Q : A  Cfg}
     (∀ x  Null $ namesʳ (Q x) )
     (xs : List A)
     namesʳ (|| map  x  P x  Q x) xs)
     namesʳ (|| map P xs)
  n≡ ∀x [] = refl
  n≡ {P = P}{Q} ∀x (x₁  []) = P∣Q≡
    where
      P∣Q≡ : namesʳ (P x₁  Q x₁)  namesʳ (P x₁)
      P∣Q≡ rewrite mapMaybe∘collectFromBase-++ isInj₂ (P x₁) (Q x₁)
                | ∀x x₁
                | L.++-identityʳ (namesʳ $ P x₁)
                = refl
  n≡ {P = P}{Q} ∀x (x₁  xs@(_  _)) =
    begin
      namesʳ (|| (P x₁  Q x₁  map  x  P x  Q x) xs))
    ≡⟨⟩
      namesʳ (P x₁  Q x₁  || map  x  P x  Q x) xs)
    ≡⟨ mapMaybe∘collectFromBase-++ isInj₂ (P x₁  Q x₁) (|| map  x  P x  Q x) xs) 
      namesʳ (P x₁  Q x₁) ++ namesʳ (|| map  x  P x  Q x) xs)
    ≡⟨ cong (_++ namesʳ (|| map  x  P x  Q x) xs)) P∣Q≡ 
      namesʳ (P x₁) ++ namesʳ (|| map  x  P x  Q x) xs)
    ≡⟨ cong (namesʳ (P x₁) ++_) $ n≡ {P = P}{Q} ∀x xs 
      namesʳ (P x₁) ++ namesʳ (|| map P xs)
    ≡⟨ sym $ mapMaybe∘collectFromBase-++ isInj₂ (P x₁) (|| map P xs) 
      namesʳ (|| (P x₁  map P xs))
    
    where
      open ≡-Reasoning

      P∣Q≡ : namesʳ (P x₁  Q x₁)  namesʳ (P x₁)
      P∣Q≡ rewrite collectFromBase-++ {X = Name} (P x₁) (Q x₁)
                | mapMaybe-++ isInj₂ (names $ P x₁) (names $ Q x₁)
                | ∀x x₁
                | L.++-identityʳ (namesʳ $ P x₁)
                = refl

namesʳ-∥map-destroy :  (ds : DepositRefs)  let xs = map (proj₂  proj₂) ds in
  xs  namesʳ (|| map (λ{ (i , Aᵢ , vᵢ , xᵢ)   Aᵢ has vᵢ ⟩at xᵢ  Aᵢ auth[ xs , ‼-map {xs = ds} i ▷ᵈˢ y ] }) (enumerate ds))
namesʳ-∥map-destroy {y = y} ds {x} x∈ = qed
  where
     = map (proj₂  proj₂) ds
    eds = enumerate ds

    P : DepositRef  Cfg
    P (Aᵢ , vᵢ , xᵢ) =  Aᵢ has vᵢ ⟩at xᵢ

    P′ :  {A : Type}  A × DepositRef  Cfg
    P′ = P  proj₂

    Q P∣Q : Index ds × DepositRef  Cfg
    Q (i , Aᵢ , vᵢ , xᵢ) = Aᵢ auth[  , ‼-map {xs = ds} i ▷ᵈˢ y ]
    P∣Q x = P′ x  Q x

    h : namesʳ (|| map P∣Q eds)
       namesʳ (|| map P′ eds)
    h = n≡ {A = Index ds × DepositRef} {P = P′} {Q = Q}  _  refl) eds

    -- [BUG] if I replace `enumerate ds` with `eds` I get an error!?
    h′ :  (ds : DepositRefs)  map P′ (enumerate ds)  map P ds
    h′ [] = refl
    h′ (pvi  ds) = cong (_ ∷_) qed
      where
        rec : map P′ (zip (L.tabulate {n = length ds} (fsuc  id)) ds)
             map (P′  map₁ fsuc) (zip (L.tabulate {n = length ds} id) ds)
        rec = map∘zip∘tabulate⟨fsuc⟩≈map⟨fsuc⟩∘zip∘tabulate {m = length ds} ds {P = P′} {f = id}

        qed : map P′ (zip (L.tabulate {n = length ds} fsuc) ds)
             map P ds
        qed = trans rec (h′ ds)

    qed : x  namesʳ (|| map P∣Q eds)
    qed rewrite h | h′ ds = namesʳ-∥map-authDestroy ds x∈

namesʳ-∥map-authCommit :  {secrets : List (Secret × Maybe )}  let (as , ms) = unzip secrets in
    as  namesˡ (|| map (uncurry  A ∶_♯_⟩) secrets)
namesʳ-∥map-authCommit {secrets = `∅ᶜ} ()
namesʳ-∥map-authCommit {secrets = (_ , _)  []} (here refl) = here refl
namesʳ-∥map-authCommit {secrets = (_ , _)  ss@(_  _)} (here refl) = here refl
namesʳ-∥map-authCommit {secrets = _  ss@(_  _)} (there a∈) = there (namesʳ-∥map-authCommit {secrets = ss} a∈)

x∈vcis⇒¬fresh :  {vcis : VIContracts}
    c , v ⟩at x ∈ᶜ || map (uncurry₃ $ flip ⟨_,_⟩at_) vcis
    --—————————————————————————————————————————————————
   x  select₃ (unzip₃ vcis)
x∈vcis⇒¬fresh {vcis = _  []}         = λ where
  (here refl)  here refl
x∈vcis⇒¬fresh {vcis = _  vs@(_  _)} = λ where
  (here refl)  here refl
  (there c∈)   there $ x∈vcis⇒¬fresh {vcis = vs} c∈

c∈vcis⇒ :  {vcis : VIContracts}
    c , v ⟩at x ∈ᶜ || map (uncurry₃ $ flip ⟨_,_⟩at_) vcis
    --———————————————————————————————————————————————————————
   c  proj₁ (proj₂ $ unzip₃ vcis)
c∈vcis⇒ {vcis = _  []}         = λ where
  (here refl)  here refl
c∈vcis⇒ {vcis = _  vs@(_  _)} = λ where
  (here refl)  here refl
  (there c∈)   there $ c∈vcis⇒ {vcis = vs} c∈

c∈vcis⇒′ :  {vcis : VIContracts} 
  let
    (vs , cs , _) = unzip₃ vcis
    vcs = zip vs cs
  in
     c , v ⟩at x ∈ᶜ || map (uncurry₃ $ flip ⟨_,_⟩at_) vcis
    --————————————————————————————————————————————————————————
   c  map proj₂ vcs
c∈vcis⇒′ {vcis = _  []}         = λ where
  (here refl)  here refl
c∈vcis⇒′ {vcis = _  vs@(_  _)} = λ where
  (here refl)  here refl
  (there c∈)   there $ c∈vcis⇒′ {vcis = vs} c∈

x∈vcis⇒ :  {vcis : VIContracts}
   x  ids (|| map (uncurry₃ $ flip ⟨_,_⟩at_) vcis)
   x  select₃ (unzip₃ vcis)
x∈vcis⇒ {vcis = _  []}         = λ where
  (here refl)  here refl
x∈vcis⇒ {vcis = _  vs@(_  _)} = λ where
  (here refl)  here refl
  (there c∈)   there $ x∈vcis⇒ {vcis = vs} c∈

-- Base/Composite configurations.

IsComposite IsBase : Pred₀ Cfg
IsComposite = λ where
  (_  _)  
  _        
IsBase = λ where
  ∅ᶜ       
  (_  _)  
  _        

¬base×composite :  Γ  ¬ (IsBase Γ × IsComposite Γ)
¬base×composite = λ where
  ∅ᶜ      (() , _)
  (_  _) (() , _)
  (` _)             (_ , ())
  ( _ has _ ⟩at _) (_ , ())
  ( _ , _ ⟩at _)   (_ , ())
  (_ auth[ _ ])     (_ , ())
  ( _  _  _ )   (_ , ())
  (_  _  _)       (_ , ())

instance
  Split-∣ : ( IsComposite) -splitsInto- Cfg
  Split-∣ .mkSplit ((l  r) , tt) = l , r

IsBase-BaseCfg  :  ( : BaseCfg)
   IsBase (to[ Cfg ] )
IsBase-BaseCfg = λ where
  (`` _)              tt
  (`⟨ _ , _ ⟩at _)    tt
  (`⟨ _ has _ ⟩at _)  tt
  (_ `auth[ _ ])      tt
  `⟨ _  _  _       tt
  (_ `∶ _  _)        tt

∈ᶜ⇒IsBase :  {γ Γ}
   γ ∈ᶜ Γ
   IsBase γ
∈ᶜ⇒IsBase {γ = γ} γ∈
  with  , `γ∈ , eq∈-map⁻ to[ Cfg ] γ∈
  = subst IsBase (sym eq) $ IsBase-BaseCfg 

instance
  Squashed-IsBase :  {Γ}  · (IsBase Γ)
  Squashed-IsBase {Γ} .∀≡ with Γ
  ... | ∅ᶜ              = λ ()
  ... | _  _           = λ ()
  ... | ` _             = λ tt tt  refl
  ... |  _ has _ ⟩at _ = λ tt tt  refl
  ... |  _ , _ ⟩at _   = λ tt tt  refl
  ... | _ auth[ _ ]     = λ tt tt  refl
  ... |  _  _  _    = λ tt tt  refl
  ... | _  _  _       = λ tt tt  refl

instance
  Cfg↝BaseCfg : Cfg  IsBase  BaseCfg
  Cfg↝BaseCfg .toBecause (` ad)            = `` ad
  Cfg↝BaseCfg .toBecause ( c , v ⟩at x)   = `⟨ c , v ⟩at x
  Cfg↝BaseCfg .toBecause ( A has v ⟩at x) = `⟨ A has v ⟩at x
  Cfg↝BaseCfg .toBecause (A auth[ a ])     = A `auth[ a ]
  Cfg↝BaseCfg .toBecause ( A  s  mn )  = `⟨ A  s  mn 
  Cfg↝BaseCfg .toBecause (A  s  n)       = A `∶ s  n

private
  _ :   c , v ⟩at x   `⟨ c , v ⟩at x
  _ = refl

IsBase-to[Cfg] :  (β : BaseCfg)  IsBase (to[ Cfg ] β)
IsBase-to[Cfg] = λ where
  (`` _)  tt
  (`⟨ _ , _ ⟩at _)  tt
  (`⟨ _ has _ ⟩at _)  tt
  (_ `auth[ _ ])  tt
  `⟨ _  _  _   tt
  (_ `∶ _  _)  tt

to[Cfg]-inverseˡ :  (β : BaseCfg) 
  ((λ _   _  IsBase-to[Cfg] β )  to[ Cfg ]) β  β
to[Cfg]-inverseˡ = λ where
  (`` _)              refl
  (`⟨ _ , _ ⟩at _)    refl
  (`⟨ _ has _ ⟩at _)  refl
  (_ `auth[ _ ])      refl
  `⟨ _  _  _       refl
  (_ `∶ _  _)        refl

to[Cfg]-inverseʳ :  (γ : Cfg) (base-γ : IsBase γ) 
  (to[ Cfg ]   _   _  base-γ )) γ  γ
to[Cfg]-inverseʳ = λ where
  (` _)             _  refl
  ( _ , _ ⟩at _)   _  refl
  ( _ has _ ⟩at _) _  refl
  (_ auth[ _ ])     _  refl
   _  _  _      _  refl
  (_  _  _)       _  refl

open import Prelude.InferenceRules
open import Prelude.Tactics.Rewrite

toCfg≡ :  γ (β : BaseCfg) 
 (γ≡ : γ  to[ Cfg ] β) 
 ──────────────────────────────────────────────
 let base-γ =  IsBase  γ≡ ~: IsBase-to[Cfg] β
 in  γ   base-γ   β
toCfg≡ (` )              (`` _)             refl = refl
toCfg≡ ( _ , _ ⟩at _)   (`⟨ _ , _ ⟩at _)   refl = refl
toCfg≡ ( _ has _ ⟩at _) (`⟨ _ has _ ⟩at _) refl = refl
toCfg≡ (_ auth[ _ ])     (_ `auth[ _ ])     refl = refl
toCfg≡  _  _  _      `⟨ _  _  _      refl = refl
toCfg≡ (_  _  _)       (_ `∶ _  _)       refl = refl

∈-Cfg′ :  γ Γ
   (γ∈ : γ ∈ᶜ Γ)
    γ  ∈ᶜ⇒IsBase {Γ = Γ} γ∈   to[ Cfg′ ] Γ
∈-Cfg′ γ Γ γ∈ =
  let β , β∈ , eq = L.Mem.∈-map⁻ to[ Cfg ] γ∈
  in L.Any.map (trans $ toCfg≡ _ _ eq) β∈

∈-resp-↭∘∈-Cfg′ :  γ Γ Γ′
   (Γ≈ : Γ  Γ′)
   (γ∈ : γ ∈ᶜ Γ)
  --————————————————————————————————————
   ( ∈-Cfg′ _ Γ′          -- ⌞ γ ⌟ ∈ to[ Cfg′ ] Γ′
     ∈ᶜ-resp-≈ {Γ}{Γ′} Γ≈ -- γ ∈ᶜ Γ′
    ) γ∈                   -- γ ∈ᶜ Γ
   ( ∈-resp-↭ Γ≈ -- ⌞ γ ⌟ ∈ to[ Cfg′ ] Γ′
     ∈-Cfg′ _ Γ  -- ⌞ γ ⌟ ∈ to[ Cfg′]  Γ
    ) γ∈          -- γ ∈ᶜ Γ
∈-resp-↭∘∈-Cfg′ γ Γ Γ′ Γ≈ γ∈
  = begin
    ( ∈-Cfg′ _ Γ′                  -- β ∈ to[ Cfg′ ] Γ′
     ∈-resp-↭ (map⁺ to[ Cfg ] Γ≈) -- γ ∈ᶜ Γ′
    ) γ∈                           -- γ ∈ᶜ Γ
  ≡⟨⟩
    ( (λ{ (β , β∈ , eq)  L.Any.map (trans $ toCfg≡ _ _ eq) β∈})
     ∈-map⁻ to[ Cfg ]
     ∈-resp-↭ (map⁺ to[ Cfg ] Γ≈)
    ) γ∈
  ≡⟨ cong (λ{ (β , β∈ , eq)  L.Any.map (trans $ toCfg≡ _ _ eq) β∈})
        $ ∈-map⁻∘∈-resp-↭∘map⁺ to[ Cfg ] Γ≈ γ∈ 
    ( (λ{ (β , β∈ , eq)  L.Any.map (trans $ toCfg≡ _ _ eq) β∈})
     map₂′ (map₁ $ ∈-resp-↭ Γ≈)
     ∈-map⁻ to[ Cfg ]
    ) γ∈
  ≡⟨⟩
    ( (λ{ (β , β∈ , eq)  L.Any.map (trans $ toCfg≡ _ _ eq) (∈-resp-↭ Γ≈ β∈)})
     ∈-map⁻ to[ Cfg ]
    ) γ∈
  ≡⟨ (let β , β∈ , eq = ∈-map⁻ to[ Cfg ] γ∈
      in Any-map∘∈-resp-↭ (trans $ toCfg≡ γ β eq) Γ≈ β∈) 
    ( (λ{ (β , β∈ , eq)  ∈-resp-↭ Γ≈ $ L.Any.map (trans $ toCfg≡ _ _ eq) β∈})
     ∈-map⁻ to[ Cfg ]
    ) γ∈
  ≡⟨⟩
    ( ∈-resp-↭ Γ≈ -- β ∈ to[Cfg′] Γ′
     ∈-Cfg′ _ Γ  -- β ∈ to[Cfg′] Γ
    ) γ∈          -- γ ∈ᶜ Γ
   where open ≡-Reasoning