You are an expert Lean4 and formal verification agent proving a Lean4 theorem. Your output **must** strictly adhere to the specified format.

### Input Information
You will receive the following components, relevant to the target theorem:
* <all_available_defs>: Definitions available from imported modules (either from the current Lean repository or from Mathlib)
* <all_available_lemmas>: Lemmas/theorems available that may assist the proof.
* <local_ctx>...</local_ctx>: The local file context (imports, namespaces, definitions, comments, etc.) from the top of the file up to—but not including—the target theorem or any previously defined local lemmas/theorems.
* <target_theorem>...</target_theorem>: The target theorem statement, ending with `:=`.

**Notes**
1. Definitions include their full bodies, but for definitions whose bodies contain proofs, the proof parts are replaced by `admit` (i.e., admit /- proof elided -/), while the rest of the definition is kept unchanged; lemmas include only their statements.
2. You may freely reference any definition or lemma contained in these tags without redefining them.
3. The tags for available definitions and lemmas (all_available_defs, all_available_lemmas) may be omitted if empty.

### Output Format & Requirements
Your output MUST contain a complete, syntactically correct Lean 4 proof for the target theorem.

**Strict Output Structure:**
<reasoning> 
...
</reasoning> 

<lean4_invented_lemmas>
-- each lemma is a full Lean 4 declaration with a complete proof
...
</lean4_invented_lemmas>

<lean4_proof>
-- Lean 4 proof body of the target theorem
...
</lean4_proof>

**Requirements:**
1. <reasoning> and <lean4_invented_lemmas> are OPTIONAL. Include them only if they aid proof construction.
2. <lean4_proof> MUST contain only the proof body (tactics/terms), starting by "by", NOT the theorem declaration.
3. <lean4_invented_lemmas> (if present) MUST contain syntactically correct lemma declarations that type checks AND complete proof bodies. Defining a lemma using `axiom` is NOT allowed.
4. <reasoning> contains high-level proof planning.
5. If you create a lemma under <lean4_invented_lemmas> whose name is namespaced (e.g., X.Y.Z), you MUST always refer to it using its fully qualified name. Do NOT rely on shortened names. For example, write rw [X.Y.Z], not rw [Z] for invented lemmas.
6. All Lean 4 code MUST be syntactically correct. No `sorry`, `admit`, or non-Lean text. Comments allowed using `--` or `/- ... -/`.
7. Follow the tags and structure EXACTLY. No extra text before, between, or after the sections.
8. Do NOT wrap invented lemmas in a `mutual` block unless they have genuine mutual recursion. Declare each lemma independently.

### Examples are provided here (example input are under "User Prompt", and example assistant response are under "Agent Response"):
Example 1 ------------------- 
User Prompt:
<all_available_defs>
structure BitVec (w : Nat) where
  /-- Construct a `BitVec w` from a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  ofFin ::

  /-- Interpret a bitvector as a number less than `2^w`.
  O(1), because we use `Fin` as the internal representation of a bitvector. -/
  toFin : Fin (hPow 2 w)
</all_available_defs>

<all_available_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) : (l₁ ++ l₂)[i] = l₁[i]
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
  x[i] = x.toNat.testBit i := rfl
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
    (cons b x).toNat = (b.toNat <<< w) ||| x.toNat
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i
</all_available_lemmas>

<local_ctx>
import Mathlib.Computability.NFA
import Mathlib.Data.FinEnum
import Mathlib.Data.Rel
import Mathlib.Data.Vector.Basic
import Blase.AutoStructs.ForLean

open Set
open Mathlib
open SetRel

-- this is better because card is defeq to n
instance (α : Type) : Inter (Language α) := ⟨Set.inter⟩
instance (α : Type) : Union (Language α) := ⟨Set.union⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width.
-/
structure BitVecs (n : Nat) where
  w : Nat
  bvs : List.Vector (BitVec w) n

def BitVecs.cast (bvs : BitVecs n) (h : n = n') : BitVecs n' :=
  { w := bvs.w, bvs := h ▸ bvs.bvs }

abbrev BitVecs.empty : BitVecs n := ⟨0, List.Vector.replicate n .nil⟩
abbrev BitVecs.singleton {w : Nat} (bv : BitVec w) : BitVecs 1 := ⟨w, bv ::ᵥ .nil⟩
abbrev BitVecs.pair {w : Nat} (bv1 bv2 : BitVec w) : BitVecs 2 := ⟨w, bv1 ::ᵥ bv2 ::ᵥ .nil⟩

/--
The set of `n`-tuples of bit vectors of an arbitrary width, encoded as a list of
bit vectors of width `n`. The width of the encoded bit vectors is the length of
the list.
-/
abbrev BitVecs' (n : Nat) := List (BitVec n)

@[simps]
def dec (bvs' : BitVecs' n) : BitVecs n where
  w := bvs'.length
  bvs := List.Vector.ofFn fun k => BitVec.ofFn fun i => bvs'[i].getLsbD k

@[simp]
</local_ctx>

<target_theorem>
lemma dec_snoc n (bvs' : BitVecs' n) (a : BitVec n) :
  dec (bvs' ++ [a]) =
    { w := bvs'.length + 1
      bvs := List.Vector.ofFn fun k =>
        BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k) } :=
</target_theorem>

Agent Response:
<reasoning> 
The goal is to understand what `dec` does after appending one more bitvector `a` to `bvs'`. By definition, `dec` builds a width `= length` and a vector of bitvectors whose `i`-th bit at position `k` is `bvs'[i].getLsbD k`. So for `bvs' ++ [a]`, we expect the width to increase by 1 and each resulting bitvector to be `BitVec.cons` of the new bit coming from `a`.

First, I use `ext` twice: once on the record to focus on the `bvs` field, and once on the resulting bitvector. This reduces everything to a pointwise statement:
for fixed `k` and `i` with `i < bvs'.length + 1`,
the bit `(bvs' ++ [a])[i].getLsbD k` should match the bit at index `i` of `BitVec.cons (a.getLsbD k) ((dec bvs').bvs.get k)`.

At this point I need a clean description of indexing into `BitVec.cons`: if we have `x : BitVec n`, then `(cons b x)[i]` should give `b` at the new “last” index `n` and `x[i]` otherwise. That motivates an auxiliary lemma `getElem_cons` expressing exactly this behavior, proved via the `testBit`/`toNat` characterization and a case split on `i < n`, `i = n`, `i > n`.

Using `getElem_cons`, the RHS becomes an `if` on whether `i = bvs'.length`. So I split into cases:
- If `i = bvs'.length`, then `(bvs' ++ [a])[i]` is the appended `a`, so both sides reduce to `a.getLsbD k`.
- If `i ≠ bvs'.length`, the bound `i < bvs'.length + 1` forces `i < bvs'.length`. Then `(bvs' ++ [a])[i] = bvs'[i]` by `List.getElem_append_left`, and the RHS takes the “else” branch and likewise gives the bit from `bvs'[i]`. In both subcases, `simp` (plus the definition of `dec`) finishes.

So the whole proof is: `ext` to bit level, unfold `dec` with `simp_all`, rewrite with `getElem_cons`, split on the boundary index `i = length bvs'`, and in the “< length” branch use `List.getElem_append_left` and bounds to line up both sides.
</reasoning> 

<lean4_invented_lemmas>
@[grind =]
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
    (cons b x)[i] = if h : i = n then b else x[i] := by
  simp only [BitVec.getElem_eq_testBit_toNat, BitVec.toNat_cons, Nat.testBit_or]
  rw [Nat.testBit_shiftLeft]
  rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
  · have p1 : ¬(n ≤ i) := by omega
    have p2 : i ≠ n := by omega
    simp [p1, p2]
  · simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
    Bool.true_and, BitVec.testBit_toNat, BitVec.getLsbD_of_ge, Bool.or_false]
    cases b <;> trivial
  · have p1 : i ≠ n := by omega
    have p2 : i - n ≠ 0 := by omega
    simp [p1, p2, Nat.testBit_bool_toNat]
</lean4_invented_lemmas>

<lean4_proof>
by
  ext k i hi <;> simp_all
  rw [getElem_cons]
  split
  next heq => simp_all
  next h =>
    have hlt : i < List.length bvs' := by simp at hi; omega
    rw [List.getElem_append_left hlt]
    simp
</lean4_proof>

