{-# OPTIONS --safe #-}
open import Prelude
open import Hash
open import Jolteon.Assumptions

module Jolteon.Properties.Steps.QCRound ( : _) (open Assumptions ) where

open import Jolteon 
open import Jolteon.Properties.State 
open import Jolteon.Properties.Steps.Core 
open import Jolteon.Properties.Steps.Phases 

-- ** Relating the round `qc-high` to `r-cur`.

AdvanceRoundLoop⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  AdvancingRound
   ls .tc-last  nothing
   ls .roundAdvanced?  true
   qc -highest-qc-∈- ls .db
    ─────────────────────────
    1 + qc ∙round  ls .r-cur
AdvanceRoundLoop⇒AdvanceRoundQC  {p} (_ , refl , (_ )) ph≡ _ _ _
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
AdvanceRoundLoop⇒AdvanceRoundQC {p} {qc = qc}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡ r≡ hqc∈
  with Rs_ , s-init , tr
  with IHAdvanceRoundLoop⇒AdvanceRoundQC {p} {qc = qc} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡ r≡ hqc∈
... | Deliver {tpm} _
  rewrite receiveMsg-ls≡ {p} {s .stateMap} (honestTPMessage tpm)
  = IH ph≡ tc≡ r≡ hqc∈
... | DishonestLocalStep _ _
  = IH ph≡ tc≡ r≡ hqc∈
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡ r≡ hqc∈
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | AdvancingRound⇒StepAdvances* ((_  st)  hp ⦄) ph≡
... | RegisterProposal m∈ x₁ x₂ x₃ x₄ | tt = contradict $ trans (sym r≡) ¬ra
  where
    ¬ra : ls′ .roundAdvanced?  false
    ¬ra = AdvancingRound⇒¬roundAdvanced Rs ((_  RegisterProposal m∈ x₁ x₂ x₃ x₄)  hp  , refl , refl , tt)
... | RegisterVote m∈ x₁ x₂ x₃ x₄ x₅ | tt = contradict $ trans (sym r≡) ¬ra
  where
    ¬ra : ls′ .roundAdvanced?  false
    ¬ra = AdvancingRound⇒¬roundAdvanced Rs ((_  RegisterVote m∈ x₁ x₂ x₃ x₄ x₅)  hp  , refl , refl , tt)
... | RegisterTimeout m∈ x₁ x₂ x₃ | tt = contradict $ trans (sym r≡) ¬ra
  where
    ¬ra : ls′ .roundAdvanced?  false
    ¬ra = AdvancingRound⇒¬roundAdvanced Rs ((_  RegisterTimeout m∈ x₁ x₂ x₃)  hp  , refl , refl , tt)
... | RegisterTC m∈ x₁ x₂ x₃ | tt = contradict $ trans (sym r≡) ¬ra
  where
    ¬ra : ls′ .roundAdvanced?  false
    ¬ra = AdvancingRound⇒¬roundAdvanced Rs ((_  RegisterTC m∈ x₁ x₂ x₃)  hp  , refl , refl , tt)
... | AdvanceRoundQC {qc = qc′} _ qc∈′ r≥ | tt
  = Nat.+-monoʳ-≤ 1 qc≥
  where
  qc≥ : qc ∙round  qc′ ∙round
  qc≥ with  isHighest qc∈ qc≤ hqc∈
      = qc≤ qc′ qc∈′

AdvanceRound⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  Locking
   ls .tc-last  nothing
   ls .roundAdvanced?  true
   qc -highest-qc-∈- ls .db
    ─────────────────────────
    1 + qc ∙round  ls .r-cur
AdvanceRound⇒AdvanceRoundQC {p} (_ , refl , (_ )) ph≡ _ _ _
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
AdvanceRound⇒AdvanceRoundQC {p} {qc = qc}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡ r≡ hqc∈
  with Rs_ , s-init , tr
  with IHAdvanceRound⇒AdvanceRoundQC {p} {qc = qc} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡ r≡ hqc∈
... | Deliver {tpm} _
  rewrite receiveMsg-ls≡ {p} {s .stateMap} (honestTPMessage tpm)
  = IH ph≡ tc≡ r≡ hqc∈
... | DishonestLocalStep _ _
  = IH ph≡ tc≡ r≡ hqc∈
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡ r≡ hqc∈
... | yes refl rewrite pLookup∘updateAt p   hp  {const ls′} (s .stateMap)
  with st | Locking⇒StepAdvances ((_  st)  hp ⦄) ph≡
... | AdvanceRoundNoOp ph≡′ _ _ | tt
  = AdvanceRoundLoop⇒AdvanceRoundQC  hp  Rs ph≡′ tc≡ r≡ hqc∈

Lock⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  Committing
   ls .tc-last  nothing
   ls .roundAdvanced?  true
    ──────────────────────────────────
    1 + ls .qc-high ∙round  ls .r-cur
Lock⇒AdvanceRoundQC {p} (_ , refl , (_ )) ph≡ _ _
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
Lock⇒AdvanceRoundQC {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡ r≡
  with Rs_ , s-init , tr
  with IHLock⇒AdvanceRoundQC {p}  hp  Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡ r≡
... | Deliver {tpm} _
  = let tpm = honestTPMessage tpm in
    subst (1 + (s′  p) .qc-high ∙round ≥_) (sym $ receiveMsg-rCur tpm)
  $ subst    1 +  ∙round  _) (sym $ receiveMsg-qcHigh tpm)
  $ IH (subst (_≡ _) (receiveMsg-phase tpm) ph≡)
       (subst (_≡ _) (receiveMsg-tcLast tpm) tc≡)
       (subst (_≡ _) (receiveMsg-roundA tpm) r≡)
... | DishonestLocalStep _ _
  = IH ph≡ tc≡ r≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡ r≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | Committing⇒StepLocks∗ ((_  st)  hp ⦄) ph≡
... | Lock ph≡ qc∈ | tt
  = AdvanceRound⇒AdvanceRoundQC {p}  hp  Rs ph≡ tc≡ r≡ qc∈

Commit⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  Voting
   ls .tc-last  nothing
   ls .roundAdvanced?  true
    ──────────────────────────────────
    1 + ls .qc-high ∙round  ls .r-cur
Commit⇒AdvanceRoundQC {p} (_ , refl , (_ )) ph≡ _ _
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
Commit⇒AdvanceRoundQC {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡ r≡
  with Rs_ , s-init , tr
  with IHCommit⇒AdvanceRoundQC {p} Rs
  with IH≫Lock⇒AdvanceRoundQC {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡ r≡
... | Deliver {tpm} _
  = let tpm = honestTPMessage tpm in
    subst (1 + (s′  p) .qc-high ∙round ≥_) (sym $ receiveMsg-rCur tpm)
  $ subst    1 +  ∙round  _) (sym $ receiveMsg-qcHigh tpm)
  $ IH (subst (_≡ _) (receiveMsg-phase tpm) ph≡)
       (subst (_≡ _) (receiveMsg-tcLast tpm) tc≡)
       (subst (_≡ _) (receiveMsg-roundA tpm) r≡)
... | DishonestLocalStep _ _
  = IH ph≡ tc≡ r≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡ r≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | Voting⇒StepCommits∗ ((_  st)  hp ⦄) ph≡
... | Commit     ph≡ _ | tt = IH≫ ph≡ tc≡ r≡
... | CommitNoOp ph≡ _ | tt = IH≫ ph≡ tc≡ r≡

Vote⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  EnteringRound
   ls .tc-last  nothing
   ls .roundAdvanced?  true
    ──────────────────────────────────
    1 + ls .qc-high ∙round  ls .r-cur
Vote⇒AdvanceRoundQC {p} (_ , refl , (_ )) ph≡ _ _
  rewrite pLookup-replicate p initLocalState
  = Nat.≤-refl
Vote⇒AdvanceRoundQC {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡ r≡
  with Rs_ , s-init , tr
  with IHVote⇒AdvanceRoundQC {p} Rs
  with IH≫Commit⇒AdvanceRoundQC {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡ r≡
... | Deliver {tpm} _
  = let tpm = honestTPMessage tpm in
    subst (1 + (s′  p) .qc-high ∙round ≥_) (sym $ receiveMsg-rCur tpm)
  $ subst    1 +  ∙round  _) (sym $ receiveMsg-qcHigh tpm)
  $ IH (subst (_≡ _) (receiveMsg-phase tpm) ph≡)
       (subst (_≡ _) (receiveMsg-tcLast tpm) tc≡)
       (subst (_≡ _) (receiveMsg-roundA tpm) r≡)
... | DishonestLocalStep _ _
  = IH ph≡ tc≡ r≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡ r≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | EnteringRound⇒StepVotes∗ ((_  st)  hp ⦄) ph≡
... | VoteBlock ph≡ _ _   | tt , _ = IH≫ ph≡ tc≡ r≡
... | VoteBlockNoOp ph≡ _ | tt , _ = IH≫ ph≡ tc≡ r≡

InitNoTC⇒AdvanceRoundQC :  {s}   _ : Honest p   Reachable s  let ls = s  p in
   ls .phase  Proposing
   ls .tc-last  nothing
    ──────────────────────────────────
    1 + ls .qc-high ∙round  ls .r-cur
InitNoTC⇒AdvanceRoundQC {p} (_ , refl , (_ )) ph≡ _
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
InitNoTC⇒AdvanceRoundQC {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡ tc≡
  with Rs_ , s-init , tr
  with IHInitNoTC⇒AdvanceRoundQC {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡ tc≡
... | Deliver {tpm} _
  = let tpm = honestTPMessage tpm in
    subst (1 + (s′  p) .qc-high ∙round ≥_) (sym $ receiveMsg-rCur tpm)
  $ subst    1 +  ∙round  _) (sym $ receiveMsg-qcHigh tpm)
  $ IH (subst (_≡ _) (receiveMsg-phase tpm) ph≡)
       (subst (_≡ _) (receiveMsg-tcLast tpm) tc≡)
... | DishonestLocalStep _ _
  = IH ph≡ tc≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡ tc≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | Proposing⇒StepInits ((_  st)  hp ⦄) ph≡
... | InitTC {tc = tc} _ tc≡′ | tt = contradict $ trans (sym tc≡) tc≡′
... | InitNoTC ph≡ _          | tt = Vote⇒AdvanceRoundQC {p}  hp  Rs ph≡ tc≡
                                   $ EnteringRound⇒roundAdvanced  hp  Rs ph≡