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
Algebra in Mathlib.Algebra.Algebra.Defs
Field in Mathlib.Algebra.Field.Defs
IsLinearMap in Mathlib.Algebra.Module.LinearMap.Defs
toFun in ToMathlib.Control.Monad.Hom
Submodule.map in Mathlib.Algebra.Module.Submodule.Map
Finset in Mathlib.Data.Finset.Defs
Finset.univ in Mathlib.Data.Fintype.Defs
Ne in Init.Core
NeZero in Init.Data.NeZero
Module.Basis in Mathlib.LinearAlgebra.Basis.Defs
Disjoint in Mathlib.Order.Disjoint
Fact in Mathlib.Logic.Basic
LinearEquiv in Mathlib.Algebra.Module.Equiv.Defs
LinearEquiv.ofBijective in Mathlib.Algebra.Module.Submodule.Equiv
LinearIndependent in Mathlib.LinearAlgebra.LinearIndependent.Defs
LinearMap in Mathlib.Algebra.Module.LinearMap.Defs
LinearMap.codRestrict in Mathlib.Algebra.Module.Submodule.LinearMap
LinearMap.ker in Mathlib.Algebra.Module.Submodule.Ker
Module.Basis.span in Mathlib.LinearAlgebra.Basis.Basic
Set.range in Mathlib.Data.Set.Operations
Submodule.subtype in Mathlib.Algebra.Module.Submodule.LinearMap
Subtype 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
Polynomial in Mathlib.Algebra.Polynomial.Basic
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
Semiring in Mathlib.Algebra.Ring.Defs
Polynomial.degreeLT in Mathlib.RingTheory.Polynomial.Basic
Set.univ in Mathlib.Data.Set.Defs
hammingDist in Mathlib.InformationTheory.Hamming
Finset.max in Mathlib.Data.Finset.Max
Module in Mathlib.Algebra.Module.Defs
Module.finrank in Mathlib.LinearAlgebra.Dimension.Finrank
ENat in Mathlib.Data.ENat.Defs
ENat.toNat in Mathlib.Data.ENat.Basic
Eq in Init.Prelude
Finset.biUnion in Mathlib.Data.Finset.Union
Finset.filter in Mathlib.Data.Finset.Filter
Fintype.ofFinite in Mathlib.Data.Fintype.EquivFin
Function.onFun in Mathlib.Logic.Function.Defs
Nonempty in Init.Prelude
Polynomial.eval in Mathlib.Algebra.Polynomial.Eval.Defs
SetLike in Mathlib.Data.SetLike.Basic
WithTop in Mathlib.Order.TypeTags
id in Init.Prelude
Finsupp in Mathlib.Data.Finsupp.Defs
Finsupp.equivFunOnFinite in Mathlib.Data.Finsupp.Defs
CharP in Mathlib.Algebra.CharP.Defs
DecidableEq in Init.Prelude
Set.image in Mathlib.Data.Set.Defs
Decidable in Init.Prelude
reduceDIte in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Core
Inhabited in Init.Prelude
Repr in Init.Data.Repr
Fin.cast in Init.Data.Fin.Basic
Nat.succ in Init.Prelude

notation "Δ₀(" u ", " v ")" => hammingDist u v

notation "Δ₀(" u ", " C ")" => distFromCode u C

scoped macro_rules
  | `(ρ $t:term) => `(LinearCode.rate $t)

noncomputable def sDomain (i : Fin r) : Subspace 𝔽q L :=
  let W_i_norm := normalizedW 𝔽q β i
  let h_W_i_norm_is_additive : IsLinearMap 𝔽q (fun x : L => W_i_norm.eval x) :=
    AdditiveNTT.normalizedW_is_additive 𝔽q β i
  Submodule.map (polyEvalLinearMap W_i_norm h_W_i_norm_is_additive)
    (U 𝔽q β ⟨ℓ + R_rate, h_ℓ_add_R_rate⟩)

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

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))

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

noncomputable def polyEvalLinearMap {L 𝔽q : Type*} [Field L] [Field 𝔽q] [Algebra 𝔽q L]
  (p : L[X]) (hp_add : IsLinearMap 𝔽q (fun x : L => p.eval x)) : L →ₗ[𝔽q] L :=
{
  toFun    := fun x => p.eval x,
  map_add' := hp_add.map_add,
  map_smul' := hp_add.map_smul
}

def binaryFinMapToNat {n : ℕ} (m : Fin n → ℕ) (h_binary : ∀ j: Fin n, m j ≤ 1) : Fin (2^n) :=

noncomputable def sDomain_basis (i : Fin r) (h_i : i < ℓ + R_rate) :
    Basis (Fin (ℓ + R_rate - i)) 𝔽q (
      sDomain 𝔽q β h_ℓ_add_R_rate i) :=

def sBasis (i : Fin r) (h_i : i < ℓ + R_rate) : Fin (ℓ + R_rate - i) → L :=
  fun k => β ⟨i + k.val, by admit /- proof elided -/
  ⟩

noncomputable def iteratedQuotientMap (i : Fin ℓ) (k : ℕ)
    (h_bound : i.val + k ≤ ℓ) (x : (sDomain 𝔽q β
    h_ℓ_add_R_rate) ⟨i, by omega⟩) :
    (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i.val + k, by omega⟩ :=

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 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))

def code (deg : ℕ) [Semiring F]: Submodule F (ι → F) :=
  (Polynomial.degreeLT F deg).map (evalOnPoints domain)

def evalOnPoints [Semiring F] : F[X] →ₗ[F] (ι → F) where
  toFun := fun p => fun x => p.eval (domain x)
  map_add' := fun x y => by admit /- proof elided -/

noncomputable def distFromCode (u : n → R) (C : Set (n → R)) : ℕ∞ :=
  sInf {d | ∃ v ∈ C, hammingDist u v ≤ d}

def toFinset (domain : ι ↪ F) (deg : ℕ) : Finset (ι → F) :=
  (RScodeSet domain deg).toFinset

abbrev RScodeSet (domain : ι ↪ F) (deg : ℕ) : Set (ι → F) := (ReedSolomon.code domain deg).carrier

noncomputable def minDist (C : Set (n → R)) : ℕ :=
  sInf {d | ∃ u ∈ C, ∃ v ∈ C, u ≠ v ∧ hammingDist u v = d}

noncomputable def rate [Semiring F] (LC : LinearCode ι F) : ℚ≥0 :=
  (dim LC : ℚ≥0) / length LC

noncomputable def dim [Semiring F] (LC : LinearCode ι F) : ℕ :=
  Module.finrank F LC

abbrev LinearCode.{u, v} (ι : Type u) [Fintype ι] (F : Type v) [Semiring F] : Type (max u v) :=
  Submodule F (ι → F)

def length [Semiring F] (_ : LinearCode ι F) : ℕ := Fintype.card ι

def symm (eqv : Equiv pSpec pSpec') : Equiv pSpec' pSpec where
  round_eq := eqv.round_eq.symm
  dir_eq := fun i => by admit /- proof elided -/

@[ext]
structure Equiv {m n : ℕ} (pSpec : ProtocolSpec m) (pSpec' : ProtocolSpec n) where
  round_eq : m = n
  dir_eq : ∀ i, pSpec.dir i = pSpec'.dir (Fin.cast round_eq i)
  typeEquiv : ∀ i, pSpec.«Type» i ≃ pSpec'.«Type» (Fin.cast round_eq i)

@[ext]
structure ProtocolSpec (n : ℕ) where
   
  dir : Fin n → Direction
   
  «Type» : Fin n → Type
deriving Inhabited

inductive Direction where
  | P_to_V  
  | V_to_P 
deriving DecidableEq, Inhabited, Repr

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 -/
  ⟩)

@[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 -/

def trans (eqv : Equiv pSpec pSpec') (eqv' : Equiv pSpec' pSpec'') : Equiv pSpec pSpec'' where
  round_eq := eqv.round_eq.trans eqv'.round_eq
  dir_eq := fun i => by admit /- proof elided -/

notation "Δ" IC => minDist IC

notation "Δ₀(" u ", " C ")" => distFromCode u C

def projectToNextSumcheckPoly (i : Fin (ℓ)) (Hᵢ : MultiquadraticPoly L (ℓ - i))
    (rᵢ : L) : -- the current challenge
    MultiquadraticPoly L (ℓ - i.succ) :=

def getUElements (i : Fin r) : List L :=
  (List.finRange (2^i.val)).map fun k =>
    (Finset.univ : Finset (Fin i)).sum fun j =>
      if Nat.getBit (n := k.val) (k := j.val) == 1 then
        β ⟨j.val, by admit /- proof elided -/
        ⟩
      else 0

@[reducible, simp] def OStmtIn := fun _ : Fin 2 => OStatement

def Reduction.liftContext
    (lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut)
    (R : Reduction oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec) :
      Reduction oSpec OuterStmtIn OuterWitIn OuterStmtOut OuterWitOut pSpec where
  prover := R.prover.liftContext lens
  verifier := R.verifier.liftContext lens.stmt

CommRing.toRing in Mathlib.Algebra.Ring.Defs

Equiv.toFun in Mathlib.Logic.Equiv.Defs

def proximityListDecodingCondition (C : LinearCode ι F)
  [Fintype ι] [Nonempty ι]
  (r : parℓ → F) [Fintype parℓ]
  (δ : ℝ) (fs : Matrix parℓ ι F)
  (IC : InterleavedCode parℓ ι F) : Prop :=
      let f_r := fun x => ∑ j, r j * fs j x
      let listHamming := relHammingBall C f_r δ
      let listIC := { fun x => ∑ j, r j * us j x | us ∈ Λᵢ(fs, IC.MF, δ)}
      listHamming ≠ listIC

instance [Zero T] [ToNat T] : Sub (Cayley T) where
  sub := sub

instance (s : Finset σ) : Fintype { x : σ | x ∈ s } :=

instance {T} [HasSucc T] : CoeFun (Cayley T) (fun _ => T → T) := ⟨Cayley.toFun⟩

structure KnowledgeStateFunctionOneShot
    (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    where
  toFun : (m : Fin (n + 1)) → StmtIn → Transcript m pSpec → Prop
   
  toFun_empty : ∀ stmtIn, ¬ toFun 0 stmtIn default
   
  toFun_next : ∀ m, pSpec.dir m = .P_to_V →
    ∀ stmt tr msg, ¬ toFun m.castSucc stmt tr → ¬ toFun m.succ stmt (tr.concat msg)
   
  toFun_full : ∀ stmt tr, ¬ toFun (.last n) stmt tr →
    [(· ∈ langOut) | do (simulateQ impl (verifier.run stmt tr)).run' (← init)] = 0

def ofMvPolynomialDeg1 (p : R⦃≤ 1⦄[X Fin n]) : MlPoly R n :=
  Vector.ofFn (fun i : Fin (2 ^ n) => p.val.coeff (monomialOfNat i))

@[inline]
def ofOutputOnly (projWit : OuterStmtIn × OuterWitOut → InnerWitOut) :
    Witness.InvLens OuterStmtIn OuterWitIn OuterWitOut OuterWitIn InnerWitOut :=
  ⟨projWit, fun _ => id⟩

@[inline, specialize]
def Prover.runToRoundDSFS [∀ i, VCVCompatible (pSpec.Challenge i)] (i : Fin (n + 1))
    (stmt : StmtIn) (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (state : prover.PrvState 0) :
        OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
          (pSpec.MessagesUpTo i ×
            DuplexSponge U (Vector U SpongeSize.N) × prover.PrvState i) :=
  Fin.induction
    (do
      
      let sponge ← liftM (DuplexSponge.start stmt)
      return ⟨default, sponge, state⟩
    )
    (prover.processRoundDSFS)
    i

structure InitialStatement where
  
  t_eval_point : Fin ℓ → L         
  original_claim : L               

def range (n : ℕ) : Fin n → ℕ := fun i => i

def implGroupExpOracle : QueryImpl (GroupExpOracle ι p) (StateT (GroupValTable ι G) Option) where
  impl | query _ ⟨i, a, j⟩ => fun table =>
    match table i with
    | some g => some ((), table.update j (some (g ^ a.val)))
    | none => none

Set.Ico in Mathlib.Order.Interval.Set.Defs

@[inline, specialize]
def oracleVerifier : OracleVerifier oSpec
    Statement OStatement Statement (OStatement ⊕ᵥ (fun _ : Fin 1 => Witness))
    (oraclePSpec Witness) where
  verify := fun stmt _ => pure stmt
  embed := .sumMap (.refl _)
    <| Equiv.toEmbedding
    <|.symm (subtypeUnivEquiv (by admit /- proof elided -/
    ))
  hEq := by admit /- proof elided -/

structure TowerEquivResult (k : ℕ) where
  ringEquiv : ConcreteBTField k ≃+* BTField k
  ringEquivForwardMapEq : ringEquiv = towerRingHomForwardMap k

def NoRedundantEntryDS (log : QueryLog (duplexSpongeChallengeOracle StmtIn U)) : Prop :=
  ∀ idx : Fin log.length, ¬ log.redundantEntryDS idx

Quotient.lift in Init.Core

def main (args : List String) : IO UInt32 := do lintStyle.validate args

partial def factor (n : ℕ) : Option (List ℕ) :=
  if deterministicMillerRabin n then
    [n]
  else do
    let f ← rho n
    let lhs ← factor f
    let rhs ← factor (n / f)
    return (lhs ++ rhs)

structure OracleContext.Lens (OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut : Type)
    {Outer_ιₛᵢ : Type} (OuterOStmtIn : Outer_ιₛᵢ → Type) [∀ i, OracleInterface (OuterOStmtIn i)]
    {Outer_ιₛₒ : Type} (OuterOStmtOut : Outer_ιₛₒ → Type) [∀ i, OracleInterface (OuterOStmtOut i)]
    {Inner_ιₛᵢ : Type} (InnerOStmtIn : Inner_ιₛᵢ → Type) [∀ i, OracleInterface (InnerOStmtIn i)]
    {Inner_ιₛₒ : Type} (InnerOStmtOut : Inner_ιₛₒ → Type) [∀ i, OracleInterface (InnerOStmtOut i)]
    (OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type) where
  stmt : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                  OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut
  wit : Witness.Lens (OuterStmtIn × ∀ i, OuterOStmtIn i) (InnerStmtOut × ∀ i, InnerOStmtOut i)
                          OuterWitIn OuterWitOut InnerWitIn InnerWitOut

noncomputable def J (q δ : ℚ) : ℝ :=
  let frac := q / (q - 1)
  (1 / frac) * (1 - Real.sqrt (1 - frac * δ))

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 -/

zsmulRec in Mathlib.Algebra.Group.Defs

def Verifier.StateFunction.id {lang : Set Statement} :
    (Verifier.id : Verifier oSpec Statement _ _).StateFunction init impl lang lang where
  toFun | ⟨0, _⟩ => fun stmtIn _ => stmtIn ∈ lang
  toFun_empty := fun _ => by admit /- proof elided -/

def verifySmallPrime (n' : Q(ℕ)) : MetaM Q(Nat.Prime $n') :=
  match n'.natLit! with
    | 2 => do haveI : $n' =Q 2 := ⟨⟩; return q(prime_2)
    | 3 => do haveI : $n' =Q 3 := ⟨⟩; return q(prime_3)
    | 5 => do haveI : $n' =Q 5 := ⟨⟩; return q(prime_5)
    | 7 => do haveI : $n' =Q 7 := ⟨⟩; return q(prime_7)
    | 11 => do haveI : $n' =Q 11 := ⟨⟩; return q(prime_11)
    | 13 => do haveI : $n' =Q 13 := ⟨⟩; return q(prime_13)
    | 17 => do haveI : $n' =Q 17 := ⟨⟩; return q(prime_17)
    | 19 => do haveI : $n' =Q 19 := ⟨⟩; return q(prime_19)
    | 23 => do haveI : $n' =Q 23 := ⟨⟩; return q(prime_23)
    | 29 => do haveI : $n' =Q 29 := ⟨⟩; return q(prime_29)
    | 31 => do haveI : $n' =Q 31 := ⟨⟩; return q(prime_31)
    | 37 => do haveI : $n' =Q 37 := ⟨⟩; return q(prime_37)
    | 41 => do haveI : $n' =Q 41 := ⟨⟩; return q(prime_41)
    | 43 => do haveI : $n' =Q 43 := ⟨⟩; return q(prime_43)
    | 47 => do haveI : $n' =Q 47 := ⟨⟩; return q(prime_47)
    | _ => failure

Semiring in Mathlib.Algebra.Ring.Defs

def LeafData.leftSubtree {α : Type} {s_left s_right : Skeleton}
    (tree : LeafData α (Skeleton.internal s_left s_right)) :
    LeafData α s_left :=
  match tree with
  | LeafData.internal left _right =>
    left

instance : SMul ℕ (UniPoly R) := ⟨nsmul⟩

@[simp]
def 𝕏 (k : ℕ) : BTField (k+1) := Z (k+1)

structure Witness (i : Fin (ℓ + 1)) where
  t : L⦃≤ 1⦄[X Fin ℓ]  
  H : L⦃≤ 2⦄[X Fin (ℓ - i)] 
  f: (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i, by admit /- proof elided -/
  ⟩ → L 

def InternalData.ofFun {α : Type} (s : Skeleton)
    (f : SkeletonInternalIndex s → α) : InternalData α s :=
  match s with
  | .leaf => InternalData.leaf
  | .internal l r =>
      InternalData.internal
        (f SkeletonInternalIndex.ofInternal)
        (InternalData.ofFun l (fun idx => f (SkeletonInternalIndex.ofLeft idx)))
        (InternalData.ofFun r (fun idx => f (SkeletonInternalIndex.ofRight idx)))

List.leftpad in Init.Data.List.Basic

instance coeFunctionFin2 [NatCast R] : Coe (σ → Fin 2) (σ → R) where
  coe := fun vec i => vec i

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 -/
      )
  }

@[inline, specialize]
def Reduction.run (stmt : StmtIn) (wit : WitIn)
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
        ((FullTranscript pSpec × StmtOut × WitOut) × StmtOut) := do
  
  let proverResult ← reduction.prover.run stmt wit
  let stmtOut ← liftM (reduction.verifier.run stmt proverResult.1)
  return ⟨proverResult, stmtOut⟩

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

noncomputable def roundConsistencyCheck [Field 𝔽] [DecidableEq 𝔽]
    (γ : 𝔽) (pts : List (𝔽 × 𝔽)) (β : 𝔽) : Bool :=
  let p := Lagrange.interpolate Finset.univ (fun i => (pts.get i).1) (fun i => (pts.get i).2)
  p.eval γ == β

@[reducible, simp]
def toRelInput : Set ((Statement × (∀ i, OStatement i)) × Unit) :=
  { ⟨⟨stmt, oStmt⟩, _⟩ | simulateQ' (toOracleImpl OStatement oStmt) (pred stmt) (hPred stmt) }

instance : HasSucc Nat where
  succ' := Nat.succ

def peval (f : σ → σ₁ ⊕ σ₂) (x : σ₁ → R) : MvPolynomial σ R →+* MvPolynomial σ₂ R :=
  eval₂Hom C (Sum.elim (fun i => C (x i)) X ∘ f)

class OracleInterfaces (pSpec : ProtocolSpec n) where
  oracleInterfaces : ∀ i, Option (OracleInterface (pSpec.Message i))

instance : Fact (Nat.Prime baseFieldSize) := ⟨BaseField_is_prime⟩

Set.offDiag in Mathlib.Data.Set.Operations

def Reduction.addSalt (R : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (saltComp : (i : pSpec.MessageIdx) → R.prover.PrvState i.1.castSucc →
      OracleComp oSpec (Salt i)) :
    Reduction oSpec StmtIn WitIn StmtOut WitOut (pSpec.addSalt Salt) where
  prover := R.prover.addSalt Salt saltComp
  verifier := R.verifier.addSalt Salt

def acceptRejectRel : Set (Bool × Unit) :=
  { (true, ()) }

@[inline, reducible]
protected def id :
    Context.Lens OuterStmtIn OuterStmtOut OuterStmtIn OuterStmtOut
                OuterWitIn OuterWitOut OuterWitIn OuterWitOut where
  stmt := Statement.Lens.id
  wit := Witness.Lens.id

alias trivial := Context.Lens.id

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

def partialEval {k : ℕ} (f : MvPolynomial (Fin m) F) (α : Fin k → F) (h : k ≤ m) :
    MvPolynomial (Fin (m - k)) F :=
  let φ : Fin m → MvPolynomial (Fin (m - k)) F := fun i =>
    if h' : i.val < k then
      C (α ⟨i.val, h'⟩)
    else
      let j := i.val - k
      let j' : Fin (m - k) := ⟨j, sorry⟩
      X j'
  eval₂ C φ f

@[simp]
def outerRelIn_Test : Set (OuterStmtIn_Test × Unit) :=
  setOf (fun ⟨⟨p, q, t⟩, _⟩ => ∑ x ∈ {0, 1}, (p * q).eval x = t)

OneMemClass in Mathlib.Algebra.Group.Submonoid.Defs

def sumPartial (m : ℕ) (n : ℕ) (D : Fin n → Finset R) :
    MvPolynomial (Fin (m + n)) R →ₗ[R] MvPolynomial (Fin m) R where
  toFun := fun p => ∑ x ∈ Fintype.piFinset D, peval (Fin.sumCommEquiv m n) x p
  map_add' := fun p q => by admit /- proof elided -/

instance : Unique (MessageIdx ⟨!v[.P_to_V], !v[Msg]⟩) where
  default := ⟨0, by admit /- proof elided -/
  ⟩
  uniq := fun i => by admit /- proof elided -/

Quotient.mk in Init.Core

def matrixSubmoduleOfLinearCode (κ : Type*) [Fintype κ]
                                (LC : LinearCode ι F) : MatrixSubmodule κ ι F :=
  Submodule.span F { V | ∀ i, V i ∈ LC }

@[inline] def ge [Zero T] [ToNat T] (a b : Cayley T) : Prop :=
  (a : Nat) ≥ (b : Nat)

map_pure in ToMathlib.Control.Monad.Hom

protected def cast (hIdx : k.val = l.val) (hSpec : pSpec₁.cast hn = pSpec₂)
    (T : pSpec₁.Transcript k) : pSpec₂.Transcript l :=
  fun i => _root_.cast (by admit /- proof elided -/
  ) (T (Fin.cast hIdx.symm i))

instance (priority := low) : DCast₂ α β γ where
  dcast₂ ha hb c := by admit /- proof elided -/

@[inline]
def seqCompose {m : ℕ} (Stmt : Fin (m + 1) → Type) (Wit : Fin (m + 1) → Type)
    {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (R : (i : Fin m) →
      Reduction oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ) (pSpec i)) :
    Reduction oSpec (Stmt 0) (Wit 0) (Stmt (Fin.last m)) (Wit (Fin.last m)) (seqCompose pSpec) where
  prover := Prover.seqCompose Stmt Wit (fun i => (R i).prover)
  verifier := Verifier.seqCompose Stmt (fun i => (R i).verifier)

def implGroupEncodeOracle [Serialize G (BitVec bitLength)] :
    QueryImpl (GroupEncodeOracle ι bitLength) (StateT (GroupValTable ι G) Option) where
  impl | query _ i => fun table =>
    match table i with
    | some g => some (serialize g, table)
    | none => none

structure ConcreteBTFAddCommGroupProps (k : ℕ) where
  add_assoc : ∀ a b c : ConcreteBTField k, (a + b) + c = a + (b + c) := add_assoc
  add_comm : ∀ a b : ConcreteBTField k, a + b = b + a := add_comm
  add_zero : ∀ a : ConcreteBTField k, a + zero = a := add_zero
  zero_add : ∀ a : ConcreteBTField k, zero + a = a := zero_add
  add_neg : ∀ a : ConcreteBTField k, a + (neg a) = zero := neg_add_cancel

noncomputable def minBlockRelDistance
  (i k : ℕ) {S : Finset ι} {φ : ι ↪ F}
  [DecidableEq F] [DecidableEq ι] [Smooth φ]
  (f : (indexPowT S φ i) → F) (S' : Finset (indexPowT S φ i))
  (φ' : (indexPowT S φ i) ↪ F) (Set : Set ((indexPowT S φ i) → F))
  [∀ i : ℕ, Fintype (indexPowT S φ i)]
  [h : DecidableBlockDisagreement i k f S' φ'] : ℝ≥0 :=
    sInf { d : ℝ≥0 | ∃ g ∈ Set, Δᵣ(i, k, f, S', φ', g) = d}

def possibleDeltas (U V : Set (ι → F)) : Set ℚ≥0 :=
  {d : ℚ≥0 | ∃ u ∈ U, δᵣ(u,V) = d}

def implGroupEqOracle [BEq G] :
    QueryImpl (GroupEqOracle ι) (StateT (GroupValTable ι G) Option) where
  impl | query _ ⟨i, j⟩ => fun table =>
    match table i, table j with
    | some g₁, some g₂ => some (g₁ == g₂, table)
    | _, _ => none

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

AddCommMonoid in Mathlib.Algebra.Group.Defs

@[reducible]
def index (op : MemoryWrite ι α) := op.1

@[inline, specialize]
def OracleReduction.runWithLog [∀ i, OracleInterface (pSpec.Message i)]
    (stmt : StmtIn) (oStmt : ∀ i, OStmtIn i) (wit : WitIn)
    (reduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
        ((FullTranscript pSpec × (StmtOut × ∀ i, OStmtOut i) × WitOut) ×
          (StmtOut × ∀ i, OStmtOut i) ×
            QueryLog (oSpec ++ₒ [pSpec.Challenge]ₒ) × QueryLog oSpec) := do
  let ⟨proverResult, proveQueryLog⟩ ←
    (simulateQ loggingOracle (reduction.prover.run ⟨stmt, oStmt⟩ wit)).run
  let ⟨stmtOut, verifyQueryLog⟩ ←
    liftM (simulateQ loggingOracle (reduction.verifier.run stmt oStmt proverResult.1)).run
  return ⟨proverResult, stmtOut, proveQueryLog, verifyQueryLog⟩

instance [DecidableEq ι] : Memory ι α (∀ i, α i) where
  read m i := m i
  write m i v := Function.update m i v

instance [Zero T] [One T] [ToNat T] : HomogeneousPow (Cayley T) where
  pow := pow

def twoLevelSkel (k0 k1 : ℕ) :
    ArityTree.Skeleton 2 (ar2 k0 k1) :=
  ArityTree.Skeleton.node (fun _ =>
    ArityTree.Skeleton.node (fun _ => ArityTree.Skeleton.leaf))

instance {i : OracleMessageIdx pSpec} : OracleInterface (pSpec.Message i) :=
  (inst.oracleInterfaces i).get i.2

def domainEmb {i : ℕ} : evalDomain D i ↪ F :=
  ⟨
    fun x => x.1.1,
    by admit /- proof elided -/
  ⟩

def computeInitialSumcheckPoly (t : MultilinearPoly L ℓ)
    (m : MultilinearPoly L ℓ) : MultiquadraticPoly L ℓ :=
  ⟨m * t, by
    rw [MvPolynomial.mem_restrictDegree_iff_degreeOf_le]
    intro i
    have h_t_deg: degreeOf i t.val ≤ 1 :=
      degreeOf_le_iff.mpr fun term a ↦ (t.property) a i
    have h_m_deg: degreeOf i m.val ≤ 1 :=
      degreeOf_le_iff.mpr fun term a ↦ (m.property) a i
    calc
      _ ≤ (degreeOf i m.val) + (degreeOf i t.val) :=
        degreeOf_mul_le i m.val t.val
      _ ≤ 2 :=

def toOracleSpec {ι : Type u} (v : ι → Type v) [O : ∀ i, OracleInterface (v i)] :
    OracleSpec ι := fun i => ((O i).Query, (O i).Response)

def prover (i : Fin n) : OracleProver oSpec
    (StatementRound R n i.castSucc) (OracleStatement R n deg) Unit
    (StatementRound R n i.succ) (OracleStatement R n deg) Unit (pSpec R deg) where
  toProverState := proverState R n deg i
  toProverInput := proverInput R n deg i
  sendMessage := (proverRound R n deg D oSpec i).sendMessage
  receiveChallenge := (proverRound R n deg D oSpec i).receiveChallenge
  toProverOutput := proverOutput R n deg oSpec i

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

instance : Unique (ChallengeIdx ⟨!v[.V_to_P], !v[Chal]⟩) where
  default := ⟨0, by admit /- proof elided -/
  ⟩
  uniq := fun i => by admit /- proof elided -/

def interleaveCode [Semiring F] [DecidableEq F] (C : Submodule F (n → F)) (ι : Type*)
  : Submodule F ((ι × n) → F) :=
  Submodule.span F {v | ∀ i, ∃ c ∈ C, c = fun j => v (i, j)}

def outputRelation :
    Set (((StmtOut R) × (∀ i, OStmtOut R deg i)) × Unit) :=
  { ⟨⟨⟨newTarget, chal⟩, oStmt⟩, _⟩ | (oStmt ()).1.eval chal = newTarget }

instance : ∀ j, SelectableType ((pSpecFold (L:=L)).Challenge j)
  | ⟨j, hj⟩ => by admit /- proof elided -/

def EvenPoly (f : Polynomial F) : Prop := ∀ n, Odd n → f.coeff n = 0

def canonical (p : UniPoly R) := p.trim = p

abbrev SEP_BYTE : String := ⟨[SEP_CHAR]⟩

Div in Init.Prelude

instance :
    ∀ i, OracleInterface
          ((pSpecFold D x k s ++ₚ FinalFoldPhase.pSpec F ++ₚ QueryRound.pSpec D x l).Message i) :=
  instOracleInterfaceMessageAppend

structure Condition
  (k r D : ℕ)
  (ωs : Fin n ↪ F)
  (f : Fin n → F)
  (Q : Polynomial (Polynomial F)) where
   
  Q_ne_0 : Q ≠ 0
   
  Q_deg : Bivariate.weightedDegree Q 1 (k-1) ≤ D
   
  Q_roots : ∀ i, (Q.eval (C <| f i)).eval (ωs i) = 0
   
  Q_multiplicity : ∀ i, r ≤ Bivariate.rootMultiplicity Q (ωs i) (f i)

Vector.tail in Init.Data.Vector.Basic

IntCast in Init.Data.Int.Basic

def constrainedCode
  (domain : ι ↪ F) [Smooth domain] (m : ℕ)
  (w : MvPolynomial (Fin (m + 1)) F) (σ : F) : Set (ι → F) :=
    { f | ∃ (h : f ∈ smoothCode domain m),
      weightConstraint (mVdecode (⟨f, h⟩ : smoothCode domain m)) w σ }

instance : MonadLift (StateT σ m) (StateT (σ × τ) m) where
  monadLift := fun x st => do let y ← x st.1; return (y.1, y.2, st.2)

structure ParamConditions (P : Params ι F) where
  m : ℕ 
  h_m : m = P.varCount 0
  h_sumkLt : ∑ i : Fin (M + 1), P.foldingParam i ≤ m
  h_varCount_i : ∀ i : Fin (M + 1),
    P.varCount i = m - ∑ j : Fin i, P.foldingParam (Fin.castLT j (Nat.lt_trans j.isLt i.isLt))
  h_smooth : ∀ i : Fin (M + 1), Smooth (P.φ i)
  h_repeatPLt : ∀ i : Fin (M + 1), P.repeatParam i ≤ Fintype.card (ι i)

@[simp]
def transpose {m n : ℕ} (matrix : Matrix α m n) : Matrix α n m :=
  ofFn (fun j => ofFn (fun i => (matrix.get i).get j))

@[reducible, inline]
instance instPolynomial : OracleInterface R[X] where
  Query := R
  Response := R
  answer := fun poly point => poly.eval point

@[inline, reducible]
def OracleStatement.Lens (OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut : Type)
    {Outer_ιₛᵢ : Type} (OuterOStmtIn : Outer_ιₛᵢ → Type) [∀ i, OracleInterface (OuterOStmtIn i)]
    {Outer_ιₛₒ : Type} (OuterOStmtOut : Outer_ιₛₒ → Type) [∀ i, OracleInterface (OuterOStmtOut i)]
    {Inner_ιₛᵢ : Type} (InnerOStmtIn : Inner_ιₛᵢ → Type) [∀ i, OracleInterface (InnerOStmtIn i)]
    {Inner_ιₛₒ : Type} (InnerOStmtOut : Inner_ιₛₒ → Type) [∀ i, OracleInterface (InnerOStmtOut i)]
  :=
    Statement.Lens (OuterStmtIn × ∀ i, OuterOStmtIn i) (OuterStmtOut × ∀ i, OuterOStmtOut i)
                  (InnerStmtIn × ∀ i, InnerOStmtIn i) (InnerStmtOut × ∀ i, InnerOStmtOut i)

instance {k : Fin 1} : Unique (MessagesUpTo k (default : ProtocolSpec 0)) where
  default := fun i => ()
  uniq := by admit /- proof elided -/

abbrev AffSpanSet [NeZero k] (U : Fin k → ι → F) : Set (ι → F) :=
  (affineSpan F (Finset.univ.image U : Set (ι → F))).carrier

@[reducible, inline, specialize]
def challenges (transcript : FullTranscript pSpec) (i : ChallengeIdx pSpec) :=
  transcript i.val

SemilatticeSup in Mathlib.Order.Lattice

@[reducible]
def fieldSize : Nat := 2 ^ 31 - 2 ^ 27 + 1

def coeffsOfPolynomial (p : F[X]) : Fin deg → F :=
  fun ⟨x, _⟩ ↦ p.coeff x

def FullData.copath {α} {s} (cache_tree : FullData α s) :
    BinaryTree.SkeletonLeafIndex s → List α
  | .ofLeaf => []
  | .ofLeft idxLeft =>
    (cache_tree.rightSubtree).getRootValue ::
      (copath cache_tree.leftSubtree idxLeft)
  | .ofRight idxRight =>
    (cache_tree.leftSubtree).getRootValue ::
      (copath cache_tree.rightSubtree idxRight)

protected def cast (i : MessageIdx pSpec₁) : MessageIdx pSpec₂ :=
  ⟨Fin.cast hn i.1, by admit /- proof elided -/
  ⟩

def fullRound (params : Params) (state : Vector KoalaBear.Field params.width)
    (roundConstants : Vector KoalaBear.Field params.width) : Vector KoalaBear.Field params.width :=
  
  let stateWithConstants := state.zipWith (·+·) roundConstants
  
  let stateAfterSbox := stateWithConstants.map (fun x => x ^ sBoxDegree)
  
  externalLinearLayer params stateAfterSbox

def liftF (f : Fin n → α) : ℕ → α :=
  fun m ↦ if h : m < n then f ⟨m, h⟩ else 0

def leq {α : Type} (m n : ChurchNat α) : ChurchBool α :=
  isZero (ChurchNat.sub m n)

instance {ι : Type u} (v : ι → Type v) [O : ∀ i, OracleInterface (v i)]
    [h : ∀ i, Fintype (Response (v i))]
    [h' : ∀ i, Inhabited (Response (v i))] :
    [v]ₒ.FiniteRange where
  range_fintype' := h
  range_inhabited' := h'

def evalBivar
  (Q : MvPolynomial (Fin 2) F) (a b : F) : F := MvPolynomial.eval (Fin.cases a (fun _ ↦ b)) Q

def lift {ι₁ ι₂ ι : Type} {σ : Type} (oSpec₁ : OracleSpec ι₁) (oSpec₂ : OracleSpec ι₂)
    (oSpec : OracleSpec ι) (so : SimOracle.Stateful oSpec₁ oSpec₂ σ) :
      SimOracle.Stateful (oSpec ++ₒ oSpec₁) (oSpec ++ₒ oSpec₂) σ where
  impl := fun q s => match q with
    | query (.inl i) q => do return ⟨← query i q, s⟩
    | query (.inr i) q => so.impl (query (spec := oSpec₁) i q) s

def pSpecCoreInteraction := (pSpecSumcheckFold 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) ++ₚ
  (pSpecFinalSumcheckStep (L:=L))

def instDefault {Message : Type u} : OracleInterface Message where
  Query := Unit
  Response := Message
  answer := fun m _ => m

@[inline] def div [Zero T] [DecidableEq T] [ToNat T]
    (dividend divisor : Cayley T) : Cayley T :=
  
  letI fuel := (↑dividend : Nat) + 1
  divNat dividend divisor fuel

def pSpecQuery : ProtocolSpec 1 :=
  ⟨![Direction.V_to_P],
    ![Fin γ_repetitions → sDomain 𝔽q β h_ℓ_add_R_rate 0]⟩

instance : VAdd (ι → F) (AffineSubspace F (ι → F)) := AffineSubspace.pointwiseVAdd

instance {s} : Functor (fun α => InternalData α s) where
  map f x := x.map f

def combined : Prop :=
  capacitySegmentDup trace ∨ notFunction trace

alias E := combined

Module.finrank in Mathlib.LinearAlgebra.Dimension.Finrank

noncomputable def uni2bi (p : Polynomial F) : MvPolynomial (Fin 2) F :=
  Polynomial.eval₂ MvPolynomial.C (MvPolynomial.X 0) p

OracleSpec.QueryLog.inl in VCVio.OracleComp.QueryTracking.Structures

Algebra.TensorProduct.instAlgebra in Mathlib.RingTheory.TensorProduct.Basic

def Function.interleave₂ {α β : Type*} (u v : α → β) : (Fin 2) × α → β :=
  Function.uncurry (fun a => if a = 0 then u else v)

instance {α : Fin 0 → Sort u} : Unique ((i : Fin 0) → α i) where
  default := fun i => elim0 i
  uniq v := by admit /- proof elided -/

@[reducible, inline, specialize]
def Messages' (pSpec : ProtocolSpec n) : Type :=
  ∀ i, (hi : pSpec.dir i = .P_to_V) → pSpec.«Type» i

Finsupp.linearCombination in Mathlib.LinearAlgebra.Finsupp.LinearCombination

@[reducible]
def sumcheckFoldOracleVerifier :=
  let stmt : Fin (ℓ / ϑ - 1 + 1) → Type :=
    fun i => Statement (L := L) (ℓ := ℓ) Context ⟨i * ϑ, blockIdx_mul_ϑ_lt_ℓ_succ i⟩
  let oStmt :=
    fun i: Fin (ℓ / ϑ - 1 + 1) => OracleStatement 𝔽q β ϑ ⟨i * ϑ, blockIdx_mul_ϑ_lt_ℓ_succ i⟩
  let nonLastBlocksOracleVerifier :=
  OracleVerifier.seqCompose (oSpec := []ₒ)
      (Stmt := stmt)
      (OStmt := oStmt)
      (pSpec := fun (bIdx: Fin (ℓ / ϑ - 1)) => pSpecFullNonLastBlock 𝔽q β bIdx)
      (V := fun bIdx => nonLastBlockOracleVerifier (L:=L) 𝔽q β (ϑ:=ϑ) (bIdx:=bIdx))

  let lastOracleVerifier := lastBlockOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)

  let sumcheckFoldOV: OracleVerifier []ₒ
    (StmtIn := Statement (L := L) (ℓ := ℓ) Context 0)
    (OStmtIn := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ 0)
    (StmtOut := Statement (L := L) (ℓ := ℓ) Context (Fin.last ℓ))
    (OStmtOut := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (pSpec := pSpecSumcheckFold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
     := by admit /- proof elided -/

MvPolynomial.X in Mathlib.Algebra.MvPolynomial.Basic

@[inline, reducible]
def lift : OuterStmtIn × OuterWitIn → InnerStmtOut × InnerWitOut → OuterStmtOut × OuterWitOut :=
  fun ctxIn ctxOut =>
    ⟨lens.stmt.toFunB ctxIn.1 ctxOut.1, lens.wit.toFunB ctxIn ctxOut⟩

id in Init.Prelude

instance [inst : ∀ i, OracleInterface (pSpec₁.Message i)] :
    ∀ i, OracleInterface ((pSpec₁.cast hn).Message i) :=
  fun i => inst (dcast₂ hn.symm (by admit /- proof elided -/
  ) i)

def Option.doubleBind_v2 {α β γ : Type} (f : α → β → Option γ)
    (x : Option α) (y : Option β) : Option γ := do
  let a ← x
  let b ← y
  f a b

def powerBasisSucc (k : ℕ) :
    PowerBasis (ConcreteBTField k) (ConcreteBTField (k + 1)) :=

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

instance : Initialize (DuplexSponge U C) (Vector UInt8 32) where
  new iv := {
    state := Initialize.new iv,
    absorbPos := 0,
    squeezePos := Fin.last SpongeSize.R
  }

@[inline, reducible]
protected def id :
    OracleContext.Lens OuterStmtIn OuterStmtOut OuterStmtIn OuterStmtOut
                OuterOStmtIn OuterOStmtOut OuterOStmtIn OuterOStmtOut
                OuterWitIn OuterWitOut OuterWitIn OuterWitOut where
  stmt := OracleStatement.Lens.id
  wit := Witness.Lens.id

alias trivial := OracleContext.Lens.id

Fin.last in Init.Data.Fin.Basic

Nat.bit in Mathlib.Data.Nat.BinaryRec

BitVec.ofNat in Init.Prelude

def mkDivisionRingInstance {k : ℕ} (props : ConcreteBTFieldProps k)
    : DivisionRing (ConcreteBTField k) where
  toRing := mkRingInstance (k:=k) props
  inv := concrete_inv
  exists_pair_ne := concrete_exists_pair_ne (k := k)
  mul_inv_cancel := props.mul_inv_cancel
  inv_zero := concrete_inv_zero
  qsmul := (Rat.castRec · * ·)
  nnqsmul := (NNRat.castRec · * ·)

local instance : Inhabited R := ⟨0⟩

@[inline] def add (a b : AssocNat) : AssocNat :=
  ⟨a ∘ b, by admit /- proof elided -/
  ⟩

instance : ∀ i, OracleInterface (Message ⟨!v[.V_to_P], !v[Chal]⟩ i)
  | ⟨0, h⟩ => nomatch h

instance : curve.IsShortNF :=

SMul in Init.Prelude

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

@[reducible]
def pSpecFold : ProtocolSpec (Fin.vsum fun (_ : Fin k) ↦ 2) :=
  ProtocolSpec.seqCompose (fun (i : Fin k) => FoldPhase.pSpec D x s i)

def ξ (x₀ : F) (R : F[X][X][Y]) (H : F[X][Y]) [φ : Fact (Irreducible H)] : 𝒪 H :=
  (ξ_regular x₀ R H).choose

Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic

Array.size in Init.Prelude

def forwardPermutationOracleImpl {α : Type*} [Permute α] :
    QueryImpl (forwardPermutationOracle α) Id where
  impl | query () q => Permute.permute (α := α) q

@[inline, specialize]
def OracleReduction.run [∀ i, OracleInterface (pSpec.Message i)]
    (stmt : StmtIn) (oStmt : ∀ i, OStmtIn i) (wit : WitIn)
    (reduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
        ((FullTranscript pSpec × (StmtOut × ∀ i, OStmtOut i) × WitOut) ×
          (StmtOut × ∀ i, OStmtOut i)) := do
  let proverResult ← reduction.prover.run ⟨stmt, oStmt⟩ wit
  let stmtOut ← liftM (reduction.verifier.run stmt oStmt proverResult.1)
  return ⟨proverResult, stmtOut⟩

def ratchet (sponge : DuplexSponge U C) :
    OracleComp (forwardPermutationOracle C) (DuplexSponge U C) := do
  let permutedState : C ← query (spec := forwardPermutationOracle C) () sponge.state
  
  let vecState : Vector U SpongeSize.N := SpongeState.get permutedState
  
  let zeroed : Vector U SpongeSize.N :=
    Vector.ofFn (fun i => if i < SpongeSize.R then 0 else vecState[i])
  
  let newVecState := SpongeState.update permutedState zeroed
  
  return { sponge with
    state := newVecState,
    squeezePos := Fin.last SpongeSize.R }

Polynomial.C in Mathlib.Algebra.Polynomial.Basic

Polynomial.degreeLTEquiv in Mathlib.RingTheory.Polynomial.Basic

def challengeTensorProduct (steps : ℕ) (r_challenges : Fin steps → L) : Vector L (2 ^ steps) :=
  if h_steps_zero : steps = 0 then
    
    by
      rw [h_steps_zero, pow_zero]
      exact ⟨#[1], rfl⟩
  else
    
    Nat.rec
      (motive := fun k => k ≤ steps → Vector L (2^k))
      (fun _ => ⟨#[1], rfl⟩)  
      (fun k ih h_k_le =>
        
        let prev_vec := ih (Nat.le_trans (Nat.le_succ k) h_k_le)
        let r_k := r_challenges ⟨k, by admit /- proof elided -/
        ⟩
        
        Vector.ofFn (fun idx : Fin (2^k.succ) =>
          let prev_idx : Fin (2^k) := ⟨idx.val / 2, by admit /- proof elided -/
            ⟩
          let bit := idx.val % 2
          let prev_val := prev_vec.get prev_idx
          if bit = 0 then (1 - r_k) * prev_val else r_k * prev_val))
      steps (le_refl steps)

class AlgebraTower {ι : Type*} [Preorder ι] (AT : ι → Type*)
  [∀ i, CommSemiring (AT i)] where
   
  protected algebraMap : ∀ i j, (h : i ≤ j) → (AT i →+* AT j)
   
  commutes' : ∀ (i j : ι) (h : i ≤ j) (r : AT i) (x : AT j),
    (algebraMap i j h r) * x = x * (algebraMap i j h r)
  coherence': ∀ (i j k : ι) (h1 : i ≤ j) (h2 : j ≤ k),
    algebraMap i k (h1.trans h2) =
      (algebraMap j k h2).comp (algebraMap i j h1)

def seqComposeChallengeIdxToSigma {m : ℕ} {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (k : (seqCompose pSpec).ChallengeIdx) : (i : Fin m) × (pSpec i).ChallengeIdx :=
  let ij := Fin.splitSum k.1
  ⟨ij.1, ⟨ij.2, by admit /- proof elided -/
    ⟩⟩

@[reducible, simp] def WitIn := Unit

noncomputable def novelPolynomialBasis (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  Basis (Fin (2^ℓ)) (R := L) (M := L⦃<2^ℓ⦄[X]) :=

Set.Pairwise in Mathlib.Logic.Pairwise

instance {α : Type*} {n : ℕ} [VCVCompatible α] : VCVCompatible (Vector α n) where

@[reducible, simp] def OStmtOut := fun _ : Fin 2 => OStatement

def findFinIdxIfTrue (p : α → Bool) (l : List α) (h : ∃ x ∈ l, p x) : Fin l.length :=
  ⟨List.findIdx' p l, by admit /- proof elided -/
  ⟩

def churchVecFold (xs : ChurchVec α) (f : α → List α → List α) (base : List α) : List α :=
  xs f base

protected def cast (pSpec : ProtocolSpec n₁) : ProtocolSpec n₂ :=
  ⟨pSpec.dir ∘ (Fin.cast hn.symm), pSpec.«Type» ∘ (Fin.cast hn.symm)⟩

def fiberwiseDisagreementSet (i : Fin ℓ) (steps : ℕ) [NeZero steps]
    (h_i_add_steps : i.val + steps ≤ ℓ) (f g : OracleFunction 𝔽q β (h_ℓ_add_R_rate :=
      h_ℓ_add_R_rate) ⟨i, by admit /- proof elided -/
      ⟩) :
  Set ((sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i.val + steps, by admit /- proof elided -/
  ⟩) :=
  
    
  {y | ∃ x, iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate (i := i)
    (k := steps) (h_bound := by admit /- proof elided -/
    ) x = y ∧ f x ≠ g x}

def liftBTFieldProps (k : ℕ) (prevBTFResult : ConcreteBTFStepResult (k := k)) :
  ConcreteBTFieldProps (k + 1) := {
    zero_mul := concrete_zero_mul (prevBTFResult.toConcreteBTFieldProps),
    zero_mul' := fun a => by admit /- proof elided -/

noncomputable def relayOracleVerifier (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleVerifier
    (oSpec := []ₒ)
    (StmtIn := Statement (L := L) Context i.succ)
    (OStmtIn := OracleStatement 𝔽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.succ)
    (pSpec := pSpecRelay) where
  verify := fun stmtIn _ => pure stmtIn
  embed := ⟨fun j => by admit /- proof elided -/
  ⟩
  hEq := fun oracleIdx => by admit /- proof elided -/

structure Context.Lens (OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                          OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type) where
  stmt : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
  wit : Witness.Lens OuterStmtIn InnerStmtOut OuterWitIn OuterWitOut InnerWitIn InnerWitOut

Equiv.cast in Mathlib.Logic.Equiv.Defs

instance : IsCyclic G :=
  isCyclic_of_prime_card PrimeOrder.hCard

structure Indexer {ι : Type} (oSpec : OracleSpec ι) {n : ℕ} (pSpec : ProtocolSpec n) (Index : Type)
    (Encoding : Type) where
  encode : Index → OracleComp oSpec Encoding
  [OracleInterface : OracleInterface Encoding]

def churchAnd (p q : ChurchBool α) : ChurchBool α :=
  fun x y => p (q x y) y

def pSpecFinalSumcheckStep : ProtocolSpec 1 := ⟨![Direction.P_to_V], ![L]⟩

instance (k : ℕ) : Preorder (ConcreteBTField k) where
  le_refl := fun x => BitVec.le_refl x
  le_trans := fun x y z hxy hyz => BitVec.le_trans hxy hyz
  lt := fun x y => x < y
  lt_iff_le_not_ge := fun x y => by admit /- proof elided -/
| intro h_le_xy h_not_le_yx =>
      have x_lt_y:= mt bitvec_statement.mp h_not_le_yx
      push_neg at x_lt_y
      exact x_lt_y

instance : Field BaseField := ZMod.instField baseFieldSize

instance instDCast₂Forall :
    DCast₂ α (fun a => ∀ b : β a, γ a b) (fun a f => ∀ b : β a, δ a b (f b)) where
  dcast₂ ha hb c := fun b => dcast₃ ha (by admit /- proof elided -/
  )
    (by admit /- proof elided -/
    ) (c (dcast ha.symm b))
  dcast₂_id := by admit /- proof elided -/

def oracleReduction.reduceClaim : OracleReduction oSpec
    (StmtAfterRandomQuery R) (OStmtAfterRandomQuery R deg) Unit
    (StmtOut R) (OStmtOut R deg) Unit !p[] :=

@[reducible, simp]
def pSpec : ProtocolSpec 1 := ⟨!v[.P_to_V], !v[Witness]⟩

instance {pSpec : ProtocolSpec n} : CoeHead (ChallengeIdx pSpec) (Fin n) where
  coe := fun i => i.1

noncomputable def towerEquiv (n : ℕ) : TowerEquivResult n :=

structure FSProverState (U : Type) [SpongeUnit U] (H : Type*) [DuplexSpongeInterface U H]
    (R : Type*) extends FSVerifierState U H where
   
  rng : ProverPrivateRng R
deriving Repr

@[simp]
abbrev FirstChallenge : Type := Fin pp.ℓ_m → R

def perm (cs : ConstraintSystem 𝓡 numWires numGates) : Equiv.Perm (Fin (3 * numGates)) := sorry

def ranges {n : ℕ} (a : Fin n → ℕ) : (i : Fin n) → Fin (a i) → ℕ :=
  match n with
  | 0 => fun i => elim0 i
  | n + 1 => fun i => by admit /- proof elided -/

def OracleSpec.FunctionType (spec : OracleSpec ι) := (i : ι) → spec.domain i → spec.range i

Even in Mathlib.Algebra.Group.Even

@[reducible]
def SimOracle.Impl (spec : OracleSpec ι) := SimOracle.Stateless spec []ₒ

@[reducible]
def scalarFieldSize : Nat :=
  8444461749428370424248824938781546531375899335154063827935233455917409239041

Fin.isEmpty' in Mathlib.Logic.IsEmpty

@[reducible, simp]
def perfectCompleteness (relation : Set (Statement × Witness))
    (proof : Proof oSpec Statement Witness pSpec) : Prop :=
  Reduction.perfectCompleteness init impl relation acceptRejectRel proof

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

structure RoundByRound
    (oSpec : OracleSpec ι) (StmtIn WitIn WitOut : Type) {n : ℕ} (pSpec : ProtocolSpec n)
    (WitMid : Fin (n + 1) → Type) where
   
  eqIn : WitMid 0 = WitIn
   
  extractMid : (m : Fin n) → StmtIn → Transcript m.succ pSpec → WitMid m.succ → WitMid m.castSucc
   
  extractOut : StmtIn → FullTranscript pSpec → WitOut → WitMid (.last n)

noncomputable def polynomialAlgEquiv : P ≃ₐ[R] R[X] where
  toFun := toPolynomialAlgHom
  invFun := ofPolynomialAlgHom
  left_inv := by admit /- proof elided -/

def powContraction :
  MvPolynomial (Fin m) F →ₗ[F] Polynomial F :=
  powAlgHom.toLinearMap

System.FilePath.fileName in Init.System.FilePath

def vflatten {m : ℕ} {n : Fin m → ℕ} (v : (i : Fin m) → Fin (n i) → α) :
    Fin (vsum n) → α :=
  dflatten v

instance {i : Fin ℓ} : ∀ j, SelectableType ((pSpecCommit 𝔽q β
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i).Challenge j)
  | ⟨0, hj⟩ => by admit /- proof elided -/

Lean.PrettyPrinter.Unexpander in Init.Prelude

def div [Field R] (p q : UniPoly R) : UniPoly R :=
  (C (q.leadingCoeff)⁻¹ • p).divByMonic (C (q.leadingCoeff)⁻¹ * q)

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

def proximityCondition (f : parℓ → ι → F) (δ : ℝ≥0) (r : parℓ → F)
    (C : LinearCode ι F) : Prop :=
  ∃ S : Finset ι,
    (S.card : ℝ≥0) ≥ (1-δ) * Fintype.card ι ∧
    ∃ u ∈ C, ∀ s ∈ S, u s = ∑ j : parℓ, r j * f j s ∧
    ∃ i : parℓ, ∀ u' ∈ C, ∃ s ∈ S, u' s ≠ f i s

def proverInput (i : Fin n) : ProverInput
    ((StatementRound R n i.castSucc) × (∀ i, OracleStatement R n deg i))
    Unit ((proverState R n deg i).PrvState 0) where
  input := Prod.fst

instance {pSpec : ProtocolSpec n} {Statement : Type} [∀ i, VCVCompatible (pSpec.Challenge i)] :
    OracleSpec.FiniteRange (fsChallengeOracle Statement pSpec) :=
  inferInstanceAs (OracleSpec.FiniteRange (srChallengeOracle Statement pSpec))

def findSumIdx' (l : List ℕ) (j : Fin l.sum) : Fin l.length := ⟨findSumIdx l j, sorry⟩

instance [Zero T] [ToNat T] : HasPred (Cayley T) where
  pred' := pred

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

IsField.toField in Mathlib.Algebra.Field.IsField

noncomputable def fold_k_set
  {S : Finset ι} {φ : ι ↪ F} {k m : ℕ}
  [∀ j : ℕ, Neg (indexPowT S φ j)]
  (set : Set ((indexPowT S φ 0) → F)) (αs : Fin k → F) (hk : k ≤ m): Set (indexPowT S φ k → F) :=
    { g | ∃ f ∈ set, g = fold_k f αs hk}

@[inline, reducible]
def Statement.Lens (OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut : Type)
  := PFunctor.Lens (OuterStmtIn X^ OuterStmtOut)
                   (InnerStmtIn X^ InnerStmtOut)

def finalSumcheckKStateProp {m : Fin (1 + 1)} (tr : Transcript m (pSpecFinalSumcheckStep (L := L)))
    (stmt : Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ))
    (witMid : FinalSumcheckWit (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ := ℓ) m)
    (oStmt : ∀ j, OracleStatement 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ) j) : Prop :=
  match m with
  | ⟨0, _⟩ => 
    masterKStateProp 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (mp := BBF_SumcheckMultiplierParam)
      (stmtIdx := Fin.last ℓ) (oracleIdx := Fin.last ℓ) (h_le := le_refl _)
      (stmt := stmt) (wit := witMid) (oStmt := oStmt) (localChecks := True)
  | ⟨1, _⟩ => 
    let tr_so_far := (pSpecFinalSumcheckStep (L := L)).take 1 (by admit /- proof elided -/
    )
    let i_msg0 : tr_so_far.MessageIdx := ⟨⟨0, by admit /- proof elided -/
    ⟩, rfl⟩
    let c : L := (ProtocolSpec.Transcript.equivMessagesChallenges (k := 1)
      (pSpec := pSpecFinalSumcheckStep (L := L)) tr).1 i_msg0

    let stmtOut : FinalSumcheckStatementOut (L := L) (ℓ := ℓ) := {
      ctx := stmt.ctx,
      sumcheck_target := stmt.sumcheck_target,
      challenges := stmt.challenges,
      final_constant := c
    }

    let sumcheckFinalCheck : Prop := stmt.sumcheck_target = eqTilde r stmt.challenges * c
    let finalFoldingProp := finalNonDoomedFoldingProp 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (h_le := by admit /- proof elided -/
        ) (input := ⟨stmtOut, oStmt⟩)

    sumcheckFinalCheck ∧ finalFoldingProp 

Fin.succAbove in Mathlib.Data.Fin.SuccPred

def hflatten {m : ℕ} {n : Fin m → ℕ} {α : (i : Fin m) → (j : Fin (n i)) → Sort*}
    (v : (i : Fin m) → (j : Fin (n i)) → α i j) : (k : Fin (vsum n)) → Fin.vflatten α k :=
  fflatten (F := id) v

@[inline] def succ (n : AssocNat) : AssocNat :=
  add n one

Submodule.module in Mathlib.Algebra.Module.Submodule.Defs

MvPolynomial.renameEquiv in Mathlib.Algebra.MvPolynomial.Rename

structure SumcheckMultiplierParam (L : Type) [CommRing L] (ℓ : ℕ) (Context : Type := Unit) where
  multpoly : (ctx: Context) → MultilinearPoly L ℓ

structure SparseMatrix (m n α : Type*) where
  numEntries : ℕ
  row : Fin numEntries → m
  col : Fin numEntries → n
  val : Fin numEntries → α
deriving Inhabited, DecidableEq

def QuotientUniPoly (R : Type*) [Ring R] [BEq R] := Quotient (@instSetoidUniPoly R _)

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

noncomputable def dist (C : Set (n → R)) : ℕ :=
  sInf {d | ∃ u ∈ C, ∃ v ∈ C, u ≠ v ∧ Δ₀( u, v ) ≤ d}

def generateSrs (n : ℕ) (a : ZMod p) : Vector G₁ (n + 1) × Vector G₂ 2 :=
  (towerOfExponents g₁ a n, towerOfExponents g₂ a 1)

private abbrev K (B : Finset (Fin n → F)) (i : Fin n) (α : F) : ℕ :=
  (Fi B i α).card

@[reducible]
def VectorIOP
    (Statement : Type) {ιₛ : Type} (OStatement : ιₛ → Type) (Witness : Type)
    (vPSpec : ProtocolSpec.VectorSpec n) (A : Type)
    [∀ i, OracleInterface (OStatement i)] :=
  OracleProof []ₒ Statement OStatement Witness (vPSpec.toProtocolSpec A)

@[inline, specialize]
def smul (r : R) (p : UniPoly R) : UniPoly R :=
  .mk (Array.map (fun a => r * a) p)

@[simp]
instance BTFieldIsDomain (k : ℕ) : IsDomain (BTField k) := inferInstance

def computableBasisExplicit (k : ℕ) (i : Fin (2 ^ k)) : ConcreteBTField k :=
  (Finset.univ : Finset (Fin k)).prod fun j =>
    if Nat.getBit (n := i.val) (k := j.val) == 1 then
      concreteTowerAlgebraMap (j.val + 1) k (by admit /- proof elided -/
      ) (Z (j.val + 1))
    else
      1

List.Vector.get in Mathlib.Data.Vector.Defs

def findIdxRev?_def {cond} {as : Array α} {k : Fin as.size} :
  findIdxRev? cond as = some k → cond as[k] :=

def regularElms (H : F[X][Y]) : Type :=
  {a : 𝕃 H // ∃ b : 𝒪 H, a = embeddingOf𝒪Into𝕃 _ b}

@[ext]
structure GroupRepresentation {G : Type*} [Group G] {p : ℕ} (prev : List G) (target : G) where
  exponents : List (ZMod p)
  hEq : (prev.zipWith (fun g a => g ^ a.val) exponents).prod = target

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)

Polynomial.resultant in Mathlib.RingTheory.Polynomial.Resultant.Basic

structure BinaryTowerResult (F : Type _) (k : ℕ) where
  vec : (List.Vector F (k + 1))
  instField : (Field F)
  instFintype : Fintype F
  specialElement : F
  specialElementNeZero : NeZero specialElement
  firstElementOfVecIsSpecialElement [Inhabited F] : vec.1.headI = specialElement
  instIrreduciblePoly : (Irreducible (p := (definingPoly specialElement)))
  sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y
  fieldFintypeCard : Fintype.card F = 2^(2^k)
  traceMapEvalAtRootsIs1 : TraceMapProperty F specialElement k

noncomputable def foldOracleReduction :
  OracleReduction []ₒ
    (Statement F i.castSucc) (OracleStatement D x s i.castSucc) (Witness F s d i.castSucc.castSucc)
    (Statement F i.succ) (OracleStatement D x s i.succ) (Witness F s d i.succ.castSucc)
    (pSpec D x s i) where
  prover := foldProver D x s d i
  verifier := foldVerifier D x s i

instance : AlgebraTower (BTField) where
  algebraMap := towerAlgebraMap
  commutes' := by admit /- proof elided -/

Prod.mk in Init.Prelude

def processMemoryOps (ops : List (MemoryOp ι α)) (startMem : M) : Option M :=
  ops.foldlM (fun m op =>
    match op with
    | .read ⟨i, v⟩ => if Memory.read m i = v then some m else none
    | .write ⟨i, v⟩ => some (Memory.write m i v)
  ) startMem

instance [VCVCompatible A] : ∀ i, VCVCompatible ((vPSpec.toProtocolSpec A).Challenge i) :=
  fun _ => by admit /- proof elided -/

structure SpecialElementRelation {F_prev : Type*} [Field F_prev] (t1 : F_prev)
  {F_cur : Type*} [Field F_cur] (u : F_cur) [Algebra F_prev F_cur] : Prop where
    sum_inv_eq : u + u⁻¹ = algebraMap F_prev F_cur t1
    h_u_square : u^2 = u * (algebraMap F_prev F_cur t1) + 1

def implGroupDecodeOracle [DeserializeOption G (BitVec bitLength)] :
    QueryImpl (GroupDecodeOracle ι bitLength) (StateT (GroupValTable ι G) Option) where
  impl | query _ (b, i) => fun table =>
    match DeserializeOption.deserialize b with
    | some g => some ((), table.update i (some g))
    | none => none

instance : DFunLike F α β where
  coe := DFunEquiv.equiv.toFun
  coe_injective' := DFunEquiv.equiv.injective

dotProduct in Mathlib.Data.Matrix.Mul

Polynomial.modByMonic in Mathlib.Algebra.Polynomial.Div

@[reducible]
def MlPolyEval (R : Type*) (n : ℕ) := Vector R (2 ^ n) 

@[inline, reducible]
protected def id :
    Statement.Lens OuterStmtIn OuterStmtOut OuterStmtIn OuterStmtOut :=
  PFunctor.Lens.id _

alias trivial := Statement.Lens.id

def OracleSpec.proverOracle (StmtIn : Type) {n : ℕ} (pSpec : ProtocolSpec n) :
    OracleSpec pSpec.MessageIdx :=
  fun i => (StmtIn × pSpec.Transcript i.val.castSucc, pSpec.Message i)

  partial def computePrattCertificate (n : ℕ) : Option (UnverifiedPrattCertificate n) :=
    
    if n ≤ 50 ∧ deterministicMillerRabin n then
      some (.knownPrime n)
    else do
      let fs ← factor' (n - 1)
      let a ← findWitness n fs
      let part ← computePrattPart fs
      return .of n a part
  where
    findWitness (n : ℕ) (fs : List PrimeWithMultiplicity) : Option ℕ := do
      for a in [2:n] do
        let mut ok := true
        for ⟨p, _⟩ in fs do
          if powMod a ((n - 1) / p) n = 1 then
            ok := false
            break

        if ok then
          return a

      none

def toNat (f : ValidChurchNat) : ℕ :=
  ChurchNat.toNat f.1

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

def bool (j : Fin numWires) : Gate 𝓡 numWires :=
  { qL := -1, qR := 0, qO := 0, qM := 1, qC := 0, a := j, b := j, c := j }

abbrev SEP_CHAR : Char := Char.ofNat 0

def JohnsonConditionWeak (B : Finset (Fin n → F)) (e : ℕ) : Prop :=
  let d := sInf { d | ∃ u ∈ B, ∃ v ∈ B, u ≠ v ∧ hammingDist u v = d }
  let q : ℚ := Fintype.card F
  (e : ℚ) / n < J q (d / n)

instance : ∀ i, OracleInterface ((pSpecFinalSumcheckStep (L:=L)).Message i)
  | ⟨0, _⟩ => by admit /- proof elided -/

instance : CommGroup G := IsCyclic.commGroup

def HList.toDVec (l : HList) : DVec (m := Fin l.length) (fun i => l[i].1) := fun i => l[i].2

class ProverLast (pSpec : ProtocolSpec n) [inst : NeZero n] where
  prover_last' : pSpec.dir ⟨n - 1, by admit /- proof elided -/
  ⟩ = .P_to_V

@[ext]
structure Extractor.Lens (OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                          OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type) where
  stmt : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
  wit : Witness.InvLens OuterStmtIn OuterWitIn OuterWitOut InnerWitIn InnerWitOut

@[reducible]
def C : R →+* P := algebraMap R P

noncomputable def restrictLinear [Semiring F] (S : Finset ι) :
  (ι → F) →ₗ[F] (S → F) :=
{ toFun := fun f i => f i.1,
  map_add' := by admit /- proof elided -/

def commit (v : α) : OracleComp (oSpec α β γ) γ := do
  let r : β ← liftComp
    (query (spec := randSpec β) () () : OracleComp (randSpec β) β) _
  let cm : γ ← liftComp
    (query (spec := ROspec α β γ) () (v, r) : OracleComp (ROspec α β γ) γ) _
  return cm

def hiding' (scheme : Scheme oSpec Data Randomness Commitment pSpec) : Prop := sorry

def lagrangeBasis (w : Vector R n) : Vector R (2 ^ n) :=
  Vector.ofFn (fun i => ∏ j : Fin n, if (BitVec.ofFin i).getLsb j then w[j] else 1 - w[j])

def roundRelation (i : Fin (ℓ + 1)) :
    Set ((Statement (L := L) Context i ×
      (∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i j)) ×
      Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) :=
  { input | roundRelationProp (mp := mp) (𝓑 := 𝓑) 𝔽q β i input}

Algebra.TensorProduct.leftAlgebra in Mathlib.RingTheory.TensorProduct.Basic

def proverOutput (i : Fin n) : ProverOutput oSpec
    ((StatementRound R n i.succ × (∀ i, OracleStatement R n deg i)) × Unit)
    ((proverState R n deg i).PrvState (Fin.last 2)) where
  output := fun x => pure (x, ())

Mathlib.Meta.NormNum.instAddMonoidWithOne in Mathlib.Tactic.NormNum.Result

def SumFunEquivProd (α β γ : Type) : ((α ⊕ β) → γ) ≃ (α → γ) × (β → γ) :=
{ toFun := fun f => (fun a => f (.inl a), fun b => f (.inr b))
  , invFun := fun p x => match x with | .inl a => p.fst a | .inr b => p.snd b
  , left_inv := by admit /- proof elided -/

def factorOutTwos (n : ℕ) : PowTwoRepr := Id.run do
  let mut two_exp := 0
  let mut odd_part := n

  while odd_part % 2 = 0 do
    two_exp := two_exp + 1
    odd_part := odd_part / 2

  return ⟨two_exp, odd_part⟩

@[reducible, simp] def OStmtIn : Unit → Type := fun _ => R⦃≤ deg⦄[X]

OracleSpec.QueryLog in VCVio.OracleComp.QueryTracking.Structures

instance instToNat {n : ℕ} : ToNat (CNat n) := match n with
  | 0 => by admit /- proof elided -/
  | .succ n => @Cayley.instToNatOfZero (CNat n) instHasSucc instZero instToNat

instance {α : Type} {s : Skeleton} :
    CoeFun (LeafData α s) fun (_ : LeafData α s) => SkeletonLeafIndex s → α where
  coe := fun tree idx => tree.get idx

@[reducible, simp] def StmtIn : Type := R

@[reducible]
def pSpecRelay : ProtocolSpec 0 := ⟨![], ![]⟩ 

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))

structure TraceMapProperty (F : Type*) [Field F] (u : F) (k : ℕ) : Prop where
  element_trace : ∑ i ∈ Finset.range (2 ^ k), u ^ (2 ^ i) = 1
  inverse_trace : ∑ i ∈ Finset.range (2 ^ k), (u⁻¹) ^ (2 ^ i) = 1

Submodule.map in Mathlib.Algebra.Module.Submodule.Map

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

HEq in Init.Prelude

Membership.mem in Init.Prelude

def finOneEquiv : MvPolynomial (Fin 1) R ≃ₐ[R] Polynomial R :=
  (finSuccEquiv R 0).trans (Polynomial.mapAlgEquiv (isEmptyAlgEquiv R (Fin 0)))

@[inline]
def zero [Zero R] : MlPolyEval R n := Vector.replicate (2 ^ n) 0

class VCVCompatible (α : Type*) extends Fintype α, Inhabited α where
  [type_decidableEq' : DecidableEq α]

minpoly in Mathlib.FieldTheory.Minpoly.Basic

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

NNRat in Mathlib.Data.Rat.Init

def rootsOfUnity (n s : ℕ) : List (Domain.evalDomain D (n - s)) :=
  List.map
    (fun i =>
      ⟨
        (DIsCyclicC.gen.1 ^ (2 ^ (n - s))) ^ i,
        by admit /- proof elided -/
      ⟩
    )
    (List.range (2 ^ s))

Fin.isValue in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Fin

def churchRec {α : Type} (n : ChurchNat α) (step : α → α) (base : α) : α :=
  n step base

abs in Mathlib.Algebra.Order.Group.Unbundled.Abs

def lastBlockOracleVerifier :=
  let bIdx := ℓ / ϑ - 1
  let stmt : Fin (ϑ + 1) → Type := fun i => Statement (L := L) (ℓ:=ℓ) Context
    ⟨bIdx * ϑ + i, by admit /- proof elided -/
    ⟩
  let oStmt := fun i: Fin (ϑ + 1) => OracleStatement 𝔽q β ϑ
    ⟨bIdx * ϑ + i, by admit /- proof elided -/
    ⟩
  let V:  OracleVerifier []ₒ (StmtIn := Statement (L := L) (ℓ := ℓ) Context
      ⟨bIdx * ϑ, by admit /- proof elided -/
      ⟩)
    (OStmtIn := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ
      ⟨bIdx * ϑ, by admit /- proof elided -/
      ⟩)
    (StmtOut := Statement (L := L) (ℓ := ℓ) Context (Fin.last ℓ))
    (OStmtOut := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (pSpec := pSpecLastBlock (L:=L) (ϑ:=ϑ)) := by admit /- proof elided -/

@[reducible, inline]
instance instMvPolynomial : OracleInterface (R[X σ]) where
  Query := σ → R
  Response := R
  answer := fun poly point => eval point poly

right_inv in ToMathlib.Control.Monad.Equiv

def modSum {m : ℕ} {n : Fin m → ℕ} (k : Fin (∑ j, n j)) : Fin (n (divSum k)) :=
  ⟨k - ∑ j, n (Fin.castLE (divSum k).isLt.le j), by admit /- proof elided -/
    ⟩

def ofMessagesChallenges (messages : MessagesUpTo k pSpec)
    (challenges : ChallengesUpTo k pSpec) : Transcript k pSpec :=
  fun i => match h : pSpec.dir (i.castLE (by admit /- proof elided -/
  )) with
  | Direction.P_to_V => messages ⟨i.castLE (by admit /- proof elided -/
  ), h⟩
  | Direction.V_to_P => challenges ⟨i.castLE (by admit /- proof elided -/
  ), h⟩

Nat.decLt in Init.Prelude

@[reducible]
def forwardPermutationOracle (α : Type*) : OracleSpec Unit := α →ₒ α

noncomputable def fullRbrKnowledgeError (i : (fullPSpec 𝔽q β γ_repetitions (ϑ := ϑ)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).ChallengeIdx) : ℝ≥0 :=
  Sum.elim (f := CoreInteraction.coreInteractionOracleRbrKnowledgeError 𝔽q β (ϑ:=ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (g := QueryPhase.queryRbrKnowledgeError 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (ChallengeIdx.sumEquiv.symm i)

List.mapM in Init.Data.List.Control

abbrev PermuteDir := Unit ⊕ Unit

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

@[reducible]
def ROspec (α β γ : Type) : OracleSpec Unit := fun _ => (α × β, γ)

@[ext]
structure Prover {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn WitIn StmtOut WitOut : Type)
    {n : ℕ} (pSpec : ProtocolSpec n) extends
      ProverState n,
      ProverInput StmtIn WitIn (PrvState 0),
      ProverRound oSpec pSpec,
      ProverOutput oSpec (StmtOut × WitOut) (PrvState (Fin.last n))

def ζ (R : F[X][X][Y]) (x₀ : F) (H : F[X][Y]) [H_irreducible : Fact (Irreducible H)] : 𝕃 H :=
  let W  : 𝕃 H := liftToFunctionField (H.leadingCoeff);
  let T : 𝕃 H := liftToFunctionField (Polynomial.X);
    Polynomial.eval₂ liftToFunctionField (T / W)
      (Bivariate.evalX (Polynomial.C x₀) R.derivative)

instance {G} [Pow G ℤ] [inst : IsCyclicWithGen G] : IsCyclic G where
  exists_zpow_surjective := ⟨inst.gen, inst.zpow_surjective⟩

IsCyclic in Mathlib.Algebra.Group.Defs

Array.mk in Init.Prelude

@[simp]
def BTFieldCard (k : ℕ) : Fintype.card (BTField k) = 2^(2^k)
  := (BinaryTowerAux k).2.fieldFintypeCard

def ConstraintSystem (𝓡 : Type) (numWires numGates : ℕ) := Fin numGates → Gate 𝓡 numWires

def binding (scheme : Scheme oSpec Data Randomness Commitment pSpec)
    (bindingError : ℝ≥0) : Prop :=
  ∀ AuxState : Type,
  ∀ adversary : BindingAdversary oSpec Data Commitment AuxState,
  ∀ prover : Prover oSpec (Commitment × O.Query × O.Response) AuxState Bool Unit pSpec,
    False

def rootMultiplicity.{u} {F : Type u} [CommSemiring F] [DecidableEq F]
  (f : F[X][Y]) (x y : F) : Option ℕ :=
  let X := (Polynomial.X : Polynomial F)
  rootMultiplicity₀ (F := F) ((f.comp (Y + (C (C y)))).map (Polynomial.compRingHom (X + C x)))

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

Int.natAbs in Init.Data.Int.Basic

Monad in Init.Prelude

@[inline, specialize]
def Prover.processRoundFS [∀ i, VCVCompatible (pSpec.Challenge i)] (j : Fin n)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (currentResult : OracleComp (oSpec ++ₒ fsChallengeOracle StmtIn pSpec)
      (pSpec.MessagesUpTo j.castSucc × StmtIn × prover.PrvState j.castSucc)) :
      OracleComp (oSpec ++ₒ fsChallengeOracle StmtIn pSpec)
        (pSpec.MessagesUpTo j.succ × StmtIn × prover.PrvState j.succ) := do
  let ⟨messages, stmtIn, state⟩ ← currentResult
  match hDir : pSpec.dir j with
  | .V_to_P => do
    let f ← prover.receiveChallenge ⟨j, hDir⟩ state
    let challenge ← query (spec := fsChallengeOracle StmtIn pSpec) ⟨j, hDir⟩ ⟨stmtIn, messages⟩
    return ⟨messages.extend hDir, stmtIn, f challenge⟩
  | .P_to_V => do
    let ⟨msg, newState⟩ ← prover.sendMessage ⟨j, hDir⟩ state
    return ⟨messages.concat hDir msg, stmtIn, newState⟩

Subgroup in Mathlib.Algebra.Group.Subgroup.Defs

MvPolynomial.restrictDegree in Mathlib.RingTheory.MvPolynomial.Basic

def foldMatrix (i : Fin r) (steps : Fin (ℓ + 1)) (h_i_add_steps : i.val + steps < ℓ + 𝓡)
    (y : (sDomain 𝔽q β h_ℓ_add_R_rate)
      ⟨↑i + steps, by apply Nat.lt_trans (m := ℓ + 𝓡) (h_i_add_steps) h_ℓ_add_R_rate⟩)
    : Matrix (Fin (2 ^ steps.val)) (Fin (2 ^ steps.val)) L :=

def Reduction.duplexSpongeFiatShamir (R : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec) :
    NonInteractiveReduction (∀ i, pSpec.Message i) (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      StmtIn WitIn StmtOut WitOut where
  prover := R.prover.duplexSpongeFiatShamir
  verifier := R.verifier.duplexSpongeFiatShamir

Array.reverse in Init.Data.Array.Basic

BitVec.extractLsb' in Init.Data.BitVec.Basic

instance : Zero (DuplexSponge U C) where
  zero := {
    state := 0,
    absorbPos := 0,
    squeezePos := 0
  }

@[inline]
def seqCompose {m : ℕ}
    (Stmt : Fin (m + 1) → Type) {ιₛ : Fin (m + 1) → Type} (OStmt : (i : Fin (m + 1)) → ιₛ i → Type)
    (Wit : Fin (m + 1) → Type) {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (P : (i : Fin m) →
      OracleProver oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Wit i.castSucc)
        (Stmt i.succ) (OStmt i.succ) (Wit i.succ) (pSpec i)) :
    OracleProver oSpec (Stmt 0) (OStmt 0) (Wit 0) (Stmt (Fin.last m)) (OStmt (Fin.last m))
      (Wit (Fin.last m)) (seqCompose pSpec) :=
  Prover.seqCompose (fun i => Stmt i × (∀ j, OStmt i j)) Wit P

def verifyProof {α} [DecidableEq α] {s}
    (idx : BinaryTree.SkeletonLeafIndex s) (leafValue : α) (rootValue : α)
    (proof : List α) : OracleComp (spec α) Unit := do
  let putative_root ← getPutativeRoot idx leafValue proof
  guard (putative_root = rootValue)

def numQueries (stmt : StmtIn) (challenges : ∀ i, pSpec.Challenge i)
    (verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec) :
  OracleComp (oSpec ++ₒ ([OStmtIn]ₒ ++ₒ [pSpec.Message]ₒ)) ℕ := sorry

def evalX (a : F) (f : F[X][Y]) : Polynomial F :=
  ⟨Finsupp.mapRange (Polynomial.eval a) eval_zero f.toFinsupp⟩

def monomialXY (n m : ℕ) : F →ₗ[F] F[X][Y] where
  toFun t := ⟨Finsupp.single m ⟨(Finsupp.single n t)⟩⟩
  map_add' x y := by admit /- proof elided -/

Or.inl in Init.Prelude

instance {ι : Type} : OracleInterface (OracleStatement ι F ()) := OracleInterface.instFunction

@[reducible]
def batchSpec (F : Type) (m : ℕ) : ProtocolSpec 1 := ⟨!v[.V_to_P], !v[Fin m → F]⟩

List.ranges in Mathlib.Data.List.Range

instance {ι : Type} : OracleInterface (OracleStatement ι F ()) := OracleInterface.instFunction

Fin.mk in Init.Prelude

List.mapM' in Init.Data.List.Monadic

instance [Zero T] [ToNat T] : LT (Cayley T) where
  lt := lt

OracleComp in VCVio.OracleComp.OracleComp

Finset.map in Mathlib.Data.Finset.Image

def oracleVerifier (i : Fin n) : OracleVerifier oSpec (StatementRound R n i.castSucc)
    (OracleStatement R n deg) (StatementRound R n i.succ) (OracleStatement R n deg) (pSpec R deg) :=
  (Simple.oracleVerifier R deg D oSpec).liftContext (oStmtLens R n deg D i)

def finUInt32Equiv : Fin (2 ^ 32) ≃ UInt32 where
  toFun := fun i => UInt32.ofFin i
  invFun := fun u => u.toFin
  left_inv _ := rfl
  right_inv _ := rfl

def quotient (f g : F[X][Y]) : Prop := ∃ q : F[X][Y], g = q * f

BitVec.extractLsb in Init.Data.BitVec.Basic

@[inline, reducible]
def idWit {stmtLens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut} :
    Extractor.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                OuterWitIn OuterWitOut OuterWitIn OuterWitOut where
  stmt := stmtLens
  wit := Witness.InvLens.id

alias trivialWit := Extractor.Lens.idWit

@[reducible]
def OracleStatement (ι F : Type) : Unit → Type :=
    fun _ => ι → F

def ofFlatten {m n : ℕ} (v : Vector α (m * n)) : Matrix α m n :=
  (Vector.finRange m).map (fun i => (v.extract (i.val * n) (i.val * n + n)).cast
    (by admit /- proof elided -/
      ))

Decidable in Init.Prelude

@[reducible, simp]
def mapOStmt (oStmtIn : ∀ i, OStmtIn i) : ∀ i, OStmtOut i := fun i => (hEq i) ▸ oStmtIn (embedIdx i)

def duplexSpongeHybridOracle : OracleSpec pSpec.ChallengeIdx :=
  fun i =>
    ⟨StmtIn × ((j : pSpec.MessageIdx) → (j.1 < i.1) → Vector U (pSpec.Lₚᵢ j)),
    Vector U (pSpec.Lᵥᵢ i)⟩

alias «𝒟_Σ» := duplexSpongeHybridOracle

instance instDCastPSigma : DCast ((a : α) ×' β a) (fun a => γ a.1 a.2) where
  dcast hab c := dcast₂ (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) c
  dcast_id := by admit /- proof elided -/

@[reducible] def NonInteractiveProver (Message : Type) {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn WitIn StmtOut WitOut : Type) :=
  Prover oSpec StmtIn WitIn StmtOut WitOut ⟨!v[.P_to_V], !v[Message]⟩

GaloisField.equivZmodP in Mathlib.FieldTheory.Finite.GaloisField

def relHammingDistRange (ι : Type*) [Fintype ι] : Set ℚ≥0 :=
  {d : ℚ≥0 | ∃ d' : ℕ, d' ≤ Fintype.card ι ∧ d = d' / Fintype.card ι}

inductive Skeleton where
  | leaf : Skeleton
  | internal : Skeleton → Skeleton → Skeleton

def ofFinMatrix {m n : ℕ} (matrix : _root_.Matrix (Fin m) (Fin n) α) : Matrix α m n :=
  Vector.ofFn (fun i => Vector.ofFn (fun j => matrix i j))

def addCast {n : ℕ} (m : ℕ) (i : Fin n) : Fin (m + n) := ⟨i, Nat.lt_add_left m i.2⟩

def verifyNeOne (n a' q : Q(ℕ)) (a : Q(ZMod $n)) (_ : Q(($a' : ZMod $n) = $a)) :
    MetaM Q($a ^ (($n - 1) / $q) ≠ 1) := do
  
  let p : Q(ZMod $n) := q($a ^ (($n - 1) / $q))
  let .isNat _ c hc ← Tactic.ReduceModChar.normIntNumeral n p
    q(CommRing.toRing) q(ZMod.charP $n) | failure
  
  
  
  assumeInstancesCommute
  have hn : Q(decide ($n ≥ 2) = true) := (q(Eq.refl true) : Expr)
  have hc₁ : Q(decide ($c < $n) = true) := (q(Eq.refl true) : Expr)
  have hc₂ : Q(decide ($c ≠ 1) = true) := (q(Eq.refl true) : Expr)
  return q(ZMod.blub $a $hn $hc₁ $hc₂ $hc)

Polynomial.derivative in Mathlib.Algebra.Polynomial.Derivative

def listDecodable (C : Code ι F) (r : ℝ) (ℓ : ℝ) : Prop :=
  ∀ y : ι → F, listOfCloseCodewordsRel C y r ≤ ℓ

abbrev Field := ZMod fieldSize

def sumcheckFoldKnowledgeError := fun j : (pSpecSumcheckFold 𝔽q β (ϑ:=ϑ)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).ChallengeIdx =>
    if hj: (j.val % NBlockMessages (ϑ:=ϑ)) % 2 = 1 then
      foldKnowledgeError 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        ⟨j / NBlockMessages (ϑ:=ϑ) * ϑ + ((j % NBlockMessages (ϑ:=ϑ)) / 2 + 1), by admit /- proof elided -/
        ⟩ ⟨1, rfl⟩
    else 0 

inductive Lit where
  | scalar (val : F)
  
  
  | vector (len : Nat) (v : Fin len → F)

instance instEquivalenceEquiv : Equivalence (equiv (R := R)) where
  refl := equiv_refl
  symm := equiv_symm
  trans := equiv_trans

Set in Mathlib.Data.Set.Defs

@[inline]
def smul [Mul R] (r : R) (p : MlPolyEval R n) : MlPolyEval R n := p.map (fun a => r * a)

OracleSpec.QueryLog.inr in VCVio.OracleComp.QueryTracking.Structures

@[inline, specialize]
def neg (p : UniPoly R) : UniPoly R := p.map (fun a => -a)

instance {k : Fin 1} : Unique (ChallengesUpTo k (default : ProtocolSpec 0)) where
  default := fun i => ()
  uniq := by admit /- proof elided -/

Finset.fold in Mathlib.Data.Finset.Fold

def oracleReduction.firstMessage :
    OracleReduction oSpec
      (Statement R pp) (OracleStatement R pp) (Witness R pp)
      (Statement.AfterFirstMessage R pp) (OracleStatement.AfterFirstMessage R pp) Unit
      ⟨!v[.P_to_V], !v[Witness R pp]⟩ :=
  SendSingleWitness.oracleReduction oSpec
    (Statement R pp) (OracleStatement R pp) (Witness R pp)

OracleSpec.SubSpec in VCVio.OracleComp.Coercions.SubSpec

inductive LeafData (α : Type) : Skeleton → Type
  | leaf (value : α) : LeafData α Skeleton.leaf
  | internal {left right} (leftData : LeafData α left) (rightData : LeafData α right) :
      LeafData α (Skeleton.internal left right)
  deriving Repr

Finset.Icc in Mathlib.Order.Interval.Finset.Defs

def toMvPolynomial (p : MlPoly R n) : R[X Fin n] :=
  ∑ i : Fin (2 ^ n), MvPolynomial.monomial (monomialOfNat i) (a:=p[i])

def queryCodeword (k : ℕ) (s : Fin (k + 1) → ℕ+) {i : Fin (k + 1)}
      (w : evalDomain D x (∑ j' ∈ (List.take i.1 (List.finRange (k + 1))).toFinset, (s j').1)) :
    OracleComp [FinalOracleStatement D x s]ₒ F :=
      OracleComp.lift <| by
        simpa using
          OracleSpec.query
            (spec := [FinalOracleStatement D x s]ₒ)
            ⟨i.1, Nat.lt_succ_of_lt i.2⟩
            (by admit /- proof elided -/
            )

noncomputable def batchProver :
  OracleProver []ₒ
    Unit (OracleStatement D x m) (Witness F s d m)
    ((Fin m → F) × Fri.Spec.Statement F (0 : Fin (k + 1)))
      (OracleStatement D x m) (Fri.Spec.Witness F s d (0 : Fin (k + 2)))
    (batchSpec F m) where
  PrvState
  | 0 => (∀j, OracleStatement D x m j) × Witness F s d m
  | 1 => (Fin m → F) × (∀j, OracleStatement D x m j) × Fri.Spec.Witness F s d (0 : Fin (k + 2))

  input := fun i => ⟨i.1.2, i.2⟩

  sendMessage
  | ⟨0, h⟩ => nomatch h

  receiveChallenge
  | ⟨0, _⟩ => fun ⟨os, ps⟩ => pure <|
    fun (cs : Fin m → F) =>
      ⟨cs, os,
        ⟨
          ps 0 + ∑ i, Polynomial.C (cs i) * (ps i.succ).1,
          by admit /- proof elided -/
        ⟩
      ⟩

  output := fun ⟨cs, os, p⟩ => pure <|
    ⟨⟨⟨cs, Fin.elim0⟩, os⟩, p⟩

class IsPerfectComplete (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec) where
  is_perfect_complete : perfectCompleteness init impl relIn relOut reduction

@[reducible]
def proverState (i : Fin n) : ProverState 2 where
  PrvState
  | 0 => (StatementRound R n i.castSucc) × (∀ i, OracleStatement R n deg i)
  | 1 => (StatementRound R n i.castSucc) × (∀ i, OracleStatement R n deg i)
  | 2 => (StatementRound R n i.succ) × (∀ i, OracleStatement R n deg i)

@[reducible]
def combineMap : StmtIn × WitIn → OracleComp oSpec (StmtOut × WitOut) :=
  fun ⟨stmt, wit⟩ => do return (← mapStmt stmt, ← mapWit stmt wit)

NatCast in Init.Data.Cast

Module.Basis.baseChange in Mathlib.LinearAlgebra.TensorProduct.Basis

instance (k : ℕ) : HMul (ConcreteBTField k) (ConcreteBTField k) (ConcreteBTField k)
  where hMul := concrete_mul

noncomputable def funcQuotient (f : ι → F) (S : Finset F) (Ans Fill : S → F) : ι → F :=
  fun x =>
    if hx : x.val ∈ S then Fill ⟨x.val, hx⟩ 
    else (f x - (ansPoly S Ans).eval x.val) / (vanishingPoly S).eval x.val

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)

def inputRelation :
    Set
      (
        (Unit × (∀ j, OracleStatement D x m j)) ×
        Witness F s d m
      ) := sorry

Nat.digits in Mathlib.Data.Nat.Digits.Defs

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

instance [ProverFirst pSpec] : ∀ i, VCVCompatible (pSpec.Challenge i) := isEmptyElim

@[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

instance : ∀ j, OracleInterface ((pSpec F).Message j)
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => by admit /- proof elided -/

noncomputable def novelToMonomialCoeffs

  (ℓ : ℕ) (h_ℓ : ℓ ≤ r) (novel_coeffs : Fin (2 ^ ℓ) → L) : Fin (2^ℓ) → L :=
  let A := changeOfBasisMatrix 𝔽q β ℓ h_ℓ
  Matrix.vecMul novel_coeffs A

def succ (n : ChurchNat α) : ChurchNat α := fun f x => f (n f x)

structure Simulator (oSpec : OracleSpec ι) (StmtIn : Type) {n : ℕ} (pSpec : ProtocolSpec n) where
  SimState : Type
  oracleSim : SimOracle.Stateful oSpec oSpec SimState
  proverSim : StmtIn → StateT SimState (OracleComp oSpec) pSpec.FullTranscript

def codeOfLinearCode (κ : Type*) [Fintype κ] (LC : LinearCode ι F) : InterleavedCode κ ι F :=
  { MF := matrixSubmoduleOfLinearCode κ LC, LC := LC }

FiniteDimensional in Mathlib.LinearAlgebra.FiniteDimensional.Defs

def deriveTranscriptSR {ι : Type} {oSpec : OracleSpec ι} {StmtIn : Type}
    (stmt : StmtIn) (k : Fin (n + 1)) (messages : pSpec.MessagesUpTo k) :
    OracleComp (oSpec ++ₒ fsChallengeOracle StmtIn pSpec) (pSpec.Transcript k) := do
  deriveTranscriptSRAux stmt k messages (Fin.last k)

alias deriveTranscriptFS := deriveTranscriptSR

def oracleReduction.sendClaim : OracleReduction oSpec (StmtIn R) (OStmtIn R deg) Unit
    (StmtAfterSendClaim R) (OStmtAfterSendClaim R deg) Unit ⟨!v[.P_to_V], !v[R⦃≤ deg⦄[X]]⟩ := sorry

def equivBool : Direction ≃ Bool where
  toFun := fun dir => match dir with | .V_to_P => false | .P_to_V => true
  invFun := fun b => match b with | false => .V_to_P | true => .P_to_V
  left_inv := fun dir => match dir with | .P_to_V => rfl | .V_to_P => rfl
  right_inv := fun b => match b with | false => rfl | true => rfl

cond in Init.Prelude

def eval₂AlgHom {A B : Type*} [CommSemiring A] [CommSemiring B] [MvPolynomialLike σ A P]
    [Algebra R A] [IsScalarTower R A P] [Algebra R B]
    (f : A →ₐ[R] B) (g : σ → B) : P →ₐ[R] B where
  toRingHom := eval₂ f g
  commutes' r := by admit /- proof elided -/

def foldKnowledgeStateFunction (i : Fin ℓ) :
    (foldOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i).KnowledgeStateFunction init impl
      (relIn := roundRelation (mp := mp) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i.castSucc)
      (relOut := foldStepRelOut (mp := mp) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i)
      (extractor := foldRbrExtractor (mp:=mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) where
  toFun := fun m ⟨stmt, oStmt⟩ tr witMid =>
    foldKStateProp (mp:=mp) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (i := i) (m := m) (tr := tr) (stmt := stmt) (witMid := witMid) (oStmt := oStmt)
  toFun_empty := fun _ _ => by admit /- proof elided -/

def StateRestoration.Soundness (oSpec : OracleSpec ι) (StmtIn : Type)
    {n : ℕ} (pSpec : ProtocolSpec n) :=
  OracleComp (oSpec ++ₒ (srChallengeOracle StmtIn pSpec)) (StmtIn × pSpec.Messages)

noncomputable def extractMLP (i : Fin ℓ) (f : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i, by omega⟩ → L) :
    Option (L⦃≤ 1⦄[X Fin (ℓ - i)]) :=

instance {k : Fin 1} : Unique (Transcript k (default : ProtocolSpec 0)) where
  default := fun i => ()
  uniq := by admit /- proof elided -/

def Transcript.removeSalt {k : Fin (n + 1)} (transcript : (pSpec.addSalt Salt).Transcript k) :
    pSpec.Transcript k :=

  fun i => by admit /- proof elided -/

def aeval {A : Type y} [CommSemiring A] [Algebra R A] {F : Type z} [FunEquiv F σ A] (g : F) :
    P →ₐ[R] A :=
  eval₂AlgHom (Algebra.ofId R A) g

noncomputable instance : Algebra Left (Left ⊗[K] Right) := Algebra.TensorProduct.leftAlgebra

ByteArray.mk in Init.Prelude

noncomputable def fold_k_core {S : Finset ι} {φ : ι ↪ F} (f : (indexPowT S φ 0) → F)
  [∀ i : ℕ, Neg (indexPowT S φ i)] : (i : ℕ) → (αs : Fin i → F) →
    indexPowT S φ i → F
| 0, _ => fun x₀ => f x₀
| k+1, αs => fun y =>
    let α := αs 0
    let αs' : Fin k → F := fun i => αs (Fin.succ i)
    let fk := fold_k_core f k αs'
    foldf S φ y fk α

@[inline, specialize]
def oracleProver : OracleProver oSpec
    Statement OStatement (∀ i, Witness i)
    Statement (OStatement ⊕ᵥ Witness) Unit
    (oraclePSpec Witness) where
  PrvState := fun _ => (Statement × (∀ i, OStatement i)) × (∀ i, Witness i)
  input := id
  sendMessage | ⟨0, _⟩ => fun ⟨stmt, wit⟩ => pure (wit, ⟨stmt, wit⟩)
  
  receiveChallenge | ⟨0, h⟩ => nomatch h
  output := fun ⟨⟨stmt, oStmt⟩, wit⟩ => pure (⟨stmt, Sum.rec oStmt wit⟩, ())

@[inline, specialize]
def oracleReduction :
  OracleReduction oSpec Unit (fun _ : Fin 2 => OStatement) Unit
    (Query OStatement) (fun _ : Fin 2 => OStatement) Unit (pSpec OStatement) where
  prover := oracleProver oSpec OStatement
  verifier := oracleVerifier oSpec OStatement

def collisionFwdFwd : Prop :=
  let ⟨baseTrace, _⟩ := removeRedundantEntryDS trace
  ∃ stateIn stateIn' stateOut,
    (stateIn, stateOut) ∈ baseTrace.getQ (.inr .Fwd) ∧
    (stateIn', stateOut) ∈ baseTrace.getQ (.inr .Fwd) ∧
    stateIn ≠ stateIn'

alias E_col_p := collisionFwdFwd

@[reducible]
def rateSegment (state : CanonicalSpongeState U) : Vector U SpongeSize.R :=
  
  (Vector.take state SpongeSize.R).cast (by admit /- proof elided -/
  )

@[inline, specialize, simp]
def verifier : Verifier oSpec Statement Statement !p[] := Verifier.id

def perfectCompleteness (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec) : Prop :=
  completeness init impl relIn relOut reduction 0

def StateRestoration (oSpec : OracleSpec ι)
    (StmtIn WitIn WitOut : Type) {n : ℕ} (pSpec : ProtocolSpec n) :=
  StmtIn → 
  WitOut → 
  pSpec.FullTranscript → 
  QueryLog (oSpec ++ₒ (srChallengeOracle StmtIn pSpec)) → 
  QueryLog oSpec → 
  OracleComp oSpec WitIn 

MvPolynomial.eval₂ in Mathlib.Algebra.MvPolynomial.Eval

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

AdjoinRoot.of in Mathlib.RingTheory.AdjoinRoot

Function.RightInverse in Init.Data.Function

def inputRelation [DecidableEq F] (δ : ℝ≥0) :
    Set
      (
        (Statement (k := k) F 0 × (∀ j, OracleStatement (k := k) D x s 0 j)) ×
        Witness F s d (0 : Fin (k + 2))
      ) :=
  match k with
  | 0 => FinalFoldPhase.inputRelation D x s d (round_bound dom_size_cond) δ
  | .succ _ => FoldPhase.inputRelation D x s d 0 (round_bound dom_size_cond) δ

@[reducible]
def FinalOracleStatement : Fin (k + 2) → Type :=
  fun j =>
    if j.1 = k + 1
    then (Unit → F[X])
    else (evalDomain D x (∑ j' ∈ finRangeTo j.1, s j') → F)

@[reducible, inline, specialize]
def MessageUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) (i : pSpec.MessageIdxUpTo k) :=
  (pSpec⟦:k.val⟧).Message i

@[reducible, simp]
def oraclePSpec : ProtocolSpec 1 := ⟨!v[.P_to_V], !v[Witness]⟩

  inductive UnverifiedPrattPart : Type
    | prime : (p : ℕ) → (k : ℕ) → (hp : UnverifiedPrattCertificate p) → UnverifiedPrattPart
    | split : UnverifiedPrattPart → UnverifiedPrattPart → UnverifiedPrattPart
  deriving Repr

Polynomial.eval₂RingHom in Mathlib.Algebra.Polynomial.Eval.Defs

def domainComplement (φ : ι ↪ F) : Finset F :=
  Finset.univ \ Finset.image φ.toFun Finset.univ

noncomputable def finalSumcheckKnowledgeStateFunction {σ : Type} (init : ProbComp σ)
    (impl : QueryImpl []ₒ (StateT σ ProbComp)) :
    (finalSumcheckVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).KnowledgeStateFunction init impl
    (relIn := roundRelation 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (𝓑 := 𝓑) (mp := BBF_SumcheckMultiplierParam) (Fin.last ℓ))
    (relOut := finalSumcheckRelOut 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (extractor := finalSumcheckRbrExtractor 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
  where
  toFun := fun m ⟨stmt, oStmt⟩ tr witMid =>
    finalSumcheckKStateProp 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (𝓑 := 𝓑) (tr := tr) (stmt := stmt) (witMid := witMid) (oStmt := oStmt)
  toFun_empty := fun stmt witMid => by admit /- proof elided -/

instance [AddCommMonoid R] : AddCommMonoid (MlPoly R n) where
  add := add
  add_assoc a b c := by admit /- proof elided -/

@[inline]
abbrev concat {m : Fin n} (msg : pSpec.«Type» m) (T : Transcript m.castSucc pSpec) :
    Transcript m.succ pSpec :=
  Fin.snoc T msg

def knowledgeSoundness (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec) (knowledgeError : ℝ≥0) : Prop :=
  ∃ extractor : Extractor.Straightline oSpec StmtIn WitIn WitOut pSpec,
  ∀ stmtIn : StmtIn,
  ∀ witIn : WitIn,
  ∀ prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec,
    letI reduction := Reduction.mk prover verifier
    [fun ⟨stmtIn, witIn, stmtOut, witOut⟩ =>
      (stmtIn, witIn) ∉ relIn ∧ (stmtOut, witOut) ∈ relOut
    | do
      let s ← init
      (simulateQ (impl ++ₛₒ challengeQueryImpl : QueryImpl _ (StateT σ ProbComp))
        <| do
      let ⟨⟨⟨transcript, ⟨_, witOut⟩⟩, stmtOut⟩, proveQueryLog, verifyQueryLog⟩ ←
        reduction.runWithLog stmtIn witIn
      let extractedWitIn ←
        liftComp (extractor stmtIn witOut transcript proveQueryLog.fst verifyQueryLog) _
      return (stmtIn, extractedWitIn, stmtOut, witOut)).run' s] ≤ knowledgeError

ZeroMemClass in Mathlib.Algebra.Group.Submonoid.Defs

noncomputable def finalSumcheckVerifier :
  OracleVerifier
    (oSpec := []ₒ)
    (StmtIn := Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ))
    (OStmtIn := OracleStatement 𝔽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 ℓ))
    (pSpec := pSpecFinalSumcheckStep (L := L)) where
  verify := fun stmtIn _ => do
    
    let c : L ← query (spec := [(pSpecFinalSumcheckStep (L := L)).Message]ₒ) ⟨0, rfl⟩ ()

    
    let eq_tilde_eval : L := eqTilde (r := stmtIn.ctx.t_eval_point) (r' := stmtIn.challenges)
    unless stmtIn.sumcheck_target = eq_tilde_eval * c do
      return { 
        ctx := {t_eval_point := 0, original_claim := 0},
        sumcheck_target := 0,
        challenges := 0,
        final_constant := 0
      }

    
    let stmtOut : FinalSumcheckStatementOut (L := L) (ℓ := ℓ) := {
      ctx := stmtIn.ctx,
      sumcheck_target := eq_tilde_eval * c, 
      challenges := stmtIn.challenges,
      final_constant := c
    }
    pure stmtOut

  embed := ⟨fun j => by admit /- proof elided -/
  ⟩
  hEq := fun oracleIdx => by admit /- proof elided -/

MvPolynomial.support in Mathlib.Algebra.MvPolynomial.Basic

noncomputable def disagreementSet (f : ι → F) (S : Finset F) (Ans : S → F) : Finset F :=
  Set.toFinset ({x : ι | x.val ∈ S ∧ (ansPoly S Ans).eval x.val ≠ f x}.image Subtype.val)

instance {s} : LawfulFunctor (fun α => FullData α s) :=

def numberOfClosePts (u v : ι → F) (deg : ℕ) (α : ι ↪ F) (e : ℕ) : ℕ :=
  Fintype.card (closePtsOnAffineLine u v deg α e)

instance (i : Fin 0) : OracleInterface i.elim0 := Fin.elim0 i

@[inline, specialize]
def run (stmt : StmtIn) (wit : WitIn)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ) (FullTranscript pSpec × StmtOut × WitOut) := do
  let ⟨transcript, state⟩ ← prover.runToRound (Fin.last n) stmt wit
  return ⟨transcript, ← prover.output state⟩

SMulZeroClass in Mathlib.Algebra.GroupWithZero.Action.Defs

LinearEquiv.ofBijective in Mathlib.Algebra.Module.Submodule.Equiv

@[simps!]
def MessageIdx.sumEquiv :
    MessageIdx pSpec₁ ⊕ MessageIdx pSpec₂ ≃ MessageIdx (pSpec₁ ++ₚ pSpec₂) where
  toFun := Sum.elim (MessageIdx.inl) (MessageIdx.inr)
  invFun := fun ⟨i, h⟩ => by admit /- proof elided -/

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 batchOracleReduction :
  OracleReduction []ₒ
    Unit (OracleStatement D x m) (Witness F s d m)
    ((Fin m → F) × Fri.Spec.Statement F (0 : Fin (k + 1)))
    (OracleStatement D x m)
    (Fri.Spec.Witness F s d (0 : Fin (k + 2)))
    (batchSpec F m) where
  prover := batchProver D x s d m
  verifier := batchVerifier (k := k) D x m

def absorbUnchecked [Permute C] (sponge : DuplexSponge U C) (arr : Array U) : DuplexSponge U C :=
  simulateQ' forwardPermutationOracleImpl (absorbFast sponge arr) (by admit /- proof elided -/
  )

instance : ∀ i, SelectableType (Challenge !p[] i) :=
  fun ⟨i, h⟩ =>
    (Fin.elim0 i : (h' : !p[].dir i = .V_to_P) → SelectableType (!p[].Challenge ⟨i, h'⟩)) h

def CEmbedding : R ↪ MvPolynomial σ R := ⟨C, C_injective σ R⟩

def partition (cs : ConstraintSystem 𝓡 numWires numGates) :
    Fin numWires → Finset (Fin (3 * numGates)) :=
  
  
  
  
  fun i => Finset.map (Equiv.toEmbedding finProdFinEquiv)
    (Finset.filter (fun j => if j.1 = 0 then (cs j.2).a = i
      else if j.1 = 1 then (cs j.2).b = i else (cs j.2).c = i)
    (Finset.univ : Finset (Fin 3 × Fin numGates)))

def concreteCanonicalEmbedding (k : ℕ)
    (prevBTFieldProps : ConcreteBTFieldProps (k := (k)))
    (curBTFieldProps : ConcreteBTFieldProps (k := (k + 1))) :
  letI := mkFieldInstance prevBTFieldProps
  letI := mkFieldInstance curBTFieldProps
  ConcreteBTField k →+* ConcreteBTField (k + 1) :=

Vector.zipWith in Init.Data.Vector.Basic

Char.ofNat in Init.Prelude

Set.Nontrivial in Mathlib.Data.Set.Subsingleton

instance {langIn : Set StmtIn} {langOut : Set StmtOut}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec} :
    CoeFun (verifier.StateFunction init impl langIn langOut)
    (fun _ => (m : Fin (n + 1)) → StmtIn → Transcript m pSpec → Prop) := ⟨fun f => f.toFun⟩

def bitVecToString (width : ℕ) (bv : BitVec width) : String :=
  Fin.foldl width (fun (s : String) (idx : Fin width) =>
    
    
    s.push (if BitVec.getLsb bv (Fin.rev idx) then '1' else '0')
  ) ""

def degreeX (f : F[X][Y]) : ℕ := f.support.sup (fun n => (f.coeff n).natDegree)

class IsComplete (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec)
    where
  completenessError : ℝ≥0
  is_complete : completeness init impl relIn relOut reduction completenessError

Polynomial.roots in Mathlib.Algebra.Polynomial.Roots

instance : Mul AssocNat where
  mul := mul

@[simp]
abbrev OracleStatement := R1CS.OracleStatement R pp.toSizeR1CS

@[ext]
class OracleInterface (Message : Type u) where
  Query : Type v
  Response : Type w
  answer : Message → Query → Response

@[reducible]
def foldRelayOracleReduction (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleReduction []ₒ
    (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.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) i.succ)
    (pSpec := pSpecFoldRelay (L:=L)) :=
  OracleReduction.append
    (pSpec₁ := pSpecFold (L:=L))
    (pSpec₂ := pSpecRelay)
        (foldOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) i)
    (relayOracleReduction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR)

def getLast (a : Array α) (h : a.size > 0) : α := a[a.size - 1]

CanLift in Mathlib.Tactic.Lift

Array.replicate in Init.Data.Array.Basic

Fintype.card in Mathlib.Data.Fintype.Card

def binaryAlgebraTower {l r : ℕ} (h_le : l ≤ r) : Algebra (BTField l) (BTField r) :=

System.FilePath.walkDir in Init.System.IO

def Cache (n : ℕ) := (layer : Fin (n + 1)) → List.Vector α (2 ^ layer.val)

inductive Program where

noncomputable def extract_x
  (S : Finset ι) (φ : ι ↪ F) (k : ℕ) (y : indexPowT S φ (k + 1)) : indexPowT S φ k :=
  let x := Classical.choose y.property
  let hx := Classical.choose_spec y.property
  let z := (φ x) ^ (2^k)
  ⟨z, ⟨x, hx.1, rfl⟩⟩

instance : SubSpec [pSpec₂.Challenge]ₒ ([(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ) where
  monadLift | query i t => instSubSpecOfProtocolSpecAppendChallenge.monadLift (query (Sum.inr i) t)

setOf in Mathlib.Data.Set.Defs

def drop {n : ℕ} {α : Fin n → Sort*} (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    (i : Fin (n - m)) → α (Fin.cast (Nat.sub_add_cancel h) (addNat i m)) :=
  fun i ↦ v (Fin.cast (Nat.sub_add_cancel h) (addNat i m))

def outputRelation : Set ((StmtOut R × (∀ i, OStmtOut R deg i)) × Unit) :=
  { ⟨⟨⟨newTarget, chal⟩, oStmt⟩, _⟩ | (oStmt ()).1.eval chal = newTarget }

def projectToMidSumcheckPoly (t : MultilinearPoly L ℓ)
    (m : MultilinearPoly L ℓ) (i : Fin (ℓ + 1))
    (challenges : Fin i → L)
    : MultiquadraticPoly L (ℓ-i) :=
  let H₀: MultiquadraticPoly L ℓ := computeInitialSumcheckPoly (ℓ:=ℓ) t m
  let Hᵢ := fixFirstVariablesOfMQP (ℓ := ℓ) (v := ⟨i, by admit /- proof elided -/
  ⟩)
    (H := H₀) (challenges := challenges)
  ⟨Hᵢ, by admit /- proof elided -/
  ⟩

@[reducible, inline, specialize]
def Transcript (k : Fin (n + 1)) (pSpec : ProtocolSpec n) : Type :=
  (pSpec⟦:k.val⟧).FullTranscript

noncomputable def matching_set_at_x
  (δ : ℚ)
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  (x : Fin n)
  : Finset F := @Set.toFinset _ {z : F | ∃ h : z ∈ matching_set k ωs δ u₀ u₁ h_gs,
    u₀ x + z * u₁ x = 
      (Pz (matching_set_is_a_sub_of_coeffs_of_close_proximity k h_gs h)).eval (ωs x)} sorry

noncomputable def towerRingEquiv0 : BTField 0 ≃+* ConcreteBTField 0 :=

@[ext]
structure VectorSpec (n : ℕ) where
  dir : Fin n → Direction
  length : Fin n → Nat

MvPolynomial.isEmptyAlgEquiv in Mathlib.Algebra.MvPolynomial.Equiv

def allScriptsDocumented : IO Bool := do
  \n  \
      {String.intercalate "," undocumented.toList}"
  return undocumented.size == 0

noncomputable def Pz
  {k : ℕ}
  {z : F}
  (hS : z ∈ coeffs_of_close_proximity k ωs δ u₀ u₁)
  :
  F[X]
  := (exists_Pz_of_coeffs_of_close_proximity (n := n) (k := k) hS).choose

instance : NatCast (UniPoly R) := ⟨fun n => UniPoly.C (n : R)⟩

BitVec.xor in Init.Data.BitVec.Basic

QueryImpl in VCVio.OracleComp.SimSemantics.SimulateQ

Lean.Elab.WF.paramLet in Lean.Elab.PreDefinition.WF.Preprocess

Subsingleton in Init.Core

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

structure PrattCertificate' (p : ℕ) : Type where
  a : ZMod p
  pow_eq_one : a ^ (p - 1) = 1
  part : PrattPartList p a (p - 1)

instance instDCastSigma {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    [DCast α β] [DCast₂ α β γ] : DCast ((a : α) × β a) (fun a => γ a.1 a.2) where
  dcast hab c := dcast₂ (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) c
  dcast_id := by admit /- proof elided -/

StateT in Init.Control.State

inductive PrattPartList : (p : ℕ) → (a : ZMod p) → ℕ → Prop
  | prime : {p : ℕ} → {a : ZMod p} → (n k nk : ℕ) → n.Prime →
      a ^ ((p - 1) / n) ≠ 1 → n ^ k = nk → PrattPartList p a nk
  | split : {p : ℕ} → {a : ZMod p} → {n : ℕ} → (list : List ℕ) →
      (∀ r ∈ list, PrattPartList p a r) → list.prod = n → PrattPartList p a n

def InternalData.rightSubtree {α : Type} {s_left s_right : Skeleton}
    (tree : InternalData α (Skeleton.internal s_left s_right)) :
    InternalData α s_right :=
  match tree with
  | InternalData.internal _ _left right =>
    right

IO.FS.Stream in Init.System.IO

def powAlgHom :
  MvPolynomial (Fin m) F →ₐ[F] Polynomial F :=
   aeval fun j => Polynomial.X ^ (2 ^ (j : ℕ))

def oracleVerifier (i : Fin n) : OracleVerifier oSpec
    (StatementRound R n i.castSucc) (OracleStatement R n deg)
    (StatementRound R n i.succ) (OracleStatement R n deg) (pSpec R deg) where
  
  
  
  
  verify := fun ⟨target, challenges⟩ chal => do
    let evals : List R ← (List.finRange m).mapM
      (fun i => do
        return ← query
          (spec := (oSpec ++ₒ ([OracleStatement R n deg]ₒ ++ₒ [(pSpec R deg).Message]ₒ)))
            (Sum.inr <| Sum.inr default) (D i))
    guard (evals.sum = target)
    let newTarget ← query
      (spec := (oSpec ++ₒ ([OracleStatement R n deg]ₒ ++ₒ [(pSpec R deg).Message]ₒ)))
        (Sum.inr <| Sum.inr default) (by admit /- proof elided -/
        )
    letI newTarget : R := by admit /- proof elided -/

OracleSpec.range in VCVio.OracleComp.OracleSpec

@[reducible] def NonInteractiveVerifier (Message : Type) {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn StmtOut : Type) :=
  Verifier oSpec StmtIn StmtOut ⟨!v[.P_to_V], !v[Message]⟩

noncomputable def H
  (δ : ℚ) (x₀ : F)
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : F[Z][X] := (exists_factors_with_large_common_root_set k δ x₀ h_gs).choose_spec.choose

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

alias trivial := Witness.InvLens.id

@[reducible]
def OracleStatement (i : Fin (k + 1)) : Fin (i.val + 1) → Type :=
  fun j =>
    evalDomain D x (∑ j' ∈ finRangeTo j.1, s j')
      → F

class Serialize.IsInjective (α : Type u) (β : Type v) [inst : Serialize α β] : Prop where
  serialize_inj : Function.Injective inst.serialize

instance : Fintype ((pSpec OStatement).Challenge ⟨0, by simp⟩) :=

def OracleProver.addSalt (P : OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec)
    (saltComp : (i : pSpec.MessageIdx) → P.PrvState i.1.castSucc → OracleComp oSpec (Salt i)) :
  OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut (pSpec.addSalt Salt) :=
  Prover.addSalt Salt P saltComp

def append (T₁ : FullTranscript pSpec₁) (T₂ : FullTranscript pSpec₂) :
    FullTranscript (pSpec₁ ++ₚ pSpec₂) :=
  Fin.happend T₁ T₂

instance : Fact (Nat.Prime scalarFieldSize) := ⟨ScalarField_is_prime⟩

def generateTag (iopBytes : ByteArray) : Vector UInt8 32 :=
  
  sorry

@[reducible, simp]
def completeness
    (relation : Set ((Statement × ∀ i, OStatement i) × Witness))
    (oracleProof : OracleProof oSpec Statement OStatement Witness pSpec)
    (completenessError : ℝ≥0) : Prop :=
  OracleReduction.completeness init impl
    relation acceptRejectOracleRel oracleProof completenessError

def IsBerlekampWelchSolution
  (e k : ℕ)
  (ωs f : Fin n → F)
  (v : Fin (2 * e + k) → F)
  : Prop
  := Matrix.mulVec (BerlekampWelchMatrix e k ωs f) v = Rhs e ωs f

def distFromCode' (C : Set (n → R)) [Fintype C] (u : n → R) : ℕ∞ :=
  Finset.min <| (@Finset.univ C _).image (fun v => hammingDist u v.1)

def snd (T : (pSpec₁ ++ₚ pSpec₂).Transcript k) : pSpec₂.Transcript ⟨k - m, by admit /- proof elided -/
⟩ :=
  if hk : k ≤ m then
    fun i => Fin.elim0 (by admit /- proof elided -/
    )
  else
    fun i => sorry

Polynomial.evalEvalRingHom in Mathlib.Algebra.Polynomial.Bivariate

@[reducible]
def pSpec : ProtocolSpec 2 :=
  ⟨
    !v[.V_to_P, .P_to_V],
    !v[
        F,
        (evalDomain D x (∑ j' ∈ (List.take (i.1 + 1) (List.finRange (k + 1))).toFinset, s j')) → F
      ]
  ⟩

MvPolynomial in Mathlib.Algebra.MvPolynomial.Basic

def fconcat {A : Sort u} {F : A → Sort v} {n : ℕ} {α : Fin n → A} {β : A}
    (u : (i : Fin n) → F (α i)) (a : F β) : (i : Fin (n + 1)) → F (Fin.vconcat α β i) :=
  match n with
  | 0 => fun i => match i with | 0 => a
  | _ + 1 => fcons (u 0) (fconcat (fun i => u (Fin.succ i)) a)

@[reducible]
def pSpecFoldCommit (i : Fin ℓ) : ProtocolSpec (3) :=
  pSpecFold (L:=L) ++ₚ pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i

Char in Init.Prelude

def SkeletonNodeIndex.rightChild {s : Skeleton} (idx : SkeletonNodeIndex s) :
    Option (SkeletonNodeIndex s) :=
  match idx with
  | SkeletonNodeIndex.ofLeaf => none
  | @SkeletonNodeIndex.ofInternal left right =>
    some (SkeletonNodeIndex.ofRight (getRootIndex right))
  | SkeletonNodeIndex.ofLeft idxLeft =>
    idxLeft.rightChild.map (SkeletonNodeIndex.ofLeft)
  | SkeletonNodeIndex.ofRight idxRight =>
    idxRight.rightChild.map (SkeletonNodeIndex.ofRight)

Finset.min in Mathlib.Data.Finset.Max

noncomputable def queryVerifier (k_le_n : (∑ j', (s j').1) ≤ n) (l : ℕ) [DecidableEq F] :
  OracleVerifier []ₒ
    (FinalStatement F k) (FinalOracleStatement D x s)
    (FinalStatement F k) (FinalOracleStatement D x s)
    (pSpec D x l) where
  verify := fun prevChallenges roundChallenge => do
    let (p : F[X]) ← getConst D x k s
    for m in (List.finRange l) do
      let s₀ := roundChallenge ⟨1, by admit /- proof elided -/
      ⟩ m
      discard <|
        (List.finRange (k + 1)).mapM
              (fun i =>
                do
                  let x₀ := prevChallenges i
                  let s₀ :
                    evalDomain D x
                      (∑ j' ∈ finRangeTo i.1, (s j').1) :=
                    ⟨_, pow_2_pow_i_mem_Di_of_mem_D _ s₀.2⟩
                  let queries :
                    List (
                      evalDomain D x
                        (∑ j' ∈ finRangeTo i.1, (s j').1)
                    ) :=
                    List.map
                      (fun r =>
                        ⟨
                          _,
                          CosetDomain.mul_root_of_unity D (roots_of_unity_lem k_le_n) s₀.2 r.2
                        ⟩
                      )
                      (Domain.rootsOfUnity D n (s i))
                  let (pts : List (F × F)) ←
                    List.mapM
                      (fun q => queryCodeword D x k s q >>= fun v => pure (q.1.1, v))
                      queries
                  let β ←
                    if h : i.1 < k
                    then
                      have := CosetDomain.pow_lift D x (s i).1 s₀.2
                      queryCodeword D x k s (i := ⟨i.1.succ, Order.lt_add_one_iff.mpr h⟩)
                        ⟨_, by admit /- proof elided -/
                        ⟩
                    else
                      pure (p.eval (s₀.1.1 ^ (2 ^ (s (Fin.last k)).1)))
                  guard (RoundConsistency.roundConsistencyCheck x₀ pts β)
              )
    pure prevChallenges
  embed :=
    ⟨
      fun j => Sum.inl j,
      by admit /- proof elided -/
    ⟩
  hEq := by admit /- proof elided -/

Tactic.ReduceModChar.normIntNumeral in Mathlib.Tactic.ReduceModChar

noncomputable def toPoly' (p : UniPoly R) : Polynomial R :=
  Polynomial.ofFinsupp (Finsupp.onFinset (Finset.range p.size) p.coeff (by admit /- proof elided -/
  ))

protected def cast (V : Verifier oSpec StmtIn StmtOut pSpec₁) :
    Verifier oSpec StmtIn StmtOut pSpec₂ where
  verify := fun stmt transcript => V.verify stmt (dcast₂ hn.symm (dcast_symm hn hSpec) transcript)

abbrev BTF₃ := ConcreteBTField 3 

def InnerStmtOut_Test := ℤ[X] × ℤ × ℤ

Fin.succ in Init.Data.Fin.Basic

def monoToLagrange_segment (n : ℕ) (r : Fin n) (l : Fin (r.val + 1)) :
    Vector R (2 ^ n) → Vector R (2 ^ n) :=
  let range := forwardRange n r l
  (range.foldl (fun acc h => monoToLagrangeLevel h acc))

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

noncomputable def liftedFRI [DecidableEq F] :
  OracleReduction []ₒ
    ((Fin m → F) × Fri.Spec.Statement F (0 : Fin (k + 1)))
      (OracleStatement D x m) (Fri.Spec.Witness F s d 0)
    (Fri.Spec.FinalStatement F k)
      (Fri.Spec.FinalOracleStatement D x s) (Fri.Spec.Witness F s d (Fin.last (k + 1)))
    (
      Fri.Spec.pSpecFold D x k s ++ₚ
      Fri.Spec.FinalFoldPhase.pSpec F ++ₚ
      Fri.Spec.QueryRound.pSpec D x l
    ) :=
    OracleReduction.liftContext
      (liftingLens D x k s d m)
      (Fri.Spec.reduction D x k s d dom_size_cond l)

def verifier (i : Fin n) : Verifier oSpec
    ((StatementRound R n i.castSucc) × (∀ i, OracleStatement R n deg i))
    (StatementRound R n i.succ × (∀ i, OracleStatement R n deg i)) (pSpec R deg) where
  verify := fun ⟨⟨target, challenges⟩, oStmt⟩ transcript => do
    let ⟨p_i, _⟩ : R⦃≤ deg⦄[X] := transcript 0
    let r_i : R := transcript 1
    guard (∑ x ∈ (univ.map D), p_i.eval x = target)
    pure ⟨⟨p_i.eval r_i, Fin.snoc challenges r_i⟩, oStmt⟩

def eval (x : Fin numWires → 𝓡) (g : Gate 𝓡 numWires) : 𝓡 :=
  g.qL * x g.a + g.qR * x g.b + g.qO * x g.c + g.qM * (x g.a * x g.b) + g.qC

def Cache.upper (n : ℕ) (cache : Cache α (n + 1)) :
    Cache α n :=
  Fin.init cache

def params24 : Params where
  width := 24
  numFullRounds := 8
  numPartialRounds := 23
  internalDiagVectors := #v[
        -2,
        1,
        2,
        1 / 2,
        3,
        4,
        -1 / 2,
        -3,
        -4,
        1 / (2 ^ 8),
        1 / 4,
        1 / 8,
        1 / 16,
        1 / 32,
        1 / 64,
        1 / (2 ^ 24),
        -1 / (2 ^ 8),
        -1 / 8,
        -1 / 16,
        -1 / 32,
        -1 / 64,
        -1 / (2 ^ 7),
        -1 / (2 ^ 9),
        -1 / (2 ^ 24)
    ]
  roundConstants := RAW_CONSTANTS_24
  width_dvd_by_4 := by admit /- proof elided -/

Infinite in Mathlib.Data.Finite.Defs

@[reducible] def NonInteractiveReduction (Message : Type) {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn WitIn StmtOut WitOut : Type) :=
  Reduction oSpec StmtIn WitIn StmtOut WitOut ⟨!v[.P_to_V], !v[Message]⟩

def relayKStateProp (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i)
  (stmtIn : Statement (L := L) Context i.succ)
  (witMid : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
  (oStmtIn : (∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j))
  : Prop :=
  masterKStateProp (mp := mp) (ϑ := ϑ) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
    (stmtIdx := i.succ) (oracleIdx := i.succ)
    (h_le := le_refl _)
    (stmt := stmtIn) (wit := witMid) (oStmt := mapOStmtOutRelayStep
      𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR oStmtIn)
    (localChecks := True)

noncomputable def evenize (f : Polynomial F) : Polynomial F :=
  match f with
  | ⟨⟨supp, g, h⟩⟩ => ⟨⟨mul_by_2 supp, fun n => if Even n then g (n / 2) else 0, by admit /- proof elided -/
  ⟩⟩

def commitKStateProp (i : Fin ℓ) (m : Fin (1 + 1))
  (stmtIn : Statement (L := L) Context i.succ)
  (witMid : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
  (oStmtIn : (i_1 : Fin (toOutCodewordsCount ℓ ϑ i.castSucc)) →
    OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc i_1)
  : Prop :=

  match m with
  | ⟨0, _⟩ => 
    masterKStateProp (mp := mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (stmtIdx := i.succ) (oracleIdx := i.castSucc)
      (h_le := by admit /- proof elided -/
      )
      (stmt := stmtIn) (wit := witMid) (oStmt := oStmtIn)
      (localChecks := True)
  | ⟨1, _⟩ => 
    let ⟨_, stmtOut, oStmtOut, witOut⟩ := getCommitProverFinalOutput 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i ⟨stmtIn, oStmtIn, witMid⟩
    masterKStateProp (mp := mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (stmtIdx := i.succ) (oracleIdx := i.succ)
      (h_le := le_refl _)
      (stmt := stmtOut) (wit := witOut) (oStmt := oStmtOut)
      (localChecks := True)

def factor' (n : ℕ) : Option (List PrimeWithMultiplicity) := do
  let facts := List.mergeSort (← factor n)
  let groups := List.splitBy (· = ·) facts
  return groups.map (fun g => ⟨g[0]!, g.length⟩)

OneHom in Mathlib.Algebra.Group.Hom.Defs

def natWeightedDegree.{u} {F : Type u} [Semiring F] (f : F[X][Y]) (u v : ℕ) : ℕ :=
  f.support.sup (fun m => u * (f.coeff m).natDegree + v * m)

BitVec.setWidth in Init.Data.BitVec.Basic

def absorb (state : HashStateWithInstructions U H) (input : Array U) :
    Except DomainSeparatorMismatch (HashStateWithInstructions U H) := do
  
  sorry

def rbrKnowledgeSoundnessOneShot (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  ∃ stateFunction : verifier.KnowledgeStateFunctionOneShot init impl relIn.language relOut.language,
  ∃ extractor : Extractor.RoundByRoundOneShot oSpec StmtIn WitIn pSpec,
  ∀ stmtIn : StmtIn,
  ∀ witIn : WitIn,
  ∀ prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec,
  ∀ i : pSpec.ChallengeIdx,
    [fun ⟨transcript, challenge, proveQueryLog⟩ =>
      letI extractedWitIn := extractor i.1.castSucc stmtIn transcript proveQueryLog.fst
      (stmtIn, extractedWitIn) ∉ relIn ∧
        ¬ stateFunction i.1.castSucc stmtIn transcript ∧
          stateFunction i.1.succ stmtIn (transcript.concat challenge)
    | do
      (simulateQ (impl ++ₛₒ challengeQueryImpl : QueryImpl _ (StateT σ ProbComp))
        (do
          let ⟨⟨transcript, _⟩, proveQueryLog⟩ ← prover.runWithLogToRound i.1.castSucc stmtIn witIn
          let challenge ← liftComp (pSpec.getChallenge i) _
          return (transcript, challenge, proveQueryLog))).run' (← init)] ≤
      rbrKnowledgeError i

instance : Zero AssocNat where
  zero := zero

class IsSecureWithGap
    (completeRelation : Set ((Statement × ∀ i, OStatement i) × Witness))
    (soundRelation : Set ((Statement × ∀ i, OStatement i) × Witness))
    (ε_rbr : vPSpec.ChallengeIdx → ℝ≥0)
    (vectorIOP : VectorIOP Statement OStatement Witness vPSpec A) where

   
  is_complete : vectorIOP.perfectCompleteness (pure ()) ⟨isEmptyElim⟩ completeRelation

   
  is_rbr_knowledge_sound :
    OracleProof.rbrKnowledgeSoundness (pure ()) ⟨isEmptyElim⟩ soundRelation vectorIOP.verifier ε_rbr

gen in VCVio.CryptoFoundations.FiatShamir

@[reducible]
def permutationOracle (α : Type*) : OracleSpec PermuteDir :=
  forwardPermutationOracle α ++ₒ backwardPermutationOracle α

def commitKState (i : Fin ℓ) (hCR : isCommitmentRound ℓ ϑ i) :
    (commitOracleVerifier 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      i hCR).KnowledgeStateFunction init impl
      (relIn := foldStepRelOut (mp := mp) 𝔽q β (ϑ := ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑) i)
      (relOut := roundRelation (mp := mp) 𝔽q β (ϑ := ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑) i.succ)
      (extractor := commitRbrExtractor 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) where
  toFun := fun m ⟨stmtIn, oStmtIn⟩ tr witMid =>
    commitKStateProp 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (i := i) (m := m) (stmtIn := stmtIn) (witMid := witMid) (oStmtIn := oStmtIn) (mp:=mp)
  toFun_empty := fun stmtIn witMid => by admit /- proof elided -/

protected def cast (T : FullTranscript pSpec₁) :
    FullTranscript pSpec₂ :=
  Transcript.cast (k := Fin.last n₁) (l := Fin.last n₂) hn hn hSpec T

def StateRestoration.KnowledgeSoundness (oSpec : OracleSpec ι) (StmtIn WitOut : Type)
    {n : ℕ} (pSpec : ProtocolSpec n) :=
  OracleComp (oSpec ++ₒ (srChallengeOracle StmtIn pSpec)) (StmtIn × pSpec.Messages × WitOut)

noncomputable def modBivar (P P' : MvPolynomial (Fin 2) F)
    (hlg : IsUnit ((MonomialOrder.lex).leadingCoeff P')) : MvPolynomial (Fin 2) F :=
      
      let ord : MonomialOrder (Fin 2) := MonomialOrder.lex
      
      let b : Unit → MvPolynomial (Fin 2) F := fun _ => P'
      
      have hb : ∀ i : Unit, IsUnit (ord.leadingCoeff (b i)) := by admit /- proof elided -/

instance [Inhabited C] [Permute C] : DuplexSpongeInterface U (DuplexSponge U C) where
  absorbUnchecked := fun (sponge, arr) => absorbUnchecked sponge arr
  squeezeUnchecked := fun (sponge, arr) => squeezeUnchecked sponge arr
  ratchetUnchecked := ratchetUnchecked

def LeafData.optionComposeBuild {α : Type} {s : Skeleton} (leaf_data_tree : LeafData α s)
    (compose : α → α → Option α) :
    FullData (Option α) s :=
  (leaf_data_tree.map (.some)).composeBuild (Option.doubleBind compose)

instance [VerifierFirst pSpec] : ∀ i, OracleInterface (pSpec.Message i) := isEmptyElim

def Z (k : ℕ) : ConcreteBTField k :=
  if h_k : k = 0 then one
  else
    《 one (k:=k-1), zero (k:=k-1) 》

@[inline]
def add [Add R] (p q : MlPolyEval R n) : MlPolyEval R n := Vector.zipWith (· + ·) p q

List.max in Init.Data.List.Basic

instance {α : Type*} [Fintype α] : Dist (PMF α) where
  dist := fun a b => ∑ x, abs ((a x).toReal - (b x).toReal)

def take (j : Fin (n + 1)) (messages : Messages pSpec) : MessagesUpTo j pSpec :=

def finUInt8Equiv : Fin (2 ^ 8) ≃ UInt8 where
  toFun := fun i => UInt8.ofFin i
  invFun := fun u => u.toFin
  left_inv _ := rfl
  right_inv _ := rfl

@[inline, specialize]
def mul (p q : UniPoly R) : UniPoly R :=
  p.zipIdx.foldl (fun acc ⟨a, i⟩ => acc.add <| (smul a q).mulPowX i) (C 0)

def baseFoldMatrix (i : Fin r) (h_i : i + 1 < ℓ + 𝓡)
    (y : ↥(sDomain 𝔽q β h_ℓ_add_R_rate ⟨↑i + 1, by admit /- proof elided -/
    ⟩)) : Matrix (Fin 2) (Fin 2) L :=
  let fiberMap := qMap_total_fiber 𝔽q β (i := i) (steps := 1)
      (h_i_add_steps := h_i) (y := y)
  let x₀ := fiberMap 0
  let x₁ := fiberMap 1
  fun i j => match i, j with
  | 0, 0 => x₁
  | 0, 1 => -x₀
  | 1, 0 => -1
  | 1, 1 => 1

def notFunction : Prop :=
  let ⟨baseTrace, _⟩ := removeRedundantEntryDS trace
  ∃ j : Fin baseTrace.length, ∃ stateIn _stateOut : CanonicalSpongeState U,
    baseTrace[j] = ⟨.inr .Fwd, stateIn, _stateOut⟩ ∧
      ∃ j' < j,
        ∃ stateOut1 : CanonicalSpongeState U, baseTrace[j'] = ⟨.inr .Fwd, stateIn, stateOut1⟩ ∨
        ∃ stateOut2 : CanonicalSpongeState U, baseTrace[j'] = ⟨.inr .Bwd, stateOut2, stateIn⟩

alias E_func := notFunction

Monoid.toMulAction in Mathlib.Algebra.Group.Action.Defs

def mapOStmtOutRelayStep (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j) :
    ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.succ j := fun j => by admit /- proof elided -/

AddHom in Mathlib.Algebra.Group.Hom.Defs

def someValues : HList' (fun x => x) someTypes :=
  HList'.cons 1 (HList'.cons "bad" (HList'.cons 3 HList'.nil))

def witnessStructuralInvariant {i : Fin (ℓ + 1)} (stmt : Statement (L := L) Context i)
    (wit : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i): Prop :=
  wit.H = projectToMidSumcheckPoly ℓ wit.t (m:=mp.multpoly stmt.ctx) i stmt.challenges ∧
  wit.f = getMidCodewords 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) wit.t stmt.challenges

Rat.castRec in Mathlib.Algebra.Field.Defs

instance {i : Fin (n + 1)} : OfNat (evalDomain D i) 1 where
  ofNat := ⟨1, one_in_doms D i⟩

@[reducible, inline, specialize]
def ChallengeUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) (i : pSpec.ChallengeIdxUpTo k) :=
  (pSpec⟦:k.val⟧).Challenge i

@[simp]
instance AlgebraTower.toIsScalarTower (a : AlgebraTower C) {i j k : ι}
    (h1 : i ≤ j) (h2 : j ≤ k) :
    letI : Algebra (C i) (C j) :=

Nat.pow in Init.Prelude

def foldPrvState (i : Fin ℓ) : Fin (2 + 1) → Type := fun
  
  | ⟨0, _⟩ => (Statement (L := L) Context i.castSucc ×
    (∀ 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.castSucc)
  
  | ⟨1, _⟩ => Statement (L := L) Context i.castSucc ×
    (∀ 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.castSucc × L⦃≤ 2⦄[X]
  
  | _ => Statement (L := L) Context i.castSucc ×
    (∀ 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.castSucc × L⦃≤ 2⦄[X] × L

WithBot in Mathlib.Order.TypeTags

instance : DecidableEq BTF₃ := (inferInstance : DecidableEq (ConcreteBTField 3))

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

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

@[reducible, simp]
def StmtIn := R

IsEmpty in Mathlib.Logic.IsEmpty

@[reducible, simp]
def ChallengeIdxUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) : Type :=
  (pSpec⟦:k.val⟧).ChallengeIdx

@[reducible]
def spec : OracleSpec Unit := fun _ => (α × α, α)

structure Opening where
  opening : Proof oSpec (Commitment × O.Query × O.Response) (Data × Randomness) pSpec

instance finiteDimensional_degreeLT {n : ℕ} (h_n_pos : 0 < n) :
  FiniteDimensional L L⦃< n⦄[X] :=

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

class Prover.IsPure (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) where
    is_pure : ∃ sendMessage : ∀ _, _ → _, ∀ i st,
      P.sendMessage i st = pure (sendMessage i st)

def relation : Set (M × M × List (MemoryOp ι α)) :=
  { ⟨startMem, finalMem, ops⟩ | processMemoryOps ops startMem = some finalMem }

instFintypeProd in Mathlib.Data.Fintype.Prod

@[reducible]
def MlPoly (R : Type*) (n : ℕ) := Vector R (2 ^ n) 

Classical.arbitrary in Mathlib.Logic.Nonempty

instance [h : VerifierFirst pSpec] : IsEmpty (pSpec.MessageIdx) where
  false | ⟨0, h'⟩ => by admit /- proof elided -/

def minRelHammingDistCode (C : Set (ι → F)) : ℚ≥0 :=
  haveI : Fintype (possibleRelHammingDists C) := @Fintype.ofFinite _ finite_possibleRelHammingDists
  if h : (possibleRelHammingDists C).Nonempty
  then (possibleRelHammingDists C).toFinset.min' (Set.toFinset_nonempty.2 h)
  else 0

Equiv.optionCongr in Mathlib.Logic.Equiv.Option

List.findIdx in Init.Data.List.Basic

@[reducible, inline, specialize]
def OracleMessageIdx := {i : pSpec.MessageIdx // (inst.oracleInterfaces i).isSome }

def choose_2 (x : ℚ) : ℚ := x * (x-1)/2

def fillNextUnits (state : FSVerifierState U H) (count : Nat) :
    Except DomainSeparatorMismatch (FSVerifierState U H × Array U) := do
  
  let bytesNeeded := count * HasSize.size U UInt8
  if state.nargString.size < bytesNeeded then
    .error {
      message := s!"Insufficient transcript remaining, need {bytesNeeded} bytes,
        got {state.nargString.size}" }
  else
    
    let readBytes := state.nargString.extract 0 bytesNeeded
    let remaining := state.nargString.extract bytesNeeded state.nargString.size
    
    let units := Array.range count |>.mapM (fun i =>
      let unitBytes := readBytes.extract (i * HasSize.size U UInt8) (HasSize.size U UInt8)
      DeserializeOption.deserialize unitBytes)
    match units with
    | some unitsArray =>
      
      let newHashState ← state.hashState.absorb unitsArray
      .ok ({ hashState := newHashState, nargString := remaining }, unitsArray)
    | none =>
      .error { message := "Failed to deserialize units from NARG string" }

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

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

class PrimeOrder (G : Type*) [Group G] where
  p : ℕ
  [hPrime : Fact (Nat.Prime p)]
  hCard : Nat.card G = p

def backTrack (trace : QueryLog (duplexSpongeChallengeOracle StmtIn U))
    (state : CanonicalSpongeState U) :
    OptionT Option ((StmtIn × (i : Fin (n + 1)) × (pSpec.MessagesUpTo i))) :=
  sorry

noncomputable def listBlockRelDistance
  (i k : ℕ) {S : Finset ι} {φ : ι ↪ F} {φ' : (indexPowT S φ i) ↪ F}
  {m : ℕ} [DecidableEq F] [DecidableEq ι] [Smooth φ]
  (f : (indexPowT S φ i) → F) (S' : Finset (indexPowT S φ i))
  [∀ i : ℕ, Fintype (indexPowT S φ i)] [DecidableEq (indexPowT S φ i)] [Smooth φ']
  (C : Set ((indexPowT S φ i) → F)) (_hcode : C = smoothCode φ' m) (δ : ℝ≥0)
  [h : DecidableBlockDisagreement i k f S' φ'] : (Set ((indexPowT S φ i) → F)) :=
    { u ∈ C | Δᵣ(i, k, f, S', φ', u) ≤ δ }

def buildMerkleTree_with_hash {s} (leaf_tree : LeafData α s) (hashFn : α → α → α) :
    (FullData α s) :=
  match leaf_tree with
  | LeafData.leaf a => FullData.leaf a
  | LeafData.internal left right =>
    let leftTree := buildMerkleTree_with_hash left hashFn
    let rightTree := buildMerkleTree_with_hash right hashFn
    let rootHash := hashFn (leftTree.getRootValue) (rightTree.getRootValue)
    FullData.internal rootHash leftTree rightTree

instance instDecidableEqOption {α : Type*} [DecidableEq α] :
    DecidableEq (Option α) := inferInstance

Fintype.ofFinite in Mathlib.Data.Fintype.EquivFin

def InternalData.get {s} {α : Type}
    (tree : InternalData α s) (idx : SkeletonInternalIndex s) : α :=
  match tree, idx with
  | InternalData.internal value _ _, SkeletonInternalIndex.ofInternal => value
  | InternalData.internal _ left _, SkeletonInternalIndex.ofLeft idxLeft =>
    InternalData.get left idxLeft
  | InternalData.internal _ _ right, SkeletonInternalIndex.ofRight idxRight =>
    InternalData.get right idxRight

@[reducible]
def pSpec : ProtocolSpec 1 := ⟨!v[.V_to_P], !v[Query OStatement]⟩

def params16 : Params where
  width := 16
  numFullRounds := 8
  numPartialRounds := 20
  internalDiagVectors := #v[
       -2,
        1,
        2,
        1 / 2,
        3,
        4,
        -1 / 2,
        -3,
        -4,
        1 / (2 ^ 8),
        1 / 8,
        1 / (2 ^ 24),
        -1 / (2 ^ 8),
        -1 / 8,
        -1 / 16,
        -1 / (2 ^ 24),
    ]
  roundConstants := rawConstants16
  width_dvd_by_4 := by admit /- proof elided -/

def e (B : Finset (Fin n → F)) (v : Fin n → F) : ℚ :=
  (1 : ℚ)/B.card * ∑ x ∈ B, Δ₀(v, x)

instance : Repr ByteArray where
  reprPrec b n := List.repr b.toList n

def millerRabinBases : List ℕ :=
  [2, 325, 9375, 28178, 450775, 9780504, 1795265022]

def getTypes {αs : List Type} (_ : HList αs) : List Type := αs

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

Function.uncurry in Init.Data.Function

structure InterleavedCode (κ ι : Type*) [Fintype κ] [Fintype ι] (F : Type*) [Semiring F] where
  MF : MatrixSubmodule κ ι F
  LC : LinearCode ι F

AddMonoidAlgebra in Mathlib.Algebra.MonoidAlgebra.Defs

instance [IsSingleRound pSpec] [h : OracleInterface (pSpec.Message default)] :
    (i : pSpec.MessageIdx) → OracleInterface (pSpec.Message i) := fun i => by admit /- proof elided -/

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

def AlgebraTowerEquiv.algebraMapLeftUp (e : AlgebraTowerEquiv A B) (i j : ι)
    (h : i ≤ j) : (B i) →+* (A j) :=

structure Selector (𝓡 : Type*) where
   
  qL : 𝓡
   
  qR : 𝓡
   
  qO : 𝓡
   
  qM : 𝓡
   
  qC : 𝓡
deriving DecidableEq

@[reducible]
def GroupEncodeOracle : OracleSpec Unit := fun _ => (ι, BitVec bitLength)

Matrix.neg in Mathlib.LinearAlgebra.Matrix.Defs

PMF.uniformOfFintype in Mathlib.Probability.Distributions.Uniform

Polynomial.degreeLT in Mathlib.RingTheory.Polynomial.Basic

Fin.snoc in Mathlib.Data.Fin.Tuple.Basic

def findSumIdx (l : List α) (j : α) : ℕ := l.partialSum.findIdx (j < ·)

def Prover.addSalt (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (saltComp : (i : pSpec.MessageIdx) → P.PrvState i.1.castSucc → OracleComp oSpec (Salt i)) :
  Prover oSpec StmtIn WitIn StmtOut WitOut (pSpec.addSalt Salt) where
  PrvState := P.PrvState
  input := P.input
  sendMessage := fun i st => by admit /- proof elided -/

instance {n : ℕ} {α : Fin n → Type*} : SliceLT ((i : Fin n) → α i) ℕ
    (fun _ stop => stop ≤ n)
    (fun _ stop h => (i : Fin stop) → α (i.castLE h))
    where
  sliceLT := fun v stop h => take stop h v

def evalWAt (i : Fin r) (x : L) : L :=
  ((getUElements (β := β) (ℓ := ℓ) (R_rate := R_rate) i).map (fun u => x - u)).prod

instance [Repr α] (αs : List Type) [HListRepr (HList αs)] : HListRepr (HList (α :: αs)) where
  repr
  | HList.cons x xs =>
    match xs with
    | HList.nil => reprPrec x 0
    | HList.cons _ _ => reprPrec x 0 ++ ", " ++ HListRepr.repr xs

noncomputable def discriminant {F : Type} [Field F] [Inhabited F] (f : F[X]) : F :=
  1/f.leadingCoeff * Polynomial.resultant f (Polynomial.derivative f)

def getNextOracle (i : Fin (ℓ + 1))
    (oStmt : ∀ j, (OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i) j)
    (j : Fin (toOutCodewordsCount ℓ ϑ i)) (hj : j.val + 1 < toOutCodewordsCount ℓ ϑ i) :
    OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨j.val * ϑ + ϑ, by
    apply Nat.lt_succ_of_le;
    let h_k_next_le_i := oracle_block_k_next_le (ℓ := ℓ) (ϑ := ϑ) (i := i) (j := j) (hj := hj)
    calc _ ≤ i.val := h_k_next_le_i
      _ ≤ ℓ := Fin.is_le i
  ⟩ :=

@[reducible, simp] def WitOut := Unit

def eval₂ [Semiring S] (f : R →+* S) (x : S) (p : UniPoly R) : S :=
  p.zipIdx.foldl (fun acc ⟨a, i⟩ => acc + f a * x ^ i) 0

Nat.and_distrib_right in Init.Data.Nat.Bitwise.Lemmas

instance oCtxLens_complete :
    (oCtxLens R n deg D i).toContext.IsComplete
      (relationRound R n deg D i.castSucc) (Simple.inputRelation R deg D)
      (relationRound R n deg D i.succ) (Simple.outputRelation R deg)
      ((Simple.oracleReduction R deg D oSpec).toReduction.compatContext
        (oCtxLens R n deg D i).toContext)
where
  proj_complete := by admit /- proof elided -/

inductive Skeleton :
    (n : ℕ) → (ar : Fin n → ℕ) → Type where
  | leaf {ar0 : Fin 0 → ℕ} : Skeleton 0 ar0
  | node {n : ℕ} {ar : Fin (n+1) → ℕ}
      (children : Fin (ar 0) →
        Skeleton n (fun i => ar i.succ)) :
      Skeleton (n+1) ar

def KnowledgeStateFunction.toStateFunction
    {relIn : Set (StmtIn × WitIn)} {relOut : Set (StmtOut × WitOut)}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec} {WitMid : Fin (n + 1) → Type}
    {extractor : Extractor.RoundByRound oSpec StmtIn WitIn WitOut pSpec WitMid}
    (kSF : KnowledgeStateFunction init impl relIn relOut verifier extractor) :
      verifier.StateFunction init impl relIn.language relOut.language where
  toFun := fun m stmtIn tr => ∃ witMid, kSF.toFun m stmtIn tr witMid
  toFun_empty := by admit /- proof elided -/

idOracle in VCVio.OracleComp.SimSemantics.SimulateQ

Set.Ioo in Mathlib.Order.Interval.Set.Defs

  partial def computePrattPart (l : List PrimeWithMultiplicity) : Option UnverifiedPrattPart := do
    if let [⟨p, k⟩] := l then
      let cert ← computePrattCertificate p
      return .prime p k cert

    let ⟨left, right⟩ := l.splitAt (l.length / 2)
    let lhs ← computePrattPart left
    let rhs ← computePrattPart right
    return .split lhs rhs

def powNat [Zero T] [One T] [ToNat T] (a : Cayley T) : Nat → Cayley T
  | 0        => one  
  | .succ k  => mul a (powNat a k)  

def erase_even (s : Finset ℕ) : Finset ℕ := s.filter Odd

Subtype.fintype in Mathlib.Data.Fintype.Sets

@[reducible] def Proof {ι : Type} (oSpec : OracleSpec ι)
    (Statement Witness : Type) {n : ℕ} (pSpec : ProtocolSpec n) :=
  Reduction oSpec Statement Witness Bool Unit pSpec

Polynomial.aeval in Mathlib.Algebra.Polynomial.AlgebraMap

Functor in Init.Prelude

instance [inst : ∀ i, SelectableType (pSpec.Challenge i)] :
    ∀ i, SelectableType ((pSpec.addSalt Salt).Challenge i) :=
  fun i => by admit /- proof elided -/

@[reducible]
def Extractor.Straightline.id : Extractor.Straightline oSpec StmtIn WitIn WitIn !p[] :=
  fun _ witOut _ _ _ => pure witOut

EquivLike in Mathlib.Data.FunLike.Equiv

structure BinaryTowerInductiveStepResult (k : ℕ) (prevBTField : Type _)
  (prevBTResult : BinaryTowerResult prevBTField k) [instPrevBTFieldIsField : Field prevBTField]
  (prevPoly : Polynomial prevBTField) (F : Type _) where
  binaryTowerResult : BinaryTowerResult F (k+1)
  eq_adjoin : F = AdjoinRoot prevPoly
  u_is_root : Eq.mp (eq_adjoin) binaryTowerResult.specialElement = AdjoinRoot.root prevPoly
  eval_defining_poly_at_root : Eq.mp (eq_adjoin) binaryTowerResult.specialElement^2 +
    Eq.mp (eq_adjoin) binaryTowerResult.specialElement * (of prevPoly) prevBTResult.specialElement
    + 1 = 0

noncomputable def sDomain.lift (i j : Fin r) (h_j : j < ℓ + R_rate) (h_le : i ≤ j)
    (y : sDomain 𝔽q β h_ℓ_add_R_rate j) :
    sDomain 𝔽q β h_ℓ_add_R_rate i :=

def instTestLensKnowledgeSound : testLensE.IsKnowledgeSound
      outerRelIn_Test innerRelIn_Test outerRelOut_Test innerRelOut_Test
      (fun ⟨p, q, _⟩ ⟨f, _⟩ => p * q = f) (fun _ _ => True) where
  proj_knowledgeSound := fun ⟨p, q, t⟩ ⟨f, t', r⟩ _ h h' => by admit /- proof elided -/

def deriveTranscriptDSFS {ι : Type} {oSpec : OracleSpec ι} {StmtIn : Type}
    (stmtIn : StmtIn) (messages : pSpec.Messages) :
    OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      (CanonicalDuplexSponge U × pSpec.FullTranscript) := do
  let sponge ← liftM (DuplexSponge.start stmtIn)
  deriveTranscriptDSFSAux sponge messages (Fin.last n)

Units.mk0 in Mathlib.Algebra.GroupWithZero.Units.Basic

Nat.boddDiv2 in Mathlib.Data.Nat.Bits

def Polynomial.toImpl {R : Type*} [Semiring R] (p : R[X]) : UniPoly R :=
  match p.degree with
  | ⊥ => #[]
  | some d  => .ofFn (fun i : Fin (d + 1) => p.coeff i)

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

def Rhs (e : ℕ) (ωs f : Fin n → F) (i : Fin n) : F :=
  let αᵢ := ωs i
  (-(f i) * αᵢ^e)

noncomputable def δ_ε_proximityGap {α : Type} [DecidableEq α] [Nonempty α]
  (P : Finset (ι → α)) (C : Set (Finset (ι → α))) (δ ε : ℝ≥0) : Prop :=
  ∀ S ∈ C, ∀ [Nonempty S],
  Xor'
  ( Pr_{let x ← $ᵖ S}[Code.relHammingDistToCode x.1 P ≤ δ] = 1 )
  ( Pr_{let x ← $ᵖ S}[Code.relHammingDistToCode x.1 P ≤ δ] ≤ ε )

Finset.Ico in Mathlib.Order.Interval.Finset.Defs

LinearIndepOn in Mathlib.LinearAlgebra.LinearIndependent.Defs

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

CharP in Mathlib.Algebra.CharP.Defs

@[inline]
def ofArray [Zero R] (coeffs : Array R) (n : ℕ) : MlPoly R n :=
  .ofFn (fun i => if h : i.1 < coeffs.size then coeffs[i] else 0)

@[reducible]
def Witness (F : Type) [Semiring F] {k : ℕ} (s : Fin (k + 1) → ℕ+) (d : ℕ+) (m : ℕ) :=
  Fin (m + 1) → F⦃< 2 ^ (∑ i, (s i).1) * d⦄[X]

instance [ProverFirst pSpec] : Unique (pSpec.MessageIdx) where
  default := ⟨0, by admit /- proof elided -/
  ⟩
  uniq := fun ⟨i, _⟩ => by admit /- proof elided -/

def BerlekampWelchMatrix
  (e k : ℕ)
  (ωs f : Fin n → F) : Matrix (Fin n) (Fin (2 * e + k)) F :=
  Matrix.of fun i j =>
    let αᵢ := ωs i
    if ↑j < e then -Rhs j.1 ωs f i else -αᵢ^(j - e)

structure WireIndices (numWires : ℕ) where
   
  a : Fin numWires
   
  b : Fin numWires
   
  c : Fin numWires
deriving DecidableEq

instance [inst : ∀ i, DecidableEq (pSpec.Message i)] {k : Fin (n + 1)} :
    DecidableEq (MessagesUpTo k pSpec) :=
  @Fintype.decidablePiFintype _ _ (fun i => inst ⟨i.1.castLE (by admit /- proof elided -/
  ), i.property⟩) _

@[reducible, inline]
instance instMvPolynomialDegreeLE : OracleInterface (R⦃≤ d⦄[X σ]) where
  Query := σ → R
  Response := R
  answer := fun ⟨poly, _⟩ point => eval point poly

Matrix.add in Mathlib.LinearAlgebra.Matrix.Defs

def LeafData.get {s} {α : Type}
    (tree : LeafData α s) (idx : SkeletonLeafIndex s) : α :=
  match tree, idx with
  | LeafData.leaf value, SkeletonLeafIndex.ofLeaf => value
  | LeafData.internal left _, SkeletonLeafIndex.ofLeft idxLeft =>
    LeafData.get left idxLeft
  | LeafData.internal _ right, SkeletonLeafIndex.ofRight idxRight =>
    LeafData.get right idxRight

def FullData.toInternalData {α : Type} {s : Skeleton}
    (tree : FullData α s) : InternalData α s :=
  match tree with
  | FullData.leaf _ => InternalData.leaf
  | FullData.internal value left right =>
    InternalData.internal value (left.toInternalData) (right.toInternalData)

instance : ∀ j, SelectableType ((pSpecRelay).Challenge j)
  | ⟨x, hj⟩ => by admit /- proof elided -/

Fin.append in Mathlib.Data.Fin.Tuple.Basic

instance : SliceGE (ProtocolSpec n) ℕ
    (fun _ start => start ≤ n)
    (fun _ start _ => ProtocolSpec (n - start))
    where
  sliceGE := fun v start h => drop start h v

Finsupp.mapRange in Mathlib.Data.Finsupp.Defs

affineSpan in Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Defs

Neg in Init.Prelude

def snoc (s : Fin n →₀ M) (y : M) : Fin (n + 1) →₀ M :=
  Finsupp.equivFunOnFinite.symm (Fin.snoc s y : Fin (n + 1) → M)

protected def cast (P : OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₁) :
    OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₂ :=
  Prover.cast hn hSpec P

def rightpad (m₂ n₂ : ℕ) (a : α) {m₁ n₁ : ℕ} (M : Matrix (Fin m₁) (Fin n₁) α) :
    Matrix (Fin m₂) (Fin n₂) α :=
  Fin.rightpad m₂ (fun _ => a) (Fin.rightpad n₂ a ∘ M)

@[reducible, simp] def WitOut := Unit

def exSkel0 : ArityTree.Skeleton 0 (fun i => nomatch i) :=
  ArityTree.Skeleton.leaf

MonadLiftT in Init.Prelude

instance [Fintype F] [Nonempty F] [Semiring F] [DecidableEq ι] [DecidableEq F] {l : ℕ}
  {u : Fin l → ι → F} : Nonempty {x // x ∈ parametrisedCurveFinite u} :=

Finset.image in Mathlib.Data.Finset.Image

def BinaryTowerAux (k : ℕ) : (Σ' (F : Type 0), BinaryTowerResult F k) :=
  match k with
  | 0 => 
    let curBTField := GF(2)
    let newList : List.Vector (GF(2)) 1 := List.Vector.cons (1 : GF(2)) List.Vector.nil
    let specialElement : GF(2) := newList.1.headI
    let firstElementOfVecIsSpecialElement : newList.1.headI = specialElement := rfl
    let specialElementIs1 : specialElement = 1 := by admit /- proof elided -/

Polynomial.monomial in Mathlib.Algebra.Polynomial.Basic

Matrix.submatrix in Mathlib.LinearAlgebra.Matrix.Defs

abbrev singleEqPolynomial (r : R) (x : MvPolynomial σ R) : MvPolynomial σ R :=
  (1 - C r) * (1 - x) + C r * x

BitVec.toNat in Init.Prelude

List in Init.Prelude

LE.le in Init.Prelude

inductive Data :
    {n : ℕ} → (pSpec : ProtocolSpec n) →
    {ar : Fin n → ℕ} → ArityTree.Skeleton n ar → Type 1 where
  | leaf {pSpec : ProtocolSpec 0} {ar0 : Fin 0 → ℕ} :
      Data pSpec (ArityTree.Skeleton.leaf (ar0 := ar0))
  | msgNode {n : ℕ}
      {pSpec : ProtocolSpec (n + 1)} {ar : Fin (n + 1) → ℕ}
      (h : pSpec.dir 0 = Direction.P_to_V)
      (val : pSpec.Message' 0 h)
      {children : Fin (ar 0) →
        ArityTree.Skeleton n (fun i => ar i.succ)}
      (childrenData : (i : Fin (ar 0)) →
        Data (pSpec := pSpec.drop 1 (Nat.succ_le_succ (Nat.zero_le n))) (children i)) :
      Data pSpec (ArityTree.Skeleton.node children)
  | chalNode {n : ℕ}
      {pSpec : ProtocolSpec (n + 1)} {ar : Fin (n + 1) → ℕ}
      (h : pSpec.dir 0 = Direction.V_to_P)
      (val : pSpec.Challenge' 0 h)
      {children : Fin (ar 0) →
        ArityTree.Skeleton n (fun i => ar i.succ)}
      (childrenData : (i : Fin (ar 0)) →
        Data (pSpec := pSpec.drop 1 (Nat.succ_le_succ (Nat.zero_le n))) (children i)) :
      Data pSpec (ArityTree.Skeleton.node children)

def pSpecFullNonLastBlock (bIdx : Fin (ℓ / ϑ - 1)) :=
  (pSpecFoldRelaySequence (L:=L) (n:=ϑ - 1) ++ₚ
      pSpecFoldCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        ⟨↑bIdx * ϑ + (ϑ - 1), by admit /- proof elided -/
          ⟩)

instance (k : ℕ) : LE (ConcreteBTField k) where
  le := fun x y => by admit /- proof elided -/

def closePtsOnAffineLine {ι : Type*} [Fintype ι]
                         (u v : ι → F) (deg : ℕ) (α : ι ↪ F) (e : ℕ) : Set (ι → F) :=
  {x : ι → F | x ∈ Affine.line u v ∧ distFromCode x (ReedSolomon.code α deg) ≤ e}

def dfoldr' (n : ℕ) (α : Fin (n + 1) → Type u)
    (f : (i : Fin n) → α i.succ → α i.castSucc) (init : α (last n)) : α 0 :=
  dfoldrM' (m := Id) n α f init

@[reducible]
def reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut !p[] where
  prover := prover mapStmt mapWit
  verifier := verifier mapStmt

def foldl' {α : Type u} (n : ℕ) (f : (i : Fin n) → α → α) (init : α) : α :=
  dfoldl' n (fun _ => α) f init

structure BerlekampWelchCondition (e k : ℕ) (ωs f : Fin n → F) (E Q : Polynomial F) : Prop where
  cond: ∀ i : Fin n, Q.eval (ωs i) = (f i) * E.eval (ωs i)
  E_natDegree : E.natDegree = e
  E_leadingCoeff : E.coeff e = 1
  Q_natDegree : Q.natDegree ≤ e + k - 1

def MlPoly.mk {R : Type*} (n : ℕ) (v : Vector R (2 ^ n)) : MlPoly R n := v

noncomputable def H_tilde' (H : F[X][Y]) : F[X][Y] :=
  let hᵢ (i : ℕ) := H.coeff i
  let d := H.natDegree
  let W := hᵢ d
  Polynomial.X ^ d +
    ∑ i ∈ (List.range d).toFinset,
      Polynomial.X^(d - 1 - i) *
      Polynomial.C (hᵢ (i + 1) * W ^ i)

List.idxOf in Init.Data.List.Basic

Polynomial.IsRoot in Mathlib.Algebra.Polynomial.Eval.Defs

noncomputable def verifyOpening (verifySrs : Vector G₂ 2) (commitment : G₁) (opening : G₁)
    (z : ZMod p) (v : ZMod p) : Prop :=
  pairing (commitment / g₁ ^ v.val) (verifySrs[0]) = pairing opening (verifySrs[1] / g₂ ^ z.val)

List.Vector.nil in Mathlib.Data.Vector.Defs

def InternalData.map {α β : Type} (f : α → β) {s : Skeleton}
    (tree : InternalData α s) : InternalData β s :=
  match tree with
  | InternalData.leaf => InternalData.leaf
  | InternalData.internal value left right =>
    InternalData.internal (f value) (left.map f) (right.map f)

@[inline] def one : AssocNat :=
  ⟨Nat.succ, by admit /- proof elided -/
  ⟩

Pi.single in Mathlib.Algebra.Notation.Pi.Basic

abbrev rtake (m : ℕ) (h : m ≤ n)
    (transcript : FullTranscript pSpec) : FullTranscript (pSpec.rtake m h) :=
  Fin.rtake m h transcript

noncomputable def towerEquiv_zero : RingEquiv (R:=GF(2)) (S:=ConcreteBTField 0) :=  {
  toFun := fun x => if x = 0 then 0 else 1,
  invFun := fun x => if x = 0 then 0 else 1,
  left_inv := fun x => by admit /- proof elided -/

noncomputable def Bstar (x : ℝ) : ℝ := x.sqrt

def init (s : Fin (n + 1) →₀ M) : Fin n →₀ M :=
  Finsupp.equivFunOnFinite.symm (Fin.init s)

List.repr in Init.Data.Repr

Int.ofNat in Init.Data.Int.Basic

def duplexSpongeToBasicFSQueryImpl :
    QueryImpl (duplexSpongeChallengeOracle StmtIn U)
      (OracleComp (fsChallengeOracle StmtIn pSpec)) :=
  sorry

alias d2SQueryImpl := duplexSpongeToBasicFSQueryImpl

instance instHasSucc {n : ℕ} : HasSucc (CNat n) := (CayleyTower n).2

@[reducible]
def capacitySegment (state : CanonicalSpongeState U) : Vector U SpongeSize.C :=
  Vector.drop state SpongeSize.R

instance [Zero T] [One T] [ToNat T] : NatPow (Cayley T) where
  pow := powNat

@[reducible, simp] def OStmtOut : Unit → Type := fun _ => R⦃≤ deg⦄[X]

def modByMonic [Field R] (p : UniPoly R) (q : UniPoly R) :
    UniPoly R :=
  (divModByMonicAux p q).2

def hintBytes (state : FSVerifierState U H) :
    Except DomainSeparatorMismatch (FSVerifierState U H × ByteArray) := do
  let newHashState ← state.hashState.hint

    
  if state.nargString.size < 4 then
    .error { message := "Insufficient transcript remaining for hint" }
  else
    
    let byte0 := state.nargString[0]!.toNat
    let byte1 := state.nargString[1]!.toNat
    let byte2 := state.nargString[2]!.toNat
    let byte3 := state.nargString[3]!.toNat
    let length := byte0 + (byte1 <<< 8) + (byte2 <<< 16) + (byte3 <<< 24)
    let rest := state.nargString.extract 4 state.nargString.size

    
    if rest.size < length then
      .error { message := s!"Insufficient transcript remaining, got {rest.size}, need {length}" }
    else
      
      let hint := rest.extract 0 length
      let remaining := rest.extract length rest.size
      .ok ({ hashState := newHashState, nargString := remaining }, hint)

noncomputable def monomialBasisOfDegreeLT {n : ℕ} : Basis (Fin n) L (L⦃< n⦄[X]) :=

noncomputable def toPoly (p : UniPoly R) : Polynomial R :=
  p.eval₂ Polynomial.C Polynomial.X

def RoundByRoundOneShot
    (oSpec : OracleSpec ι) (StmtIn WitIn : Type) {n : ℕ} (pSpec : ProtocolSpec n) :=
  (m : Fin (n + 1)) → StmtIn → Transcript m pSpec → QueryLog oSpec → WitIn

def accepts (x : Fin numWires → 𝓡) (g : Gate 𝓡 numWires) : Prop :=
  g.eval x = 0

instance instHasPred {n : ℕ} : HasPred (CNat n) := match n with
  | 0 => by admit /- proof elided -/
  | .succ n => by admit /- proof elided -/

@[inline, reducible]
def proj : (OuterStmtIn × (∀ i, OuterOStmtIn i)) × OuterWitIn →
    (InnerStmtIn × (∀ i, InnerOStmtIn i)) × InnerWitIn :=
  fun ctxIn => ⟨lens.stmt.proj ctxIn.1, lens.wit.proj ctxIn⟩

Equiv.ofBijective in Mathlib.Logic.Equiv.Defs

@[reducible]
def pSpec : ProtocolSpec 1 :=
  ⟨!v[.V_to_P], !v[Fin l → evalDomain D x 0]⟩

def oracleReduction.linearCombination :
    OracleReduction oSpec
      (Statement.AfterFirstSumcheck R pp) (OracleStatement.AfterFirstSumcheck R pp) (Witness R pp)
      (Statement.AfterLinearCombination R pp) (OracleStatement.AfterLinearCombination R pp) Unit
      ⟨!v[.V_to_P], !v[LinearCombinationChallenge R]⟩ :=
  sorry

def matchSize (l₁ : List α) (l₂ : List α) (unit : α) : List α × List α :=
  (l₁.rightpad (l₂.length) unit, l₂.rightpad (l₁.length) unit)

@[reducible]
def oSpec (α β γ : Type) : OracleSpec (Unit ⊕ Unit) := randSpec β ++ₒ ROspec α β γ

def partialSum {α : Type*} [AddMonoid α] (l : List α) : List α :=
  [0] ++ match l with
  | [] => []
  | a :: l' => (partialSum l').map (a + ·)

Bool in Init.Prelude

Finsupp in Mathlib.Data.Finsupp.Defs

@[reducible, simp]
def soundness (langIn : Set Statement)
    (verifier : Verifier oSpec Statement Bool pSpec)
    (soundnessError : ℝ≥0) : Prop :=
  verifier.soundness init impl langIn acceptRejectRel.language soundnessError

tag in Examples.FrankingProtocol

instance instDivConcreteBTF {k : ℕ} : Div (ConcreteBTField k) where
  div a b := a * (concrete_inv b)

@[inline, specialize]
def runToRound (i : Fin (n + 1))
    (stmt : StmtIn) (wit : WitIn) (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ) (pSpec.Transcript i × prover.PrvState i) :=
  Fin.induction
    (pure ⟨default, prover.input (stmt, wit)⟩)
    (prover.processRound)
    i

Trans in Init.Prelude

def renameMessage (pSpec : ProtocolSpec n) (NewMessage : pSpec.MessageIdx → Type) :
    ProtocolSpec n :=
  ⟨ pSpec.dir,
    fun i => if h : pSpec.dir i = Direction.P_to_V then NewMessage ⟨i, h⟩ else pSpec.«Type» i⟩

LinearEquiv in Mathlib.Algebra.Module.Equiv.Defs

protected noncomputable def ElocPoly (n : ℕ) (ωs f : ℕ → F) (p : Polynomial F) : Polynomial F :=
  List.prod <| (List.range n).map fun i =>
    if f i = p.eval (ωs i)
    then 1
    else X - C (ωs i)

def sigmaMessageIdxToSeqCompose {m : ℕ} {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (i : Fin m) (j : (pSpec i).MessageIdx) : (seqCompose pSpec).MessageIdx :=
  ⟨Fin.embedSum i j.1, by admit /- proof elided -/
  ⟩

class IsCyclicWithGen (G : Type) [Pow G ℤ] where
  gen : G
  zpow_surjective : Function.Surjective (gen ^ · : ℤ → G)

DFunLike in Mathlib.Data.FunLike.Basic

Vector.finRange in Init.Data.Vector.FinRange

def degCor
  (φ : ι ↪ F) (dstar degree : ℕ) (r : F) (f : ι → F) (x : ι) : F :=
    f x * ∑ l ∈ range (dstar - degree + 1), ((φ x) * r) ^ l

noncomputable def foldf (S : Finset ι) (φ : ι ↪ F)
  {k : ℕ} [Neg (indexPowT S φ k)] (y : indexPowT S φ (k + 1))
  (f : indexPowT S φ k → F) (α : F) : F :=
  let xPow := extract_x S φ k y
  let fx := f xPow
  let f_negx := f (-xPow)
  (fx + f_negx) / 2 + α * ((fx - f_negx) / (2 * (xPow.val : F)))

def extractMiddleFinMask (v : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨0, by exact pos_of_neZero r⟩)
    (i : Fin ℓ) (steps : ℕ) : Fin (2 ^ steps) :=

instance inhabited [Inhabited R] : Inhabited (MlPolyEval R n) :=

def Cache.leaves (n : ℕ) (cache : Cache α (n + 1)) :
    List.Vector α (2 ^ (n + 1)) := cache (Fin.last _)

def toChallengesUpTo (transcript : Transcript k pSpec) : ChallengesUpTo k pSpec :=
  fun ⟨i, _⟩ => transcript i

@[simp]
def outerRelOut_Test : Set (OuterStmtOut_Test × Unit) :=
  setOf (fun ⟨⟨p, q, t, r⟩, _⟩ => (p * q).eval r = t)

def finToBinaryCoeffs (i : Fin r) (idx : Fin (2 ^ (ℓ + R_rate - i.val))) :
  Fin (ℓ + R_rate - i.val) → 𝔽q := fun j =>
    if (Nat.getBit (k:=j) (n:=idx)) = 1 then (1 : 𝔽q) else (0 : 𝔽q)

@[reducible, inline, specialize, simp]
def Challenge' (pSpec : ProtocolSpec n) (i : Fin n) (_ : pSpec.dir i = .V_to_P) := pSpec.«Type» i

def ratchet (state : HashStateWithInstructions U H) :
    Except DomainSeparatorMismatch (HashStateWithInstructions U H) := do
  
  sorry

noncomputable def codewordToPoly
  [Fintype ι] [Field F] [DecidableEq ι]
  {deg : ℕ} {domain : ι ↪ F} (f : code domain deg) : F[X] :=
  Lagrange.interpolate Finset.univ domain.toFun f

@[inline, reducible]
def proj : OuterStmtIn × OuterWitIn → InnerStmtIn × InnerWitIn :=
  fun ctxIn => ⟨lens.stmt.toFunA ctxIn.1, lens.wit.toFunA ctxIn⟩

Module.Basis.reindex in Mathlib.LinearAlgebra.Basis.Defs

@[inline]
def neg [Neg R] (p : MlPoly R n) : MlPoly R n := p.map (fun a => -a)

def relHammingBall (C : Code ι F) (y : ι → F) (r : ℝ) : Code ι F :=
  { c | c ∈ C ∧ Code.relHammingDist y c ≤ r }

class SliceGE (coll : Type u) (start : Type v) (valid : outParam (coll → start → Prop))
    (subcoll : outParam ((xs : coll) → (start : start) → (h : valid xs start) → Type w)) where
  sliceGE : (xs : coll) → (start : start) → (h : valid xs start) → subcoll xs start h

inductive MemoryOp (ι : Type u) (α : ι → Type v) where
  | read (op : MemoryRead ι α)
  | write (op : MemoryWrite ι α)

noncomputable def queryOracleVerifier :
  OracleVerifier
    (oSpec := []ₒ)
    (StmtIn := FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (OStmtIn := OracleStatement 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (
    Fin.last ℓ))
    (StmtOut := Bool)
    (OStmtOut := fun _ : Empty => Unit)
    (pSpec := pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) where
  verify := fun (stmt: FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (challenges: (pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Challenges) => do
    
    let c := stmt.final_constant
    let fold_challenges : Fin γ_repetitions → sDomain 𝔽q β h_ℓ_add_R_rate 0 :=
      challenges ⟨0, by admit /- proof elided -/
      ⟩

    
    
    for rep in (List.finRange γ_repetitions) do
      let mut c_cur : L := 0 
      let v := fold_challenges rep

      for k_val in List.finRange (ℓ / ϑ) do
        let i := k_val * ϑ
        have h_k: k_val ≤ (ℓ/ϑ - 1) := by admit /- proof elided -/

@[inline, specialize, simp]
def reduction : Reduction oSpec Statement Witness Statement Witness !p[] := Reduction.id

Sum.elim in Init.Data.Sum.Basic

Fin.succEmb in Mathlib.Data.Fin.Embedding

def getPutativeRoot_with_hash {s} (idx : BinaryTree.SkeletonLeafIndex s)
    (leafValue : α) (proof : List α) (hashFn : α → α → α) : α :=
  match proof with
  | [] => leafValue 
  | siblingBelowRootHash :: restProof =>
    match idx with
    | BinaryTree.SkeletonLeafIndex.ofLeaf =>
      
      
      
      leafValue
    | BinaryTree.SkeletonLeafIndex.ofLeft idxLeft =>
      
      hashFn (getPutativeRoot_with_hash idxLeft leafValue restProof hashFn) siblingBelowRootHash
    | BinaryTree.SkeletonLeafIndex.ofRight idxRight =>
      
      hashFn siblingBelowRootHash (getPutativeRoot_with_hash idxRight leafValue restProof hashFn)

@[reducible]
def CanonicalDuplexSponge (U : Type) [SpongeUnit U] [SpongeSize] :=
  DuplexSponge U (CanonicalSpongeState U)

@[reducible]
def coreInteractionOracleVerifier :=
  OracleVerifier.append (oSpec:=[]ₒ)
    (Stmt₁ := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) 0)
    (Stmt₂ := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) (Fin.last ℓ))
    (Stmt₃ := FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (OStmt₁ := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ 0)
    (OStmt₂ := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (OStmt₃ := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ))
    (pSpec₁ := pSpecSumcheckFold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (pSpec₂ := pSpecFinalSumcheckStep (L:=L))
    (V₁ := sumcheckFoldOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (V₂ := finalSumcheckVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))

noncomputable def sDomainToFin (i : Fin r) (h_i : i < ℓ + R_rate)
  (x : sDomain 𝔽q β h_ℓ_add_R_rate i) :
  Fin (2^(ℓ + R_rate - i.val)) :=

MonadLift.monadLift in Init.Prelude

noncomputable def foldProver :
  OracleProver []ₒ
    (Statement F i.castSucc) (OracleStatement D x s i.castSucc) (Witness F s d i.castSucc.castSucc)
    (Statement F i.succ) (OracleStatement D x s i.succ) (Witness F s d i.castSucc.succ)
    (pSpec D x s i) where
  PrvState
  | 0 =>
    (Statement F i.castSucc × ((j : Fin (↑i.castSucc + 1)) → OracleStatement D x s i.castSucc j)) ×
      Witness F s d i.castSucc.castSucc
  | _ =>
    (Statement F i.succ × ((j : Fin (↑i.castSucc + 1)) → OracleStatement D x s i.castSucc j)) ×
      Witness F s d i.castSucc.succ

  input := id

  sendMessage
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => fun ⟨⟨chals, o⟩, p⟩ =>
    pure ⟨fun x => p.1.eval x.1.1, ⟨⟨chals, o⟩, p⟩⟩

  receiveChallenge
  | ⟨0, _⟩ => fun ⟨⟨chals, o⟩, p⟩ => pure <|
    fun (α : F) =>
      ⟨
        ⟨Fin.append chals (fun (_ : Fin 1) => α), o⟩,
        ⟨p.1.foldNth (2 ^ (s i.castSucc).1) α, witness_lift p.2⟩
      ⟩
  | ⟨1, h⟩ => nomatch h

  output := fun ⟨⟨chals, o⟩, p⟩ => pure <|
    ⟨
      ⟨
        chals,
        fun j =>
          if h : j.1 < i.1
          then by admit /- proof elided -/
      ⟩,
      p
    ⟩

Fin.init in Mathlib.Data.Fin.Tuple.Basic

def sub_descending (p q : UniPoly R) : QuotientUniPoly R :=
  Quotient.mk _ (sub p q)

LT.lt in Init.Prelude

Matrix.det in Mathlib.LinearAlgebra.Matrix.Determinant.Basic

def findNeighbors {n : ℕ} (i : Fin (2 ^ n)) (layer : Fin n) :
    Fin (2 ^ (layer.val + 1)) :=
  
  
  let bits := (Vector.ofFn (finFunctionFinEquiv.invFun i)).reverse
  
  let neighbor := (bits.set layer (bits.get layer + 1)).take (layer.val + 1)
  have : min (layer.val + 1) n = layer.val + 1 := by admit /- proof elided -/

RatFunc in Mathlib.FieldTheory.RatFunc.Defs

def bitsToU (i : Fin r) (k : Fin (2 ^ i.val)) :
    AdditiveNTT.U (L := L) (𝔽q := 𝔽q) (β := β) i :=
  let val := (Finset.univ : Finset (Fin i)).sum fun j =>
    if (Nat.getBit (n := k.val) (k := j.val) == 1) then
      β ⟨j, by admit /- proof elided -/
      ⟩
    else 0

  
  ⟨val, by admit /- proof elided -/
  ⟩

noncomputable def relayRbrExtractor (i : Fin ℓ) :
  Extractor.RoundByRound []ₒ
    (StmtIn := (Statement (L := L) Context i.succ) × (∀ j, OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc j))
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (pSpec := pSpecRelay)
    (WitMid := fun _messageIdx => Witness (L := L) 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ) where
  eqIn := rfl
  extractMid := fun _ _ _ witMidSucc => witMidSucc
  extractOut := fun _ _ witOut => witOut

instance {i : Fin r} : Module (R := 𝔽q) (M := U 𝔽q β i) := Submodule.module _

Polynomial.toFinsupp in Mathlib.Algebra.Polynomial.Basic

def getPutativeRoot {n : ℕ} (i : Fin (2 ^ n)) (leaf : α) (proof : List.Vector α n) :
    OracleComp (spec α) α := do
  match h : n with
  | 0 => do
    
    return leaf
  | n + 1 => do
    
    let signBit := i.val % 2
    
    let i' : Fin (2 ^ n) := ⟨i.val / 2, by admit /- proof elided -/
    ⟩
    if signBit = 0 then
      
      let newLeaf ← query (spec := spec α) () ⟨leaf, proof.get (Fin.last n)⟩
      getPutativeRoot i' newLeaf (proof.drop 1)
    else
      
      let newLeaf ← query (spec := spec α) () ⟨proof.get (Fin.last n), leaf⟩
      getPutativeRoot i' newLeaf (proof.drop 1)

@[reducible, inline, specialize, simp]
def Challenge (pSpec : ProtocolSpec n) (i : ChallengeIdx pSpec) := pSpec.«Type» i.val

Finset.card in Mathlib.Data.Finset.Card

def MLE (evals : (σ → Fin 2) → R) : MvPolynomial σ R :=
    ∑ x : σ → Fin 2, (eqPolynomial (x : σ → R)) * C (evals x)

def liftConcreteBTField (k : ℕ) (prevBTFResult : ConcreteBTFStepResult (k := k)) :
  Field (ConcreteBTField (k + 1)) :=

def testNTTBTF₃ : Fin (2 ^ (2 + 2)) → BTF₃ :=

def finSum'FinEquiv' {m : ℕ} {n : Fin m → ℕ} : (i : Fin m) × Fin (n i) ≃ Fin (vsum n) where
  toFun := fun ij => embedSum ij.1 ij.2
  invFun := splitSum
  left_inv := fun ij => splitSum_embedSum ij.1 ij.2
  right_inv := embedSum_splitSum

CommMonoid in Mathlib.Algebra.Group.Defs

def last_nonzero (p : UniPoly R) : Option (Fin p.size) :=
  p.findIdxRev? (· != 0)

def Verifier.liftContext
    (lens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut)
    (V : Verifier oSpec InnerStmtIn InnerStmtOut pSpec) :
      Verifier oSpec OuterStmtIn OuterStmtOut pSpec where
  verify := fun stmtIn transcript => do
    let innerStmtIn := lens.proj stmtIn
    let innerStmtOut ← V.verify innerStmtIn transcript
    return lens.lift stmtIn innerStmtOut

MulOneClass in Mathlib.Algebra.Group.Defs

abbrev 𝕃 (H : F[X][Y]) : Type :=
  (Polynomial (RatFunc F)) ⧸ (Ideal.span {H_tilde H})

def mulVec [Zero α] [Add α] [Mul α] {numRows numCols : Nat}
    (M : Vector (Vector α numCols) numRows)
    (x : Vector α numCols) : Vector α numRows :=
  M.map (fun row => row *ᵥ x)

noncomputable def batchVerifier :
  OracleVerifier []ₒ
    Unit (OracleStatement D x m)
    ((Fin m → F) × Fri.Spec.Statement F (0 : Fin (k + 1)))
    (OracleStatement D x m)
    (batchSpec F m) where
  verify := fun _ chals => pure ⟨chals ⟨0, by admit /- proof elided -/
  ⟩, Fin.elim0⟩
  embed :=
    ⟨
      fun i => Sum.inl i,
      by admit /- proof elided -/
    ⟩
  hEq := by admit /- proof elided -/

@[simp]
abbrev EvalClaim : R1CS.MatrixIdx → Type := fun _ => R

def Adversary (ι : Type) (G : Type) (p : ℕ) (bitLength : ℕ) (α : Type) : Type _ :=
  ReaderT (GroupValTable ι G)
    (OracleComp (GroupOpOracle ι ++ₒ GroupExpOracle ι p ++ₒ
      GroupEqOracle ι ++ₒ GroupEncodeOracle ι bitLength))
    (List ι × α)

def deriveTranscriptSR {ι : Type} {oSpec : OracleSpec ι} {StmtIn : Type}
    (stmt : StmtIn) (messages : pSpec.Messages) :
    OracleComp (oSpec ++ₒ fsChallengeOracle StmtIn pSpec) pSpec.FullTranscript := do
  MessagesUpTo.deriveTranscriptSR stmt (Fin.last n) messages

alias deriveTranscriptFS := deriveTranscriptSR

Int.negSucc in Init.Data.Int.Basic

@[reducible, simp]
def ChallengeIdx (pSpec : ProtocolSpec n) :=
  {i : Fin n // pSpec.dir i = Direction.V_to_P}

LawfulBEq in Init.Core

instance polyMonic (n : ℕ) : Monic (poly n) := definingPoly_is_monic (Z n)

@[reducible]
def empty : ProtocolSpec 0 := ⟨!v[], !v[]⟩

def Prover.duplexSpongeFiatShamir (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
    NonInteractiveProver (∀ i, pSpec.Message i) (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      StmtIn WitIn StmtOut WitOut where
  PrvState := fun i => match i with
    | 0 => StmtIn × P.PrvState 0
    | _ => P.PrvState (Fin.last n)
  input := fun ctx => ⟨ctx.1, P.input ctx⟩
  
  sendMessage | ⟨0, _⟩ => fun ⟨stmtIn, state⟩ => do
    let ⟨messages, _, state⟩ ← P.runToRoundDSFS (Fin.last n) stmtIn state
    return ⟨messages, state⟩
  
  receiveChallenge | ⟨0, h⟩ => nomatch h
  output := fun st => (P.output st).liftComp _

Matrix.vecMul in Mathlib.Data.Matrix.Mul

instance [VerifierFirst pSpec] [h : VCVCompatible (pSpec.«Type» 0)] :
    ∀ i, VCVCompatible (pSpec.Challenge i)
  | ⟨0, _⟩ => inferInstance

instance : One (Cayley T) where
  one := one

structure ConcreteBTFStepResult (k : ℕ) extends (ConcreteBTFieldProps k) where
  instFintype : Fintype (ConcreteBTField k)
  fieldFintypeCard : Fintype.card (ConcreteBTField k) = 2^(2^k)
  
  sumZeroIffEq : ∀ (x y : ConcreteBTField k), x + y = 0 ↔ x = y
  traceMapEvalAtRootsIs1 :
    letI := mkFieldInstance (k:=k) (props:=toConcreteBTFieldProps)
    TraceMapProperty (ConcreteBTField k) (u:=Z k) k
  instIrreduciblePoly :
    letI := mkFieldInstance (k:=k) (props:=toConcreteBTFieldProps)
    (Irreducible (p := (definingPoly (s:=(Z k)))))

def Verifier.StateFunction.liftContext
    {σ : Type} {init : ProbComp σ} {impl : QueryImpl oSpec (StateT σ ProbComp)}
    (lens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut)
    (V : Verifier oSpec InnerStmtIn InnerStmtOut pSpec)
    (outerLangIn : Set OuterStmtIn) (outerLangOut : Set OuterStmtOut)
    (innerLangIn : Set InnerStmtIn) (innerLangOut : Set InnerStmtOut)
    [lensSound : lens.IsSound outerLangIn outerLangOut innerLangIn innerLangOut
      (V.compatStatement lens)]
    (stF : V.StateFunction init impl innerLangIn innerLangOut) :
      (V.liftContext lens).StateFunction init impl outerLangIn outerLangOut
where
  toFun := fun m outerStmtIn transcript =>
    stF m (lens.proj outerStmtIn) transcript
  toFun_empty := fun stmt => by admit /- proof elided -/

def coeffs [DecidableEq F] (f : F[X][Y]) : Finset F[X] := f.support.image f.coeff

def three : ChurchNat α := succ two

instance : ∀ j, OracleInterface ((pSpec D x l).Message j) := fun j =>
  match j with
  | ⟨0, h⟩ => nomatch h

Option in Init.Prelude

def leftpad {m : ℕ} {α : Sort*} (n : ℕ) (a : α) (v : Fin m → α) : Fin n → α :=
  fun i => if h : n - m ≤ i then v ⟨i - (n - m), by admit /- proof elided -/
  ⟩ else a

@[reducible]
noncomputable def reductionFold :
  OracleReduction []ₒ
    (Statement F (0 : Fin (k + 1))) (OracleStatement D x s (0 : Fin (k + 1)))
      (Witness F s d (0 : Fin (k + 2)))
    (FinalStatement F k) (FinalOracleStatement D x s)
      (Witness F s d (Fin.last (k + 1)))
    (pSpecFold D x k s ++ₚ FinalFoldPhase.pSpec F)
 := OracleReduction.append
      (OracleReduction.seqCompose _ _ (fun (i : Fin (k + 1)) => Witness F s d i.castSucc)
        (FoldPhase.foldOracleReduction D x s d))
      (FinalFoldPhase.finalFoldOracleReduction D x (k := k) s d)

class Serialize (α : Type u) (β : Type v) where
  serialize : α → β

Fin.castSucc in Init.Data.Fin.Basic

SimOracle.append in VCVio.OracleComp.SimSemantics.Append

class Verifier.IsPure (V : Verifier oSpec StmtIn StmtOut pSpec) where
    is_pure : ∃ verify : _ → _ → _, ∀ stmtIn transcript,
      V.verify stmtIn transcript = pure (verify stmtIn transcript)

Nat.zero in Init.Prelude

instance (k : ℕ) : NeZero (2^k) :=

abbrev OutputStatement := StatementRound R _ (.last n)

noncomputable instance {H : F[X][Y]} : Ring (𝒪 H) :=
  Ideal.Quotient.ring (Ideal.span {H_tilde' H})

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

instance instDCast : DCast Nat ProtocolSpec where
  dcast h := ProtocolSpec.cast h
  dcast_id := cast_id

instance [VerifierFirst pSpec] : VerifierLast pSpec where
  verifier_last' := by admit /- proof elided -/

absurd in Init.Prelude

Fintype.decidablePiFintype in Mathlib.Data.Fintype.Defs

def duplexSpongeToBasicFSAlgo
    (P : OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
    (StmtIn × pSpec.Messages)) :
    OracleComp (oSpec ++ₒ fsChallengeOracle StmtIn pSpec) (StmtIn × pSpec.Messages) :=
  sorry

alias d2SAlgo := duplexSpongeToBasicFSAlgo

finProdFinEquiv in Mathlib.Logic.Equiv.Fin.Basic

tail in ToMathlib.Control.Comonad.Instances

Nat.floor in Mathlib.Algebra.Order.Floor.Defs

instance : LE AssocNat where
  le a b := a 0 ≤ b 0

System.FilePath in Init.System.FilePath

@[reducible, simp] def WitIn := Unit

instance instDCastSigmaSigma {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    {δ : (a : α) → (b : β a) → γ a b → Type*}
    [DCast α β] [DCast₂ α β γ] [DCast₃ α β γ δ] :
    DCast ((a : α) × (b : β a) × γ a b) (fun a => δ a.1 a.2.1 a.2.2) where
  dcast hc d := dcast₃ (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) d
  dcast_id := by admit /- proof elided -/

def BBF_CodeDistance (ℓ 𝓡 : ℕ) (i : Fin (ℓ + 1)) : ℕ :=
  2^(ℓ + 𝓡 - i.val) - 2^(ℓ - i.val) + 1

instance BitVec.instDCast : DCast Nat BitVec where
  dcast h := BitVec.cast h
  dcast_id := by admit /- proof elided -/

def computeLookaheadSequenceFamily
    (trace : QueryLog (forwardPermutationOracle (CanonicalSpongeState U)))
    (state : CanonicalSpongeState U) (i : pSpec.ChallengeIdx) :
    LookaheadSequenceFamily trace state i :=
  sorry

RingHom.toAlgebra in Mathlib.Algebra.Algebra.Defs

abbrev MultiquadraticPoly (L : Type) [CommSemiring L] (ℓ : ℕ) := L⦃≤ 2⦄[X Fin ℓ]

def findSum (l : List α) (j : α) : Option α := l.partialSum.find? (j < ·)

@[simp]
def evalDomain (i : ℕ) : Set Fˣ :=
  (x ^ (2 ^ i)) • (Domain.evalDomain D i)

IO.throwServerError in Lean.Server.Utils

def disagreementSet (i : Fin ℓ) (steps : ℕ) [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
  (f g : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i.val + steps, by admit /- proof elided -/
    ⟩) :
  Set ((sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i.val + steps, by admit /- proof elided -/
  ⟩) :=
  {y | f y ≠ g y}

def isScalarTower_succ_right (l r : ℕ) (h_le : l ≤ r) :=
    instAlgebraTowerConcreteBTF.toIsScalarTower (i:=l) (j:=r) (k:=r+1)
    (h1:=by admit /- proof elided -/
    ) (h2:=by admit /- proof elided -/
    )

noncomputable def liftBivariate {H : F[X][Y]} : F[X][Y] →+* 𝕃 H :=
  RingHom.comp (Ideal.Quotient.mk (Ideal.span {H_tilde H})) bivPolyHom

instance (n : AssocNat) : DecidableEq (AssocFin n) :=

def relayPrvState (i : Fin ℓ) : Fin (0 + 1) → Type := fun
  | ⟨0, _⟩ => 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

String.intercalate in Init.Data.String.Defs

Nat.gcd in Init.Data.Nat.Gcd

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

instance instOI₁ : ∀ i, OracleInterface ((⟨!v[.P_to_V], !v[R⦃≤ deg⦄[X]]⟩ ++ₚ !p[]).Message i) :=
  instOracleInterfaceMessageAppend

BitVec.append in Init.Data.BitVec.Basic

noncomputable def eCodeDistNew (C : Set (n → R)) : ENNReal := C.einfsep

def rbrKnowledgeSoundness
    (relIn : Set ((StmtIn × ∀ i, OStmtIn i) × WitIn))
    (relOut : Set ((StmtOut × ∀ i, OStmtOut i) × WitOut))
    (verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  verifier.toVerifier.rbrKnowledgeSoundness init impl relIn relOut rbrKnowledgeError

noncomputable def D_X (rho : ℚ) (n m : ℕ) : ℝ := (m + 1/2) * (Real.sqrt rho) * n

Fin.castLE in Init.Data.Fin.Basic

def append {ι₁ : Type u} {T₁ : ι₁ → Type v} [∀ i, OracleInterface (T₁ i)]
    {ι₂ : Type u} {T₂ : ι₂ → Type v} [∀ i, OracleInterface (T₂ i)] : OracleSpec (ι₁ ⊕ ι₂) :=
  [Sum.rec T₁ T₂]ₒ

instance : ∀ j, OracleInterface ((pSpecNonLastBlocks 𝔽q β (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Message j) := instOracleInterfaceMessageSeqCompose

instance instOfNat {n : ℕ} : OfNat (CNat n) n := match n with
  | 0 => by admit /- proof elided -/
  | .succ n => by admit /- proof elided -/

private def k [Zero F] (B : Finset (Fin n → F)) : ℚ :=
  (1 : ℚ) / n * ∑ i, K B i 0

Mathlib.Linter.TextBased.lintModules in Mathlib.Tactic.Linter.TextBased

@[inline] def toT [Zero T] (c : Cayley T) : T := c.toFun 0

@[simp]
abbrev Statement.AfterFirstSumcheck : Type :=
  FirstSumcheckChallenge R pp × Statement.AfterFirstChallenge R pp

def dummyLastWitness :
    Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ) := {
  t := ⟨0, by admit /- proof elided -/
  ⟩,
  H := ⟨0, by admit /- proof elided -/
  ⟩,
  f := fun _ => 0
}

def isRead : MemoryOp ι α → Prop
  | read _ => True
  | _ => False

AddGroup in Mathlib.Algebra.Group.Defs

noncomputable def foldRbrExtractor (i : Fin ℓ) :
  Extractor.RoundByRound []ₒ
    (StmtIn := (Statement (L := L) Context i.castSucc) × (∀ j,
      OracleStatement 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc j))
    (WitIn := Witness (L := L) 𝔽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))
    (WitMid := fun _messageIdx => Witness (L := L) 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc) where
  eqIn := rfl
  extractMid := fun _ _ _ witMidSucc => witMidSucc
  extractOut := fun ⟨stmtIn, oStmtIn⟩ fullTranscript witOut => by admit /- proof elided -/

CommSemiring in Mathlib.Algebra.Ring.Defs

Vector.flatten in Init.Data.Vector.Basic

@[ext]
structure Verifier {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn StmtOut : Type) {n : ℕ} (pSpec : ProtocolSpec n) where
  verify : StmtIn → FullTranscript pSpec → OracleComp oSpec StmtOut

def natCast_succ {k : ℕ} (n : ℕ) : natCast (k:=k) (n + 1) = natCast (k:=k) n + 1 :=

@[reducible]
def GroupValTable (ι : Type*) (G : Type*) := Π₀ _ : ι, Option G

UInt16.ofFin in Init.Data.UInt.Basic

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 -/

def computableNTTStage [Fact (LinearIndependent 𝔽q β)]
  (i : Fin ℓ) (b : Fin (2 ^ (ℓ + R_rate)) → L) : Fin (2^(ℓ + R_rate)) → L :=
  have h_2_pow_i_lt_2_pow_ℓ_add_R_rate: 2^i.val < 2^(ℓ + R_rate) := by admit /- proof elided -/

BitVec.zero in Init.Data.BitVec.Basic

structure PrimeWithMultiplicity : Type where
  prime : ℕ
  multiplicity : ℕ
deriving Repr

Prod.snd in Init.Prelude

Algebra.ofId in Mathlib.Algebra.Algebra.Hom

def MLE' {n : ℕ} (evals : Fin (2 ^ n) → R) : MvPolynomial (Fin n) R :=
  MLE (evals ∘ finFunctionFinEquiv)

instance instDCast₂ : DCast₂ Nat ProtocolSpec (fun _ pSpec => FullTranscript pSpec) where
  dcast₂ h h' T := FullTranscript.cast h h' T
  dcast₂_id := cast_id

@[inline] def lagrangeToMonoLevel {n : ℕ} (j : Fin n) : Vector R (2 ^ n) → Vector R (2 ^ n) :=
  fun v =>
    let stride : ℕ := 2 ^ j.val  
    Vector.ofFn (fun i : Fin (2 ^ n) =>
      if (BitVec.ofFin i).getLsb j then
        v[i] - v[i - stride]'(Nat.sub_lt_of_lt i.isLt)
      else
        v[i])

instance : OracleInterfaces (vPSpec.toProtocolSpec A) where
  oracleInterfaces := fun _ => some OracleInterface.instVector

Vector in Init.Data.Vector.Basic

Vector.insertIdx in Init.Data.Vector.Basic

class IsSecure
    (relation : Set ((Statement × ∀ i, OStatement i) × Witness))
    (ε_rbr : vPSpec.ChallengeIdx → ℝ≥0)
    (vectorIOP : VectorIOP Statement OStatement Witness vPSpec A) where

   
  is_complete : vectorIOP.perfectCompleteness (pure ()) ⟨isEmptyElim⟩ relation

   
  is_rbr_knowledge_sound :
    OracleProof.rbrKnowledgeSoundness (pure ()) ⟨isEmptyElim⟩ relation vectorIOP.verifier ε_rbr

instance [Zero T] [ToNat T] : Mul (Cayley T) where
  mul := mul

hammingNorm in Mathlib.InformationTheory.Hamming

def finUInt16Equiv : Fin (2 ^ 16) ≃ UInt16 where
  toFun := fun i => UInt16.ofFin i
  invFun := fun u => u.toFin
  left_inv _ := rfl
  right_inv _ := rfl

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)

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 -/

@[reducible]
def messageLength (vPSpec : VectorSpec n) (i : MessageIdx vPSpec) : Nat := vPSpec.length i

def truncate (p : Polynomial F) (n : ℕ) : Polynomial F
  := ⟨⟨p.1.1 ∩ Finset.range n, fun i ↦ if i < n then p.1.2 i else 0, by admit /- proof elided -/
  ⟩⟩

instance [h : VerifierFirst pSpec] : VerifierFirst pSpec where
  verifier_first' := by admit /- proof elided -/

@[inline]
def ofOutputOnly (liftStmt : OuterStmtIn → InnerStmtOut → OuterStmtOut) :
    Statement.Lens OuterStmtIn OuterStmtOut OuterStmtIn InnerStmtOut :=
  ⟨id, liftStmt⟩

def LeafData.composeBuild {α : Type} {s : Skeleton} (leaf_data_tree : LeafData α s)
    (compose : α → α → α) :
    FullData α s :=
  match s, leaf_data_tree with
  | Skeleton.leaf, LeafData.leaf value =>
    FullData.leaf value
  | Skeleton.internal _ _, LeafData.internal left right =>
    let left_tree := LeafData.composeBuild left compose
    let right_tree := LeafData.composeBuild right compose
    FullData.internal
      (compose left_tree.getRootValue right_tree.getRootValue)
      left_tree
      right_tree

def statelessOracle (baseSpec : OracleSpec ιₜ) (spec : OracleSpec ι)
    (f : (i : ι) → spec.domain i → spec.range i) :
    SimOracle.Stateless (baseSpec ++ₒ spec) baseSpec where
  impl
  | query (.inl i) t => query i t
  | query (.inr i) t => pure (f i t)

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

@[reducible, simp] def OStmtIn := fun _ : Fin 2 => OStatement

def ExtractabilityAdversary (oSpec : OracleSpec ι) (Data Commitment AuxState : Type)
    [O : OracleInterface Data] :=
  OracleComp oSpec (Commitment × O.Query × O.Response × AuxState)

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

  PrvState := foldPrvState 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i

  input := fun ⟨⟨stmt, oStmt⟩, wit⟩ => (stmt, oStmt, wit)

  sendMessage 
  | ⟨0, _⟩ => fun ⟨stmt, oStmt, wit⟩ => do
    let curH : ↥L⦃≤ 2⦄[X Fin (ℓ - ↑i.castSucc)] := wit.H
    let h_i : L⦃≤ 2⦄[X] := by admit /- proof elided -/

noncomputable def relayOracleProver (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleProver (oSpec := []ₒ)
    
    (StmtIn := Statement (L := L) Context i.succ)
    (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.succ)
    (StmtOut := Statement (L := L) Context i.succ)
    (OStmtOut := OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ := ℓ) i.succ)
    (pSpec := pSpecRelay) where
  PrvState := relayPrvState 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i
  input := fun ⟨⟨stmtIn, oStmtIn⟩, witIn⟩ => (stmtIn, oStmtIn, witIn)
  sendMessage | ⟨x, h⟩ => by admit /- proof elided -/
| ⟨x, h⟩ => by admit /- proof elided -/

def relation (cs : ConstraintSystem 𝓡 numWires numGates) (ℓ : ℕ) (hℓ : ℓ ≤ numWires) :
    (publicInputs : Fin ℓ → 𝓡) → (privateWitness : Fin (numWires - ℓ) → 𝓡) → Prop :=
  fun (x : Fin ℓ → 𝓡) (ω : Fin (numWires - ℓ) → 𝓡) =>
    let combined := Fin.append x ω ∘ Fin.cast (by admit /- proof elided -/
    )
    cs.accepts combined

Polynomial.reverse in Mathlib.Algebra.Polynomial.Reverse

def monomial (n : ℕ) (r : R) : P := C r * X ^ n

def makeZero (ι : ℕ) (F : Type*) [Zero F] : Fin ι → F := fun _ ↦ 0

abbrev MultilinearPoly (L : Type) [CommSemiring L] (ℓ : ℕ) := L⦃≤ 1⦄[X Fin ℓ]

Polynomial.Monic in Mathlib.Algebra.Polynomial.Degree.Definitions

LT in Init.Prelude

class Initialize (α : Type u) (β : Type v) where
   
  new : β → α

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

@[inline] def ofNat' (k : Nat) : AssocNat :=
  ⟨fun m => k + m, fun m => Nat.add_assoc k m 1⟩

Set.Ioc in Mathlib.Order.Interval.Set.Defs

def multilinearBasis (l r : ℕ) (h_le : l ≤ r) :
    letI instAlgebra := ConcreteBTFieldAlgebra (h_le:=h_le)
    Basis (Fin (2 ^ (r - l))) (ConcreteBTField l) (ConcreteBTField r) :=

def numOStmtQueries [DecidableEq ιₛᵢ] (i : ιₛᵢ)
    (stmt : StmtIn) (challenges : ∀ i, pSpec.Challenge i)
    (naVerifier : OracleVerifier.NonAdaptive oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec) : ℕ :=
  (naVerifier.queryOStmt stmt challenges).filter (fun q => q.1 = i) |>.length

Quotient.lift₂ in Init.Core

List.finRange in Init.Data.List.FinRange

def finIdxOfIfTrue [BEq α] [LawfulBEq α] (a : α) (l : List α) (h : a ∈ l) : Fin l.length :=
  ⟨List.idxOf' a l, by admit /- proof elided -/
  ⟩

@[reducible, inline, specialize]
def UniPoly (R : Type*) := Array R

@[reducible]
def relation :
    (Fin sz.n_x → R) → 
    (MatrixIdx → Matrix (Fin sz.m) (Fin sz.n) R) → 
    (Fin sz.n_w → R) → 
    Prop :=
  fun stmt matrix wit =>
    letI 𝕫 := 𝕫 stmt wit
    (matrix .A *ᵥ 𝕫) * (matrix .B *ᵥ 𝕫) = (matrix .C *ᵥ 𝕫)

def verifier : Verifier oSpec (StmtIn R × (∀ i, OStmtIn R deg i))
                              (StmtOut R × (∀ i, OStmtOut R deg i)) (pSpec R deg) where
  verify := fun ⟨target, oStmt⟩ transcript => do
    letI polyLE := transcript 0
    guard (∑ x ∈ (univ.map D), polyLE.val.eval x = target)
    letI chal := transcript 1
    pure ⟨⟨(oStmt ()).val.eval chal, chal⟩, fun _ => oStmt ()⟩

instance : Field ScalarField := ZMod.instField scalarFieldSize

def srSoundnessGame (P : Prover.StateRestoration.Soundness oSpec StmtIn pSpec) :
    OracleComp (oSpec ++ₒ (srChallengeOracle StmtIn pSpec))
      (pSpec.FullTranscript × StmtIn) := do
  let ⟨stmtIn, messages⟩ ← P
  let transcript ← messages.deriveTranscriptSR stmtIn
  return ⟨transcript, stmtIn⟩

def subLeftFull (U : Matrix (Fin m) (Fin n) F) (c_reindex : Fin m → Fin n) :
  Matrix (Fin m) (Fin m) F := Matrix.submatrix U id c_reindex

def collisionPerm : Prop :=
  collisionFwdFwd trace ∨ collisionBwdBwd trace ∨ collisionFwdBwd trace ∨ collisionBwdFwd trace

alias E_prp := collisionPerm

Monoid in Mathlib.Algebra.Group.Defs

def ratchetUnchecked [Permute C] (sponge : DuplexSponge U C) : DuplexSponge U C :=
  simulateQ' forwardPermutationOracleImpl (ratchet sponge) (by admit /- proof elided -/
  )

def getNargString (state : FSProverState U H R) : ByteArray := state.nargString

structure Rewinding (oSpec : OracleSpec ι)
    (StmtIn StmtOut WitIn WitOut : Type) {n : ℕ} (pSpec : ProtocolSpec n) where
   
  ExtState : Type
   
  simChallenge : SimOracle.Stateful [pSpec.Challenge]ₒ [pSpec.Challenge]ₒ ExtState
   
  simOracle : SimOracle.Stateful oSpec oSpec ExtState
   
  runExt : StmtOut → WitOut → StmtIn →
    StateT ExtState (OracleComp (OracleSpec.proverOracle StmtIn pSpec)) WitIn

@[simp]
def finRangeTo {k : ℕ} (i : ℕ) : Finset (Fin k) :=
  (List.take i (List.finRange k)).toFinset

RingHom.id in Mathlib.Algebra.Ring.Hom.Defs

@[inline, specialize]
def neg {R : Type*} [Ring R] [BEq R] (p : QuotientUniPoly R) : QuotientUniPoly R :=
  Quotient.lift neg_descending neg_descends p

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

def finSuccEquivNth' (i : Fin n) : Fin n ≃ Option (Fin (n - 1)) :=

instance polyIrreducible (n : ℕ) : Irreducible (poly n) := (BinaryTowerAux n).2.instIrreduciblePoly

OracleSpec.OracleQuery in VCVio.OracleComp.OracleComp

instance instOneConcreteBTField (k : ℕ) : One (ConcreteBTField k) where
  one := one

@[reducible, inline]
instance instPolynomialDegreeLT : OracleInterface (R⦃< d⦄[X]) where
  Query := R
  Response := R
  answer := fun ⟨poly, _⟩ point => poly.eval point

instance (priority := high) : MonadLiftT (OracleComp []ₒ) (OracleComp spec) where
  monadLift := OracleComp.construct pure (fun a => by admit /- proof elided -/
  ) failure

instance instDCast₁₂ : DCast (β a) (γ a) where
  dcast hb c := dcast₂ (Eq.refl a) (by admit /- proof elided -/
  ) c
  dcast_id := by admit /- proof elided -/

def checkSrs (proveSrs : Vector G₁ (n + 1)) (verifySrs : Vector G₂ 2) : Prop :=
  ∀ i : Fin n,
    pairing (proveSrs[i.succ]) (verifySrs[0]) = pairing (proveSrs[i.castSucc]) (verifySrs[1])

def Function.extendDomain {α β : Type*} [DecidableEq α] [Zero β] {s : Finset α}
    (f : (x : α) → (x ∈ s) → β) : α → β :=
  fun x ↦ if hx : x ∈ s then f x hx else 0

@[inline] def max [Zero T] [ToNat T] (a b : Cayley T) : Cayley T :=
  if (a : Nat) ≥ (b : Nat) then a else b

Function.update in Mathlib.Logic.Function.Basic

instance : ∀ j, SelectableType ((fullPSpec 𝔽q β γ_repetitions (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Challenge j) := instSelectableTypeChallengeAppend

UInt8.ofFin in Init.Data.UInt.Basic

class GenMutualCorrParams (P : Params ι F) (S : ∀ i : Fin (M + 1), Finset (ι i)) where

  δ : Fin (M + 1) → ℝ≥0
  dist : (i : Fin (M + 1)) → Fin ((P.foldingParam i) + 1) → ℝ≥0


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

  inst1 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (indexPowT (S i) (P.φ i) j)
  inst2 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    Nonempty (indexPowT (S i) (P.φ i) j)
  inst3 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    DecidableEq (indexPowT (S i) (P.φ i) j)
  inst4 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Smooth (φ i j)

  parℓ_type : ∀ i : Fin (M + 1), ∀ _ : Fin ((P.foldingParam i) + 1), Type
  inst5 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (parℓ_type i j)

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



  Gen_α : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    ProximityGenerator (indexPowT (S i) (P.φ i) j) F :=
      fun i j => RSGenerator.genRSC (parℓ_type i j) (φ i j) (P.varCount i - j) (exp i j)

  inst6 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (Gen_α i j).parℓ

  BStar : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    (Set ((indexPowT (S i) (P.φ i) j) → F)) → Type → ℝ≥0
  errStar : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    (Set ((indexPowT (S i) (P.φ i) j) → F)) → Type → ℝ → ENNReal

  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

  h : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    hasMutualCorrAgreement (Gen_α i j)
      (BStar i j (C i j) (Gen_α i j).parℓ)
      (errStar i j (C i j) (Gen_α i j).parℓ)

  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

  hδLe : ∀ i : Fin (M + 1),
    (δ i) ≤ 1 - Finset.univ.sup (fun j => BStar i j (C i j) (Gen_α i j).parℓ)

  hlistDecode : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    listDecodable (C i j) (δ i) (dist i j)

def join_via_add_smul (k : ℕ) (h_pos : k > 0) (hi_btf lo_btf : ConcreteBTField (k - 1)) :
    ConcreteBTField k :=

def toRoundByRound (E : RoundByRoundOneShot oSpec StmtIn WitIn pSpec) :
    RoundByRound oSpec StmtIn WitIn WitOut pSpec (fun _ => WitIn) where
  eqIn := rfl
  extractMid := fun m stmtIn tr witIn =>
    if m.castSucc = 0 then witIn else E m.castSucc stmtIn (Fin.init tr) default
  extractOut := fun stmtIn tr _ => E (.last n) stmtIn tr default

def relayKnowledgeError (m : pSpecRelay.ChallengeIdx) : ℝ≥0 :=
  match m with
  | ⟨j, _⟩ => j.elim0

def vconcat {n : ℕ} (v : Fin n → α) (a : α) : Fin (n + 1) → α :=
  dconcat v a

@[inline]
def ofInputOnly (projStmt : OuterStmtIn → InnerStmtIn) :
    Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn OuterStmtOut :=
  ⟨projStmt, fun _ => id⟩

instance : IsSingleRound (pSpec R deg) where
  prover_first' := by admit /- proof elided -/

def eval (p : MlPolyEval R n) (x : Vector R n) : R :=
  Vector.dotProduct p (lagrangeBasis x)

@[inline, specialize]
def prover : Prover oSpec Statement Witness (Statement × Witness) Unit (pSpec Witness) where
  PrvState
  | 0 => Statement × Witness
  | 1 => Statement × Witness
  input := id
  sendMessage | ⟨0, _⟩ => fun ⟨stmt, wit⟩ => pure (wit, ⟨stmt, wit⟩)
  receiveChallenge | ⟨0, h⟩ => nomatch h
  output := fun ⟨stmt, wit⟩ => pure (⟨stmt, wit⟩, ())

def widthDiv4 : Nat := params.width / 4

def relationAfterRandomQuery :
    Set (((StmtAfterRandomQuery R) × (∀ i, OStmtAfterRandomQuery R deg i)) × Unit) :=
  { ⟨⟨chal, oStmt⟩, _⟩ | (oStmt (Sum.inr ())).1.eval chal = (oStmt (Sum.inl ())).1.eval chal }

Module.Basis.mk in Mathlib.LinearAlgebra.Basis.Basic

def AlgebraTowerEquiv.toAlgEquivOverLeft (e : AlgebraTowerEquiv A B) (i j : ι) (h : i ≤ j) :
  letI : Algebra (A i) (A j) :=

Or in Init.Prelude

def outputRelation (cond : ∑ i, (s i).1 ≤ n) [DecidableEq F] (δ : ℝ≥0) :
    Set
      (
        (FinalStatement F k × ∀ j, FinalOracleStatement D x s j) ×
        Witness F s d (Fin.last (k + 1))
      ) := sorry

@[reducible, inline, specialize]
def ChallengesUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) : Type :=
  ∀ i, (pSpec.take k k.is_le).Challenge i

Polynomial.ofFn in Mathlib.Algebra.Polynomial.OfFn

def buildMerkleTree (α) (n : ℕ) (leaves : List.Vector α (2 ^ n)) :
    OracleComp (spec α) (Cache α n) := do
  match n with
  | 0 => do
    return fun j => (by admit /- proof elided -/
      )
  | n + 1 => do
    let lastLayer ← buildLayer α n leaves
    let cache ← buildMerkleTree α n lastLayer
    return Cache.cons α n leaves cache

def BTField_succ_alg_equiv_adjoinRoot (k : ℕ) :
  AdjoinRoot (poly k) ≃ₐ[BTField k] BTField (k + 1) :=

def AlgebraTowerEquiv.toAlgebraOverLeft (e : AlgebraTowerEquiv A B) (i j : ι)
    (h : i ≤ j) : Algebra (A i) (B j) :=

def RAW_CONSTANTS_24 : Vector KoalaBear.Field 215 := #v[
    487143900,
    1829048205,
    1652578477,
    646002781,
    1044144830,
    53279448,
    1519499836,
    22697702,
    1768655004,
    230479744,
    1484895689,
    705130286,
    1429811285,
    1695785093,
    1417332623,
    1115801016,
    1048199020,
    878062617,
    738518649,
    249004596,
    1601837737,
    24601614,
    245692625,
    364803730,
    1857019234,
    1906668230,
    1916890890,
    835590867,
    557228239,
    352829675,
    515301498,
    973918075,
    954515249,
    1142063750,
    1795549558,
    608869266,
    1850421928,
    2028872854,
    1197543771,
    1027240055,
    1976813168,
    963257461,
    652017844,
    2113212249,
    213459679,
    90747280,
    1540619478,
    324138382,
    1377377119,
    294744504,
    512472871,
    668081958,
    907306515,
    518526882,
    1907091534,
    1152942192,
    1572881424,
    720020214,
    729527057,
    1762035789,
    86171731,
    205890068,
    453077400,
    1201344594,
    986483134,
    125174298,
    2050269685,
    1895332113,
    749706654,
    40566555,
    742540942,
    1735551813,
    162985276,
    1943496073,
    1469312688,
    703013107,
    1979485151,
    1278193166,
    548674995,
    2118718736,
    749596440,
    1476142294,
    1293606474,
    918523452,
    890353212,
    1691895663,
    1932240646,
    1180911992,
    86098300,
    1592168978,
    895077289,
    724819849,
    1697986774,
    1608418116,
    1083269213,
    691256798,
    328586442,
    1572520009,
    1375479591,
    322991001,
    967600467,
    1172861548,
    1973891356,
    1503625929,
    1881993531,
    40601941,
    1155570620,
    571547775,
    1361622243,
    1495024047,
    1733254248,
    964808915,
    763558040,
    1887228519,
    994888261,
    718330940,
    213359415,
    603124968,
    1038411577,
    2099454809,
    949846777,
    630926956,
    1168723439,
    222917504,
    1527025973,
    1009157017,
    2029957881,
    805977836,
    1347511739,
    540019059,
    589807745,
    440771316,
    1530063406,
    761076336,
    87974206,
    1412686751,
    1230318064,
    514464425,
    1469011754,
    1770970737,
    1510972858,
    965357206,
    209398053,
    778802532,
    40567006,
    1984217577,
    1545851069,
    879801839,
    1611910970,
    1215591048,
    330802499,
    1051639108,
    321036,
    511927202,
    591603098,
    1775897642,
    115598532,
    278200718,
    233743176,
    525096211,
    1335507608,
    830017835,
    1380629279,
    560028578,
    598425701,
    302162385,
    567434115,
    1859222575,
    958294793,
    1582225556,
    1781487858,
    1570246000,
    1067748446,
    526608119,
    1666453343,
    1786918381,
    348203640,
    1860035017,
    1489902626,
    1904576699,
    860033965,
    1954077639,
    1685771567,
    971513929,
    1877873770,
    137113380,
    520695829,
    806829080,
    1408699405,
    1613277964,
    793223662,
    648443918,
    893435011,
    403879071,
    1363789863,
    1662900517,
    2043370,
    2109755796,
    931751726,
    2091644718,
    606977583,
    185050397,
    946157136,
    1350065230,
    1625860064,
    122045240,
    880989921,
    145137438,
    1059782436,
    1477755661,
    335465138,
    1640704282,
    1757946479,
    1551204074,
    681266718,
]

Add in Init.Prelude

instance : Unique (FullTranscript (default : ProtocolSpec 0)) := inferInstance

@[inline, specialize]
def add {R : Type*} [Ring R] [BEq R] [LawfulBEq R] (p q : QuotientUniPoly R) : QuotientUniPoly R :=
  Quotient.lift₂ add_descending add_descends p q

List.Vector.mmap in Mathlib.Data.Vector.Basic

instance : ∀ i, VCVCompatible ((pSpec Witness).Challenge i) | ⟨0, h⟩ => nomatch h

@[reducible, simp]
def relIn : Set ((StmtIn × ∀ i, OStmtIn OStatement i) × WitIn) :=
  { ⟨⟨(), oracles⟩, ()⟩ | oracles 0 = oracles 1 }

@[inline] def mul [Zero T] [ToNat T] (a b : Cayley T) : Cayley T :=
  mulNat a ↑b

ZMod in Mathlib.Data.ZMod.Defs

Set.toFinset in Mathlib.Data.Fintype.Sets

Fin.addCases in Init.Data.Fin.Lemmas

Fin.consInduction in Mathlib.Data.Fin.Tuple.Basic

abbrev MatrixSubmodule.{u, v, w} (κ : Type u) [Fintype κ] (ι : Type v) [Fintype ι]
                                 (F : Type w) [Semiring F] : Type (max u v w) :=
  Submodule F (Matrix κ ι F)

instance {α : Type u} : Slice (List α) Nat Nat (fun _ _ _ => True) (fun _ _ _ _ => List α) where
  slice xs start stop _ := xs.extract start stop

BitVec.ofFin in Init.Prelude

noncomputable def finalFoldProver :
  OracleProver []ₒ
    (Statement F (Fin.last k)) (OracleStatement D x s (Fin.last k))
      (Witness F s d (Fin.last k).castSucc)
    (FinalStatement F k) (FinalOracleStatement D x s)
      (Witness F s d (Fin.last (k + 1)))
    (pSpec F) where
  PrvState
  | 0 =>
    (Statement F (Fin.last k) × ((j : Fin (k + 1)) → OracleStatement D x s (Fin.last k) j)) ×
      Witness F s d (Fin.last k).castSucc
  | _ =>
    (FinalStatement F k × ((j : Fin (k + 1)) → OracleStatement D x s (Fin.last k) j)) ×
      Witness F s d (Fin.last (k + 1))

  input := id

  sendMessage
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => fun ⟨⟨chals, o⟩, p⟩ =>
    pure ⟨fun x => p.1, ⟨⟨chals, o⟩, p⟩⟩

  receiveChallenge
  | ⟨0, _⟩ => fun ⟨⟨chals, o⟩, p⟩ => pure <|
    fun (α : F) =>
      ⟨
        ⟨Fin.vappend chals !v[α], o⟩,
        ⟨
          p.1.foldNth (2 ^ (s (Fin.last k)).1) α,
          by admit /- proof elided -/
        ⟩
      ⟩
  | ⟨1, h⟩ => nomatch h

  output := fun ⟨⟨chals, o⟩, p⟩ => pure <|
    ⟨
      ⟨
        chals,
        fun j => by admit /- proof elided -/
      ⟩,
      p
    ⟩

AlgHom in Mathlib.Algebra.Algebra.Hom

instance : IsEmpty (ChallengeIdx ⟨!v[.P_to_V], !v[Msg]⟩) :=
  ⟨fun ⟨i, h⟩ => by admit /- proof elided -/
  ⟩

@[simp]
def BTField (k : ℕ) := (BinaryTowerAux k).1

Fin.tail in Mathlib.Data.Fin.Tuple.Basic

@[simp]
abbrev OracleStatement.AfterFirstSumcheck : R1CS.MatrixIdx ⊕ Fin 1 → Type :=
  OracleStatement.AfterFirstChallenge R pp

private noncomputable def evenPart' (f : Polynomial F) : Polynomial F :=
  match f with
  | ⟨⟨supp, f, pr⟩⟩ => ⟨⟨erase_odd supp, fun n => if Even n then f n else 0, by admit /- proof elided -/
  ⟩⟩

HMul.hMul in Init.Prelude

@[reducible, simp]
def toRelOut : Set ((Statement × Witness) × Unit) :=
  Prod.fst ⁻¹' relIn

@[inline, reducible]
def proj : OuterStmtIn × (∀ i, OuterOStmtIn i) → InnerStmtIn × (∀ i, InnerOStmtIn i) :=
  lens.toFunA

def LeafData.rightSubtree {α : Type} {s_left s_right : Skeleton}
    (tree : LeafData α (Skeleton.internal s_left s_right)) :
    LeafData α s_right :=
  match tree with
  | LeafData.internal _left right =>
    right

@[reducible, simp]
def rbrSoundness
    (langIn : Set (Statement × ∀ i, OStatement i))
    (verifier : OracleVerifier oSpec Statement OStatement Bool (fun _ : Empty => Unit) pSpec)
    (rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  verifier.rbrSoundness init impl langIn acceptRejectOracleRel.language rbrSoundnessError

def canonicalEmbedding (k : ℕ) : BTField k →+* BTField (k+1) :=
  AdjoinRoot.of (poly k)

instance [Zero T] [ToNat T] : DecidableEq (Cayley T) := fun a b =>
  if h : (↑a : Nat) = (↑b : Nat) then
    isTrue (by admit /- proof elided -/
      )
  else
    isFalse (fun heq => h (by admit /- proof elided -/
    ))

def commitKnowledgeError {i : Fin ℓ}
    (m : (pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i).ChallengeIdx) : ℝ≥0 :=
  match m with
  | ⟨j, hj⟩ => by admit /- proof elided -/

Subtype.eq_iff in Init.Ext

instance : ∀ i, VCVCompatible (Challenge ⟨!v[.P_to_V], !v[Msg]⟩ i)
  | ⟨0, h⟩ => nomatch h

@[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⟩

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»}

USize.ofNat in Init.Data.UInt.BasicAux

def ar2 (k0 k1 : ℕ) : Fin 2 → ℕ
  | ⟨0, _⟩ => k0
  | ⟨1, _⟩ => k1

def oracleReduction : OracleReduction oSpec (StmtIn R) (OStmtIn R deg) Unit
                                            (StmtOut R) (OStmtOut R deg) Unit (pSpec R deg) where
  prover := prover R deg oSpec
  verifier := oracleVerifier R deg D oSpec

def divide_by_2 (s : Finset ℕ) : Finset ℕ :=
  (erase_odd s).image (fun n => n / 2)

Rat in Init.Data.Rat.Basic

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

def fromNat {k : ℕ} (n : Nat) : ConcreteBTField k :=
  BitVec.ofNat (2 ^ k) n

instance {α : Type u} : SliceLT (List α) Nat (fun _ _ => True) (fun _ _ _ => List α) where
  sliceLT xs stop _ := List.take stop xs

def rho' (n : ℕ) (start : ℕ) (c : ℕ) : Option ℕ := Id.run do
  if n % 2 = 0 then
    return some 2

  let mut x := start
  let mut y := x
  let mut d := 1

  while d = 1 do
    x := g n c x
    y := g n c (g n c y)
    d := Nat.gcd (Int.natAbs (x - y)) n

  if d = n then
    return none
  else
    return some d

Fin.succAboveEmb in Mathlib.Data.Fin.Embedding

def sub (a b : AssocNat) : AssocNat :=
  subNat a b.toNat

def neg_descending (p : UniPoly R) : QuotientUniPoly R :=
  Quotient.mk _ (neg p)

instance instNatPow {n : ℕ} : NatPow (CNat n) := match n with
  | 0 => by admit /- proof elided -/
  | .succ n => by admit /- proof elided -/

def sumcheckConsistencyProp {k : ℕ} (sumcheckTarget : L) (H : L⦃≤ 2⦄[X Fin (k)]) : Prop :=
  sumcheckTarget = ∑ x ∈ (univ.map 𝓑) ^ᶠ (k), H.val.eval x

MvPolynomial.degreeOf in Mathlib.Algebra.MvPolynomial.Degrees

def ratchet (ds : DomainSeparator U H) : DomainSeparator U H :=
  { io := ds.io ++ SEP_BYTE ++ "R" }

Nat.reduceBEq in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat

def ri (dstar : ℕ) (degs : Fin m → ℕ) (r : F) (i : Fin m) : F :=
          match i.1 with
          | 0 => 1
          | .succ i' =>
            let exp := i' + ∑ j < i, (dstar - degs j)
            r ^ exp

Finset.add in Mathlib.Algebra.Group.Pointwise.Finset.Basic

ZMod.charP in Mathlib.Data.ZMod.Basic

Polynomial.ofFinsupp in Mathlib.Algebra.Polynomial.Basic

@[reducible]
def MemoryRead (ι : Type u) (α : ι → Type v) := (index : ι) × (α index)

@[reducible]
def GroupDecodeOracle : OracleSpec Unit := fun _ => (BitVec bitLength × ι, Unit)

Finset.univ in Mathlib.Data.Fintype.Defs

Algebra.TensorProduct.comm in Mathlib.RingTheory.TensorProduct.Maps

noncomputable def polyQ (P q : Polynomial F) : MvPolynomial (Fin 2) F :=
  
  let Pbi : MvPolynomial (Fin 2) F := uni2bi P
  
  let P' : MvPolynomial (Fin 2) F := (MvPolynomial.X 1) - uni2bi q
  
  have h_unit : IsUnit ((MonomialOrder.lex).leadingCoeff P') := sorry
  modBivar Pbi P' h_unit

private noncomputable def E (ωs : Fin n → F)
  (f : Fin n → F) (p : Polynomial F) (e : ℕ) : Polynomial F :=
  X ^ (e - (Δ₀(f, p.eval ∘ ωs) : ℕ)) * ElocPolyF ωs f p

def outputRelation :
    Set
      (
        (Fri.Spec.Statement F (0 : Fin (k + 1)) ×
        (∀ j, Fri.Spec.OracleStatement D x s (0 : Fin (k + 1)) j)) ×
        Fri.Spec.Witness F s d (0 : Fin (k + 2))
      ) := sorry

def inputRelation : Set ((StmtIn R × (∀ i, OStmtIn R deg i)) × Unit) :=
  { ⟨⟨target, oStmt⟩, _⟩ | ∑ x ∈ (univ.map D), (oStmt ()).1.eval x = target }

instance [IsSingleRound pSpec] : Unique (pSpec.ChallengeIdx) where
  default := ⟨1, by admit /- proof elided -/
  ⟩
  uniq := fun ⟨i, hi⟩ => by admit /- proof elided -/

instance : HListRepr (HList []) where
  repr := fun _ => ""

noncomputable def ofPolynomialAlgHom : R[X] →ₐ[R] P := Polynomial.aeval PolynomialLike.X

inductive VectorOp where | dotProd

Exists in Init.Core

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

@[inline]
def neg [Neg R] (p : MlPolyEval R n) : MlPolyEval R n := p.map (fun a => -a)

def generateProof {s} (cache_tree : FullData α s) :
    BinaryTree.SkeletonLeafIndex s → List α
  | .ofLeaf => []
  | .ofLeft idxLeft =>
    (cache_tree.rightSubtree).getRootValue ::
      (generateProof cache_tree.leftSubtree idxLeft)
  | .ofRight idxRight =>
    (cache_tree.leftSubtree).getRootValue ::
      (generateProof cache_tree.rightSubtree idxRight)

def finalSumcheckRelOutProp
    (input : ((FinalSumcheckStatementOut (L := L) (ℓ := ℓ) ×
      (∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ) j)) ×
      (Unit))) : Prop :=
  
  finalNonDoomedFoldingProp 𝔽q β
    (h_le := by admit /- proof elided -/
    )
    (input := input.1)

def squeezeUnchecked [Permute C] (sponge : DuplexSponge U C) (arr : Array U) :
    DuplexSponge U C × Array U :=
  simulateQ' (m := Id) forwardPermutationOracleImpl (squeezeInto sponge arr) (by admit /- proof elided -/
  )

List.Vector in Mathlib.Data.Vector.Defs

def Fin.sumCommEquiv (m : ℕ) (n : ℕ) : Fin (m + n) ≃ (Fin n) ⊕ (Fin m) :=
  (@finSumFinEquiv m n).symm.trans (Equiv.sumComm (Fin m) (Fin n))

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

@[reducible]
def C : R →+* P := algebraMap R P

abbrev Fwd : PermuteDir := Sum.inl ()

def proximityChecksSpec (γ_challenges :
    Fin γ_repetitions → sDomain 𝔽q β h_ℓ_add_R_rate ⟨0, by omega⟩)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ) j)
    (fold_challenges : Fin ℓ → L) (final_constant : L) : Prop :=
  ∀ rep : Fin γ_repetitions,
    let v := γ_challenges rep
    -- For all folding levels k = 0, ..., ℓ/ϑ - 1, we track c_cur through the iterations
    ∀ k_val : Fin (ℓ / ϑ),
      let i := k_val.val * ϑ
      have h_k: k_val ≤ (ℓ/ϑ - 1) := by omega
      have h_i_add_ϑ_le_ℓ : i + ϑ ≤ ℓ := by
        calc i + ϑ = k_val * ϑ + ϑ := by omega
          _ ≤ (ℓ/ϑ - 1) * ϑ + ϑ := by
            apply Nat.add_le_add_right; apply Nat.mul_le_mul_right; omega
          _ = ℓ/ϑ * ϑ :=

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 redundantEntryDS (log : QueryLog (duplexSpongeChallengeOracle StmtIn U))
    (idx : Fin log.length) : Prop :=
  match log[idx] with
   
  | ⟨.inl _, ⟨stmt, state⟩⟩ => ∃ j' < idx, log[j'] = ⟨.inl _, ⟨stmt, state⟩⟩
   
  | ⟨.inr .Fwd, stateIn, stateOut⟩ =>
    ∃ j' < idx, log[j'] = ⟨.inr .Fwd, stateIn, stateOut⟩ ∨ log[j'] = ⟨.inr .Bwd, stateOut, stateIn⟩
  | ⟨.inr .Bwd, stateOut, stateIn⟩ =>
    ∃ j' < idx, log[j'] = ⟨.inr .Bwd, stateOut, stateIn⟩ ∨ log[j'] = ⟨.inr .Fwd, stateIn, stateOut⟩

@[to_additive existing]
def partialProd {α : Type*} [Monoid α] (l : List α) : List α :=
  [1] ++ match l with
  | [] => []
  | a :: l' => (partialProd l').map (a * ·)

Finset.Nonempty in Mathlib.Data.Finset.Empty

instance coe_field_adjoinRoot (k : ℕ) : Coe (AdjoinRoot (poly k)) (BTField (k+1)) where
  coe := Eq.mp (BTField_succ_eq_adjoinRoot k)

def verifyProof {n : ℕ} (i : Fin (2 ^ n)) (leaf : α) (root : α) (proof : List.Vector α n) :
    OracleComp (spec α) Unit := do
  let putative_root ← getPutativeRoot α i leaf proof
  guard (putative_root = root)

class ProverFirst (pSpec : ProtocolSpec n) [NeZero n] where
  prover_first' : pSpec.dir 0 = .P_to_V

AddMonoid in Mathlib.Algebra.Group.Defs

Polynomial.div in Mathlib.Algebra.Polynomial.FieldDivision

noncomputable def decoder (e k : ℕ) [NeZero n] (ωs f : Fin n → F) : Option (Polynomial F) :=
  if ‖f‖₀ ≤ e
  then some 0
  else
    let x := linsolve (BerlekampWelchMatrix e k ωs f) (Rhs e ωs f)
    match x with
    | none => none
    | some x =>
      let E := solutionToE e k x
      let Q := solutionToQ e k x
      if Q % E = 0 then
        let p := Q / E
        if Δ₀(f, p.eval ∘ ωs) ≤ e then
          some p
        else
          none
      else
        none

instance [VerifierFirst pSpec] : Unique (pSpec.ChallengeIdx) where
  default := ⟨0, by admit /- proof elided -/
  ⟩
  uniq := fun ⟨i, _⟩ => by admit /- proof elided -/

instance [ToString α] (αs : List Type) [HListString (HList αs)] :
    HListString (HList (α :: αs)) where
  toString
  | HList.cons x xs =>
    match xs with
    | HList.nil => toString x
    | HList.cons _ _ => toString x ++ ", " ++ HListString.toString xs

noncomputable def towerRingEquivFromConcrete0 : ConcreteBTField 0 ≃+* BTField 0 :=

@[elab_as_elim]
def dappend {m n : ℕ} {motive : Fin (m + n) → Sort u}
    (u : (i : Fin m) → motive (Fin.castAdd n i))
    (v : (i : Fin n) → motive (Fin.natAdd m i))
    (i : Fin (m + n)) : motive i :=
  match n with
  | 0 => u i
  | k + 1 => dconcat (dappend u (fun i => v (Fin.castSucc i))) (v (Fin.last k)) i

def pad (sz₁ sz₂ : Size)
    (stmt : Statement R sz₁)
    (matrices : MatrixIdx → Matrix (Fin sz₁.m) (Fin sz₁.n) R)
    (wit : Witness R sz₁) :
    Statement R sz₂ × (MatrixIdx → Matrix (Fin sz₂.m) (Fin sz₂.n) R) × Witness R sz₂ :=
  (Fin.rightpad sz₂.n_x 0 stmt,
    fun idx => Matrix.rightpad sz₂.m sz₂.n 0 (matrices idx),
    Fin.rightpad sz₂.n_w 0 wit)

noncomputable def toMLE (A : Matrix (Fin (2 ^ m)) (Fin (2 ^ n)) R) : R[X Fin n][X Fin m] :=
  MLE' (MLE' ∘ A)

instance {α : Type} [Sampleable α] : DecidableEq α := inferInstance

def nonLastBlockOracleReduction (bIdx : Fin (ℓ / ϑ - 1)) :=
  let stmt : Fin (ϑ - 1 + 1) → Type :=
    fun i => Statement (L := L) (ℓ := ℓ) Context ⟨bIdx * ϑ + i, bIdx_mul_ϑ_add_i_cast_lt_ℓ_succ bIdx i⟩
  let oStmt := fun i: Fin (ϑ - 1 + 1) =>
    OracleStatement 𝔽q β ϑ ⟨bIdx * ϑ + i, bIdx_mul_ϑ_add_i_cast_lt_ℓ_succ bIdx i⟩
  let wit := fun i: Fin (ϑ - 1 + 1) =>
    Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ)
      ⟨bIdx * ϑ + i, bIdx_mul_ϑ_add_i_cast_lt_ℓ_succ bIdx i⟩
  let firstFoldRelayRoundsOracleReduction :=
    OracleReduction.seqCompose (oSpec := []ₒ)
      (Stmt := stmt)
      (OStmt := oStmt)
      (Wit := wit)
      (pSpec := fun i => pSpecFoldRelay (L:=L))
      (R := fun i => by admit /- proof elided -/
      )

  let h1 : ↑bIdx * ϑ + (ϑ - 1) < ℓ := by admit /- proof elided -/

def InternalData.leftSubtree {α : Type} {s_left s_right : Skeleton}
    (tree : InternalData α (Skeleton.internal s_left s_right)) :
    InternalData α s_left :=
  match tree with
  | InternalData.internal _ left _right =>
    left

List.drop in Init.Data.List.Basic

def D_YZ (Q : F[Z][X][Y]) : ℕ :=
  Option.getD (dflt := 0) <| Finset.max
    (Finset.image
            (
              fun j =>
                Option.getD (
                  Finset.max (
                    Finset.image
                      (fun k => j + (Bivariate.coeff Q j k).natDegree)
                      (Q.coeff j).support
                  )
                ) 0
            )
            Q.support
    )

def FullData.toLeafData {α : Type} {s : Skeleton}
    (tree : FullData α s) : LeafData α s :=
  match tree with
  | FullData.leaf value => LeafData.leaf value
  | FullData.internal _ left right =>
    LeafData.internal (left.toLeafData) (right.toLeafData)

Group in Mathlib.Algebra.Group.Defs

NeZero in Init.Data.NeZero

def AlgebraTowerEquiv.symm (e : AlgebraTowerEquiv A B) : AlgebraTowerEquiv B A where
  toRingEquiv := fun i => (e.toRingEquiv i).symm
  commutesLeft' := fun i j h r => by admit /- proof elided -/

@[reducible]
def fieldSize : Nat := 2 ^ 31 - 1

@[reducible]
def foldRelayOracleVerifier (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleVerifier []ₒ
    (StmtIn := Statement (L := L) Context i.castSucc)
    (OStmtIn := OracleStatement 𝔽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.succ)
    (pSpec := pSpecFoldRelay (L:=L)) :=
  OracleVerifier.append
        (pSpec₁ := pSpecFold (L:=L))
    (pSpec₂ := pSpecRelay)
    (foldOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
    (relayOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR)

def take (j : Fin (k + 1)) (messages : MessagesUpTo k pSpec) :
    MessagesUpTo (j.castLE (by admit /- proof elided -/
    )) pSpec :=
  fun i => messages ⟨i.val.castLE (by admit /- proof elided -/
  ), i.property⟩

instance : Field ScalarField := ZMod.instField scalarFieldSize

@[inline, specialize]
def oracleProver : OracleProver oSpec
    Statement OStatement Unit Statement OStatement Unit !p[] where
  PrvState := fun _ => Statement × (∀ i, OStatement i)
  input := Prod.fst
  sendMessage := fun i => nomatch i
  receiveChallenge := fun i => nomatch i
  output := fun stmt => pure (stmt, ())

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 }

@[simp]
instance CommRing (k : ℕ) : CommRing (BTField k) := Field.toCommRing

Polynomial.rootMultiplicity in Mathlib.Algebra.Polynomial.Div

Sum.inr in Init.Core

def BBF_eq_multiplier (r : Fin ℓ → L) : MultilinearPoly L ℓ :=
  ⟨MvPolynomial.eqPolynomial r, by admit /- proof elided -/
  ⟩

def BindingAdversary (oSpec : OracleSpec ι) (Data Commitment AuxState : Type)
    [O : OracleInterface Data] :=
  OracleComp oSpec (Commitment × O.Query × O.Response × O.Response × AuxState)

def erase_odd (s : Finset ℕ) : Finset ℕ := s.filter Even

List.dropLast in Init.Data.List.Basic

instance (αs : List Type) [HListRepr (HList αs)] : Repr (HList αs) where
  reprPrec
  | v, _ => "[" ++ HListRepr.repr v ++ "]"

@[reducible, simp]
def completeness (relation : Set (Statement × Witness)) (completenessError : ℝ≥0)
    (proof : Proof oSpec Statement Witness pSpec) : Prop :=
  Reduction.completeness init impl relation acceptRejectRel proof completenessError

@[simps]
def subtypeSumComplEquiv {α : Type*} {p : α → Prop} [DecidablePred p] :
    {a // p a} ⊕ {a // ¬ p a} ≃ α where
  toFun := fun x => match x with
    | Sum.inl a => a.1
    | Sum.inr a => a.1
  invFun := fun x =>
    if h : p x then Sum.inl ⟨x, h⟩ else Sum.inr ⟨x, h⟩
  left_inv := fun x => match x with
    | Sum.inl a => by admit /- proof elided -/
    | Sum.inr a => by admit /- proof elided -/

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

structure Scheme extends
    Commit oSpec Data Randomness Commitment,
    Opening oSpec Data Randomness Commitment pSpec

class LawfulPermute (α : Type*) [Permute α] where
  permuteInv : α → α
  left_inv : Function.LeftInverse permuteInv Permute.permute
  right_inv : Function.RightInverse permuteInv Permute.permute

def simulateQ' (oa : OracleComp spec α) (h : oa.neverFails) : m α :=

protected def cast (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₁) :
    Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₂ where
  PrvState := P.PrvState ∘ Fin.cast (congrArg (· + 1) hn.symm)
  input := P.input
  sendMessage := fun i st => do
    let ⟨msg, newSt⟩ ← P.sendMessage (i.cast hn.symm (cast_symm hSpec)) st
    return ⟨(Message.cast_idx_symm hSpec) ▸ msg, newSt⟩
  receiveChallenge := fun i st => do
    let f ← P.receiveChallenge (i.cast hn.symm (cast_symm hSpec)) st
    return fun chal => f (Challenge.cast_idx hSpec ▸ chal)
  output := P.output ∘ (fun st => _root_.cast (by admit /- proof elided -/
  ) st)

def shift_left (s : Finset ℕ) : Finset ℕ :=
  s.filterMap
    (fun n => match n with
      | 0 => .none
      | n + 1 => .some n
      )
    (by admit /- proof elided -/
    )

@[inline] def min [Zero T] [ToNat T] (a b : Cayley T) : Cayley T :=
  if (a : Nat) ≤ (b : Nat) then a else b

instance : Neg (UniPoly R) := ⟨UniPoly.neg⟩

instance : Mul (UniPoly R) := ⟨UniPoly.mul⟩

def findImports (path : System.FilePath) : IO (Array Lean.Name) := do
  return (← Lean.parseImports' (← IO.FS.readFile path) path.toString)
    |>.map (fun imp ↦ imp.module) |>.erase `Init

def StateFunction.append
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁)
    (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    (S₁ : V₁.StateFunction init impl lang₁ lang₂)
    (S₂ : V₂.StateFunction init impl lang₂ lang₃)
    
    (verify : Stmt₁ → pSpec₁.FullTranscript → Stmt₂)
    (hVerify : V₁ = ⟨fun stmt tr => pure (verify stmt tr)⟩) :
      (V₁.append V₂).StateFunction init impl lang₁ lang₃ where
  toFun := fun roundIdx stmt₁ transcript =>
    if h : roundIdx.val ≤ m then
    
      S₁ ⟨roundIdx, by admit /- proof elided -/
      ⟩ stmt₁ (by admit /- proof elided -/
      )
    else
    
    
    
      S₁ ⟨m, by admit /- proof elided -/
      ⟩ stmt₁ (by admit /- proof elided -/
      ) ∧
      S₂ ⟨roundIdx - m, by admit /- proof elided -/
      ⟩ (verify stmt₁
        (by admit /- proof elided -/
        ))
        (by admit /- proof elided -/
        )
  toFun_empty := sorry
  toFun_next := sorry
  toFun_full := sorry

instance : ∀ j, OracleInterface ((pSpecRelay).Message j)
  | ⟨x, h⟩ => by admit /- proof elided -/

def take (j : Fin (k + 1)) (challenges : ChallengesUpTo k pSpec) :
    ChallengesUpTo (j.castLE (by admit /- proof elided -/
    )) pSpec :=
  fun i => challenges ⟨i.val.castLE (by admit /- proof elided -/
  ), i.property⟩

def α' (x₀ : F) (R : F[X][X][Y]) (H_irreducible : Irreducible H) (t : ℕ) : 𝕃 H :=
  α x₀ R _ (φ := ⟨H_irreducible⟩) t

def findIdxRev? (cond : α → Bool) (as : Array α) : Option (Fin as.size) :=
  find ⟨ as.size, Nat.lt_succ_self _ ⟩
where
  find : Fin (as.size + 1) → Option (Fin as.size)
    | 0 => none
    | ⟨ i+1, h ⟩ =>
      if (cond as[i]) then
        some ⟨ i, Nat.lt_of_succ_lt_succ h ⟩
      else
        find ⟨ i, Nat.lt_of_succ_lt h ⟩

def inputRelation : Set (((StmtIn R) × (∀ i, OStmtIn R deg i)) × Unit) :=
  { ⟨⟨target, oStmt⟩, _⟩ | ∑ x ∈ (univ.map D), (oStmt ()).1.eval x = target }

Nat.reduceMod in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat

AdjoinRoot.powerBasis in Mathlib.RingTheory.AdjoinRoot

@[inline, reducible]
def toContext :
    Context.Lens (OuterStmtIn × (∀ i, OuterOStmtIn i)) (OuterStmtOut × (∀ i, OuterOStmtOut i))
                (InnerStmtIn × (∀ i, InnerOStmtIn i)) (InnerStmtOut × (∀ i, InnerOStmtOut i))
                OuterWitIn OuterWitOut InnerWitIn InnerWitOut :=
  ⟨lens.stmt, lens.wit⟩

noncomputable def linearEquivMvPolynomialDeg1 : MlPoly R n ≃ₗ[R] R⦃≤ 1⦄[X Fin n] :=
  { toEquiv := equivMvPolynomialDeg1
    map_add' := by admit /- proof elided -/

def liftRightNil {ι : Type} {σ : Type} (oSpec : OracleSpec ι) :
    SimOracle.Stateful (oSpec ++ₒ []ₒ) oSpec σ where impl
  | query (.inl i) q => fun s ↦ do return ⟨← query i q, s⟩

Fintype.ofEquiv in Mathlib.Data.Fintype.OfMap

def OuterStmtOut_Test := ℤ[X] × ℤ[X] × ℤ × ℤ

@[simp]
abbrev LinearCombinationChallenge : Type := R1CS.MatrixIdx → R

noncomputable def E_and_Q_to_a_solution (e : ℕ) (E Q : Polynomial F) (i : Fin n) : F :=
  if i < e then E.toFinsupp i else Q.toFinsupp (i - e)

inferInstanceAs in Init.Prelude

def oracleReduction (i : Fin n) : OracleReduction oSpec
    (StatementRound R n i.castSucc) (OracleStatement R n deg) Unit
    (StatementRound R n i.succ) (OracleStatement R n deg) Unit (pSpec R deg) :=
  (Simple.oracleReduction R deg D oSpec).liftContext (oCtxLens R n deg D i)

@[inline, specialize, simp]
def oracleReduction : OracleReduction oSpec
    Statement OStatement Witness Statement OStatement Witness !p[] := OracleReduction.id

IO.eprintln in Init.System.IO

@[reducible]
def value (op : MemoryWrite ι α) := op.2

@[simp]
def poly (k : ℕ) : Polynomial (BTField k) := definingPoly (s:=(Z k))

MonomialOrder in Mathlib.Data.Finsupp.MonomialOrder

def badEventExistsProp
    (stmtIdx : Fin (ℓ + 1)) (oracleIdx : Fin (ℓ + 1))
    (oStmt : ∀ j, (OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (i := oracleIdx) j))
    (challenges : Fin stmtIdx → L) : Prop :=
  ∃ j, foldingBadEventAtBlock 𝔽q β (stmtIdx := stmtIdx) (oracleIdx := oracleIdx)
    (oStmt := oStmt) (challenges := challenges) j

def β (R : F[X][X][Y]) (t : ℕ) : 𝒪 H :=
  (β_regular R H (Nat.le_refl _) t).choose

@[reducible]
def coeffs {R : Type*} (p : UniPoly R) : Array R := p

structure LookaheadSequence (trace : QueryLog (forwardPermutationOracle (CanonicalSpongeState U)))
    (state : CanonicalSpongeState U) where
   
  inputState : List (CanonicalSpongeState U)
   
  outputState : List (CanonicalSpongeState U)

   
  inputState_length_eq_outputState_length : inputState.length = outputState.length

   
  first_inputState_eq_state : inputState[0]? = state

   
  inputOutput_in_trace : ∀ i : Fin inputState.length,
    (inputState[i], outputState[i]) ∈ trace.getQ ()

   
  outputState_eq_next_inputState : ∀ i : Fin (outputState.length - 1),
    outputState[i] = inputState[i.val + 1]

   
  capacitySegment_inputState_ne_outputState : ∀ i : Fin inputState.length,
    inputState[i].capacitySegment ≠ outputState[i].capacitySegment

Fin.castLT in Init.Data.Fin.Basic

@[reducible]
def Statement (F : Type) (i : Fin (k + 1)) : Type := Fin i.val → F

class DuplexSpongeInterface (U : Type) [SpongeUnit U] (α : Type*)
    extends Inhabited α, Zero α, Initialize α (Vector UInt8 32) where
   
  absorbUnchecked : α × Array U → α

   
  squeezeUnchecked : α × Array U → α × Array U

   
  ratchetUnchecked : α → α

class Extractor.Lens.IsKnowledgeSound
    {OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut : Type}
    {OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type}
    (outerRelIn : Set (OuterStmtIn × OuterWitIn))
    (innerRelIn : Set (InnerStmtIn × InnerWitIn))
    (outerRelOut : Set (OuterStmtOut × OuterWitOut))
    (innerRelOut : Set (InnerStmtOut × InnerWitOut))
    (compatStmt : OuterStmtIn → InnerStmtOut → Prop)
    (compatWit : OuterWitOut → InnerWitIn → Prop)
    (lens : Extractor.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                            OuterWitIn OuterWitOut InnerWitIn InnerWitOut) where

   
  proj_knowledgeSound : ∀ outerStmtIn innerStmtOut outerWitOut,
    compatStmt outerStmtIn innerStmtOut →
    (lens.stmt.lift outerStmtIn innerStmtOut, outerWitOut) ∈ outerRelOut →
    (innerStmtOut, lens.wit.proj (outerStmtIn, outerWitOut)) ∈ innerRelOut

   
  lift_knowledgeSound : ∀ outerStmtIn outerWitOut innerWitIn,
    compatWit outerWitOut innerWitIn →
    (lens.stmt.proj outerStmtIn, innerWitIn) ∈ innerRelIn →
    (outerStmtIn, lens.wit.lift (outerStmtIn, outerWitOut) innerWitIn) ∈ outerRelIn

def rbrSoundness (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  ∃ stateFunction : verifier.StateFunction init impl langIn langOut,
  ∀ stmtIn ∉ langIn,
  ∀ WitIn WitOut : Type,
  ∀ witIn : WitIn,
  ∀ prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec,
  ∀ i : pSpec.ChallengeIdx,
    [fun ⟨transcript, challenge⟩ =>
      ¬ stateFunction i.1.castSucc stmtIn transcript ∧
        stateFunction i.1.succ stmtIn (transcript.concat challenge)
    | do
      (simulateQ (impl ++ₛₒ challengeQueryImpl : QueryImpl _ (StateT σ ProbComp))
        (do
          let ⟨transcript, _⟩ ← prover.runToRound i.1.castSucc stmtIn witIn
          let challenge ← liftComp (pSpec.getChallenge i) _
          return (transcript, challenge))).run' (← init)] ≤
      rbrSoundnessError i

class LawfulHasPred (T : Type u) [HasSucc T] [HasPred T] : Prop where
   
  pred'_succ : ∀ x : T, pred' (succ' x) = x

def concrete_inv {k : ℕ} (a : ConcreteBTField k) : ConcreteBTField k :=
  if h_k_zero : k = 0 then
    if a = 0 then 0 else 1
  else
    if h_a_zero : a = 0 then 0
    else if h_a_one : a = 1 then 1
    else
      let h_k_gt_0 : k > 0 := Nat.zero_lt_of_ne_zero h_k_zero
      let (a_hi, a_lo) := split (k:=k) (h:=h_k_gt_0) a
      let prevZ := Z (k - 1)
      let a_lo_next := a_lo + concrete_mul a_hi prevZ
      let delta := concrete_mul a_lo a_lo_next + concrete_mul a_hi a_hi
      let delta_inverse := concrete_inv delta
      let out_hi := concrete_mul delta_inverse a_hi
      let out_lo := concrete_mul delta_inverse a_lo_next
      let res := 《 out_hi, out_lo 》
      res

def RoundByRound.append
    {WitMid₁ : Fin (m + 1) → Type} {WitMid₂ : Fin (n + 1) → Type}
    (E₁ : Extractor.RoundByRound oSpec Stmt₁ Wit₁ Wit₂ pSpec₁ WitMid₁)
    (E₂ : Extractor.RoundByRound oSpec Stmt₂ Wit₂ Wit₃ pSpec₂ WitMid₂) :
      Extractor.RoundByRound oSpec Stmt₁ Wit₁ Wit₃ (pSpec₁ ++ₚ pSpec₂)
        (Fin.append (m := m + 1) WitMid₁ (Fin.tail WitMid₂) ∘ Fin.cast (by admit /- proof elided -/
        )) where
  eqIn := by admit /- proof elided -/

instance Vector.instFintype {α : Type*} {n : ℕ} [VCVCompatible α] : Fintype (Vector α n) :=
  Fintype.ofEquiv _ (Equiv.rootVectorEquivFin).symm

def inputRelation (cond : ∑ i, (s i).1 ≤ n) [DecidableEq F] (δ : ℝ≥0) :
    Set
      (
        (
          Statement F (Fin.last k) ×
          (∀ j, OracleStatement D x s (Fin.last k) j)
        ) ×
        Witness F s d (Fin.last k).castSucc
      ) := sorry

instance : Dist (n → R) where
  dist := fun u v => hammingDist u v

Lean.parseImports' in Lean.Elab.ParseImportsFast

instance irreducible_quadratic_defining_poly_of_traceMap_eq_1
  {F : Type*} [Field F] [Fintype F] [CharP F 2] (s : F) [NeZero s] (k : ℕ)
  (trace_map_prop : TraceMapProperty F s k)
  (fintypeCard : Fintype.card F = 2 ^ (2 ^ k))
  : Irreducible (definingPoly s) :=

abbrev BaseField := ZMod baseFieldSize

List.rightpad in Init.Data.List.Basic

def pred (n : ChurchNat α) : ChurchNat α := sorry

noncomputable def vanishingPoly (S : Finset F) : Polynomial F :=
  ∏ s ∈ S, (Polynomial.X - Polynomial.C s)

@[simp]
def evalDomain (i : ℕ) : Subgroup Fˣ :=
  Subgroup.zpowers (DIsCyclicC.gen ^ (2 ^ i))

def BBF_SumcheckMultiplierParam : SumcheckMultiplierParam L ℓ (SumcheckBaseContext L ℓ) :=
  { multpoly := fun ctx => BBF_eq_multiplier ctx.t_eval_point }

noncomputable def commitRbrExtractor (i : Fin ℓ) :
  Extractor.RoundByRound []ₒ
    (StmtIn := (Statement (L := L) Context i.succ) × (∀ j, OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc j))
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (pSpec := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
    (WitMid := fun _messageIdx => Witness (L := L) 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ) where
  eqIn := rfl
  extractMid := fun _ _ _ witMidSucc => witMidSucc
  extractOut := fun _ _ witOut => witOut

Fin.pred in Init.Data.Fin.Basic

instance : ∀ i, SelectableType ((pSpecNonLastBlocks 𝔽q β (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Challenge i) := instSelectableTypeChallengeSeqCompose

@[inline, specialize]
def add_raw (p q : UniPoly R) : UniPoly R :=
  let ⟨p', q'⟩ := Array.matchSize p q 0
  .mk (Array.zipWith (· + ·) p' q' )

instance : NonBinaryField Field where
  char_neq_2 := by admit /- proof elided -/

def proximityMeasure (u v : n → F) (d : ℕ) : ℕ :=
  Fintype.card {r : F | Δ₀'(r • u + (1 - r) • v, C) ≤ d}

@[reducible, simp] def OStmtAfterRandomQuery : Unit ⊕ Unit → Type := fun _ => R⦃≤ deg⦄[X]

def g (n : ℕ) (c : ℕ) (x : ℕ) := (x * x + c) % n

instance {s} : LawfulFunctor (fun α => InternalData α s) :=

abbrev CNat (n : ℕ) : Type := (CayleyTower n).1

Module.Basis.smulTower in Mathlib.RingTheory.AlgebraTower

Eq in Init.Prelude

Membership in Init.Prelude

def OracleReduction.liftContext
    (lens : OracleContext.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                              OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut
                              OuterWitIn OuterWitOut InnerWitIn InnerWitOut)
    (R : OracleReduction oSpec InnerStmtIn InnerOStmtIn InnerWitIn
                            InnerStmtOut InnerOStmtOut InnerWitOut pSpec) :
      OracleReduction oSpec OuterStmtIn OuterOStmtIn OuterWitIn
                      OuterStmtOut OuterOStmtOut OuterWitOut pSpec where
  prover := R.prover.liftContext lens
  verifier := R.verifier.liftContext lens.stmt

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

def SkeletonLeafIndex.isRoot {s : Skeleton} (idx : SkeletonLeafIndex s) : Bool :=
  match idx with
  | SkeletonLeafIndex.ofLeaf => true
  | SkeletonLeafIndex.ofLeft _ => false
  | SkeletonLeafIndex.ofRight _ => false

instance : ∀ j, OracleInterface ((pSpecFinalSumcheckStep (L := L)).Message j) := fun j =>
  match j with
  | ⟨0, _⟩ => OracleInterface.instDefault

def redundantQuery (log : QueryLog spec) (i : ι) (q : spec.domain i) (r : spec.range i) : Prop :=
  (log.getQ i).count (q, r) > 1

instance [IsSingleRound pSpec] : Unique (pSpec.MessageIdx) where
  default := ⟨0, by admit /- proof elided -/
  ⟩
  uniq := fun ⟨i, hi⟩ => by admit /- proof elided -/

def relHammingBallInterleavedCode [DecidableEq F] (U : Matrix κ ι F)
  (IC : MatrixSubmodule κ ι F) (r : ℝ) :=
    {V | V ∈ IC ∧ relDistCodewords U V < r}

def InnerStmtIn_Test := ℤ[X] × ℤ

DivisionSemiring in Mathlib.Algebra.Field.Defs

def mul_by_2 (s : Finset ℕ) : Finset ℕ :=
  s.map ⟨fun n => 2 * n, by admit /- proof elided -/
  ⟩

Vector.foldl in Init.Data.Vector.Basic

@[reducible, inline]
instance instProdForall {ι : Type u} (v : ι → Type v) [O : ∀ i, OracleInterface (v i)] :
    OracleInterface (∀ i, v i) where
  Query := (i : ι) × (O i).Query
  Response := (i : ι) × (O i).Response
  answer := fun f ⟨i, q⟩ => ⟨i, (O i).answer (f i) q⟩

noncomputable def monomialToNovelCoeffs

  (ℓ : ℕ) (h_ℓ : ℓ ≤ r) (monomial_coeffs : Fin (2 ^ ℓ) → L) : Fin (2^ℓ) → L :=
  let A := changeOfBasisMatrix 𝔽q β ℓ h_ℓ
  
  
  Matrix.vecMul monomial_coeffs A⁻¹

def computableAdditiveNTT (a : Fin (2 ^ ℓ) → L) : Fin (2^(ℓ + R_rate)) → L :=
  let b: Fin (2^(ℓ + R_rate)) → L := tileCoeffs a 
  Fin.foldl (n:=ℓ) (f:= fun current_b i  =>
    computableNTTStage (𝔽q := 𝔽q) (β := β) (ℓ := ℓ) (R_rate := R_rate)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := ⟨ℓ - 1 - i, by admit /- proof elided -/
      ⟩) (b:=current_b)
  ) (init:=b)

def outputRelation [DecidableEq F] (δ : ℝ≥0) :
    Set
      (
        (FinalStatement F k × ∀ j, FinalOracleStatement D x s j) ×
        Witness F s d (Fin.last (k + 1))
      )
  := QueryRound.outputRelation D x s d (round_bound dom_size_cond) δ

List.IsPrefix in Init.Data.List.Basic

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

def toNat (n : ChurchNat ℕ) : ℕ := n Nat.succ 0

instance {i : Fin (k + 1)} : ∀ j, OracleInterface (OracleStatement D x s i j) :=
  fun _ => inferInstance

def BTField.isScalarTower_succ_right (l r : ℕ) (h_le : l ≤ r) :=
  instAlgebraTowerNatBTField.toIsScalarTower (i:=l) (j:=r) (k:=r+1)
  (h1:=by admit /- proof elided -/
  ) (h2:=by admit /- proof elided -/
  )

def rtake {n : ℕ} {α : Fin n → Sort*} (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    (i : Fin m) → α (Fin.cast (Nat.sub_add_cancel h) (natAdd (n - m) i)) :=
  fun i => v (Fin.cast (Nat.sub_add_cancel h) (natAdd (n - m) i))

def divNat [Zero T] [DecidableEq T] [ToNat T]
    (dividend divisor : Cayley T) : Nat → Cayley T
  | 0        => zero  
  | .succ fuel =>
    
    if (↑divisor : Nat) = 0 then
      zero
    else
      
      if (↑divisor : Nat) ≤ (↑dividend : Nat) then
        
        add one (divNat (sub dividend divisor) divisor fuel)
      else
        zero

Array.zipIdx in Init.Data.Array.Basic

Fin.add in Init.Data.Fin.Basic

noncomputable def relayOracleReduction (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleReduction (oSpec := []ₒ)
    (StmtIn := Statement (L := L) Context i.succ)
    (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.succ)
    (StmtOut := Statement (L := L) Context i.succ)
    (OStmtOut := OracleStatement 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (pSpec := pSpecRelay) where
  prover := relayOracleProver 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR
  verifier := relayOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR

def internalLinearLayer (state : Vector KoalaBear.Field params.width) :
    Vector KoalaBear.Field params.width :=
  
  
  let sumAll := state.foldl (fun acc x => acc + x) 0

  
  
  state.zipWith (fun s d => sumAll + d * s) params.internalDiagVectors

AdjoinRoot in Mathlib.RingTheory.AdjoinRoot

def last_nonzero_prop {p : UniPoly R} (k : Fin p.size) : Prop :=
  p[k] ≠ 0 ∧ (∀ j, (hj : j < p.size) → j > k → p[j] = 0)

HomogeneousPow in Init.Prelude

List.Vector.cons in Mathlib.Data.Vector.Defs

def domainEnum (i : Fin (n + 1)) : Fin (2 ^ (n - i)) ↪ evalDomain D i :=
  ⟨domain D n i.1, domain_injective D i.1 (by admit /- proof elided -/
  )⟩

guard in Init.Control.Basic

def Matrix (α : Type*) (m n : ℕ) := Vector (Vector α n) m

noncomputable def toMvPolynomialAlgHom : P →ₐ[R] MvPolynomial σ R := aeval MvPolynomial.X

@[reducible]
def twoAdicity : Nat := 24

Subspace in Mathlib.Algebra.Module.Submodule.Basic

Functor.map in Init.Prelude
</all_available_defs>

<all_available_lemmas>
Fin.is_le in Init.Data.Fin.Lemmas
Nat.lt_of_add_right_lt in Init.Data.Nat.Basic
Nat.lt_of_le_of_lt in Init.Prelude
Fin.eta in Init.Data.Fin.Lemmas
add_zero in Mathlib.Algebra.Group.Defs
Module.Basis.repr_linearCombination in Mathlib.LinearAlgebra.Basis.Defs
Module.Basis.repr_symm_apply in Mathlib.LinearAlgebra.Basis.Defs
Nat.add_zero in Init.Core
cast_eq in Init.Core
eq_mp_eq_cast in Init.PropLemmas
not_lt_zero' in Mathlib.Algebra.Order.GroupWithZero.Canonical
tsub_zero in Mathlib.Algebra.Order.Sub.Defs
Decidable.not_not in Init.PropLemmas
Fin.eq_of_val_eq in Init.Prelude
Fin.is_lt in Init.Data.Fin.Lemmas
Fintype.card_fin in Mathlib.Data.Fintype.Card
Fintype.card_setUniv in Mathlib.Data.Fintype.Card
Set.card_image_of_injective in Mathlib.Data.Set.Finite.Basic
false_or in Init.SimpLemmas
imp_false in Init.Core
left_eq_ite_iff in Init.PropLemmas
one_ne_zero in Mathlib.Algebra.NeZero
right_eq_ite_iff in Init.PropLemmas
zero_ne_one in Mathlib.Algebra.NeZero
nonpos_iff_eq_zero in Mathlib.Algebra.Order.Monoid.Canonical.Defs
not_lt in Mathlib.Order.Defs.LinearOrder
Polynomial.ext in Mathlib.Algebra.Polynomial.Basic
add_lt_iff_neg_right in Mathlib.Algebra.Order.Monoid.Unbundled.Basic
add_tsub_cancel_right in Mathlib.Algebra.Order.Sub.Defs
Nat.le_of_not_lt in Init.Data.Nat.Basic
Nat.sub_lt_sub_right in Init.Data.Nat.Basic
Nat.sub_sub in Init.Data.Nat.Basic
dite_eq_right_iff in Init.PropLemmas
forall_const in Init.PropLemmas
ite_eq_left_iff in Init.PropLemmas
Finset.disjoint_iff_inter_eq_empty in Mathlib.Data.Finset.Lattice.Lemmas
Finset.mem_of_mem_inter_left in Mathlib.Data.Finset.Lattice.Basic
Finset.mem_of_mem_inter_right in Mathlib.Data.Finset.Lattice.Basic
Finset.nonempty_of_ne_empty in Mathlib.Data.Finset.Empty
Set.mem_image in Mathlib.Data.Set.Operations
Set.mem_toFinset in Mathlib.Data.Fintype.Sets
ENat.coe_le_coe in Mathlib.Data.ENat.Basic
ENat.coe_lt_coe in Mathlib.Data.ENat.Basic
ENat.coe_mul in Mathlib.Data.ENat.Basic
ENat.coe_toNat in Mathlib.Data.ENat.Basic
Finset.card_biUnion in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.card_le_card in Mathlib.Data.Finset.Card
Finset.coe_univ in Mathlib.Data.Fintype.Defs
Finset.mem_biUnion in Mathlib.Data.Finset.Union
Finset.mem_filter in Mathlib.Data.Finset.Filter
Finset.mem_image in Mathlib.Data.Finset.Image
Finset.mem_univ in Mathlib.Data.Fintype.Defs
Finset.sum_congr in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.sum_const in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Fintype.card_ofFinset in Mathlib.Data.Fintype.Card
Nat.add_sub_cancel in Init.Data.Nat.Basic
Nat.card_coe_set_eq in Mathlib.Data.Set.Card
Nat.card_eq_fintype_card in Mathlib.SetTheory.Cardinal.Finite
Nat.le_of_lt_succ in Init.Prelude
Nat.lt_add_of_pos_right in Init.Data.Nat.Basic
Nat.lt_of_le_pred in Init.Data.Nat.Basic
Nat.ofNat_pos in Mathlib.Data.Nat.Cast.Order.Ring
Nat.pos_of_neZero in Init.Data.Nat.Basic
Nat.pow_add in Init.Data.Nat.Lemmas
Nat.pow_lt_pow_right in Init.Data.Nat.Lemmas
Nat.sInf_mem in Mathlib.Data.Nat.Lattice
Nat.sub_mul in Init.Data.Nat.Basic
Set.image_nonempty in Mathlib.Data.Set.Image
Set.image_univ in Mathlib.Data.Set.Image
Set.nonempty_iff_ne_empty' in Mathlib.Data.Set.Basic
Set.toFinset_card in Mathlib.Data.Fintype.Card
Set.toFinset_range in Mathlib.Data.Fintype.Sets
Set.toFinset_setOf in Mathlib.Data.Fintype.Sets
Set.univ_nonempty in Mathlib.Data.Set.Basic
SetLike.mem_coe in Mathlib.Data.SetLike.Basic
Submodule.coe_mem in Mathlib.Algebra.Module.Submodule.Defs
Submodule.nonempty in Mathlib.Algebra.Module.Submodule.Defs
Subtype.coe_eta in Mathlib.Data.Subtype
WithTop.coe_lt_coe in Mathlib.Order.WithBot
and_self in Init.SimpLemmas
ge_iff_le in Init.Core
le_of_eq_of_le in Init.Core
le_refl in Mathlib.Order.Defs.PartialOrder
le_trans in Mathlib.Order.Defs.PartialOrder
mul_assoc in Mathlib.Algebra.Group.Defs
mul_le_mul_right in Mathlib.Algebra.Order.Monoid.Unbundled.Basic
ne_eq in Init.SimpLemmas
nonempty_subtype in Mathlib.Logic.Nonempty
not_false_eq_true in Init.SimpLemmas
pow_pos in Mathlib.Algebra.Order.GroupWithZero.Unbundled.Basic
sInf_le in Mathlib.Order.CompleteLattice.Defs
smul_eq_mul in Mathlib.Algebra.Group.Action.Defs
true_and in Init.SimpLemmas

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

@[simp]
lemma lt_add_of_pos_right_of_le (a b c : ℕ) [NeZero c] (h : a ≤ b) : a < b + c

lemma eq_iff_eq_all_getBits {n m : ℕ} : n = m ↔ ∀ k, getBit k n = getBit k m

lemma getBit_of_lt_two_pow {n: ℕ} (a: Fin (2^n)) (k: ℕ) :
  getBit k a = if k < n then getBit k a else 0

lemma getBit_eq_testBit (k n : Nat) : getBit k n = if n.testBit k then 1 else 0

lemma getBit_lt_2 {k n : Nat} : getBit k n < 2

lemma getBit_eq_zero_or_one {k n : Nat} :
  getBit k n = 0 ∨ getBit k n = 1

omit [DecidableEq 𝔽q] hF₂ in
lemma getSDomainBasisCoeff_of_iteratedQuotientMap
    [NeZero R_rate] (i : Fin ℓ) (k : ℕ)
    (h_bound : i.val + k ≤ ℓ) (x : (sDomain 𝔽q β
    h_ℓ_add_R_rate) ⟨i, by omega⟩) :
    let y

theorem base_intermediateNormVpoly
  (k : Fin (ℓ + 1)) :
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate ⟨0, by
    by_contra ht
    simp only [not_lt, nonpos_iff_eq_zero] at ht
    contradiction
  ⟩ ⟨k, by simp only [tsub_zero]; omega⟩ =
  normalizedW 𝔽q β ⟨k, by omega⟩

lemma normalizedW_eq_qMap_composition (ℓ R_rate : ℕ) (i : Fin r) :
    normalizedW 𝔽q β i = qCompositionChain 𝔽q β (ℓ:=ℓ) (R_rate:=R_rate) i

lemma qMap_comp_normalizedW (i : Fin r) (h_i_add_1 : i + 1 < r) :
  (qMap 𝔽q β i).comp (normalizedW 𝔽q β i) = normalizedW 𝔽q β (i + 1)

lemma qCompositionChain_eq_foldl (i : Fin r) :
  qCompositionChain 𝔽q β (ℓ:=ℓ) (R_rate:=R_rate) i =
  Fin.foldl (n:=i) (fun acc j =>
    (qMap 𝔽q β ⟨j, by omega⟩).comp acc) (X)

omit [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 in
lemma getSDomainBasisCoeff_of_sum_repr [NeZero R_rate] (i : Fin (ℓ + 1))
    (x : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i, by omega⟩)
    (x_coeffs : Fin (ℓ + R_rate - i) → 𝔽q)
    (hx : x = ∑ j_x, (x_coeffs j_x) • (sDomain_basis 𝔽q β
      h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (h_i := by
        simp only; apply Nat.lt_add_of_pos_right_of_le; omega) j_x).val) :
    ∀ (j: Fin (ℓ + R_rate - i)), ((sDomain_basis 𝔽q β
      h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (h_i := by
        simp only; apply Nat.lt_add_of_pos_right_of_le; omega)).repr x) j = x_coeffs j

omit [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 in
lemma get_sDomain_basis (i : Fin r) (h_i : i < ℓ + R_rate) :
    ∀ (k : Fin (ℓ + R_rate - i)),
    (sDomain_basis 𝔽q β h_ℓ_add_R_rate
      i (by omega)) k = eval (β ⟨i + k.val, by omega⟩) (normalizedW 𝔽q β i)

omit [DecidableEq L] [DecidableEq 𝔽q] h_Fq_char_prime hF₂ hβ_lin_indep h_β₀_eq_1 in
theorem intermediateNormVpoly_comp (i : Fin ℓ) (k : Fin (ℓ - i + 1))
  (l : Fin (ℓ - (i.val + k.val) + 1)) :
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (k:=⟨k + l, by
      simp only; omega⟩) =
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i+k, by omega⟩) (k:=⟨l, by
      simp only; omega⟩)).comp (
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (k:=⟨k, by
      simp only; omega⟩)
  )

omit [DecidableEq L] [DecidableEq 𝔽q] hF₂ hβ_lin_indep h_β₀_eq_1 in
lemma intermediateNormVpoly_eval_is_linear_map (i : Fin (ℓ + 1)) (k : Fin (ℓ - i + 1)) :
  IsLinearMap 𝔽q (fun x : L =>
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate i k).eval x)

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

omit h_Fq_char_prime in
lemma 𝔽q_element_eq_zero_or_eq_one : ∀ c: 𝔽q, c = 0 ∨ c = 1

lemma getBit_of_binaryFinMapToNat {n : ℕ} (m : Fin n → ℕ) (h_binary: ∀ j: Fin n, m j ≤ 1) :
    ∀ k: ℕ, Nat.getBit k (binaryFinMapToNat m h_binary).val
      = if h_k: k < n then m ⟨k, by omega⟩ else 0

lemma and_two_pow_eq_zero_of_getBit_0 {n i : ℕ} (h_getBit : getBit i n = 0)
    : n &&& (2 ^ i) = 0

lemma and_eq_zero_iff_and_each_getBit_eq_zero {n m : ℕ} :
    n &&& m = 0 ↔ ∀ k, Nat.getBit k n &&& Nat.getBit k m = 0

lemma shiftRight_and_one_distrib {n m k : ℕ} :
    Nat.getBit k (n &&& m) = Nat.getBit k n &&& Nat.getBit k m

lemma getBit_two_pow {i k : ℕ} : (getBit k (2^i) = if i == k then 1 else 0)

lemma getBit_of_xor {n m k: ℕ} : getBit k (n ^^^ m) = getBit k n ^^^ getBit k m

lemma getBit_zero_eq_zero {k : Nat} : getBit k 0 = 0

lemma sum_of_and_eq_zero_is_xor {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n + m = n ^^^ m

lemma sum_eq_xor_plus_twice_and (n : Nat) : ∀ m : ℕ, n + m = (n ^^^ m) + 2 * (n &&& m)

lemma and_by_split_lowBits {n m n1 m1 bn bm : ℕ} (h_bn : bn < 2) (h_bm : bm < 2)
  (h_n : n = n1 * 2 + bn) (h_m : m = m1 * 2 + bm):
  n &&& m = (n1 &&& m1) * 2 + (bn &&& bm)

lemma div_2_form {nD2 b : ℕ} (h_b : b < 2):
  (nD2 * 2 + b) / 2 = nD2

lemma or_by_split_lowBits {n m n1 m1 bn bm : ℕ} (h_bn : bn < 2) (h_bm : bm < 2)
  (h_n : n = n1 * 2 + bn) (h_m : m = m1 * 2 + bm):
  n ||

lemma xor_by_split_lowBits {n m n1 m1 bn bm : ℕ} (h_bn : bn < 2) (h_bm : bm < 2)
  (h_n : n = n1 * 2 + bn) (h_m : m = m1 * 2 + bm):
  n ^^^ m = (n1 ^^^ m1) * 2 + (bn ^^^ bm)

theorem distFromCode_eq_top_iff_empty (u : n → R) (C : Set (n → R)) : Δ₀(u, C) = ⊤ ↔ C = ∅

theorem sub_add_eq_sub_sub_rev (a b c : Nat) (h1 : c ≤ b) (h2 : b ≤ a) :
  a - b + c = a - (b - c)

@[simp] theorem rightpad_length (n : Nat) (unit : α) (l : List α) :
    (rightpad n unit l).length = max n l.length

@[simp]
lemma aeval_X {A : Type y} [CommSemiring A] [Algebra R A] {F : Type z} [FunEquiv F σ A] (g : F)
    (s : σ) : aeval g (X s : P) = g s

@[simp]
theorem dappend_dempty {motive : Fin (m + 0) → Sort u} (v : (i : Fin m) → motive (castAdd 0 i)) :
    dappend (motive := motive) v !d⟨fun _ : Fin 0 => motive (natAdd m _)⟩[] = v

@[simp]
theorem dcons_zero {motive : Fin (n + 1) → Sort u} (a : motive 0)
    (v : (i : Fin n) → motive i.succ) : (a ::ᵈ⟨motive⟩ v) 0 = a

@[simp]
lemma concrete_natCast_zero_eq_zero {k : ℕ} : natCast 0 = (0 : ConcreteBTField k)

lemma rtake_eq_rtake : transcript⟦m:⟧ = transcript.drop m h

@[simp]
theorem drop_drop {m m' : ℕ} (h : m ≤ n - m') (h' : m' ≤ n) (v : (i : Fin n) → α i) :
    drop m h (drop m' h' v) =
      (fun i =>
        letI := drop (m + m') (Nat.add_le_of_le_sub h' h) v (i.cast (by omega))
        dcast (by simp [Fin.cast, add_assoc]) this)

@[simp]
theorem dcast₃_eq : dcast₃ (Eq.refl a) dcast_eq dcast₂_eq d = d

@[simp] theorem toNat_ofNat (n : Nat) : toNat (ofNat n) = n

@[simp]
theorem getLastI_append_single [Inhabited α] (x : α) : (l ++ [x]).getLastI = x

theorem seqCompose_rbrSoundness
    (lang : (i : Fin (m + 1)) → Set (Stmt i))
    (V : (i : Fin m) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i))
    (rbrSoundnessError : ∀ i, (pSpec i).ChallengeIdx → ℝ≥0)
    (h : ∀ i, (V i).rbrSoundness init impl (lang i.castSucc) (lang i.succ) (rbrSoundnessError i)) :
      (Verifier.seqCompose Stmt V).rbrSoundness init impl (lang 0) (lang (Fin.last m))
        (fun combinedIdx =>
          letI ij := seqComposeChallengeIdxToSigma combinedIdx
          rbrSoundnessError ij.1 ij.2)

Fin.append_left in Mathlib.Data.Fin.Tuple.Basic

lemma h_middle_sub {k : ℕ} : 2 ^ (k - 1) - 1 - 0 + 1 = 2 ^ (k - 1)

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]
theorem OracleReduction.id_runWithLog (stmt : StmtIn) (oStmt : ∀ i, OStmtIn i) (wit : WitIn) :
    (OracleReduction.id : OracleReduction oSpec StmtIn OStmtIn WitIn _ _ _ _).runWithLog
      stmt oStmt wit = pure ⟨⟨default, ⟨stmt, oStmt⟩, wit⟩, ⟨stmt, oStmt⟩, [], []⟩

lemma out_of_dom_smpl_1
  {δ l : ℝ≥0} {s : ℕ} {f : ι → F} {degree : ℕ} {φ : ι ↪ F}
  (C : Set (ι → F)) (hC : C = code φ degree)
  (h_decodable : listDecodable C δ l)
  (h_nonempty : Nonempty (domainComplement φ)) :
  listDecodingCollisionProbability φ f δ s degree h_nonempty ≤
    ((l * (l-1) / 2)) * ((degree - 1) / (Fintype.card F - Fintype.card ι))^s

theorem join_eq_join_iff {k : ℕ} (h_pos : k > 0) (hi₀ lo₀ hi₁ lo₁ : ConcreteBTField (k - 1)) :
  《 hi₀, lo₀ 》 = 《 hi₁, lo₁ 》 ↔ (hi₀ = hi₁ ∧ lo₀ = lo₁)

@[simp]
lemma Transcript.def_eq {k : Fin (n + 1)} {pSpec : ProtocolSpec n} :
    (pSpec.take k k.is_le).FullTranscript =
      ((i : Fin k) → pSpec.«Type» (Fin.castLE (by omega) i))

@[grind ←]
lemma mul_ne_zero [IsDomain F] (f g : F[X][Y]) (hf : f ≠ 0) (hg : g ≠ 0) :
  f * g ≠ 0

omit [Finite F] in
lemma pow_lift : ∀ {a : Fˣ} {i : ℕ} (s : ℕ),
    a ∈ evalDomain D x i → a ^ (2 ^ s) ∈ evalDomain D x (i + s)

@[grind =] theorem idxOf'_cons [BEq α] {a : α} {x : α} {xs : List α} :
    idxOf' a (x :: xs) = bif x == a then 0 else idxOf' a xs + 1

lemma mul_trans_inequality {k : ℕ} (x : ℕ) (h_k : k ≤ 2) (h_x : x ≤ 2 ^ (2 ^ k) - 1) : x < 16

private lemma johnson_bound₀ [Zero F]
  (h_n : 0 < n)
  (h_B : 2 ≤ B.card)
  (h_card : 2 ≤ (Fintype.card F))
  :
  B.card *
    ((1 - ((Fintype.card F : ℚ) / (Fintype.card F - 1)) * (e B 0 / n)) ^ 2
      - (1 - ((Fintype.card F : ℚ) / (Fintype.card F - 1)) * (d B/n)))  ≤
  ((Fintype.card F : ℚ) / (Fintype.card F - 1)) * d B/n

@[simp] -- main lemma for bIdx: Fin (ℓ / ϑ - 1) bounds
lemma bIdx_mul_ϑ_add_x_lt_ℓ_sub_ϑ (bIdx : Fin (ℓ / ϑ - 1)) (x : ℕ) {hx : x ≤ ϑ} :
    ↑bIdx * ϑ + x ≤ ℓ - ϑ

theorem ScalarField_is_prime : Nat.Prime SCALAR_FIELD_CARD

@[simp] lemma extract_Type : pSpec⟦start:stop⟧.«Type» = pSpec.«Type»⟦start:stop⟧

private lemma BerlekampWelchCondition_to_Solution [NeZero n]
  (hk_or_e : 1 ≤ k ∨ 1 ≤ e)
  (h : BerlekampWelchCondition e k ωs f E Q)
  : IsBerlekampWelchSolution e k ωs f (E_and_Q_to_a_solution e E Q)

theorem add_comm : p + q = q + p

lemma natDegree_lt_of_mem_degreeLT [NeZero deg] (h : p ∈ degreeLT F deg) : p.natDegree < deg

@[simp] theorem findIdx'_nil {p : α → Bool} : findIdx' p [] = 0

@[simp]
theorem fappend₂_right {α₁ : Fin m → A} {α₂ : Fin m → B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (u : (i : Fin m) → F₂ (α₁ i) (α₂ i)) (v : (i : Fin n) → F₂ (β₁ i) (β₂ i)) (i : Fin n) :
    fappend₂ (F := F₂) u v (natAdd m i) =
      cast (by simp [vappend_right]) (v i)

@[simp]
theorem Basis_cast_dest_apply {ι : Type*} (α β γ : ℕ)
    (h_le1 : α ≤ β) (h_le2 : α ≤ γ)
    (h_eq : β = γ) {k : ι} (b : @Basis ι (ConcreteBTField α) (ConcreteBTField β) _ _
    (@ConcreteBTFieldAlgebra (l := α) (r := β) (h_le := h_le1)).toModule) :
    let castBasis : @Basis ι (ConcreteBTField α) (ConcreteBTField γ) _ _
      (@ConcreteBTFieldAlgebra (l := α) (r := γ) (h_le := h_le2)).toModule :=
      cast (by
        exact Basis_cast_dest_eq α γ β h_le2 h_le1 h_eq
      ) b
    (castBasis k) = cast (by
      exact cast_ConcreteBTField_eq β γ h_eq) (b k)

lemma neg_add_cancel {k : ℕ} (a : ConcreteBTField k) : neg a + a = 0

theorem rbrKnowledgeSoundness_implies_rbrSoundness
    {relIn : Set (StmtIn × WitIn)} {relOut : Set (StmtOut × WitOut)}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec}
    {rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0}
    (h : verifier.rbrKnowledgeSoundness init impl relIn relOut rbrKnowledgeError) :
    verifier.rbrSoundness init impl relIn.language relOut.language rbrKnowledgeError

@[simp]
lemma getTypes_hcons (x : Σ α : Type u, α) (xs : HList) :
    (x ::ₕ xs).getTypes = x.1 :: xs.getTypes

@[simp]
theorem fconcat_castSucc {α : Fin n → A} {β : A}
    (v : (i : Fin n) → F (α i)) (b : F β) (i : Fin n) :
    (v :+ʰ⦃F⦄ b) (castSucc i) = cast (by simp [vconcat_castSucc]) (v i)

theorem singleEqPolynomial_zeroOne_C (r : Fin 2) (x : Fin 2) :
    (singleEqPolynomial (r : R) (C x) : MvPolynomial σ R) = if x = r then 1 else 0

@[csimp, grind =]
theorem idxOf'_eq_idxOf : @idxOf' = @idxOf

theorem oddRefinement_eq_novel_poly_of_1_leading_suffix (i : Fin ℓ) (v : Fin (2 ^ i.val))
    (original_coeffs : Fin (2 ^ ℓ) → L) :
    have h_v: v.val ||

lemma concrete_div_eq_mul_inv {k : ℕ} (a b : ConcreteBTField k) : a / b = a * (concrete_inv b)

theorem mulVecLin_coeff_vandermondens_eq_eval_matrixOfPolynomials
  {n : ℕ} [NeZero n] {v : ι ↪ F} {p : F[X]} (h_deg : p.natDegree < n) :
  (Vandermonde.nonsquare (ι' := n) v).mulVecLin (Fin.liftF' p.coeff) =
  fun i => p.eval (v i)

@[simp]
theorem insertNth_last : insertNth (Fin.last n) y s = snoc s y

@[to_additive (attr := simp)]
theorem prod_Iic_zero : ∏ j ∈ Iic 0, v j = v 0

@[simp] -- TODO: more general version/class for query impls that never have failures
lemma loggingOracle.probFailure_simulateQ [spec.FiniteRange] (oa : OracleComp spec α) :
    [⊥ | (simulateQ loggingOracle oa).run] = [⊥ | oa] := by
  induction oa using OracleComp.induction with

theorem liftContext_runWithLogToRound
    {lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {outerStmtIn : OuterStmtIn} {outerWitIn : OuterWitIn} {i : Fin (n + 1)}
    (P : Prover oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec) :
      (P.liftContext lens).runWithLogToRound i outerStmtIn outerWitIn
      = do
        let ⟨⟨transcript, prvState⟩, queryLog⟩ ←
          (P.runWithLogToRound i).uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨⟨transcript, ⟨prvState, outerStmtIn, outerWitIn⟩⟩, queryLog⟩

theorem eqPolynomial_degreeOf (r : σ → R) (i : σ) : degreeOf i (eqPolynomial r) ≤ 1

Finset.sup_lt_iff in Mathlib.Data.Finset.Lattice.Fold

lemma algebraMap_eq_zero_x {i j : ℕ} (h_le : i < j) (x : BTField i) :
    letI instAlgebra := binaryAlgebraTower (l:=i) (r:=j) (h_le:=by omega)
    letI instAlgebraPred := binaryAlgebraTower (l:=i) (r:=j-1) (h_le:=by omega)
    algebraMap (BTField i) (BTField j) x
      = ⋘ 0, algebraMap (BTField i) (BTField (j-1)) x ⋙

@[simp]
theorem addCases'_right {m n : ℕ} {α : Fin m → Sort u} {β : Fin n → Sort u}
    (left : (i : Fin m) → α i) (right : (j : Fin n) → β j) (i : Fin n) :
      addCases' left right (Fin.natAdd m i) = (Fin.append_right α β i) ▸ (right i)

lemma zipWith_const {α β : Type _} {f : α → β → β} {l₁ : List α} {l₂ : List β}
  (h₁ : l₁.length = l₂.length) (h₂ : ∀ a b, f a b = b) : l₁.zipWith f l₂ = l₂

lemma bwm_of_neg [NeZero n] (h : e ≤ j.1) :
  BerlekampWelchMatrix e k ωs f i j = -(ωs i)^(j - e)

theorem is_unit_iff_deg_0 {R : Type*} [Field R] {p : R[X]} : p.degree = 0 ↔ IsUnit p

@[grind]
lemma quotient_nezero {f q : F[X][Y]} (hg : q * f ≠ 0) : q ≠ 0

theorem MLE_mem_restrictDegree (evals : (σ → Fin 2) → R) : (MLE evals) ∈ R⦃≤ 1⦄[X σ]

@[simp]
theorem fappend₂_succ {α₁ : Fin m → A} {α₂ : Fin m → B}
    {β₁ : Fin (n + 1) → A} {β₂ : Fin (n + 1) → B}
    (u : (i : Fin m) → F₂ (α₁ i) (α₂ i)) (v : (i : Fin (n + 1)) → F₂ (β₁ i) (β₂ i)) :
    fappend₂ (F := F₂) u v =
      fconcat₂ (F := F₂) (fappend₂ (F := F₂) u (fun i => v (castSucc i))) (v (last n))

omit [Finite F] in
lemma sqr_mem_D_succ_i_of_mem_D_i : ∀ {x : Fˣ} {i : ℕ},
  x ∈ evalDomain D i → x ^ 2 ∈ evalDomain D (i + 1)

lemma guruswami_sudan_for_proximity_gap_property {k m : ℕ} {ωs : Fin n ↪ F}
  {f : Fin n → F}
  {Q : F[X][X]}
  {p : ReedSolomon.code ωs n}
  (h : Δ₀(f, (ReedSolomon.codewordToPoly p).eval ∘ f) ≤ proximity_gap_johnson (n := n) k m)
  :
  ((X : F[X][X]) - C (ReedSolomon.codewordToPoly p)) ∣ Q

lemma odd_index_intermediate_novel_basis_decomposition
    (i : Fin ℓ) (j : Fin (2 ^ (ℓ - i - 1))) :
    intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i, by omega⟩ ⟨j * 2 + 1, by
      apply mul_two_add_bit_lt_two_pow j (ℓ-i-1) (ℓ-i) ⟨1, by omega⟩ (by omega) (by omega)
    ⟩  = X * (intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i+1, by omega⟩ ⟨j, by
      apply lt_two_pow_of_lt_two_pow_exp_le j (ℓ-i-1) (ℓ-(i+1)) (by omega) (by omega)
    ⟩).comp (qMap 𝔽q β ⟨i, by omega⟩)

theorem neg_trim [LawfulBEq R] (p : UniPoly R) : p.trim = p → (-p).trim = -p

omit Oₘ in
theorem seqCompose_completeness (hInit : init.neverFails)
    (rel : (i : Fin (m + 1)) → Set (Stmt i × Wit i))
    (R : ∀ i, Reduction oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ)
      (pSpec i))
    (completenessError : Fin m → ℝ≥0)
    (h : ∀ i, (R i).completeness init impl (rel i.castSucc) (rel i.succ) (completenessError i)) :
      (Reduction.seqCompose Stmt Wit R).completeness init impl (rel 0) (rel (Fin.last m))
        (∑ i, completenessError i)

lemma list_0 : list 0 = List.Vector.cons (1 : GF(2)) List.Vector.nil

@[simp]
private lemma leadingCoeff_E : (E ωs f p e).leadingCoeff = 1

lemma listOfCloseCodewords_eq_zero :
  listOfCloseCodewords C y n = 0 ↔ IsEmpty (hammingBall C y n) ∨ Infinite (hammingBall C y n)

lemma min_dist_le_d [Field F] {B : Finset (Fin n → F)} (v : Fin n → F)
  :
  sInf { d | ∃ u ∈ B, ∃ v ∈ B, u ≠ v ∧ hammingDist u v = d } ≤ d B

private lemma aux_sum [Zero F]
  (h_n : 0 < n)
  : n * choose_2 (aux_frac B (k B)) ≤ ∑ i, choose_2 (aux_frac B (K B i 0))

theorem dfoldl_congr {n : ℕ}
    {α α' : Fin (n + 1) → Type u}
    {f : (i : Fin n) → α i.castSucc → α i.succ}
    {f' : (i : Fin n) → α' i.castSucc → α' i.succ}
    {init : α 0} {init' : α' 0}
    (hα : ∀ i, α i = α' i)
    (hf : ∀ i a, f i a = (cast (hα _).symm (f' i (cast (hα _) a))))
    (hinit : init = cast (hα 0).symm init') :
      dfoldl n α f init = cast (hα (last n)).symm (dfoldl n α' f' init')

@[simp]
theorem dflatten_two_eq_append {n : Fin 2 → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    {v : (i : Fin 2) → (j : Fin (n i)) → motive (embedSum i j)} :
    dflatten (motive := motive) v = dappend (v 0) (v 1)

@[simp]
lemma erase_even_empty :
    erase_even ∅ = ∅

theorem oracleVerifier_eq_verifier :
    (oracleVerifier R deg D oSpec).toVerifier = verifier R deg D oSpec

theorem FullData.toLeafData_eq_leaf {α} (a : α) (tree)
    (h : LeafData.leaf a = tree.toLeafData) :
    tree = FullData.leaf a

lemma getBit_eq_pred_getBit_of_div_two {n k : ℕ} (h_k: k > 0) :
    getBit k (n) = getBit (k-1) (n/2)

omit [DecidableEq 𝔽q] hF₂ in
lemma getSDomainBasisCoeff_of_iteratedQuotientMap
    [NeZero R_rate] (i : Fin ℓ) (k : ℕ)
    (h_bound : i.val + k ≤ ℓ) (x : (sDomain 𝔽q β
    h_ℓ_add_R_rate) ⟨i, by omega⟩) :
    let y := iteratedQuotientMap (i := i) (k:=k) (h_bound:=h_bound) (x:=x)
    ∀ (j: Fin (ℓ + R_rate - (i + k))),
    ((sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨↑i + k, by omega⟩) (h_i := by
      simp only;
      apply Nat.lt_add_of_pos_right_of_le; omega)).repr y) j =
    ((sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨↑i, by omega⟩)
      (h_i := by simp only; omega)).repr x) ⟨j + k, by simp only; omega⟩

@[simp]
theorem BTField.PowerBasis.dim_of_eq_rec
    (r1 r : ℕ)
    (h_r : r = r1 + 1)
    (b : PowerBasis (BTField r1) (BTField (r1 + 1))) :
    letI instAlgebra : Algebra (BTField r1) (BTField r) :=
      binaryAlgebraTower (l:=r1) (r:=r) (h_le:=by omega)
    ((Eq.rec (motive:=fun (x : ℕ) (_ : r1 + 1 = x) => by
      letI instAlgebraCur : Algebra (BTField r1) (BTField x) :=
        binaryAlgebraTower (l:=r1) (r:=x) (h_le:=by omega)
      exact PowerBasis (BTField r1) (BTField x)) (refl:=b) (t:=h_r.symm)) :
        PowerBasis (BTField r1) (BTField r)).dim
    = b.dim

@[simp]
lemma OracleVerifier.append_toVerifier
    (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ pSpec₂) :
      (OracleVerifier.append V₁ V₂).toVerifier =
        Verifier.append V₁.toVerifier V₂.toVerifier

theorem degreeOf_linear_le {a b : R} : degreeOf n (C a + C b * p) ≤ degreeOf n p

theorem dconcat_dcons_eq_dcons_dconcat {motive : Fin (n + 2) → Sort u} (a : motive 0)
    (v : (i : Fin n) → motive (succ (castSucc i))) (b : motive (last (n + 1))) :
    (a ::ᵈ v) :+ᵈ⟨motive⟩ b = a ::ᵈ⟨motive⟩ (v :+ᵈ b)

theorem mca_capacity_bound_CONJECTURE
  [DecidableEq ι]
  (α : F) (φ : ι ↪ F) (m : ℕ) [Smooth φ]
  (parℓ_type : Type) [Fintype parℓ_type] (exp : parℓ_type ↪ ℕ) :
  let Gen := RSGenerator.genRSC parℓ_type φ m exp
  let : Fintype Gen.parℓ := Gen.hℓ
  haveI := Gen.Gen_nonempty
  ∃ (c₁ c₂ : ℕ),
    ∀ (f : Gen.parℓ → ι → F) (η : ℝ) (_hη : 0 < η) (δ : ℝ≥0)
      (_hδ : 0 < δ ∧ δ < 1 - Gen.rate - η),
      Pr_{let r ←$ᵖ Gen.Gen}[ proximityCondition f δ r Gen.C ] ≤
        ENNReal.ofReal (
          (((Fintype.card parℓ_type - 1) : ℝ)^c₂ * ((2^m) : ℝ)^c₂) /
          (η^c₁ * Gen.rate^(c₁+c₂) * (Fintype.card F))
        )

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

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

lemma zipWith_size {R} {f : R → R → R} {a b : Array R} (h : a.size = b.size) :
    (Array.zipWith f a b).size = a.size

lemma eq_degree_of_equiv [LawfulBEq R] {p q : UniPoly R} : equiv p q → p.degree = q.degree

@[grind]
lemma degreeY_le_degreeY_sub_degreeY [IsDomain F] {f q : F[X][Y]} (hf : f ≠ 0) (hg : q * f ≠ 0) :
  natDegreeY q ≤ natDegreeY (q * f) - natDegreeY f

@[simp]
theorem runWithOracle_freeMonad_pure_some (f : spec.FunctionType) (a : α) :
    runWithOracle f (FreeMonad.pure (a : Option α)) = a

lemma concrete_zero_mul0 (b : ConcreteBTField 0) :
  concrete_mul (zero (k:=0)) b = zero (k:=0)

theorem prime_17 : Nat.Prime 17

theorem liftContext_completeness
    (h : R.completeness init impl innerRelIn innerRelOut completenessError) :
      (R.liftContext lens).completeness init impl outerRelIn outerRelOut completenessError

@[simp]
lemma liftComp_support {ι' : Type w} {superSpec : OracleSpec ι'}
    [h : MonadLift (OracleQuery spec) (OracleQuery superSpec)]
    (oa : OracleComp spec α) : (liftComp oa superSpec).support = oa.support

lemma BTField.coe_one_succ (l : ℕ) :
  (@binaryAlgebraTower (l:=l) (r:=l+1) (h_le:=by omega)).algebraMap (1 : BTField l) =
    (1 : BTField (l+1))

theorem liftContext_rbr_soundness [Inhabited InnerStmtOut]
    {outerLangIn : Set OuterStmtIn} {outerLangOut : Set OuterStmtOut}
    {innerLangIn : Set InnerStmtIn} {innerLangOut : Set InnerStmtOut}
    {rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0}
    {lens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut}
    (V : Verifier oSpec InnerStmtIn InnerStmtOut pSpec)
    -- TODO: figure out the right compatibility relation for the IsSound condition
    [lensSound : lens.IsSound outerLangIn outerLangOut innerLangIn innerLangOut
      (V.compatStatement lens)]
    (h : V.rbrSoundness init impl innerLangIn innerLangOut rbrSoundnessError) :
      (V.liftContext lens).rbrSoundness init impl outerLangIn outerLangOut rbrSoundnessError

@[simp] lemma my_neg_mod_two (m : ℤ) : ( - m) % 2 = if m % 2 = 0 then 0 else 1

theorem proximity_gap_RSCodes {k t : ℕ} [NeZero k] [NeZero t] {deg : ℕ} {domain : ι ↪ F}
  (C : Fin t → (Fin k → (ι → F))) {δ : ℝ≥0} (hδ : δ ≤ 1 - (ReedSolomonCode.sqrtRate deg domain)) :
  δ_ε_proximityGap
    (ReedSolomonCode.toFinset domain deg)
    (Affine.AffSpanFinsetCollection C)
    δ
    (errorBound δ deg domain)

omit h_β₀_eq_1 in
theorem sDomainFin_bijective (i : Fin r) (h_i : i < ℓ + R_rate)
: Function.Bijective
  (sDomainFinEquiv 𝔽q β h_ℓ_add_R_rate i h_i)

@[simp]
theorem oracleReduction_completeness (h : init.neverFails) :
    (oracleReduction oSpec Statement OStatement pred).perfectCompleteness init impl
    (toRelInput pred hPred) Set.univ

theorem singleton_subset_Icc (n : ℕ) : {1} ⊆ Finset.Icc 1 (n + 1)

@[simp]
theorem vappend_right (u : Fin m → α) (v : Fin n → α) (i : Fin n) :
    vappend u v (natAdd m i) = v i

lemma mca_linearCode
  (Gen : ProximityGenerator ι F) [Fintype Gen.parℓ] [Nonempty Gen.parℓ]
  (C : LinearCode ι F) (hC : C = Gen.C) :
    hasMutualCorrAgreement
     -- Gen
      Gen
    -- BStar (using δᵣ produced )
      (min (1 - (δᵣ (C : Set (ι → F))) / 2) (Gen.B Gen.C Gen.parℓ))
    -- errStar
      (fun δ => Gen.err C Gen.parℓ δ)

@[simp]
theorem partialSum_succ {a : α} {l : List α} :
    (a :: l).partialSum = [0] ++ (partialSum l).map (a + ·)

lemma eqRec_fun_eq_eqRec_sort {α : Sort*} {β : α → Sort u} {a a' : α}
    (h : a = a') (h' : β a = β a') (b : β a) :
  h ▸ b = h' ▸ b

theorem eq_iff_split_eq {k : ℕ} (h_pos : k > 0) (x₀ x₁ : ConcreteBTField k) :
  x₀ = x₁ ↔ (split h_pos x₀ = split h_pos x₁)

@[simp]
lemma coe_toFun_of_coe_apply (f : ∀ a, β a) (a : α) : (f : F) a = f a

@[simp] theorem fromNat_toNat_eq_self {k : ℕ} (bv : BitVec (2 ^ k)) :
  (fromNat (BitVec.toNat bv) : ConcreteBTField k) = bv

lemma lagrangeToMono_eq_lagrangeToMono_segment (n : ℕ) [NeZero n] (v : Vector R (2 ^ n)) :
  have h_n_ne_zero: n ≠ 0

lemma norm_of_ne_zero_is_ne_zero {k : ℕ}
  {h_k_gt_0 : k > 0} (prevBTFieldResult : ConcreteBTFStepResult (k := k - 1))
  (a : ConcreteBTField k) (h_a_ne_zero : a ≠ 0) :
  let a₁ := (split h_k_gt_0 a).1
  let a₀ := (split h_k_gt_0 a).2
  concrete_mul a₀ (a₀ + concrete_mul a₁ (Z (k - 1))) + concrete_mul a₁ a₁ ≠ 0

@[simp]
theorem fcons₂_succ {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (a : F₂ α₁ α₂) (b : (i : Fin n) → F₂ (β₁ i) (β₂ i)) (i : Fin n) :
    fcons₂ (F := F₂) a b i.succ =
      cast (by simp [Fin.vcons_succ]) (b i)

theorem oracleVerifier_rbrKnowledgeSoundness [Fintype R] :
    (oracleVerifier R deg D oSpec).rbrKnowledgeSoundness init impl
    (inputRelation R deg D) (outputRelation R deg) (fun _ => (deg : ℝ≥0) / (Fintype.card R))

@[simp]
lemma seqCompose_zero
    (Stmt : Fin 1 → Type) (Wit : Fin 1 → Type) {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (P : (i : Fin 0) →
      Prover oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ) (pSpec i)) :
    seqCompose Stmt Wit P = Prover.id

lemma last_nonzero_unique {p : UniPoly Q} {k k' : Fin p.size} :
  last_nonzero_prop k → last_nonzero_prop k' → k = k'

@[simp]
theorem cast_val {m n : ℕ} (h : m = n) (a : Fin m) : (Fin.cast h a).val = a.val

theorem vappend_assoc {p : ℕ} (u : Fin m → α) (v : Fin n → α) (w : Fin p → α) :
    (vappend (vappend u v) w) = (vappend u (vappend v w)) ∘ Fin.cast (add_assoc m n p)

@[simp]
theorem acceptRejectOracleRel_language :
    acceptRejectOracleRel.language = { (true, isEmptyElim) }

@[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))

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

theorem append_completeness (R₁ : OracleReduction oSpec Stmt₁ OStmt₁ Wit₁ Stmt₂ OStmt₂ Wit₂ pSpec₁)
    (R₂ : OracleReduction oSpec Stmt₂ OStmt₂ Wit₂ Stmt₃ OStmt₃ Wit₃ pSpec₂)
    {completenessError₁ completenessError₂ : ℝ≥0}
    (h₁ : R₁.completeness init impl rel₁ rel₂ completenessError₁)
    (h₂ : R₂.completeness init impl rel₂ rel₃ completenessError₂) :
      (R₁.append R₂).completeness init impl
        rel₁ rel₃ (completenessError₁ + completenessError₂)

@[simp]
theorem fconcat₂_last {α₁ : Fin n → A} {α₂ : Fin n → B} {β₁ : A} {β₂ : B}
    (v : (i : Fin n) → F₂ (α₁ i) (α₂ i)) (a : F₂ β₁ β₂) :
    fconcat₂ (F := F₂) v a (last n) = cast (by simp [vconcat_last]) a

theorem generator_on_curve : let (x, y) := generator
  y^2 = x^3 + 3

theorem hconcat_init_self {α : Fin n.succ → Sort u} (v : (i : Fin (n + 1)) → α i) :
    True

lemma extract_eq_extract : transcript⟦start:stop⟧ = transcript.extract start stop h1 h2

@[simp]
theorem cast_rbrKnowledgeSoundness (ε : pSpec₁.ChallengeIdx → ℝ≥0)
    (hRbrKs : V.rbrKnowledgeSoundness init impl relIn relOut ε) :
    (V.cast hn hSpec).rbrKnowledgeSoundness init impl relIn relOut
      (ε ∘ (ChallengeIdx.cast hn.symm (cast_symm hSpec)))

@[simp]
lemma solutionToE_zero_eq_C {v : Fin (2 * 0 + k) → F} :
  solutionToE 0 k v = C (1 : F)

theorem snoc_left_injective : Injective (Finsupp.snoc · y : (Fin n →₀ M) → Fin (n + 1) →₀ M)

List.le_sum_of_mem in Mathlib.Algebra.Order.BigOperators.Group.List

@[simp]
theorem vcons_fin_zero (a : α) (v : Fin 0 → α) : a ::ᵛ v = fun i => match i with

theorem liftContext_runWithLog
    {lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {outerStmtIn : OuterStmtIn} {outerWitIn : OuterWitIn}
    {R : Reduction oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec} :
      (R.liftContext lens).runWithLog outerStmtIn outerWitIn = do
        let ⟨⟨⟨fullTranscript, innerCtxOut⟩, verInnerStmtOut⟩, queryLog⟩ ←
          R.runWithLog.uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨⟨⟨fullTranscript, lens.lift (outerStmtIn, outerWitIn) innerCtxOut⟩,
                lens.stmt.lift outerStmtIn verInnerStmtOut⟩, queryLog⟩

Nat.zero_add in Init.Data.Nat.Basic

theorem sumcheck_roundPoly_degreeLE (i : Fin (n + 1)) {challenges : Fin i.castSucc → R}
    {poly : R[X Fin (n + 1)]} (hp : poly ∈ R⦃≤ deg⦄[X Fin (n + 1)]) :
      ∑ x ∈ (univ.map D) ^ᶠ (n - i), poly ⸨X ⦃i⦄, challenges, x⸩'
        (by simp; omega) ∈ R⦃≤ deg⦄[X]

@[simp]
lemma seqCompose_toReduction {m : ℕ}
    (Stmt : Fin (m + 1) → Type)
    {ιₛ : Fin (m + 1) → Type} (OStmt : (i : Fin (m + 1)) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    (Wit : Fin (m + 1) → Type)
    {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (R : (i : Fin m) →
      OracleReduction oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Wit i.castSucc)
        (Stmt i.succ) (OStmt i.succ) (Wit i.succ) (pSpec i)) :
    (seqCompose Stmt OStmt Wit R).toReduction =
      Reduction.seqCompose (fun i => Stmt i × (∀ j, OStmt i j)) Wit
        (fun i => (R i).toReduction)

lemma duplexSpongeToFSGameStatDist
    (maliciousProver : OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      (StmtIn × pSpec.Messages))
    (tₒ : ι → ℕ) (tₕ tₚ tₚᵢ : ℕ)
    -- TODO: state query bound only for subset of the oracles
    (hQuery : IsQueryBound maliciousProver (tₒ ⊕ᵥ (tₕ ⊕ᵥ (tₚ ⊕ᵥ tₚᵢ)))) : True

lemma Fin.lt_succ' (a : Fin r) (h_a_add_1 : a + 1 < r) : a < a + 1

@[simp]
theorem rdrop_eq_take (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    rdrop m h v = take (n - m) (by omega) v

theorem reduction_completeness {ε : ℝ≥0}
    (hRel : ∀ stmtIn witIn, (stmtIn, witIn) ∈ relIn →
      [fun ⟨stmtOut, witOut⟩ => (stmtOut, witOut) ∈ relOut|do
        (simulateQ impl <| combineMap mapStmt mapWit ⟨stmtIn, witIn⟩).run' (← init)] ≥ 1 - ε) :
    Reduction.completeness init impl relIn relOut (reduction mapStmt mapWit) ε

@[simp]
theorem simulateQ_bind_fst (oa : OracleComp spec α) (f : α → OracleComp spec β) :
    (do let a ← (simulateQ loggingOracle oa).run; f a.1) = oa >>= f

lemma approximate_solution_is_exact_solution_coeffs
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : ∀ t ≥ k,
  α' 
    x₀ 
    (R k δ x₀ h_gs) 
    (irreducible_H k h_gs) 
    t 
  = 
  (0 : AppendixA.𝕃 (H k δ x₀ h_gs))

@[simp]
lemma degree_polynomialOfCoeffs_deg_lt_deg :
  (polynomialOfCoeffs coeffs).degree < deg

@[simp]
theorem sum_degreeLT_monomial_eq_subtype {n : ℕ} (p : L⦃< n⦄[X]) :
  (⟨p.val.sum (fun n a => Polynomial.monomial n a), by
    -- degree of sum is degree of p.val, which is < n
    rw [Polynomial.sum_monomial_eq p.val]
    exact p.property
  ⟩ : L⦃< n⦄[X]) = p

theorem hconcat_right_injective {α : Fin n → Sort u} {β : Sort u} (v : (i : Fin n) → α i) :
    Function.Injective (hconcat v : β → (i : Fin (n + 1)) → vconcat α β i)

@[simp]
theorem cast_run (stmt : StmtIn) (transcript : FullTranscript pSpec₁) :
    V.run stmt transcript = (V.cast hn hSpec).run stmt (transcript.cast hn hSpec)

theorem binaryTowerAlgebra_apply_assoc (l mid r : ℕ) (h_l_le_mid : l ≤ mid) (h_mid_le_r : mid ≤ r) :
    ∀ x : BTField l,
    (@binaryAlgebraTower (l:=l) (r:=r) (h_le:=by
      exact Nat.le_trans h_l_le_mid h_mid_le_r)).algebraMap x =
    (@binaryAlgebraTower (l:=mid) (r:=r) (h_le:=h_mid_le_r)).algebraMap
      ((@binaryAlgebraTower (l:=l) (r:=mid) (h_le:=h_l_le_mid)).algebraMap x)

@[simp]
lemma not_P_to_V_eq_V_to_P {x : Direction} (h : x ≠ .V_to_P) : x = .P_to_V

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

theorem Iic_castSucc (i : Fin n) : Iic (castSucc i) = (Iic i).map Fin.castSuccEmb

lemma lifted_trace_map_eval_at_roots_prev_BTField
  {curBTField : Type*} [Field curBTField]
  (u : curBTField) (t1 : curBTField) -- here t1 is already lifted to curBTField
  (k : ℕ)
  (sumZeroIffEq : ∀ (x y : curBTField), x + y = 0 ↔ x = y)
  (u_plus_inv_eq_t1 : u + u⁻¹ = t1)
  (galois_automorphism : u^(2^(2^k)) = u⁻¹ ∧ (u⁻¹)^(2^(2^k)) = u)
  (trace_map_at_prev_root : ∑ i ∈ Finset.range (2 ^ k), t1 ^ (2 ^ i) = 1) :
  ∑ i ∈ Finset.range (2 ^ (k+1)), u ^ (2 ^ i) = 1

theorem mul_two_eq_add {a : CNat 50} : a * 2 = a + a

@[simp]
lemma degreeX_monomialXY {n m : ℕ} {a : F} (ha : a ≠ 0) :
    degreeX (monomialXY n m a) = n

@[simp]
theorem dconcat_castSucc {motive : Fin (n + 1) → Sort u} (v : (i : Fin n) → motive (castSucc i))
    (a : motive (last n)) (i : Fin n) : (v :+ᵈ⟨motive⟩ a) (castSucc i) = v i

theorem dotProduct_eq_root_dotProduct (a b : Vector R n) :
    dotProduct a b = _root_.dotProduct a.get b.get

@[simp]
theorem vappend_left (u : Fin m → α) (v : Fin n → α) (i : Fin m) :
    vappend u v (castAdd n i) = u i

lemma Fin.le_iff_lt_succ (a b : Fin r) (h_b : b + 1 < r) : a ≤ b ↔ a < b + 1

@[simp]
theorem reduction_completeness (h : init.neverFails) :
    (reduction oSpec Statement Witness).perfectCompleteness init impl relIn (toRelOut relIn)

lemma irreducible_H
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
  Irreducible (H k δ x₀ h_gs)

lemma pow_2_pow_i_mem_Di_of_mem_D {F : Type} [NonBinaryField F] [Finite F] {D : Subgroup Fˣ}
  [DIsCyclicC : IsCyclicWithGen ↥D] {x : Fˣ} :
  ∀ {a : Fˣ} (i : ℕ),
    a ∈ evalDomain D x 0 → a ^ (2 ^ i) ∈ evalDomain D x i

theorem eq_of_degreeOf_lt_card_of_eval_eq {p q : R[X σ]} (S : σ → Finset R)
    (hDegree : ∀ i, p.degreeOf i < #(S i))
    (hEval : ∀ x ∈ piFinset fun i ↦ S i, eval x p = eval x q) : p = q

@[simp]
theorem LeafData.get_internal_ofRight {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (idxRight : SkeletonLeafIndex s_right) :
    (LeafData.internal left right).get (SkeletonLeafIndex.ofRight idxRight) =
      right.get idxRight

theorem prime_47 : Nat.Prime 47

@[simp]
theorem oracleVerifier_rbrKnowledgeSoundness :
    (oracleVerifier oSpec Statement OStatement).rbrKnowledgeSoundness init impl rel rel 0

@[simp, grind _=_]
lemma degreeX_mul [IsDomain F] (f g : F[X][Y]) (hf : f ≠ 0) (hg : g ≠ 0) :
  degreeX (f * g) = degreeX f + degreeX g

lemma isPrimitiveRoot_twoAdicGenerator (bits : Fin (twoAdicity + 1)) :
    IsPrimitiveRoot (twoAdicGenerators[bits]) (2 ^ (bits : Nat))

@[simp]
theorem fflatten₂_one {A : Sort u} {B : Sort v} {F : A → B → Sort w} {n : Fin 1 → ℕ}
    {α : (i : Fin 1) → (j : Fin (n i)) → A}
    {β : (i : Fin 1) → (j : Fin (n i)) → B}
    {v : (i : Fin 1) → (j : Fin (n i)) → F (α i j) (β i j)} :
    fflatten₂ v = v 0

theorem snoc_ne_zero_of_right (h : y ≠ 0) : snoc s y ≠ 0

Nat.lt_succ_of_lt in Init.Data.Nat.Basic

lemma algebra_adjacent_tower_def (l : ℕ) :
  (algebra_adjacent_tower l) = (canonicalEmbedding l).toAlgebra

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

@[simp]
lemma natDegree_solutionToQ :
  (solutionToQ e k v).natDegree ≤ e + k - 1

@[simp]
lemma getTypes_cons (x : Σ α : Type u, α) (xs : HList) :
    getTypes (x :: xs) = x.1 :: xs.getTypes

@[simp, grind] lemma fin_chunkSize_lt_N (arrSize : Nat) (i : Fin (min arrSize SpongeSize.R)) :
    i < SpongeSize.N

theorem completeness_relOut_mono {ε : ℝ≥0} {relOut' : Set (StmtOut × WitOut)}
    (hrelOut : relOut ⊆ relOut') :
      completeness init impl relIn relOut reduction ε →
        completeness init impl relIn relOut' reduction ε

lemma polynomialAlgEquiv_unique (f : P ≃ₐ[R] R[X]) : f = polynomialAlgEquiv

private lemma johnson_condition_strong_implies_n_pos
  (h_johnson : JohnsonConditionStrong B v)
  :
  0 < n

@[simp]
theorem LeafData.map_internal {α β} {s_left s_right : Skeleton}
    (f : α → β) (left : LeafData α s_left) (right : LeafData α s_right) :
    (LeafData.internal left right).map f =
      LeafData.internal (left.map f) (right.map f)

@[simp]
theorem Ici_succ (i : Fin n) : Ici i.succ = (Ici i).map (Fin.succEmb _)

theorem seqCompose_rbrKnowledgeSoundness
    (rel : ∀ i, Set (Stmt i × Wit i))
    (V : ∀ i, Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i))
    (rbrKnowledgeError : ∀ i, (pSpec i).ChallengeIdx → ℝ≥0)
    (h : ∀ i, (V i).rbrKnowledgeSoundness init impl
      (rel i.castSucc) (rel i.succ) (rbrKnowledgeError i)) :
      (Verifier.seqCompose Stmt V).rbrKnowledgeSoundness init impl (rel 0) (rel (Fin.last m))
        (fun combinedIdx =>
          letI ij := seqComposeChallengeIdxToSigma combinedIdx
          rbrKnowledgeError ij.1 ij.2)

theorem vcons_right_injective (a : α) :
    Function.Injective (vcons a : (Fin n → α) → Fin (n + 1) → α)

theorem add_zero : @add α zero = @id (ChurchNat α)

lemma towerRingHomForwardMap_join {k : ℕ} (h_pos : k > 0) (hi lo : ConcreteBTField (k - 1)) :
  towerRingHomForwardMap (k:=k) (《 hi, lo 》) =
    BinaryTower.join_via_add_smul (k:=k) (h_pos:=by omega)
      (hi_btf := towerRingHomForwardMap (k:=k-1) hi)
      (lo_btf := towerRingHomForwardMap (k:=k-1) lo)

lemma getBit_of_highBits {n: ℕ} (numLowBits : ℕ) : ∀ k, getBit k (getHighBits numLowBits n) =
    if k < numLowBits then 0 else getBit (k) (n)

lemma W_add_U_invariant
  (i : Fin r) :
  ∀ x : L, ∀ y ∈ U 𝔽q β i, (W 𝔽q β i).eval (x + y) = (W 𝔽q β i).eval x

theorem BitVec.eq_mp_eq_dcast {w w2 : ℕ} (x : BitVec w) (h_width_eq : w = w2)
  (h_bitvec_eq : BitVec w = BitVec w2 := by rw [h_width_eq]) :
  Eq.mp (h:=h_bitvec_eq) (a:=x) = dcast (h_width_eq) (x)

lemma le_sInf_of_LB {S : Set ℕ} (hne : S.Nonempty) {i : ℕ}
    (hLB : ∀ s ∈ S, i ≤ s) : i ≤ sInf S

@[simp]
theorem append_fst (T₁ : FullTranscript pSpec₁) (T₂ : FullTranscript pSpec₂) :
    (T₁ ++ₜ T₂).fst = T₁

private lemma errors_are_roots_of_E {i : Fin n}
  (h : f i ≠ p.eval (ωs i)) : (E ωs f p e).eval (ωs i) = 0

@[simp]
theorem hcons_zero {β : Fin n → Sort u} (a : α) (b : (i : Fin n) → β i) :
    hcons a b 0 = cast (vcons_zero α β).symm a

lemma towerAlgebraMap_succ (l r : ℕ) (h_le : l ≤ r) :
  towerAlgebraMap (l:=l) (r:=r+1) (h_le:=by omega) =
  (towerAlgebraMap (l:=r) (r:=r+1) (h_le:=by omega)).comp
  (towerAlgebraMap (l:=l) (r:=r) (h_le:=by omega))

@[simp]
theorem ConcreteBTField.RingHom_eq_of_source_eq (k n m : ℕ) (h_eq : k = n) :
    (ConcreteBTField k →+* ConcreteBTField m)
    = (ConcreteBTField n →+* ConcreteBTField m)

lemma trim_add_trim [LawfulBEq R] (p q : UniPoly R) : p.trim + q = p + q

theorem one_le_sub_consecutive_two_pow (n : ℕ): 1 ≤ 2^(n+1) - 2^n

theorem singleEqPolynomial_symm (r : R) (s : R) :
    (singleEqPolynomial r (C s) : MvPolynomial σ R) = singleEqPolynomial s (C r)

lemma ConcreteBTFieldAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
    @ConcreteBTFieldAlgebra (l:=l) (r:=r) (h_le:=h_le)
    = (concreteTowerAlgebraMap l r h_le).toAlgebra

theorem two_eq_zero_in_char2_field {F : Type*} [Field F]
  (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y) : (2 : F) = 0

theorem and_highBits_lowBits_eq_zero {n : ℕ} (numLowBits : ℕ) :
    getHighBits numLowBits n &&& getLowBits numLowBits n = 0

theorem SkeletonNodeIndex.parent_of_depth_zero {s : Skeleton}
    (idx : SkeletonNodeIndex s) (h : idx.depth = 0) :
    parent idx = none

congrArg in Init.Prelude

@[simp]
theorem induction_one {motive : Fin 2 → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin 1, motive i.castSucc → motive i.succ} :
      induction (motive := motive) zero succ (last 1) = succ 0 zero

lemma add_zero {k : ℕ} (a : ConcreteBTField k) : a + 0 = a

omit [SelectableType R] in
@[simp]
lemma oracleReduction_verifier_eq_verifier {i : Fin n} :
    (oracleReduction R n deg D oSpec i).verifier = oracleVerifier R n deg D oSpec i

theorem frobenius_identity_in_ground_field
  [Fact (Nat.Prime (ringChar Fq))] (f g : Fq[X]) :
    (f + g)^(Fintype.card Fq) = f^(Fintype.card Fq) + g^(Fintype.card Fq)

lemma getMiddleBits_lt_two_pow {n offset len : ℕ} :
  getMiddleBits offset len n < 2 ^ len

lemma exists_a_set_and_a_matching_polynomial
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
  ∃ S', ∃ (h_sub : S' ⊆ coeffs_of_close_proximity k ωs δ u₀ u₁), ∃ P : F[Z][X],
    #S' > #(coeffs_of_close_proximity k ωs δ u₀ u₁) / (2 * D_Y Q) ∧
    ∀ z : S', Pz (h_sub z.2) = P.map (Polynomial.evalRingHom z.1) ∧
    P.natDegree ≤ k ∧
    Bivariate.degreeX P ≤ 1

theorem induction_heq {n n' : ℕ} {motive : Fin (n + 1) → Sort u} {motive' : Fin (n' + 1) → Sort u}
    {zero : motive 0} {zero' : motive' 0}
    {succ : ∀ i : Fin n, motive i.castSucc → motive i.succ}
    {succ' : ∀ i : Fin n', motive' i.castSucc → motive' i.succ}
    {i : Fin (n + 1)} {i' : Fin (n' + 1)}
    (hn : n = n') (hmotive : HEq motive motive') (hzero : HEq zero zero')
    (hsucc : HEq succ succ') (hi : HEq i i') :
      HEq (induction (motive := motive) zero succ i)
        (induction (motive := motive') zero' succ' i')

@[simp]
theorem dcast_eq : dcast (Eq.refl a) b = b

lemma ξ_regular (x₀ : F) (R : F[X][X][Y]) (H : F[X][Y]) [H_irreducible : Fact (Irreducible H)] :
  ∃ pre : 𝒪 H,
    let d := R.natDegree
    let W : 𝕃 H := liftToFunctionField (H.leadingCoeff);
    embeddingOf𝒪Into𝕃 _ pre = W ^ (d - 2) * ζ R x₀ H

theorem hcons_eq_hcons_iff {β : Fin n → Sort u} (a₁ a₂ : α) (v₁ v₂ : (i : Fin n) → β i) :
    hcons a₁ v₁ = hcons a₂ v₂ ↔ a₁ = a₂ ∧ v₁ = v₂

List.length_drop in Init.Data.List.TakeDrop

@[simp]
theorem cast_id : Transcript.cast rfl rfl rfl = (id : pSpec₁.Transcript k → _)

theorem evalNormalizedWAt_eq_normalizedW (i : Fin r) (x : L) :
  evalNormalizedWAt (β := β) (ℓ := ℓ) (R_rate := R_rate) (i := i) x
    = (normalizedW (𝔽q := 𝔽q) (β := β) (i := i)).eval x

theorem split_of_join {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
    (hi_btf lo_btf : ConcreteBTField (k - 1))
    (h_join : x = 《hi_btf, lo_btf》) :
    (hi_btf, lo_btf) = split h_pos x

@[csimp]
theorem dconcat_eq_snoc : @dconcat = @snoc

@[simp]
lemma solutionToQ_zero {v : Fin (2 * 0 + 0) → F} :
  solutionToQ (F := F) 0 0 v = 0

theorem split_zero {k : ℕ} (h_pos : k > 0) : split h_pos zero = (zero, zero)

@[simp] lemma ofMvPolynomialAlgHom_X (s : σ) :
    ofMvPolynomialAlgHom (MvPolynomial.X s : MvPolynomial σ R) = (X s : P)

lemma linsolve_to_BerlekampWelch_condition {e k : ℕ}
  [NeZero n]
  {ωs f : Fin n → F}
  {v : Fin (2 * e + k) → F}
  (h_sol : linsolve (BerlekampWelchMatrix e k ωs f) (Rhs e ωs f) = some v)
  : BerlekampWelchCondition e k ωs f (solutionToE e k v) (solutionToQ e k v)

@[simp, grind _=_]
theorem monomialXY_pow {n m k : ℕ} {a : F} :
  monomialXY n m a ^ k = monomialXY (n * k) (m * k) (a ^ k)

theorem eqPolynomial_expanded (r : σ → R) :
    eqPolynomial r = ∏ i : σ, ((1 - C (r i)) * (1 - X i) + C (r i) * X i)

theorem append_right' {u : Fin m → α} {v : Fin n → α} {i : Fin n}
    (j : Fin (m + n)) (h : j = natAdd m i) : append u v j = v i

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

theorem traceMapProperty_of_quadratic_extension
  (F_prev : Type*) [Field F_prev] [Fintype F_prev] (k : ℕ)
  (fintypeCardPrev : Fintype.card F_prev = 2 ^ (2 ^ k))
  (t1 : F_prev) [instNeZero_t1 : NeZero t1]
  {F_cur : Type*} [Field F_cur] (u : F_cur) [instNeZero_u : NeZero u]
  [Algebra F_prev F_cur]
  (h_rel : SpecialElementRelation (t1 := t1) (u := u))
  (prev_trace_map : TraceMapProperty F_prev t1 (k))
  (sumZeroIffEq : ∀ (x y : F_cur), x + y = 0 ↔ x = y)
  : TraceMapProperty F_cur u (k + 1)

theorem inverse_is_root_of_prevPoly
    {prevBTField : Type*} [Field prevBTField]
    {curBTField : Type*} [Field curBTField]
    (of_prev : prevBTField →+* curBTField)
    (u : curBTField) (t1 : prevBTField)
    (specialElementNeZero : u ≠ 0)
    (eval_prevPoly_at_root : u ^ 2 + of_prev t1 * u + 1 = 0)
    (h_eval : ∀ (x : curBTField),
      eval₂ of_prev x (X ^ 2 + (C t1 * X + 1)) = x ^ 2 + of_prev t1 * x + 1) :
    eval₂ of_prev u⁻¹ (X ^ 2 + (C t1 * X + 1)) = 0

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma ℓ_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r}
    : ℓ < r

private lemma k_and_e [Zero F]
  (h_n : n ≠ 0)
  (h_B : B.card ≠ 0)
  :
  k B = B.card * (n - e B 0) / n

theorem two_le_two_pow_n_plus_1 (n : ℕ) : 2 ≤ 2 ^ (n + 1)

theorem trim_equiv [LawfulBEq R] (p : UniPoly R) : equiv p.trim p

lemma neverFails_map_iff' (oa : OracleComp spec α) (f : α → β) :
    neverFails (f <$> oa) ↔ neverFails oa

@[simp]
theorem FullData.ofFun_get {α} {s} (tree : FullData α s) :
    FullData.ofFun s (fun idx => tree.get idx) = tree

theorem is_multilinear_eq_iff_eq_evals_zeroOne (p : MvPolynomial σ R) (q : MvPolynomial σ R)
    (hp : p ∈ R⦃≤ 1⦄[X σ]) (hq : q ∈ R⦃≤ 1⦄[X σ]) :
    p = q ↔ p.toEvalsZeroOne = q.toEvalsZeroOne

lemma rank_nonsquare_eq_deg_of_ι_le (inj : Function.Injective α) (h : m ≤ n) :
  (Vandermonde.nonsquare (ι' := n) α).rank = m

@[simp]
theorem cast_idx_symm {i : ChallengeIdx pSpec₂} :
    pSpec₁.Challenge (i.cast hn.symm (cast_symm hSpec)) = pSpec₂.Challenge i

omit [Fintype F] in
private lemma hamming_dist_eq_sum {x y : Fin n → F} :
  Δ₀(x, y) = ∑ i, if x i = y i then 0 else 1

lemma decoded_polynomial_lt_deg (c : ReedSolomon.code domain deg) :
  decode c ∈ (degreeLT F deg : Submodule F F[X])

theorem add_assoc [LawfulBEq R] : p + q + r = p + (q + r)

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 singleEqPolynomial_zeroOne (r : Fin 2) (x : MvPolynomial σ R) :
    singleEqPolynomial (r : R) x = if r = 0 then 1 - x else x

private lemma roots_of_unity_lem {s : Fin (k + 1) → ℕ+} {i : Fin (k + 1)}
    (k_le_n : (∑ j', (s j').1) ≤ n) :
  (∑ j' ∈ finRangeTo i.1, (s j').1) ≤ n - (s i).1

@[simp] theorem one_mul {a : AssocNat} : 1 * a = a

protected lemma elocPoly_congr {ωs' f' : ℕ → F}
  (h₁ : ∀ {m}, m < n → ωs m = ωs' m) (h₂ : ∀ {m}, m < n → f m = f' m) :
  ElocPoly n ωs f = ElocPoly n ωs' f'

theorem seqCompose_soundness
    (lang : (i : Fin (m + 1)) → Set (Stmt i))
    (V : (i : Fin m) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i))
    (soundnessError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).soundness init impl (lang i.castSucc) (lang i.succ) (soundnessError i)) :
      (Verifier.seqCompose Stmt V).soundness init impl (lang 0) (lang (Fin.last m))
        (∑ i, soundnessError i)

theorem vconcat_vcons_eq_vcons_vconcat (a : α) (v : Fin n → α) (b : α) :
    vconcat (a ::ᵛ v) b = a ::ᵛ (vconcat v b)

lemma natDegree_definingPoly {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).natDegree = 2

theorem hcons_happend_comm {β : Fin m → Sort u} {γ : Fin n → Sort u}
    (a : α) (u : (i : Fin m) → β i) (v : (i : Fin n) → γ i) :
    True

omit [DecidableEq L] [Fintype 𝔽q] h_Fq_char_prime hβ_lin_indep in
lemma normalizedW₀_eq_1_div_β₀ : normalizedW (𝔽q := 𝔽q) (β := β) (i :=0) = X * C (1 / (β 0))

lemma wt_eq_zero_iff [Zero F] {v : ι → F} :
  wt v = 0 ↔ Fintype.card ι = 0 ∨ ∀ i, v i = 0

@[to_additive vsum_eq_univ_sum]
lemma vprod_eq_univ_prod [CommMonoid α] {a : Fin n → α} : vprod a = ∏ i, a i

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

theorem FullData.toLeafData_leftSubtree {α} {s_left s_right : Skeleton}
    (tree : FullData α (Skeleton.internal s_left s_right)) :
    tree.toLeafData.leftSubtree =
      tree.leftSubtree.toLeafData

theorem frobenius_identity_in_algebra [Fact (Nat.Prime (ringChar Fq))]
  (f g : L[X]) : (f + g)^(Fintype.card Fq) = f^(Fintype.card Fq) + g^(Fintype.card Fq)

theorem completeness_relIn_mono {ε : ℝ≥0} {relIn' : Set (StmtIn × WitIn)}
    (hrelIn : relIn' ⊆ relIn) :
      completeness init impl relIn relOut reduction ε →
        completeness init impl relIn' relOut reduction ε

theorem rbrKnowledgeSoundness_implies_knowledgeSoundness
    (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) :
      rbrKnowledgeSoundness init impl relIn relOut verifier rbrKnowledgeError →
        knowledgeSoundness init impl relIn relOut verifier (∑ i, rbrKnowledgeError i)

lemma rounds_sub_steps_lt : ℓ - ϑ < ℓ :=
  Nat.sub_lt (pos_of_neZero ℓ) (folding_steps_pos)

lemma ϑ_sub_one_le_self : ϑ - 1 < ϑ

lemma exists_unique_bivariate
  (qPoly : Polynomial F) (hdeg_q_min : qPoly.natDegree > 0)
  (hdeg_q_max : qPoly.natDegree < Fintype.card F) (fPoly : Polynomial F) :
    -- Q ∈ 𝔽[X,Y]
    ∃! Q : MvPolynomial (Fin 2) F,
      -- deg_x(Q) = Floor ( deg(fPoly) / deg(qPoly) )
      -- This is natural number division towards zero, which is floor
      (MvPolynomial.degreeOf 0 Q = (Polynomial.natDegree fPoly) / (Polynomial.natDegree qPoly)) ∧
      -- deg_y(Q) < deg (q)
      (MvPolynomial.degreeOf 1 Q < Polynomial.natDegree qPoly) ∧
      -- point‑wise equality on F: f(z) = Q(q(z), z)
      (∀ z : F, Polynomial.eval z fPoly = evalBivar Q (Polynomial.eval z qPoly) z) ∧
      (∀ t : ℕ, fPoly.natDegree < t * qPoly.natDegree → MvPolynomial.degreeOf 0 Q < t)

lemma e_leq_dist_over_3 [DecidableEq F] {deg : ℕ} {α : ι ↪ F} {e : ℕ} {u v : ι → F}
  (he : (e : ℚ) < (Code.minDist (RScodeSet α deg) : ℚ) / 3) :
  ∀ x ∈ Affine.line u v, distFromCode x (ReedSolomon.code α deg) ≤ e
  ∨ (numberOfClosePts u v deg α e) ≤ Code.minDist (RScodeSet α deg)

theorem cast_idx {i : MessageIdx pSpec₁} :
    pSpec₂.Message (i.cast hn hSpec) = pSpec₁.Message i

omit hF₂ in
theorem kernel_W_eq_U (i : Fin r) :
  LinearMap.ker (polyEvalLinearMap (W 𝔽q β i)
    (W_is_additive 𝔽q β i)) = U 𝔽q β i

@[simp]
lemma seqCompose_toVerifier {m : ℕ}
    (Stmt : Fin (m + 1) → Type)
    {ιₛ : Fin (m + 1) → Type} (OStmt : (i : Fin (m + 1)) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (V : (i : Fin m) →
      OracleVerifier oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Stmt i.succ) (OStmt i.succ)
        (pSpec i)) :
    (seqCompose Stmt OStmt V).toVerifier =
      Verifier.seqCompose (fun i => Stmt i × (∀ j, OStmt i j)) (fun i => (V i).toVerifier)

@[simp]
theorem take_append_left :
    (pSpec₁ ++ₚ pSpec₂).take m (Nat.le_add_right m n) = pSpec₁

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

omit [NeZero ℓ] in
lemma fin_ℓ_lt_ℓ_add_one (i : Fin ℓ) : i < ℓ + 1

theorem happend_assoc {α : Fin m → Sort u} {β : Fin n → Sort u} {p : ℕ} {γ : Fin p → Sort u}
    (u : (i : Fin m) → α i) (v : (i : Fin n) → β i) (w : (i : Fin p) → γ i) :
    happend (happend u v) w =
      fun i => cast (by simp [vappend_assoc])
        (happend u (happend v w) (i.cast (by omega)))

theorem ofFn_drop_get {α : Type*} {m : ℕ} (l : List α) (h : m ≤ l.length) :
    List.ofFn (drop m h l.get) = l.drop m

lemma folding_preserves_listdecoding_base
  {S : Finset ι} {k m : ℕ} (hm : 1 ≤ m) {φ : ι ↪ F} [Smooth φ] {δ : ℝ≥0}
  {S_0 : Finset (indexPowT S φ 0)} {S_1 : Finset (indexPowT S φ 1)}
  {φ_0 : (indexPowT S φ 0) ↪ F} {φ_1 : (indexPowT S φ 1) ↪ F}
  [∀ i : ℕ, Fintype (indexPowT S φ i)] [∀ i : ℕ, DecidableEq (indexPowT S φ i)]
  [Smooth φ_0] [Smooth φ_1]
  [h : ∀ {f : (indexPowT S φ 0) → F}, DecidableBlockDisagreement 0 k f S_0 φ_0]
  [h : ∀ {f : (indexPowT S φ 1) → F}, DecidableBlockDisagreement 1 k f S_1 φ_1]
  [∀ i : ℕ, Neg (indexPowT S φ i)]
  {C : Set ((indexPowT S φ 0) → F)} (hcode : C = smoothCode φ_0 m)
  (C' : Set ((indexPowT S φ 1) → F)) (hcode' : C' = smoothCode φ_1 (m-1))
  {BStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0}
  {errStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0 → ℝ≥0} :
    Pr_{let α ←$ᵖ F}[ ∀ { f : (indexPowT S φ 0) → F} (hδLe: 0 < δ ∧ δ < 1 - (BStar C' 2)),
               let listBlock : Set ((indexPowT S φ 0) → F) := Λᵣ(0, k, f, S_0, C, hcode, δ)
               let vec_α : Fin 1 → F := (fun _ : Fin 1 => α)
               let foldSet := fold_k_set listBlock vec_α hm
               let fold := fold_k f vec_α hm
               let listBlock' : Set ((indexPowT S φ 1) → F) := Λᵣ(1, k, fold, S_1, C', hcode', δ)
               foldSet ≠ listBlock'
             ] < errStar C' 2 δ

theorem fcons_left_injective {β : Fin n → A} (b : (i : Fin n) → F (β i)) :
    Function.Injective (fun (a : F α) => fcons a b)

@[simp]
lemma elocPolyF_deg {ωs f : Fin n → F} : (ElocPolyF ωs f p).natDegree = Δ₀(f, p.eval ∘ ωs)

lemma add_equiv_raw [LawfulBEq R] (p q : UniPoly R) : Trim.equiv (p.add q) (p.add_raw q)

theorem basisVectors_linear_independent (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
    LinearIndependent L (basisVectors 𝔽q β ℓ h_ℓ)

theorem leftpad_toList {a : Array α} {n : Nat} {unit : α} :
    a.leftpad n unit = mk (a.toList.leftpad n unit)

@[simp]
theorem seqCompose_succ_eq_append {m : ℕ} {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = append (pSpec 0) (seqCompose (fun i => pSpec (Fin.succ i)))

theorem prime_5 : Nat.Prime 5

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

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))

lemma blockRelDistance_eq_relHammingDist_of_k_eq_i -- Renamed for clarity
  (i : ℕ) {S : Finset ι} {φ : ι ↪ F}
  [DecidableEq F] [DecidableEq ι] [Smooth φ]
  -- The Fintype instance is now declared before it is needed by `hS'`.
  [h_fintype : ∀ i : ℕ, Fintype (indexPowT S φ i)]
  (f g : (indexPowT S φ i) → F) (S' : Finset (indexPowT S φ i))
  (hS' : S' = Finset.univ) -- This now works.
  (φ' : (indexPowT S φ i) ↪ F)
  [h_dec : DecidableBlockDisagreement i i f S' φ'] [DecidableEq (indexPowT S φ i)] :
  Δᵣ(i, i, f, S', φ', g) = δᵣ(f, g)

lemma Z_ne_zero {k : ℕ} : Z k ≠ zero

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

@[simp]
theorem cast_rbrKnowledgeSoundness (ε : pSpec₁.ChallengeIdx → ℝ≥0)
    (hRbrKs : V.rbrKnowledgeSoundness init impl relIn relOut ε) :
    (V.cast hn hSpec hOₘ).rbrKnowledgeSoundness init impl relIn relOut
      (ε ∘ (ChallengeIdx.cast hn.symm (cast_symm hSpec)))

theorem coeff_eq_getElem_of_lt [LawfulBEq R] {p : UniPoly R} {i} (hi : i < p.size) :
  p.trim.coeff i = p[i]

@[simp]
theorem dappend_left {motive : Fin (m + n) → Sort u} (u : (i : Fin m) → motive (castAdd n i))
    (v : (i : Fin n) → motive (natAdd m i)) (i : Fin m) :
    dappend (motive := motive) u v (castAdd n i) = u i

theorem vcons_inj (a b : α) (v w : Fin n → α) : a ::ᵛ v = b ::ᵛ w ↔ a = b ∧ v = w

theorem ext_hcons {β : Fin n → Sort u} (a₁ a₂ : α) (v₁ v₂ : (i : Fin n) → β i) :
    hcons a₁ v₁ = hcons a₂ v₂ ↔ a₁ = a₂ ∧ v₁ = v₂

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

Nat.lt_add_one in Init.Prelude

@[simp]
lemma invFun_toFun (f : F) : inst.equiv.invFun (inst.equiv.toFun f) = f

lemma getBit_of_shiftRight {n p : ℕ}:
  ∀ k, getBit k (n >>> p) = getBit (k+p) n

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

private lemma leadingCoeff_E'
  (h_dist : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  : (E ωs f p e).coeff e = 1

theorem add_coeff {p q : UniPoly Q} {i : ℕ} (hi : i < (add_raw p q).size) :
  (add_raw p q)[i] = p.coeff i + q.coeff i

lemma getBit_of_sub_two_pow_of_bit_1 {n i j: ℕ} (h_getBit_eq_1: getBit i n = 1) :
  getBit j (n - 2^i) = (if j = i then 0 else getBit j n)

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

theorem add_succ (m n : ChurchNat α) : add (succ m) n = succ (add m n)

theorem BitVec.extractLsb_eq_and_pow_2_minus_1_ofNat {n num_bits : Nat}
  (h_num_bits : num_bits > 0) (x : BitVec n) :
  BitVec.extractLsb (hi:= num_bits - 1) (lo := 0) x =
    BitVec.ofNat (num_bits - 1 - 0 + 1) (x.toNat &&& (2 ^ num_bits - 1))

theorem ZMod.blub :
    ∀ {n q c : ℕ} (a : ZMod n), (decide (n ≥ 2) = true) → (decide (c < n) = true) →
      (decide (c ≠ 1) = true) → IsNat (a ^ ((n - 1) / q)) c → a ^ ((n - 1) / q) ≠ 1

theorem liftContext_perfectCompleteness
    (h : R.perfectCompleteness init impl innerRelIn innerRelOut) :
      (R.liftContext lens).perfectCompleteness init impl outerRelIn outerRelOut

lemma irreducibleHTildeOfIrreducible {H : Polynomial (Polynomial F)} :
    (Irreducible H → Irreducible (H_tilde H))

theorem linsolve_none {A : Matrix (Fin n) (Fin m) F} {b : Fin n → F}
  (h : linsolve A b = none)
  : ¬∃ x, A.mulVec x = b

lemma towerRingHomBackwardMap_forwardMap_eq (k : ℕ) (x : ConcreteBTField k) :
  towerRingHomBackwardMap (k:=k) (towerRingHomForwardMap (k:=k) x) = x

lemma bIdx_succ_mul_ϑ_lt_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) :
    (↑bIdx + 1) * ϑ < ℓ + 1

lemma getBit_of_multiple_of_power_of_two {n p : ℕ}: ∀ k,
  getBit (k) (2^p * n) = if k < p then 0 else getBit (k-p) n

@[simp]
theorem splitSum_zero {n : Fin 0 → ℕ} {k : Fin (vsum n)} : splitSum k = Fin.elim0 k

lemma getLowBits_le_self {n : ℕ} (numLowBits : ℕ) : getLowBits numLowBits n ≤ n

@[simp]
lemma natDegree_solutionToE :
  (solutionToE e k v).natDegree = e

lemma modified_guruswami_has_a_solution
  {m n k : ℕ}
  {ωs : Fin n ↪ F} {u₀ u₁ : Fin n → F}
  :
  ∃ Q : F[Z][X][Y], ModifiedGuruswami m n k ωs Q u₀ u₁

theorem oracleVerifier_rbrKnowledgeSoundness [Fintype R] :
    (oracleVerifier R deg D n oSpec).rbrKnowledgeSoundness init impl
      (relationRound R n deg D 0) (relationRound R n deg D (.last n))
      (fun _ => (deg : ℝ≥0) / (Fintype.card R))

theorem cast_runToRound (j : Fin (n₁ + 1)) (stmt : StmtIn) (wit : WitIn)
    (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₁) :
    P.runToRound j stmt wit =
      cast (sorry) ((P.cast hn hSpec).runToRound (Fin.cast (congrArg (· + 1) hn) j) stmt wit)

@[simp]
theorem rtake_self (v : (i : Fin n) → α i) :
    rtake n (by omega) v = fun i : Fin n => dcast (by simp [Fin.cast]) (v i)

@[simp]
theorem reduction_completeness (h : init.neverFails)
    (hRel : ∀ stmtIn witIn, (stmtIn, witIn) ∈ relIn ↔
      (mapStmt stmtIn, mapWit stmtIn witIn) ∈ relOut) :
    (reduction oSpec mapStmt mapWit).perfectCompleteness init impl relIn relOut

@[simp]
theorem OracleReduction.id_perfectCompleteness
    {rel : Set ((StmtIn × ∀ i, OStmtIn i) × WitIn)}
    (hInit : init.neverFails) :
    (OracleReduction.id : OracleReduction oSpec _ _ _ _ _ _ _).perfectCompleteness
      init impl rel rel

theorem add_assoc {n : ℕ} (a b c : CNat (n + 1)) : (a + b) + c = a + (b + c)

lemma twoAdicity_maximal : ¬ (2 ^ (twoAdicity + 1)) ∣ (fieldSize - 1)

private lemma sum_sum_K_i_eq_n_sub_d
  (h_B : 2 ≤ B.card)
  :
  ∑ i, sum_choose_K_i B i = choose_2 B.card * (n - d B)

theorem LeafData.composeBuild_internal {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (compose : α → α → α) :
    (LeafData.internal left right).composeBuild compose =
      FullData.internal
        (compose (left.composeBuild compose).getRootValue (right.composeBuild compose).getRootValue)
        (left.composeBuild compose)
        (right.composeBuild compose)

@[simp]
lemma oddPart_coeff {f : Polynomial F} {n : ℕ} :
    (oddPart f).coeff n = if Even n then f.coeff (n + 1) else 0

@[simp]
lemma cons_empty_tail_eq_nil {α} (hd : α) (tl : Vector α 0) :
    cons hd tl = ⟨#[hd], rfl⟩

lemma add_eq_one_iff (a b : ConcreteBTField 0) :
  a + b = 1 ↔ (a = 0 ∧ b = 1) ∨ (a = 1 ∧ b = 0)

@[simp]
theorem OracleVerifier.run_eq_run_verifier [Oₘ : ∀ i, OracleInterface (pSpec.Message i)]
    {stmt : StmtIn} {oStmt : ∀ i, OStmtIn i} {transcript : FullTranscript pSpec}
    {verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec} :
      verifier.run stmt oStmt transcript =
        verifier.toVerifier.run ⟨stmt, oStmt⟩ transcript

theorem Reduction.run_of_prover_first [ProverOnly pSpec] (stmt : StmtIn) (wit : WitIn)
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      reduction.run stmt wit = (do
        let state := reduction.prover.input (stmt, wit)
        let ⟨msg, state⟩ ← liftComp (reduction.prover.sendMessage ⟨0, by simp⟩ state) _
        let ctxOut ← reduction.prover.output state
        let transcript : pSpec.FullTranscript := fun i => match i with | ⟨0, _⟩ => msg
        let stmtOut ← reduction.verifier.verify stmt transcript
        return (⟨transcript, ctxOut⟩, stmtOut))

theorem cast_eq_dcast₂ {V : Verifier oSpec StmtIn StmtOut pSpec₁} :
    V.cast hn hSpec = dcast₂ hn hSpec V

theorem runWithOracle_succeeds_iff_simulateQ_randomOracle_neverFails
     {β}
    [DecidableEq ι] [spec.DecidableEq] [(i : ι) → SelectableType (OracleSpec.range spec i)]
    (oa : OracleComp (spec) β) (f : spec.FunctionType) :
    (runWithOracle f oa).isSome ↔
    ((oa.simulateQ randomOracle).run (fun i q => some (f i q))).neverFails

theorem prime_43 : Nat.Prime 43

@[simp] theorem ofNat_add (n m : Nat) : ofNat (n + m) = add (ofNat n) (ofNat m)

lemma evenize_is_even {f : Polynomial F} :
    EvenPoly (evenize f)

lemma cast_ConcreteBTField_eq (k m : ℕ) (h_eq : k = m) :
  ConcreteBTField k = ConcreteBTField m

theorem eqPolynomial_symm (x : σ → R) (y : σ → R) :
    MvPolynomial.eval y (eqPolynomial x) = MvPolynomial.eval x (eqPolynomial y)

private lemma eval_solutionToQ_aux {i : Fin ((solutionToQ e k v).natDegree + 1)} [NeZero e]
  : e + i < 2 * e + k

theorem split_sum_eq_sum_split {k : ℕ} (h_pos : k > 0) (x₀ x₁ : ConcreteBTField k)
  (hi₀ lo₀ hi₁ lo₁ : ConcreteBTField (k - 1))
  (h_split_x₀ : split h_pos x₀ = (hi₀, lo₀))
  (h_split_x₁ : split h_pos x₁ = (hi₁, lo₁)) :
  split h_pos (x₀ + x₁) = (hi₀ + hi₁, lo₀ + lo₁)

theorem stir_main
  (secpar : ℕ) [SelectableType F]
  {ι : Type} [Fintype ι] [Nonempty ι] [DecidableEq ι]
  {φ : ι ↪ F} {degree : ℕ} [hsmooth : Smooth φ]
  {k proofLen qNumtoInput qNumtoProofstr : ℕ}
  (hk : ∃ p, k = 2 ^ p) (hkGe : k ≥ 4)
  (δ : ℝ≥0) (hδub : δ < 1 - 1.05 * Real.sqrt (degree / Fintype.card ι))
  (hF : Fintype.card F ≤
        secpar * 2 ^ secpar * degree ^ 2 * (Fintype.card ι) ^ (7 / 2) /
          Real.log (1 / rate (code φ degree))) :
  ∃ n : ℕ,
  ∃ vPSpec : ProtocolSpec.VectorSpec n,
  ∃ ε_rbr : vPSpec.ChallengeIdx → ℝ≥0,
  ∃ π : VectorIOP Unit (OracleStatement ι F) Unit vPSpec F,
  IsSecureWithGap (stirRelation degree φ 0)
                  (stirRelation degree φ δ)
                  ε_rbr π
  ∧ ∀ i, ε_rbr i ≤ (1 : ℚ≥0) / (2 ^ secpar)
  ∧ ∃ c > 0, M ≤ c * (Real.log degree / Real.log k)
  ∧ ∃ cₖ : ℕ → ℝ, proofLen ≤ (Fintype.card ι) + (cₖ k) * (Real.log degree)
  ∧ qNumtoInput = secpar / (- Real.log (1 - δ))
  ∧ ∃ cₖ : ℕ → ℝ, qNumtoProofstr ≤
    (cₖ k) * ((Real.log degree) +
      secpar * (Real.log ((Real.log degree) / Real.log (1/rate (code φ degree)))))

theorem prime_3 : Nat.Prime 3

lemma domain_injective (i : ℕ) : i ≤ n → Function.Injective (domain D n i)

@[simp]
lemma eval₂_monomial {S : Type w} [CommSemiring S] (f : R →+* S) (x : S) (n : ℕ) (r : R) :
    eval₂ (P := P) f x (monomial n r) = f r * x ^ n

Nat.le_trans in Init.Prelude

theorem happend_hcons {β : Fin m → Sort u} {γ : Fin n → Sort u}
    (a : α) (u : (i : Fin m) → β i) (v : (i : Fin n) → γ i) :
    True

theorem get_rtake_eq_rtake_get_comp_cast {α : Type*} {m : ℕ} (l : List α) (h : m ≤ l.length) :
    (l.rtake m).get = rtake m h l.get ∘ Fin.cast (by simp [List.rtake]; omega)

@[simp]
theorem ofNat_succ (n : ℕ) : @ofNat α (n.succ) = succ (ofNat n)

@[simp]
theorem append_cast_left {n m : ℕ} {pSpec : ProtocolSpec n} {pSpec' : ProtocolSpec m} (n' : ℕ)
    (h : n + m = n' + m) :
      dcast h (pSpec ++ₚ pSpec') = (dcast (Nat.add_right_cancel h) pSpec) ++ₚ pSpec'

lemma definingPoly_is_monic {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).Monic

lemma foldl_NTTStage_inductive_aux (h_ℓ : ℓ ≤ r) (k : Fin (ℓ + 1))
    (original_coeffs : Fin (2 ^ ℓ) → L) :
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate
    (Fin.foldl k (fun current_b i ↦ NTTStage 𝔽q β h_ℓ_add_R_rate
      ⟨ℓ - i -1, by omega⟩ current_b) (tileCoeffs original_coeffs))
    original_coeffs ⟨ℓ - k, by omega⟩

theorem unique_linear_form_of_elements_in_adjoined_commring
    {R : Type*} [CommRing R] (f : R[X]) (hf_deg : f.natDegree = 2)
    (hf_monic : Monic f) (c1 : AdjoinRoot f) :
    ∃! p : R × R, c1 = (AdjoinRoot.of f) p.1 * root f + (AdjoinRoot.of f) p.2

@[simp]
theorem Iic_zero : Iic (0 : Fin (n + 1)) = {0}

lemma BerlekampWelch_E_ne_zero {e k : ℕ}
  {ωs f : Fin n → F}
  {E Q : Polynomial F}
  (h_cond : BerlekampWelchCondition e k ωs f E Q)
  : E ≠ 0

theorem unique_repr {R : Type*} [CommRing R] {S : Type*} [CommRing S] [Algebra R S]
    (pb : PowerBasis R S) (repr1 repr2 : Fin pb.dim →₀ R)
    (h : ∑ i : Fin pb.dim, repr1 i • pb.basis i = ∑ i : Fin pb.dim, repr2 i • pb.basis i) :
    repr1 = repr2

lemma getBit_of_and {n m k: ℕ} : getBit k (n &&& m) = getBit k n &&& getBit k m

@[simp]
theorem vcons_self_tail (v : Fin (n + 1) → α) : (v 0) ::ᵛ (tail v) = v

theorem leftpad_eq_self (v : Fin n → α) (a : α) : leftpad n a v = v

@[simp]
theorem fconcat_zero {α : Fin 0 → A} {β : A} (a : F β) : !h⦃F⦄⟨α⟩[] :+ʰ a =
  fun i => match i with

theorem eval_eq_eval_mv_eval_finSuccEquivNth (s : Fin n → R) (y : R)
    (f : MvPolynomial (Fin (n + 1)) R) :
      eval (Fin.insertNth p y s : Fin (n + 1) → R) f =
        Polynomial.eval y (Polynomial.map (eval s) (finSuccEquivNth R p f))

@[simp]
lemma append_zero_of_succ_left {u : Fin (m + 1) → α} {v : Fin n → α} :
    (append u v) 0 = u 0

@[simp]
theorem dcast₂_eq' (h : a = a) (h' : dcast h b = b) : dcast₂ h h' c = c

@[simp]
theorem seqCompose_zero {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    {T : ∀ i, FullTranscript (pSpec i)} :
    seqCompose T = !h[]

lemma neg_mod_2_eq_0_iff_mod_2_eq_0 {n : ℤ} : ( - n) % 2 = 0 ↔ n % 2 = 0

lemma concrete_one_ne_zero {k : ℕ} : (one (k:=k)) ≠ (zero (k:=k))

theorem join_zero_one {k : ℕ} (h_k : k > 0) :
    《 zero (k:=k - 1), one (k:=k - 1) 》 = one (k:=k)

@[simp] theorem leftpad_eq_self (l : List α) (n : Nat) (h : l.length ≥ n) :
    leftpad n unit l = l

theorem hcons_injective2 {α : Sort u} {β : Fin n → Sort u} :
    Function.Injective2 (@hcons n α β)

lemma quotienting [DecidableEq F] {degree : ℕ} {domain : ι ↪ F} [Nonempty ι]
  (S : Finset F) (hS_lt : S.card < degree) (r : F)
  (f : ι → F) (Ans Fill : S → F) (δ : ℝ) (hδPos : δ > 0) (hδLt : δ < 1)
  (h : ∀ u : code domain degree, u.val ∈ (relHammingBall ↑(code domain degree) f δ) →
    ∃ (x : S) (hx : x.val ∈ S), ((decodeLT u) : F[X]).eval x.val ≠ Ans ⟨x.val, hx⟩) :
    δᵣ((funcQuotient f S Ans Fill), (code domain (degree - S.card))) +
      ((disagreementSet f S Ans).card : ℝ) / (ι.card : ℝ) > δ

theorem zero_canonical : (0 : UniPoly R).trim = 0

@[simp]
theorem perfectCompleteness_eq_prob_one :
    reduction.perfectCompleteness init impl relIn relOut ↔
      ∀ stmtIn witIn, (stmtIn, witIn) ∈ relIn →
        [fun ⟨⟨_, (prvStmtOut, witOut)⟩, stmtOut⟩ =>
          (stmtOut, witOut) ∈ relOut ∧ prvStmtOut = stmtOut
        | do (simulateQ (impl ++ₛₒ challengeQueryImpl : QueryImpl _ (StateT σ ProbComp))
            <| reduction.run stmtIn witIn).run' (← init)] = 1

@[simp]
theorem seqCompose_two_eq_append {n : Fin 2 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = append (pSpec 0) (pSpec 1)

@[simp]
theorem splitSum_embedSum {m : ℕ} {n : Fin m → ℕ} (i : Fin m) (j : Fin (n i)) :
    splitSum (embedSum i j) = ⟨i, j⟩

theorem toNat_ofNat (n : ℕ) : toNat (ofNat n) = n

theorem fiberwise_dist_lt_imp_dist_lt_unique_decoding_radius (i : Fin ℓ) (steps : ℕ)
    [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
    (f : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by omega⟩)
  (h_fw_dist_lt : fiberwiseClose 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    (i := i) (steps := steps) (h_i_add_steps := h_i_add_steps) (f := f)) :
  hammingClose 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by omega⟩ f

theorem degreeOf_X_le (i j : σ) : degreeOf i (X (R := R) j) ≤ 1

theorem sum_of_root_and_inverse_is_t1
    {curBTField : Type*} [Field curBTField]
    (u : curBTField) (t1 : curBTField) -- here t1 is already lifted to curBTField
    (specialElementNeZero : u ≠ 0)
    (eval_prevPoly_at_root : u ^ 2 + t1 * u + 1 = 0)
    (sumZeroIffEq : ∀ (x y : curBTField), x + y = 0 ↔ x = y) :
    u + u⁻¹ = t1

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

@[simp]
theorem hconcat_last {α : Fin n → Sort u} {β : Sort u} (v : (i : Fin n) → α i) (b : β) :
    hconcat v b (last n) = cast (vconcat_last α β).symm b

@[simp]
theorem insertNth_zero : insertNth 0 y s = cons y s

lemma degree_s_smul_X {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (C s * (X : (F)[X])).degree = 1

private lemma sum_choose_K' [Zero F]
  (h_card : 2 ≤ (Fintype.card F))
  :
  (Fintype.card (α := F) - 1) * choose_2 ((B.card - K B i 0) / (Fintype.card (α := F) - 1)) ≤
  ∑ (α : F) with α ≠ 0, choose_2 (K B i α)

@[simp]
theorem distFromCode_of_mem (C : Set (n → R)) {u : n → R} (h : u ∈ C) : Δ₀(u, C) = 0

theorem buildMerkleTree_neverFails (α : Type) [DecidableEq α] [SelectableType α] {n : ℕ}
    (leaves : List.Vector α (2 ^ n)) (preexisting_cache : (spec α).QueryCache) :
    ((simulateQ randomOracle (buildMerkleTree α n leaves)).run preexisting_cache).neverFails

theorem fconcat_injective2 {α : Fin n → A} {β : A} :
    Function.Injective2 (@fconcat A F n α β)

@[simp]
protected lemma elocPolyF_eq_elocPoly :
  ElocPolyF (n := n) (liftF' ωs) (liftF' f) = ElocPoly n ωs f

@[simp]
lemma runWithLog_discard_log_eq_run (stmt : StmtIn) (wit : WitIn)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      Prod.fst <$> prover.runWithLog stmt wit = prover.run stmt wit

lemma evenize_eq_comp_x_squared {f : Polynomial F} :
    evenize f = f.comp (Polynomial.X * Polynomial.X)

omit [Finite F] in
lemma sqr_mem_D_succ_i_of_mem_D_i : ∀ {a : Fˣ} {i : ℕ},
    a ∈ evalDomain D x i → a ^ 2 ∈ evalDomain D x (i + 1)

@[simp]
lemma foldr'_zero {α : Type u} (f : (i : Fin 0) → α → α) (x : α) :
    foldr' 0 f x = x

theorem support_finSuccEquivNth (f : MvPolynomial (Fin (n + 1)) R) :
    (finSuccEquivNth R p f).support = Finset.image (fun m : Fin (n + 1) →₀ ℕ => m p) f.support

theorem finSigmaFinEquiv'_pair {m : ℕ} {n : Fin m → ℕ} (i : Fin m) (k : Fin (n i)) :
    (finSigmaFinEquiv' ⟨i, k⟩ : ℕ) = ∑ j, n (Fin.castLE i.isLt.le j) + k

@[simp]
theorem mul_by_2_mem {s : Finset ℕ} {d : ℕ} :
    d ∈ mul_by_2 s ↔ Even d ∧ (d / 2) ∈ s

lemma folding_preserves_listdecoding_bound
  {S : Finset ι} {k m : ℕ} (hm : 1 ≤ m) {φ : ι ↪ F} [Smooth φ] {δ : ℝ≥0} {f : (indexPowT S φ 0) → F}
  {S_0 : Finset (indexPowT S φ 0)} {S_1 : Finset (indexPowT S φ 1)}
  {φ_0 : (indexPowT S φ 0) ↪ F} {φ_1 : (indexPowT S φ 1) ↪ F}
  [∀ i : ℕ, Fintype (indexPowT S φ i)] [∀ i : ℕ, DecidableEq (indexPowT S φ i)]
  [Smooth φ_0] [Smooth φ_1]
  [h : ∀ {f : (indexPowT S φ 0) → F}, DecidableBlockDisagreement 0 k f S_0 φ_0]
  [h : ∀ {f : (indexPowT S φ 1) → F}, DecidableBlockDisagreement 1 k f S_1 φ_1]
  [∀ i : ℕ, Neg (indexPowT S φ i)]
  {C : Set ((indexPowT S φ 0) → F)} (hcode : C = smoothCode φ_0 m)
  (C' : Set ((indexPowT S φ 1) → F)) (hcode' : C' = smoothCode φ_1 (m-1))
  {BStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0}
  {errStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0 → ℝ≥0} :
      ∀ α : F,
        let listBlock : Set ((indexPowT S φ 0) → F) := Λᵣ(0, k, f, S_0, C, hcode, δ)
        let vec_α : Fin 1 → F := (fun _ : Fin 1 => α)
        let foldSet := fold_k_set listBlock vec_α hm
        let fold := fold_k f vec_α hm
        let listBlock' : Set ((indexPowT S φ 1) → F) := Λᵣ(1, k, fold, S_1, C', hcode', δ)
        foldSet ⊆ listBlock'

@[simp]
theorem seqCompose_succ_dir {m : ℕ} {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    (seqCompose pSpec).dir = Fin.vflatten (fun i => (pSpec i).dir)

omit [NeZero ϑ] [NeZero ℓ] hdiv in
lemma toCodewordsCount_mul_ϑ_le_i (i : Fin (ℓ + 1)) :
  ∀ j: Fin (toOutCodewordsCount ℓ ϑ i), j.val * ϑ ≤
    (if i.val < ℓ then i.val else ℓ - ϑ)

@[simp]
theorem fflatten₂_zero {A : Sort u} {B : Sort v} {F : A → B → Sort w} {n : Fin 0 → ℕ}
    {α : (i : Fin 0) → (j : Fin (n i)) → A}
    {β : (i : Fin 0) → (j : Fin (n i)) → B}
    {v : (i : Fin 0) → (j : Fin (n i)) → F (α i j) (β i j)} : fflatten₂ v = !h[]

theorem snoc_ne_zero_of_left (h : s ≠ 0) : snoc s y ≠ 0

omit [NoZeroDivisors 𝔽] in
lemma foldNth_degree_le {n : ℕ} {f : 𝔽[X]} {α : 𝔽} [inst : NeZero n] :
    (foldNth n f α).natDegree ≤ f.natDegree / n

Fin.ext in Init.Data.Fin.Lemmas

theorem append_rbrSoundness {lang₁ : Set Stmt₁} {lang₂ : Set Stmt₂} {lang₃ : Set Stmt₃}
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁)
    (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    {rbrSoundnessError₁ : pSpec₁.ChallengeIdx → ℝ≥0}
    {rbrSoundnessError₂ : pSpec₂.ChallengeIdx → ℝ≥0}
    (h₁ : V₁.rbrSoundness init impl lang₁ lang₂ rbrSoundnessError₁)
    (h₂ : V₂.rbrSoundness init impl lang₂ lang₃ rbrSoundnessError₂) :
      (V₁.append V₂).rbrSoundness init impl lang₁ lang₃
        (Sum.elim rbrSoundnessError₁ rbrSoundnessError₂ ∘ ChallengeIdx.sumEquiv.symm)

omit [CharP L 2] [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 [NeZero 𝓡] in
lemma take_snoc_oracle_eq_oStmtIn (i : Fin ℓ)
    (oStmtIn : (j : Fin (toOutCodewordsCount ℓ ϑ i.castSucc)) →
      OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j)
    (newOracleFn : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ) :
    (take_snoc_oracle 𝔽q β i oStmtIn newOracleFn) = oStmtIn

lemma getBit_of_shiftLeft {n p : ℕ}:
  ∀ k, getBit (k) (n <<< p) = if k < p then 0 else getBit (k - p) n

lemma toOutCodewordsCount_mul_ϑ_eq_i_succ (i : Fin ℓ) (hCR : isCommitmentRound ℓ ϑ i) :
  (toOutCodewordsCount ℓ ϑ i.castSucc) * ϑ = i.val + 1

theorem BerlekampWelchCondition_iff_Solution {e k : ℕ} [NeZero n]
  {ωs f : Fin n → F} {v : Fin (2 * e + k) → F}
  :
  IsBerlekampWelchSolution e k ωs f v
  ↔
  (BerlekampWelchCondition e k ωs f (solutionToE e k v) (solutionToQ e k v))

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

lemma hammingDist_eq_wt_sub [CommRing F] {u v : ι → F} : hammingDist u v = Code.wt (u - v)

@[simp]
theorem mul_accepts_iff : (mul a b c).accepts x ↔ x c = x a * x b

Nat.lt_of_le_of_lt in Init.Prelude

theorem getBit_repr {ℓ : Nat} : ∀ j, j < 2^ℓ →
  j = ∑ k ∈ Finset.Icc 0 (ℓ-1), (getBit k j) * 2^k

theorem linear_form_of_elements_in_adjoined_commring
    {R : Type*} [CommRing R] (f : R[X]) (hf_deg : f.natDegree = 2)
    (hf_monic : Monic f) (c1 : AdjoinRoot f) :
    ∃ a b : R, c1 = (AdjoinRoot.of f) a * root f + (AdjoinRoot.of f) b

@[simp]
theorem prover_last (pSpec : ProtocolSpec n) [NeZero n] [h : ProverLast pSpec] :
    pSpec.dir ⟨n - 1, by simp [Nat.pos_of_neZero]⟩ = .P_to_V

theorem cast_eq_cast_iff {α β γ : Sort u} {h : α = γ} {h' : β = γ} {a : α} {b : β} :
    cast h a = cast h' b ↔ a = cast (h'.trans h.symm) b

lemma getLast_toImpl {p : Q[X]} (hp : p ≠ 0) : let h : p.toImpl.size > 0 := toImpl_nonzero hp;
    p.toImpl[p.toImpl.size - 1] = p.leadingCoeff

theorem dcast₂_symm (ha : a = a') (hb : dcast ha b = b') (hc : dcast₂ ha hb c = c') :
    dcast₂ ha.symm (dcast_symm ha hb) c' = c

lemma add_assoc {k : ℕ} : ∀ (a b c : ConcreteBTField k), a + b + c = a + (b + c)

@[simp]
lemma OracleReduction.append_toReduction
    (R₁ : OracleReduction oSpec Stmt₁ OStmt₁ Wit₁ Stmt₂ OStmt₂ Wit₂ pSpec₁)
    (R₂ : OracleReduction oSpec Stmt₂ OStmt₂ Wit₂ Stmt₃ OStmt₃ Wit₃ pSpec₂) :
      (OracleReduction.append R₁ R₂).toReduction =
        Reduction.append R₁.toReduction R₂.toReduction

private lemma evenPart_eq_evenPart' {f : Polynomial F} : evenPart f = evenPart' f

lemma split_smul_Z_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField (k - 1)) :
  letI instAlgebra := ConcreteBTFieldAlgebra (l:=k-1) (r:=k) (h_le:=by omega)
  split h_pos (x • Z k) = (x, 0)

lemma and_one_eq_of_eq {a b : ℕ} : a = b → a &&& 1 = b &&& 1

theorem finSuccEquivNth_apply (f : MvPolynomial (Fin (n + 1)) R) :
    finSuccEquivNth R p f =
      eval₂Hom (Polynomial.C.comp (C : R →+* MvPolynomial (Fin n) R))
        (Fin.insertNth p Polynomial.X (Polynomial.C ∘ X)) f

lemma linearIndependent_rows_of_lower_triangular_ne_zero_diag
  {n : ℕ} {R : Type*} [Field R] (A : Matrix (Fin n) (Fin n) R)
  (h_lower_triangular : A.BlockTriangular ⇑OrderDual.toDual) (h_diag : ∀ i, A i i ≠ 0) :
  LinearIndependent R A

theorem PrattCertificate.out {p : ℕ} (c : PrattCertificate p) : p.Prime

theorem neg_add_cancel : -p + p = 0

@[simp]
theorem fappend₂_left {α₁ : Fin m → A} {α₂ : Fin m → B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (u : (i : Fin m) → F₂ (α₁ i) (α₂ i)) (v : (i : Fin n) → F₂ (β₁ i) (β₂ i)) (i : Fin m) :
    fappend₂ (F := F₂) u v (castAdd n i) =
      cast (by simp [vappend_left]) (u i)

theorem insertNth_ne_zero_of_right (h : s ≠ 0) : insertNth p y s ≠ 0

@[simp] theorem rightpad_eq_self (l : List α) (n : Nat) (h : n ≤ l.length) :
    rightpad n unit l = l

theorem induction_append_right {m n : ℕ} {motive : Fin (m + n + 1) → Sort*} {zero : motive 0}
  {succ : ∀ i : Fin (m + n), motive i.castSucc → motive i.succ} {i : Fin (n + 1)} :
    induction zero succ (i.natAdd m) =
      @induction n (fun i => motive (i.natAdd m))
        (@induction m (fun j => motive (Fin.cast (by omega) (j.castAdd n)))
          zero (fun j x => succ (j.castAdd n) x) (last m))
        (fun i x => succ (i.natAdd m) x) i

omit [Fintype F] [DecidableEq F] in
private lemma choose_2_card_ne_zero (h : 2 ≤ B.card) : choose_2 ↑B.card ≠ 0

theorem srSoundness_addSalt_implies_srSoundness_original
    (langIn : Set StmtIn) (langOut : Set StmtOut)
    (Salt : pSpec.MessageIdx → Type) [∀ i, Nonempty (Salt i)] [∀ i, Fintype (Salt i)]
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (srInit : ProbComp (srChallengeOracle StmtIn (pSpec.addSalt Salt)).FunctionType)
    (srImpl : QueryImpl oSpec
      (StateT (srChallengeOracle StmtIn (pSpec.addSalt Salt)).FunctionType ProbComp))
    (srSoundnessError : ℝ≥0) :
      Verifier.StateRestoration.soundness srInit srImpl langIn langOut
        (verifier.addSalt Salt) srSoundnessError →
        Verifier.StateRestoration.soundness sorry sorry langIn langOut
          verifier srSoundnessError

theorem eq_monomialOfNat_iff_eq_bitRepr (m : Fin n →₀ ℕ)
  (h_binary : ∀ j : Fin n, m j ≤ 1) (i: Fin (2^n)) :
  monomialOfNat i = m ↔ i = Nat.binaryFinMapToNat m h_binary

lemma weight_ξ_bound (x₀ : F) {D : ℕ} (hD : D ≥ Bivariate.totalDegree H) :
  weight_Λ_over_𝒪 (ξ x₀ R H) D ≤
    WithBot.some ((Bivariate.natDegreeY R - 1) * (D - Bivariate.natDegreeY H + 1))

Nat.le_of_succ_le in Init.Data.Nat.Basic

@[simp]
theorem append_cast_right {n m : ℕ} (pSpec : ProtocolSpec n) (pSpec' : ProtocolSpec m) (m' : ℕ)
    (h : n + m = n + m') :
      dcast h (pSpec ++ₚ pSpec') = pSpec ++ₚ (dcast (Nat.add_left_cancel h) pSpec')

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] theorem ofNat_succ (n : Nat) : ofNat n.succ = succ (ofNat n)

theorem drop_append_right {n' : ℕ} {α : Sort*} (m : ℕ) (h : m ≤ n') (u : (i : Fin n) → α)
    (v : (i : Fin n') → α) :
      drop (n + m) (Nat.add_le_add_left h n) (append u v) =
        fun i => (drop m h v (i.cast (by omega)))

lemma coprime_three_fieldSize_sub_one : Nat.Coprime 3 (fieldSize - 1)

@[simp]
theorem cast_dir_idx {hn} (hSpec : pSpec₁.cast hn = pSpec₂) {i : Fin n₁} :
    pSpec₂.dir (Fin.cast hn i) = pSpec₁.dir i

@[simp]
theorem drop_zero (v : (i : Fin n) → α i) : drop 0 n.zero_le v = v

omit [Finite F] in
private lemma op_der_eq : Monoid.toMulAction Fˣ = Units.mulAction'

lemma powerBasisSucc_dim (k : ℕ) :
  powerBasisSucc (k:=k).dim = 2

Nat.lt_succ_of_le in Init.Prelude

@[simp]
lemma finite_relHammingDistRange [Nonempty ι] : (relHammingDistRange ι).Finite

lemma split_algebraMap_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : BTField (k - 1)) :
  letI instAlgebra := binaryAlgebraTower (l:=k-1) (r:=k) (h_le:=by omega)
  split (k:=k) (h_k:=h_pos) (algebraMap (BTField (k - 1)) (BTField k) x) = (0, x)

theorem minDist [Field F] [DecidableEq F] (inj : Function.Injective α) [NeZero n] (h : n ≤ m) :
  minDist ((ReedSolomon.code ⟨α, inj⟩ n) : Set (Fin m → F)) = m - n + 1

theorem last_nonzero_spec [LawfulBEq R] {p : UniPoly R} {k} :
  p.last_nonzero = some k
  → p[k] ≠ 0 ∧ (∀ j, (hj : j < p.size) → j > k → p[j] = 0)

@[simp]
theorem rtake_append_right :
    (pSpec₁ ++ₚ pSpec₂).rtake n (Nat.le_add_left n m) = pSpec₂

omit [DecidableEq L] [DecidableEq 𝔽q] h_Fq_char_prime hF₂ hβ_lin_indep h_β₀_eq_1 in
theorem qMap_eval_𝔽q_eq_0 (i : Fin r) :
  ∀ c: 𝔽q, (qMap 𝔽q β i).eval (algebraMap 𝔽q L c) = 0

theorem induction_init {n : ℕ} {motive : Fin (n + 2) → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin (n + 1), motive i.castSucc → motive i.succ} {i : Fin (n + 1)} :
      induction (motive := motive) zero succ i.castSucc =
        induction (motive := Fin.init motive) zero (fun j x => succ j.castSucc x) i

theorem foldl_split_inner {α : Type u} {β : Type v} (f : α → β → α) (init : α)
    (l : List β) (h : l ≠ []): foldl (f:=f) (init:=init) (l)
    = foldl (f:=f) (init:=f (init) (l.head (by omega))) (l.tail)

theorem image_support_finSuccEquivNth {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} :
    Finset.image (Finsupp.insertNth p i) (Polynomial.coeff ((finSuccEquivNth R p) f) i).support =
      f.support.filter fun m => m p = i

theorem init_vconcat (v : Fin n → α) (a : α) :
    (fun i => vconcat v a (Fin.castSucc i)) = v

@[simp]
theorem bit_finProdFinEquiv_symm_2_pow_succ {n : ℕ} (j : Fin (2 ^ (n + 1))) (i : Fin (n + 1)) :
  let e:=finProdFinEquiv (m:=2^(n)) (n:=2).symm
  Nat.getBit (i) j = if i.val > 0 then Nat.getBit (i.val-1) (e j).1 else (e j).2

theorem rightpad_eq_if_rightpad_eq_of_ge (l l' : List α) (m n n' : Nat) (h : n ≤ m) (h' : n' ≤ m) :
    rightpad n unit l = rightpad n' unit l' →
        rightpad m unit l = rightpad m unit l'

@[simp]
lemma runWithLogToRound_discard_log_eq_runToRound (i : Fin (n + 1))
    (stmt : StmtIn) (wit : WitIn) (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      Prod.fst <$> prover.runWithLogToRound i stmt wit =
        prover.runToRound i stmt wit

lemma addSalt_Message (i : pSpec.MessageIdx) :
    (pSpec.addSalt Salt).Message i = (pSpec.Message i × Salt i)

theorem completeness_error_mono {ε₁ ε₂ : ℝ≥0} (hε : ε₁ ≤ ε₂) :
      completeness init impl relIn relOut reduction ε₁ →
        completeness init impl relIn relOut reduction ε₂

theorem degreeOf_eval_C_finSuccEquiv (p : MvPolynomial (Fin (n + 1)) R) (j : Fin n) (x : R) :
    degreeOf j (Polynomial.eval (C x) (finSuccEquiv R n p)) ≤ degreeOf j.succ p

theorem heq_of_dcast (ha : a = a') (hb : dcast ha b = b') : HEq b b'

beq_iff_eq in Init.Core

theorem support_eval [DecidableEq σ] {τ : Type*} {f : τ → R} {p : R[X σ][X τ]} :
    (eval (C ∘ f) p).support ⊆ p.support.biUnion (fun c => (coeff c p).support)

lemma zsmul_neg' {k : ℕ} (n : ℕ) (a : ConcreteBTField k) :
  (if ((Int.negSucc n) : ℤ) % (2 : ℤ) = (0 : ℤ) then zero else a) =
    neg (if (↑n.succ : ℤ) % (2 : ℤ) = (0 : ℤ) then zero else a)

theorem fconcat₂_injective2 {α₁ : Fin n → A} {α₂ : Fin n → B} {β₁ : A} {β₂ : B} :
    Function.Injective2 (@fconcat₂ A B F₂ n α₁ β₁ α₂ β₂)

lemma oracleWitnessConsistency_relay_preserved
    (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i)
    (stmt : Statement (L := L) Context i.succ)
    (wit : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j) :
    oracleWitnessConsistency (mp := mp) (𝓑 := 𝓑) 𝔽q β i.succ i.castSucc
      (le_succ ↑i.castSucc) stmt wit oStmt =
    oracleWitnessConsistency (mp := mp) (𝓑 := 𝓑) 𝔽q β i.succ i.succ (by rfl) stmt wit
      (mapOStmtOutRelayStep 𝔽q β i hNCR oStmt)

lemma sum_insertNth' [AddCommMonoid M] [AddCommMonoid N] {n : ℕ} (σ : Fin n →₀ M) (i : M)
    (p : Fin (n + 1)) (f : Fin (n+1) → M → N) (h : ∀ x, f x 0 = 0) :
    sum (insertNth p i σ) f = f p i + sum σ (Fin.removeNth p f)

theorem castSum_castAdd {n m : ℕ} (i : Fin n) : castSum [n, m] (by simp) i = castAdd m i

omit [NoZeroDivisors 𝔽] in
lemma splitNth_degree_le {n : ℕ} {f : 𝔽[X]} [inst : NeZero n] :
  ∀ {i}, (splitNth f n i).natDegree ≤ f.natDegree / n

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

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R deg D oSpec).perfectCompleteness init impl
      (inputRelation R deg D) (outputRelation R deg)

omit h_β₀_eq_1 in
lemma finToBinaryCoeffs_sDomainToFin (i : Fin r) (h_i : i < ℓ + R_rate)
    (x : sDomain 𝔽q β h_ℓ_add_R_rate i) :
    let pointFinIdx := (sDomainToFin 𝔽q β h_ℓ_add_R_rate i h_i) x
    finToBinaryCoeffs 𝔽q (i := i) (idx :=pointFinIdx) =
    (sDomain_basis 𝔽q β
    h_ℓ_add_R_rate i h_i).repr x

lemma liftF_eq_of_lt {i : ℕ} (h : i < n) : liftF f' i = f' ⟨i, h⟩

theorem ofNat_toNat (n : ChurchNat ℕ) : ofNat (toNat n) = n

theorem nsmul_raw_succ (n : ℕ) (p : UniPoly Q) :
  nsmul_raw (n + 1) p = add_raw (nsmul_raw n p) p

@[simp]
lemma coeff_solutionToE :
  (solutionToE e k v).coeff n = if n = e then 1 else if n < e then liftF v n else 0

theorem FullData.toLeafData_rightSubtree {α} {s_left s_right : Skeleton}
    (tree : FullData α (Skeleton.internal s_left s_right)) :
    tree.toLeafData.rightSubtree =
      tree.rightSubtree.toLeafData

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

lemma algebraMap_adjacent_tower_def (l : ℕ) :
    (algebraMap (ConcreteBTField l) (ConcreteBTField (l + 1))) =
    canonicalAlgMap l

@[simp]
theorem dappend_zero {motive : Fin (m + 0) → Sort u} (u : (i : Fin m) → motive (castAdd 0 i)) :
    dappend (motive := motive) u !d⟨fun _ : Fin 0 => motive (natAdd m _)⟩[] = u

theorem oracleReduction_perfectCompleteness (hInit : init.neverFails) :
    (oracleReduction R n deg D oSpec i).perfectCompleteness init impl
      (relationRound R n deg D i.castSucc) (relationRound R n deg D i.succ)

@[simp]
private lemma F2i_disjoint :
  Set.PairwiseDisjoint Set.univ (F2i B i)

lemma exist_bit_diff_if_diff {n: ℕ} (a: Fin (2^n)) (b: Fin (2^n)) (h_a_ne_b: a ≠ b):
  ∃ k: Fin n, getBit k a ≠ getBit k b

lemma even_index_intermediate_novel_basis_decomposition (i : Fin ℓ) (j : Fin (2 ^ (ℓ - i - 1))) :
  intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i, by omega⟩ ⟨j * 2, by
    apply mul_two_add_bit_lt_two_pow j (ℓ-i-1) (ℓ-i) ⟨0, by omega⟩ (by omega) (by omega)
  ⟩  = (intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i+1, by omega⟩ ⟨j, by
    apply lt_two_pow_of_lt_two_pow_exp_le j (ℓ-i-1) (ℓ-(i+1)) (by omega) (by omega)
  ⟩).comp (qMap 𝔽q β ⟨i, by omega⟩)

private lemma E_and_Q_BerlekampWelch_condition
  (h_p_deg : p.natDegree < k)
  (h_dist : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  : BerlekampWelchCondition e k ωs f (E ωs f p e) (Q ωs f p e)

@[simp]
theorem vconcat_last (v : Fin n → α) (a : α) : vconcat v a (Fin.last n) = a

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r} (i : Fin ℓ)
    : i.val < r

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

@[simp]
theorem BTField.Basis_cast_dest_apply {ι : Type*} (α β γ : ℕ) (h_le1 : α ≤ β) (h_le2 : α ≤ γ)
    (h_eq : β = γ) {k : ι} (b : @Basis ι (BTField α) (BTField β) _ _
    (@binaryAlgebraTower (l := α) (r := β) (h_le := h_le1)).toModule) :
    let castBasis : @Basis ι (BTField α) (BTField γ) _ _
      (@binaryAlgebraTower (l := α) (r := γ) (h_le := h_le2)).toModule :=
      cast (by
        exact Basis_cast_dest_eq α γ β h_le2 h_le1 h_eq
      ) b
    (castBasis k) = cast (by exact BTField.cast_BTField_eq β γ h_eq) (b k)

lemma deevenize_comp_x_squared {f : Polynomial F} (hEven : EvenPoly f) :
    (deevenize f).comp (Polynomial.X * Polynomial.X) = f

Nat.cast_pow in Mathlib.Data.Nat.Cast.Basic

lemma solutionToE_eq_polynomialOfCoeffs
  (h : n < e) : (solutionToE e k v).coeff n = (polynomialOfCoeffs v).coeff n

theorem mul_add {a b c : AssocNat} : a * (b + c) = a * b + a * c

lemma bIdx_succ_mul_ϑ_le_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) : (↑bIdx + 1) * ϑ ≤ ℓ + 1

theorem eq_zero_of_degreeOf_lt_card_of_eval_eq_zero_of_fin {n : ℕ} {p : R[X Fin n]}
    (S : Fin n → Finset R) (hDegree : ∀ i, p.degreeOf i < (S i).card)
    (hEval : ∀ x ∈ piFinset fun i ↦ S i, eval x p = 0) :
        p = 0

@[simp] theorem toNat_add (a b : AssocNat) : toNat (add a b) = toNat a + toNat b

protected lemma elocPoly_leftF_leftF_eq_contract {ωs f : Fin m → F} :
  ElocPoly n (liftF ωs) (liftF f) =
  ElocPoly n (contract n ωs) (contract n f)

@[simp]
lemma ofPolynomialAlgHom_toPolynomialAlgHom_X :
    ofPolynomialAlgHom (toPolynomialAlgHom (X : P)) = (Polynomial.X : R[X])

lemma rank_eq_rowRank : U.rank = rowRank U

@[simp]
theorem cast_id : ChallengeIdx.cast (Eq.refl n₁) rfl = (id : pSpec₁.ChallengeIdx → _)

lemma card_le_card_of_count_inj {α β : Type*} [DecidableEq α] [DecidableEq β]
    {s : Multiset α} {s' : Multiset β}
  {f : α → β} (inj : Function.Injective f) (h : ∀ a : α, s.count a ≤ s'.count (f a)) :
  s.card ≤ s'.card

Nat.le_add_left in Init.Data.Nat.Basic

lemma rank_eq_min_row_col_rank : U.rank = min (rowRank U) (colRank U)

lemma eval₂_induction_on : True

@[to_additive vsum_castSucc]
lemma vprod_castSucc [CommMonoid α] {a : Fin (n + 1) → α} :
    vprod a = vprod (a ∘ Fin.castSucc) * a (last n)

omit [Fintype L] [DecidableEq L] in
theorem Polynomial.foldl_comp (n : ℕ) (f : Fin n → L[X]) : ∀ initInner initOuter: L[X],
    Fin.foldl (n:=n) (fun acc j => (f j).comp acc) (initOuter.comp initInner)
    = (Fin.foldl (n:=n) (fun acc j => (f j).comp acc) (initOuter)).comp initInner

theorem lagrangeToMonoLevel_monoToLagrangeLevel_id (v : Vector R (2 ^ n)) (i : Fin n) :
  lagrangeToMonoLevel i (monoToLagrangeLevel i v) = v

lemma degree_definingPoly {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).degree = 2

@[simp]
theorem finSuccEquivNth_X_above {i : Fin n} (h : p < i.succ) :
    finSuccEquivNth R p (X i.succ) = Polynomial.C (X i)

theorem dist'_eq_dist : ‖C‖₀'.toNat = ‖C‖₀

@[simp]
lemma coe_of_coe_fn (f : F) : (f : ∀ a, β a) = inst.equiv.toFun f

theorem is_multilinear_iff_eq_evals_zeroOne {p : MvPolynomial σ R} :
    p ∈ R⦃≤ 1⦄[X σ] ↔ MLE p.toEvalsZeroOne = p

@[simp] theorem equiv_trans {p q r : UniPoly Q} : Trim.equiv p q → equiv q r → equiv p r

@[simp]
theorem fflatten_two_eq_append {A : Sort u} {F : A → Sort v} {n : Fin 2 → ℕ}
    {α : (i : Fin 2) → (j : Fin (n i)) → A}
    {v : (i : Fin 2) → (j : Fin (n i)) → F (α i j)} :
    fflatten v = fappend (F := F) (v 0) (v 1)

theorem completeness : (oracleReduction oSpec Statement OStatement relComp).perfectCompleteness
    init impl relIn (relOut OStatement)

lemma W_is_additive
  (i : Fin r) :
  IsLinearMap (R := 𝔽q) (M := L) (M₂ := L) (f := fun x ↦ (W 𝔽q β i).eval x)

lemma coeff_toPoly {p : UniPoly Q} {n : ℕ} : p.toPoly.coeff n = p.coeff n

theorem additiveNTT_correctness (h_ℓ : ℓ ≤ r)
    (original_coeffs : Fin (2 ^ ℓ) → L)
    (output_buffer : Fin (2 ^ (ℓ + R_rate)) → L)
    (h_alg : output_buffer = additiveNTT 𝔽q β h_ℓ_add_R_rate original_coeffs) :
    let P := polynomialFromNovelCoeffs 𝔽q β ℓ h_ℓ original_coeffs
    ∀ (j : Fin (2^(ℓ + R_rate))),
      output_buffer j = P.eval (evaluationPointω 𝔽q β h_ℓ_add_R_rate ⟨0, by omega⟩ j)

omit [DecidableEq 𝔽q] hF₂ in
lemma initial_tiled_coeffs_correctness (h_ℓ : ℓ ≤ r) (a : Fin (2 ^ ℓ) → L) :
    let b: Fin (2^(ℓ + R_rate)) → L := tileCoeffs a
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate b a (i := ⟨ℓ, by omega⟩)

Nat.add_le_add_left in Init.Data.Nat.Basic

theorem vconcat_inj (v w : Fin n → α) (a b : α) :
    vconcat v a = vconcat w b ↔ v = w ∧ a = b

@[simp]
theorem FullData.internal_getRootValue {s_left s_right : Skeleton} {α : Type}
    (value : α) (left : FullData α s_left) (right : FullData α s_right) :
    (FullData.internal value left right).getRootValue =
      value

@[simp]
lemma finite_possibleRelHammingDistsToCode [Nonempty ι] [DecidableEq F] :
  (possibleDistsToCode w C relHammingDist).Finite

theorem whir_rbr_soundness
    [SelectableType F] {d dstar : ℕ}
  -- P : set of M + 1 parameters including foldingParamᵢ, varCountᵢ, φᵢ, repeatParamᵢ,
  --

@[simp]
lemma bIdx_mul_ϑ_add_x_lt_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) (x : ℕ) {hx : x ≤ ϑ} :
    ↑bIdx * ϑ + x < ℓ + 1

theorem singletonBound [CommRing F] [StrongRankCondition F]
  (LC : LinearCode ι F) :
  dim LC ≤ length LC - Code.minDist (LC : Set (ι → F)) + 1

lemma out_of_dom_smpl_2
  {δ l : ℝ≥0} {s : ℕ} {f : ι → F} {degree : ℕ} {φ : ι ↪ F}
  (C : Set (ι → F)) (hC : C = code φ degree)
  (h_decodable : listDecodable C δ l)
  (h_nonempty : Nonempty (domainComplement φ)) :
  listDecodingCollisionProbability φ f δ s degree h_nonempty ≤
    ((l^2 / 2)) * (degree / (Fintype.card F - Fintype.card ι))^s

theorem non_zero_map [LawfulBEq R] (f : R → R) (hf : ∀ r, f r = 0 → r = 0) (p : UniPoly R) :
  let fp := UniPoly.mk (p.map f);
  p.trim = p → fp.trim = fp

@[simp]
lemma numFullRounds_pos : 0 < params.numFullRounds

lemma johnson_condition_weak_implies_strong {B : Finset (Fin n → F)} {v : Fin n → F} {e : ℕ}
  (h : JohnsonConditionWeak B e)
  :
  JohnsonConditionStrong (B ∩ ({ x | Δ₀(x, v) ≤ e } : Finset _)) v

lemma join_split_eq_join {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k) :
  《 (split h_pos x).fst, (split h_pos x).snd 》 = x

@[simp]
theorem dempty_dappend {motive : Fin (0 + n) → Sort u} (v : (i : Fin n) → motive (natAdd 0 i)) :
    dappend (motive := motive) !d⟨fun _ : Fin 0 => motive (castAdd n _)⟩[] v =
      fun i => cast (by simp) (v (i.cast (by omega)))

omit [Finite F] in
@[simp]
lemma domain_lem₂ :
  [FinalOracleStatement D x s]ₒ.domain (Fin.last (k + 1)) = Unit

@[simp]
theorem cast_idx_symm {i : MessageIdx pSpec₂} :
    pSpec₁.Message (i.cast hn.symm (cast_symm hSpec)) = pSpec₂.Message i

lemma towerAlgebraMap_id (k : ℕ) : towerAlgebraMap (h_le:=by omega) = RingHom.id (BTField k)

lemma mca_list_decoding
  [Fintype ι] [Nonempty ι]
  (Gen : ProximityGenerator ι F) [Fintype Gen.parℓ]
  (δ BStar : ℝ) (errStar : ℝ → ENNReal)
  (fs us : Matrix Gen.parℓ ι F)
  (IC : InterleavedCode Gen.parℓ ι F)
  (haveIC : IC = codeOfLinearCode Gen.parℓ Gen.C)
      (hGen : hasMutualCorrAgreement Gen BStar errStar)
  (C : Set (ι → F)) (hC : C = Gen.C) :
    haveI := Gen.Gen_nonempty
    ∀ {fs : Matrix Gen.parℓ ι F}
    (hδPos : δ > 0) (hδLt : δ < min (δᵣ C : ℝ) (1 - BStar)),
      Pr_{let r ←$ᵖ Gen.Gen}[ proximityListDecodingCondition Gen.C r δ fs IC ]
        ≤ errStar δ

theorem get_rtake_ofFn_eq_rtake_comp_cast {α : Type*} {m : ℕ} (v : Fin n → α) (h : m ≤ n) :
    ((List.ofFn v).rtake m).get =
      rtake m h v ∘ Fin.cast (by simp [List.rtake]; omega)

@[simp]
lemma liftF'_liftF : Function.LeftInverse liftF' (liftF (α := α) (n := n))

lemma eval_trim_eq_eval [LawfulBEq R] (x : R) (p : UniPoly R) : p.trim.eval x = p.eval x

lemma oracle_block_k_bound (i : Fin (ℓ + 1)) (j : Fin (toOutCodewordsCount ℓ ϑ i)) :
    j.val * ϑ < ℓ

lemma sDomain_eq_image_of_upper_span (i : Fin r) (h_i : i < ℓ + R_rate) :
    let V_i := Submodule.span 𝔽q (Set.range (sBasis β h_ℓ_add_R_rate i h_i))
    let W_i_map := polyEvalLinearMap (normalizedW 𝔽q β i)
      (normalizedW_is_additive 𝔽q β i)
    sDomain 𝔽q β h_ℓ_add_R_rate i
    = Submodule.map W_i_map V_i

theorem finSuccEquivNth_coeff_coeff (m : Fin n →₀ ℕ) (f : MvPolynomial (Fin (n + 1)) R) (i : ℕ) :
    coeff m (Polynomial.coeff (finSuccEquivNth R p f) i) = coeff (m.insertNth p i) f

@[simp, grind] lemma C_pos : 0 < sz.C

lemma nonDoomedFoldingProp_relay_preserved (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i)
    (challenges : Fin i.succ → L)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j)
    :
    nonDoomedFoldingProp 𝔽q β i.castSucc (Fin.init challenges) oStmt ↔
    nonDoomedFoldingProp 𝔽q β i.succ challenges (mapOStmtOutRelayStep 𝔽q β i hNCR oStmt)

@[simp]
theorem fappend_left {α : Fin m → A} {β : Fin n → A}
    (u : (i : Fin m) → F (α i)) (v : (i : Fin n) → F (β i)) (i : Fin m) :
    fappend u v (castAdd n i) = cast (by simp [vappend_left]) (u i)

@[simp]
theorem embedSum_zero {n : Fin 0 → ℕ} {i : Fin 0} (j : Fin (n i)) : embedSum i j = i

theorem BitVec.dcast_bitvec_extractLsb_eq {w hi1 lo1 hi2 lo2 : ℕ}
    (x : BitVec w) (h_lo_eq : lo1 = lo2)
    (h_width_eq : hi1 - lo1 + 1 = hi2 - lo2 + 1) :
    dcast h_width_eq (BitVec.extractLsb (hi:=hi1) (lo:=lo1) x)
      = BitVec.extractLsb (hi:=hi2) (lo:=lo2) (x)

theorem toPoly_toImpl {p : Q[X]} : p.toImpl.toPoly = p

lemma and_two_pow_eq_two_pow_of_getBit_eq_one {n i : ℕ} (h_getBit: getBit i n = 1)
    : n &&& (2 ^ i) = 2 ^ i

lemma qMap_eval_mem_sDomain_succ (i : Fin ℓ)
    (h_i_add_1 : i.val + 1 ≤ ℓ) (x : (sDomain 𝔽q β
    h_ℓ_add_R_rate) ⟨i, by omega⟩) :
    (qMap 𝔽q β ⟨i.val, by omega⟩).eval (x.val : L) ∈
    sDomain 𝔽q β h_ℓ_add_R_rate
      ⟨i.val + 1, by omega⟩

@[simp]
lemma seqCompose_succ {m : ℕ}
    (Stmt : Fin (m + 2) → Type) (Wit : Fin (m + 2) → Type)
    {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (R : (i : Fin (m + 1)) →
      Reduction oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ) (pSpec i)) :
    seqCompose Stmt Wit R =
      append (R 0) (seqCompose (Stmt ∘ Fin.succ) (Wit ∘ Fin.succ) (fun i => R (Fin.succ i)))

theorem fcons₂_right_injective {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (a : F₂ α₁ α₂) :
    Function.Injective
      (fcons₂ (F := F₂) a : ((i : Fin n) → F₂ (β₁ i) (β₂ i)) → (i : Fin (n + 1)) → _ )

lemma probOfBadPts {deg : ℕ} {α : ι ↪ F} {e : ℕ} {U : Matrix κ ι F}
  (he : (e : ℚ) < (Code.minDist (RScodeSet α deg) : ℚ) / 3)
  (hU : e < Δ(U, matrixSubmoduleOfLinearCode κ (ReedSolomon.code α deg))) :
  (PMF.uniformOfFintype (Matrix.rowSpan U)).toOuterMeasure
    { w | distFromCode (n := ι) (R := F) w (ReedSolomon.code α deg) ≤ e }
  ≤ (Code.minDist (RScodeSet α deg) : ℝ≥0) /(Fintype.card F : ℝ≥0)

lemma twoAdicGenerators_pow_twoPow_eq_one (bits : Fin (twoAdicity + 1)) :
    (twoAdicGenerators[bits]) ^ (2 ^ (bits : Nat)) = (1 : Field)

@[simp, grind] lemma absorbPos_lt_N (sponge : DuplexSponge U C) :
    sponge.absorbPos < SpongeSize.N

@[simp]
theorem dempty_happend {α : Fin 0 → Sort u} {β : Fin n → Sort u} (v : (i : Fin n) → β i) :
    happend !d⟨α⟩[] v =
      fun i : Fin (0 + n) => cast (by simp) (v <| i.cast (by omega))

lemma xor_of_and_eq_zero_is_or {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n ^^^ m = n ||

theorem coeffs_of_comp_minus_x {f : Polynomial F} {n : ℕ} :
    (f.comp (-X)).coeff n = if Even n then f.coeff n else -f.coeff n

Nat.add_sub_cancel in Init.Data.Nat.Basic

@[simp]
theorem vconcat_zero (a : α) : vconcat !v[] a = !v[a]

@[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

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

@[simp]
theorem coe_basis_apply {R S : Type*} [CommRing R] [Ring S] [Algebra R S]
  (pb : PowerBasis R S) (i : Fin pb.dim) : ⇑pb.basis i = pb.gen ^ (i : ℕ)

omit h_Fq_char_prime in
theorem changeOfBasisMatrix_lower_triangular
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  (changeOfBasisMatrix 𝔽q β ℓ h_ℓ).BlockTriangular ⇑OrderDual.toDual

lemma nsmul_succ {k : ℕ} (n : ℕ) (x : ConcreteBTField k) :
  (if ↑n.succ % 2 = 0 then zero else x) = (if ↑n % 2 = 0 then zero else x) + x

lemma neg_descends (a b : UniPoly R) : equiv a b → neg_descending a = neg_descending b

lemma IsBerlekampWelchSolution_def
  : IsBerlekampWelchSolution e k ωs f v
  ↔ Matrix.mulVec (BerlekampWelchMatrix e k ωs f) v = (Rhs e ωs f)

@[simp]
theorem Verifier.id_soundness {lang : Set StmtIn} :
    (Verifier.id : Verifier oSpec _ _ _).soundness init impl lang lang 0

lemma split_join_via_add_smul_eq_iff_split (k : ℕ) (h_pos : k > 0)
    (hi_btf lo_btf : BTField (k - 1)) :
    split (k:=k) (h_k:=h_pos) (⋘ hi_btf, lo_btf ⋙) = (hi_btf, lo_btf)

@[simp]
theorem FullData.leftSubtree_internal {α} {s_left s_right : Skeleton}
    (value : α) (left : FullData α s_left) (right : FullData α s_right) :
    (FullData.internal value left right).leftSubtree = left

theorem generates_quotient_point_if_is_fiber_of_y
    (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i.val + steps ≤ ℓ)
    (x : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩))
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩))
    (hx_is_fiber : ∃ (k : Fin (2 ^ steps)), x = qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩)
      (steps := steps) (h_i_add_steps := by
        simp only; exact fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps) (y := y) k) :
    y = iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate i (k := steps) (h_bound := h_i_add_steps) x

omit [Finite F] in
lemma mul_root_of_unity {x : Fˣ} :
  ∀ {a b : Fˣ} {i j : ℕ},
    i ≤ j → a ∈ evalDomain D x i → b ∈ Domain.evalDomain D j →
      a * b ∈ evalDomain D x i

theorem dconcat_inj {motive : Fin (n + 1) → Sort u} (v w : (i : Fin n) → motive (castSucc i))
    (a b : motive (last n)) :
    (v :+ᵈ⟨motive⟩ a) = (w :+ᵈ⟨motive⟩ b) ↔ v = w ∧ a = b

theorem seqCompose_knowledgeSoundness
    (rel : (i : Fin (m + 1)) → Set ((Stmt i × ∀ j, OStmt i j) × Wit i))
    (V : (i : Fin m) →
      OracleVerifier oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Stmt i.succ) (OStmt i.succ)
        (pSpec i))
    (knowledgeError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).knowledgeSoundness init impl (rel i.castSucc) (rel i.succ) (knowledgeError i)) :
      (OracleVerifier.seqCompose Stmt OStmt V).knowledgeSoundness
        init impl (rel 0) (rel (Fin.last m)) (∑ i, knowledgeError i)

@[simp]
theorem cast_toReduction
    (R : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₁) :
    (R.cast hn hSpec hOₘ).toReduction = Reduction.cast hn hSpec R.toReduction

theorem support_coeff_finSuccEquivNth {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} {m : Fin n →₀ ℕ} :
    m ∈ (Polynomial.coeff ((finSuccEquivNth R p) f) i).support ↔ m.insertNth p i ∈ f.support

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

theorem take_drop_addCases' (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    Fin.addCases' (take m h v) (drop m h v) =
      fun i =>
        cast (by simp [append, addCases, castLE, Fin.cast]; intro hi; rw! [Nat.sub_add_cancel hi])
          (v (i.cast (by omega)))

@[simp]
theorem Set.mem_language_iff {α β} (rel : Set (α × β)) (stmt : α) :
    stmt ∈ rel.language ↔ ∃ wit, (stmt, wit) ∈ rel

@[simp]
theorem acceptRejectRel_language : acceptRejectRel.language = { true }

theorem cast_injective : Function.Injective (ChallengeIdx.cast hn hSpec)

@[simp]
theorem Ici_zero : Ici (0 : Fin (n + 1)) = univ

theorem johnson_bound_alphabet_free [Field F] [DecidableEq F]
  {B : Finset (Fin n → F)}
  {v : Fin n → F}
  {e : ℕ}
  :
  let d := sInf { d | ∃ u ∈ B, ∃ v ∈ B, u ≠ v ∧ hammingDist u v = d }
  let q : ℚ := Fintype.card F
  let frac := q / (q - 1)
  e ≤ n - ((n * (n - d)) : ℝ).sqrt
  →
  (B ∩ ({ x | Δ₀(x, v) ≤ e } : Finset _)).card ≤ q * d * n

lemma algebraMap_succ_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : BTField (k - 1)) :
  letI instAlgebra := binaryAlgebraTower (l:=k-1) (r:=k) (h_le:=by omega)
  algebraMap (BTField (k - 1)) (BTField k) x = ⋘ 0, x ⋙

lemma proximity_gap
  {F : Type} [Field F] [Fintype F] [DecidableEq F]
  {ι : Type} [Fintype ι] [Nonempty ι] {φ : ι ↪ F}
  {degree m : ℕ} {δ : ℝ≥0} {f : Fin m → ι → F} {GenFun : F → Fin m → F}
  (h : ∀ (hδLe : δ < 1 - Bstar (LinearCode.rate (code φ degree))) {f : Fin m → ι → F},
        Pr_{
          let r ← $ᵖ F}[δᵣ((fun x => ∑ j : Fin m, (GenFun r j) * f j x), code φ degree) ≤ (δ : ℝ)]
            > ENNReal.ofReal (proximityError F degree (LinearCode.rate (code φ degree)) δ m)) :

        ∃ S : Finset ι,
          S.card ≥ (1 - δ) * (Fintype.card ι) ∧
        ∃ u : (ι → F),
          u ∈ (code φ degree) ∧ ∀ i : Fin m, ∀ x ∈ S, f i x = u x

@[simp]
theorem hflatten_one {n : Fin 1 → ℕ} {α : (i : Fin 1) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin 1) → (j : Fin (n i)) → α i j} : hflatten v = v 0

theorem insertNth_right_injective :
    Injective (Finsupp.insertNth p y : (Fin n →₀ M) → Fin (n + 1) →₀ M)

theorem zero_mul {a : AssocNat} : 0 * a = 0

lemma concrete_mul_comm
  {h_k : k > 0} (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a b : ConcreteBTField k) :
  concrete_mul a b = concrete_mul b a

@[simp]
theorem sumExceptFirst'_degree_le (n : ℕ) (h : n > 0) (D : Fin (n - 1) → Finset R)
    (p : MvPolynomial (Fin n) R) : (sumExceptFirst' n h D p).degree ≤ p.degreeOf ⟨0, h⟩

@[simp]
theorem seqCompose_embedSum {m : ℕ} {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    {T : ∀ i, FullTranscript (pSpec i)} (i : Fin m) (j : Fin (n i)) :
    seqCompose T (Fin.embedSum i j) = cast (by simp) (T i j)

@[simp]
theorem tail_vcons (a : α) (v : Fin n → α) : tail (a ::ᵛ v) = v

@[simp]
theorem cast_id : FullTranscript.cast rfl rfl = (id : pSpec₁.FullTranscript → _)

@[simp]
lemma seqCompose_zero
    (Stmt : Fin 1 → Type)
    {ιₛ : Fin 1 → Type} (OStmt : (i : Fin 1) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (V : (i : Fin 0) → OracleVerifier oSpec
      (Stmt i.castSucc) (OStmt i.castSucc) (Stmt i.succ) (OStmt i.succ) (pSpec i)) :
    seqCompose Stmt OStmt V = OracleVerifier.id

lemma liftF_liftF'_of_lt (h : m < n) : liftF (liftF' (n := n) f) m = f m

theorem finrank_degreeLT_n (n : ℕ) : Module.finrank L (L⦃< n⦄[X]) = n

@[simp]
theorem dappend_right {motive : Fin (m + n) → Sort u} (u : (i : Fin m) → motive (castAdd n i))
    (v : (i : Fin n) → motive (natAdd m i)) (i : Fin n) :
    dappend (motive := motive) u v (natAdd m i) = v i

lemma towerRingHomForwardMap_backwardMap_eq (k : ℕ) (x : BTField k) :
  towerRingHomForwardMap (k:=k) (towerRingHomBackwardMap (k:=k) x) = x

theorem vflatten_eq_vappend_last {m : ℕ} {n : Fin (m + 1) → ℕ}
    {v : (i : Fin (m + 1)) → Fin (n i) → α} :
    vflatten v =
      vappend (vflatten (fun i => v i.castSucc)) (v (last _)) ∘ Fin.cast vsum_castSucc

@[grind _=_]
theorem monomialXY_def {n m : ℕ} {a : F} : monomialXY n m a = monomial m (monomial n a)

@[simp]
theorem LeafData.get_internal_ofLeft {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (idxLeft : SkeletonLeafIndex s_left) :
    (LeafData.internal left right).get (SkeletonLeafIndex.ofLeft idxLeft) =
      left.get idxLeft

@[simp]
lemma coeff_polynomialOfCoeffs_eq_coeffs'' :
  (polynomialOfCoeffs coeffs).coeff = Fin.liftF coeffs

nonpos_iff_eq_zero in Mathlib.Algebra.Order.Monoid.Canonical.Defs

@[simp]
theorem runWithOracle_failure (f : spec.FunctionType) :
    runWithOracle f (failure : OracleComp spec α) = none

theorem snoc_support :
    (s.snoc y).support ⊆ insert (Fin.last n) (s.support.map Fin.castSuccEmb)

lemma evenize_eval {f : Polynomial F} {s : F} :
    (evenize f).eval s = f.eval (s * s)

lemma solutionToQ_ne_zero {e k : ℕ}
  [NeZero n]
  {ωs f : Fin n → F}
  {v : Fin (2 * e + k) → F}
  (h_dist : e < Δ₀(f, 0))
  (h_sol : IsBerlekampWelchSolution e k ωs f v)
  (h_inj : Function.Injective ωs)
  : solutionToQ e k v ≠ 0

theorem Nat.shiftRight_eq_sub_mod_then_div_two_pow {n lo_len : ℕ} :
  n >>> lo_len = (n - n % 2 ^ lo_len) / 2 ^ lo_len

@[simp]
lemma list_length (k : ℕ) : (list k).length = k + 1

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

@[to_additive]
theorem prod_Iic_eq_univ (i : Fin (n + 1)) :
    ∏ j ∈ Iic i, v j = ∏ j : Fin (i + 1), v (Fin.castLE i.isLt j)

@[simp]
theorem seqCompose_succ_type {m : ℕ} {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    (seqCompose pSpec).Type = Fin.vflatten (fun i => (pSpec i).Type)

@[simp]
theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction oSpec Statement Witness).perfectCompleteness init impl rel rel

@[simp]
theorem LeafData.get_ofLeft {s_left s_right : Skeleton} {α : Type}
    (tree : LeafData α (Skeleton.internal s_left s_right))
    (idxLeft : SkeletonLeafIndex s_left) :
    tree.get (SkeletonLeafIndex.ofLeft idxLeft) =
      tree.leftSubtree.get idxLeft

@[simp] theorem BitVec.dcast_one {n m : ℕ} (h : n = m) : DCast.dcast h (1#n) = 1#m

theorem fconcat_right_injective {α : Fin n → A} {β : A} (v : (i : Fin n) → F (α i)) :
    Function.Injective (fconcat v : F β → (i : Fin (n + 1)) → F (vconcat α β i))

@[simp]
lemma seqCompose_succ {m : ℕ} (Stmt : Fin (m + 2) → Type)
    {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (V : (i : Fin (m + 1)) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i)) :
    seqCompose Stmt V = append (V 0) (seqCompose (Stmt ∘ Fin.succ) (fun i => V (Fin.succ i)))

theorem findSum_of_le_sum {l : List ℕ} {j : ℕ} (h : j < l.sum) : ∃ n, findSum l j = some n

theorem singleton_bound_linear [CommRing F] [StrongRankCondition F]
    (LC : LinearCode ι F) :
    Module.finrank F LC ≤ card ι - (Code.dist LC.carrier) + 1

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

theorem folding_listdecoding_if_genMutualCorrAgreement
  {S : Finset ι} {φ : ι ↪ F} [Smooth φ] {k m : ℕ}
  {S' : Finset (indexPowT S φ 0)} {φ' : (indexPowT S φ 0) ↪ F}
  [∀ i : ℕ, Fintype (indexPowT S φ i)] [DecidableEq (indexPowT S φ 0)] [Smooth φ']
  [h : ∀ {f : (indexPowT S φ 0) → F}, DecidableBlockDisagreement 0 k f S' φ']
  [∀ i : ℕ, Neg (indexPowT S φ i)]
  {C : Set ((indexPowT S φ 0) → F)} (hcode : C = smoothCode φ' m) (hLe : k ≤ m)
  {δ : ℝ≥0}
  {params : GenMutualCorrParams S φ k} :

  -- necessary typeclasses of underlying domain (ιᵢ)^2ʲ regarding finiteness,
  -- non-emptiness and smoothness
    let _ : ∀ j : Fin (k + 1), Fintype (indexPowT S φ j) := params.inst1
    let _ : ∀ j : Fin (k + 1), Nonempty (indexPowT S φ j) := params.inst2

    Pr_{let αs ←$ᵖ (Fin k → F)}[ -- for every function `f : ι → F` and
                      ∀ (f : (indexPowT S φ 0) → F),
                      -- `hδLe` : `δ ∈ (0, max_{j ∈ [0,k]} BStar(Cⱼ, parℓ = 2))`
                       (0 < δ ∧ δ < 1 - Finset.univ.sup
                        (fun j => params.BStar j (params.Gen_α j).C (params.Gen_α j).parℓ)) →

                      let listBlock : Set ((indexPowT S φ 0) → F) := Λᵣ(0, k, f, S', C, hcode, δ)
                      let fold := fold_k f αs hLe
                      let foldSet := fold_k_set listBlock αs hLe
                      let kFin : Fin (k + 1) := ⟨k, Nat.lt_succ_self k⟩
                      let Cₖ := (params.Gen_α kFin).C
                      let listHamming := relHammingBall Cₖ fold δ

                      foldSet ≠ listHamming
                    ] < (∑ i : Fin (k + 1),
                          params.errStar i (params.Gen_α i).C (params.Gen_α i).parℓ δ)

theorem drop_eq_rtake' {α : Sort*} (m : ℕ) (h : m ≤ n) (v : Fin n → α) :
    drop m h v = rtake (n - m) (by omega) v

omit [Finite F] in
@[simp]
lemma range_lem₁ {i : Fin (k + 1)} :
    [FinalOracleStatement D x s]ₒ.range ⟨i.1, Nat.lt_succ_of_lt i.2⟩ = F

@[simp]
theorem snoc_init_self : snoc (init t) (t (Fin.last n)) = t

lemma erase_even_def {s : Finset ℕ} :
    erase_even s = s.filter Odd

@[simp]
lemma support_polynomialOfCoeffs : (polynomialOfCoeffs coeffs).support =
  Finset.map ⟨Fin.val, Fin.val_injective⟩ {i | coeffs i ≠ 0}

lemma combine_theorem
  {φ : ι ↪ F} {dstar m degree : ℕ}
  (fs : Fin m → ι → F) (degs : Fin m → ℕ) (hdegs : ∀ i, degs i ≤ dstar)
  (δ : ℝ) (hδPos : δ > 0)
  (hδLt : δ < (min (1 - Bstar (rate (code φ degree)))
                   (1 - (rate (code φ degree)) - 1 / Fintype.card ι)))
  (hProb : Pr_{ let r ← $ᵖ F}[δᵣ((combine φ dstar r fs degs), (code φ dstar)) ≤ δ] >
    ENNReal.ofReal (proximityError F dstar (rate (code φ degree)) δ (m * (dstar + 1) - ∑ i, degs i))) :
      ProximityGap.correlatedAgreement (code φ degree) ⟨δ, by linarith⟩ fs

lemma powContraction_is_right_inverse_to_linearMvExtension
  (p : Polynomial.degreeLT F (2^m)) :
    powContraction.comp linearMvExtension p = p

lemma full_row_rank_via_rank_subLeftFull (h : m ≤ n) :
   (subLeftFull U (Fin.castLE h)).rank = m → U.rank = m

Fin.val_injective in Mathlib.Data.Fin.Basic

theorem liftContext_knowledgeSoundness [Inhabited InnerStmtOut] [Inhabited InnerWitIn]
    {outerRelIn : Set (OuterStmtIn × OuterWitIn)} {outerRelOut : Set (OuterStmtOut × OuterWitOut)}
    {innerRelIn : Set (InnerStmtIn × InnerWitIn)} {innerRelOut : Set (InnerStmtOut × InnerWitOut)}
    {knowledgeError : ℝ≥0}
    {stmtLens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut}
    {witLens : Witness.InvLens OuterStmtIn OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    (V : Verifier oSpec InnerStmtIn InnerStmtOut pSpec)
    [lensKS : Extractor.Lens.IsKnowledgeSound outerRelIn innerRelIn outerRelOut innerRelOut
      (V.compatStatement stmtLens) (fun _ _ => True) ⟨stmtLens, witLens⟩]
    (h : V.knowledgeSoundness init impl innerRelIn innerRelOut knowledgeError) :
      (V.liftContext stmtLens).knowledgeSoundness init impl outerRelIn outerRelOut
        knowledgeError

protected lemma roots_of_eloc_poly {x : F}
  (h : (ElocPoly n ωs f p).eval x = 0) :
  ∃ i, i < n ∧ f i ≠ p.eval (ωs i)

@[simp]
theorem BTField.RingHom_eq_of_dest_AdjoinRoot_eq (k m : ℕ) :
  (BTField k →+* BTField (m+1)) = (BTField k →+* (AdjoinRoot (poly m)))

theorem degreeOf_X_of_ne (i j : σ) (h : i ≠ j) : degreeOf i (X (R := R) j) = 0

@[simp]
theorem LeafData.optionComposeBuild_leaf {α} (a : α)
    (compose : α → α → Option α) :
    (LeafData.leaf a).optionComposeBuild compose = FullData.leaf (.some a)

theorem sum_of_pow_exp_of_2 {F : Type*} [Field F]
  (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y)
  (i : ℕ) : ∀ (a b c : F), a + b = c → a^(2^i) + b^(2^i) = c^(2^i)

@[to_additive (attr := simp) vsum_zero]
lemma vprod_zero [CommMonoid α] {a : Fin 0 → α} : vprod a = 1

@[simp]
lemma E_and_Q_to_a_solution_coeff
  : E_and_Q_to_a_solution e E Q i = if i < e then E.coeff i else Q.coeff (i - e)

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)

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]
protected lemma elocPoly_zero : ElocPoly 0 ωs f p = 1

theorem rsum_eq_t1_square_aux
  {curBTField : Type*} [Field curBTField] -- curBTField ≃ 𝔽_{2^{2^k}}
  (u : curBTField) -- here u is already lifted to curBTField
  (k : ℕ)
  (x_pow_card : ∀ (x : curBTField), x ^ (2 ^ (2 ^ (k))) = x)
  (u_ne_zero : u ≠ 0)
  (trace_map_prop : TraceMapProperty curBTField u k):
   ∑ j ∈ Finset.Icc 1 (2 ^ (k)), u ^ (2 ^ 2 ^ (k) - 2 ^ j) = u

lemma Wᵢ_vanishing (i : Fin r) :
  ∀ u ∈ U 𝔽q β i, (W 𝔽q β i).eval u = 0

lemma H_tilde_equiv_H_tilde' (H : F[X][Y]) : (H_tilde' H).map univPolyHom = H_tilde H

private lemma almost_johnson_choose_2_elimed [Zero F]
  (h_n : 0 < n)
  (h_B : 2 ≤ B.card)
  (h_card : 2 ≤ Fintype.card F)
  :
  (k B * (k B - 1)  +
    (B.card - k B) * ((B.card - k B)/(Fintype.card F-1) - 1))
  ≤
  B.card * (B.card - 1) * (n - d B)/n

theorem ConcreteBTFieldAlgebra_apply_assoc (l mid r : ℕ)
    (h_l_le_mid : l ≤ mid) (h_mid_le_r : mid ≤ r) :
    ∀ x : ConcreteBTField l,
    (@ConcreteBTFieldAlgebra (l:=l) (r:=r) (h_le:=by
      exact Nat.le_trans h_l_le_mid h_mid_le_r)).algebraMap x =
    (@ConcreteBTFieldAlgebra (l:=mid) (r:=r) (h_le:=h_mid_le_r)).algebraMap
      ((@ConcreteBTFieldAlgebra (l:=l) (r:=mid) (h_le:=h_l_le_mid)).algebraMap x)

theorem drop_eq_rtake (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    drop m h v = fun i => dcast (by simp [Fin.cast]; omega) (rtake (n - m) (by omega) v i)

private lemma really_glorious_lemma {f f' : Polynomial F} (h : 2 * f = 2 * f') :
    f = f'

theorem coeff_of_toMvPolynomial_eq_coeff_of_MlPoly (p : MlPoly R n) (m : Fin n →₀ ℕ) :
  coeff m (toMvPolynomial p) =
    if h_binary: (∀ j: Fin n, m j ≤ 1) then
      let i_of_m: ℕ := Nat.binaryFinMapToNat (m:=m) (h_binary:=h_binary)
      p[i_of_m]
    else
      0

@[simp]
lemma constantCode_eq_ofNat_zero_iff [Nonempty ι] :
  constantCode x ι = 0 ↔ x = 0

theorem rbrKnowledgeSoundnessOneShot_implies_rbrKnowledgeSoundness
    {relIn : Set (StmtIn × WitIn)} {relOut : Set (StmtOut × WitOut)}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec}
    {rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0}
    (hInit : init.neverFails)
    (h : verifier.rbrKnowledgeSoundnessOneShot init impl relIn relOut rbrKnowledgeError) :
    verifier.rbrKnowledgeSoundness init impl relIn relOut rbrKnowledgeError

lemma add_shiftRight_distrib {n m k : ℕ} (h_and_zero : n &&& m = 0):
  (n + m) >>> k = (n >>> k) + (m >>> k)

theorem append_perfectCompleteness
    (R₁ : OracleReduction oSpec Stmt₁ OStmt₁ Wit₁ Stmt₂ OStmt₂ Wit₂ pSpec₁)
    (R₂ : OracleReduction oSpec Stmt₂ OStmt₂ Wit₂ Stmt₃ OStmt₃ Wit₃ pSpec₂)
    (h₁ : R₁.perfectCompleteness init impl rel₁ rel₂)
    (h₂ : R₂.perfectCompleteness init impl rel₂ rel₃) :
      (R₁.append R₂).perfectCompleteness init impl rel₁ rel₃

lemma Oracle.containsCache_of_cache {ι : Type} {spec : OracleSpec ι}
    [(i : ι) → Inhabited (OracleSpec.range spec i)]
    (cache : spec.QueryCache) :
    ∃ (f : spec.FunctionType), Oracle.containsCache f cache

lemma geometric_sum_units {F : Type*} [Field F] [DecidableEq F] {r : Fˣ} {a : ℕ} :
  ∑ j ∈ range (a + 1), (r ^ j : F) =
    if r = 1 then (a + 1 : F)
    else (1 - r ^ (a + 1)) / (1 - r)

@[simp]
lemma addSalt_Type (i : Fin n) :
    (pSpec.addSalt Salt).«Type» i = match hDir : pSpec.dir i with

theorem append_knowledgeSoundness (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ 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₂)

omit [Finite F] in
lemma one_in_doms (i : ℕ) : 1 ∈ evalDomain D i

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

lemma linsolve_is_berlekamp_welch_solution
  (h_linsolve : linsolve (BerlekampWelchMatrix e k ωs f) (Rhs e ωs f) = some v)
  : IsBerlekampWelchSolution e k ωs f v

@[simp]
lemma possibleRelHammingDists_subset_relHammingDistRange :
  possibleRelHammingDists C ⊆ relHammingDistRange ι

theorem LeafData.composeBuild_getRootValue {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (compose : α → α → α) :
    ((LeafData.internal left right).composeBuild compose).getRootValue =
      compose (left.composeBuild compose).getRootValue (right.composeBuild compose).getRootValue

private lemma Bi_biUnion_F2i :
  Bi B i = Finset.univ.biUnion (F2i B i)

theorem last_nonzero_some [LawfulBEq R] {p : UniPoly R} {i} (hi : i < p.size) (h : p[i] ≠ 0) :
  ∃ k, p.last_nonzero = some k

@[grind _=_]
lemma degreeY_as_weighted_deg (hf : f ≠ 0) :
  natDegreeY f = natWeightedDegree f 0 1

omit [CharP L 2] [DecidableEq 𝔽q] h_β₀_eq_1 [NeZero 𝓡] in
lemma firstOracleWitnessConsistencyProp_relay_preserved (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) (wit : Witness (L := L) 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j) :
    firstOracleWitnessConsistencyProp 𝔽q β wit.t (getFirstOracle 𝔽q β oStmt) =
    firstOracleWitnessConsistencyProp 𝔽q β wit.t
      (getFirstOracle 𝔽q β (mapOStmtOutRelayStep 𝔽q β i hNCR oStmt))

omit [NoZeroDivisors 𝔽] in
lemma splitNth_def (n : ℕ) (f : 𝔽[X]) [inst : NeZero n] :
    f =
      ∑ i : Fin n,
        (Polynomial.X ^ i.1) *
          Polynomial.eval₂ Polynomial.C (Polynomial.X ^ n) (splitNth f n i)

theorem BitVec.eq_append_iff_extract {lo_size hi_size : ℕ} (lo : BitVec lo_size)
  (hi : BitVec hi_size) (h_hi_gt_0 : hi_size > 0) (h_lo_gt_0 : lo_size > 0)
  (x : BitVec (hi_size + lo_size)) : x = dcast (by rfl) (BitVec.append (msbs:=hi) (lsbs:=lo)) ↔
  hi = dcast (by omega) (BitVec.extractLsb (hi:=hi_size + lo_size - 1) (lo:=lo_size) x) ∧
  lo = dcast (by omega) (BitVec.extractLsb (hi:=lo_size - 1) (lo:=0) x)

lemma rank_eq_dim_fromColGenMat [CommRing F] {G : Matrix κ ι F} :
  G.rank = dim (fromColGenMat G)

@[simp]
theorem removeNth_update : removeNth p (update s p y) = removeNth p s

theorem cast_eq_dcast {m n : ℕ} (h : m = n) (a : Fin m) :
    Fin.cast h a = dcast h a

@[simp]
theorem leftpad_apply_ge (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : n - m ≤ i.val) : leftpad n a v i = v ⟨i.val - (n - m), by omega⟩

lemma NTTStage_correctness (i : Fin (ℓ))
    (input_buffer : Fin (2 ^ (ℓ + R_rate)) → L) (original_coeffs : Fin (2 ^ ℓ) → L) :
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (evaluation_buffer:=input_buffer)
      (original_coeffs:=original_coeffs) (i := ⟨i.val+1, by omega⟩) →
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (evaluation_buffer:=NTTStage 𝔽q β h_ℓ_add_R_rate
      ⟨i, by omega⟩ input_buffer) (original_coeffs:=original_coeffs) ⟨i, by omega⟩

@[simp]
theorem append_snd (T₁ : FullTranscript pSpec₁) (T₂ : FullTranscript pSpec₂) :
    (T₁ ++ₜ T₂).snd = T₂

@[simp]
theorem simulateQ_map_fst (oa : OracleComp spec α) :
    Prod.fst <$> (simulateQ loggingOracle oa).run = oa

lemma getMiddleBits_eq_mod {n offset len : ℕ} :
  getMiddleBits offset len n = (n >>> offset) % (2 ^ len)

@[simp]
theorem hcons_one {β : Fin (n + 1) → Sort u} (a : α) (v : (i : Fin (n + 1)) → β i) :
    hcons a v 1 = cast (vcons_succ α β 0).symm (v 0)

lemma sum_inv_Z_next_eq
  (k : ℕ)
  (prev : ConcreteBTFStepResult (k := k)) :
  letI : Field (ConcreteBTField k) := mkFieldInstance (prev.toConcreteBTFieldProps)
  letI : Field (ConcreteBTField (k + 1)) := mkFieldInstance (k:=k+1)
    (props:=liftBTFieldProps (k:=k) (prevBTFResult:=prev))
  letI : Algebra (ConcreteBTField k) (ConcreteBTField (k + 1)) :=
    instAlgebraLiftConcreteBTField k prev
  Z (k + 1) + (Z (k + 1))⁻¹ = (algebraMap (ConcreteBTField k) (ConcreteBTField (k + 1))) (Z k)

theorem one_le_two_pow_n (n : ℕ) : 1 ≤ 2 ^ n

private lemma sum_add_one {i : Fin (k + 1)} :
  ∑ j' ∈ finRangeTo (i.1 + 1), (s j').1 = (∑ j' ∈ finRangeTo i.1, (s j').1) + (s i).1

@[simp]
lemma seqCompose_succ {m : ℕ}
    (Stmt : Fin (m + 2) → Type)
    {ιₛ : Fin (m + 2) → Type} (OStmt : (i : Fin (m + 2)) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    (Wit : Fin (m + 2) → Type)
    {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (R : (i : Fin (m + 1)) →
      OracleReduction oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Wit i.castSucc)
        (Stmt i.succ) (OStmt i.succ) (Wit i.succ) (pSpec i)) :
    seqCompose Stmt OStmt Wit R =
      append (R 0) (seqCompose (Stmt ∘ Fin.succ) (fun i => OStmt (Fin.succ i)) (Wit ∘ Fin.succ)
        (Oₛ := fun i => Oₛ (Fin.succ i)) (Oₘ := fun i => Oₘ (Fin.succ i))
          (fun i => R (Fin.succ i)))

lemma discr_of_irred_components_nonzero
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : ∃ x₀,
      ∀ R ∈ (irreducible_factorization_of_gs_solution h_gs).choose_spec.choose,
      Bivariate.evalX x₀ (Bivariate.discr_y R) ≠ 0

@[simp]
lemma natDegree_polynomialOfCoeffs_deg_lt_deg
  [NeZero deg] {coeffs : Fin deg → F} :
  (polynomialOfCoeffs coeffs).natDegree < deg

@[simp]
theorem shift_left_mem {s : Finset ℕ} {d : ℕ} : d ∈ shift_left s ↔ (d + 1) ∈ s

theorem dcast_symm (ha : a = a') (hb : dcast ha b = b') : dcast (ha.symm) b' = b

@[simp]
theorem hflatten_succ {m : ℕ} {n : Fin (m + 1) → ℕ}
    {α : (i : Fin (m + 1)) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin (m + 1)) → (j : Fin (n i)) → α i j} :
    hflatten v = happend (v 0) (hflatten (fun i => v i.succ))

@[csimp]
theorem dappend_eq_addCases : @dappend = @addCases

@[grind _=_]
theorem monomialXY_mul_monomialXY {n m p q : ℕ} {a b : F} :
    monomialXY n m a * monomialXY p q b = monomialXY (n + p) (m + q) (a * b)

theorem degreeOf_coeff_finSuccEquivNth (f : MvPolynomial (Fin (n + 1)) R) (j : Fin n) (i : ℕ) :
    degreeOf j (Polynomial.coeff (finSuccEquivNth R p f) i) ≤ degreeOf (p.succAbove j) f

@[simp]
theorem zero_vappend {u : Fin 0 → α} (v : Fin n → α) :
    vappend u v = v ∘ Fin.cast (Nat.zero_add n)

lemma qMap_total_fiber_repr_coeff (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i.val + steps ≤ ℓ)
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩))
    (k : Fin (2 ^ steps)) :
    let x := qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩)
      (steps := steps)
      (h_i_add_steps := by simp only; exact fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps) (y := y) k
    let basis_y := sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩)
      (h_i := by simp only; exact fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps)
    let y_coeffs := basis_y.repr y
    ∀ j, -- j refers to bit index of the fiber point x
      ((sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (by simp only; omega)).repr x) j
      = fiber_coeff (i := i) (steps := steps) (j := j) (elementIdx := k)
        (y_coeffs := y_coeffs)

@[simp]
lemma List.get_nil (i : Fin 0) (a : α) : [].get i = a

@[grind _=_]
lemma weightedDegree_eq_natWeightedDegree {u v : ℕ} :
  f ≠ 0 → weightedDegree f u v = natWeightedDegree f u v

lemma pow_inj {i : ℕ} {a b : Fin (2 ^ (n - i))} :
    i ≤ n → (DIsCyclicC.gen.1 ^ 2 ^ i) ^ a.1 = (DIsCyclicC.gen.1 ^ 2 ^ i) ^ b.1 → a = b

theorem linear_map_of_comp_to_linear_map_of_eval (f : L[X])
  (h_f_linear : IsLinearMap (R := Fq) (M := L[X]) (M₂ := L[X])
    (f := fun inner_p ↦ f.comp inner_p)) :
    IsLinearMap (R := Fq) (M := L) (M₂ := L) (f := fun x ↦ f.eval x)

private lemma sum_K_eq_card : ∑ (α : F), K B i α = B.card

theorem le_iff_toNat_le (a b : AssocNat) : a ≤ b ↔ toNat a ≤ toNat b

theorem vcons_eq_const (a : α) : a ::ᵛ (fun _ : Fin n => a) = fun _ => a

lemma schwartz_zippel_of_fintype {p : MvPolynomial σ R} (hp : p ≠ 0) (S : σ → Finset R) :
    #{x ∈ S ^^ σ | eval x p = 0} / ∏ i, (#(S i) : ℚ≥0) ≤ ∑ i, (p.degreeOf i / #(S i) : ℚ≥0)

lemma Polishchuk_Spielman {F : Type} [Field F]
  (a_x a_y b_x b_y : ℕ) (n_x n_y : ℕ+)
  (h_bx_ge_ax : b_x ≥ a_x) (h_by_ge_ay : b_y ≥ a_y)
  (A B : F[X][Y])
  (h_f_degX : a_x ≥ Bivariate.degreeX A) (h_g_degX : b_x ≥ Bivariate.degreeX B)
  (h_f_degY : a_y ≥ natDegreeY A) (h_g_degY : b_y ≥ natDegreeY B)
  (P_x P_y : Finset F) [Nonempty P_x] [Nonempty P_y]
  (quot_X : F → F[X]) (quot_Y : F → F[X])
  (h_card_Px : n_x ≤ P_x.card) (h_card_Py : n_y ≤ P_y.card)
  (h_quot_X : ∀ y ∈ P_y,
    (quot_X y).natDegree ≤ (b_x - a_x) ∧ Bivariate.evalY y B = (quot_X y) * (Bivariate.evalY y A))
  (h_quot_Y : ∀ x ∈ P_x,
    (quot_Y x).natDegree ≤ (b_y - a_y) ∧ Bivariate.evalX x B = (quot_Y x) * (Bivariate.evalX x A))
  (h_le_1 : 1 > (b_x : ℚ) / (n_x : ℚ) + (b_y : ℚ) / (n_y : ℚ))
  : ∃ P : F[X][Y], B = P * A
    ∧ Bivariate.degreeX P ≤ b_x - a_x ∧ natDegreeY P ≤ b_y - a_y
    ∧ (∃ Q_x : Finset F, Q_x.card ≥ n_x - a_x ∧ Q_x ⊆ P_x ∧
        ∀ x ∈ Q_x, Bivariate.evalX x P = quot_Y x)
    ∧ (∃ Q_y : Finset F, Q_y.card ≥ n_y - a_y ∧ Q_y ⊆ P_y ∧
        ∀ y ∈ Q_y, Bivariate.evalX y P = quot_X y)

lemma getBit_eq_succ_getBit_of_mul_two {n k : ℕ} : getBit (k+1) (2*n) = getBit k n

@[ext]
theorem ext' {a b : AssocNat} (h : a 0 = b 0) : a = b

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

theorem decoder_eq_some {e k : ℕ} [NeZero n] {ωs f : Fin n → F} {p : Polynomial F}
  (he : 2 * e < n - k + 1)
  (hn : k ≤ n)
  (h_inj : Function.Injective ωs)
  (h_deg : p.natDegree < k)
  (h_dist : Δ₀(f, p.eval ∘ ωs) ≤ e)
  : decoder e k ωs f = some p

theorem multilinearBasis_apply (r : ℕ) : ∀ l : ℕ, (h_le : l ≤ r) → ∀ (j : Fin (2  ^ (r - l))),
  multilinearBasis (l:=l) (r:=r) (h_le:=h_le) j =
    (Finset.univ : Finset (Fin (r - l))).prod (fun i =>
      (binaryAlgebraTower (l:=l + i + 1) (r:=r) (h_le:=by omega)).algebraMap (
        (𝕏 (l + i)) ^ (Nat.getBit i j)))

theorem join_eq_iff_dcast_extractLsb {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
  (hi_btf lo_btf : ConcreteBTField (k - 1)) :
  x = 《 hi_btf, lo_btf 》 ↔
  (hi_btf = dcast (h_sub_middle h_pos) (BitVec.extractLsb (hi := 2 ^ k - 1) (lo := 2 ^ (k - 1)) x) ∧
  lo_btf = dcast (h_middle_sub) (BitVec.extractLsb (hi := 2 ^ (k - 1) - 1) (lo := 0) x))

theorem setWidth_eq_ofNat_mod {n num_bits : Nat} (x : BitVec n) :
  BitVec.setWidth num_bits x = BitVec.ofNat num_bits (x.toNat % 2 ^ num_bits)

theorem non_zero_divisors_iff (M₀ : Type*) [Mul M₀] [Zero M₀] :
    NoZeroDivisors M₀ ↔ ∀ {a b : M₀}, a * b = 0 → a = 0 ∨ b = 0

@[to_additive]
theorem prod_Iic_succ (i : Fin n) :
    ∏ j ∈ Iic i.succ, v j = (∏ j ∈ Iic i.castSucc, v j) * v i.succ

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

Fin.isLt in Init.Prelude

lemma matchSize_size {p q : UniPoly Q} :
    let (p', _) := Array.matchSize p q 0
    p'.size = max p.size q.size

omit [Finite R] in
theorem projection_injective
    (C : Set (n → R))
    (nontriv : ‖C‖₀ ≥ 1)
    (S : Finset n)
    (hS : card S = card n - (‖C‖₀ - 1))
    (u v : n → R)
    (hu : u ∈ C)
    (hv : v ∈ C) : projection S u = projection S v → u = v

@[simp]
theorem reduction_completeness (h : init.neverFails) [Nonempty σ] :
    (reduction oSpec Statement pred).perfectCompleteness init impl
    (relIn Statement pred) (relOut Statement)

@[simp]
theorem runWithOracle_freeMonad_query_roll (f : spec.FunctionType)
    (i : ι) (t : spec.domain i)
    (r : (spec.range i) → FreeMonad (spec.OracleQuery) (Option α)) :
    runWithOracle f (FreeMonad.roll (query i t) r) = runWithOracle f (r (f i t))

lemma aeval_eq {A : Type y} [CommSemiring A] [Algebra R A] (f : P →ₐ[R] A) :
    f = aeval (fun s => f (X s))

@[simp]
lemma divide_by_2_empty :
    divide_by_2 ∅ = ∅

theorem finSuccEquivNth_rename_finSuccEquivNth (e : σ ≃ Fin n) (φ : MvPolynomial (Option σ) R) :
    ((finSuccEquivNth R p) ((rename ((Equiv.optionCongr e).trans (_root_.finSuccEquiv' p).symm)) φ))
      = Polynomial.map (rename e).toRingHom (optionEquivLeft R σ φ)

@[simp] theorem zero_add {a : AssocNat} : 0 + a = a

private lemma Fis_cover_B : B = Finset.univ.biUnion (Fi B i)

theorem fappend₂_ext {α₁ : Fin m → A} {α₂ : Fin m → B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (u₁ u₂ : (i : Fin m) → F₂ (α₁ i) (α₂ i)) (v₁ v₂ : (i : Fin n) → F₂ (β₁ i) (β₂ i)) :
    fappend₂ (F := F₂) u₁ v₁ = fappend₂ (F := F₂) u₂ v₂ ↔ u₁ = u₂ ∧ v₁ = v₂

@[simp]
lemma lin_shift_hamming_distance [Field F] {x₁ x₂ v : Fin n → F}
  :
  Δ₀(x₁ - v, x₂ - v) = Δ₀(x₁, x₂)

theorem singleton_append (a : α) (v : Fin n → α) :
    vappend !v[a] v = vcons a v ∘ Fin.cast (Nat.add_comm _ n)

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

lemma eq_zero_or_eq_one_of_lt_two {n : ℕ} (h_lt : n < 2) : n = 0 ∨ n = 1

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

private lemma choose_2_eq_half_f :
  choose_2 = (1/2) * f

theorem vcons_eq_cons (a : α) (v : Fin n → α) : a ::ᵛ v = cons a v

theorem liftContext_rbr_knowledgeSoundness [Inhabited InnerWitIn]
    {rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0}
    {stmtLens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut}
    {witLens : Witness.InvLens (OuterStmtIn × ∀ i, OuterOStmtIn i)
                            OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    (V : OracleVerifier oSpec InnerStmtIn InnerOStmtIn InnerStmtOut InnerOStmtOut pSpec)
    [lensKS : Extractor.Lens.IsKnowledgeSound
      outerRelIn innerRelIn outerRelOut innerRelOut
      (V.toVerifier.compatStatement stmtLens) (fun _ _ => True) ⟨stmtLens, witLens⟩]
    (h : V.rbrKnowledgeSoundness init impl innerRelIn innerRelOut rbrKnowledgeError) :
      (V.liftContext stmtLens).rbrKnowledgeSoundness init impl outerRelIn outerRelOut
        rbrKnowledgeError

lemma fold_f_g_poly
  {S : Finset ι} {φ : ι ↪ F} {k m : ℕ}
  {φ_0 : (indexPowT S φ 0) ↪ F} {φ_k : (indexPowT S φ k) ↪ F}
  [Fintype (indexPowT S φ 0)] [DecidableEq (indexPowT S φ 0)] [Smooth φ_0]
  [Fintype (indexPowT S φ k)] [DecidableEq (indexPowT S φ k)] [Smooth φ_k]
  [∀ i : ℕ, Neg (indexPowT S φ i)]
  (αs : Fin k → F) (hk : k ≤ m)
  (f : smoothCode φ_0 m) (g : smoothCode φ_k (m-k)) :
  let fPoly

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_r_succ_bound {h_ℓ_add_R_rate : ℓ + 𝓡 < r} (i : Fin r) (h_i : i + 1 < ℓ + 𝓡)
    : i + 1 < r

lemma concrete_mul_right_distrib0 (a b c : ConcreteBTField 0) :
  concrete_mul (a + b) c = concrete_mul a c + concrete_mul b c

private lemma solutionToE_from_E
  (h_p_deg : p.natDegree < k)
  (h_dist : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  : solutionToE e k (E_and_Q_to_a_solution e (E ωs f p e) (Q ωs f p e)) = E ωs f p e

theorem unique_linear_decomposition_succ (k : ℕ) :
  letI : Algebra (ConcreteBTField k) (ConcreteBTField (k+1)) :=
    ConcreteBTFieldAlgebra (l:=k) (r:=k+1) (h_le:=by omega)
  ∀ (x : ConcreteBTField (k+1)), ∃! (p : ConcreteBTField k × ConcreteBTField k),
    x = join_via_add_smul (k+1) (by omega) p.1 p.2

theorem liftContext_completeness
    (h : R.completeness init impl innerRelIn innerRelOut completenessError) :
      (R.liftContext lens).completeness init impl outerRelIn outerRelOut completenessError

theorem is_prime : Nat.Prime fieldSize

lemma evenPart_even {f : Polynomial F} :
    EvenPoly (evenPart f)

theorem seqCompose_completeness (hInit : init.neverFails)
    (rel : (i : Fin (m + 1)) → Set ((Stmt i × ∀ j, OStmt i j) × Wit i))
    (R : ∀ i, OracleReduction oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Wit i.castSucc)
      (Stmt i.succ) (OStmt i.succ) (Wit i.succ) (pSpec i))
    (completenessError : Fin m → ℝ≥0)
    (h : ∀ i, (R i).completeness init impl (rel i.castSucc) (rel i.succ) (completenessError i)) :
      (OracleReduction.seqCompose Stmt OStmt Wit R).completeness
        init impl (rel 0) (rel (Fin.last m)) (∑ i, completenessError i)

theorem succ_succ {T : Type u} [HasSucc T] [Add T] [One T] [LawfulHasSucc T] (x : T) :
    succ' (succ' x) = x + 1 + 1

theorem append_soundness {lang₁ : Set Stmt₁} {lang₂ : Set Stmt₂} {lang₃ : Set Stmt₃}
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁) (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    {soundnessError₁ soundnessError₂ : ℝ≥0}
    (h₁ : V₁.soundness init impl lang₁ lang₂ soundnessError₁)
    (h₂ : V₂.soundness init impl lang₂ lang₃ soundnessError₂) :
      (V₁.append V₂).soundness init impl lang₁ lang₃ (soundnessError₁ + soundnessError₂)

@[simp]
lemma foldl'_succ {n : ℕ} {α : Type u} (f : (i : Fin (n + 1)) → α → α) (x : α) :
    foldl' (n + 1) f x = f (last n) (foldl' n (fun i => f i.castSucc) x)

lemma mkLastOracleIndex_last : mkLastOracleIndex ℓ ϑ (Fin.last ℓ) = ℓ / ϑ - 1

theorem GF_2_one_add_one_eq_zero : (1 + 1 : GF(2)) = 0

@[simp]
theorem snoc_zero_zero : snoc (0 : Fin n →₀ M) 0 = 0

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

@[simp]
theorem cast_id : Verifier.cast rfl rfl = (id : Verifier oSpec StmtIn StmtOut pSpec₁ → _)

private lemma johnson_unrefined_by_M' [Zero F]
  (h_n : 0 < n)
  (h_B : 2 ≤ B.card)
  (h_card : 2 ≤ (Fintype.card F))
  :
  B.card * (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)
  ≤
  (Fintype.card F / (Fintype.card F - 1)) * d B/n

lemma getBit_eq_succ_getBit_of_mul_two_add_one {n k : ℕ} : getBit (k+1) (2*n + 1) = getBit k n

@[simp]
theorem dcons_one {motive : Fin (n + 2) → Sort u} (a : motive 0)
    (v : (i : Fin (n + 1)) → motive i.succ) : (a ::ᵈ⟨motive⟩ v) 1 = v 0

theorem foldRelayOracleVerifier_rbrKnowledgeSoundness
    (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
    (foldRelayOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR).rbrKnowledgeSoundness
      init impl
      (relIn := roundRelation 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑:=𝓑) i.castSucc (mp := mp))
      (relOut := roundRelation 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑:=𝓑) i.succ (mp := mp))
      (rbrKnowledgeError := fun m => foldKnowledgeError 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i ⟨m, by
        match m with
        | ⟨0, h0⟩ => nomatch h0
        | ⟨1, h1⟩ => rfl
      ⟩)

theorem zero_add {n : ℕ} (a : CNat (n + 1)) : 0 + a = a

lemma aeval_eq' {A : Type w} [CommSemiring A] [Algebra R A] (f : P →ₐ[R] A) (p : P) :
    f p = aeval (f X) p

omit [Ring Q] in
@[simp] theorem zero_def : (0 : UniPoly Q) = #[]

@[simp]
theorem oracleReduction_completeness (hInit : init.neverFails) :
    (oracleReduction oSpec OStatement).perfectCompleteness
      init impl (relIn OStatement) (relOut OStatement)

lemma h_sub_middle {k : ℕ} (h_pos : k > 0) : 2 ^ k - 1 - 2 ^ (k - 1) + 1 = 2 ^ (k - 1)

theorem liftContext_run
    {lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {outerStmtIn : OuterStmtIn} {outerWitIn : OuterWitIn}
    {P : Prover oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec} :
      (P.liftContext lens).run outerStmtIn outerWitIn
      = do
        let ⟨fullTranscript, innerCtxOut⟩ ←
          P.run.uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨fullTranscript, lens.lift (outerStmtIn, outerWitIn) innerCtxOut⟩

@[simp]
lemma seqCompose_type {m : ℕ} {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    (seqCompose pSpec).Type = Fin.vflatten (fun i => (pSpec i).Type)

@[coe]
theorem BTField_succ_eq_adjoinRoot (k : ℕ) : AdjoinRoot (poly k) = BTField (k+1)

lemma listBlock_subset_listHamming
  (i k : ℕ) {S : Finset ι} {φ : ι ↪ F} {φ' : (indexPowT S φ i) ↪ F}
  {m : ℕ} [DecidableEq F] [DecidableEq ι] [Smooth φ]
  (f : (indexPowT S φ i) → F) (S' : Finset (indexPowT S φ i))
  [h_fintype : ∀ i : ℕ, Fintype (indexPowT S φ i)] [DecidableEq (indexPowT S φ i)] [Smooth φ']
  (C : Set ((indexPowT S φ i) → F)) (hcode : C = smoothCode φ' m)
  [h_dec : DecidableBlockDisagreement i k f S' φ']
  (δ : ℝ≥0) (hδLe : δ ≤ 1) :
  Λᵣ(i, k, f, S', C, hcode, δ) ⊆ relHammingBall C f δ

private lemma johnson_condition_strong_implies_2_le_F_card
  (h_johnson : JohnsonConditionStrong B v)
  :
  2 ≤ Fintype.card F

lemma getBit_zero_eq_self {n : ℕ} (h_n : n < 2) : getBit 0 n = n

@[simp] lemma twoAdicGenerators_succ_square_eq (idx : Nat) (h : idx < twoAdicity) :
    haveI : idx + 1 < twoAdicGenerators.length

theorem foldr_split_outer {α : Type u} {β : Type v} (f : α → β → β) (init : β)
    (l : List α) (h : l ≠ []): foldr (f:=f) (init:=init) (l)
    = f (l.head (by omega)) (foldr (f:=f) (init:=init) (l.tail))

lemma evenPart_def :
  evenPart f = C (2⁻¹ : F) * (f + f.comp (-X))

theorem zero_lt_pow_n (m : ℕ) (n : ℕ) (h_m : m > 0): 0 < m^n

theorem coeff_eq_coeff [LawfulBEq R] (p : UniPoly R) (i : ℕ) :
  p.trim.coeff i = p.coeff i

Nat.zero_le in Init.Prelude

lemma toImpl_elim (p : Q[X]) :
    (p = 0 ∧ p.toImpl = #[])
  ∨ (p ≠ 0 ∧ p.toImpl = .ofFn (fun i : Fin (p.natDegree + 1) => p.coeff i))

theorem 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) :
    ∃ a b : R, s = a • pb.gen + algebraMap R S b

theorem vcons_vappend_comm (a : α) (u : Fin m → α) (v : Fin n → α) :
    vcons a (vappend u v) = (vappend (vcons a u) v) ∘ Fin.cast (Nat.succ_add m n).symm

@[simp]
theorem monomialBasis_zero {w : Vector R 0} : monomialBasis w = #v[1]

@[simp]
theorem oracleVerifier_rbrKnowledgeSoundness (hRel : ∀ stmtIn oStmtIn witOut,
      ((mapStmt stmtIn, mapOStmt embedIdx hEq oStmtIn), witOut) ∈ relOut →
      ((stmtIn, oStmtIn), mapWitInv (stmtIn, oStmtIn) witOut) ∈ relIn) :
    (oracleVerifier oSpec mapStmt embedIdx hEq).rbrKnowledgeSoundness init impl relIn relOut 0

lemma normalizedWᵢ_vanishing (i : Fin r) :
  ∀ u ∈ U 𝔽q β i, (normalizedW 𝔽q β i).eval u = 0

@[simp]
lemma coe_fn_of_coe (f : ∀ a, β a) : (f : F) = inst.equiv.invFun f

lemma rank_eq_if_subUpFull_eq (h : n ≤ m) :
   (subUpFull U (Fin.castLE h)).rank = n  → U.rank = n

theorem fcons₂_injective2 {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B} :
    Function.Injective2 (@fcons₂ A B F₂ n α₁ β₁ α₂ β₂)

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

@[simp]
theorem fcons₂_zero {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (a : F₂ α₁ α₂) (b : (i : Fin n) → F₂ (β₁ i) (β₂ i)) :
    fcons₂ (F := F₂) a b 0 = cast (by simp [Fin.vcons_zero]) a

theorem commitOracleReduction_perfectCompleteness (hInit : init.neverFails) (i : Fin ℓ)
    (hCR : isCommitmentRound ℓ ϑ i) :
    OracleReduction.perfectCompleteness
      (pSpec := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
      (relIn := foldStepRelOut (mp := mp) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i)
      (relOut := roundRelation (mp := mp) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i.succ)
      (oracleReduction := commitOracleReduction 𝔽q β (ϑ := ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hCR)
      (init := init)
      (impl := impl)

lemma oodSampling_rs_le_bound
    {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) }[ ∃ 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)
                      ] ≤ ENNReal.ofReal (((l : ℝ)^2 / 2) * (((2^m : ℝ) / Fintype.card F)^s))

theorem seqCompose_knowledgeSoundness
    (rel : (i : Fin (m + 1)) → Set (Stmt i × Wit i))
    (V : (i : Fin m) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i))
    (knowledgeError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).knowledgeSoundness init impl (rel i.castSucc) (rel i.succ) (knowledgeError i)) :
      (Verifier.seqCompose Stmt V).knowledgeSoundness init impl (rel 0) (rel (Fin.last m))
        (∑ i, knowledgeError i)

lemma num_eq_highBits_add_lowBits {n: ℕ} (numLowBits: ℕ) :
  n = getHighBits numLowBits n + getLowBits numLowBits n

@[simp]
theorem cast_completeness (ε : ℝ≥0) (hComplete : R.completeness init impl relIn relOut ε) :
    (R.cast hn hSpec).completeness init impl relIn relOut ε

omit [Finite F] in
lemma pow_2_pow_i_mem_Di_of_mem_D :
  ∀ {x : Fˣ} (i : ℕ),
    x ∈ D → x ^ (2 ^ i) ∈ evalDomain D i

@[simp]
theorem PowerBasis.cast_basis_succ_of_eq_rec_apply
    (r1 r : ℕ) (h_r : r = r1 + 1)
    (k : Fin 2) :
    letI instAlgebra : Algebra (ConcreteBTField r1) (ConcreteBTField r) :=
      ConcreteBTFieldAlgebra (l:=r1) (r:=r) (h_le:=by omega)
    letI instAlgebraSucc : Algebra (ConcreteBTField (r1 + 1)) (ConcreteBTField (r)) :=
      ConcreteBTFieldAlgebra (l:=r1 + 1) (r:=r) (h_le:=by omega)
    let b : PowerBasis (ConcreteBTField r1) (ConcreteBTField (r1 + 1))
      := powerBasisSucc (k:=r1)
    let bCast : PowerBasis (ConcreteBTField r1) (ConcreteBTField r) := Eq.rec (motive:=
      fun (x : ℕ) (_ : r1 + 1 = x) => by
        letI instAlgebraCur : Algebra (ConcreteBTField r1) (ConcreteBTField x) :=
          ConcreteBTFieldAlgebra (l:=r1) (r:=x) (h_le:=by omega)
        exact PowerBasis (ConcreteBTField r1) (ConcreteBTField x)) (refl:=b) (t:=h_r.symm)
    have h_pb_dim : b.dim = 2 := by
      exact powerBasisSucc_dim r1

    have h_pb'_dim : bCast.dim = 2 := by
      dsimp [bCast]
      rw [PowerBasis.dim_of_eq_rec (r1:=r1) (r:=r) (h_r:=h_r) (b:=b)]
      exact h_pb_dim

    have h_pb_type_eq : Basis (Fin bCast.dim) (ConcreteBTField r1) (ConcreteBTField r) =
      Basis (Fin 2) (ConcreteBTField r1) (ConcreteBTField r) := by
      congr

   -- The `cast` needs a proof that `bCast.dim = 2`. We construct it here.
    let left : Basis (Fin 2) (ConcreteBTField r1) (ConcreteBTField r)
      := cast (by exact h_pb_type_eq) bCast.basis
    let right := (algebraMap (ConcreteBTField (r1 + 1)) (ConcreteBTField r))
      (b.basis (Fin.cast h_pb_dim.symm k))
    left k = right

@[simp]
theorem Fin.cast_val_eq_val {n m : ℕ} [NeZero n] (a : Fin n) (h_eq : n = m):
  (Fin.cast (h_eq) a).val = a.val

@[simp, grind] lemma R_pos : 0 < sz.R

theorem hcons_right_injective {β : Fin n → Sort u} (a : α) :
    Function.Injective (hcons a : ((i : Fin n) → β i) → (i : Fin (n + 1)) → vcons α β i)

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

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R deg D n oSpec).perfectCompleteness init impl
      (relationRound R n deg D 0) (relationRound R n deg D (.last n))

@[simp]
theorem fappend₂_zero {α₁ : Fin m → A} {α₂ : Fin m → B} {β₁ : Fin 0 → A} {β₂ : Fin 0 → B}
    (u : (i : Fin m) → F₂ (α₁ i) (α₂ i)) :
    fappend₂ (F := F₂) u (!h⦃F₂⦄⟨β₁⟩⟨β₂⟩[] : (i : Fin 0) → F₂ (β₁ i) (β₂ i)) = u

lemma getLowBits_succ {n: ℕ} (numLowBits: ℕ) :
    getLowBits (numLowBits + 1) n = getLowBits numLowBits n
    + (getBit numLowBits n) <<< numLowBits

Polynomial.degree_sum_le in Mathlib.Algebra.Polynomial.Degree.Definitions

@[simp]
theorem append_left_cancel_iff {pSpec : ProtocolSpec n} {p1 p2 : ProtocolSpec m} :
    p1 ++ₚ pSpec = p2 ++ₚ pSpec ↔ p1 = p2

omit [Fintype 𝔽q] h_Fq_char_prime hβ_lin_indep in
lemma eval_W_eq_zero_iff_in_U (i : Fin r) (a : L) :
  (W 𝔽q β i).eval a = 0 ↔ a ∈ U 𝔽q β i

@[simp]
lemma width_pos : 0 < params.width

lemma algebra_adjacent_tower_eq_AdjoinRoot_algebra (k : ℕ) :
  (algebra_adjacent_tower k) = (AdjoinRoot.instAlgebra (poly k))

@[simp]
lemma OracleVerifier.id_toVerifier :
    (OracleVerifier.id : OracleVerifier oSpec Statement OStatement _ _ _).toVerifier =
      Verifier.id

Fin.is_le' in Init.Data.Fin.Lemmas

lemma algebraMap_adjacent_tower_def (l : ℕ) :
  (algebraMap (BTField l) (BTField (l + 1))) = canonicalEmbedding l

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

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

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_lt_ℓ_add_R (i : Fin ℓ)
    : i.val < ℓ + 𝓡

@[simp]
lemma mul_by_empty :
    mul_by_2 ∅ = ∅

theorem insertNth_zero_eq_cases {n : ℕ} {α : Fin (n + 1) → Sort u} :
    insertNth 0 = cases (motive := α)

@[simp]
theorem OracleReduction.run_eq_run_reduction [∀ i, OracleInterface (pSpec.Message i)]
    {stmt : StmtIn} {oStmt : ∀ i, OStmtIn i} {wit : WitIn}
    {oracleReduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec} :
      oracleReduction.run stmt oStmt wit =
        oracleReduction.toReduction.run ⟨stmt, oStmt⟩ wit

@[simp]
lemma evenPart_coeff {f : Polynomial F} {n : ℕ} :
    (evenPart f).coeff n = if Even n then f.coeff n else 0

Nat.pow_lt_pow_right in Init.Data.Nat.Lemmas

lemma Fin.val_sub_one (a : Fin r) (h_a_sub_1 : a > 0) : (a - 1).val = a.val - 1

lemma definingPoly_coeffOf1 {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
    (definingPoly s).coeff 1 = s

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

theorem join_of_split {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
    (hi_btf lo_btf : ConcreteBTField (k - 1))
    (h_split_eq : split h_pos x = (hi_btf, lo_btf)) :
    x = 《 hi_btf, lo_btf 》

theorem join_eq_bitvec_iff_fromNat {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
  (hi_btf lo_btf : ConcreteBTField (k - 1)) :
  x = 《 hi_btf, lo_btf 》 ↔
  (hi_btf = fromNat (k:=k - 1) (x.toNat >>> 2 ^ (k - 1)) ∧
  lo_btf = fromNat (k:=k - 1) (x.toNat &&& (2 ^ (2 ^ (k - 1)) - 1)))

theorem embedSum_succ {m : ℕ} {n : Fin (m + 1) → ℕ} {i : Fin (m + 1)} (j : Fin (n i)) :
    embedSum i j = (match i with
    | 0 => Fin.castAdd _ j
    | ⟨i + 1, h⟩ => Fin.natAdd _ (embedSum ⟨i, Nat.succ_lt_succ_iff.mp h⟩ j))

@[simp]
theorem generateProof_leaf (a : α) (idx) :
    generateProof (FullData.leaf a) idx = []

@[simp]
lemma coeff_polynomialOfCoeffs_eq_coeffs :
  Fin.liftF' (polynomialOfCoeffs coeffs).coeff = coeffs

lemma forwardRange_0_eq_finRange (n : ℕ) [NeZero n] : forwardRange n ⟨n - 1, by
    have h_ne

@[simp]
lemma possibleRelHammingDistsToC_subset_relHammingDistRange [DecidableEq F] :
  possibleDistsToCode w C relHammingDist ⊆ relHammingDistRange ι

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

@[simp]
theorem hflatten_two_eq_append {n : Fin 2 → ℕ} {α : (i : Fin 2) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin 2) → (j : Fin (n i)) → α i j} : hflatten v = happend (v 0) (v 1)

theorem rightpad_getElem_eq_getD {a b : List α} {unit : α} {i : Nat}
  (h : i < (a.rightpad b.length unit).length) :
    (a.rightpad b.length unit)[i] = a.getD i unit

lemma getLowBits_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
  getLowBits n (joinBits low high).val = low.val

@[simp]
theorem runWithOracle_freeMonad_pure_none (f : spec.FunctionType) :
    runWithOracle f (FreeMonad.pure (none : Option α)) = none

lemma one_is_1 {k : ℕ} : (one (k:=k)) = 1

theorem rightpad_eq_self (v : Fin n → α) (a : α) : rightpad n a v = v

omit [DecidableEq L] [DecidableEq 𝔽q] h_Fq_char_prime hF₂ hβ_lin_indep h_β₀_eq_1 in
lemma intermediateNovelBasisX_zero_eq_one (i : Fin (ℓ + 1)) :
    intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate i ⟨0, by
      exact Nat.two_pow_pos (ℓ - ↑i)⟩ = 1

@[simp]
lemma liftF'_zero_eq_zero
  : liftF' (fun _ ↦ (0 : α)) = (fun (_ : Fin n) ↦ (0 : α))

@[simp]
theorem dist_subsingleton {C : Set (n → R)} [Subsingleton C] : ‖C‖₀ = 0

theorem challengeOracleInterface_cast {h : n₁ = n₂} {hSpec : pSpec₁.cast h = pSpec₂}
    {i : pSpec₁.ChallengeIdx} :
    pSpec₁.challengeOracleInterface i =
      dcast (by simp) (pSpec₂.challengeOracleInterface (i.cast hn hSpec))

add_zero in Mathlib.Algebra.Group.Defs

theorem dconcat_left_injective {motive : Fin (n + 1) → Sort u} (a : motive (last n)) :
    Function.Injective (fun v => dconcat (motive := motive) v a)

theorem liftContext_knowledgeSoundness [Inhabited InnerWitIn]
    {knowledgeError : ℝ≥0}
    {stmtLens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut}
    {witLens : Witness.InvLens (OuterStmtIn × ∀ i, OuterOStmtIn i)
                            OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    (V : OracleVerifier oSpec InnerStmtIn InnerOStmtIn InnerStmtOut InnerOStmtOut pSpec)
    [lensKS : Extractor.Lens.IsKnowledgeSound
      outerRelIn innerRelIn outerRelOut innerRelOut
      (V.toVerifier.compatStatement stmtLens) (fun _ _ => True) ⟨stmtLens, witLens⟩]
    (h : V.knowledgeSoundness init impl innerRelIn innerRelOut knowledgeError) :
      (V.liftContext stmtLens).knowledgeSoundness init impl outerRelIn outerRelOut
        knowledgeError

@[simp]
theorem vflatten_zero {n : Fin 0 → ℕ} {v : (i : Fin 0) → Fin (n i) → α} : vflatten v = !v[]

@[simp] theorem rightpad_twice_eq_rightpad_max (m n : Nat) (unit : α) (l : List α) :
    rightpad n unit (rightpad m unit l) = rightpad (max m n) unit l

@[simp]
theorem init_update_last : init (update s (Fin.last n) y) = init s

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R n deg D oSpec i).perfectCompleteness init impl
    (relationRound R n deg D i.castSucc) (relationRound R n deg D i.succ)

@[simp]
theorem oracleReduction_perfectCompleteness (hInit : init.neverFails) :
    (oracleReduction oSpec Statement OStatement Witness).perfectCompleteness init impl rel rel

theorem support_C_mul_le (p : MvPolynomial σ R) (r : R) : (C r * p).support ⊆ p.support

lemma resultant_is_divisible_by_leadingCoeff {F : Type} [CommRing F] [Inhabited F] (f : F[X])
  : ∃ r',
    Polynomial.resultant f (Polynomial.derivative f) = f.leadingCoeff * r'

Nat.lt_of_add_right_lt in Init.Data.Nat.Basic

@[simp]
theorem insertNth_apply_same : insertNth p y s p = y

lemma dim_eq_deg_of_le [NeZero n] (inj : Function.Injective α) (h : n ≤ m) :
  dim (ReedSolomon.code ⟨α, inj⟩ n) = n

lemma generalised_round_consistency_completeness
  {𝔽 : Type} [inst1 : Field 𝔽] [DecidableEq 𝔽] {f : Polynomial 𝔽}
  {n : ℕ} [inst : NeZero n]
  {γ : 𝔽}
  {s₀ : 𝔽}
  {ω : Fin n ↪ 𝔽}
  (h : ∀ i, (ω i) ^ n = 1)
  (h₁ : s₀ ≠ 0)
  :
    roundConsistencyCheck
      γ
      (List.map (fun i => (ω i * s₀, f.eval (ω i * s₀))) (List.finRange n))
      ((foldNth n f γ).eval (s₀^n)) = true

theorem intermediateNormVpoly_comp_qmap (i : Fin (ℓ))
    (k : Fin (ℓ - i - 1)) : -- corresponds to intermediateNormVpoly_comp

theorem add_zero {n : ℕ} (a : CNat (n + 1)) : a + 0 = a

lemma matching_set_is_a_sub_of_coeffs_of_close_proximity
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : matching_set k ωs δ u₀ u₁ h_gs ⊆ coeffs_of_close_proximity k ωs δ u₀ u₁

theorem FullData.map_getRootValue {α β : Type} {s : Skeleton}
    (f : α → β) (tree : FullData α s) :
    (tree.map f).getRootValue = f (tree.getRootValue)

@[simp]
lemma range_def : (spec α).range () = α

omit [DecidableEq α] [Inhabited α] [Fintype α] in
@[simp]
lemma Cache.leaves_cons (n : ℕ) (leaves : List.Vector α (2 ^ (n + 1))) (cache : Cache α n) :
    Cache.leaves α n (Cache.cons α n leaves cache) = leaves

theorem two_pow_ne_zero (n : ℕ) : 2 ^ n ≠ 0

@[simp]
theorem dflatten_splitSum {m : ℕ} {n : Fin m → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    (v : (k : Fin (vsum n)) → motive k) (k : Fin (vsum n)) :
    dflatten (motive := motive) (fun i j => v (embedSum i j)) k = v k

theorem lt_iff_toNat_lt (a b : AssocNat) : a < b ↔ toNat a < toNat b

lemma polynomialOfCoeffs_coeffsOfPolynomial {p : F[X]}
  (h : p.natDegree + 1 = deg) : polynomialOfCoeffs (coeffsOfPolynomial (deg := deg) p) = p

theorem add_size {p q : UniPoly Q} : (add_raw p q).size = max p.size q.size

omit [Finite F] in
lemma dom_n_eq_triv : evalDomain D n = ⊥

@[simp]
lemma dfoldl'_succ_last {n : ℕ} {α : Fin (n + 2) → Type u}
    (f : (i : Fin (n + 1)) → α i.castSucc → α i.succ) (x : α 0) :
    dfoldl' (n + 1) α f x = f (last n) (dfoldl' n (α ∘ castSucc) (fun i => f i.castSucc) x)

private lemma le_sum_sum_choose_K [Zero F]
  (h_n : 0 < n)
  (h_B : B.card ≠ 0)
  (h_card : 2 ≤ Fintype.card F)
  :
  n * (choose_2 (k B) + (Fintype.card (α := F) - 1)
    * choose_2 ((B.card - k B) / ((Fintype.card (α := F) - 1))))
  ≤ ∑ i, sum_choose_K_i B i

lemma concrete_zero_mul
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul (zero (k:=k)) a = zero (k:=k)

theorem dcast₂_dcast : dcast₂ rfl rfl c = dcast dcast_eq.symm c

@[simp, grind =]
theorem monomialXY_eq_zero_iff {n m : ℕ} {a : F} : monomialXY n m a = 0 ↔ a = 0

@[simp]
theorem cast_id :
    Reduction.cast rfl rfl = (id : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec₁ → _)
</all_available_lemmas>

<local_ctx>
import ArkLib.Data.CodingTheory.BerlekampWelch.BerlekampWelch

import ArkLib.Data.CodingTheory.ReedSolomon

import ArkLib.Data.FieldTheory.AdditiveNTT.AdditiveNTT

import ArkLib.Data.MvPolynomial.Multilinear

import ArkLib.Data.Vector.Basic

import ArkLib.ProofSystem.Sumcheck.Spec.SingleRound

namespace Binius.BinaryBasefold

open OracleSpec OracleComp ProtocolSpec Finset AdditiveNTT Polynomial MvPolynomial
  Binius.BinaryBasefold

open scoped NNReal

open ReedSolomon Code BerlekampWelch

open Finset AdditiveNTT Polynomial MvPolynomial Nat Matrix

section Preliminaries

variable {L : Type} [CommRing L] (ℓ : ℕ) [NeZero ℓ]

variable (𝓑 : Fin 2 ↪ L)

end Preliminaries

noncomputable section       -- expands with 𝔽q in front

variable {r : ℕ} [NeZero r]

variable {L : Type} [Field L] [Fintype L] [DecidableEq L] [CharP L 2]

variable (𝔽q : Type) [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 {ℓ 𝓡 ϑ : ℕ} (γ_repetitions : ℕ) [NeZero ℓ] [NeZero 𝓡] [NeZero ϑ] -- Should we allow ℓ = 0?

variable {h_ℓ_add_R_rate : ℓ + 𝓡 < r} -- ℓ ∈ {1, ..., r-1}

variable {𝓑 : Fin 2 ↪ L}

section Essentials

abbrev OracleFunction (i : Fin (ℓ + 1)) : Type _ := sDomain 𝔽q β h_ℓ_add_R_rate ⟨i, by admit /- proof elided -/
    ⟩ → L

noncomputable def fiber_coeff
    (i : Fin r) (steps : ℕ)
    (j : Fin (ℓ + 𝓡 - i)) (elementIdx : Fin (2 ^ steps))
    (y_coeffs : Fin (ℓ + 𝓡 - (i + steps)) →₀ 𝔽q) : 𝔽q :=
  if hj : j.val < steps then
    if Nat.getBit (k := j) (n := elementIdx) = 0 then 0 else 1
  else y_coeffs ⟨j.val - steps, by admit /- proof elided -/
    ⟩

noncomputable def qMap_total_fiber
    
      (i : Fin r) (steps : ℕ) (h_i_add_steps : i.val + steps < ℓ + 𝓡)
        (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by admit /- proof elided -/
        ⟩)) :
    Fin (2 ^ steps) → sDomain 𝔽q β h_ℓ_add_R_rate i :=
  if h_steps : steps = 0 then by
    
    subst h_steps
    simp only [add_zero, Fin.eta] at y
    exact fun _ => y
  else by
    
    let basis_y := sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨i+steps,by admit /- proof elided -/
    ⟩) (by admit /- proof elided -/
    )
    let y_coeffs : Fin (ℓ + 𝓡 - (↑i + steps)) →₀ 𝔽q := basis_y.repr y

    let basis_x := sDomain_basis 𝔽q β h_ℓ_add_R_rate ⟨i, by admit /- proof elided -/
    ⟩ (by admit /- proof elided -/
    )
    exact fun elementIdx => by admit /- proof elided -/

def pointToIterateQuotientIndex (i : Fin (ℓ + 1)) (steps : ℕ) (h_i_add_steps : i.val + steps ≤ ℓ)
    (x : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩)) : Fin (2 ^ steps) :=

end Essentials

section SoundnessTools

def BBF_Code (i : Fin (ℓ + 1)) : Submodule L ((sDomain 𝔽q β h_ℓ_add_R_rate)
    ⟨i, by admit /- proof elided -/
        ⟩ → L) :=
  let domain : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i, by admit /- proof elided -/
  ⟩ ↪ L :=
    ⟨fun x => x.val, fun x y h => by admit /- proof elided -/
    ⟩
  ReedSolomon.code (domain := domain) (deg := 2^(ℓ - i.val))

def BBF_CodeDistance (ℓ 𝓡 : ℕ) (i : Fin (ℓ + 1)) : ℕ :=
  2^(ℓ + 𝓡 - i.val) - 2^(ℓ - i.val) + 1

def fiberwiseDisagreementSet (i : Fin ℓ) (steps : ℕ) [NeZero steps]
    (h_i_add_steps : i.val + steps ≤ ℓ) (f g : OracleFunction 𝔽q β (h_ℓ_add_R_rate :=
      h_ℓ_add_R_rate) ⟨i, by admit /- proof elided -/
      ⟩) :
  Set ((sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i.val + steps, by admit /- proof elided -/
  ⟩) :=
  
    
  {y | ∃ x, iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate (i := i)
    (k := steps) (h_bound := by admit /- proof elided -/
    ) x = y ∧ f x ≠ g x}

def fiberwiseDistance (i : Fin ℓ) (steps : ℕ) [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
  (f : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i.val, by admit /- proof elided -/
  ⟩) : ℕ :=
  
  
  let C_i := BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i.val, by admit /- proof elided -/
  ⟩
  let disagreement_sizes := (fun (g : C_i) =>
    (fiberwiseDisagreementSet 𝔽q β i steps h_i_add_steps f g).ncard) '' Set.univ
  sInf disagreement_sizes

def fiberwiseClose (i : Fin ℓ) (steps : ℕ) [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
    (f : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      ⟨i, by admit /- proof elided -/
      ⟩) : Prop :=
  2 * fiberwiseDistance 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i) steps
    (h_i_add_steps := h_i_add_steps) (f := f) < (BBF_CodeDistance ℓ 𝓡 ⟨i + steps, by admit /- proof elided -/
    ⟩ : ℕ∞)

def hammingClose (i : Fin (ℓ + 1)) (f : OracleFunction 𝔽q β
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) : Prop :=
  2 * Code.distFromCode (u := f)
    (C := BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) <
    (BBF_CodeDistance ℓ 𝓡 i : ℕ∞)
</local_ctx>

<target_theorem>
theorem fiberwise_dist_lt_imp_dist_lt_unique_decoding_radius (i : Fin ℓ) (steps : ℕ)
    [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
    (f : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by omega⟩)
  (h_fw_dist_lt : fiberwiseClose 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    (i := i) (steps := steps) (h_i_add_steps := h_i_add_steps) (f := f)) :
  hammingClose 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by omega⟩ f :=
</target_theorem>

