-- FVIntmax/AttackGame.lean

import FVIntmax.Wheels.AuthenticatedDictionary

import FVIntmax.Wheels.SignatureAggregation

import FVIntmax.BalanceProof

import FVIntmax.Block

import FVIntmax.Request

import FVIntmax.Wheels

namespace Intmax

noncomputable section Intmax

section RollupContract

open Classical

section

variable {C : Type} [Nonempty C]

         {V : Type} [Lattice V] [AddCommGroup V]
         
         {K₁ : Type} [Finite K₁] [Nonempty K₁]
         {K₂ : Type} [Finite K₂]
         {Sigma : Type}
         [ADScheme K₂ (C × K₁ × ExtraDataT) C Pi]
         [SA : SignatureAggregation (C × K₁ × ExtraDataT) K₂ KₛT Sigma]

def Block.updateBalance (bal : V) (block : Block K₁ K₂ C Sigma V) : V :=
  match block with
   
  | .deposit _ v  => bal + v
   
  | .transfer ..  => bal
   
  | .withdrawal B => bal - ∑ k : K₁, (B k).1

end

section

variable {C : Type}
         {V : Type} [Lattice V] [AddCommGroup V]
         {K₁ : Type} [Finite K₁]
         {K₂ : Type}
         {Sigma : Type}
         {block : Block K₁ K₂ C Sigma V}
         {v : V}

section Lemmas

end Lemmas

namespace Scontract

section

variable [LinearOrder K₁] [Nonempty K₁]
         [LinearOrder K₂] [Finite K₂]
         [Nonempty C]
         [CovariantClass V V (· + ·) (· ≤ ·)]
         [CovariantClass V V (Function.swap (· + ·)) (· ≤ ·)]
         [ADScheme K₂ (C × K₁ × ExtraDataT) C Pi]
         [SignatureAggregation (C × K₁ × ExtraDataT) K₂ KₛT Sigma]

section appendBlock

variable {σ : Scontract K₁ K₂ V C Sigma} {request : Request K₁ K₂ C Sigma Pi V}

end appendBlock

end

section

variable [LinearOrder K₁]
         [Finite K₂] [LinearOrder K₂]
         {σ : Scontract K₁ K₂ V C Sigma}
         {request : Request K₁ K₂ C Sigma Pi V}
         [CovariantClass V V (· + ·) (· ≤ ·)]
         [CovariantClass V V (Function.swap (· + ·)) (· ≤ ·)]

end

end Scontract

end

end RollupContract

section AttackGameDefs

variable {K₁ : Type} [Finite K₁] [LinearOrder K₁] [Nonempty K₁]
         {K₂ : Type} [Finite K₂] [LinearOrder K₂]

         {V : Type} [Lattice V] [AddCommGroup V]
         [CovariantClass V V (· + ·) (· ≤ ·)]
         [CovariantClass V V (Function.swap (· + ·)) (· ≤ ·)]

         {Sigma : Type}
         {C : Type} [Nonempty C]

         [ADScheme K₂ (C × K₁ × ExtraDataT) C Pi]
         [SignatureAggregation (C × K₁ × ExtraDataT) K₂ KₛT Sigma]

         (requests : List (Request K₁ K₂ C Sigma Pi V))
         (σ : Scontract K₁ K₂ V C Sigma)

def computeBalance' (blocks : Scontract K₁ K₂ V C Sigma) (acc : V) : V :=
  blocks.foldl Block.updateBalance acc

end AttackGameDefs

section AttackGameLemmas

variable {K₁ K₂ Sigma C : Type}
         {V : Type} [Lattice V] [AddCommGroup V]
         [CovariantClass V V (· + ·) (· ≤ ·)]
         [ADScheme K₂ (C × K₁ × ExtraDataT) C Pi]

section computeBalanceSum

variable {k : ℕ}

end computeBalanceSum

variable [Finite K₁]

end AttackGameLemmas

section ComputeLemmas

variable {K₁ : Type} [Finite K₁] {K₂ Sigma C : Type}
         {V : Type} [Lattice V] [AddCommGroup V]
         {σ : Scontract K₁ K₂ V C Sigma}
         [ADScheme K₂ (C × K₁ × ExtraDataT) C Pi]

-- Repository definitions used:
content: inductive Block (K₁ K₂ : Type) (C Sigma : Type) (V : Type) [PreWithZero V] where
   
  | deposit (recipient : K₂) (amount : V₊)
   
  | transfer (aggregator : K₁) (extradata : ExtraDataT) (commitment : C) (senders : List K₂) (sigma : Sigma)
   
  | withdrawal (withdrawals : K₁ → V₊)

content: abbrev Scontract (K₁ K₂ V : Type) [PreWithZero V] (C Sigma : Type) :=
  List (Block K₁ K₂ C Sigma V)

content: abbrev ExtraDataT : Type := ℕ

content: class abbrev PreWithZero (α : Type) := Preorder α, Zero α

content: def NonNeg (α : Type) [PreWithZero α] := { a : α // 0 ≤ a }

content: postfix:max "₊" => NonNeg

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: def Block.updateBalance (bal : V) (block : Block K₁ K₂ C Sigma V) : V :=
  match block with
   
  | .deposit _ v  => bal + v
   
  | .transfer ..  => bal
   
  | .withdrawal B => bal - ∑ k : K₁, (B k).1

content: def computeBalance' (blocks : Scontract K₁ K₂ V C Sigma) (acc : V) : V :=
  blocks.foldl Block.updateBalance acc

-- Local lemmas used:
content: lemma Block.updateBalance_eq_zero :
  block.updateBalance v = v + block.updateBalance 0

content: @[simp]
lemma computeBalance'_cons : computeBalance' (hd :: σ) v =
                             computeBalance' σ (Block.updateBalance v hd)

-- Target theorem and proof:
lemma computeBalance'_eq_zero : computeBalance' σ v = v + computeBalance' σ 0
:= by
  induction' σ with hd tl ih generalizing v
  · simp
  · rw [computeBalance'_cons, computeBalance'_cons, ih, Block.updateBalance_eq_zero]
    nth_rw 2 [ih]
    exact add_assoc v _ _