### Your task:
<all_available_defs>
Fin in Init.Prelude
Subspace in Mathlib.Algebra.Module.Submodule.Basic
Set in Mathlib.Data.Set.Defs
Set.Ico in Mathlib.Order.Interval.Set.Defs
Submodule in Mathlib.Algebra.Module.Submodule.Defs
Submodule.span in Mathlib.LinearAlgebra.Span.Defs
Polynomial.C in Mathlib.Algebra.Polynomial.Basic
Nat in Init.Prelude
Fintype in Mathlib.Data.Fintype.Defs
Fintype.card in Mathlib.Data.Fintype.Card
algebraMap in Mathlib.Algebra.Algebra.Defs
Fin.foldl in Init.Data.Fin.Fold
context in Examples.FrankingProtocol
Finset in Mathlib.Data.Finset.Defs
Finset.univ in Mathlib.Data.Fintype.Defs
Eq in Init.Prelude
Fin.mk in Init.Prelude
DecidableEq in Init.Prelude
Fin.isValue in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Fin
Finset.sum in Mathlib.Algebra.BigOperators.Group.Finset.Defs
Polynomial.eval in Mathlib.Algebra.Polynomial.Eval.Defs
Nat.succ in Init.Prelude
IsLinearMap in Mathlib.Algebra.Module.LinearMap.Defs
RingHom in Mathlib.Algebra.Ring.Hom.Defs
RingHom.id in Mathlib.Algebra.Ring.Hom.Defs
Polynomial.rootMultiplicity in Mathlib.Algebra.Polynomial.Div
CommRing in Mathlib.Algebra.Ring.Defs
Polynomial.algEquivOfCompEqX in Mathlib.Algebra.Polynomial.AlgebraMap
Polynomial in Mathlib.Algebra.Polynomial.Basic
Polynomial.X in Mathlib.Algebra.Polynomial.Basic

noncomputable def W (i : Fin r) : L[X] :=
  ∏ u : U 𝔽q β i, (X - C u.val)

def U (i : Fin r) : Subspace 𝔽q L := Submodule.span 𝔽q (β '' (Set.Ico 0 i))

noncomputable def normalizedW (i : Fin r) : L[X] :=
  C (1 / (W 𝔽q β i).eval (β i)) * W 𝔽q β i

def getBit (k n : Nat) : Nat := (n >>> k) &&& 1

def getLowBits (numLowBits : ℕ) (n : ℕ) := n &&& ((1 <<< numLowBits) - 1)

@[elab_as_elim] def Fin.succRecOnSameFinType {motive : Fin r → Sort _}
    (zero : motive (0 : Fin r))
    (succ : ∀ i : Fin r, i + 1 < r → motive i → motive (i + 1)) : ∀ (i : Fin r), motive i
  | ⟨0, _⟩ => by admit /- proof elided -/
  | ⟨Nat.succ i_val, h⟩ => by admit /- proof elided -/

@[simps!]
noncomputable def algEquivAevalXSubC {R : Type*} [CommRing R] (t : R) : R[X] ≃ₐ[R] R[X] :=

structure BacktrackSequenceFamily (trace : QueryLog (duplexSpongeChallengeOracle StmtIn U))
    (state : CanonicalSpongeState U) where
   
  seqFamily : Finset (BacktrackSequence trace state)
   
  maximality : ∀ s ∈ seqFamily, ∀ s' ∈ seqFamily,
    (s.stmt ≠ s'.stmt) ∨ ¬ (s.inputState ⊆ s'.inputState) ∨ ¬ (s'.outputState ⊆ s.outputState)

def InputStatement := R

@[inline, reducible]
def proj : OuterStmtIn × OuterWitIn → InnerWitIn :=
  lens.toFunA

@[reducible]
def addSalt (pSpec : ProtocolSpec n) (Salt : pSpec.MessageIdx → Type) :
    ProtocolSpec n :=
  ⟨pSpec.dir, fun i => match hDir : pSpec.dir i with
    | .P_to_V => (pSpec.«Type» i) × Salt ⟨i, hDir⟩
    | .V_to_P => pSpec.«Type» i⟩

@[reducible, inline, specialize, simp]
def srChallengeQueryImpl' {Statement : Type} {pSpec : ProtocolSpec n}
    [∀ i, SelectableType (pSpec.Challenge i)] :
    QueryImpl (srChallengeOracle Statement pSpec)
      (StateT (srChallengeOracle Statement pSpec).FunctionType ProbComp)
    where
  impl | query i t => fun f => pure (f i t, f)

def α (x₀ : F) (R : F[X][X][Y]) (H : F[X][Y]) [φ : Fact (Irreducible H)] (t : ℕ) : 𝕃 H :=
  let W : 𝕃 H := liftToFunctionField (H.leadingCoeff)
  embeddingOf𝒪Into𝕃 _ (β R t) / (W ^ (t + 1) * (embeddingOf𝒪Into𝕃 _ (ξ x₀ R H)) ^ (2*t - 1))

@[inline]
def nsmul [SMul ℕ R] (m : ℕ) (p : MlPolyEval R n) : MlPolyEval R n := p.map (fun a => m • a)

structure Gate (𝓡 : Type*) (numWires : ℕ) extends Selector 𝓡, WireIndices numWires
deriving DecidableEq

@[inline, specialize]
def processRound (j : Fin n)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (currentResult : OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
      (pSpec.Transcript j.castSucc × prover.PrvState j.castSucc)) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
        (pSpec.Transcript j.succ × prover.PrvState j.succ) := do
  let ⟨transcript, state⟩ ← currentResult
  match hDir : pSpec.dir j with
  | .V_to_P => do
    let challenge ← pSpec.getChallenge ⟨j, hDir⟩
    letI newState := (← prover.receiveChallenge ⟨j, hDir⟩ state) challenge
    return ⟨transcript.concat challenge, newState⟩
  | .P_to_V => do
    let ⟨msg, newState⟩ ← prover.sendMessage ⟨j, hDir⟩ state
    return ⟨transcript.concat msg, newState⟩

abbrev CoeffVecSpace (L : Type u) (ℓ : Nat) := Fin (2^ℓ) → L

instance {i : ℕ} : SmoothPowerOfTwo (n - i) (evalDomain D i) where
  smooth := by admit /- proof elided -/

LawfulMonad in Init.Control.Lawful.Basic

@[inline, reducible]
def Witness.Lens (OuterStmtIn InnerStmtOut OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type)
    := PFunctor.Lens ((OuterStmtIn × OuterWitIn) X^ OuterWitOut)
                     (InnerWitIn X^ (InnerStmtOut × InnerWitOut))

def SkeletonNodeIndex.depth {s : Skeleton} : SkeletonNodeIndex s → Nat
  | SkeletonNodeIndex.ofLeaf => 0
  | SkeletonNodeIndex.ofInternal => 0
  | SkeletonNodeIndex.ofLeft idxLeft => idxLeft.depth + 1
  | SkeletonNodeIndex.ofRight idxRight => idxRight.depth + 1

@[inline]
def ofOutputOnly
    (liftStmt : OuterStmtIn × (∀ i, OuterOStmtIn i) → InnerStmtOut × (∀ i, InnerOStmtOut i) →
                OuterStmtOut × (∀ i, OuterOStmtOut i)) :
    OracleStatement.Lens OuterStmtIn OuterStmtOut OuterStmtIn InnerStmtOut
                        OuterOStmtIn OuterOStmtOut OuterOStmtIn InnerOStmtOut :=
  ⟨id, liftStmt⟩

noncomputable def π_z {H : F[X][Y]} (z : F) (root : rationalRoot (H_tilde' H) z) : 𝒪 H →+* F :=
  Ideal.Quotient.lift (Ideal.span {H_tilde' H}) (π_z_lift z root) sorry

instance : Field ScalarField := ZMod.instField scalarFieldSize

System.mkFilePath in Init.System.FilePath

def StraightlineExtractor (oSpec : OracleSpec ι) (Data Commitment : Type) :=
  Commitment → QueryLog oSpec → Data

example : !d⟨Mymotive⟩[(1 : ℕ), (true : Bool), ("hello" : String)] =
  (Fin.dcons (1 : ℕ) (Fin.dcons (true : Bool) (Fin.dcons ("hello" : String) Fin.dempty)) :
   (i : Fin 3) → Mymotive i) := rfl

def lintStyleCli (args : Cli.Parsed) : IO UInt32 := do
  let style : ErrorFormat := match args.hasFlag "github" with
    | true => ErrorFormat.github
    | false => ErrorFormat.humanReadable
  let fix := args.hasFlag "fix"
  
  let mut allModuleNames := #[]
  for s in ["ArkLib.lean"] do
    allModuleNames := allModuleNames.append (← findImports s)
  
  allModuleNames := allModuleNames.erase `Batteries
  let mut numberErrors ← lintModules allModuleNames style fix
  if ← checkInitImports then numberErrors := numberErrors + 1
  
  
  
  
  if args.hasFlag "fix" then
    return 0
  else return min numberErrors 125

abbrev sqrtRate [Fintype ι] (deg : ℕ) (domain : ι ↪ F) : ℝ≥0 :=
  (LinearCode.rate (ReedSolomon.code domain deg) : ℝ≥0).sqrt

alias fsChallengeOracle := srChallengeOracle

def coreInteractionOracleRbrKnowledgeError (j : (pSpecCoreInteraction 𝔽q β (ϑ := ϑ)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).ChallengeIdx) : ℝ≥0 :=
    Sum.elim
      (f := fun i => sumcheckFoldKnowledgeError 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
      (g := fun i => finalSumcheckKnowledgeError (L := L) i)
      (ChallengeIdx.sumEquiv.symm j)

let st0 := externalLinearLayer params state

private def f (x : ℚ) : ℚ := x^2 - x

def Extractor.Straightline.compatWit
    (lens : Extractor.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut)
    (E : Extractor.Straightline oSpec InnerStmtIn InnerWitIn InnerWitOut pSpec) :
      OuterStmtIn × OuterWitOut → InnerWitIn → Prop :=
  fun ⟨outerStmtIn, outerWitOut⟩ innerWitIn =>
    ∃ stmt tr logP logV, innerWitIn ∈
      (E stmt (lens.wit.proj (outerStmtIn, outerWitOut)) tr logP logV).support

def minDist [DecidableEq F] (IC : MatrixSubmodule κ ι F) : ℕ :=
  sInf { d : ℕ | ∃ U ∈ IC, ∃ V ∈ IC, distCodewords U V = d }

def computableTwiddleFactor (i : Fin ℓ) (u : Fin (2 ^ (ℓ + R_rate - i - 1))) : L :=
  
  ∑ (⟨k, hk⟩: Fin (ℓ + R_rate - i - 1)),
  if Nat.getBit k u.val = 1 then
    
      
    (evalNormalizedWAt (β := β) (ℓ := ℓ) (R_rate := R_rate)
      (i := ⟨i, by admit /- proof elided -/
      ⟩) (x := β ⟨i + 1 + k, by admit /- proof elided -/
      ⟩))
  else 0

def rdrop (m : ℕ) (h : m ≤ n) (pSpec : ProtocolSpec n) : ProtocolSpec (n - m) :=
  {dir := Fin.rdrop m h pSpec.dir, «Type» := Fin.rdrop m h pSpec.«Type»}

@[inline, reducible]
def lift : OuterStmtIn × OuterWitIn → InnerStmtOut × InnerWitOut → OuterWitOut :=
  lens.toFunB

def eval₂ (p : MlPoly R n) (f : R →+* S) (x : Vector S n) : S := eval (map f p) x

Vector in Init.Data.Vector.Basic

hℓ_bound : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    Fintype.card (Gen_α i j).parℓ = 2
  hℓ_bound' : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    Fintype.card (parℓ_type i j) = 2

instance domain_neg_inst {i : Fin n} : Neg (evalDomain D i.1) where
  neg := fun x => ⟨_, minus_one_in_doms D i.2⟩ * x

def MessageIdx.inr (i : MessageIdx pSpec₂) : MessageIdx (pSpec₁ ++ₚ pSpec₂) :=
  ⟨Fin.natAdd m i.1, by admit /- proof elided -/
  ⟩

def whirRelation
    {F : Type} [Field F] [Fintype F] [DecidableEq F]
    {ι : Type} [Fintype ι] [Nonempty ι]
    (varCount : ℕ) (φ : ι ↪ F) [Smooth φ] (err : ℝ)
    : Set ((Unit × ∀ i, (OracleStatement ι F i)) × Unit) :=
  { ⟨⟨_, oracle⟩, _⟩ | δᵣ(oracle (), smoothCode φ varCount) ≤ err }

ENat in Mathlib.Data.ENat.Defs

@[reducible, inline, specialize]
def FullTranscript (pSpec : ProtocolSpec n) := (i : Fin n) → pSpec.«Type» i

φ : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), (indexPowT (S i) (P.φ i) j) ↪ F

def churchFalse : ChurchBool α := fun _ y => y

class DCast₂ (α : Sort*) (β : α → Sort*) (γ : (a : α) → β a → Sort*) [DCast α β] where
  dcast₂ : ∀ {a a' : α} {b : β a} {b' : β a'},
    (ha : a = a') → (dcast ha b = b') → γ a b → γ a' b'
  dcast₂_id : ∀ {a : α} {b : β a}, dcast₂ (Eq.refl a) dcast_eq = (id : γ a b → γ a b)

@[reducible]
def CanonicalSpongeState (U : Type) [SpongeUnit U] [SpongeSize] : Type :=
  Vector U SpongeSize.N

def totalNumPermQueries : Nat :=
  pSpec.totalNumPermQueriesMessage + pSpec.totalNumPermQueriesChallenge

@[reducible, inline, specialize, simp]
def ChallengeIdx (vPSpec : VectorSpec n) := {i : Fin n // vPSpec.dir i = .V_to_P}

@[simp]
abbrev Witness.AfterFirstChallenge : Type := Unit

Multiset.filter in Mathlib.Data.Multiset.Filter

lift_complete : ∀ outerStmtIn outerWitIn innerStmtOut innerWitOut,
    compat (outerStmtIn, outerWitIn) (innerStmtOut, innerWitOut) →
    (outerStmtIn, outerWitIn) ∈ outerRelIn →
    (innerStmtOut, innerWitOut) ∈ innerRelOut →
    (lens.stmt.lift outerStmtIn innerStmtOut,
    lens.wit.lift (outerStmtIn, outerWitIn) (innerStmtOut, innerWitOut)) ∈ outerRelOut

def fappend {A : Sort u} {F : A → Sort v} {m n : ℕ} {α : Fin m → A} {β : Fin n → A}
    (u : (i : Fin m) → F (α i)) (v : (i : Fin n) → F (β i)) :
    (i : Fin (m + n)) → F (Fin.vappend α β i) :=
  match n with
  | 0 => u
  | k + 1 => fconcat (fappend u (fun i => v (Fin.castSucc i))) (v (Fin.last k))

instance : IsEmpty (OracleQuery []ₒ α) where
  false := by admit /- proof elided -/

abbrev ScalarField := ZMod scalarFieldSize

Finset.Ici in Mathlib.Order.Interval.Finset.Defs

Set.PairwiseDisjoint in Mathlib.Data.Set.Pairwise.Basic

def listOfCloseCodewordsRel (C : Code ι F) (y : ι → F) (r : ℝ) : ℕ :=
  Nat.card (relHammingBall C y r)

def add {k : ℕ} (x y : ConcreteBTField k) : ConcreteBTField k := BitVec.xor x y

noncomputable def foldNth (n : ℕ) (f : 𝔽[X]) (α : 𝔽) [inst : NeZero n] : 𝔽[X] :=
  ∑ i : Fin n, Polynomial.C α ^ i.1 * splitNth f n i

let fiberwise_disagreements := fiberwiseDisagreementSet 𝔽q β i steps h_i_add_steps
      f_i f_bar_i
    let folded_disagreements := disagreementSet 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i steps
      h_i_add_steps folded_f_i folded_f_bar_i
    
    ¬ (fiberwise_disagreements ⊆ folded_disagreements)
  else
    
    
    
    let folded_f_i := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (steps := ⟨steps, by admit /- proof elided -/
      ⟩) (i := ⟨i, by admit /- proof elided -/
      ⟩)
      (h_i_add_steps := by admit /- proof elided -/
      ) f_i challenges
    let dist_to_code := distFromCode folded_f_i
      (BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i + steps, by admit /- proof elided -/
      ⟩)
    2 * dist_to_code < (d_i_plus_steps : ℕ∞)

MvPolynomial.sumToIter in Mathlib.Algebra.MvPolynomial.Equiv

@[inline]
def ofInputOnly
    (liftWit : OuterStmtIn × OuterWitOut → InnerWitIn → OuterWitIn) :
    Witness.InvLens OuterStmtIn OuterWitIn OuterWitOut InnerWitIn OuterWitOut :=
  ⟨Prod.snd, liftWit⟩

Matrix.rank in Mathlib.LinearAlgebra.Matrix.Rank

instance : DFunEquiv (∀ a : α, β a) α β where
  equiv := Equiv.refl _

noncomputable def finalSumcheckOracleReduction :
  OracleReduction
    (oSpec := []ₒ)
    (StmtIn := Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ))
    (OStmtIn := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ))
    (StmtOut := FinalSumcheckStatementOut (L := L) (ℓ := ℓ))
    (OStmtOut := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (WitOut := Unit)
    (pSpec := pSpecFinalSumcheckStep (L := L)) where
  prover := finalSumcheckProver 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
  verifier := finalSumcheckVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)

def extract (start stop : ℕ) (h1 : start ≤ stop) (h2 : stop ≤ n) (pSpec : ProtocolSpec n) :
    ProtocolSpec (stop - start) where
  dir := Fin.extract start stop h1 h2 pSpec.dir
  «Type» := Fin.extract start stop h1 h2 pSpec.«Type»

private def toWeightAssignment
  (p : MvPolynomial (Fin m) F)
  (b : Fin m → Fin 2) : Fin (m+1) → F :=
    let b' : Fin m → F := fun i => ↑(b i : ℕ)
    Fin.cases (MvPolynomial.eval b' p)
              (fun i => ↑(b i : ℕ))

def InternalData.EquivIndexFun {α : Type} (s : Skeleton) :
    InternalData α s ≃ (SkeletonInternalIndex s → α) where
  toFun := fun tree idx => tree.get idx
  invFun := fun f => InternalData.ofFun s f
  left_inv := by admit /- proof elided -/

noncomputable def foldOracleProver (i : Fin ℓ) :
  OracleProver (oSpec := []ₒ)
    
    (StmtIn := Statement (L := L) Context i.castSucc)
    (OStmtIn := OracleStatement 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc)
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ := ℓ) i.castSucc)
    
    (StmtOut := Statement (L := L) Context i.succ)
    (OStmtOut := OracleStatement 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ := ℓ) i.succ)
    (pSpec := pSpecFold (L := L)) where

sendMessage 
  | ⟨0, _⟩ => fun inputPrvState => by admit /- proof elided -/
  | ⟨0, h⟩ => nomatch h

@[simp]
abbrev SecondSumcheckChallenge : Type := Fin pp.ℓ_n → R

@[simp]
def innerRelIn_Test : Set (InnerStmtIn_Test × Unit) :=
  setOf (fun ⟨⟨f, t⟩, _⟩ => ∑ x ∈ {0, 1}, f.eval x = t)

def rbrSoundness
    (langIn : Set (StmtIn × ∀ i, OStmtIn i))
    (langOut : Set (StmtOut × ∀ i, OStmtOut i))
    (verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec)
    (rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  verifier.toVerifier.rbrSoundness init impl langIn langOut rbrSoundnessError

@[simp]
instance BTField_Fintype (k : ℕ) : Fintype (BTField k) := (BinaryTowerAux k).2.instFintype

input := fun ⟨⟨_, oStmt⟩, _⟩ => oStmt ()

C : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Set ((indexPowT (S i) (P.φ i) j) → F)
  hcode : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), (C i j) = (Gen_α i j).C

example : (1 : ℕ) ::ʰ (Fin.dempty : (i : Fin 0) → Fin.vempty i) =
  (!h[(1 : ℕ)] : (i : Fin 1) → !v[ℕ] i) := rfl

Multiset.ofList in Mathlib.Data.Multiset.Defs

Fintype.elems in Mathlib.Data.Fintype.Defs

sumcheckFinalCheck ∧ finalFoldingProp

def absorbFast (sponge : DuplexSponge U C) (arr : Array U) :
    OracleComp (forwardPermutationOracle C) (DuplexSponge U C) := do
  
  let sponge1 := { sponge with squeezePos := Fin.last SpongeSize.R }
  
  
  if hEmpty : arr.isEmpty then
    return sponge1
  else
    
    
    if hFull : sponge.absorbPos = SpongeSize.R then do
      
      have : 0 < sponge.absorbPos := by admit /- proof elided -/

hammingDist in Mathlib.InformationTheory.Hamming

instance instTestLensComplete : testLens.IsComplete
      outerRelIn_Test innerRelIn_Test outerRelOut_Test innerRelOut_Test
      (fun ⟨⟨p, q, _⟩, _⟩ ⟨⟨f, _⟩, _⟩ => p * q = f) where
  proj_complete := fun ⟨p, q, t⟩ () hRelIn => by admit /- proof elided -/

def rightpad {m : ℕ} {α : Sort*} (n : ℕ) (a : α) (v : Fin m → α) : Fin n → α :=
  fun i => if h : i < m then v ⟨i, h⟩ else a

abbrev Bwd : PermuteDir := Sum.inr ()

noncomputable def commitOracleVerifier (i : Fin ℓ) (hCR : isCommitmentRound ℓ ϑ i) :
  OracleVerifier
    (oSpec := []ₒ)
    (StmtIn := Statement (L := L) Context i.succ)
    (OStmtIn := OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc)
    (Oₘ := fun i => by admit /- proof elided -/
    )
    
    (StmtOut := Statement (L := L) Context i.succ)
    (OStmtOut := OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (pSpec := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) where

exp : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), (parℓ_type i j) ↪ ℕ

instance : Unique (ProtocolSpec 0) where
  default := empty
  uniq := fun ⟨_, _⟩ => by admit /- proof elided -/

instance : ∀ i, VCVCompatible ((default : ProtocolSpec 0).Challenge i) := fun ⟨i, _⟩ => Fin.elim0 i

def FullData.Equiv {α} (s : Skeleton) :
    FullData α s ≃ InternalData α s × LeafData α s :=

List.foldr in Init.Data.List.Basic

HMod in Init.Prelude

ToString in Init.Data.ToString.Basic

instance [ProverFirst pSpec] [h : OracleInterface (pSpec.«Type» 0)] :
    ∀ i, OracleInterface (pSpec.Message i)
  | ⟨0, _⟩ => inferInstance

instance [Oₘ : ∀ i, OracleInterface (pSpec.Message i)] :
    ∀ i, OracleInterface ((pSpec.addSalt Salt).Message i) :=
  fun i => {
    Query := (Oₘ i).Query
    Response := (Oₘ i).Response
    answer := fun msg => (Oₘ i).answer (by admit /- proof elided -/
      )
  }

Finite in Mathlib.Data.Finite.Defs

noncomputable def generateOpening [Fact (Nat.Prime p)] (srs : Vector G₁ (n + 1))
    (coeffs : Fin (n + 1) → ZMod p) (z : ZMod p) : G₁ :=
  letI poly : degreeLT (ZMod p) (n + 1) := (degreeLTEquiv (ZMod p) (n + 1)).invFun coeffs
  letI q : degreeLT (ZMod p) (n + 1) :=
    ⟨Polynomial.div (poly.val - C (poly.val.eval z)) (X - C z), by admit /- proof elided -/
      ⟩
  commit srs (degreeLTEquiv (ZMod p) (n + 1) q)

def OracleReduction.toReduction {ι : Type} {oSpec : OracleSpec ι}
    {StmtIn : Type} {ιₛᵢ : Type} {OStmtIn : ιₛᵢ → Type} {WitIn : Type}
    {StmtOut : Type} {ιₛₒ : Type} {OStmtOut : ιₛₒ → Type} {WitOut : Type}
    {n : ℕ} {pSpec : ProtocolSpec n}
    [Oₛᵢ : ∀ i, OracleInterface (OStmtIn i)] [Oₘ : ∀ i, OracleInterface (pSpec.Message i)]
    (oracleReduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) :
      Reduction oSpec (StmtIn × (∀ i, OStmtIn i)) WitIn
        (StmtOut × (∀ i, OStmtOut i)) WitOut pSpec :=
  ⟨oracleReduction.prover, oracleReduction.verifier.toVerifier⟩

instance (k : ℕ) : Fintype (ConcreteBTField k) := (getBTFResult k).instFintype

@[reducible, simp]
def rbrKnowledgeSoundness (relation : Set (Statement × Bool))
    (verifier : Verifier oSpec Statement Bool pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  verifier.rbrKnowledgeSoundness init impl relation acceptRejectRel rbrKnowledgeError

class HasSize (α : Type*) (β : Type*) where
  size : Nat
  toFun : α ↪ Vector β size

PowerBasis in Mathlib.RingTheory.PowerBasis

def divSum {m : ℕ} {n : Fin m → ℕ} (k : Fin (∑ j, n j)) : Fin m :=
  (divSum? n k).get (divSum?_is_some_iff_lt_sum.mpr k.isLt)

def queryCodeword (j : Fin (toOutCodewordsCount ℓ ϑ (Fin.last ℓ)))
    (point : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨j.val * ϑ,
      by admit /- proof elided -/
          ⟩) :
  OracleComp ([OracleStatement 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (
  Fin.last ℓ)]ₒ) L :=
      OracleComp.lift <| by
        simpa using
          OracleSpec.query
            (spec := [OracleStatement 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ)]ₒ)
            ⟨j, by admit /- proof elided -/
            ⟩
            (by admit /- proof elided -/
            )

def finSuccEquivNth : MvPolynomial (Fin (n + 1)) R ≃ₐ[R] Polynomial (MvPolynomial (Fin n) R) :=
  (renameEquiv R (_root_.finSuccEquiv' p)).trans (optionEquivLeft R (Fin n))

Fin.cast in Init.Data.Fin.Basic

Infinite in Mathlib.Data.Finite.Defs

def fflatten₂ {A : Sort u} {B : Sort v} {F : A → B → Sort w} {m : ℕ} {n : Fin m → ℕ}
    {α : (i : Fin m) → (j : Fin (n i)) → A} {β : (i : Fin m) → (j : Fin (n i)) → B}
    (v : (i : Fin m) → (j : Fin (n i)) → F (α i j) (β i j)) :
    (k : Fin (vsum n)) → F (Fin.vflatten α k) (Fin.vflatten β k) :=
  match m with
  | 0 => !h[]
  | _ + 1 => fappend₂ (v 0) (fflatten₂ (fun i => v i.succ))

if d = n then
    return none
  else
    return some d

structure Size where
  m : ℕ 
  n : ℕ 
  n_w : ℕ 
  n_w_le_n : n_w ≤ n := by admit /- proof elided -/

@[inline]
def zsmul [SMul ℤ R] (m : ℤ) (p : MlPoly R n) : MlPoly R n := p.map (fun a => m • a)

OracleSpec.domain in VCVio.OracleComp.OracleSpec

Matrix.cRank in Mathlib.LinearAlgebra.Matrix.Rank

instance instST₁ : ∀ i, SelectableType ((⟨!v[.P_to_V], !v[R⦃≤ deg⦄[X]]⟩ ++ₚ !p[]).Challenge i) :=
  instSelectableTypeChallengeAppend

toFun in ToMathlib.Control.Monad.Hom

def correlatedAgreement (C : Set (n → F)) (δ : ℝ≥0) {k : ℕ} (W : Fin k → n → F) : Prop :=
  ∃ S : Finset n, #(S) ≥ (1 - δ) * (Fintype.card n) ∧
    ∃ v : Fin k → n → F, ∀ i, v i ∈ C ∧ {j | v i j = W i j} = S

Module.Basis.smulTower in Mathlib.RingTheory.AlgebraTower

message in Examples.FrankingProtocol

@[reducible]
def duplexSpongeChallengeOracle (StartType : Type) (U : Type) [SpongeUnit U] [SpongeSize] :
    OracleSpec (Unit ⊕ PermuteDir) :=
  (StartType →ₒ Vector U SpongeSize.C) ++ₒ permutationOracle (CanonicalSpongeState U)

def perfectCompleteness
    (relIn : Set ((StmtIn × ∀ i, OStmtIn i) × WitIn))
    (relOut : Set ((StmtOut × ∀ i, OStmtOut i) × WitOut))
    (oracleReduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) :
      Prop :=
  Reduction.perfectCompleteness init impl relIn relOut oracleReduction.toReduction

Fin.pred in Init.Data.Fin.Basic

def rbrKnowledgeSoundness
    (relIn : Set ((Statement × ∀ i, OStatement i) × Witness))
    (verifier : OracleVerifier oSpec Statement OStatement Bool (fun _ : Empty => Unit) pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  verifier.rbrKnowledgeSoundness init impl relIn acceptRejectOracleRel rbrKnowledgeError

noncomputable def polyFold
  [DecidableEq F] (fPoly : Polynomial F)
  (k : ℕ) (hk0 : 0 < k) (hkfin : k < Fintype.card F)
  (r : F) : Polynomial F :=
    let qPoly : Polynomial F := Polynomial.X ^ k
    let hdeg_q_min : qPoly.natDegree > 0 := sorry
    let hdeg_q_max : qPoly.natDegree < Fintype.card F := sorry
  
    let Q : MvPolynomial (Fin 2) F := polyQ fPoly qPoly
    MvPolynomial.eval₂Hom
      (Polynomial.C : F →+* Polynomial F)
      (fun i : Fin 2 => if i = 0 then Polynomial.X else Polynomial.C r) Q

def foldStepRelOut (i : Fin ℓ) :
    Set ((Statement (L := L) Context i.succ ×
      (∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j)) ×
      Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ) :=
  { input | foldStepRelOutProp (mp := mp) (𝓑 := 𝓑) 𝔽q β i input}

noncomputable def finalSumcheckRbrExtractor :
  Extractor.RoundByRound []ₒ
    (StmtIn := (Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ)) × (∀ j, OracleStatement 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ  (Fin.last ℓ) j))
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ))
    (WitOut := Unit)
    (pSpec := pSpecFinalSumcheckStep (L := L))
    (WitMid := FinalSumcheckWit (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ := ℓ)) where
  eqIn := rfl
  extractMid := fun m ⟨stmtMid, oStmtMid⟩ trSucc witMidSucc => by admit /- proof elided -/
    | none => 
      exact dummyLastWitness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    | some tpoly =>
      
      exact {
        t := tpoly,
        H := projectToMidSumcheckPoly (L := L) (ℓ := ℓ) (t := tpoly)
          (m := BBF_SumcheckMultiplierParam.multpoly stmtMid.ctx)
          (i := Fin.last ℓ) (challenges := stmtMid.challenges),
        f := getMidCodewords 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) tpoly stmtMid.challenges
      }
  extractOut := fun ⟨stmtIn, oStmtIn⟩ tr witOut => ()

@[inline, reducible]
protected def id :
    Witness.Lens OuterStmtIn OuterStmtOut OuterWitIn OuterWitOut OuterWitIn OuterWitOut :=
  ⟨Prod.snd, fun _ => Prod.snd⟩

instance {k : ℕ} : IntCast (ConcreteBTField k) where
  intCast n:= intCast n

Set in Mathlib.Data.Set.Defs

Pow in Init.Prelude

@[inline] def zero : AssocNat :=
  ⟨id, by admit /- proof elided -/
  ⟩

Sum.isRight in Init.Data.Sum.Basic
</all_available_defs>

<all_available_lemmas>
Fintype.card_pos in Mathlib.Data.Fintype.Card
Polynomial.C_1 in Mathlib.Algebra.Polynomial.Basic
Polynomial.C_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.C_mul in Mathlib.Algebra.Polynomial.Basic
Polynomial.C_pow in Mathlib.Algebra.Polynomial.Basic
Polynomial.X_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.comp_X in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.mul_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.prod_comp in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.sub_comp in Mathlib.Algebra.Polynomial.Eval.Defs
inv_eq_one_div in Mathlib.Algebra.Group.Defs
map_pow in Mathlib.Algebra.Group.Hom.Defs
mul_assoc in Mathlib.Algebra.Group.Defs
mul_comm in Mathlib.Algebra.Group.Defs
mul_inv_cancel₀ in Mathlib.Algebra.GroupWithZero.Defs
mul_one in Mathlib.Algebra.Group.Defs
mul_pow in Mathlib.Algebra.Group.Basic
mul_pow_sub_one in Mathlib.Algebra.Group.Basic
mul_sub in Mathlib.Algebra.Ring.Defs
one_div in Mathlib.Algebra.Group.Defs
one_mul in Mathlib.Algebra.Group.Defs
one_pow in Mathlib.Algebra.Group.Defs
Fin.eta in Init.Data.Fin.Lemmas
Fin.mk_eq_mk in Mathlib.Data.Fin.Basic
Nat.succ_eq_add_one in Init.Data.Nat.Basic
Polynomial.eval_X in Mathlib.Algebra.Polynomial.Eval.Defs
div_one in Mathlib.Algebra.Group.Basic
Fin.coe_cast in Init.Data.Fin.Lemmas
Fin.coe_castSucc in Init.Data.Fin.Lemmas
Fin.coe_ofNat_eq_mod in Mathlib.Data.Fin.Basic
Fin.foldl_succ_last in Init.Data.Fin.Fold
Fin.foldl_zero in Init.Data.Fin.Fold
Fin.val_last in Init.Data.Fin.Lemmas
Nat.zero_mod in Init.Data.Nat.Div.Basic
nonpos_iff_eq_zero in Mathlib.Algebra.Order.Monoid.Canonical.Defs
not_lt in Mathlib.Order.Defs.LinearOrder
tsub_zero in Mathlib.Algebra.Order.Sub.Defs
Fin.mk_zero' in Mathlib.Data.Fin.Basic
zero_add in Mathlib.Algebra.Group.Defs
Fin.val_zero in Init.Data.Fin.Lemmas
Nat.sub_zero in Init.Data.Nat.Basic
Fin.cast_zero in Init.Data.Fin.Lemmas
Fin.prod_congr' in Mathlib.Algebra.BigOperators.Fin
Fin.prod_univ_zero in Mathlib.Algebra.BigOperators.Fin
Fin.sum_congr' in Mathlib.Algebra.BigOperators.Fin
Fin.sum_univ_one in Mathlib.Algebra.BigOperators.Fin
Nat.lt_one_iff in Init.Data.Nat.Basic
Nat.lt_two_pow_self in Init.Data.Nat.Lemmas
Nat.zero_or in Init.Data.Nat.Bitwise.Lemmas
Nat.zero_shiftLeft in Init.Data.Nat.Lemmas
Polynomial.eval_C in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.eval_mul in Mathlib.Algebra.Polynomial.Eval.Defs
Polynomial.eval_one in Mathlib.Algebra.Polynomial.Eval.Defs
pow_zero in Mathlib.Algebra.Group.Defs
tsub_self in Mathlib.Algebra.Order.Sub.Basic

lemma Xⱼ_zero_eq_one (ℓ : ℕ) (h_ℓ : ℓ ≤ r) :
  Xⱼ 𝔽q β ℓ h_ℓ ⟨0, by exact Nat.two_pow_pos ℓ⟩ = 1

omit hF₂ in
theorem W_linear_comp_decomposition (i : Fin r) (h_i_add_1 : i + 1 < r) :
    ∀ p: L[X], (W 𝔽q β (i + 1)).comp p =
      ((W 𝔽q β i).comp p) ^ Fintype.card 𝔽q -
        C (eval (β i) (W 𝔽q β i)) ^ (Fintype.card 𝔽q - 1) * ((W 𝔽q β i).comp p)

theorem W_linearity (i : Fin r)
    : IsLinearMap 𝔽q (f := fun inner_p ↦ (W 𝔽q β i).comp inner_p)

omit hF₂ in
lemma inductive_linear_map_W (i : Fin r) (h_i_add_1 : i + 1 < r)
    (h_prev_linear_map : IsLinearMap 𝔽q (f := fun inner_p ↦ (W 𝔽q β i).comp inner_p))
    : IsLinearMap 𝔽q (f := fun inner_p ↦ (W 𝔽q β (i + 1)).comp inner_p)

omit h_Fq_char_prime hF₂ in
lemma inductive_rec_form_W_comp (i : Fin r) (h_i_add_1 : i + 1 < r)
    (h_prev_linear_map : IsLinearMap (R := 𝔽q) (M := L[X]) (M₂ := L[X])
      (f := fun inner_p ↦ (W 𝔽q β i).comp inner_p))
    : ∀ p: L[X], (W 𝔽q β (i + 1)).comp p =
      ((W 𝔽q β i).comp p) ^ Fintype.card 𝔽q -
        C (eval (β i) (W 𝔽q β i)) ^ (Fintype.card 𝔽q - 1) * ((W 𝔽q β i).comp p)

lemma Wᵢ_eval_βᵢ_neq_zero
    (i : Fin r): (W 𝔽q β i).eval (β i) ≠ 0

lemma βᵢ_not_in_Uᵢ (i : Fin r) :
    β i ∉ U 𝔽q β i

lemma W_prod_comp_decomposition
    (i : Fin r) (hi : i > 0) :
    (W 𝔽q β i) = ∏ c: 𝔽q, (W 𝔽q β (i-1)).comp (X - C (c • β (i-1)))

lemma W_splits (i : Fin r) : (W 𝔽q β i).Splits (RingHom.id L)

omit h_Fq_char_prime hF₂ in
lemma rootMultiplicity_prod_W_comp_X_sub_C
    (i : Fin r) (h_i_add_1 : i + 1 < r) (a : L) :
    rootMultiplicity a ((univ : Finset 𝔽q).prod (fun c => (W 𝔽q β i).comp (X - C (c • β i)))) =
    if a ∈ (U 𝔽q β (i+1) : Set L) then 1 else 0

omit [DecidableEq L] h_Fq_char_prime hF₂ hβ_lin_indep in
lemma Prod_W_comp_X_sub_C_ne_zero (i : Fin r) :
    (univ : Finset 𝔽q).prod (fun c => (W 𝔽q β i).comp (X - C (c • β i))) ≠ 0

omit [DecidableEq L] [Fintype 𝔽q] hβ_lin_indep in
lemma W_ne_zero (i : Fin r) : (W 𝔽q β i) ≠ 0

lemma roots_comp_X_sub_C (p : L[X]) (a : L) :
    (p.comp (X - C a)).roots = p.roots.map (fun r => r + a)

lemma rootMultiplicity_comp_X_sub_C (p : L[X]) (a x : L) :
    rootMultiplicity x (p.comp (X - C a)) = rootMultiplicity (x - a) p

omit [Fintype L] [DecidableEq L] in
lemma comp_X_sub_C_eq_zero_iff (p : L[X]) (a : L) :
  p.comp (X - C a) = 0 ↔ p = 0

lemma rootMultiplicity_W (i : Fin r) (a : L) :
    rootMultiplicity a (W 𝔽q β i) = if a ∈ (U 𝔽q β i : Set L) then 1 else 0

lemma roots_W (i : Fin r) : -- converts root Multiset into (univ: Uᵢ.val.map)
  (W 𝔽q β i).roots = (univ : Finset (U 𝔽q β i)).val.map (fun u => u.val)

omit [Fintype L] [DecidableEq L] [Fintype 𝔽q] h_Fq_char_prime hβ_lin_indep in
theorem root_U_lift_up (i : Fin r) (h_i_add_1 : i + 1 < r) (a : L) (x : 𝔽q) :
  a - x • β i ∈ (U 𝔽q β i) → a ∈ (U 𝔽q β (i+1))

omit [Fintype L] [DecidableEq L] [Fintype 𝔽q] h_Fq_char_prime in
theorem root_U_lift_down
  (i : Fin r) (h_i_add_1 : i + 1 < r) (a : L) :
  a ∈ (U 𝔽q β (i+1)) → ∃! x: 𝔽q, a - x • β i ∈ (U 𝔽q β i)

lemma W_monic (i : Fin r) : (W 𝔽q β i).Monic

lemma comp_sub_C_of_linear_eval (p : L[X])
  (h_lin : IsLinearMap 𝔽q (f := fun inner_p ↦ p.comp inner_p)) (a : L) :
    p.comp (X - C a) = p - C (eval a p)

theorem prod_poly_sub_C_eq_poly_pow_card_sub_poly_in_L
  (p : L[X]) :
  (∏ c ∈ (Finset.univ : Finset Fq), (p - Polynomial.C (algebraMap Fq L c))) =
    p^(Fintype.card Fq) - p

theorem prod_X_sub_C_eq_X_pow_card_sub_X_in_L :
  (∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C (algebraMap Fq L c))) =
    Polynomial.X^(Fintype.card Fq) - Polynomial.X

theorem prod_X_sub_C_eq_X_pow_card_sub_X :
  (∏ c ∈ (Finset.univ : Finset Fq), (Polynomial.X - Polynomial.C c)) =
    Polynomial.X^(Fintype.card Fq) - Polynomial.X

omit [DecidableEq L] [Fintype 𝔽q] hβ_lin_indep in
lemma W₀_eq_X : W 𝔽q β 0 = X

lemma Fin.val_add_one' (a : Fin r) (h_a_add_1 : a + 1 < r) : (a + 1).val = a.val + 1

lemma getLowBits_eq_mod_two_pow {numLowBits : ℕ} (n : ℕ) :
  getLowBits numLowBits n = n % (2 ^ numLowBits)

lemma getLowBits_lt_two_pow {n : ℕ} (numLowBits : ℕ) :
    getLowBits numLowBits n < 2 ^ numLowBits

theorem unique_linear_sum_repr (R : Type*) [CommRing R] (S : Type*) [CommRing S] [Algebra R S]
    (pb : PowerBasis R S) (h_dim : pb.dim = 2) (s : S) :
    ∃! p : R × R, s = p.fst • pb.gen + algebraMap R S p.snd

lemma gamma_eq_P
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
  γ' x₀ (R k δ x₀ h_gs) (irreducible_H k (x₀ := x₀) (δ := δ) h_gs) =
  AppendixA.polyToPowerSeries𝕃 _ 
    (P k δ x₀ h_gs)

lemma guruswami_sudan_for_proximity_gap_existence {k m : ℕ} {ωs : Fin n ↪ F} {f : Fin n → F} :
  ∃ Q, Condition (k + 1) m ((proximity_gap_degree_bound ((k + 1 : ℚ) / n) m n)) ωs f Q

theorem bitsToU_bijective (i : Fin r) :
  Function.Bijective (bitsToU (𝔽q := 𝔽q) (β := β) (ℓ := ℓ) (R_rate := R_rate) i)

NeZero.ne in Init.Data.NeZero

theorem vext_iff {v w : Fin n → α} : v = w ↔ ∀ i, v i = w i

@[simp] lemma twoAdicGenerators_succ_square_eq' (idx : Fin twoAdicity) :
    twoAdicGenerators[idx.val + 1] ^ 2 = twoAdicGenerators[idx]

lemma coeff_polynomialOfCoeffs_eq_coeffs' :
  (polynomialOfCoeffs coeffs).coeff = fun x ↦ if h : x < deg then coeffs ⟨x, h⟩ else 0

theorem toNatInRange {k : ℕ} (b : ConcreteBTField k) :
  BitVec.toNat b ≤ 2 ^ (2 ^ k) * 1

omit hF₂ in
theorem kernel_normalizedW_eq_U (i : Fin r) :
    LinearMap.ker (polyEvalLinearMap (normalizedW 𝔽q β i)
    (normalizedW_is_additive 𝔽q β i))
    = U 𝔽q β i

omit [Finite F] in
lemma minus_one_in_doms {i : ℕ} (h : i < n) :
    -1 ∈ evalDomain D i

theorem rtake_eq_take_rev {α : Sort*} (m : ℕ) (h : m ≤ n) (v : Fin n → α) :
    rtake m h v = (take m h (v ∘ Fin.rev)) ∘ Fin.rev

theorem canonical_iff [LawfulBEq R] {p : UniPoly R} :
   p.trim = p ↔ ∀ hp : p.size > 0, p.getLast hp ≠ 0

lemma split_join_via_add_smul_eq_iff_split {k : ℕ} (h_pos : k > 0)
    (hi_btf lo_btf : ConcreteBTField (k - 1)) :
    split (k:=k) (h:=by omega) (x:=join_via_add_smul (k:=k) (h_pos:=h_pos) hi_btf lo_btf) =
      (hi_btf, lo_btf)

@[simp]
lemma length_getTypes (l : HList) : l.getTypes.length = l.length

theorem snoc_ne_zero_iff : snoc s y ≠ 0 ↔ s ≠ 0 ∨ y ≠ 0

theorem BitVec.dcast_bitvec_eq_zero {l r : ℕ} (h_width_eq : l = r) :
  dcast (h_width_eq) 0#(l) = 0#(r)

theorem eval_toImpl_eq_eval [LawfulBEq R] (x : R) (p : R[X]) : p.toImpl.eval x = p.eval x

omit [(i : ιₛ) → OracleInterface (OStatement i)] [OracleInterface Witness] in
theorem oracleProver_run {stmt : Statement} {oStmt : ∀ i, OStatement i} {wit : Witness} :
    (oracleProver oSpec Statement OStatement Witness).run ⟨stmt, oStmt⟩ wit =
      pure (fun i => by aesop, ⟨stmt, Sum.rec oStmt (fun _ => wit)⟩, ())

@[simp]
theorem leftpad_apply_lt (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : i.val < n - m) : leftpad n a v i = a

@[simp]
theorem erase_even_mem
  {s : Finset ℕ}
  {n : ℕ}
  : n ∈ (erase_even s) ↔ Odd n ∧ n ∈ s

theorem cast_Type_idx_symm {hn} (hSpec : pSpec₁.cast hn = pSpec₂) {i : Fin n₂} :
    pSpec₁.«Type» (Fin.cast hn.symm i) = pSpec₂.«Type» i

private lemma johnson_denom [Zero F]
  (h_card : 2 ≤ (Fintype.card F))
  :
  (Fintype.card F / (Fintype.card F - 1)) *
  ((1 - e B 0 / n) ^ 2  + (e B 0) ^ 2 / ((Fintype.card F - 1) * n^2) - 1 + d B/n)
  =
  (1 - ((Fintype.card F) / (Fintype.card F - 1)) *
  (e B 0 / n)) ^ 2 - (1 - ((Fintype.card F) / (Fintype.card F - 1)) * (d B/n))

@[simp]
lemma bIdx_mul_ϑ_add_i_cast_lt_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) (i : Fin (ϑ - 1 + 1))
    : ↑bIdx * ϑ + i < ℓ + 1

theorem computableNTTStage_eq_NTTStage (i : Fin ℓ) :
  computableNTTStage (𝔽q := 𝔽q) (r := r) (L := L) (ℓ := ℓ) (β := β) (R_rate := R_rate)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := ⟨i, by omega⟩) =
  NTTStage (𝔽q := 𝔽q) (L := L) (β := β) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    (i := ⟨i, by omega⟩)

theorem mem_restrictDegree_iff_degreeOf_le (p : MvPolynomial σ R) (n : ℕ) :
    p ∈ restrictDegree σ R n ↔ ∀ i, p.degreeOf i ≤ n

lemma mem_image_support_coeff_finSuccEquivNth {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} {x} :
    x ∈ Finsupp.insertNth p i '' ((finSuccEquivNth R p f).coeff i).support ↔
      x ∈ f.support ∧ x p = i

theorem range_vcons {α : Type*} (a : α) (v : Fin n → α) :
    Set.range (a ::ᵛ v) = insert a (Set.range v)

@[simp]
theorem vcons_empty (a : α) : a ::ᵛ !v[] = !v[a]

@[simp]
lemma oddPart_by_2 :
    2 * (oddPart f) = (f - f.comp (-X)) /ₘ X

theorem functional_completeness (α : Type) {s : Skeleton}
  (idx : SkeletonLeafIndex s)
  (leaf_data_tree : LeafData α s)
  (hash : α → α → α) :
  (getPutativeRoot_with_hash
    idx
    (leaf_data_tree.get idx)
    (generateProof
      (buildMerkleTree_with_hash leaf_data_tree hash) idx)
    (hash)) =
  (buildMerkleTree_with_hash leaf_data_tree hash).getRootValue

@[simp]
theorem dist_le_card (C : Set (n → R)) : dist C ≤ Fintype.card n

theorem add_coeff? (p q : UniPoly Q) (i : ℕ) :
  (add_raw p q).coeff i = p.coeff i + q.coeff i

Nat.zero_le in Init.Prelude

theorem take_addCases'_left {n' : ℕ} {β : Fin n' → Sort u} (m : ℕ) (h : m ≤ n)
    (u : (i : Fin n) → α i) (v : (j : Fin n') → β j) (i : Fin m) :
    take m (Nat.le_add_right_of_le h) (addCases' u v) i =
      (append_left α β (castLE h i)) ▸ (take m h u i)

@[simp]
theorem ranges_length_eq_self_length {l : List ℕ} : l.ranges.length = l.length

@[simp]
lemma eval₂_C' {r : R} {S : Type w} [CommSemiring S] (f : R →+* S) (x : S) :
    eval₂ (P := P) f x (C r) = f r

omit [NeZero r] [Field L] [Fintype L] [DecidableEq L] [Field 𝔽q] [Algebra 𝔽q L] in
lemma sBasis_range_eq (i : Fin r) (h_i : i < ℓ + R_rate) :
    β '' Set.Ico i ⟨ℓ + R_rate, h_ℓ_add_R_rate⟩
    = Set.range (sBasis β h_ℓ_add_R_rate i h_i)

theorem SkeletonNodeIndex.rightChild_bind_parent {s : Skeleton}
    (idx : SkeletonNodeIndex s) :
    idx.rightChild >>= parent = idx.rightChild.map (fun _ => idx)

@[simp]
theorem fflatten₂_succ {A : Sort u} {B : Sort v} {F : A → B → Sort w} {m : ℕ} {n : Fin (m + 1) → ℕ}
    {α : (i : Fin (m + 1)) → (j : Fin (n i)) → A}
    {β : (i : Fin (m + 1)) → (j : Fin (n i)) → B}
    {v : (i : Fin (m + 1)) → (j : Fin (n i)) → F (α i j) (β i j)} :
    fflatten₂ v = fappend₂ (v 0) (fflatten₂ (fun i => v i.succ))

@[simp]
lemma probFailure_bind_eq_zero_iff [spec.FiniteRange]
    (oa : OracleComp spec α) (ob : α → OracleComp spec β) :
    [⊥ | oa >>= ob] = 0 ↔ [⊥ | oa] = 0 ∧ ∀ x ∈ oa.support, [⊥ | ob x] = 0

private lemma le_sum_choose_K [Zero F]
  (h_card : 2 ≤ (Fintype.card F)) :
  choose_2 (K B i 0) + (Fintype.card (α := F) - 1) *
  choose_2 ((B.card - K B i 0) / (Fintype.card (α := F) - 1)) ≤ sum_choose_K_i B i

theorem vappend_ext (u₁ u₂ : Fin m → α) (v₁ v₂ : Fin n → α) :
    vappend u₁ v₁ = vappend u₂ v₂ ↔ u₁ = u₂ ∧ v₁ = v₂

theorem peval_eq_eval_sumToIter_rename (f : σ → σ₁ ⊕ σ₂) (x : σ₁ → R) (p : MvPolynomial σ R) :
    peval f x p = eval (C ∘ x) (sumToIter R σ₁ σ₂ (rename f p))

theorem succ'_ne_zero (n : Nat) : succ' n ≠ 0

protected lemma elocPolyF_ne_zero {ωs f : Fin m → F} :
  ElocPolyF ωs f p ≠ 0

private lemma johnson_condition_strong_implies_2_le_B_card
  (h_johnson : JohnsonConditionStrong B v)
  :
  2 ≤ B.card

lemma oodSampling_crs_eq_rs
    {f : ι → F} {m s : ℕ} {φ : ι ↪ F} [Smooth φ]
    (l δ : ℝ≥0) (hδLe : δ ≤ 1)
    {C : Set (ι → F)} (hcode : C = smoothCode φ m ∧ listDecodable C δ l) :
    Pr_{ let rs ←$ᵖ (Fin s → F) }[ (∃ σ : Fin s → F,
                        let w : Fin s → MvPolynomial (Fin (m + 1)) F :=
                          fun i =>
                            let ri := rs i
                            let rVec := fun j : Fin m => ri ^ (2^(j : ℕ))
                            MvPolynomial.X (Fin.last m) * rename Fin.castSucc (eqPolynomial rVec)
                        let multiCRSCode := multiConstrainedCode φ m s w σ
                        ∃ u u' : ι → F, u ≠ u' ∧
                          u ∈ relHammingBall multiCRSCode f δ ∧
                          u' ∈ relHammingBall multiCRSCode f δ)]
    =
    Pr_{ let rs ←$ᵖ (Fin s → F) }[ (∃ u u' : smoothCode φ m,
                        u.val ≠ u'.val ∧
                        u.val ∈ relHammingBall C f δ ∧
                        u'.val ∈ relHammingBall C f δ ∧
                        ∀ i : Fin s,
                          let ri := rs i
                          let rVec := fun j : Fin m => ri ^ (2^(j : ℕ))
                          (mVdecode u).eval (rVec) = (mVdecode u').eval (rVec))]

@[simp]
lemma domain_def : (spec α).domain () = (α × α)

@[simp, grind] lemma N_pos : 0 < sz.N

theorem cast_symm {hn} (hSpec : pSpec₁.cast hn = pSpec₂) : pSpec₂.cast hn.symm = pSpec₁

theorem zero_add (hp : p.canonical) : 0 + p = p

@[simp]
theorem cons_toList_eq_List_cons {α} {n : ℕ} (hd : α) (tl : Vector α n) :
    (cons hd tl).toList = hd :: tl.toList

theorem towerAlgebraMap_succ_last (r : ℕ) : ∀ l : ℕ, (h_le : l ≤ r) →
  towerAlgebraMap (l:=l) (r:=r+1) (h_le:=by
    exact Nat.le_trans (n:=l) (m:=r) (k:=r+1) (h_le) (by omega)) =
  (towerAlgebraMap (l:=l+1) (r:=r+1) (by omega)).comp (towerAlgebraMap
    (l:=l) (r:=l+1) (by omega))

@[simp]
theorem LeafData.get_ofFun {α} {s} (f : SkeletonLeafIndex s → α) :
    (LeafData.ofFun s f).get = f

theorem vconcat_left_injective {n : ℕ} (a : α) :
    Function.Injective (fun v : Fin n → α => vconcat v a)

theorem append_knowledgeSoundness (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁)
    (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    {knowledgeError₁ knowledgeError₂ : ℝ≥0}
    (h₁ : V₁.knowledgeSoundness init impl rel₁ rel₂ knowledgeError₁)
    (h₂ : V₂.knowledgeSoundness init impl rel₂ rel₃ knowledgeError₂) :
      (V₁.append V₂).knowledgeSoundness init impl
        rel₁ rel₃ (knowledgeError₁ + knowledgeError₂)

Fin.append_right in Mathlib.Data.Fin.Tuple.Basic

@[simp]
theorem verifier_first (pSpec : ProtocolSpec n) [NeZero n] [h : VerifierFirst pSpec] :
    pSpec.dir 0 = .V_to_P

theorem ofFn_drop_eq_drop_ofFn {α : Type*} {m : ℕ} (h : m ≤ n) (v : Fin n → α) :
    List.ofFn (drop m h v) = (List.ofFn v).drop m

Nat.lt_of_le_of_lt in Init.Prelude

@[simp]
private lemma K_le_card {α : F} : K B i α ≤ B.card

omit [Finite F] in
lemma D_def : D = evalDomain D 0

theorem addCases_right' {motive : Fin (m + n) → Sort*}
    {left : (i : Fin m) → motive (castAdd n i)} {right : (j : Fin n) → motive (natAdd m j)}
    {i : Fin n} (j : Fin (m + n)) (h : j = natAdd m i) :
      addCases (motive := motive) left right j = h ▸ (right i)

theorem eq_of_equiv [LawfulBEq R] {p q : UniPoly R} : equiv p q → p.trim = q.trim

@[simp]
theorem vconcat_zero (a : α) : vconcat !v[] a = !v[a]
</all_available_lemmas>

<local_ctx>
import ArkLib.Data.FieldTheory.AdditiveNTT.NovelPolynomialBasis

import Mathlib.Tactic

import Mathlib.Data.Finsupp.Defs

import Mathlib.LinearAlgebra.LinearIndependent.Defs

open Polynomial AdditiveNTT Module

namespace AdditiveNTT

variable {r : ℕ} [NeZero r]

variable {L : Type u} [Field L] [Fintype L] [DecidableEq L]

variable (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q] [DecidableEq 𝔽q]
  [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [hF₂ : Fact (Fintype.card 𝔽q = 2)]

variable [Algebra 𝔽q L]

variable (β : Fin r → L) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)]
  [h_β₀_eq_1 : Fact (β 0 = 1)]

variable {ℓ R_rate : ℕ} (h_ℓ_add_R_rate : ℓ + R_rate < r)-- ℓ ∈ {1, ..., r-1}

section IntermediateStructures

noncomputable def qMap (i : Fin r) : L[X] :=
  let constMultiplier := ((W 𝔽q β i).eval (β i))^(Fintype.card 𝔽q)
    / ((W 𝔽q β (i + 1)).eval (β (i + 1)))
  C constMultiplier * ∏ c: 𝔽q, (X - C (algebraMap 𝔽q L c))

noncomputable def qCompositionChain (i : Fin r) : L[X] :=
  match i with
  | ⟨0, _⟩ => X
  | ⟨k + 1, h_k_add_1⟩ => (qMap 𝔽q β ⟨k, by admit /- proof elided -/
  ⟩).comp (qCompositionChain ⟨k, by admit /- proof elided -/
  ⟩)

noncomputable section DomainBijection

end DomainBijection

noncomputable def intermediateNormVpoly
    
    (i: Fin (ℓ+1)) (k : Fin (ℓ - i + 1)) : L[X] :=
  
  Fin.foldl (n:=k) (fun acc j =>
    (qMap 𝔽q β ⟨(i : ℕ) + (j : ℕ), by admit /- proof elided -/
    ⟩).comp acc) (X)

noncomputable def intermediateNovelBasisX (i : Fin (ℓ + 1)) (j : Fin (2 ^ (ℓ - i))) : L[X] :=
  (Finset.univ: Finset (Fin (ℓ - i)) ).prod (fun k =>
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate i (k:=⟨k, by admit /- proof elided -/
    ⟩)) ^ (Nat.getBit k j))

noncomputable def intermediateEvaluationPoly (i : Fin (ℓ + 1))
    (coeffs : Fin (2 ^ (ℓ - i)) → L) : L[X] :=
  ∑ (⟨j, hj⟩: Fin (2^(ℓ-i))), C (coeffs ⟨j, by admit /- proof elided -/
  ⟩) *
    (intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate i ⟨j, by admit /- proof elided -/
    ⟩)

end IntermediateStructures

section AlgorithmCorrectness

noncomputable def evaluationPointω (i : Fin (ℓ + 1))
    (x : Fin (2 ^ (ℓ + R_rate - i))) : L := 
    
  ∑ (⟨k, hk⟩: Fin (ℓ + R_rate - i)),
    if Nat.getBit k x.val = 1 then
      (normalizedW 𝔽q β ⟨i, by admit /- proof elided -/
      ⟩).eval (β ⟨i + k, by admit /- proof elided -/
      ⟩)
    else
      0

def tileCoeffs (a : Fin (2 ^ ℓ) → L) : Fin (2^(ℓ + R_rate)) → L :=
  fun v => a (Fin.mk (v.val % (2^ℓ)) (Nat.mod_lt v.val (pow_pos (zero_lt_two) ℓ)))

def coeffsBySuffix (a : Fin (2 ^ ℓ) → L) (i : Fin (ℓ + 1)) (v : Fin (2 ^ i.val)) :
  Fin (2 ^ (ℓ - i)) → L :=
  fun ⟨j, hj⟩ => by admit /- proof elided -/

def additiveNTTInvariant (evaluation_buffer : Fin (2 ^ (ℓ + R_rate)) → L)
    (original_coeffs : Fin (2 ^ ℓ) → L) (i : Fin (ℓ + 1)) : Prop :=
  ∀ (j : Fin (2^(ℓ + R_rate))),
    let u_b_v := j.val
    let v: Fin (2^i.val) := ⟨Nat.getLowBits i.val u_b_v, by admit /- proof elided -/
    ⟩ 
    let u_b := u_b_v / (2^i.val) 
    have h_u_b : u_b = u_b_v / (2^i.val) := by admit /- proof elided -/
</local_ctx>

<target_theorem>
omit [DecidableEq 𝔽q] hF₂ in
lemma initial_tiled_coeffs_correctness (h_ℓ : ℓ ≤ r) (a : Fin (2 ^ ℓ) → L) :
    let b: Fin (2^(ℓ + R_rate)) → L :=
</target_theorem>

