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>
Fintype in Mathlib.Data.Fintype.Defs
Polynomial.X in Mathlib.Algebra.Polynomial.Basic
Semiring in Mathlib.Algebra.Ring.Defs
toFun in ToMathlib.Control.Monad.Hom
Submodule in Mathlib.Algebra.Module.Submodule.Defs
Polynomial in Mathlib.Algebra.Polynomial.Basic
Polynomial.degreeLT in Mathlib.RingTheory.Polynomial.Basic
Zero in Init.Prelude
DecidableEq in Init.Prelude
Field in Mathlib.Algebra.Field.Defs
Fin in Init.Prelude
Function.Injective in Init.Data.Function
NeZero in Init.Data.NeZero
Set in Mathlib.Data.Set.Defs
Finset in Mathlib.Data.Finset.Defs
Matrix.add in Mathlib.LinearAlgebra.Matrix.Defs
Multiset in Mathlib.Data.Multiset.Defs
Multiset.count in Mathlib.Data.Multiset.Count
Set.InjOn in Mathlib.Data.Set.Operations
Finset.max in Mathlib.Data.Finset.Max
Module in Mathlib.Algebra.Module.Defs
Module.finrank in Mathlib.LinearAlgebra.Dimension.Finrank
Matrix in Mathlib.LinearAlgebra.Matrix.Defs
Matrix.of in Mathlib.LinearAlgebra.Matrix.Defs
Finset.min in Mathlib.Data.Finset.Max
Fin.castLE in Init.Data.Fin.Basic
Matrix.submatrix in Mathlib.LinearAlgebra.Matrix.Defs
id in Init.Prelude
Matrix.vandermonde in Mathlib.LinearAlgebra.Vandermonde
IsDomain in Mathlib.Algebra.Ring.Defs
Matrix.det in Mathlib.LinearAlgebra.Matrix.Determinant.Basic
Matrix.rank in Mathlib.LinearAlgebra.Matrix.Rank
Matrix.cRank in Mathlib.LinearAlgebra.Matrix.Rank
Fin.val in Init.Prelude
Finset.map in Mathlib.Data.Finset.Image
CommRing in Mathlib.Algebra.Ring.Defs
LinearMap in Mathlib.Algebra.Module.LinearMap.Defs
LinearMap.range in Mathlib.Algebra.Module.Submodule.Range
Finset.range in Mathlib.Data.Finset.Range
CommSemiring in Mathlib.Algebra.Ring.Defs
Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic
hammingDist in Mathlib.InformationTheory.Hamming
Fintype.card in Mathlib.Data.Fintype.Card
StrongRankCondition in Mathlib.LinearAlgebra.InvariantBasisNumber

def wt [Zero F]
  (v : ι → F) : ℕ := #{i | v i ≠ 0}

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 subUpFull (U : Matrix (Fin m) (Fin n) F) (r_reindex : Fin n → Fin m) :
  Matrix (Fin n) (Fin n) F := Matrix.submatrix U r_reindex id

@[simps]
def refl (pSpec : ProtocolSpec n) : Equiv pSpec pSpec where
  round_eq := rfl
  dir_eq := fun _ => rfl
  typeEquiv := fun _ => _root_.Equiv.refl _

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 polynomialOfCoeffs (coeffs : Fin deg → F) : F[X] :=
  ⟨
    Finset.map ⟨Fin.val, Fin.val_injective⟩ {i | coeffs i ≠ 0},
    fun i ↦ if h : i < deg then coeffs ⟨i, h⟩ else 0,
    fun a ↦ by admit /- proof elided -/
  ⟩

def liftF' (f : ℕ → α) : Fin n → α :=
  fun m ↦ f m.1

noncomputable def fromColGenMat [CommRing F] (G : Matrix ι κ F) : LinearCode ι F :=
  LinearMap.range G.mulVecLin

def coeff.{u} {F : Type u} [Semiring F] (f : F[X][Y]) (i j : ℕ) : F := (f.coeff j).coeff i

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

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

noncomputable def minWtCodewords [Semiring F] (LC : LinearCode ι F) : ℕ :=
  sInf {w | ∃ c ∈ LC, c ≠ 0 ∧ Code.wt c = w}

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

notation "Δ" IC => minDist IC

@[reducible, simp] def StmtOut := Query OStatement

structure Commit where
  commit : Data → Randomness → OracleComp oSpec Commitment

@[inline]
def seqCompose {m : ℕ} (Stmt : Fin (m + 1) → Type)
    {n : Fin m → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (V : (i : Fin m) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i)) :
    Verifier oSpec (Stmt 0) (Stmt (Fin.last m)) (seqCompose pSpec) := match m with
  | 0 => Verifier.id
  | _ + 1 => append (V 0) (seqCompose (Stmt ∘ Fin.succ) (fun i => V (Fin.succ i)))

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

noncomputable instance fintype_sDomain (i : Fin r) :
  Fintype (sDomain 𝔽q β h_ℓ_add_R_rate i) :=

Polynomial.derivative in Mathlib.Algebra.Polynomial.Derivative

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

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

abbrev BTF₃ := ConcreteBTField 3 

Set.fintypeMemFinset in Mathlib.Data.Set.Finite.Basic

@[ext]
structure ProverOutput {ι : Type} (oSpec : OracleSpec ι) (Output PrvState : Type) where
  output : PrvState → OracleComp oSpec Output

def foldStepRelOutProp (i : Fin ℓ)
    (input : (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) : Prop :=
  let stmt := input.1.1
  let oStmt := input.1.2
  let wit := input.2
  masterKStateProp (mp := mp) (𝓑 := 𝓑) 𝔽q β
    (stmtIdx := i.succ) (oracleIdx := i.castSucc)
    (h_le := Nat.le_of_lt (Fin.castSucc_lt_succ i)) stmt wit oStmt (localChecks := True)

def hconcat {n : ℕ} {α : Fin n → Sort u} {β : Sort u} (u : (i : Fin n) → α i) (a : β) :
    (i : Fin (n + 1)) → Fin.vconcat α β i :=
  fconcat (F := id) u a

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

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⟩

MvPolynomial in Mathlib.Algebra.MvPolynomial.Basic

def linearMvExtension :
  Polynomial.degreeLT F (2^m) →ₗ[F] MvPolynomial (Fin m) F where
    
    toFun p := (p : Polynomial F).sum fun i a =>
      MvPolynomial.monomial (bitExpo i) a
    map_add' := by admit /- proof elided -/

ByteArray.mk in Init.Prelude

instance : Add (Cayley T) where
  add := add

noncomputable def hasMutualCorrAgreement
  (Gen : ProximityGenerator ι F) [Fintype Gen.parℓ]
  (BStar : ℝ) (errStar : ℝ → ENNReal) :=
    haveI := Gen.Gen_nonempty
    ∀ (f : Gen.parℓ → ι → F) (δ : ℝ≥0) (_hδ : 0 < δ ∧ δ < 1 - BStar),
    Pr_{let r ←$ᵖ Gen.Gen}[ proximityCondition f δ r Gen.C ] ≤ errStar δ

@[inline]
def ofOutputOnly
    (stmtLift : OuterStmtIn × (∀ i, OuterOStmtIn i) → InnerStmtOut × (∀ i, InnerOStmtOut i) →
                OuterStmtOut × (∀ i, OuterOStmtOut i))
    (witLift : (OuterStmtIn × (∀ i, OuterOStmtIn i)) × OuterWitIn →
               (InnerStmtOut × (∀ i, InnerOStmtOut i)) × InnerWitOut → OuterWitOut) :
    OracleContext.Lens OuterStmtIn OuterStmtOut OuterStmtIn InnerStmtOut
                OuterOStmtIn OuterOStmtOut OuterOStmtIn InnerOStmtOut
                OuterWitIn OuterWitOut OuterWitIn InnerWitOut where
  stmt := OracleStatement.Lens.ofOutputOnly stmtLift
  wit := Witness.Lens.ofOutputOnly witLift

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

def BBF_eq_multiplier (r : Fin ℓ → L) : MultilinearPoly L ℓ :=
  ⟨MvPolynomial.eqPolynomial r, by admit /- proof elided -/
  ⟩

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

@[reducible]
def OracleStatement : Fin (m + 1) → Type :=
  fun _ => evalDomain D x 0 → F

def squeeze (sponge : DuplexSponge U C) (len : Nat) :
    OracleComp (forwardPermutationOracle C) (Vector U len × DuplexSponge U C) :=
  match len with
  
  | 0 => pure (#v[], sponge)
  
  | n + 1 => do
    
    let sponge1 : DuplexSponge U C := { sponge with absorbPos := 0 }
    let sponge2 ← if sponge1.squeezePos = SpongeSize.R then
      let permutedState ← query (spec := forwardPermutationOracle _) () (sponge1.state)
      let sponge2 : DuplexSponge U C := { sponge1 with state := permutedState, squeezePos := 0 }
      pure sponge2
    else
      pure sponge1
    let squeezedVal := (SpongeState.get sponge2.state)[sponge2.squeezePos]
    let sponge3 := { sponge2 with squeezePos := sponge2.squeezePos + 1 }
    
    let (restVec, sponge4) ← squeeze sponge3 n
    
    
    return (restVec.insertIdx 0 squeezedVal, sponge4)

@[inline, specialize]
def OracleVerifier.run [Oₘ : ∀ i, OracleInterface (pSpec.Message i)]
    (stmt : StmtIn) (oStmtIn : ∀ i, OStmtIn i) (transcript : FullTranscript pSpec)
    (verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec) :
      OracleComp oSpec (StmtOut × (∀ i, OStmtOut i)) := do
  let f := OracleInterface.simOracle2 oSpec oStmtIn transcript.messages
  let stmtOut ← simulateQ f (verifier.verify stmt transcript.challenges)
  let oStmtOut : ∀ i, OStmtOut i := fun i => match h : verifier.embed i with
  | .inl j => by admit /- proof elided -/
  | .inr j => by admit /- proof elided -/

class Extractor.Straightline.IsMonotone
    (relIn : Set (StmtIn × WitIn))
    (E : Extractor.Straightline oSpec StmtIn WitIn WitOut pSpec)
    [oSpec.FiniteRange]
    where
  is_monotone : ∀ witOut stmtIn transcript, ∀ proveQueryLog₁ proveQueryLog₂ : oSpec.QueryLog,
    ∀ verifyQueryLog₁ verifyQueryLog₂ : oSpec.QueryLog,
    proveQueryLog₁.Sublist proveQueryLog₂ →
    verifyQueryLog₁.Sublist verifyQueryLog₂ →
    
    [fun witIn => (stmtIn, witIn) ∈ relIn |
      E stmtIn witOut transcript proveQueryLog₁ verifyQueryLog₁] ≤
    [fun witIn => (stmtIn, witIn) ∈ relIn |
      E stmtIn witOut transcript proveQueryLog₂ verifyQueryLog₂]

def γ (x₀ : F) (R : F[X][X][Y]) (H : F[X][Y]) [φ : Fact (Irreducible H)] : PowerSeries (𝕃 H) :=
  let subst (t : ℕ) : 𝕃 H :=
    match t with
    | 0 => fieldTo𝕃 (-x₀)
    | 1 => 1
    | _ => 0
  PowerSeries.subst (PowerSeries.mk subst) (PowerSeries.mk (α x₀ R H))

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 existPriorSameQuery (log : QueryLog spec) (idx : Fin log.length) : Prop :=
  ∃ j' < idx, log[j'] = log[idx]

Dist in Mathlib.Topology.MetricSpace.Pseudo.Defs

Set.imageFactorization in Mathlib.Data.Set.Operations

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

@[reducible]
def GroupEqOracle : OracleSpec Unit := fun _ => (ι × ι, Bool)

def relayKnowledgeStateFunction (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
    (relayOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        i hNCR).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 := relayRbrExtractor 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) where
  toFun := fun m ⟨stmtIn, oStmtIn⟩ tr witMid =>
    relayKStateProp (mp:=mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (𝓑 := 𝓑) i hNCR stmtIn witMid oStmtIn
  toFun_empty := fun ⟨stmtIn, oStmtIn⟩ witIn => by admit /- proof elided -/

def nonLastBlockOracleVerifier (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 β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ
    ⟨bIdx * ϑ + i, bIdx_mul_ϑ_add_i_cast_lt_ℓ_succ bIdx i⟩
  let firstFoldRelayRoundsOracleVerifier :=
    OracleVerifier.seqCompose (oSpec := []ₒ)
      (Stmt := stmt)
      (OStmt := oStmt)
      (pSpec := fun i => pSpecFoldRelay (L:=L))
      (V := fun i => by admit /- proof elided -/
      )
  let h1 : ↑bIdx * ϑ + (ϑ - 1) < ℓ := by admit /- proof elided -/

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

OrderBot in Mathlib.Order.BoundedOrder.Basic

instance : Field ScalarField := ZMod.instField scalarFieldSize

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

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

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

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

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

evalDist in VCVio.EvalDist.Basic

private noncomputable def Q (ωs : Fin n → F)
  (f : Fin n → F) (p : Polynomial F) (e : ℕ) : Polynomial F :=
  p * (E ωs f p e)

@[elab_as_elim]
def dflatten {m : ℕ} {n : Fin m → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    (v : (i : Fin m) → (j : Fin (n i)) → motive (embedSum i j)) (k : Fin (vsum n)) : motive k :=
  match m with
  | 0 => Fin.elim0 k
  | _ + 1 =>
    dappend
      (fun j => v 0 j)
      (fun j => dflatten (motive := fun j => motive (natAdd _ j)) (fun i => v i.succ) j)
      k

inductive ScalarVectorOp where | scale

@[reducible] def OracleProof {ι : Type} (oSpec : OracleSpec ι)
    (Statement : Type) {ιₛᵢ : Type} (OStatement : ιₛᵢ → Type) (Witness : Type)
    {n : ℕ} (pSpec : ProtocolSpec n)
    [Oₛᵢ : ∀ i, OracleInterface (OStatement i)]
    [Oₘ : ∀ i, OracleInterface (pSpec.Message i)] :=
  OracleReduction oSpec Statement OStatement Witness Bool (fun _ : Empty => Unit) Unit pSpec

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

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

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

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

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

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

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

class IsSound (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec) where
  soundnessError : ℝ≥0
  is_sound : soundness init impl langIn langOut verifier soundnessError

Subtype.fintype in Mathlib.Data.Fintype.Sets

instance : IsEmpty (ChallengeIdx ⟨!v[.P_to_V], !v[Msg]⟩) :=
  ⟨fun ⟨i, h⟩ => by admit /- proof elided -/
  ⟩

@[inline, specialize]
def oracleReduction : OracleReduction oSpec
    Statement OStatement Unit Statement OStatement Unit !p[] where
  prover := oracleProver oSpec Statement OStatement
  verifier := oracleVerifier oSpec Statement OStatement pred

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

structure DomainSeparator (U : Type) [SpongeUnit U] (H : Type*) [DuplexSpongeInterface U H] where
   
  io : String
deriving Repr

BitVec.toNat in Init.Prelude

Subsingleton in Init.Core

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

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

minpoly in Mathlib.FieldTheory.Minpoly.Basic

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

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)

private noncomputable def oddPart' (f : Polynomial F) : Polynomial F :=
  match f with
  | ⟨⟨supp, f, pr⟩⟩ => ⟨⟨
      shift_left (erase_even supp),
      fun n => if Even n then f (n + 1) else 0, by admit /- proof elided -/
      ⟩⟩

System.mkFilePath in Init.System.FilePath

@[inline]
def ofOutputOnly
    (witLift :
      OuterStmtIn × OuterWitIn → InnerStmtOut × InnerWitOut → OuterWitOut)
    (stmtLift : OuterStmtIn → InnerStmtOut → OuterStmtOut) :
    Context.Lens OuterStmtIn OuterStmtOut OuterStmtIn InnerStmtOut
                OuterWitIn OuterWitOut OuterWitIn InnerWitOut where
  wit := Witness.Lens.ofOutputOnly witLift
  stmt := Statement.Lens.ofOutputOnly stmtLift

def start {α : Type} (a : α) : OracleComp (α →ₒ Vector U SpongeSize.C) (DuplexSponge U C) := do
  let capacitySegment : Vector U SpongeSize.C ← query (spec := α →ₒ Vector U SpongeSize.C) () a
  let vecSponge := (Vector.replicate SpongeSize.R (0 : U)) ++ capacitySegment
  return {
    state := SpongeState.update (α := C) (0 : C) (vecSponge.cast (by admit /- proof elided -/
    )),
    absorbPos := 0,
    squeezePos := Fin.last SpongeSize.R
  }

@[reducible, simp]
def relOut : (StmtOut OStatement × ∀ i, OStmtOut OStatement i) → WitOut → Prop :=
  fun ⟨⟨q, r⟩, oStmt⟩ () => answer (oStmt 0) q = r

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

head in ToMathlib.Control.Comonad.Instances

Array.map in Init.Data.Array.Basic

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

@[reducible]
def Set.language {α β} (rel : Set (α × β)) : Set α :=
  Prod.fst '' rel

def distanceLE (Message : Type*) [O : OracleInterface Message]
    [Fintype (O.Query)] [DecidableEq (O.Response)] (d : ℕ) : Prop :=
  ∀ a b : Message, a ≠ b → #{q | OracleInterface.answer a q = OracleInterface.answer b q} ≤ d

SetLike in Mathlib.Data.SetLike.Basic

def nil {α} : Vector α 0 := ⟨#[], rfl⟩ 

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

inductive ScalarOp where | add | sub | mul | div

def NBlockMessages := 2 * (ϑ - 1) + 3

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

@[simp]
abbrev OracleStatement.AfterFirstChallenge : R1CS.MatrixIdx ⊕ Fin 1 → Type :=
  OracleStatement.AfterFirstMessage R pp

@[inline, specialize]
def Prover.processRoundDSFS [∀ i, VCVCompatible (pSpec.Challenge i)] (j : Fin n)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (currentResult : OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      (pSpec.MessagesUpTo j.castSucc ×
        CanonicalDuplexSponge U × prover.PrvState j.castSucc)) :
      OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
        (pSpec.MessagesUpTo j.succ ×
          CanonicalDuplexSponge U × prover.PrvState j.succ) := do
  let ⟨messages, sponge, state⟩ ← currentResult
  match hDir : pSpec.dir j with
  | .V_to_P => do
    let f ← prover.receiveChallenge ⟨j, hDir⟩ state
    let (challenge, newSponge) ←
      liftM (DuplexSponge.squeeze sponge (challengeSize ⟨j, hDir⟩))
    
    let deserializedChallenge : pSpec.Challenge ⟨j, hDir⟩ := Deserialize.deserialize challenge
    return ⟨messages.extend hDir, newSponge, f deserializedChallenge⟩
  | .P_to_V => do
    let ⟨msg, newState⟩ ← prover.sendMessage ⟨j, hDir⟩ state
    let serializedMessage : Vector U (messageSize ⟨j, hDir⟩) := Serialize.serialize msg
    let newSponge ← liftM (DuplexSponge.absorb sponge serializedMessage.toList)
    return ⟨messages.concat hDir msg, newSponge, newState⟩

@[reducible]
def OracleStatement : Unit → Type := fun _ => R⦃≤ deg⦄[X Fin n]

def getHighBits (numLowBits : ℕ) (n : ℕ) : ℕ :=
  (getHighBits_no_shl numLowBits n) <<< numLowBits

Fin.rev in Init.Data.Fin.Basic

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)

instance : Slice (FullTranscript pSpec) ℕ ℕ
    (fun _ start stop => start ≤ stop ∧ stop ≤ n)
    (fun _ start stop _ => FullTranscript (pSpec⟦start:stop⟧))
    where
  slice := fun v start stop h => extract start stop h.1 h.2 v

def divX (p : UniPoly R) : UniPoly R := p.extract 1 p.size

def JohnsonConditionStrong (B : Finset (Fin n → F)) (v : Fin n → F) : Prop :=
  let e := e B v
  let d := d B
  let q : ℚ := Fintype.card F
  let frac := q / (q - 1)
  (1 - frac * d/n) < (1- frac * e/n) ^ 2

List.rightpad in Init.Data.List.Basic

USize.ofNat in Init.Data.UInt.BasicAux

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

BitVec.zero in Init.Data.BitVec.Basic

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

instance instDCast₂OracleProver : DCast₂ Nat ProtocolSpec
    (fun _ pSpec => OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) where
  dcast₂ := OracleProver.cast
  dcast₂_id := OracleProver.cast_id

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

@[reducible]
def pBits : Nat := 31

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

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

List.max? in Init.Data.List.Basic

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

Lagrange.basis in Mathlib.LinearAlgebra.Lagrange

def deriveTranscriptDSFSAux {ι : Type} {oSpec : OracleSpec ι} {StmtIn : Type}
    (sponge : CanonicalDuplexSponge U)
    (messages : pSpec.Messages) (i : Fin (n + 1)) :
      OracleComp (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
        (CanonicalDuplexSponge U × pSpec.Transcript i) :=
  Fin.induction
    (pure (sponge, fun i => i.elim0))
    (fun i ih => do
      let ⟨curSponge, prevTranscript⟩ ← ih
      match hDir : pSpec.dir i with
      | .V_to_P =>
        let ⟨challenge, newSponge⟩ ← liftM (curSponge.squeeze (challengeSize ⟨i, hDir⟩))
        let deserializedChallenge : pSpec.Challenge ⟨i, hDir⟩ :=
          Deserialize.deserialize challenge
        return (newSponge, prevTranscript.concat deserializedChallenge)
      | .P_to_V =>
        let serializedMessage : Vector U (messageSize ⟨i, hDir⟩) :=
          Serialize.serialize (messages ⟨i, hDir⟩)
        let newSponge ← liftM (DuplexSponge.absorb curSponge serializedMessage.toList)
        return (newSponge, prevTranscript.concat (messages ⟨i, hDir⟩)))
    i

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

def findFinIdx (p : α → Bool) (l : List α) : Fin (l.length + 1) :=
  ⟨List.findIdx' p l,
    Nat.lt_succ_of_le (by admit /- proof elided -/
    )⟩

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

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

instance : LawfulHasPred Nat where
  pred'_succ := Nat.pred_succ

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

def getCommitProverFinalOutput (i : Fin ℓ)
    (inputPrvState : commitPrvState (Context := Context) 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i 0) :
  (↥(sDomain 𝔽q β h_ℓ_add_R_rate ⟨↑i + 1, by admit /- proof elided -/
  ⟩) → L) ×
  commitPrvState (Context := Context) 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i 1 :=
  let (stmt, oStmtIn, wit) := inputPrvState
  let fᵢ_succ := wit.f
  let oStmtOut := snoc_oracle 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    oStmtIn fᵢ_succ 
  (fᵢ_succ, (stmt, oStmtOut, wit))

instance : SMul R (UniPoly R) := ⟨UniPoly.smul⟩

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

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

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)

StateT.lift in Init.Control.State

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

instance [ProverFirst pSpec] : ProverLast pSpec where
  prover_last' := by admit /- proof elided -/

instance {Message : Type u} : Inhabited (OracleInterface Message) :=
  ⟨instDefault⟩

AlgHom in Mathlib.Algebra.Algebra.Hom

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

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

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

Neg in Init.Prelude

partial def verifyCertificate (n' : Q(ℕ)) (n : ℕ) :
    UnverifiedPrattCertificate n → MetaM Q(Nat.Prime $n')
  | .knownPrime n => verifySmallPrime n'
  | .of n a part => do
      let cert ← generateCertificate n' n a part
      return q(PrattCertificate.out $cert)
  where
  generateCertificate (n' : Q(ℕ)) (_ : ℕ) (a : ℕ) (part : UnverifiedPrattPart) :
      MetaM Q(PrattCertificate $n') := do
    have alit : Q(ℕ) := mkRawNatLit a
    let ⟨a', pa'⟩ ← mkOfNat q(ZMod $n') q(instAddMonoidWithOne) alit
    let hpow : Q($a' ^ ($n' - 1) = 1) ← verifyEqOne n' alit a' pa'
    let result ← generatePart n' a' alit pa' part
    haveI : $(result.1) =Q $n' - 1 := ⟨⟩
    return q(PrattCertificate.mk $a' $hpow $(result.2))
  generatePart (n' : Q(ℕ)) (a : Q(ZMod $n')) (a' : Q(ℕ)) (pa' : Q(($a' : ZMod $n') = $a)) :
      UnverifiedPrattPart → MetaM ((nn : Q(ℕ)) × Q(PrattPart $n' $a $nn))
    | .prime p k hp => do
      
      have plit : Q(ℕ) := mkRawNatLit p
      let inner ← verifyCertificate plit p hp
      have pklit : Q(ℕ) := mkRawNatLit (p ^ k)
      have klit : Q(ℕ) := mkRawNatLit k
      let hpow ← verifyNeOne n' a' plit a pa'
      haveI : $pklit =Q $plit ^ $klit := ⟨⟩
      return ⟨pklit, q(PrattPart.prime $plit $klit _ $inner $hpow (.refl _))⟩
    | .split left right => do
      let ⟨nleft, pleft⟩ ← generatePart n' a a' pa' left
      let ⟨nright, pright⟩ ← generatePart n' a a' pa' right
      
      have nn : Q(ℕ) := mkRawNatLit (nleft.natLit! * nright.natLit!)
      haveI : $nn =Q $nleft * $nright := ⟨⟩
      return ⟨nn, q(PrattPart.split $nleft $nright $pleft $pright (.refl _))⟩

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

def Extractor.RoundByRound.id :
    Extractor.RoundByRound oSpec Statement Witness Witness !p[] (fun _ => Witness) where
  eqIn := rfl
  extractMid := fun i => Fin.elim0 i
  extractOut := fun _ _ => _root_.id

def Fin.traverseM {β : Fin n → Type u}
    (f : (i : Fin n) → m (β i)) : m ((i : Fin n) → β i) :=
  let rec aux (k : ℕ) (h : k ≤ n) : m ((i : Fin k) → β (Fin.castLE h i)) :=
    match k with
    | 0 => pure (fun i => i.elim0)
    | k' + 1 => do
      let tail ← aux k' (Nat.le_of_succ_le h)
      let head ← f (Fin.castLE h (Fin.last k'))
      return (Fin.snoc tail head)
  aux n (le_refl n)

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

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)

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

instance [Zero T] [DecidableEq T] [ToNat T] : Div (Cayley T) where
  div := div

noncomputable def foldingDistRange
   (degree : ℕ) [Fintype ι] [Nonempty ι] (φ : ι ↪ F) (f : ι → F) : ℝ :=
    let C : Set (ι → F) := code φ degree
    min δᵣ(f, C) (1 - Bstar (LinearCode.rate (code φ degree)))

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

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

  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

instance {α : Type u} [ToNat α] : CoeHead α Nat where
  coe := ToNat.toNat

Fin.succEmb in Mathlib.Data.Fin.Embedding

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}

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

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

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

Quotient.lift in Init.Core

noncomputable def vanishingPoly (S : Finset F) : Polynomial F :=
  ∏ s ∈ S, (Polynomial.X - Polynomial.C s)

instance : ∀ j, OracleInterface ((pSpecFold D x k s).Message j) :=
  instOracleInterfaceMessageSeqCompose

protected def cast (R : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₁) :
    OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₂ where
  prover := R.prover.cast hn hSpec
  verifier := R.verifier.cast hn hSpec hOₘ

def buildLayer (n : ℕ) (leaves : List.Vector α (2 ^ (n + 1))) :
    OracleComp (spec α) (List.Vector α (2 ^ n)) := do
  let leaves : List.Vector α (2 ^ n * 2) :=

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

instance {ι : Type u} (v : ι → Type v) [O : ∀ i, OracleInterface (v i)]
    [h : ∀ i, DecidableEq (Query (v i))]
    [h' : ∀ i, DecidableEq (Response (v i))] :
    [v]ₒ.DecidableEq where
  domain_decidableEq' := h
  range_decidableEq' := h'

Id.run in Init.Control.Id

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

@[app_unexpander Fin.fcons]
def fconsUnexpander : Lean.PrettyPrinter.Unexpander
  | `($_ $a !h⦃$F⦄⟨$α⟩[$b, $bs,*]) => `(!h⦃$F⦄⟨$α⟩[$a, $b, $bs,*])
  | `($_ $a !h⦃$F⦄⟨$α⟩[$b]) => `(!h⦃$F⦄⟨$α⟩[$a, $b])
  | `($_ $a !h⦃$F⦄⟨$α⟩[]) => `(!h⦃$F⦄⟨$α⟩[$a])
  | _ => throw ()

def toVerifierState (ds : DomainSeparator U H) (transcript : ByteArray) : FSVerifierState U H :=
  FSVerifierState.new ds transcript

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}

Std.Format in Init.Data.Format.Basic

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

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

NatCast in Init.Data.Cast

noncomputable def linearEquivMvPolynomialDeg1 : MlPoly R n ≃ₗ[R] R⦃≤ 1⦄[X Fin n] :=
  { toEquiv := equivMvPolynomialDeg1
    map_add' := by admit /- proof elided -/

instance : Unique (Transcript 0 pSpec) where
  default := fun i => Fin.elim0 i
  uniq := fun T => by admit /- proof elided -/

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

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

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

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

ToString in Init.Data.ToString.Basic

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

noncomputable def queryOracleReduction :
  OracleReduction
    (oSpec := []ₒ)
    (StmtIn := FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (OStmtIn := OracleStatement 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (
    Fin.last ℓ))
    (WitIn := Unit)
    (StmtOut := Bool)
    (OStmtOut := fun _ : Empty => Unit)
    (WitOut := Unit)
    (pSpec := pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) where
  prover := queryOracleProver 𝔽q β (ϑ:=ϑ) γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
  verifier := queryOracleVerifier 𝔽q β (ϑ:=ϑ) γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)

ZMod in Mathlib.Data.ZMod.Defs

def Option.doubleBind {α β γ : Type} (f : α → β → Option γ)
    (x : Option α) (y : Option β) : Option γ :=
  match x, y with
  | none, _ => none
  | _, none => none
  | some a, some b => f a b

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

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

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

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

def getRoot {n : ℕ} (cache : Cache α n) : α :=
  (cache 0).get ⟨0, by admit /- proof elided -/
  ⟩

def zeroCheckVirtualPolynomial (𝕩 : Statement.AfterFirstMessage R pp)
    
    (oStmt : ∀ i, OracleStatement.AfterFirstMessage R pp i) :
      MvPolynomial (Fin pp.ℓ_m) R :=
  letI 𝕫 := R1CS.𝕫 𝕩 (oStmt (.inr 0))
  ∑ x : Fin (2 ^ pp.ℓ_m),
    (eqPolynomial (finFunctionFinEquiv.symm x : Fin pp.ℓ_m → R)) *
      C ((oStmt (.inl .A) *ᵥ 𝕫) x * (oStmt (.inl .B) *ᵥ 𝕫) x - (oStmt (.inl .C) *ᵥ 𝕫) x)

Functor in Init.Prelude

def bivPolyHom {F : Type} [CommRing F] [IsDomain F] :
  Polynomial (F[X]) →+* Polynomial (RatFunc F) := Polynomial.mapRingHom (univPolyHom)

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

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

Set.Pairwise in Mathlib.Logic.Pairwise

Array.foldl in Init.Data.Array.Basic

Prod.fst in Init.Prelude

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

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

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

def externalLinearLayer (state : Vector KoalaBear.Field params.width) :
    Vector KoalaBear.Field params.width :=
  
  let chunks := Vector.Matrix.ofFlatten (state.cast (params.widthDiv4_mul_4_eq_width).symm)
  let chunksAfterM4 := chunks.map (fun chunk => applyM4 chunk)

  
  

  
  let transposedMatrix := Vector.Matrix.transpose chunksAfterM4

  
  let columnSums := transposedMatrix.map (fun col => col.foldl (· + ·) 0)

  
  let chunksAfterDiffusion := chunksAfterM4.map (fun row => row.zipWith (· + ·) columnSums)

  
  (Vector.flatten chunksAfterDiffusion).cast (params.widthDiv4_mul_4_eq_width)

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

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

def SkeletonNodeIndex.path {s : Skeleton} (idx : SkeletonNodeIndex s) :
    List (SkeletonNodeIndex s) := sorry

OracleComp.liftComp in VCVio.OracleComp.Coercions.SubSpec

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

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

def acceptRejectOracleRel : Set ((Bool × (∀ _ : Empty, Unit)) × Unit) :=
  { ((true, isEmptyElim), ()) }

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
    ⟩

Nat.all in Init.Data.Nat.Fold

def Transcript.extractSalt {k : Fin (n + 1)} (transcript : (pSpec.addSalt Salt).Transcript k) :
    (i : pSpec.MessageIdxUpTo k) → Salt ⟨i.val.castLE (by admit /- proof elided -/
    ), by admit /- proof elided -/
    ⟩ :=
  fun i => 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

UInt32 in Init.Prelude

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

@[simp]
def AlgebraTower.toAlgebra {i j : ι} (h : i ≤ j) : Algebra (A i) (A j) :=
  (AlgebraTower.algebraMap (i:=i) (j:=j) (h:=h)).toAlgebra

IO.eprintln in Init.System.IO

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

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 perfectCompleteness
    (relIn : Set ((StmtIn × ∀ i, OStmtIn i) × WitIn))
    (relOut : Set ((StmtOut × ∀ i, OStmtOut i) × WitOut))
    (oracleReduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec) :
      Prop :=
  Reduction.perfectCompleteness init impl relIn relOut oracleReduction.toReduction

MvPolynomial.eval in Mathlib.Algebra.MvPolynomial.Eval

DecidablePred in Init.Prelude

instance instDCast₂Sigma {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    {δ : (a : α) → (b : β a) → γ a b → Type*}
    [DCast α β] [DCast₂ α β γ] [DCast₃ α β γ δ] :
    DCast₂ ((a : α) × β a) (fun a => γ a.1 a.2) (fun a => δ a.1 a.2) where
  dcast₂ ha hb c := dcast₃ (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) (by admit /- proof elided -/
  ) c
  dcast₂_id := by admit /- proof elided -/

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

noncomputable def polynomialFromNovelCoeffs (ℓ : ℕ) (h_ℓ : ℓ ≤ r)
  (a : Fin (2 ^ ℓ) → L) : L[X] := ∑ j, C (a j) * (Xⱼ 𝔽q β ℓ h_ℓ j)

abbrev contract (m : ℕ) (f : Fin n → α) := liftF (liftF' (n := m) (liftF f))

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

LinearMap.codRestrict in Mathlib.Algebra.Module.Submodule.LinearMap

Mathlib.Linter.TextBased.ErrorFormat in Mathlib.Tactic.Linter.TextBased

noncomputable def monomialToNovelCoeffs

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

instance : Field BaseField := ZMod.instField baseFieldSize

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

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

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

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

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

instance {k : Fin 1} : Unique (Transcript k !p[]) where
  default := fun ⟨i, h⟩ => by admit /- proof elided -/

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

def ar2 (k0 k1 : ℕ) : Fin 2 → ℕ
  | ⟨0, _⟩ => k0
  | ⟨1, _⟩ => k1

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

def proximityMeasure (u v : n → F) (d : ℕ) : ℕ :=
  Fintype.card {r : F | Δ₀'(r • u + (1 - r) • v, C) ≤ d}

noncomputable def ElocPolyF (ωs f : Fin n → F) (p : Polynomial F) : Polynomial F :=
  ElocPoly n (liftF ωs) (liftF f) p

abbrev SEP_CHAR : Char := Char.ofNat 0

def foldKStateProp {i : Fin ℓ} (m : Fin (2 + 1))
    (tr : Transcript m (pSpecFold (L := L))) (stmt : Statement (L := L) Context i.castSucc)
    (witMid : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.castSucc)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j) :
    Prop :=
  
  let h_star : ↥L⦃≤ 2⦄[X] := getSumcheckRoundPoly ℓ 𝓑 (i := i) (h := witMid.H)
  
  let get_Hᵢ := fun (m: Fin (2 + 1)) (tr: Transcript m pSpecFold) (hm: 1 ≤ m.val) =>
    let ⟨msgsUpTo, _⟩ := Transcript.equivMessagesChallenges (k := m)
      (pSpec := pSpecFold (L := L)) tr
    let i_msg1 : ((pSpecFold (L := L)).take m m.is_le).MessageIdx :=
      ⟨⟨0, Nat.lt_of_succ_le hm⟩, by admit /- proof elided -/
      ⟩
    let h_i : L⦃≤ 2⦄[X] := msgsUpTo i_msg1
    h_i

  let get_rᵢ' := fun (m: Fin (2 + 1)) (tr: Transcript m pSpecFold) (hm: 2 ≤ m.val) =>
    let ⟨msgsUpTo, chalsUpTo⟩ := Transcript.equivMessagesChallenges (k := m)
      (pSpec := pSpecFold (L := L)) tr
    let i_msg1 : ((pSpecFold (L := L)).take m m.is_le).MessageIdx :=
      ⟨⟨0, Nat.lt_of_succ_le (Nat.le_trans (by admit /- proof elided -/
      ) hm)⟩, by admit /- proof elided -/
      ⟩
    let h_i : L⦃≤ 2⦄[X] := msgsUpTo i_msg1
    let i_msg2 : ((pSpecFold (L := L)).take m m.is_le).ChallengeIdx :=
      ⟨⟨1, Nat.lt_of_succ_le hm⟩, by admit /- proof elided -/
      ⟩
    let r_i' : L := chalsUpTo i_msg2
    r_i'

  match m with
  | ⟨0, _⟩ => 
    masterKStateProp (mp := mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (stmtIdx := i.castSucc) (oracleIdx := i.castSucc)
      (h_le := le_refl _)
      (stmt := stmt) (wit := witMid) (oStmt := oStmt)
      (localChecks := True)
  | ⟨1, h1⟩ => 
    masterKStateProp (mp := mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (stmtIdx := i.castSucc) (oracleIdx := i.castSucc)
      (h_le := le_refl _)
      (stmt := stmt) (wit := witMid) (oStmt := oStmt)
      (localChecks :=
        let h_i := get_Hᵢ (m := ⟨1, h1⟩) (tr := tr) (hm := by admit /- proof elided -/
        )
        let explicitVCheck := h_i.val.eval 0 + h_i.val.eval 1 = stmt.sumcheck_target
        let localizedRoundPolyCheck := h_i = h_star
        explicitVCheck ∧ localizedRoundPolyCheck
      )
  | ⟨2, h2⟩ => 
    
    masterKStateProp (mp := mp) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑)
      (stmtIdx := i.castSucc) (oracleIdx := i.castSucc)
      (h_le := le_refl _)
      (stmt := stmt) (wit := witMid) (oStmt := oStmt)
      (localChecks :=
        let h_i := get_Hᵢ (m := ⟨2, h2⟩) (tr := tr) (hm := by admit /- proof elided -/
        )
        let r_i' := get_rᵢ' (m := ⟨2, h2⟩) (tr := tr) (hm := by admit /- proof elided -/
        )
        let localizedRoundPolyCheck := h_i = h_star
        let nextSumcheckTargetCheck := 
          h_i.val.eval r_i' = h_star.val.eval r_i'
        localizedRoundPolyCheck ∧ nextSumcheckTargetCheck
      ) 

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

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

instance instInvConcreteBTF {k : ℕ} : Inv (ConcreteBTField k) where
  inv := concrete_inv

Nat.max in Init.Data.Nat.Basic

def toList (xs : ChurchVec α) : List α :=
  churchVecFold xs (fun x acc => x :: acc) []

CommGroup in Mathlib.Algebra.Group.Defs

Or in Init.Prelude

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

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

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

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

Finsupp.cons in Mathlib.Data.Finsupp.Fin

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

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

instance {bIdx : Fin (ℓ / ϑ - 1)} : ∀ j, OracleInterface ((pSpecFullNonLastBlock 𝔽q β
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate) bIdx).Message j) :=
  instOracleInterfaceMessageAppend

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

structure GaloisAutomorphism (F : Type*) [Field F] (u : F) (k : ℕ) : Prop where
  forward : u ^ (2 ^ (2 ^ k)) = u⁻¹
  reverse : (u⁻¹) ^ (2 ^ (2 ^ k)) = u

MulOneClass in Mathlib.Algebra.Group.Defs

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

instance instSetoidUniPoly : Setoid (UniPoly R) where
  r := equiv
  iseqv := instEquivalenceEquiv

Matrix.submatrix in Mathlib.LinearAlgebra.Matrix.Defs

Finset.sum in Mathlib.Algebra.BigOperators.Group.Finset.Defs

private def Fi (B : Finset (Fin n → F)) (i : Fin n) (α : F) : Finset (Fin n → F) :=
  { x | x ∈ B ∧ x i = α }

@[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 add (p q : UniPoly R) : UniPoly R :=
  add_raw p q |> trim

def AlgebraTowerEquiv.toAlgEquivOverRight (e : AlgebraTowerEquiv A B) (i j : ι) (h : i ≤ j) :
  letI : Algebra (B i) (B j) :=

instance : ∀ i, OracleInterface ((pSpecCoreInteraction 𝔽q β (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Message i) := instOracleInterfaceMessageAppend

Set in Mathlib.Data.Set.Defs

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

@[reducible]
def oracleReduction : OracleReduction oSpec
    (StatementRound R n 0) (OracleStatement R n deg) Unit
    (StatementRound R n (.last n)) (OracleStatement R n deg) Unit
    (pSpec R deg n) :=
  OracleReduction.seqCompose (oSpec := oSpec)
    (Stmt := StatementRound R n)
    (OStmt := fun _ => OracleStatement R n deg)
    (Wit := fun _ => Unit)
    (pSpec := fun _ => SingleRound.pSpec R deg)
    (SingleRound.oracleReduction R n deg D oSpec)

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

Fintype.card in Mathlib.Data.Fintype.Card

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

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

def SkeletonInternalIndex.toNodeIndex {s : Skeleton} (idx : SkeletonInternalIndex s) :
    SkeletonNodeIndex s :=
  match idx with
  | SkeletonInternalIndex.ofInternal => SkeletonNodeIndex.ofInternal
  | SkeletonInternalIndex.ofLeft idxLeft =>
    SkeletonNodeIndex.ofLeft (SkeletonInternalIndex.toNodeIndex idxLeft)
  | SkeletonInternalIndex.ofRight idxRight =>
    SkeletonNodeIndex.ofRight (SkeletonInternalIndex.toNodeIndex idxRight)

Context in Examples.FrankingProtocol

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

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

alias trivial := Witness.InvLens.id

def parametrisedCurveFinite [DecidableEq ι] [Fintype F] [DecidableEq F] [Semiring F]
  {l : ℕ} (u : Fin l → ι → F) : Finset (ι → F) :=
  {v | ∃ r : F, v = ∑ i : Fin l, (r ^ (i : ℕ)) • u i}

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

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

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

@[simp]
def oCtxLens (i : Fin n) : OracleContext.Lens
    (StatementRound R n i.castSucc) (StatementRound R n i.succ) (Simple.StmtIn R) (Simple.StmtOut R)
    (OracleStatement R n deg) (OracleStatement R n deg)
    (Simple.OStmtIn R deg) (Simple.OStmtOut R deg)
    Unit Unit Unit Unit where
  wit := Witness.Lens.trivial
  stmt := oStmtLens R n deg D i

instance : ∀ j, OracleInterface ((batchSpec F m).Message j)
  | ⟨0, h⟩ => nomatch h

abbrev Fwd : PermuteDir := Sum.inl ()

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

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

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

def map {α β : Fin n → Sort*} (f : (i : Fin n) → α i → β i) (a : (i : Fin n) → α i) :
    (i : Fin n) → β i := fun i => f i (a i)

instance : curve.IsElliptic :=

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

private def Bi (B : Finset (Fin n → F)) (i : Fin n) : Finset ((Fin n → F) × (Fin n → F)) :=
  { x | x ∈ B ×ˢ B ∧ x.1 i = x.2 i ∧ x.1 ≠ x.2 }

noncomputable def listDecodingCollisionProbability
  (φ : ι ↪ F) (f : ι → F) (δ : ℝ) (s degree : ℕ)
  (h_nonempty : Nonempty (domainComplement φ)) : ENNReal :=
  Pr_{let r ←$ᵖ (Fin s → domainComplement φ)}[ ∃ (u u' : code φ degree),
                                    u.val ≠ u'.val ∧
                                    u.val ∈ relHammingBall (code φ degree) f δ ∧
                                    u'.val ∈ relHammingBall (code φ degree) f δ ∧
                                    ∀ i : Fin s,
                                    let uPoly := decodeLT u
                                    let uPoly' := decodeLT u'
                                    (uPoly : F[X]).eval (r i).1
                                      = (uPoly' : F[X]).eval (r i).1
                                    ]

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

Fin.succAboveEmb in Mathlib.Data.Fin.Embedding

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

noncomputable def S_β {H : F[X][Y]} (β : 𝒪 H) : Set F :=
  {z : F | ∃ root : rationalRoot (H_tilde' H) z, (π_z z root) β = 0}

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

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

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

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

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

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

def DVec {m : Type v} (α : m → Type u) : Type (max u v) := ∀ i, α i

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

def Reduction.append (R₁ : Reduction oSpec Stmt₁ Wit₁ Stmt₂ Wit₂ pSpec₁)
    (R₂ : Reduction oSpec Stmt₂ Wit₂ Stmt₃ Wit₃ pSpec₂) :
      Reduction oSpec Stmt₁ Wit₁ Stmt₃ Wit₃ (pSpec₁ ++ₚ pSpec₂) where
  prover := Prover.append R₁.prover R₂.prover
  verifier := Verifier.append R₁.verifier R₂.verifier

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

Nat.boddDiv2 in Mathlib.Data.Nat.Bits

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

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

def extractability (scheme : Scheme oSpec Data Randomness Commitment pSpec)
    (extractabilityError : ℝ≥0) : Prop :=
  ∃ extractor : StraightlineExtractor oSpec Data Commitment,
  ∀ AuxState : Type,
  ∀ adversary : ExtractabilityAdversary oSpec Data Commitment AuxState,
  ∀ prover : Prover oSpec (Commitment × O.Query × O.Response) AuxState Bool Unit pSpec,
    False

instance [Semiring R] : Module R (MlPolyEval R n) where
  smul := smul
  one_smul a := by admit /- proof elided -/

def mkRingInstance {k : ℕ} (props : ConcreteBTFieldProps k) : Ring (ConcreteBTField k) where
  toAddCommGroup := mkAddCommGroupInstance
  toOne := inferInstance
  mul := concrete_mul
  mul_assoc := props.mul_assoc
  one_mul := props.one_mul
  mul_one := props.mul_one
  left_distrib := props.mul_left_distrib
  right_distrib := props.mul_right_distrib
  zero_mul := props.zero_mul
  mul_zero := props.mul_zero

  natCast n := natCast n
  natCast_zero := natCast_zero
  natCast_succ n := natCast_succ n
  intCast n := intCast n
  intCast_ofNat n := intCast_ofNat n
  intCast_negSucc n := intCast_negSucc n

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

toNat in Mathlib.Computability.Reduce

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

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

AddMonoidAlgebra in Mathlib.Algebra.MonoidAlgebra.Defs

Fin.tail in Mathlib.Data.Fin.Tuple.Basic

Sum.inl in Init.Core

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

def secondSumCheckVirtualPolynomial
    (stmt : Statement.AfterLinearCombination R pp)
    (oStmt : ∀ i, OracleStatement.AfterLinearCombination R pp i) :
      MvPolynomial (Fin pp.ℓ_n) R := sorry

def FullData.getRootValue {s} {α : Type} (tree : FullData α s) :=
  tree.get (getRootIndex s)

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

instance : Coe (∀ a : α, β a) F where
  coe := DFunEquiv.equiv.invFun

Finsupp.linearCombination in Mathlib.LinearAlgebra.Finsupp.LinearCombination

def mkFieldInstance {k : ℕ} (props : ConcreteBTFieldProps k) : Field (ConcreteBTField k) where
  toDivisionRing := mkDivisionRingInstance (k:=k) props
  mul_comm := props.mul_comm

noncomputable def towerRingHomForwardMap (k : ℕ) : ConcreteBTField k → BTField k :=

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

@[ext]
structure Cayley (T : Type u) [HasSucc T] where
   
  toFun : T → T
   
  toFun_succ : ∀ (t : T), toFun (succ' t) = succ' (toFun t)

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

HSMul in Init.Prelude

@[app_unexpander Fin.vcons]
def vconsUnexpander : Lean.PrettyPrinter.Unexpander
  | `($_ $term !v[$term2, $terms,*]) => `(!v[$term, $term2, $terms,*])
  | `($_ $term !v[$term2]) => `(!v[$term, $term2])
  | `($_ $term !v[]) => `(!v[$term])
  | _ => throw ()

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

Nat.decEq 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 · * ·)

def getConst (k : ℕ) (s : Fin (k + 1) → ℕ+) : OracleComp [FinalOracleStatement D x s]ₒ F[X] :=
  OracleComp.lift
    (by admit /- proof elided -/
    )

def SkeletonNodeIndex.isLeaf {s : Skeleton} (idx : SkeletonNodeIndex s) : Bool :=
  match idx with
  | SkeletonNodeIndex.ofLeaf => true
  | SkeletonNodeIndex.ofInternal => false
  | SkeletonNodeIndex.ofLeft _ => false
  | SkeletonNodeIndex.ofRight _ => false

instance coe_field_adjoinRoot (k : ℕ) : Coe (AdjoinRoot (poly k)) (BTField (k+1)) where
  coe := Eq.mp (BTField_succ_eq_adjoinRoot k)

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

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

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

Fintype in Mathlib.Data.Fintype.Defs

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 OracleReduction.addSalt
    (R : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec)
    (saltComp : (i : pSpec.MessageIdx) → R.prover.PrvState i.1.castSucc →
      OracleComp oSpec (Salt i)) :
    OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut (pSpec.addSalt Salt) where
  prover := R.prover.addSalt Salt saltComp
  verifier := R.verifier.addSalt Salt

def basisSucc (k : ℕ) : Basis (Fin 2) (ConcreteBTField k) (ConcreteBTField (k + 1)) :=

Matrix.vandermonde in Mathlib.LinearAlgebra.Vandermonde

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

Subgroup.zpowers in Mathlib.Algebra.Group.Subgroup.ZPowers.Basic

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

Nat.cast in Init.Data.Cast

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

def finUInt64Equiv : Fin (2 ^ 64) ≃ UInt64 where
  toFun := fun i => UInt64.ofFin i
  invFun := fun u => u.toFin
  left_inv _ := rfl
  right_inv _ := rfl

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

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

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

instance : Zero (Cayley T) where
  zero := zero

Nat.decLe in Init.Prelude

Eq in Init.Prelude

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

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

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

structure FinalSumcheckStatementOut extends
  Statement (L := L) (Context := SumcheckBaseContext L ℓ) (Fin.last ℓ) where
  final_constant : L               

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

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

Vector.tail in Init.Data.Vector.Basic

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

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

OrderDual in Mathlib.Order.Basic

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

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 γ == β

Submodule.span in Mathlib.LinearAlgebra.Span.Defs

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

def Mymotive : Fin 3 → Type := !v[ℕ, Bool, String]

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


example : !v[1, 2] ++ᵛ !v[3, 4] = !v[1, 2, 3, 4] := rfl
example : (0 : ℕ) ::ᵛ !v[1, 2] = !v[0, 1, 2] := rfl
example : !v[1, 2] :+ᵛ (3 : ℕ) = !v[1, 2, 3] := rfl


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


example : !h[(1 : ℕ), (true : Bool), ("hello" : String)] =
  Fin.hcons 1 (Fin.hcons true ("hello" ::ʰ⟨String ; !v[]⟩ !h[])) := rfl

def powFiber (S : Finset ι) (φ : ι ↪ F) (k : ℕ) (y : indexPow S φ k) : Finset ι :=
  S.filter (fun x => (φ x) ^ k = y)

def Matrix (α : Type*) (m n : ℕ) := Vector (Vector α n) m

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

@[inline] def le [Zero T] [ToNat T] (a b : Cayley T) : Prop :=
  (↑a : Nat) ≤ (↑b : Nat)

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

UInt8 in Init.Prelude

def inputRelation : Set ((StmtIn R × (∀ i, OStmtIn R deg i)) × Unit) :=
  { ⟨⟨target, oStmt⟩, _⟩ | ∑ x ∈ (univ.map D), (oStmt ()).1.eval x = target }

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

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

noncomputable instance {s : Set (ι → F)} : Fintype (affineSpan F s) :=
  Fintype.ofFinite ↥(affineSpan F s)

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

Fin.succ in Init.Data.Fin.Basic

Repr in Init.Data.Repr

Finsupp in Mathlib.Data.Finsupp.Defs

def curve : WeierstrassCurve BaseField := {
  a₁ := 0,  
  a₂ := 0,  
  a₃ := 0,  
  a₄ := 0,  
  a₆ := 3   
}

def knowledgeStateFunction (hRel : ∀ stmtIn witOut,
      (mapStmt stmtIn, witOut) ∈ relOut → (stmtIn, mapWitInv stmtIn witOut) ∈ relIn) :
    (verifier oSpec mapStmt).KnowledgeStateFunction
      init impl relIn relOut (extractor mapWitInv) where
  toFun | ⟨0, _⟩ => fun stmtIn _ witIn => ⟨stmtIn, witIn⟩ ∈ relIn
  toFun_empty := fun stmtIn witIn => by admit /- proof elided -/

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

Polynomial.modByMonic in Mathlib.Algebra.Polynomial.Div

def fiberEvaluationMapping (i : Fin r) (steps : ℕ) (h_i_add_steps : i.val + steps < ℓ + 𝓡)
    (f : (sDomain 𝔽q β h_ℓ_add_R_rate) i → L)
    (y : (sDomain 𝔽q β h_ℓ_add_R_rate)
      ⟨↑i + steps, by admit /- proof elided -/
      ⟩)
    : Fin (2 ^ steps) → L :=
  
  let fiberMap := qMap_total_fiber 𝔽q β (i := i) (steps := steps)
    (h_i_add_steps := h_i_add_steps) (y := y)

  
  fun idx => f (fiberMap idx)

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

instance : ∀ j, OracleInterface (OracleStatement D x m j) :=
  fun _ => inferInstance

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
    )

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

noncomputable def polyQuotient (S : Finset F) (fPoly : F[X]) : F[X] :=
    (fPoly - (ansPoly S (fun s => fPoly.eval s))) / (vanishingPoly S)

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

ZMod.instField in Mathlib.Algebra.Field.ZMod

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

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

Empty in Init.Prelude

def uniqueDecodable (C : Code ι F) (r : ℝ) : Prop :=
  listDecodable C r 1

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

Nat.succ in Init.Prelude

@[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 listOfCloseCodewordsRel (C : Code ι F) (y : ι → F) (r : ℝ) : ℕ :=
  Nat.card (relHammingBall C y r)

noncomputable def UniPolyC.toPoly (p : UniPolyC R) : Polynomial R := p.val.toPoly

alias ofPoly := Polynomial.toImpl

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

def absorb (sponge : DuplexSponge U C) (ls : List U) :
    OracleComp (forwardPermutationOracle C) (DuplexSponge U C) :=
  match ls with
  
  
  | [] => pure { sponge with squeezePos := Fin.last SpongeSize.R }
  
  | x :: xs =>
    
    
    
    if sponge.absorbPos = SpongeSize.R then do
      let permutedState ← query (spec := forwardPermutationOracle _) () (sponge.state)
      let newSponge : DuplexSponge U C := {
        state := SpongeState.modify permutedState (Vector.set · 0 x),
        absorbPos := 1
        squeezePos := Fin.last SpongeSize.R }
      
      absorb newSponge xs
    else do
      
      
      
      let newSponge : DuplexSponge U C := {
        state := SpongeState.modify sponge.state (Vector.set · (sponge.absorbPos : Nat) x),
        absorbPos := sponge.absorbPos + 1,
        squeezePos := Fin.last SpongeSize.R }
      absorb newSponge xs

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

def linearCodeDist' {F} {ι} [Fintype ι] [Semiring F] [DecidableEq F] [Fintype F] [DecidableEq ι]
 (LC : LinearCode ι F) [DecidablePred (· ∈ LC)] : ℕ∞ :=
  Finset.min <| ((Finset.univ (α := LC)).filter (fun v => v ≠ 0)).image (fun v => hammingNorm v.1)

@[inline, specialize]
def nsmul (n : ℕ) (p : UniPoly R) : UniPoly R :=
  nsmul_raw n p |> trim

Multiset.count in Mathlib.Data.Multiset.Count

@[ext]
structure Reduction {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn WitIn StmtOut WitOut : Type) {n : ℕ} (pSpec : ProtocolSpec n) where
  prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec
  verifier : Verifier oSpec StmtIn StmtOut pSpec

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

@[reducible, simp] def StmtOut : Type := R × R

BitVec in Init.Prelude

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

Fin.insertNth in Mathlib.Data.Fin.Tuple.Basic

IsField.toField in Mathlib.Algebra.Field.IsField

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

LE.le in Init.Prelude

Multiset.ofList in Mathlib.Data.Multiset.Defs

@[inline]
def ofOutputOnly
    (liftWit : OuterStmtIn × OuterWitIn → InnerStmtOut × InnerWitOut → OuterWitOut) :
    Witness.Lens OuterStmtIn InnerStmtOut OuterWitIn OuterWitOut OuterWitIn InnerWitOut :=
  ⟨Prod.snd, liftWit⟩

noncomputable def fromConcreteBTF0 : ConcreteBTField 0 → (GF(2)) :=
  fun x => if decide (x = zero) then 0 else 1

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

def toProverState (ds : DomainSeparator U H) (rng : R) : FSProverState U H R :=
  FSProverState.new ds rng

Nat.testBit in Init.Data.Nat.Bitwise.Basic

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)

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

class Deserialize (α : Type u) (β : Type v) where
  deserialize : β → α

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

ByteArray.empty in Init.Prelude

CommMonoid in Mathlib.Algebra.Group.Defs

instance (priority := low) : DCast α β where
  dcast h := cast (congrArg β h)
  dcast_id := by admit /- proof elided -/

Fintype.ofFinite in Mathlib.Data.Fintype.EquivFin

Unique in Mathlib.Logic.Unique

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

Infinite in Mathlib.Data.Finite.Defs

instance : ∀ i, NeZero (toOutCodewordsCount ℓ ϑ i) :=

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

@[simp]
instance BTFieldNoZeroDiv (k : ℕ) : NoZeroDivisors (BTField k) :=

cast in Init.Prelude

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

ENat.toNat in Mathlib.Data.ENat.Basic

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

structure SumcheckBaseContext (L : Type) (ℓ : ℕ) where
  t_eval_point : Fin ℓ → L         
  original_claim : L               

ZeroMemClass in Mathlib.Algebra.Group.Submonoid.Defs

def singleHash (left : α) (right : α) : OracleComp (spec α) α := do
  let out ← query (spec := spec α) () ⟨left, right⟩
  return out

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

def equivFin2 : Direction ≃ Fin 2 where
  toFun := fun dir => match dir with | .V_to_P => ⟨0, by admit /- proof elided -/
  ⟩ | .P_to_V => ⟨1, by admit /- proof elided -/
  ⟩
  invFun := fun n => match n with | ⟨0, _⟩ => .V_to_P | ⟨1, _⟩ => .P_to_V
  left_inv := fun dir => match dir with | .P_to_V => rfl | .V_to_P => rfl
  right_inv := fun n => match n with | ⟨0, _⟩ => rfl | ⟨1, _⟩ => rfl

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

Nat.bit in Mathlib.Data.Nat.BinaryRec

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

noncomputable def ηStar (U : Type) [SpongeUnit U] [Fintype U]
    (tₕ tₚ tₚᵢ : ℕ) (L : ℕ) (εcodec : pSpec.ChallengeIdx → ℝ≥0) : ℝ≥0 :=
  let tTotal : ℕ := (tₕ + tₚ + tₚᵢ)
  
  
  
  
  let firstTermNumerator : ℝ≥0 :=
    7 * tTotal ^2 + (28 * L + 25) * tTotal + (14 * L + 1) * (L + 1)
  let firstTermDenominator : ℝ≥0 := 2 * ((Fintype.card U) ^ (SpongeSize.C + 1))
  
  let secondTerm : ℝ≥0 := θStar tₕ tₚ tₚᵢ * (iSup εcodec)
  
  let thirdTerm : ℝ≥0 := ∑ i, εcodec i
  
  firstTermNumerator / firstTermDenominator + secondTerm + thirdTerm

noncomputable def sDomainBasisVectors (i : Fin r) : Fin (ℓ + R_rate - i) → L :=
  fun k => (normalizedW 𝔽q β i).eval (β ⟨i + k.val, by admit /- proof elided -/
  ⟩)

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

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

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

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

@[inline, specialize]
def oracleVerifier : OracleVerifier oSpec
    Unit (fun _ : Fin 2 => OStatement)
    (Query OStatement) (fun _ : Fin 2 => OStatement) (pSpec OStatement) where

  verify := fun _ chal => do
    let q : Query OStatement := chal ⟨0, rfl⟩
    pure q

  embed := Function.Embedding.inl

  hEq := by admit /- proof elided -/

instance : Unique (FullTranscript (default : ProtocolSpec 0)) := inferInstance

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

def fnOracle (spec : OracleSpec ι) (f : (i : ι) → spec.domain i → spec.range i) :
    SimOracle.Impl spec where
  impl | query i t => pure (f i t)

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

@[inline, reducible]
def lift : OuterStmtIn → InnerStmtOut → OuterStmtOut :=
  lens.toFunB

class PolynomialLike.LawfulCoeff (R : Type u) [CommSemiring R] (P : Type v) [CommSemiring P]
    [PolynomialLike R P] (coeff : P → ℕ → R) where
  coeff_finite (p : P) : Set.Finite {n | coeff p n ≠ 0}

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

OptionT in Init.Control.Option

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

structure CodeParams (P : Params ι F) (Dist : Distances M) where
  C : ∀ i : Fin (M + 1), Set ((ι i) → F)
  h_code : ∀ i : Fin (M + 1), C i = code (P.φ i) (degree ι P i)
  h_listDecode : ∀ i : Fin (M + 1), i ≠ 0 → listDecodable (C i) (Dist.δ i) (Dist.l i)

Classical.arbitrary in Mathlib.Logic.Nonempty

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

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

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

instance [inst : SelectableType Chal] : ∀ i, SelectableType (Challenge ⟨!v[.V_to_P], !v[Chal]⟩ i)
  | ⟨0, _⟩ => inst

UInt64.ofFin in Init.Data.UInt.Basic

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

GaloisField.equivZmodP in Mathlib.FieldTheory.Finite.GaloisField

instance : ∀ i, VCVCompatible (Challenge ⟨!v[.P_to_V], !v[Msg]⟩ i)
  | ⟨0, h⟩ => nomatch h

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

LinearIndepOn in Mathlib.LinearAlgebra.LinearIndependent.Defs

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

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

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

def multilinearBasis (l r : ℕ) (h_le : l ≤ r) :
    letI instAlgebra : Algebra (BTField l) (BTField r) := binaryAlgebraTower (h_le:=h_le)
    Basis (Fin (2 ^ (r - l))) (BTField l) (BTField r) :=

def lt {α : Type} (m n : ChurchNat α) : ChurchBool α :=
  ChurchBool.churchAnd (leq m n) (ChurchBool.churchNot (leq n m))

OrderDual.toDual in Mathlib.Order.Synonym

def KnowledgeStateFunctionOneShot.toKnowledgeStateFunction
    {relIn : Set (StmtIn × WitIn)} {relOut : Set (StmtOut × WitOut)}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec}
    (stF : KnowledgeStateFunctionOneShot init impl relIn.language relOut.language verifier)
    (oneShotE : Extractor.RoundByRoundOneShot oSpec StmtIn WitIn pSpec) :
    verifier.KnowledgeStateFunction init impl relIn relOut oneShotE.toRoundByRound where
  toFun := fun m stmtIn tr witIn => if m = 0 then (stmtIn, witIn) ∈ relIn else
    stF.toFun m stmtIn tr ∨ (stmtIn, oneShotE m stmtIn tr default) ∈ relIn
  toFun_empty := fun stmtIn witIn => by admit /- proof elided -/

@[inline, specialize]
def runWithLogToRound (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) × QueryLog (oSpec ++ₒ [pSpec.Challenge]ₒ)) :=
  (simulateQ loggingOracle (prover.runToRound i stmt wit)).run

cond in Init.Prelude

def extract {n : ℕ} {α : Fin n → Sort*} (start stop : ℕ) (h1 : start ≤ stop) (h2 : stop ≤ n)
    (v : (i : Fin n) → α i) : (i : Fin (stop - start)) → α ⟨i + start, by admit /- proof elided -/
    ⟩ :=
  fun i ↦ v ⟨i + start, by admit /- proof elided -/
  ⟩

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

inductive PrattPart : (p : ℕ) → (a : ZMod p) → ℕ → Prop
  | prime : {p : ℕ} → {a : ZMod p} → (n k nk : ℕ) → n.Prime →
      a ^ ((p - 1) / n) ≠ 1 → n ^ k = nk → PrattPart p a nk
  | split : {p : ℕ} → {a : ZMod p} → {n : ℕ} → (l r : ℕ) →
      PrattPart p a l → PrattPart p a r → l * r = n → PrattPart p a n

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

AdjoinRoot in Mathlib.RingTheory.AdjoinRoot

def Option.doubleBind_v3 {α β γ : Type} (f : α → β → Option γ)
    (x : Option α) (y : Option β) : Option γ := do f (← x) (← y)

instance : ∀ j, OracleInterface ((fullPSpec 𝔽q β γ_repetitions (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Message j) := instOracleInterfaceMessageAppend

instance {U : Type} {H : Type*} {R : Type*} [SpongeUnit U] [DuplexSpongeInterface U H] :
    UnitTranscript (FSProverState U H R) U where
  publicUnits state input := do
    
    
    let newState ← state.addUnits input
    .ok { rng := newState.rng, hashState := newState.hashState,
          nargString := state.nargString } 
  fillChallengeUnits state count :=
    match state.hashState.squeeze count with
    | .ok (newHashState, output) =>
      .ok ({ rng := state.rng, hashState := newHashState, nargString := state.nargString }, output)
    | .error e => .error e

def eq {α : Type u} (mx my : m α) : Prop :=
  evalDist mx = evalDist my

class HasSucc (T : Type u) where
   
  succ' : T → T

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

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 millerRabinBases : List ℕ :=
  [2, 325, 9375, 28178, 450775, 9780504, 1795265022]

List.Vector.snoc in Mathlib.Data.Vector.Snoc

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

def subNat [Zero T] [ToNat T] (a : Cayley T) : Nat → Cayley T
  | 0        => a
  | .succ k  => pred (subNat a k)

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

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

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

UInt16.ofFin in Init.Data.UInt.Basic

instance : Sub AssocNat where
  sub := sub

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

  inductive UnverifiedPrattCertificate : ℕ → Type
    | knownPrime : (n : ℕ) → UnverifiedPrattCertificate n
    | of : (n : ℕ) → (a : ℕ) → (part : UnverifiedPrattPart) → UnverifiedPrattCertificate n
  deriving Repr

NatPow in Init.Prelude

instance [Inhabited OuterWitOut]
    [instKS : lens.IsKnowledgeSound
                outerRelIn innerRelIn
                outerRelOut innerRelOut
                compatStmt (fun _ _ => True)] :
    lens.stmt.IsSound
      outerRelIn.language outerRelOut.language
      innerRelIn.language innerRelOut.language
      compatStmt where
  proj_sound := fun outerStmtIn hCompat => by admit /- proof elided -/

DivisionRing in Mathlib.Algebra.Field.Defs

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

def binaryTowerModule {l r : ℕ} (h_le : l ≤ r) : Module (BTField l) (BTField r) :=
  (binaryAlgebraTower (h_le:=h_le)).toModule

def block (i : ℕ) {k : ℕ} {S : Finset ι} {φ : ι ↪ F}
  (S' : Finset (indexPowT S φ i))
  (φ' : (indexPowT S φ i) ↪ F) (z : indexPowT S φ k)
  [DecidableEq F] [DecidableEq ι] [Smooth φ] :=
    powFiberT i S' φ' z

noncomputable def ofPolynomialAlgHom : R[X] →ₐ[R] P := Polynomial.aeval PolynomialLike.X

def towerOfExponents (g : G) (a : ZMod p) (n : ℕ) : Vector G (n + 1) :=
  .ofFn (fun i => g ^ (a.val ^ i.val))

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

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

RingHom in Mathlib.Algebra.Ring.Hom.Defs

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

structure ProverInteraction {ι : Type} (oSpec : OracleSpec ι) {n : ℕ} (pSpec : ProtocolSpec n)
    extends ProverState n, ProverInit (PrvState 0), ProverRound oSpec pSpec

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

Lean.parseImports' in Lean.Elab.ParseImportsFast

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

noncomputable def basisVectors (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  Fin (2 ^ ℓ) → L⦃<2^ℓ⦄[X] :=
  fun j => ⟨Xⱼ 𝔽q β ℓ h_ℓ j, by admit /- proof elided -/
  ⟩

instance {i : Fin r} : DecidableEq (U 𝔽q β i) :=

BitVec.getLsb in Init.Data.BitVec.Basic

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 ⟩

Polynomial.charP in Mathlib.Algebra.Polynomial.Coeff

def masterKStateProp (stmtIdx : Fin (ℓ + 1))
    (oracleIdx : Fin (ℓ + 1))
    (h_le : oracleIdx.val ≤ stmtIdx.val) (stmt : Statement (L := L) Context stmtIdx)
    (wit : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) stmtIdx)
    (oStmt : ∀ j, (OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (i := oracleIdx) j))
    (localChecks : Prop := True) : Prop :=
  let oracleWitnessConsistency: Prop := oracleWitnessConsistency (mp := mp) (𝓑 := 𝓑) 𝔽q β
    stmtIdx oracleIdx h_le stmt wit oStmt
  let badEventExists := badEventExistsProp (ϑ := ϑ) 𝔽q β oracleIdx
    (challenges := Fin.take (m := oracleIdx) (v := stmt.challenges) (h := by admit /- proof elided -/
    ))
    (oStmt := oStmt)
  localChecks ∧ (badEventExists ∨ oracleWitnessConsistency)

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

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

MvPolynomial.monomial in Mathlib.Algebra.MvPolynomial.Basic

instance : Pow (UniPoly R) Nat := ⟨UniPoly.pow⟩

Finset.Nonempty in Mathlib.Data.Finset.Empty

Fin.natAdd in Init.Data.Fin.Basic

Fin.removeNth in Mathlib.Data.Fin.Tuple.Basic

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 }

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, inline, specialize]
def OracleMessage (i : pSpec.OracleMessageIdx) := pSpec.Message i.1

instance {k : Fin 1} : Unique (MessagesUpTo k !p[]) where
  default := fun ⟨⟨i, h⟩, _⟩ => by admit /- proof elided -/

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

List.IsPrefix in Init.Data.List.Basic

HMul.hMul in Init.Prelude

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

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 

def someTypes : List Type := [Nat, String, Nat]

Module.Basis in Mathlib.LinearAlgebra.Basis.Defs

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⟩ :=

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

noncomputable def mVdecode :
  (smoothCode domain m) →ₗ[F] MvPolynomial (Fin m) F :=
    linearMvExtension.comp decodeLT

def knowledgeStateFunction :
    (oracleVerifier oSpec OStatement).KnowledgeStateFunction init impl
    (relIn OStatement) (relOut OStatement) (rbrExtractor oSpec OStatement) where
  toFun
  | 0 => fun ⟨_, oracles⟩ _ _ => oracles 0 = oracles 1
  | 1 => fun ⟨_, oracles⟩ chal _ =>
    let q : Query OStatement := by admit /- proof elided -/

def Verifier.addSalt (V : Verifier oSpec StmtIn StmtOut pSpec) :
    Verifier oSpec StmtIn StmtOut (pSpec.addSalt Salt) where
  verify := fun stmtIn transcript => V.verify stmtIn transcript.removeSalt

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

def relationRound (i : Fin (n + 1)) :
    Set (((StatementRound R n i) × (∀ i, OracleStatement R n deg i)) × Unit) :=
  { ⟨⟨⟨target, challenges⟩, polyOracle⟩, _⟩ |
    ∑ x ∈ (univ.map D) ^ᶠ (n - i), (polyOracle ()).val ⸨challenges, x⸩ = target }

def ofNat (n : ℕ) : ValidChurchNat :=
  ⟨ChurchNat.ofNat n, n, by admit /- proof elided -/
      ⟩

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

def completeness (relIn : Set (StmtIn × WitIn))
    (relOut : Set (StmtOut × WitOut))
    (reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec)
    (completenessError : ℝ≥0) : Prop :=
  ∀ stmtIn : StmtIn,
  ∀ witIn : 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 - completenessError

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

def InnerStmtIn_Test := ℤ[X] × ℤ

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 {i : Fin k} : ∀ j, OracleInterface ((pSpec D x s i).Message j)
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => by admit /- proof elided -/

List.finRange in Init.Data.List.FinRange

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

@[reducible]
noncomputable def batchedFRIreduction [DecidableEq F] :=
  OracleReduction.append
    (BatchingRound.batchOracleReduction D x s d m)
    (liftedFRI D x k s d dom_size_cond l m)

def hcons {n : ℕ} {α : Sort u} {β : Fin n → Sort u} (a : α) (b : (i : Fin n) → β i) :
    (i : Fin (n + 1)) → Fin.vcons α β i :=
  fcons (F := id) a b

AdjoinRoot.root in Mathlib.RingTheory.AdjoinRoot

Classical.typeDecidableEq in Init.Classical

@[reducible, simp]
def StmtOut : Type := R × R

@[inline, specialize]
def reduction : Reduction oSpec Statement Unit Statement Unit !p[] where
  prover := prover oSpec Statement
  verifier := verifier oSpec Statement pred

def firstOracleWitnessConsistencyProp (t : MultilinearPoly L ℓ)
    (f₀ : sDomain 𝔽q β h_ℓ_add_R_rate 0 → L) : Prop :=
  let P₀: L[X]_(2 ^ ℓ) := polynomialFromNovelCoeffsF₂ 𝔽q β ℓ (by admit /- proof elided -/
  ) (fun ω => t.val.eval ω)
  
  2 * hammingDist (fun x => P₀.val.eval x.val) f₀ < BBF_CodeDistance ℓ 𝓡 ⟨0, by admit /- proof elided -/
  ⟩

noncomputable def queryOracleReduction [DecidableEq F] :
  OracleReduction []ₒ
    (FinalStatement F k) (FinalOracleStatement D x s) (Witness F s d (Fin.last (k + 1)))
    (FinalStatement F k) (FinalOracleStatement D x s) (Witness F s d (Fin.last (k + 1)))
    (pSpec D x l) where
  prover := queryProver D x s d l
  verifier := queryVerifier D x s (round_bound domain_size_cond) l

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

def verifyEqOne (n a' : Q(ℕ)) (a : Q(ZMod $n)) (_ : Q(($a' : ZMod $n) = $a)) :
    MetaM Q($a ^ ($n - 1) = 1) := do
  let p : Q(ZMod $n) := q($a ^ ($n - 1))
  let .isNat _ c hc ← Tactic.ReduceModChar.normIntNumeral n p
    q(CommRing.toRing) q(ZMod.charP $n) | failure
  assumeInstancesCommute
  haveI : $p =Q $a ^ ($n - 1) := ⟨⟩
  haveI : $c =Q 1 := ⟨⟩
  return q(ZMod.bla $a (.refl _) $hc)

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

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

instance : NeZero (2^3) := ⟨by admit /- proof elided -/
⟩

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

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

def foldingBadEvent (i : Fin ℓ) (steps : ℕ) [NeZero steps] (h_i_add_steps : i + steps ≤ ℓ)
  (f_i : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by admit /- proof elided -/
  ⟩)
  (challenges : Fin steps → L) : Prop :=
  let d_i_plus_steps := BBF_CodeDistance ℓ 𝓡 ⟨i + steps, by admit /- proof elided -/
  ⟩
  if h_is_close : 2 * fiberwiseDistance 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i)
      steps h_i_add_steps f_i < (d_i_plus_steps : ℕ∞) then
    
    
    
    let h_dist_curr_lt := fiberwise_dist_lt_imp_dist_lt_unique_decoding_radius 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i) (steps := steps) h_i_add_steps f_i h_is_close

    let f_bar_i := uniqueClosestCodeword 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (i := ⟨i, by admit /- proof elided -/
      ⟩) (h_i := by admit /- proof elided -/
      ) f_i
      h_dist_curr_lt
    let folded_f_i := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (steps := ⟨steps, by admit /- proof elided -/
      ⟩) (i := ⟨i, by admit /- proof elided -/
      ⟩)
      (h_i_add_steps := by admit /- proof elided -/
      ) f_i challenges
    let folded_f_bar_i := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (steps := ⟨steps, by admit /- proof elided -/
      ⟩) (i := ⟨i, by admit /- proof elided -/
      ⟩)
      (h_i_add_steps := by admit /- proof elided -/
      ) f_bar_i challenges

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

def forwardRange (n : ℕ) (r : Fin (n)) (l : Fin (r.val + 1)) : List (Fin n) :=
  let len := r.val - l.val + 1
  List.ofFn (fun (k : Fin len) =>
    let val := l.val + k.val
    have h_bound : val < n := by admit /- proof elided -/
  )

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

List.cons in Init.Prelude

OfNat in Init.Prelude

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

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

def churchRecNat {β : Type} (n : ChurchNat ℕ) (step : β → β) (base : β) : β :=
  Nat.iterate step (ChurchNat.toNat n) base

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

def parametrisedCurve {l : ℕ} [Semiring F] (u : Fin l → ι → F) : Set (ι → F)
  := {v | ∃ r : F, v = ∑ i : Fin l, (r ^ (i : ℕ)) • u i}

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

def getMiddleBits (offset len n : ℕ) : ℕ :=
  getLowBits (numLowBits:=len) (n:=n >>> offset)

IO.FS.readFile in Init.System.IO

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)

def rbrKnowledgeSoundness (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  ∃ WitMid : Fin (n + 1) → Type,
  ∃ extractor : Extractor.RoundByRound oSpec StmtIn WitIn WitOut pSpec WitMid,
  ∃ kSF : verifier.KnowledgeStateFunction init impl relIn relOut extractor,
  ∀ stmtIn : StmtIn,
  ∀ witIn : WitIn,
  ∀ prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec,
  ∀ i : pSpec.ChallengeIdx,
    [fun ⟨transcript, challenge, _proveQueryLog⟩ =>
      ∃ witMid,
        ¬ kSF i.1.castSucc stmtIn transcript
          (extractor.extractMid i.1 stmtIn (transcript.concat challenge) witMid) ∧
          kSF i.1.succ stmtIn (transcript.concat challenge) witMid
    | 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

def mul (a b : AssocNat) : AssocNat :=
  mulNat a b.toNat

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

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

@[reducible]
def reduction : Reduction oSpec
    (StatementRound R n 0 × ∀ i, OracleStatement R n deg i) Unit
    (StatementRound R n (.last n) × ∀ i, OracleStatement R n deg i) Unit
    (pSpec R deg n) :=
  Reduction.seqCompose (oSpec := oSpec)
    (Stmt := fun i => StatementRound R n i × (∀ j, OracleStatement R n deg j))
    (Wit := fun _ => Unit)
    (pSpec := fun _ => SingleRound.pSpec R deg)
    (SingleRound.reduction R n deg D oSpec)

instance instDCast₃ : DCast₃ Nat (fun n => Fin (n + 1)) (fun n _ => ProtocolSpec n)
    (fun _ k pSpec => pSpec.Transcript k) where
  dcast₃ h h' h'' T := Transcript.cast h
    (by admit /- proof elided -/
    )
    (by admit /- proof elided -/
    )
    T
  dcast₃_id := cast_id

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

noncomputable def P
  (δ : ℚ) (x₀ : F)
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
  F[Z][X] :=
  let v₀ := Classical.choose (solution_gamma_is_linear_in_Z k (δ := δ) (x₀ := x₀) h_gs)
  let v₁ := Classical.choose 
    (Classical.choose_spec <| solution_gamma_is_linear_in_Z k (δ := δ) (x₀ := x₀) h_gs)
  (
    (Polynomial.map Polynomial.C v₀) +
    (Polynomial.C Polynomial.X) * (Polynomial.map Polynomial.C v₁)
  )

instance : Slice (ProtocolSpec n) ℕ ℕ
    (fun _ start stop => start ≤ stop ∧ stop ≤ n)
    (fun _ start stop _ => ProtocolSpec (stop - start))
    where
  slice := fun v start stop h => extract start stop h.1 h.2 v

instance : Serialize UInt8 ByteArray where
  serialize byte := ByteArray.mk #[byte]

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

noncomputable def finalSumcheckProver :
  OracleProver
    (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
  PrvState := fun
    | 0 => Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ) × (∀ j, OracleStatement 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ) j)
        × Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ)
    | _ => Statement (L := L) (SumcheckBaseContext L ℓ) (Fin.last ℓ) × (∀ j, OracleStatement 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ (Fin.last ℓ) j)
        × Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ) × L
  input := fun ⟨⟨stmt, oStmt⟩, wit⟩ => (stmt, oStmt, wit)

  sendMessage
  | ⟨0, _⟩ => fun ⟨stmtIn, oStmtIn, witIn⟩ => do
    let fℓ : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := ⟨ℓ, by admit /- proof elided -/
    ⟩)
      := witIn.f
    
    let c : L := fℓ ⟨0, by admit /- proof elided -/
    ⟩ 
    pure ⟨c, (stmtIn, oStmtIn, witIn, c)⟩

  receiveChallenge
  | ⟨0, h⟩ => nomatch h 

  output := fun ⟨stmtIn, oStmtIn, witIn, c⟩ => do
    let stmtOut : FinalSumcheckStatementOut (L := L) (ℓ := ℓ) := {
      ctx := stmtIn.ctx,
      
      sumcheck_target := stmtIn.sumcheck_target,
      challenges := stmtIn.challenges,
      final_constant := c
    }

    pure (⟨stmtOut, oStmtIn⟩, ())

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 numQueries (stmt : StmtIn) (challenges : ∀ i, pSpec.Challenge i)
    (verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec) :
  OracleComp (oSpec ++ₒ ([OStmtIn]ₒ ++ₒ [pSpec.Message]ₒ)) ℕ := sorry

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 finUInt16Equiv : Fin (2 ^ 16) ≃ UInt16 where
  toFun := fun i => UInt16.ofFin i
  invFun := fun u => u.toFin
  left_inv _ := rfl
  right_inv _ := rfl

FreeMonad in ToMathlib.Control.Monad.Free

@[inline, specialize]
def mulX (p : UniPoly R) : UniPoly R := p.mulPowX 1

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)

Function.RightInverse in Init.Data.Function

Polynomial.degreeLTEquiv in Mathlib.RingTheory.Polynomial.Basic

@[reducible, inline]
instance (priority := low) instTensorForall {ι : 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 q i => (O i).answer (f i) (q i)

@[reducible]
def StateRestoration.KnowledgeSoundness (oSpec : OracleSpec ι)
    (StmtIn : Type) {ιₛᵢ : Type} (OStmtIn : ιₛᵢ → Type) (WitOut : Type)
    {n : ℕ} {pSpec : ProtocolSpec n} :=
  Prover.StateRestoration.KnowledgeSoundness oSpec (StmtIn × (∀ i, OStmtIn i)) WitOut pSpec

OracleComp.uniformOfFintype in VCVio.OracleComp.Constructions.UniformSelect

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

tail in ToMathlib.Control.Comonad.Instances

def ratchetUnchecked [Permute C] (sponge : DuplexSponge U C) : DuplexSponge U C :=
  simulateQ' forwardPermutationOracleImpl (ratchet sponge) (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

Real in Mathlib.Data.Real.Basic

Cardinal in Mathlib.SetTheory.Cardinal.Defs

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

def liftLeftNil {ι : Type} {σ : Type} (oSpec : OracleSpec ι) :
    SimOracle.Stateful ([]ₒ ++ₒ oSpec) oSpec σ where impl
  | query (.inr i) q => fun s ↦ do return ⟨← query i q, s⟩

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

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

repr in Init.Data.Repr

MonomialOrder.lex in Mathlib.Data.Finsupp.MonomialOrder

def deterministicMillerRabin (n : ℕ) : Bool := Id.run do
  if n ≤ 2 ∨ n % 2 = 0 then
    return n = 2

  let ⟨s, d⟩ := factorOutTwos (n - 1)
  for a in millerRabinBases do
    if a % n == 0 then
      continue

    let mut x := powMod a d n
    if x = 1 ∨ x = n - 1 then
      continue

    for _ in [0:s] do
      x := (x * x) % n
      if x == n - 1 ∨ x ≤ 1 then
        break
    if x ≠ n - 1 then
      return false

  return true

RingHom.toAlgebra in Mathlib.Algebra.Algebra.Defs

def toOracleImpl {ι : Type u} (v : ι → Type v) [O : ∀ i, OracleInterface (v i)]
    (data : ∀ i, v i) : QueryImpl [v]ₒ Id where
  impl | query i t => (O i).answer (data i) t

instance {k : ℕ} : Mul (ConcreteBTField k) where
  mul := concrete_mul

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

FreeMonad.roll in ToMathlib.Control.Monad.Free

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

def twoAdicGenerators : List Field :=
  [
    (0x1 : Field),
    (0x7F000000 : Field),
    (0x7E010002 : Field),
    (0x6832FE4A : Field),
    (0x8DBD69C : Field),
    (0xA28F031 : Field),
    (0x5C4A5B99 : Field),
    (0x29B75A80 : Field),
    (0x17668B8A : Field),
    (0x27AD539B : Field),
    (0x334D48C7 : Field),
    (0x7744959C : Field),
    (0x768FC6FA : Field),
    (0x303964B2 : Field),
    (0x3E687D4D : Field),
    (0x45A60E61 : Field),
    (0x6E2F4D7A : Field),
    (0x163BD499 : Field),
    (0x6C4A8A45 : Field),
    (0x143EF899 : Field),
    (0x514DDCAD : Field),
    (0x484EF19B : Field),
    (0x205D63C3 : Field),
    (0x68E7DD49 : Field),
    (0x6AC49F88 : Field)
  ]

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

def backwardPermutationOracleImpl {α : Type*} [Permute α] [LawfulPermute α] :
    QueryImpl (backwardPermutationOracle α) Id where
  impl | query () q => LawfulPermute.permuteInv (α := α) q

@[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⟩, ())

commit in VCVio.CryptoFoundations.SigmaAlg

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

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

protected def OracleReduction.id :
    OracleReduction oSpec Statement OStatement Witness Statement OStatement Witness !p[] :=
  ⟨OracleProver.id, OracleVerifier.id⟩

alias Prover.trivial := Prover.id
alias Verifier.trivial := Verifier.id
alias Reduction.trivial := Reduction.id
alias OracleProver.trivial := OracleProver.id
alias OracleVerifier.trivial := OracleVerifier.id
alias OracleReduction.trivial := OracleReduction.id

@[reducible, simp]
def relOut : Set ((StmtOut OStatement × ∀ i, OStmtOut OStatement i) × WitOut) :=
  { ⟨⟨q, oStmt⟩, ()⟩ | answer (oStmt 0) q = answer (oStmt 1) q }

def halfNumFullRounds : Nat := params.numFullRounds / 2

HomogeneousPow in Init.Prelude

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 d (B : Finset (Fin n → F)) : ℚ :=
  (1 : ℚ)/(2 * choose_2 B.card) * ∑ x ∈ (Finset.product B B) with x.1 ≠ x.2, Δ₀(x.1, x.2)

DecidableRel in Init.Prelude

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

@[reducible]
def get {αs : List (Type u)} : HList αs → (n : Fin αs.length) → αs.get n
  | x ::ₕ _, ⟨0, _⟩ => x
  | _ ::ₕ xs, ⟨n+1, h⟩ => xs.get ⟨n, Nat.lt_of_succ_lt_succ h⟩

Fin.modNat in Batteries.Data.Fin.Basic

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

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 implGroupOpOracle : QueryImpl (GroupOpOracle ι) (StateT (GroupValTable ι G) Option) where
  impl | query _ ⟨i, j, k⟩ => fun table =>
    match table i, table j with
    | some g₁, some g₂ => some ((), table.update k (some (g₁ * g₂)))
    | _, _ => none

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

Decidable in Init.Prelude

Vector.finRange in Init.Data.Vector.FinRange

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

@[reducible, simp]
def knowledgeSoundness
    (relation : Set ((Statement × ∀ i, OStatement i) × Witness))
    (verifier : OracleVerifier oSpec Statement OStatement Bool (fun _ : Empty => Unit) pSpec)
    (knowledgeError : ℝ≥0) : Prop :=
  verifier.toVerifier.knowledgeSoundness init impl relation acceptRejectOracleRel knowledgeError

@[reducible, inline, specialize]
def getChallenge (pSpec : ProtocolSpec n) (i : pSpec.ChallengeIdx) :
    OracleComp ([pSpec.Challenge]ₒ'challengeOracleInterface) (pSpec.Challenge i) :=
  (query i () : OracleQuery ([pSpec.Challenge]ₒ'challengeOracleInterface) (pSpec.Challenge i))

VAdd in Mathlib.Algebra.Notation.Defs

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

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

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

def addUnits (state : FSProverState U H R) (input : Array U) :
    Except DomainSeparatorMismatch (FSProverState U H R) :=
  match state.hashState.absorb input with
  | .ok newHashState =>
    
    
    .ok { rng := state.rng, hashState := newHashState, nargString := state.nargString }
  | .error e => .error e

instance : HListRepr (HList []) where
  repr := fun _ => ""

Polynomial.sum in Mathlib.Algebra.Polynomial.Basic

@[reducible, simp] def WitIn := Unit

instance : Inhabited (UniPolyC R) := ⟨#[], Trim.canonical_empty⟩

Algebra.TensorProduct.instCommSemiring in Mathlib.RingTheory.TensorProduct.Basic

@[to_additive existing]
def partialProd {α : Type*} [Monoid α] (l : List α) : List α :=
  [1] ++ match l with
  | [] => []
  | a :: l' => (partialProd l').map (a * ·)

structure ConcreteBTFDivisionRingProps (k : ℕ) extends (ConcreteBTFRingProps k) where
  
  mul_inv_cancel : ∀ a : ConcreteBTField k, a ≠ zero → concrete_mul a (concrete_inv a) = one

instance : LawfulToNat Nat where
  toNat_zero := rfl
  toNat_succ := fun _ => rfl

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

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

Subtype.mk in Init.Prelude

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

def erase_odd (s : Finset ℕ) : Finset ℕ := s.filter Even

HAdd in Init.Prelude

noncomputable def toMLE (A : Matrix (Fin (2 ^ m)) (Fin (2 ^ n)) R) : R[X Fin n][X Fin m] :=
  MLE' (MLE' ∘ A)

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

Mathlib.Meta.NormNum.IsNat in Mathlib.Tactic.NormNum.Result

Algebra.TensorProduct.includeLeftRingHom in Mathlib.RingTheory.TensorProduct.Basic

instance : ∀ j, OracleInterface (FinalOracleStatement D x s j) :=
  fun j =>
    if h : j = k + 1
    then {
           Query := Unit
           Response := F[X]
           answer := cast (by admit /- proof elided -/
           )
                          (id (α := Unit → F[X]))
         }
    else {
           Query :=
            ↑(
              evalDomain D x
              (∑ j' ∈ finRangeTo j.1, s j')
            )
           Response := F
           answer := cast (by admit /- proof elided -/
           )
                          (id (α := ↑(evalDomain D x (∑ j' ∈ finRangeTo j.1, s j')) → F))
         }

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

Rat in Init.Data.Rat.Basic

def binary_tower_inductive_step
  (k : Nat)
  (prevBTField : Type _) [Field prevBTField]
  (prevBTResult : BinaryTowerResult prevBTField k)
: Σ' (F : Type _), BinaryTowerInductiveStepResult (k:=k) (prevBTField:=prevBTField)
  (prevBTResult:=prevBTResult) (prevPoly:=definingPoly (F:=prevBTField)
    (instField:=prevBTResult.instField) (s:=prevBTResult.specialElement)) (F:=F)
  (instPrevBTFieldIsField:=prevBTResult.instField) :=

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

Finset.map in Mathlib.Data.Finset.Image

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

QueryImpl in VCVio.OracleComp.SimSemantics.SimulateQ

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

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 ≤ δ] ≤ ε )

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

Nat.mod in Init.Prelude

def shift_left (s : Finset ℕ) : Finset ℕ :=
  s.filterMap
    (fun n => match n with
      | 0 => .none
      | n + 1 => .some n
      )
    (by admit /- proof elided -/
    )

instance : LawfulHasSucc Nat where
  succ'_eq_add_one := Nat.succ_eq_add_one

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

@[simp]
abbrev OracleStatement.AfterFirstMessage : R1CS.MatrixIdx ⊕ Fin 1 → Type :=
  Sum.rec (OracleStatement R pp) (fun _ => Witness R pp)

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

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

List.mergeSort in Init.Data.List.Sort.Basic

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 Rhs (e : ℕ) (ωs f : Fin n → F) (i : Fin n) : F :=
  let αᵢ := ωs i
  (-(f i) * αᵢ^e)

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

noncomputable def proximityError (F : Type*) [Fintype F] (d : ℕ) (ρ : ℝ) (δ : ℝ) (m : ℕ) : ℝ :=
  if δ ≤ (1 - ρ) / 2 then
    ((m - 1) * d) / (ρ * (Fintype.card F))
  else
    let min_val := min (1 - (Real.sqrt ρ) - δ ) ((Real.sqrt ρ) / 20)
    ((m - 1) * d^2) / ((Fintype.card F) * (2 * min_val)^7)

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

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

gen in VCVio.CryptoFoundations.FiatShamir

False.elim in Init.Prelude

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)

Set.Finite in Mathlib.Data.Finite.Defs

noncomputable def H_tilde (H : F[X][Y]) : Polynomial (RatFunc F) :=
  let hᵢ (i : ℕ) := H.coeff i
  let d := H.natDegree
  let W := (RingHom.comp Polynomial.C univPolyHom) (hᵢ d)
  let S : Polynomial (RatFunc F) := Polynomial.X / W
  let H' := Polynomial.eval₂ (RingHom.comp Polynomial.C univPolyHom) S H
  W ^ (d - 1) * H'

Array.reverse in Init.Data.Array.Basic

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

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

List.Vector.ofFn in Mathlib.Data.Vector.Defs

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

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

instance instDCast₂ : DCast₂ Nat ProtocolSpec
    (fun _ pSpec => Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) where
  dcast₂ := Prover.cast
  dcast₂_id := Prover.cast_id

def equivMonomialLagrangeRepr : MlPoly R n ≃ MlPolyEval R n where
  toFun := monoToLagrange n
  invFun := lagrangeToMono n
  left_inv v := by admit /- proof elided -/

@[reducible, simp] def WitIn := Unit

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

Polynomial.evalEvalRingHom in Mathlib.Algebra.Polynomial.Bivariate

ZMod.charP in Mathlib.Data.ZMod.Basic

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

@[simp]
def BTField (k : ℕ) := (BinaryTowerAux k).1

instDecidableEqOfLawfulBEq in Init.Core

Int.ofNat in Init.Data.Int.Basic

def toEvalsZeroOne (p : MvPolynomial σ R) : (σ → Fin 2) → R :=
  fun x => eval (x : σ → R) p

instance Z_NeZero {k : ℕ} : NeZero (Z k) := { out := Z_ne_zero (k:=k) }

List.findIdx in Init.Data.List.Basic

def twoLevelData {α} (k0 k1 : ℕ)
    (root : α)
    (lvl1 : Fin k0 → α)
    (lvl2 : (i : Fin k0) → Fin k1 → α) :
    ArityTree.Data α (twoLevelSkel k0 k1) :=

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

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}

Polynomial.evalEval in Mathlib.Algebra.Polynomial.Bivariate

def dfoldrM' {m : Type u → Type v} [Monad m]
    (n : ℕ) (α : Fin (n + 1) → Type u)
    (f : (i : Fin n) → α i.succ → m (α i.castSucc)) (init : α (last n)) : m (α 0) :=
  match n with
  | 0 => pure init
  | n + 1 => do
    let x ← dfoldrM' n (α ∘ succ) (fun i => f i.succ) init
    f 0 x

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

noncomputable def coeffs_of_close_proximity (ωs : Fin n ↪ F) (δ : ℚ) (u₀ u₁ : Fin n → F)
  : Finset F := Set.toFinset { z | ∃ v : ReedSolomon.code ωs (k + 1), δᵣ(u₀ + z • u₁, v) ≤ δ}

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

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

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

noncomputable def oddPart (f : Polynomial F) : Polynomial F :=
    C (2⁻¹ : F) * (f - f.comp (-X)) /ₘ X

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

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

noncomputable instance {H : F[X][Y]} [inst : Fact (Irreducible H)] : Field (𝕃 H) :=
  IsField.toField (isField_of_irreducible inst.out)

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

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

@[reducible, inline, specialize]
def PlainMessage (i : pSpec.PlainMessageIdx) := pSpec.Message i.1

inductive MatrixIdx where | A | B | C deriving Inhabited, DecidableEq

@[reducible]
def matchSize (a b : Array α) (unit : α) : Array α × Array α :=
  (a.rightpad (b.size) unit, b.rightpad (a.size) unit)

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

affineSpan in Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Defs

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 {U : Type} [SpongeUnit U] [SpongeSize] :
    SpongeState U (Vector U SpongeSize.N) where
  
  new := fun _ => 0
  get := id
  update := fun _ v => v

def divByMonic [Field R] (p : UniPoly R) (q : UniPoly R) :
    UniPoly R :=
  (divModByMonicAux p q).1

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

instance instVector : OracleInterface (Vector α n) where
  Query := Fin n
  Response := α
  answer := fun vec i => vec[i]

instance [LawfulBEq R] : AddCommGroup (UniPolyC R) where
  add_assoc := add_assoc
  zero_add := zero_add
  add_zero := add_zero
  add_comm := add_comm
  neg_add_cancel := neg_add_cancel
  nsmul := nsmul 
  nsmul_zero := nsmul_zero
  nsmul_succ := nsmul_succ
  zsmul := zsmulRec 

class RoundByRoundOneShot.IsMonotone (E : RoundByRoundOneShot oSpec StmtIn WitIn pSpec)
    (relIn : Set (StmtIn × WitIn)) where
  is_monotone : ∀ roundIdx stmtIn transcript,
    ∀ proveQueryLog₁ proveQueryLog₂ : oSpec.QueryLog,
    
    proveQueryLog₁.Sublist proveQueryLog₂ →
    
    
    (stmtIn, E roundIdx stmtIn transcript proveQueryLog₁) ∈ relIn →
      (stmtIn, E roundIdx stmtIn transcript proveQueryLog₂) ∈ relIn

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

abbrev FunEquiv F α β := DFunEquiv F α fun _ => β

Array.zipWith in Init.Data.Array.Basic

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

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

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

def possibleDists (C : Set (ι → F)) (δf : (ι → F) → (ι → F) → α) : Set α :=
  {d : α | ∃ p ∈ Set.offDiag C, δf p.1 p.2 = d}

def MLEEquivFin {n : ℕ} : R⦃≤ 1⦄[X (Fin n)] ≃ (Fin (2 ^ n) → R) :=
  Equiv.trans MLEEquiv (Equiv.piCongr finFunctionFinEquiv (fun _ => Equiv.refl _))

@[reducible, inline]
def OracleProver {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn : Type) {ιₛᵢ : Type} (OStmtIn : ιₛᵢ → Type) (WitIn : Type)
    (StmtOut : Type) {ιₛₒ : Type} (OStmtOut : ιₛₒ → Type) (WitOut : Type)
    {n : ℕ} (pSpec : ProtocolSpec n) :=
  Prover oSpec (StmtIn × (∀ i, OStmtIn i)) WitIn (StmtOut × (∀ i, OStmtOut i)) WitOut pSpec

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

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

instance : ∀ j, OracleInterface ((pSpecFoldRelay (L:=L)).Message j) :=
  instOracleInterfaceMessageAppend

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

def α' (x₀ : F) (R : F[X][X][Y]) (H_irreducible : Irreducible H) (t : ℕ) : 𝕃 H :=
  α x₀ R _ (φ := ⟨H_irreducible⟩) t

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

Algebra.TensorProduct.includeRight in Mathlib.RingTheory.TensorProduct.Basic

Setoid in Init.Core

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

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

Ideal in Mathlib.RingTheory.Ideal.Defs

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

@[app_unexpander Fin.hcons]
def hconsUnexpander : Lean.PrettyPrinter.Unexpander
  | `($_ $term !h[$term2, $terms,*]) => `(!h[$term, $term2, $terms,*])
  | `($_ $term !h[$term2]) => `(!h[$term, $term2])
  | `($_ $term !h[]) => `(!h[$term])
  | _ => throw ()

def ofNat : ℕ → ChurchNat α
  | 0 => zero
  | Nat.succ n => succ (ofNat n)

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

Finset.range in Mathlib.Data.Finset.Range

finSuccEquiv in Mathlib.Logic.Equiv.Fin.Basic

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

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

def leadingCoeff (p : UniPoly R) : R := p.trim.getLastD 0

def powFiberT (i : ℕ) {k : ℕ} {S : Finset ι} {φ : ι ↪ F} (S' : Finset (indexPowT S φ i))
  (φ' : (indexPowT S φ i) ↪ F) (y : indexPowT S φ k) :=
  { x : (indexPowT S φ i) // x ∈ S' ∧ (φ' x) ^ (2^(k-i)) = y.val }

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

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

def hammingBall (C : Code ι F) (y : ι → F) (r : ℕ) : Set (ι → F) :=
  { c | c ∈ C ∧ hammingDist 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 ι α)

instance extractorLens_rbr_knowledge_soundness :
    Extractor.Lens.IsKnowledgeSound
      (relationRound R n deg D i.castSucc) (Simple.inputRelation R deg D)
      (relationRound R n deg D i.succ) (Simple.outputRelation R deg)
      ((Simple.oracleVerifier R deg D oSpec).toVerifier.compatStatement (oStmtLens R n deg D i))
      (fun _ _ => True)
      ⟨oStmtLens R n deg D i, Witness.InvLens.trivial⟩ where
  proj_knowledgeSound := by admit /- proof elided -/

PFunctor.Lens.id in ToMathlib.PFunctor.Lens.Basic

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

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

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

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 

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

noncomputable def foldVerifier :
  OracleVerifier []ₒ
    (Statement F i.castSucc) (OracleStatement D x s i.castSucc)
    (Statement F i.succ) (OracleStatement D x s i.succ)
    (pSpec D x s i) where
  verify := fun prevChallenges roundChallenge =>
    pure (Fin.vappend prevChallenges (fun _ => roundChallenge ⟨0, by admit /- proof elided -/
    ⟩))
  embed :=
    ⟨
      fun j =>
        if h : j.val = (i.val + 1)
        then Sum.inr ⟨1, by admit /- proof elided -/
        ⟩
        else Sum.inl ⟨j.val, by admit /- proof elided -/
        ⟩,
      by admit /- proof elided -/
    ⟩
  hEq := by admit /- proof elided -/

Id in Init.Control.Id

Vector.drop in Init.Data.Vector.Basic

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 relationAfterCheckClaim :
    Set (((StmtAfterCheckClaim R) × (∀ i, OStmtAfterCheckClaim R deg i)) × Unit) :=
  { ⟨⟨_, oStmt⟩, _⟩ | oStmt (Sum.inr ()) = oStmt (Sum.inl ()) }

Sum.elim in Init.Data.Sum.Basic

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

def relayKnowledgeError (m : pSpecRelay.ChallengeIdx) : ℝ≥0 :=
  match m with
  | ⟨j, _⟩ => j.elim0

MvPolynomial.sumToIter in Mathlib.Algebra.MvPolynomial.Equiv

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

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)

abbrev eqPolynomial (r : σ → R) : R[X σ] :=
  ∏ i : σ, singleEqPolynomial (r i) (X i)

instance : ∀ i, OracleInterface ((pSpecQuery 𝔽q β γ_repetitions
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Message i) := fun _ => OracleInterface.instDefault

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

def splitSum {m : ℕ} {n : Fin m → ℕ} (k : Fin (vsum n)) : (i : Fin m) × Fin (n i) := match m with
  | 0 => Fin.elim0 k
  | _ + 1 => Fin.dappend
    (fun k => ⟨0, k⟩)
    (fun k => ⟨(splitSum k).1.succ, (splitSum k).2⟩)
    k

LinearMap.ker in Mathlib.Algebra.Module.Submodule.Ker

def X : UniPoly R := #[0, 1]

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

CommRing.toRing in Mathlib.Algebra.Ring.Defs

noncomputable def eval_on_Z₀ (p : (RatFunc F)) (z : F) : F :=
  RatFunc.eval (RingHom.id _) z p


notation3:max R "[Z][X]" => Polynomial (Polynomial R)

notation3:max R "[Z][X][Y]" => Polynomial (Polynomial (Polynomial (R)))

notation3:max "Y" => Polynomial.X
notation3:max "X" => Polynomial.C Polynomial.X
notation3:max "Z" => Polynomial.C (Polynomial.C Polynomial.X)

abbrev ScalarField := ZMod scalarFieldSize

Nat.Coprime in Init.Data.Nat.Coprime

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

Option.getD in Init.Prelude

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

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

abbrev extract (start stop : ℕ) (h1 : start ≤ stop) (h2 : stop ≤ n)
    (transcript : FullTranscript pSpec) : FullTranscript (pSpec.extract start stop h1 h2) :=
  Fin.extract start stop h1 h2 transcript

@[reducible, inline]
def 𝕫 {R} {sz} (stmt : Statement R sz) (wit : Witness R sz) : Fin sz.n → R :=
  Fin.append stmt wit ∘ Fin.cast (by admit /- proof elided -/
  )

def canonicalEmbedding (k : ℕ) : BTField k →+* BTField (k+1) :=
  AdjoinRoot.of (poly k)

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

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

Fin.consInduction in Mathlib.Data.Fin.Tuple.Basic

OracleComp.SelectableType.probFailure_selectElem in VCVio.OracleComp.Constructions.UniformSelect

def squeeze (state : HashStateWithInstructions U H) (outputSize : Nat) :
    Except DomainSeparatorMismatch (HashStateWithInstructions U H × Array U) := do
  
  sorry

def binaryTowerModule {l r : ℕ} (h_le : l ≤ r) :
    Module (ConcreteBTField l) (ConcreteBTField r) :=
  (ConcreteBTFieldAlgebra (h_le:=h_le)).toModule

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

noncomputable def Basis.baseChangeRight (b : Basis ι K Left) : Basis ι Right (Left ⊗[K] Right) :=

def ChurchBool (α : Type) : Type := α → α → α

instance : ∀ j, OracleInterface ((pSpec D x l).Challenge j) := fun j =>
  by admit /- proof elided -/

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

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

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

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

Fin.succAboveCases in Mathlib.Data.Fin.Tuple.Basic

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

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)

right_inv in ToMathlib.Control.Monad.Equiv

Quotient.lift₂ in Init.Core

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

def pSpecLastBlock := pSpecFoldRelaySequence (L:=L) (n:=ϑ)

SMulZeroClass in Mathlib.Algebra.GroupWithZero.Action.Defs

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

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

def concrete_pow_nat {k : ℕ} (x : ConcreteBTField k) (n : ℕ) : ConcreteBTField k :=
  if n = 0 then one
  else if n % 2 = 0 then concrete_pow_nat (concrete_mul x x) (n / 2)
  else concrete_mul x (concrete_pow_nat (concrete_mul x x) (n / 2))

AdjoinRoot.powerBasis' in Mathlib.RingTheory.AdjoinRoot

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

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

class IsSingleRound (pSpec : ProtocolSpec 2) extends ProverFirst pSpec, VerifierLast pSpec

alias ProverThenVerifier := IsSingleRound

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

List.take in Init.Data.List.Basic

Function.comp in Init.Prelude

MvPolynomial.totalDegree in Mathlib.Algebra.MvPolynomial.Degrees

instance : LT AssocNat where
  lt a b := a 0 < b 0

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

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

Polynomial.aeval in Mathlib.Algebra.Polynomial.AlgebraMap

@[reducible]
def pSpecFold : ProtocolSpec 2 := ⟨![Direction.P_to_V, Direction.V_to_P], ![L⦃≤ 2⦄[X], L]⟩

outParam in Init.Prelude

instance instDCastPSigmaPSigma :
    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 -/

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

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

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

structure LookaheadSequenceFamily
    (trace : QueryLog (forwardPermutationOracle (CanonicalSpongeState U)))
    (state : CanonicalSpongeState U) (i : pSpec.ChallengeIdx) where
   
  seqFamily : Finset (LookaheadSequence trace state)
   
  maximality : ∀ s ∈ seqFamily, ∀ s' ∈ seqFamily,
    ¬ (s.inputState ⊆ s'.inputState) ∨ ¬ (s'.outputState ⊆ s.outputState)
   
  length_le_challengeSize : ∀ s ∈ seqFamily, s.inputState.length ≤ challengeSize i

def eqTilde {L : Type} [CommRing L] {ℓ : ℕ} (r r' : Fin ℓ → L) : L :=
  MvPolynomial.eval r' (MvPolynomial.eqPolynomial r)

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

LT in Init.Prelude

def generateProof {n : ℕ} (i : Fin (2 ^ n)) (cache : Cache α n) :
    List.Vector α n :=
  match n with
  | 0 => List.Vector.nil
  | n + 1 => List.Vector.snoc (generateProof ⟨i.val / 2, by admit /- proof elided -/
  ⟩ (cache.upper))
                              ((cache.leaves).get (findNeighbors i (Fin.last _)))

def rightpadPowerOfTwo (unit : α) (a : Array α) : Array α :=
  a.rightpad (2 ^ (Nat.clog 2 a.size)) unit

instance : IsEmpty (AssocFin AssocNat.zero) :=

class ProverOnly (pSpec : ProtocolSpec 1) extends ProverFirst pSpec

 
alias NonInteractive := ProverOnly

CommSemiring in Mathlib.Algebra.Ring.Defs

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

Mul in Init.Prelude

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

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

Polynomial.erase in Mathlib.Algebra.Polynomial.Basic

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

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

private def sum_choose_K_i (B : Finset (Fin n → F)) (i : Fin n) : ℚ :=
  ∑ (α : F), choose_2 (K B i α)

liftM in Init.Prelude

instance [Zero T] [ToNat T] : ToNat (Cayley T) where
  toNat := ToNat.toNat ∘ toT

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

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

def colSpan : Submodule F (ι → F) :=
  Submodule.span F {Matrix.transpose U i | i : ι'}

def foldKnowledgeError (i : Fin ℓ) (_ : (pSpecFold (L := L)).ChallengeIdx) : ℝ≥0 :=
  let err_SC := (1 : ℝ≥0) / (Fintype.card L)
  
  let err_BE := if hi : ϑ ∣ (i.val + 1) then
    
    ϑ * (Fintype.card ((sDomain 𝔽q β h_ℓ_add_R_rate)
      ⟨i.val + 1, by admit /- proof elided -/
        ⟩) : ℝ≥0) / (Fintype.card L)
  else 0
  err_SC + err_BE

local instance {α : Type*} : Zero (Option α) where
  zero := none

noncomputable def toRatFuncPoly (p : F[Z][X][Y]) : (RatFunc F)[X][Y] :=
  p.map (Polynomial.mapRingHom (algebraMap F[X] (RatFunc F)))

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)

OracleComp.construct' in VCVio.OracleComp.OracleComp

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

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

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

@[inline] def monoToLagrange (n : ℕ) : MlPoly R n → MlPolyEval R n :=
  (List.finRange n).foldl (fun acc level => monoToLagrangeLevel level acc)

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

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

Fin.castLT in Init.Data.Fin.Basic

@[inline] def pred [Zero T] [ToNat T] (a : Cayley T) : Cayley T :=
  match (↑a : Nat) with
  | 0 => zero
  | Nat.succ n => ofNat n

def hli_level_diff_0 (l : ℕ) :
  letI instAlgebra:= ConcreteBTFieldAlgebra (l:=l) (r:=l) (h_le:=by omega)
  @Basis (Fin 1) (ConcreteBTField l) (ConcreteBTField l) _ _ instAlgebra.toModule :=

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

@[reducible]
def coreInteractionOracleReduction :=
  OracleReduction.append (oSpec:=[]ₒ)
    (Stmt₁ := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) 0)
    (Stmt₂ := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) (Fin.last ℓ))
    (Stmt₃ := FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (Wit₁ := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) 0)
    (Wit₂ := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) (Fin.last ℓ))
    (Wit₃ := Unit)
    (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))
    (R₁ := sumcheckFoldOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑))
    (R₂ := finalSumcheckOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))

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

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

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)

zsmulRec in Mathlib.Algebra.Group.Defs

@[inline]
def ofInputOnly (projStmt : OuterStmtIn → InnerStmtIn) :
    Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn OuterStmtOut :=
  ⟨projStmt, fun _ => id⟩

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 FullData.map {α β : Type} (f : α → β) {s : Skeleton}
    (tree : FullData α s) : FullData β s :=
  match tree with
  | FullData.leaf value => FullData.leaf (f value)
  | FullData.internal value left right =>
    FullData.internal (f value) (left.map f) (right.map f)

def append' (so₁ : SimOracle.Stateful spec₁ specₜ₁ σ) (so₂ : SimOracle.Stateful spec₂ specₜ₂ τ) :
    SimOracle.Stateful (spec₁ ++ₒ spec₂) (specₜ₁ ++ₒ specₜ₂) (σ × τ) where
  impl
  | query (.inl i) t => fun (s₁, s₂) ↦ do
      let (u, s₁') ← so₁.impl (query i t) s₁; return (u, s₁', s₂)
  | query (.inr i) t => fun (s₁, s₂) ↦ do
      let (u, s₂') ← so₂.impl (query i t) s₂; return (u, s₁, s₂')

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 vflatten {m : ℕ} {n : Fin m → ℕ} (v : (i : Fin m) → Fin (n i) → α) :
    Fin (vsum n) → α :=
  dflatten v

@[reducible, simp] def StmtOut := Query OStatement × Response OStatement

AffineSubspace in Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Defs

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

noncomputable def getFoldProverFinalOutput (i : Fin ℓ)
    (finalPrvState : foldPrvState 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      i 2 (Context := Context)) :
  ((Statement (L := L) Context i.succ × ((j : Fin (toOutCodewordsCount ℓ ϑ i.castSucc)) →
    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) :=

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

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

Finset.filterMap in Mathlib.Data.Finset.Image

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

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

def getMidCodewords {i : Fin (ℓ + 1)} (t : L⦃≤ 1⦄[X Fin ℓ]) 
    (challenges : Fin i → L) : (sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by admit /- proof elided -/
    ⟩) → L) :=
  let P₀ : L⦃< 2^ℓ⦄[X] := polynomialFromNovelCoeffsF₂ 𝔽q β ℓ (by admit /- proof elided -/
  ) (fun ω => t.val.eval ω)
  let f₀ : (sDomain 𝔽q β h_ℓ_add_R_rate 0) → L := fun x => P₀.val.eval x.val
  let fᵢ := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    (i := 0)
    (steps := i)
    (h_i_add_steps := by admit /- proof elided -/
      )
    (f := f₀)
    (r_challenges := challenges)
  fun x => fᵢ ⟨x, by admit /- proof elided -/
  ⟩

GaloisField in Mathlib.FieldTheory.Finite.GaloisField

abbrev Field := ZMod fieldSize

def zero {k : ℕ} : ConcreteBTField k := BitVec.zero (2 ^ k)

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

instance [IsSingleRound pSpec] [h : VCVCompatible (pSpec.Challenge default)] :
    (i : pSpec.ChallengeIdx) → VCVCompatible (pSpec.Challenge i) := fun i => by admit /- proof elided -/

RingHomCompTriple in Mathlib.Algebra.Ring.CompTypeclasses

def toStatement (stmt : FinalSumcheckStatementOut (L := L) (ℓ := ℓ)) :
  Statement (L := L) (Context := SumcheckBaseContext L ℓ) (Fin.last ℓ)  :=
  {
    sumcheck_target := stmt.sumcheck_target,
    challenges := stmt.challenges,
    ctx := stmt.ctx
  }

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

Polynomial in Mathlib.Algebra.Polynomial.Basic

def finIdxOf [BEq α] [LawfulBEq α] (a : α) (l : List α) : Fin (l.length + 1) :=
  ⟨List.idxOf' a l, Nat.lt_succ_of_le (by admit /- proof elided -/
  )⟩

@[inline]
def permute (params : Params) (state : Vector KoalaBear.Field params.width) :
    Vector KoalaBear.Field params.width :=
  letI rcs := params.roundConstants

  
  let st0 := externalLinearLayer params state

  
  let st1 : Vector KoalaBear.Field params.width :=
    Fin.foldl params.halfNumFullRounds (fun st_acc rc_idx =>
      let rc_chunk := (rcs.extract rc_idx (rc_idx + params.width)).cast (by admit /- proof elided -/
      )
      let st_new := fullRound params st_acc rc_chunk
      st_new) st0

  
  let rcs := rcs.drop (params.halfNumFullRounds * params.width)

  
  let st2 := Fin.foldl params.numPartialRounds (fun st_acc rc_idx =>
    let rc_val := rcs[rc_idx]'(sorry)
    let st_new := partialRound params st_acc rc_val
    st_new) st1

  
  let rcs := rcs.drop params.numPartialRounds

  
  let st3 := Fin.foldl params.halfNumFullRounds (fun st_acc rc_idx =>
    let rc_chunk := (rcs.extract rc_idx (rc_idx + params.width)).cast (by admit /- proof elided -/
    )
    let st_new := fullRound params st_acc rc_chunk
    st_new) st2

  st3

def Array.toFinVec {α : Type _} (n : ℕ) (arr : Array α) (h : arr.size = n) : Fin n → α :=
  fun i => arr[i]

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 

def queryKStateProp {m : Fin (1 + 1)}
  (tr : ProtocolSpec.Transcript m
    (pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)))
  (stmt : FinalSumcheckStatementOut (L := L) (ℓ := ℓ))
  (witMid : Unit)
  (oStmt : ∀ j, OracleStatement 𝔽q β (ϑ := ϑ)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ) j) : Prop :=
if h0 : m.val = 0 then
  
  Binius.BinaryBasefold.finalSumcheckRelOutProp 𝔽q β (input:=⟨⟨stmt, oStmt⟩, witMid⟩)
else
    let r := stmt.ctx.t_eval_point
    let s := stmt.ctx.original_claim
    let challenges : Fin ℓ → L := stmt.challenges
    let tr_so_far := (pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).take m m.is_le
    let chalIdx : tr_so_far.ChallengeIdx := ⟨⟨0,
      Nat.lt_of_succ_le (by admit /- proof elided -/
      )⟩, by admit /- proof elided -/
      ⟩
    let γ_challenges : Fin γ_repetitions → sDomain 𝔽q
      β h_ℓ_add_R_rate ⟨0, by admit /- proof elided -/
      ⟩ := ((ProtocolSpec.Transcript.equivMessagesChallenges (k:=m)
        (pSpec:=pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
        tr).2 chalIdx)
    let fold_challenges := stmt.challenges
    
    let proximityTestsCheck : Prop :=
      proximityChecksSpec 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (ϑ:=ϑ) γ_repetitions γ_challenges oStmt fold_challenges stmt.final_constant
    proximityTestsCheck

def PlainMessages (pSpec : ProtocolSpec n) [OracleInterfaces pSpec] : Type :=
  ∀ i, pSpec.PlainMessage i

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 isBoolean {R : Type _} [Zero R] [One R] (a : Array R) : Prop :=
    ∀ i : Fin a.size, (a[i] = 0) ∨ (a[i] = 1)

@[reducible]
def foldCommitOracleVerifier (i : Fin ℓ) (hCR : 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 := pSpecFoldCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) :=
    OracleVerifier.append (oSpec:=[]ₒ)
      (pSpec₁ := pSpecFold (L:=L))
      (pSpec₂ := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
      (V₁ := foldOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
      (V₂ := commitOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hCR)

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

def divide_by_2 (s : Finset ℕ) : Finset ℕ :=
  (erase_odd s).image (fun n => n / 2)

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

def BBF_SumcheckMultiplierParam : SumcheckMultiplierParam L ℓ (SumcheckBaseContext L ℓ) :=
  { multpoly := fun ctx => BBF_eq_multiplier ctx.t_eval_point }

def neg_descending (p : UniPoly R) : QuotientUniPoly R :=
  Quotient.mk _ (neg p)

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

def sumCases {l : List ℕ} {motive : Fin l.sum → Sort*}
    (cases : ∀ (n : ℕ) (h : n ∈ l) (i : Fin n), motive (castSum l h i))
    (i : Fin l.sum) : motive i := match l with
  | [] => by admit /- proof elided -/
  | n' :: l' => by admit /- proof elided -/

instance polyIrreducibleFact (n : ℕ) : Fact (Irreducible (poly n)) := ⟨polyIrreducible n⟩

def concat' {k : Fin n}
    (messages : (i : Fin k) → (pSpec.dir (i.castLE (by admit /- proof elided -/
    )) = .P_to_V
      → pSpec.«Type» (i.castLE (by admit /- proof elided -/
      ))))
    (msg : (h : pSpec.dir k = .P_to_V) → pSpec.Message ⟨k, h⟩) :
    (i : Fin (k + 1)) → (pSpec.dir (i.castLE (by admit /- proof elided -/
    )) = .P_to_V) →
      pSpec.«Type» (i.castLE (by admit /- proof elided -/
      )) :=
  Fin.dconcat messages msg

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

def simulateQ' (oa : OracleComp spec α) (h : oa.neverFails) : m α :=

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

def commit (srs : Vector G₁ n) (coeffs : Fin n → ZMod p) : G₁ :=
  ∏ i : Fin n, srs[i] ^ (coeffs i).val

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

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

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

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)

structure StateFunction
    (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 : ∀ stmt, stmt ∈ langIn ↔ toFun 0 stmt default
   
  toFun_next : ∀ m, pSpec.dir m = .P_to_V →
    ∀ stmt tr, ¬ toFun m.castSucc stmt tr →
    ∀ msg, ¬ 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

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 vcons {n : ℕ} (a : α) (v : Fin n → α) : Fin (n + 1) → α :=
  dcons a v

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

alias trivial := Statement.Lens.id

def map (f : R →+* S) (p : MlPolyEval R n) : MlPolyEval S n :=
  Vector.map (fun a => f a) p

@[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⟩, ())

structure Params where
  
  width : Nat
  numFullRounds : Nat
  numPartialRounds : Nat
  internalDiagVectors : Vector KoalaBear.Field width
  roundConstants : Vector KoalaBear.Field (numFullRounds * width + numPartialRounds)

  

   
  [width_ne_zero : NeZero width]

   
  [numFullRounds_ne_zero : NeZero numFullRounds]

   
  [numPartialRounds_ne_zero : NeZero numPartialRounds]

   
  width_dvd_by_4 : 4 ∣ width
   
  numFullRounds_even : Even numFullRounds

instance {k : ℕ} : NeZero (1 : ConcreteBTField k) :=

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

def AlgebraTowerEquiv.toAlgebraOverRight (e : AlgebraTowerEquiv A B) (i j : ι)
    (h : i ≤ j) : Algebra (B i) (A j) :=

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

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

BitVec.ofNat in Init.Prelude

@[reducible]
def pSpec (F : Type) [Semiring F] : ProtocolSpec 2 := ⟨!v[.V_to_P, .P_to_V], !v[F, Unit → F[X]]⟩

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

AdjoinRoot.instField in Mathlib.RingTheory.AdjoinRoot

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

def rawConstants16 : Vector KoalaBear.Field 148 := #v[
    2128964168,
    288780357,
    316938561,
    2126233899,
    426817493,
    1714118888,
    1045008582,
    1738510837,
    889721787,
    8866516,
    681576474,
    419059826,
    1596305521,
    1583176088,
    1584387047,
    1529751136,
    1863858111,
    1072044075,
    517831365,
    1464274176,
    1138001621,
    428001039,
    245709561,
    1641420379,
    1365482496,
    770454828,
    693167409,
    757905735,
    136670447,
    436275702,
    525466355,
    1559174242,
    1030087950,
    869864998,
    322787870,
    267688717,
    948964561,
    740478015,
    679816114,
    113662466,
    2066544572,
    1744924186,
    367094720,
    1380455578,
    1842483872,
    416711434,
    1342291586,
    1692058446,
    1493348999,
    1113949088,
    210900530,
    1071655077,
    610242121,
    1136339326,
    2020858841,
    1019840479,
    678147278,
    1678413261,
    1361743414,
    61132629,
    1209546658,
    64412292,
    1936878279,
    1980661727,
    1423960925,
    2101391318,
    1915532054,
    275400051,
    1168624859,
    1141248885,
    356546469,
    1165250474,
    1320543726,
    932505663,
    1204226364,
    1452576828,
    1774936729,
    926808140,
    1184948056,
    1186493834,
    843181003,
    185193011,
    452207447,
    510054082,
    1139268644,
    630873441,
    669538875,
    462500858,
    876500520,
    1214043330,
    383937013,
    375087302,
    636912601,
    307200505,
    390279673,
    1999916485,
    1518476730,
    1606686591,
    1410677749,
    1581191572,
    1004269969,
    143426723,
    1747283099,
    1016118214,
    1749423722,
    66331533,
    1177761275,
    1581069649,
    1851371119,
    852520128,
    1499632627,
    1820847538,
    150757557,
    884787840,
    619710451,
    1651711087,
    505263814,
    212076987,
    1482432120,
    1458130652,
    382871348,
    417404007,
    2066495280,
    1996518884,
    902934924,
    582892981,
    1337064375,
    1199354861,
    2102596038,
    1533193853,
    1436311464,
    2012303432,
    839997195,
    1225781098,
    2011967775,
    575084315,
    1309329169,
    786393545,
    995788880,
    1702925345,
    1444525226,
    908073383,
    1811535085,
    1531002367,
    1635653662,
    1585100155,
    867006515,
    879151050,
]

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

def add_descending (p q : UniPoly R) : QuotientUniPoly R :=
  Quotient.mk _ (add p q)

id in Init.Prelude

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

instance : ∀ i, VCVCompatible ((pSpec Witness).Challenge i) | ⟨0, h⟩ => nomatch h

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

Fin.cons in Mathlib.Data.Fin.Tuple.Basic

finProdFinEquiv in Mathlib.Logic.Equiv.Fin.Basic

instance : Fintype (pSpec.MessageIdx) := Subtype.fintype (fun i => pSpec.dir i = .P_to_V)

@[reducible, simp] def WitOut := Unit

inline in Init.Core

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

OracleComp.inductionOn in VCVio.OracleComp.OracleComp

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)

CommMonoidWithZero in Mathlib.Algebra.GroupWithZero.Defs

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

instance {α : Type u} : Slice (List α) Nat Nat (fun _ _ _ => True) (fun _ _ _ _ => List α) where
  slice xs start stop _ := xs.extract start stop

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

CommRing in Mathlib.Algebra.Ring.Defs

def getConst (F : Type) [NonBinaryField F] : OracleComp [(pSpec F).Message]ₒ F[X] :=
  OracleComp.lift
    (by admit /- proof elided -/
    )

instance : Unique (ChallengesUpTo 0 pSpec) where
  default := fun ⟨i, _⟩ => Fin.elim0 i
  uniq := fun T => by admit /- proof elided -/

@[simp]
instance BTFieldIsField (k : ℕ) : Field (BTField k) := (BinaryTowerAux k).2.instField

One in Init.Prelude

def oracleWitnessConsistency
    (stmtIdx : Fin (ℓ + 1)) (oracleIdx : Fin (ℓ + 1))
    (h_le : oracleIdx.val ≤ stmtIdx.val) (stmt : Statement (L := L) (Context := Context) stmtIdx)
    (wit : Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) stmtIdx)
    (oStmt : ∀ j, (OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      ϑ (i := oracleIdx) j)) : Prop :=
  let witnessStructuralInvariant: Prop := witnessStructuralInvariant (mp := mp) (i:=stmtIdx) 𝔽q β
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) stmt wit
  let sumCheckConsistency: Prop := sumcheckConsistencyProp (𝓑 := 𝓑) stmt.sumcheck_target wit.H
  let firstOracleConsistency: Prop := firstOracleWitnessConsistencyProp 𝔽q β
    wit.t (getFirstOracle 𝔽q β oStmt)
  let oracleFoldingConsistency: Prop := oracleFoldingConsistencyProp 𝔽q β oracleIdx
    (challenges := Fin.take (m := oracleIdx) (v := stmt.challenges) (h := by admit /- proof elided -/
    ))
    (oStmt := oStmt)
  witnessStructuralInvariant ∧ sumCheckConsistency ∧ firstOracleConsistency ∧
    oracleFoldingConsistency

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

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

@[reducible, simp]
def toRelOut : Set ((Statement × Witness) × Unit) :=
  Prod.fst ⁻¹' relIn

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

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

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

def towerAlgebraMap (l r : ℕ) (h_le : l ≤ r) : BTField l →+* BTField r :=

instance [Zero T] [ToNat T] : DecidableRel (@LT.lt (Cayley T) _) := fun a b =>
  Nat.decLt (↑a) (↑b)

noncomputable def commitOracleReduction (i : Fin ℓ) (hCR : 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 := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) where
  prover := commitOracleProver 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i
  verifier := commitOracleVerifier 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hCR

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

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

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

EDist in Mathlib.Topology.EMetricSpace.Defs

def starData {α} (k : ℕ) (root : α) (leaves : Fin k → α) :
    ArityTree.Data α (starSkel k) :=

def MyTypeVec : Fin 3 → Type := !v[ℕ, Bool, String]

example : !d⟨MyTypeVec⟩[(1 : ℕ), true, "hello"] =
  (!h[1, true, "hello"] : (i : Fin 3) → MyTypeVec i) := rfl


example : !d⟨!v[]⟩[] = (Fin.dempty : (i : Fin 0) → !v[] i) := rfl


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


example : let motive : Fin 2 → Type := fun i => if i = 0 then ℕ else Bool
          !d⟨motive⟩[(1 : ℕ), (true : Bool)] =
          (Fin.dcons (1 : ℕ) (Fin.dcons (true : Bool) Fin.dempty) : (i : Fin 2) → motive i) := rfl

def mul_by_2 (s : Finset ℕ) : Finset ℕ :=
  s.map ⟨fun n => 2 * n, by admit /- proof elided -/
  ⟩

Equiv.ofBijective in Mathlib.Logic.Equiv.Defs

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

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

def combined : Prop :=
  capacitySegmentDup trace ∨ notFunction trace

alias E := combined

def concreteTowerAlgebraMap (l r : ℕ) (h_le : l ≤ r) :
    ConcreteBTField l →+* ConcreteBTField r :=

instance {α : Type u} : SliceLT (List α) Nat (fun _ _ => True) (fun _ _ _ => List α) where
  sliceLT xs stop _ := List.take stop xs

def rho (n : ℕ) : Option ℕ := Id.run do
  for st in [2:n] do
    for c in [1:n] do
      if let some d := rho' n st c then
        return some d

  return none

def subNat (c : AssocNat) : Nat → AssocNat
| 0            => c 
| Nat.succ k   => pred (subNat c k) 

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

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

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

def proverRound (i : Fin n) : ProverRound oSpec (pSpec R deg) where
  PrvState := (proverState R n deg i).PrvState

  sendMessage
  | ⟨0, _⟩ => fun state =>
    match n with
    | 0 => sorry
    | n + 1 =>
      let ⟨⟨_, challenges⟩, oStmt⟩ := state
      let ⟨poly, hp⟩ := oStmt 0
      pure ⟨ ⟨∑ x ∈ (univ.map D) ^ᶠ (n - i), poly ⸨X ⦃i⦄, challenges, x⸩'(by admit /- proof elided -/
      ),
        sumcheck_roundPoly_degreeLE R n deg D i hp⟩,
          state⟩
  | ⟨1, h⟩ => nomatch h

  receiveChallenge
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => fun ⟨⟨target, challenges⟩, oStmt⟩ => pure fun chal =>
    let ⟨poly, hp⟩ := oStmt 0
    letI newChallenges : Fin i.succ → R := Fin.snoc challenges chal
    letI newTarget := ∑ x ∈ (univ.map D) ^ᶠ (n - i - 1), poly ⸨newChallenges, x⸩'(by admit /- proof elided -/
    )
    ⟨⟨newTarget, newChallenges⟩, fun _ => ⟨poly, hp⟩⟩

def squeeze (ds : DomainSeparator U H) (count : Nat) (label : String) : DomainSeparator U H :=
  
  
  
  
  { io := ds.io ++ SEP_BYTE ++ s!"S{count}" ++ label }

IO.FS.Stream.write in Init.System.IO

setOf in Mathlib.Data.Set.Defs

Iff in Init.Core

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

def dotProduct [Zero R] [Add R] [Mul R] (a b : Vector R n) : R :=
  a.zipWith (· * ·) b |>.foldl (· + ·) 0

@[reducible]
def MemoryRead (ι : Type u) (α : ι → Type v) := (index : ι) × (α index)

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

Finset.min in Mathlib.Data.Finset.Max

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

noncomputable def queryKnowledgeStateFunction {σ : Type} (init : ProbComp σ)
    (impl : QueryImpl []ₒ (StateT σ ProbComp)) :
  (queryOracleVerifier 𝔽q β (ϑ:=ϑ) γ_repetitions).KnowledgeStateFunction init impl
  (relIn := finalSumcheckRelOut 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
  (relOut := acceptRejectOracleRel)
  (extractor := queryRbrExtractor 𝔽q β (ϑ:=ϑ) γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) where
  toFun := fun m ⟨stmt, oStmt⟩ tr witMid =>
    queryKStateProp 𝔽q β (ϑ:=ϑ) (γ_repetitions:=γ_repetitions)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (m:=m) (tr:=tr) (stmt:=stmt) (witMid:=witMid) (oStmt:=oStmt)
  toFun_empty := fun stmt witMid => by admit /- proof elided -/

MvPolynomial.degreeOf in Mathlib.Algebra.MvPolynomial.Degrees

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

Polynomial.monomial in Mathlib.Algebra.Polynomial.Basic

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

class HListRepr (α : Type _) where
  repr: α → Std.Format

ByteArray in Init.Prelude

noncomputable def toPolynomialAlgHom : P →ₐ[R] R[X] := PolynomialLike.aeval Polynomial.X

context in Examples.FrankingProtocol

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

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

MvPolynomial.X in Mathlib.Algebra.MvPolynomial.Basic

def singleHash (left : α) (right : α) : OracleComp (spec α) α := do
  let out ← query (spec := spec α) () ⟨left, right⟩
  return out

@[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 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.roots in Mathlib.Algebra.Polynomial.Roots

OracleSpec.DecidableEq in VCVio.OracleComp.OracleSpec

@[inline, specialize, simp]
def oracleReduction : OracleReduction oSpec
    Statement OStatement Witness Statement OStatement Witness !p[] := OracleReduction.id

Array.rightpad in Init.Data.Array.Basic

abbrev Bwd : PermuteDir := Sum.inr ()

MvPolynomial.degrees in Mathlib.Algebra.MvPolynomial.Degrees

noncomputable def toMvPolynomialAlgHom : P →ₐ[R] MvPolynomial σ R := aeval MvPolynomial.X

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

@[reducible, inline, specialize]
def challengeOracleInterfaceSR (StmtIn : Type) (pSpec : ProtocolSpec n) :
    ∀ i, OracleInterface (pSpec.Challenge i) := fun i =>
  { Query := StmtIn × pSpec.MessagesUpTo i.1.castSucc
    Response := pSpec.Challenge i
    answer := fun c _ => c }

alias challengeOracleInterfaceFS := challengeOracleInterfaceSR

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

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

protected def OracleProver.id :
    OracleProver oSpec Statement OStatement Witness Statement OStatement Witness !p[] :=
  Prover.id

Array.zipIdx in Init.Data.Array.Basic

Set.Nonempty in Mathlib.Data.Set.Defs

Vector.zipWith in Init.Data.Vector.Basic

def OracleMessages (pSpec : ProtocolSpec n) [OracleInterfaces pSpec] : Type :=
  ∀ i, pSpec.OracleMessage i

Algebra.algebraMap in Mathlib.Algebra.Algebra.Defs

def inputRelation [DecidableEq F] (δ : ℝ≥0) :
    Set
      (
        Unit × (∀ j, OracleStatement D x m j) × (Witness F s d m)
      ) := sorry

instance [h : ProverLast pSpec] : ProverFirst pSpec where
  prover_first' := by admit /- proof elided -/

instance : HListString (HList []) where
  toString
  | HList.nil => ""

@[elab_as_elim]
def dconcat {n : ℕ} {motive : Fin (n + 1) → Sort u}
    (u : (i : Fin n) → motive i.castSucc) (a : motive (last n)) (i : Fin (n + 1)) : motive i :=
  match n with
  | 0 => match i with | 0 => a
  | _ + 1 => dcons (u 0) (dconcat (fun i => u (Fin.succ i)) a) i

Fin.add in Init.Data.Fin.Basic

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

instance {α : Type} [Sampleable α] : DecidableEq α := inferInstance

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

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

instance : MvPolynomialLike σ R (MvPolynomial σ R) where
  X := MvPolynomial.X
  eval₂ := fun f g => eval₂Hom f g
  eval₂_C := fun f g r => by admit /- proof elided -/

List.ofFn in Init.Data.List.OfFn

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

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

iSup in Mathlib.Order.SetNotation

LawfulMonad in Init.Control.Lawful.Basic

structure AlgebraTowerEquiv (A : ι → Type*) [∀ i, CommSemiring (A i)] [a : AlgebraTower A]
  (B : ι → Type*) [∀ i, CommSemiring (B i)] [b : AlgebraTower B]
  where
    toRingEquiv : ∀ i, (A i ≃+* B i)
    commutesLeft' : ∀ (i j : ι) (h : i ≤ j) (r : A i),
      (b.algebraMap (i:=i) (j:=j) (h:=h)) ((toRingEquiv i) r) =
      (toRingEquiv j) (a.algebraMap (i:=i) (j:=j) (h:=h) r)

class Serde (α : Type u) (β : Type v) extends Serialize α β, DeserializeOption α β

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)

Polynomial.reverse in Mathlib.Algebra.Polynomial.Reverse

@[reducible]
def scalarFieldSize : Nat :=
  21888242871839275222246405745257275088548364400416034343698204186575808495617

def ratchet (state : FSVerifierState U H) :
    Except DomainSeparatorMismatch (FSVerifierState U H) := do
  let newHashState ← state.hashState.ratchet
  .ok { hashState := newHashState, nargString := state.nargString }

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 Nontrivial (k : ℕ) : Nontrivial (BTField k) := inferInstance

Nontrivial in Mathlib.Logic.Nontrivial.Defs

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

Field in Mathlib.Algebra.Field.Defs

def perfectCorrectness (scheme : Scheme oSpec Data Randomness Commitment pSpec) : Prop :=
  correctness scheme 0

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

Polynomial.degreeLT in Mathlib.RingTheory.Polynomial.Basic

noncomputable instance (ℓ : Nat) : AddCommGroup (CoeffVecSpace L ℓ) :=

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

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

def somePairs : HList' (fun x => x × x) someTypes :=
  HList'.cons (1, 1) (HList'.cons ("good", "bad") (HList'.cons (5, 3) HList'.nil))

@[simp]
abbrev OracleStatement.AfterFirstSumcheck : R1CS.MatrixIdx ⊕ Fin 1 → Type :=
  OracleStatement.AfterFirstChallenge R pp

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

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

def Permute.ofEquiv (α : Type*) (e : Equiv α α) : Permute α where
  permute := e.toFun

@[reducible]
def SimOracle.Stateful (spec : OracleSpec ι) (specₜ : OracleSpec ιₜ) (σ : Type) :=
  QueryImpl spec (StateT σ (OracleComp specₜ))

def composeM {m' : Type u → Type v} [Monad m'] (hom : m →ᵐ m') (so : QueryImpl spec m) :
    QueryImpl spec m' where
  impl | query i t => hom (so.impl (query i t))

Ne in Init.Core

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 erase_even (s : Finset ℕ) : Finset ℕ := s.filter Odd

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

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

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

instance : Sub (UniPoly R) := ⟨UniPoly.sub⟩

def checkInitImports : IO Bool := do
  \n\
      The `header` linter is included in Mathlib.Init, and every file in Mathlib \
      should import Mathlib.Init.\nPlease adjust the imports accordingly."
    return true

  e

List.range in Init.Data.List.Basic

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

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

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

List.leftpad in Init.Data.List.Basic

Nat.zero in Init.Prelude

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

instance instSelectableTypeChallengePSpec [SelectableType R] :
    ∀ i, SelectableType ((pSpec R deg).Challenge i) :=
  instSelectableTypeChallengeAppend

noncomputable instance changeOfBasisMatrix_invertible
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  Invertible (changeOfBasisMatrix 𝔽q β ℓ h_ℓ) :=

@[inline, reducible]
def lift : (OuterStmtIn × (∀ i, OuterOStmtIn i)) × OuterWitIn →
    (InnerStmtOut × (∀ i, InnerOStmtOut i)) × InnerWitOut →
    (OuterStmtOut × (∀ i, OuterOStmtOut i)) × OuterWitOut :=
  fun ctxIn ctxOut => ⟨lens.stmt.lift ctxIn.1 ctxOut.1, lens.wit.lift ctxIn ctxOut⟩

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

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

def oracleReduction.sendEvalClaim :
    OracleReduction oSpec
      (Statement.AfterFirstSumcheck R pp) (OracleStatement.AfterFirstSumcheck R pp) (Witness R pp)
      (Statement.AfterSendEvalClaim R pp) (OracleStatement.AfterSendEvalClaim R pp) Unit
      ⟨!v[.P_to_V], !v[∀ i, EvalClaim R i]⟩ :=
  sorry

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 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) :=
  (Simple.verifier R deg D oSpec).liftContext (oStmtLens R n deg D i)

@[inline, specialize, simp]
def oracleVerifier : OracleVerifier oSpec Statement OStatement Statement OStatement !p[] :=
  OracleVerifier.id

MvPolynomial.restrictDegree in Mathlib.RingTheory.MvPolynomial.Basic

@[reducible]
def value (op : MemoryWrite ι α) := op.2

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

instance {k : Fin 1} : Unique (ChallengesUpTo k !p[]) where
  default := fun ⟨⟨i, h⟩, _⟩ => by admit /- proof elided -/

def capacitySegmentDupHash : Prop :=
  let ⟨baseTrace, _⟩ := removeRedundantEntryDS trace
  ∃ j : Fin baseTrace.length, ∃ capSeg : Vector U SpongeSize.C,
    ∃ stmt : StmtIn, baseTrace[j] = ⟨.inl (), stmt, capSeg⟩ ∧
      ∃ j' < j,
        ∃ stmt', baseTrace[j'] = ⟨.inl (), stmt', capSeg⟩ ∨
        (∃ stateIn1 stateOut1, baseTrace[j'] = ⟨.inr .Fwd, stateIn1, stateOut1⟩
          ∧ stateOut1.capacitySegment = capSeg) ∨
        (∃ stateOut2 stateIn2, baseTrace[j'] = ⟨.inr .Bwd, stateOut2, stateIn2⟩
          ∧ stateIn2.capacitySegment = capSeg) ∨
        (∃ stateIn3 stateOut3, baseTrace[j'] = ⟨.inr .Fwd, stateIn3, stateOut3⟩
          ∧ stateIn3.capacitySegment = capSeg) ∨
        (∃ stateOut4 stateIn4, baseTrace[j'] = ⟨.inr .Bwd, stateOut4, stateIn4⟩
          ∧ stateOut4.capacitySegment = capSeg)

alias E_h := capacitySegmentDupHash

noncomputable def polyToPowerSeries𝕃 (H : F[X][Y])
  (P : F[X][Y])
    : PowerSeries (𝕃 H) :=
  PowerSeries.mk <| fun n =>
    liftToFunctionField (P.coeff n)

@[reducible]
def mk {R : Type*} (coeffs : Array R) : UniPoly R := coeffs

EquivLike in Mathlib.Data.FunLike.Equiv

def dropLastWhile (p : α → Bool) (l : List α) : List α :=
  (l.reverse.dropWhile p).reverse

BitVec.xor in Init.Data.BitVec.Basic

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 isCommitmentRound (i : Fin ℓ) : Prop :=
  ϑ ∣ i.val + 1 ∧ i.val + 1 ≠ ℓ

@[reducible]
def FinalStatement (F : Type) (k : ℕ) : Type := Fin (k + 1) → F

class SpongeSize where
   
  N : Nat
   
  R : Nat
   
  R_lt_N : R < N := by admit /- proof elided -/

@[reducible, simp]
def OracleStatement.Lens.IsSound {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)]
    (outerLangIn : Set (OuterStmtIn × (∀ i, OuterOStmtIn i)))
    (outerLangOut : Set (OuterStmtOut × (∀ i, OuterOStmtOut i)))
    (innerLangIn : Set (InnerStmtIn × (∀ i, InnerOStmtIn i)))
    (innerLangOut : Set (InnerStmtOut × (∀ i, InnerOStmtOut i)))
    (compatStmt :
      OuterStmtIn × (∀ i, OuterOStmtIn i) → InnerStmtOut × (∀ i, InnerOStmtOut i) → Prop)
    (lens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                    OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut) :=
  Statement.Lens.IsSound outerLangIn outerLangOut innerLangIn innerLangOut compatStmt lens

class IsRBRSound (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec) where
  rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0
  is_rbr_sound : rbrSoundness init impl langIn langOut verifier rbrSoundnessError

class HasPred (T : Type u) where
   
  pred' : T → T

def coeffsToBitVec {n : ℕ} (coeffs : List (ZMod 2)) : BitVec n :=
  let val := List.foldr (fun c acc => acc * 2 + c.val) 0 (coeffs.take n)
  BitVec.ofNat n val

def Straightline.append (E₁ : Extractor.Straightline oSpec Stmt₁ Wit₁ Wit₂ pSpec₁)
    (E₂ : Extractor.Straightline oSpec Stmt₂ Wit₂ Wit₃ pSpec₂)
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁) :
      Extractor.Straightline oSpec Stmt₁ Wit₁ Wit₃ (pSpec₁ ++ₚ pSpec₂) :=
  fun stmt₁ wit₃ transcript proveQueryLog verifyQueryLog => do
    let stmt₂ ← V₁.verify stmt₁ transcript.fst
    let wit₂ ← E₂ stmt₂ wit₃ transcript.snd proveQueryLog verifyQueryLog
    let wit₁ ← E₁ stmt₁ wit₂ transcript.fst proveQueryLog verifyQueryLog
    return wit₁

instance Vector.instFintype {α : Type*} {n : ℕ} [VCVCompatible α] : Fintype (Vector α n) :=
  Fintype.ofEquiv _ (Equiv.rootVectorEquivFin).symm

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

instance : EDist (n → R) where
  edist := fun u v => hammingDist u v

OracleComp in VCVio.OracleComp.OracleComp

Mod in Init.Prelude

noncomputable def definingPoly {F : Type*} [instField : Field F] (s : F)
  := X ^ 2 + C s * X + 1

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

FiniteDimensional in Mathlib.LinearAlgebra.FiniteDimensional.Defs

def sub (m n : ChurchNat α) : ChurchNat α := sorry 

class LawfulHasSucc (T : Type u) [HasSucc T] [Add T] [One T] : Prop where
   
  succ'_eq_add_one : ∀ x : T, succ' x = x + 1

noncomputable def ansPoly (S : Finset F) (Ans : S → F) : Polynomial F :=
  Lagrange.interpolate S.attach (fun i => (i : F)) Ans

@[simp]
def evalDomain (i : ℕ) : Subgroup Fˣ :=
  Subgroup.zpowers (DIsCyclicC.gen ^ (2 ^ i))

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

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

Set.Nontrivial in Mathlib.Data.Set.Subsingleton

noncomputable def proximity_gap_degree_bound (rho : ℚ) (m n : ℕ) : ℕ :=
  let b := D_X rho m n
  if h : ∃ n : ℕ, b = n
  then h.choose - 1
  else Nat.floor b

instance : ∀ j, SelectableType ((pSpecFoldRelay (L:=L)).Challenge j) :=
  instSelectableTypeChallengeAppend

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

@[inline, specialize]
def eval (x : R) (p : UniPoly R) : R :=
  p.eval₂ (RingHom.id R) x

instance : _root_.Field Field := ZMod.instField fieldSize

def relHammingBallInterleavedCode [DecidableEq F] (U : Matrix κ ι F)
  (IC : MatrixSubmodule κ ι F) (r : ℝ) :=
    {V | V ∈ IC ∧ relDistCodewords U V < r}

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

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

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

UInt8.ofFin in Init.Data.UInt.Basic

List.getLast in Init.Data.List.Basic

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

@[reducible, simp]
def relOut : Set (Statement × Unit) := Set.univ

Units.mulAction' in Mathlib.Algebra.Group.Action.Units

def evalNormalizedWAt (i : Fin r) (x : L) : L :=
  let W_x := evalWAt (r := r) (L := L) (ℓ := ℓ) (β := β) (R_rate := R_rate) (i := i) x
  let beta_i := β i
  let W_beta := evalWAt (β := β) (ℓ := ℓ) (R_rate := R_rate) (i := i) beta_i
  W_x * W_beta⁻¹

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

@[inline] def pow [Zero T] [One T] [ToNat T] (a b : Cayley T) : Cayley T :=
  powNat a ↑b

def Verifier.duplexSpongeFiatShamir (V : Verifier oSpec StmtIn StmtOut pSpec) :
    NonInteractiveVerifier (∀ i, pSpec.Message i) (oSpec ++ₒ duplexSpongeChallengeOracle StmtIn U)
      StmtIn StmtOut where
  verify := fun stmtIn proof => do
    
    let messages : pSpec.Messages := proof 0
    
    let ⟨_, transcript⟩ ← messages.deriveTranscriptDSFS stmtIn
    V.verify stmtIn transcript

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

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

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

def rowSpan : Submodule F (ι' → F) :=
  Submodule.span F {U i | i : ι}

def intCast_negSucc {k : ℕ} (n : ℕ) : intCast (k:=k) (Int.negSucc n)
  = - (↑(n + 1) : ConcreteBTField k) :=

WithBot.addMonoidWithOne in Mathlib.Algebra.Order.Monoid.Unbundled.WithTop

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

Fin.cast in Init.Data.Fin.Basic

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 sumcheckConsistencyProp {k : ℕ} (sumcheckTarget : L) (H : L⦃≤ 2⦄[X Fin (k)]) : Prop :=
  sumcheckTarget = ∑ x ∈ (univ.map 𝓑) ^ᶠ (k), H.val.eval x

noncomputable def fieldTo𝕃 {H : F[X][Y]} : F →+* 𝕃 H :=
  RingHom.comp liftToFunctionField Polynomial.C

instance {i : ℕ} : IsCyclicWithGen (evalDomain D i) :=

def g (n : ℕ) (c : ℕ) (x : ℕ) := (x * x + c) % n

MonomialOrder in Mathlib.Data.Finsupp.MonomialOrder

inductive HList' {α : Type v} (β : α → Type u) : List α → Type (max u v)
  | nil  : HList' β []
  | cons : β i → HList' β is → HList' β (i :: is)

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

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

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

Set.toFinset in Mathlib.Data.Fintype.Sets

BitVec.cast in Init.Data.BitVec.Basic

Prod in Init.Prelude
</all_available_defs>

<all_available_lemmas>
Finset.image_subset_iff in Mathlib.Data.Finset.Image
Finset.sum_image in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.sum_le_sum in Mathlib.Algebra.Order.BigOperators.Group.Finset
Finset.sum_le_sum_of_subset_of_nonneg in Mathlib.Algebra.Order.BigOperators.Group.Finset
Multiset.count_pos in Mathlib.Data.Multiset.Count
Multiset.toFinset_sum_count_eq in Mathlib.Algebra.BigOperators.Group.Finset.Basic
le_trans in Mathlib.Order.Defs.PartialOrder
lt_of_lt_of_le in Mathlib.Order.Defs.PartialOrder
Polynomial.mem_degreeLT in Mathlib.RingTheory.Polynomial.Basic
Polynomial.natDegree_lt_iff_degree_lt in Mathlib.Algebra.Polynomial.Degree.Definitions
Polynomial.ext in Mathlib.Algebra.Polynomial.Basic
Fin.castLE_injective in Mathlib.Data.Fin.SuccPred
Function.Injective.comp in Init.Data.Function
Matrix.det_vandermonde_ne_zero_iff in Mathlib.LinearAlgebra.Vandermonde
Matrix.mulVecLin_apply in Mathlib.LinearAlgebra.Matrix.ToLin
Matrix.mulVec_eq_sum in Mathlib.Data.Matrix.Mul
Finset.mem_range in Mathlib.Data.Finset.Range
Finset.sum_congr in Mathlib.Algebra.BigOperators.Group.Finset.Basic
Finset.sum_fin_eq_sum_range in Mathlib.Data.Fintype.BigOperators
Polynomial.eval_eq_sum_range' in Mathlib.Algebra.Polynomial.Eval.Degree
LinearMap.mem_range in Mathlib.Algebra.Module.Submodule.Range
Submodule.mem_map in Mathlib.Algebra.Module.Submodule.Map
Finset.filter_card_add_filter_neg_card_eq_card in Mathlib.Data.Finset.Card
Multiset.count_eq_one_of_mem in Mathlib.Data.Multiset.Count
Multiset.count_filter in Mathlib.Data.Multiset.Filter
Multiset.nodup_iff_count_eq_one in Mathlib.Data.Multiset.Count
Polynomial.card_roots' in Mathlib.Algebra.Polynomial.Roots
le_antisymm in Mathlib.Order.Defs.PartialOrder
le_csInf in Mathlib.Order.ConditionallyCompleteLattice.Basic
lt_of_le_of_lt in Mathlib.Order.Defs.PartialOrder

lemma rank_eq_if_det_ne_zero {U : Matrix (Fin n) (Fin n) F} [IsDomain F] :
  Matrix.det U ≠ 0 → U.rank = n

lemma rank_eq_if_subUpFull_eq (h : n ≤ m) :
   (subUpFull U (Fin.castLE h)).rank = n  → U.rank = n

lemma full_row_rank_via_rank_subLeftFull (h : m ≤ n) :
   (subLeftFull U (Fin.castLE h)).rank = m → U.rank = m

lemma cRank_rank_conversion :
  ↑(U.rank) = U.cRank

@[simp]
lemma liftF'_p_coeff {p : F[X]} {k : ℕ} {i : Fin k} : liftF' p.coeff i = p.coeff i

@[simp]
lemma coeff_polynomialOfCoeffs_eq_coeffs :
  Fin.liftF' (polynomialOfCoeffs coeffs).coeff = coeffs

lemma rank_eq_dim_fromColGenMat [CommRing F] {G : Matrix κ ι F} :
  G.rank = dim (fromColGenMat G)

theorem singletonBound [CommRing F] [StrongRankCondition F]
  (LC : LinearCode ι F) :
  dim LC ≤ length LC - Code.minDist (LC : Set (ι → F)) + 1

lemma dist_UB [CommRing F] {LC : LinearCode ι F} :
    Code.minDist (LC : Set (ι → F)) ≤ length LC

lemma dist_eq_minWtCodewords [CommRing F] {LC : LinearCode ι F} :
  Code.minDist (LC : Set (ι → F)) = minWtCodewords LC

lemma hammingDist_eq_wt_sub [CommRing F] {u v : ι → F} : hammingDist u v = Code.wt (u - v)

lemma add_eq_zero_iff_eq {k : ℕ} (a b : ConcreteBTField k) : a + b = 0 ↔ a = b

theorem cast_run (stmt : StmtIn) (wit : WitIn) :
    R.run stmt wit = cast (sorry) ((R.cast hn hSpec).run stmt wit)

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 nsmul_succ (n : ℕ) (p : UniPolyC R) : nsmul (n + 1) p = nsmul n p + p

@[simp]
theorem cast_id :
    OracleVerifier.cast rfl rfl (fun i => rfl) =
      (id : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec₁ → _)

omit [NeZero r] [NeZero 𝓡] in
lemma isCommitmentRoundOfNonLastBlock (bIdx : Fin (ℓ / ϑ - 1)) :
    isCommitmentRound ℓ ϑ ⟨↑bIdx * ϑ + (ϑ - 1), by
      have hpos: ϑ > 0 := by exact Nat.pos_of_neZero ϑ
      conv_rhs => rw [←Nat.add_zero (n:=ℓ)]
      change bIdx.val * ϑ + (⟨ϑ - 1, by omega⟩: Fin ϑ).val < ℓ + 0
      apply bIdx_mul_ϑ_add_i_lt_ℓ_succ (m:=0)
    ⟩

theorem degrees_eval [DecidableEq σ] {τ : Type*} {f : τ → R} {p : R[X σ][X τ]} :
    (eval (C ∘ f) p).degrees ≤ p.support.sup (fun c => (coeff c p).degrees)

@[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 take_eq_take : transcript⟦:m⟧ = transcript.take m h

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

theorem toPoly_toImpl {p : Q[X]} : p.toImpl.toPoly = p

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)

Nat.sub_mul in Init.Data.Nat.Basic

Nat.add_le_of_le_sub in Init.Data.Nat.Basic

theorem heq_of_dcast (ha : a = a') (hb : dcast ha b = b') : HEq b b'

@[simp] theorem equiv_symm {p q : UniPoly Q} : equiv p q → equiv q p

theorem prime_19 : Nat.Prime 19

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

@[simp] theorem zero_add {a : AssocNat} : 0 + a = a

omit [NeZero r] [NeZero 𝓡] in
lemma isNeCommitmentRound (bIdx : Fin (ℓ / ϑ - 1)) (x : ℕ) {hx : x < ϑ - 1} :
    ¬isCommitmentRound ℓ ϑ ⟨↑bIdx * ϑ + x, by
      conv_rhs => rw [←Nat.add_zero (n:=ℓ)]
      change bIdx.val * ϑ + (⟨x, by omega⟩: Fin ϑ).val < ℓ + 0
      apply bIdx_mul_ϑ_add_i_lt_ℓ_succ (m:=0)
    ⟩

lemma sup_eq_of_le_of_reach {α β : Type} [SemilatticeSup β] [OrderBot β] {s : Finset α} {f : α → β}
      (x : α) {y : β} (h : x ∈ s) :
    f x = y →
    (∀ x ∈ s, f x ≤ y) →
    s.sup f = y

theorem GF_2_pow_card (x : GF(2)) : x ^ Fintype.card (GF(2)) = x

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

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

@[simp]
theorem embedSum_succ_zero {n : Fin (m + 1) → ℕ} {j : Fin (n 0)} :
    embedSum 0 j = Fin.castAdd _ j

@[simp]
theorem toNat_succ (n : ChurchNat ℕ) : toNat (succ n) = n.toNat.succ

@[simp]
theorem removeNth_zero : removeNth 0 s = tail s

omit [DecidableEq α] [Inhabited α] [Fintype α] in
@[simp]
lemma Cache.upper_cons (n : ℕ) (leaves : List.Vector α (2 ^ (n + 1))) (cache : Cache α n) :
    Cache.upper α n (Cache.cons α n leaves cache) = cache

theorem insertNth_self_removeNth : insertNth p (t p) (removeNth p t) = t

theorem prime_43 : Nat.Prime 43

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

theorem seqCompose_rbrKnowledgeSoundness
    (rel : ∀ i, 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))
    (rbrKnowledgeError : ∀ i, (pSpec i).ChallengeIdx → ℝ≥0)
    (h : ∀ i, (V i).rbrKnowledgeSoundness init impl
      (rel i.castSucc) (rel i.succ) (rbrKnowledgeError i)) :
    (OracleVerifier.seqCompose Stmt OStmt V).rbrKnowledgeSoundness
        init impl (rel 0) (rel (Fin.last m))
        (fun combinedIdx =>
          letI ij := seqComposeChallengeIdxToSigma combinedIdx
          rbrKnowledgeError ij.1 ij.2)

theorem snoc_ne_zero_of_left (h : s ≠ 0) : snoc s y ≠ 0

private lemma solution_to_BerlekampWelch_condition {e k : ℕ}
  [NeZero n]
  {ωs f : Fin n → F}
  {v : Fin (2 * e + k) → F}
  (h_sol : IsBerlekampWelchSolution e k ωs f v)
  : BerlekampWelchCondition e k ωs f (solutionToE e k v) (solutionToQ e k v)

@[simp]
lemma numFullRounds_pos : 0 < params.numFullRounds

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

lemma h_sum_two_same_pow2 {k : ℕ} (h_pos : k > 0) : 2 ^ (k - 1) + 2 ^ (k - 1) = 2 ^ k

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

Fin.append_left in Mathlib.Data.Fin.Tuple.Basic

@[simp] theorem rightpad_length (n : Nat) (unit : α) (l : List α) :
    (rightpad n unit l).length = max n l.length

lemma concrete_mul_one
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul a (one (k:=k)) = a

theorem pow_three_eq_mul_sq {a : CNat 1} : a ^ 3 = a * (a * a)

lemma bwm_of_neg [NeZero n] (h : e ≤ j.1) :
  BerlekampWelchMatrix e k ωs f i j = -(ωs i)^(j - e)

Finset.sup_lt_iff in Mathlib.Data.Finset.Lattice.Fold

lemma aeval_eq' {A : Type w} [CommSemiring A] [Algebra R A] (f : P →ₐ[R] A) (p : P) :
    f p = aeval (f X) p

theorem randomOracle_cache_neverFails_iff_runWithOracle_neverFails {β}
    [DecidableEq ι] [spec.DecidableEq] [(i : ι) → SelectableType (OracleSpec.range spec i)]
    (oa : OracleComp (spec) β) (preexisting_cache : spec.QueryCache)
    :
    ((oa.simulateQ randomOracle).run preexisting_cache).neverFails
    ↔
    (∀ (f : spec.FunctionType),
      Oracle.containsCache f preexisting_cache →
      (runWithOracle f oa).isSome)

lemma add_assoc {k : ℕ} : ∀ (a b c : ConcreteBTField k), a + b + c = a + (b + c)

lemma rounds_sub_steps_lt : ℓ - ϑ < ℓ :=
  Nat.sub_lt (pos_of_neZero ℓ) (folding_steps_pos)

lemma ϑ_sub_one_le_self : ϑ - 1 < ϑ

theorem stir_rbr_soundness
    [SelectableType F] {s : ℕ}
    {P : Params ι F} {φ : (i : Fin (M + 1)) → (ι i ↪ F)}
    [h_nonempty : ∀ i : Fin (M + 1), Nonempty (ι i)]
    {hParams : ParamConditions ι P} {Dist : Distances M}
    {Codes : CodeParams ι P Dist}
    (h_not_code : ∀ f₀ : (ι 0) → F, f₀ ∉ (Codes.C 0))
    (hδ₀Le : ∀ f₀ : (ι 0) → F, Dist.δ 0 ≤ (δᵣ(f₀, (Codes.C 0)) : ℝ) ∧
      Dist.δ 0 < (1 - Bstar (rate (code (P.φ 0) P.deg))))
    (hδᵢ : ∀ {j : Fin (M + 1)}, j ≠ 0 →
        Dist.δ j < (1 - rate (code (P.φ j) (degree ι P j))
          - 1 / Fintype.card (ι j) : ℝ) ∧
        Dist.δ j < (1 - Bstar (rate (code (P.φ j) (degree ι P j)))))
    (ε_fold : ℝ≥0) (ε_out : Fin M → ℝ≥0) (ε_shift : Fin M → ℝ≥0) (ε_fin : ℝ≥0) :
    ∃ n : ℕ,
    -- There exists an `n`-message vector IOPP,
    ∃ vPSpec : ProtocolSpec.VectorSpec n,
    -- such that there are `2 * M + 2` challenges from the verifier to the prover,
    Fintype.card (vPSpec.ChallengeIdx) = 2 * M + 2 ∧
    -- ∃ vector IOPP π with the aforementioned `vPSpec`, and for
    -- `Statement = Unit, Witness = Unit, OracleStatement(ι₀, F)` such that
    ∃ π : VectorIOP Unit (OracleStatement (ι 0) F) Unit vPSpec F,
    let ε_rbr : vPSpec.ChallengeIdx → ℝ≥0

@[simp]
theorem simulateQ'_query (q : OracleQuery spec α) :
    simulateQ' so q (by simp) = so.impl q

@[simp]
theorem OracleSpec.append_range_left {ι₁ ι₂ : Type} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂}
    (i : ι₁) : (spec₁ ++ₒ spec₂).range (Sum.inl i) = spec₁.range i

Nat.add_zero in Init.Core

theorem cast_eq_dcast {m n : ℕ} (h : m = n) (a : Fin m) :
    Fin.cast h a = dcast h a

@[simp]
theorem fappend_succ {α : Fin m → A} {β : Fin (n + 1) → A}
    (u : (i : Fin m) → F (α i)) (v : (i : Fin (n + 1)) → F (β i)) :
    fappend u v = fconcat (fappend u (fun i => v (castSucc i))) (v (last n))

lemma liftF_eval {f : Fin n → α} {i : Fin n} :
  liftF f i.val = f i

protected lemma errors_are_roots_of_elocPolyF {i : Fin n} {ωs f : Fin n → F}
  (h : f i ≠ p.eval (ωs i)) : (ElocPolyF ωs f p).eval (ωs i) = 0

lemma add_eq_one_iff (a b : ConcreteBTField 0) :
  a + b = 1 ↔ (a = 0 ∧ b = 1) ∨ (a = 1 ∧ b = 0)

theorem and_highBits_lowBits_eq_zero {n : ℕ} (numLowBits : ℕ) :
    getHighBits numLowBits n &&& getLowBits numLowBits n = 0

lemma wt_eq_hammingNorm [Zero F] {v : ι → F} :
  wt v = hammingNorm v

lemma relHammingDist_le_blockRelDistance
  (i k : ℕ) {S : Finset ι} {φ : ι ↪ F} {φ' : (indexPowT S φ i) ↪ F}
  [DecidableEq F] [DecidableEq ι] [Smooth φ]
  (f g : (indexPowT S φ i) → F) (S' : Finset (indexPowT S φ i))
  [h_fintype : ∀ i : ℕ, Fintype (indexPowT S φ i)]
  [DecidableEq (indexPowT S φ i)] [Smooth φ']
  [h_dec : DecidableBlockDisagreement i k f S' φ'] :
  δᵣ(f, g) ≤ Δᵣ(i, k, f, S', φ', g)

lemma getBit_of_highBits_no_shl {n: ℕ} (numLowBits : ℕ) :
    ∀ k, getBit k (getHighBits_no_shl numLowBits n)
  = getBit (k + numLowBits) (n)

theorem add_succ (m n : ChurchNat α) : add (succ m) n = succ (add m n)

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 sum_join_via_add_smul (k : ℕ) (h_pos : k > 0) (a₁ a₀ b₁ b₀ : BTField (k - 1)) :
  ⋘ a₁, a₀ ⋙ + ⋘ b₁, b₀ ⋙ = ⋘ a₁ + b₁, a₀ + b₀ ⋙

lemma towerRingHomForwardMap_add_eq (k : ℕ) (x y : ConcreteBTField k) :
    towerRingHomForwardMap (k:=k) (x + y)
    = towerRingHomForwardMap (k:=k) x + towerRingHomForwardMap (k:=k) y

@[simp]
lemma OracleVerifier.id_toVerifier :
    (OracleVerifier.id : OracleVerifier oSpec Statement OStatement _ _ _).toVerifier =
      Verifier.id

theorem fcons_right_injective {β : Fin n → A} (a : F α) :
    Function.Injective (fcons a : ((i : Fin n) → F (β i)) → (i : Fin (n + 1)) → _)

theorem getElem?_eq_toList {a : Array α} {i : ℕ} : a.toList[i]? = a[i]?

@[simp]
theorem acceptRejectRel_language : acceptRejectRel.language = { true }

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

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 concrete_mul_zero
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul a (zero (k:=k)) = zero (k:=k)

omit h_Fq_char_prime in
theorem changeOfBasisMatrix_lower_triangular
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  (changeOfBasisMatrix 𝔽q β ℓ h_ℓ).BlockTriangular ⇑OrderDual.toDual

@[simp]
lemma oddPart_coeff {f : Polynomial F} {n : ℕ} :
    (oddPart f).coeff n = if Even n then f.coeff (n + 1) else 0

private lemma Fis_pairwise_disjoint : Set.PairwiseDisjoint Set.univ (Fi B i)

lemma irreducible_factorization_of_gs_solution
  {k : ℕ}
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁) :
  ∃ (C : F[Z][X]) (R : List F[Z][X][Y]) (f : List ℕ) (e : List ℕ),
    R.length = f.length ∧
    f.length = e.length ∧
    ∀ eᵢ ∈ e, 1 ≤ eᵢ ∧
    ∀ Rᵢ ∈ R, Rᵢ.Separable ∧
    ∀ Rᵢ ∈ R, Irreducible Rᵢ ∧
    Q = (Polynomial.C C) *
        ∏ (Rᵢ ∈ R.toFinset) (fᵢ ∈ f.toFinset) (eᵢ ∈ e.toFinset),
          (Rᵢ.comp ((Y : F[Z][X][Y]) ^ fᵢ))^eᵢ

lemma xor_of_and_eq_zero_is_or {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n ^^^ m = n ||

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 sum_eq_xor_plus_twice_and (n : Nat) : ∀ m : ℕ, n + m = (n ^^^ m) + 2 * (n &&& m)

omit Oₘ in
theorem seqCompose_perfectCompleteness (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))
    (h : ∀ i, (R i).perfectCompleteness init impl (rel i.castSucc) (rel i.succ)) :
      (Reduction.seqCompose Stmt Wit R).perfectCompleteness
        init impl (rel 0) (rel (Fin.last m))

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

theorem two_eq_zero_in_char2_field {F : Type*} [Field F]
  (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y) : (2 : F) = 0

theorem galois_automorphism_power
    {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)
    (specialElementNeZero : u ≠ 0)
    (prevSpecialElementNeZero : t1 ≠ 0)
    (u_plus_inv_eq_t1 : u + u⁻¹ = t1)
    (h_u_square : u ^ 2 = u * t1 + 1)
    (h_t1_pow : t1 ^ (2 ^ (2 ^ k) - 1) = 1 ∧ (t1⁻¹) ^ (2 ^ (2 ^ k) - 1) = 1)
    (trace_map_roots : ∑ i ∈ Finset.range (2 ^ k), t1 ^ (2 ^ i) = 1 ∧
                      ∑ i ∈ Finset.range (2 ^ k), t1⁻¹ ^ (2 ^ i) = 1) :
    u^(2^(2^k)) = u⁻¹ ∧ (u⁻¹)^(2^(2^k)) = u

@[simp]
lemma Rhs_zero_eq_neg : Rhs 0 ωs f i = -f i

@[simp]
lemma possibleDeltas_subset_relHammingDistRange :
  possibleDeltas U C ⊆ relHammingDistRange ι

@[simp]
theorem rtake_zero (v : (i : Fin n) → α i) :
    rtake 0 (by omega) v = fun i => Fin.elim0 i

lemma MessageIdxUpTo.eq_MessageIdx {k : Fin (n + 1)} {pSpec : ProtocolSpec n} :
    pSpec.MessageIdxUpTo k = {i : Fin k // pSpec.dir (i.castLE (by omega)) = .P_to_V}

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

theorem completeness_relOut_mono {ε : ℝ≥0} {relOut' : Set (StmtOut × WitOut)}
    (hrelOut : relOut ⊆ relOut') :
      completeness init impl relIn relOut reduction ε →
        completeness init impl relIn relOut' reduction ε

@[simp]
theorem drop_one {α : Fin (n + 1) → Sort*} (v : (i : Fin (n + 1)) → α i) :
    drop 1 (Nat.le_add_left 1 n) v = tail v

theorem liftContext_processRound
    {lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {i : Fin n}
    {P : Prover oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec}
    {resultRound : OracleComp (oSpec ++ₒ [pSpec.Challenge]ₒ)
      (pSpec.Transcript i.castSucc × (P.liftContext lens).PrvState i.castSucc)} :
      (P.liftContext lens).processRound i resultRound
      = do
        let ⟨transcript, prvState, outerStmtIn, outerWitIn⟩ ← resultRound
        let ⟨newTranscript, newPrvState⟩ ← P.processRound i (do return ⟨transcript, prvState⟩)
        return ⟨newTranscript, ⟨newPrvState, outerStmtIn, outerWitIn⟩⟩

@[simp]
lemma lt_add_of_pos_right_of_le (a b c : ℕ) [NeZero c] (h : a ≤ b) : a < b + c

theorem is_prime : Nat.Prime fieldSize

@[simp]
theorem hflatten_embedSum {m : ℕ} {n : Fin m → ℕ} {α : (i : Fin m) → (j : Fin (n i)) → Sort*}
    (v : (i : Fin m) → (j : Fin (n i)) → α i j) (i : Fin m) (j : Fin (n i)) :
    hflatten v (embedSum i j) = cast (vflatten_embedSum α i j).symm (v i j)

lemma lagrangeToMono_eq_lagrangeToMono_segment (n : ℕ) [NeZero n] (v : Vector R (2 ^ n)) :
  have h_n_ne_zero: n ≠ 0

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

@[simp]
theorem embedSum_succ_succ {n : Fin (m + 1) → ℕ} {i : Fin m} (j : Fin (n i.succ)) :
    embedSum (i.succ) j = Fin.natAdd _ (embedSum i j)

lemma join_via_add_smul_zero {k : ℕ} (h_pos : k > 0) :
  ⋘ 0, 0 ⋙ = 0

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)

theorem funext_heq_iff {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v}
    {f : (x : α) → β x} {g : (x : α') → β' x} (ha : α = α') (hb : ∀ x, β x = β' (cast ha x)) :
      HEq f g ↔ ∀ x, HEq (f x) (g (cast ha x))

@[simp]
theorem Basis_cast_index_eq (i j k n : ℕ) (h_le : k ≤ n) (h_eq : i = j) :
    letI instAlgebra : Algebra (ConcreteBTField k) (ConcreteBTField n) :=
      ConcreteBTFieldAlgebra (l:=k) (r:=n) (h_le:=h_le)
    letI : Module (ConcreteBTField k) (ConcreteBTField n) := instAlgebra.toModule
    (Basis (Fin (i)) (ConcreteBTField k) (ConcreteBTField n)) =
    (Basis (Fin (j)) (ConcreteBTField k) (ConcreteBTField n))

@[simp, grind] lemma R_le_N : sz.R ≤ sz.N

theorem append_rbrKnowledgeSoundness
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁)
    (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    {rbrKnowledgeError₁ : pSpec₁.ChallengeIdx → ℝ≥0}
    {rbrKnowledgeError₂ : pSpec₂.ChallengeIdx → ℝ≥0}
    (h₁ : V₁.rbrKnowledgeSoundness init impl rel₁ rel₂ rbrKnowledgeError₁)
    (h₂ : V₂.rbrKnowledgeSoundness init impl rel₂ rel₃ rbrKnowledgeError₂) :
      (V₁.append V₂).rbrKnowledgeSoundness init impl rel₁ rel₃
        (Sum.elim rbrKnowledgeError₁ rbrKnowledgeError₂ ∘ ChallengeIdx.sumEquiv.symm)

theorem distFromCode_eq_zero_iff_mem (C : Set (n → R)) (u : n → R) : Δ₀(u, C) = 0 ↔ u ∈ C

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

lemma eval₂_induction_on : True

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)

@[simp]
lemma OracleVerifier.id_rbrKnowledgeSoundness
    {rel : Set ((Statement × ∀ i, OStatement i) × Witness)} :
    (OracleVerifier.id : OracleVerifier oSpec Statement OStatement _ _ _).rbrKnowledgeSoundness
      init impl rel rel 0

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

@[csimp]
theorem vappend_eq_append : @vappend = @append

lemma concrete_mul_comm0 (a b : ConcreteBTField 0) :
  concrete_mul a b = concrete_mul b a

Nat.pos_of_neZero in Init.Data.Nat.Basic

theorem hammingDist_le_of_decoder_eq_some [NeZero n] {ωs f : Fin n → F}
  (h : decoder e k ωs f = some p) : Δ₀(f, p.eval ∘ ωs) ≤ e

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

lemma getBit_of_xor {n m k: ℕ} : getBit k (n ^^^ m) = getBit k n ^^^ getBit k m

@[simp]
theorem seqCompose_one {n : Fin 1 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = pSpec 0

lemma mkLastOracleIndex_last : mkLastOracleIndex ℓ ϑ (Fin.last ℓ) = ℓ / ϑ - 1

theorem cast_eq_dcast {h : n₁ = n₂} {pSpec : ProtocolSpec n₁} :
    pSpec.cast h = dcast h pSpec

omit [NeZero r] [Field L] [Fintype L] [DecidableEq L] [DecidableEq 𝔽q] [Field 𝔽q] [Algebra 𝔽q L] in
lemma base_coeffsBySuffix (a : Fin (2 ^ ℓ) → L) :
  coeffsBySuffix (r:=r) (R_rate := R_rate) a 0 0 = a

lemma getFoldingChallenges_init_succ_eq (i : Fin ℓ)
    (j : Fin (toOutCodewordsCount ℓ ϑ i.castSucc)) (challenges : Fin i.succ → L)
    (h : ↑j * ϑ + ϑ ≤ ↑i.castSucc) :
    getFoldingChallenges (r := r) (𝓡 := 𝓡) (ϑ := ϑ) i.castSucc (Fin.init challenges) (↑j * ϑ)
      (h := by omega) =
    getFoldingChallenges (r := r) (𝓡 := 𝓡) i.succ challenges (↑j * ϑ)
      (h := by simp only [Fin.val_succ]; simp only [Fin.coe_castSucc] at h; omega)

Nat.lt_trans in Init.Prelude

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)

Nat.add_left_cancel in Init.Data.Nat.Basic

@[simp]
theorem ConcreteBTField.RingHom_eq_of_source_eq (k n m : ℕ) (h_eq : k = n) :
    (ConcreteBTField k →+* ConcreteBTField m)
    = (ConcreteBTField n →+* ConcreteBTField m)

@[simp]
lemma toFun_invFun (f : ∀ a, β a) : inst.equiv.toFun (equiv.invFun f : F) = f

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

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

lemma getLowBits_zero_eq_zero {n : ℕ} : getLowBits 0 n = 0

@[simp]
lemma eval_solutionToE {x : F} :
  eval x (solutionToE e k v) = x ^ e + ∑ y : Fin e, v ⟨y, by omega⟩ * x ^ y.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

@[simp]
theorem LeafData.rightSubtree_internal {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right) :
    (LeafData.internal left right).rightSubtree = right

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)

lemma listOfCloseCodewords_eq_zero :
  listOfCloseCodewords C y n = 0 ↔ IsEmpty (hammingBall C y n) ∨ Infinite (hammingBall C y n)

@[simp]
lemma evenPart_by_2 :
  2 * (evenPart f) = f + f.comp (-X)

@[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 irreducibleHTildeOfIrreducible {H : Polynomial (Polynomial F)} :
    (Irreducible H → Irreducible (H_tilde H))

lemma forwardRange_eq_of_r_eq (n : ℕ) (r1 r2 : Fin n) (h_r_eq : r1 = r2) (l : Fin (r1.val + 1)) :
  forwardRange n r1 l = forwardRange n r2 ⟨l, by omega⟩

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

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)

lemma Fin.le_succ (a : Fin r) (h_a_add_1 : a + 1 < r) : a ≤ a + 1

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

lemma concrete_mul_zero0 (a : ConcreteBTField 0) :
  concrete_mul a (zero (k:=0)) = zero (k:=0)

@[simp]
lemma constantCode_eq_ofNat_zero_iff [Nonempty ι] :
  constantCode x ι = 0 ↔ x = 0

@[simp]
theorem oracleReduction_completeness (h : init.neverFails)
    (hRel : ∀ stmtIn oStmtIn witIn,
      ((stmtIn, oStmtIn), witIn) ∈ relIn →
      ((mapStmt stmtIn, mapOStmt embedIdx hEq oStmtIn), mapWit stmtIn witIn) ∈ relOut) :
    (oracleReduction oSpec mapStmt mapWit embedIdx hEq).perfectCompleteness init impl
      relIn relOut

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 divide_by_2_mem {s : Finset ℕ} {d : ℕ} :
  d ∈ divide_by_2 s ↔ 2 * d ∈ s

lemma isInterleaved_codeOfLinearCode : (codeOfLinearCode κ LC).isInterleaved

@[to_additive (attr := simp) vsum_succ]
lemma vprod_succ [CommMonoid α] {a : Fin (n + 1) → α} : vprod a = a 0 * vprod (a ∘ Fin.succ)

@[simp]
theorem ConcreteBTFieldAlgebra_id {l r : ℕ} (h_eq : l = r) :
    @ConcreteBTFieldAlgebra l r (h_le:=by omega) =
    (h_eq ▸ (Algebra.id (ConcreteBTField l)) :
      Algebra (ConcreteBTField l) (ConcreteBTField r))

theorem liftContext_perfectCompleteness
    (h : R.perfectCompleteness init impl innerRelIn innerRelOut) :
      (R.liftContext lens).perfectCompleteness init impl outerRelIn outerRelOut

@[simp]
theorem zero_dappend {motive : Fin (0 + n) → Sort u} {u : (i : Fin 0) → motive (castAdd n i)}
    (v : (i : Fin n) → motive (natAdd 0 i)) :
    dappend (motive := motive) u v = fun i => cast (by simp) (v (i.cast (by omega)))

@[simp]
lemma lastBlockIdx_mul_ϑ_add_fin_lt_ℓ (i : Fin ϑ) :
    (ℓ / ϑ - 1) * ϑ + ↑i < ℓ

@[simp]
theorem FullData.map_internal {α β} {s_left s_right : Skeleton}
    (f : α → β) (value : α) (left : FullData α s_left) (right : FullData α s_right) :
    (FullData.internal value left right).map f =
      FullData.internal (f value) (left.map f) (right.map f)

theorem support_mul_C_le (p : MvPolynomial σ R) (r : R) : (p * C r).support ⊆ p.support

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

lemma runWithOracle_getPutativeRoot {s} (idx : BinaryTree.SkeletonLeafIndex s)
    (leafValue : α) (proof : List α) (f) :
    (runWithOracle f (getPutativeRoot idx leafValue proof))
      =
    getPutativeRoot_with_hash idx leafValue proof fun (left right : α) => (f () ⟨left, right⟩)

lemma sum_of_and_eq_zero_is_or {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n + m = n ||

lemma forwardRange_pred_le_ne_empty (n : ℕ) (r : Fin n) (l : Fin (r.val + 1))
    (h_l_gt_0 : l.val > 0) : forwardRange n r ⟨l.val - 1, by omega⟩ ≠ []

theorem liftContext_completeness
    (h : R.completeness init impl innerRelIn innerRelOut completenessError) :
      (R.liftContext lens).completeness init impl outerRelIn outerRelOut completenessError

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

lemma eq_degree_of_equiv [LawfulBEq R] {p q : UniPoly R} : equiv p q → p.degree = q.degree

lemma Lemma_A_1 {H : F[X][Y]} (β : 𝒪 H) (D : ℕ) (hD : D ≥ Bivariate.totalDegree H)
    (S_β_card : Set.ncard (S_β β) > (weight_Λ_over_𝒪 β D) * H.natDegree) :
  embeddingOf𝒪Into𝕃 _ β = 0

lemma domain_injective {i : ℕ} : i ≤ n → Function.Injective (domain D x n i)

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

@[simp]
theorem oracleReduction_completeness (h : init.neverFails) :
    (oracleReduction oSpec Statement OStatement Witness).perfectCompleteness init impl oRelIn
    (toORelOut oRelIn)

theorem vconcat_inj (v w : Fin n → α) (a b : α) :
    vconcat v a = vconcat w b ↔ v = w ∧ a = b

theorem linsolve_some {A : Matrix (Fin n) (Fin m) F} {b : Fin n → F} {x : Fin m → F}
  (h : linsolve A b = some x)
  : A.mulVec x = b

@[simp]
theorem runWithOracle_bind (f : spec.FunctionType)
    (oa : OracleComp spec α) (ob : α → OracleComp spec β) :
    runWithOracle f (oa >>= ob) =
    (runWithOracle f oa) >>=
    (fun x => runWithOracle f (ob x))

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

theorem foldCommitOracleVerifier_rbrKnowledgeSoundness
    (i : Fin ℓ) (hCR : isCommitmentRound ℓ ϑ i) :
    (foldCommitOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hCR).rbrKnowledgeSoundness
      init impl
      (relIn := roundRelation (mp := mp) 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) i.castSucc)
      (relOut := roundRelation (mp := mp) 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) i.succ)
      (rbrKnowledgeError := fun _ => foldKnowledgeError 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i ⟨1, by rfl⟩
      )

theorem one_le_sub_consecutive_two_pow (n : ℕ): 1 ≤ 2^(n+1) - 2^n

@[simp]
lemma evenize_coeff {f : Polynomial F} {n : ℕ} :
    (evenize f).coeff n = if Even n then f.coeff (n / 2) else 0

lemma bwm_of_pos [NeZero n] (h : j.1 < e) :
  BerlekampWelchMatrix e k ωs f i j = -Rhs j.1 ωs f i

@[simp] theorem rightpad_eq_self (l : List α) (n : Nat) (h : n ≤ l.length) :
    rightpad n unit l = l

@[simp]
protected lemma elocPoly_zero : ElocPoly 0 ωs f p = 1

lemma schwartz_zippel' {p : MvPolynomial σ R} (hp : p ≠ 0) (S : σ → Finset R) :
    #{x ∈ Finset.pi p.vars S | eval (extendDomain x) p = 0} / ∏ i ∈ p.vars, (#(S i) : ℚ≥0)
      ≤ ∑ i ∈ p.vars, (p.degreeOf i / #(S i) : ℚ≥0)

lemma dappend_left_of_lt {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 + n)) (h : i.val < m) :
      dappend (motive := motive) u v i = cast (by simp) (u ⟨i, h⟩)

lemma rtake_eq_rtake : transcript⟦m:⟧ = transcript.drop m h

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)

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

@[csimp, grind =]
theorem idxOf'_eq_idxOf : @idxOf' = @idxOf

lemma folding_steps_pos : (ϑ : ℕ) > 0

@[simp] theorem BitVec.cast_zero {n m : ℕ} (h : n = m) : BitVec.cast h 0 = 0

lemma iterated_fold_transitivity
    (i : Fin r) (steps₁ steps₂ : Fin (ℓ + 1))
    (h_bounds : i.val + steps₁ + steps₂ ≤ ℓ) -- A single, sufficient bounds check
    (f : sDomain 𝔽q β h_ℓ_add_R_rate (i := i) → L)
    (r_challenges₁ : Fin steps₁ → L) (r_challenges₂ : Fin steps₂ → L) :
    -- LHS : The nested fold (folding twice)
    have hi1 : i.val + steps₁ ≤ ℓ := by exact le_of_add_right_le h_bounds
    have hi2 : i.val + steps₂ ≤ ℓ := by
      rw [Nat.add_assoc, Nat.add_comm steps₁ steps₂, ←Nat.add_assoc] at h_bounds
      exact le_of_add_right_le h_bounds
    have hi12 : steps₁ + steps₂ < ℓ + 1 := by
      apply Nat.lt_succ_of_le; rw [Nat.add_assoc] at h_bounds;
      exact Nat.le_of_add_left_le h_bounds
    let lhs := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (i := ⟨i.val + steps₁, by -- ⊢ ↑i + ↑steps₁ < r
        apply Nat.lt_of_le_of_lt (m := ℓ) (hi1) (ℓ_lt_r (h_ℓ_add_R_rate := h_ℓ_add_R_rate))⟩)
      (steps := steps₂)
      (h_i_add_steps := by simp only; apply Nat.lt_add_of_pos_right_of_le; exact h_bounds)
      (f := by
        exact iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i) (steps := steps₁)
          (h_i_add_steps := by apply Nat.lt_add_of_pos_right_of_le; exact hi1) (f := f)
          (r_challenges := r_challenges₁)
      ) r_challenges₂
    let rhs := iterated_fold 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i)
      (steps := ⟨steps₁ + steps₂, hi12⟩)
      (h_i_add_steps := by
        simp only; rw [←Nat.add_assoc]; apply Nat.lt_add_of_pos_right_of_le; exact h_bounds)
      (f := f) (r_challenges := Fin.append r_challenges₁ r_challenges₂)
    lhs = by
      simp only [←Nat.add_assoc] at ⊢ rhs
      exact rhs

theorem monoToLagrangeLevel_lagrangeToMonoLevel_id (v : Vector R (2 ^ n)) (i : Fin n) :
  monoToLagrangeLevel i (lagrangeToMonoLevel i v) = v

@[simp]
theorem snoc_last : snoc s y (Fin.last n) = y

@[simp]
theorem induction_two' {motive : Fin 3 → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin 2, motive i.castSucc → motive i.succ} :
      induction (motive := motive) zero succ (2 : Fin 3) = succ 1 (succ 0 zero)

theorem lagrangeToMonoLevel_monoToLagrangeLevel_id (v : Vector R (2 ^ n)) (i : Fin n) :
  lagrangeToMonoLevel i (monoToLagrangeLevel i v) = v

Fin.is_le in Init.Data.Fin.Lemmas

theorem concrete_mul_eq
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a b : ConcreteBTField k) {a₁ a₀ b₁ b₀ : ConcreteBTField (k - 1)}
  (h_a : (a₁, a₀) = split h_k a) (h_b : (b₁, b₀) = split h_k b) :
  concrete_mul a b =
    《 concrete_mul a₀ b₁ + concrete_mul b₀ a₁ + concrete_mul (concrete_mul a₁ b₁) (Z (k - 1)),
      concrete_mul a₀ b₀ + concrete_mul a₁ b₁ 》

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

@[simp]
theorem drop_zero (v : (i : Fin n) → α i) : drop 0 n.zero_le v = v

private lemma fold_max_lemma {ι : Type} {s : Finset ι} {f : ι → ℕ} {n : ℕ} :
    (∀ i ∈ s, f i ≤ n) → Finset.fold max 0 f s ≤ n

theorem prime_11 : Nat.Prime 11

lemma towerRingHomForwardMap_split_eq (k : ℕ) (h_pos : k > 0) (x : ConcreteBTField k) :
  let p := split (k:=k) (h:=h_pos) x
  towerRingHomForwardMap (k:=k) (x) =
    BinaryTower.join_via_add_smul (k:=k) (h_pos:=h_pos)
      (hi_btf := towerRingHomForwardMap (k:=k-1) (p.1))
      (lo_btf := towerRingHomForwardMap (k:=k-1) (p.2))

theorem add_zero : p + 0 = p

List.le_sum_of_mem in Mathlib.Algebra.Order.BigOperators.Group.List

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 * ((1 - e B 0 / n) ^ 2  + (e B 0) ^ 2 / ((Fintype.card F - 1) * n^2) - 1 + d B/n)
  ≤
  d B/n

@[simp, grind =] lemma R_plus_C_eq_N : sz.R + sz.C = sz.N

lemma rootMultiplicity_some_implies_root {F : Type} [CommSemiring F] [DecidableEq F]
  {x y : F} {f : F[X][Y]} (h : some 0 < (rootMultiplicity (f := f) x y))
  : (f.eval 0).eval 0 = 0

@[simp]
lemma eval₂AlgHom_apply {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 : P) :
    (eval₂AlgHom f g) p = eval₂ f g p

lemma mul_by_2_def {s : Finset ℕ} :
    mul_by_2 s = s.map ⟨fun n => 2 * n, by {
      intro a b
      simp
    }⟩

@[simp]
lemma aeval_X {A : Type w} [CommSemiring A] [Algebra R A] (s : A) : aeval s X (P := P) = s

theorem append_comp' {a : Fin m → α} {b : Fin n → α} (f : α → β)
    (i : Fin (m + n)) : append (f ∘ a) (f ∘ b) i = f (append a b i)

theorem oracleReduction_eq_reduction :
    (oracleReduction R deg D oSpec).toReduction = reduction R deg D oSpec

private lemma oddPart_eq_oddPart' {f : Polynomial F} : oddPart f = oddPart' f

theorem foldOracleVerifier_rbrKnowledgeSoundness (i : Fin ℓ) :
    (foldOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i).rbrKnowledgeSoundness 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)
      (foldKnowledgeError 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)

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)

@[simp]
theorem Z_succ_eq_adjointRoot_root (k : ℕ) : Z (k+1) = AdjoinRoot.root (poly k)

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 eval_solutionToQ {x : F} :
  eval x (solutionToQ e k v) =
  ∑ i ∈ Finset.range (e + k), liftF v (e + i) * x ^ i

@[simp]
lemma length_cons (x : Σ α : Type u, α) (xs : HList) : (x ::ₕ xs).length = xs.length + 1

lemma subUpFull_of_vandermonde_is_vandermonde (h : n ≤ m) :
  Matrix.vandermonde (α ∘ Fin.castLE h) =
  Matrix.subUpFull (nonsquare n α) (Fin.castLE h)

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_lt_ℓ_add_R (i : Fin ℓ)
    : i.val < ℓ + 𝓡

@[simp]
lemma eval₂AlgHom_apply {A : Type w} {B : Type*} [CommSemiring A] [CommSemiring B]
    [PolynomialLike A P] [Algebra R A] [IsScalarTower R A P] [Algebra R B]
    (f : A →ₐ[R] B) (b : B) (p : P) :
    (eval₂AlgHom f b) p = eval₂ f b p

lemma toImpl_toPoly_of_canonical [LawfulBEq R] (p : UniPolyC R) : p.toPoly.toImpl = p

lemma matchSize_size {p q : UniPoly Q} :
    let (p', _) := Array.matchSize p q 0
    p'.size = max p.size q.size

lemma getLowBits_succ {n: ℕ} (numLowBits: ℕ) :
    getLowBits (numLowBits + 1) n = getLowBits numLowBits n
    + (getBit numLowBits n) <<< numLowBits

@[simp]
theorem distFromCode_of_mem (C : Set (n → R)) {u : n → R} (h : u ∈ C) : Δ₀(u, C) = 0

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

@[simp]
lemma length_nil : nil.length = 0

@[csimp]
theorem dappend_eq_addCases : @dappend = @addCases

theorem lagrangeBasis_getElem {w : Vector R n} (i : Fin (2 ^ n)) :
    (lagrangeBasis w)[i] = ∏ j : Fin n, if (BitVec.ofFin i).getLsb j then w[j] else 1 - w[j]

theorem insertNth_zero_eq_cases {n : ℕ} {α : Fin (n + 1) → Sort u} :
    insertNth 0 = cases (motive := α)

@[grind _=_]
lemma degreeX_as_weighted_deg :
  degreeX f = natWeightedDegree f 1 0

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

theorem add_comm (m n : ChurchNat α) : add m n = add n m

@[simp]
theorem eq_refl {α : Type u} (mx : m α) : eq mx mx

@[simp]
lemma getTypes_hcons (x : Σ α : Type u, α) (xs : HList) :
    (x ::ₕ xs).getTypes = x.1 :: xs.getTypes

theorem Nat.Prime_of_isNat : ∀ {n n' : ℕ}, IsNat n n' → n'.Prime → n.Prime

@[grind _=_]
lemma degreeY_as_weighted_deg (hf : f ≠ 0) :
  natDegreeY f = natWeightedDegree f 0 1

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

theorem fconcat₂_injective2 {α₁ : Fin n → A} {α₂ : Fin n → B} {β₁ : A} {β₂ : B} :
    Function.Injective2 (@fconcat₂ A B F₂ n α₁ β₁ α₂ β₂)

@[simp]
lemma natDegree_truncate [φ : NeZero n] : (truncate p n).natDegree < n

theorem hconcat_hcons {α : Sort u} {β : Fin n → Sort u} {γ : Sort u} (a : α) (v : (i : Fin n) → β i) (c : γ) :
    True

theorem vconcat_right_injective (v : Fin n → α) : Function.Injective (vconcat v)

@[simp]
lemma natDegree_solutionToQ :
  (solutionToQ e k v).natDegree ≤ e + k - 1

lemma johnson_condition_strong_iff_johnson_denom_pos {B : Finset (Fin n → F)} {v : Fin n → F} :
  JohnsonConditionStrong B v ↔ 0 < JohnsonDenominator B v

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

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

theorem dcast_eq_root_cast (h : a = a') : dcast h b = _root_.cast (congrArg β h) b

lemma getMiddleBits_eq_mod {n offset len : ℕ} :
  getMiddleBits offset len n = (n >>> offset) % (2 ^ len)

Nat.le_of_succ_le in Init.Data.Nat.Basic

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

@[simp]
lemma aeval_C {A : Type w} [CommSemiring A] [Algebra R A] (x : A) (r : R) :
    (aeval x) (C r : P) = algebraMap R A r

lemma deevenize_comp_x_squared {f : Polynomial F} (hEven : EvenPoly f) :
    (deevenize f).comp (Polynomial.X * Polynomial.X) = f

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₂

theorem changeOfBasisMatrix_det_ne_zero
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  (changeOfBasisMatrix 𝔽q β ℓ h_ℓ).det ≠ 0

theorem sub_add_eq_sub_sub_rev (a b c : Nat) (h1 : c ≤ b) (h2 : b ≤ a) :
  a - b + c = a - (b - c)

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 [Fintype F] in
private lemma hamming_weight_eq_sum [Zero F] {x : Fin n → F}
  :
  ‖x‖₀ = ∑ i, if x i = 0 then 0 else 1

theorem fconcat_inj {α : Fin n → A} {β : A}
    (v₁ v₂ : (i : Fin n) → F (α i)) (a₁ a₂ : F β) :
    fconcat v₁ a₁ = fconcat v₂ a₂ ↔ v₁ = v₂ ∧ a₁ = a₂

@[simp]
theorem dflatten_embedSum {m : ℕ} {n : Fin m → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    (v : (i : Fin m) → (j : Fin (n i)) → motive (embedSum i j)) (i : Fin m) (j : Fin (n i)) :
    dflatten (motive := motive) v (embedSum i j) = v i j

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

lemma fieldSize_sub_one_factorization : fieldSize - 1 = 2 ^ twoAdicity * 127

@[simp]
theorem dflatten_one {n : Fin 1 → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    {v : (i : Fin 1) → (j : Fin (n i)) → motive (embedSum i j)} :
    dflatten (motive := motive) v = v 0

List.length_drop in Init.Data.List.TakeDrop

@[simp, grind] lemma absorbPos_lt_N (sponge : DuplexSponge U C) :
    sponge.absorbPos < SpongeSize.N

theorem vcons_eq_const (a : α) : a ::ᵛ (fun _ : Fin n => a) = fun _ => a

@[simp] lemma mod_two_eq_zero (m : ℤ) : m % 2 = ( - m) % 2

@[simp]
theorem rightpad_apply_ge (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : m ≤ i.val) : rightpad n a v i = a

theorem succ'_injective : Function.Injective (succ' : Nat → Nat)

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

@[simp]
theorem fappend_right {α : Fin m → A} {β : Fin n → A}
    (u : (i : Fin m) → F (α i)) (v : (i : Fin n) → F (β i)) (i : Fin n) :
    fappend u v (natAdd m i) = cast (by simp [vappend_right]) (v i)

lemma distToCode_of_nonempty {α : Type*} [LinearOrder α] [Zero α]
                             {ι F : Type*}
                             {w : ι → F} {C : Set (ι → F)}
                             {δf : (ι → F) → (ι → F) → α}
                             (h₁ : (possibleDistsToCode w C δf).Finite)
                             (h₂ : (possibleDistsToCode w C δf).Nonempty) :
  haveI := @Fintype.ofFinite _ h₁
  distToCode w C δf h₁ = .some ((possibleDistsToCode w C δf).toFinset.min' (by simpa))

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

theorem support_C_mul_le (p : MvPolynomial σ R) (r : R) : (C r * p).support ⊆ p.support

@[simp]
theorem verifier_rbrKnowledgeSoundness (hRel : ∀ stmtIn witOut,
      (mapStmt stmtIn, witOut) ∈ relOut → (stmtIn, mapWitInv stmtIn witOut) ∈ relIn) :
    (verifier oSpec mapStmt).rbrKnowledgeSoundness init impl relIn relOut 0

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

lemma getBit_eq_succ_getBit_of_mul_two_add_one {n k : ℕ} : getBit (k+1) (2*n + 1) = getBit k n

omit [Fintype L] [DecidableEq L] in
theorem Polynomial.comp_same_inner_eq_if_same_outer (f g : L[X]) (h_f_eq_g : f = g) :
  ∀ x, f.comp x = g.comp x

lemma approximate_solution_is_exact_solution_coeffs'
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
    γ' x₀ (R k δ x₀ h_gs) (irreducible_H k h_gs) =
        PowerSeries.mk (fun t =>
          if t ≥ k
          then (0 : AppendixA.𝕃 (H k δ x₀ h_gs))
          else PowerSeries.coeff _ t
            (γ' 
              x₀
              (R k (x₀ := x₀) (δ := δ) h_gs)
              (irreducible_H k h_gs)))

theorem eq_join_via_add_smul_eq_iff_split (k : ℕ) (h_pos : k > 0)
    (x : BTField k) (hi_btf lo_btf : BTField (k - 1)) :
    x = ⋘ hi_btf, lo_btf ⋙ ↔
  split (k:=k) (h_k:=h_pos) x = (hi_btf, lo_btf)

theorem LeafData.composeBuild_leaf {α} (a : α)
    (compose : α → α → α) :
    (LeafData.leaf a).composeBuild compose = FullData.leaf a

theorem BitVec.extractLsb_concat_hi {hi_size lo_size : ℕ} (hi : BitVec hi_size)
  (lo : BitVec lo_size) (h_hi : hi_size > 0) :
  BitVec.extractLsb (hi:=hi_size + lo_size - 1) (lo:=lo_size)
  (BitVec.append (msbs:=hi) (lsbs:=lo)) = dcast (by
    rw [←Nat.sub_add_comm (by omega), Nat.sub_add_cancel (by omega), Nat.add_sub_cancel]
  ) hi

@[simp]
theorem dcons_succ {motive : Fin (n + 1) → Sort u} (a : motive 0)
    (v : (i : Fin n) → motive i.succ) (i : Fin n) : (a ::ᵈ⟨motive⟩ v) i.succ = v i

@[simp] theorem popWhile_nil_or_last_false (p : α → Bool) (as : Array α)
    (h : (as.popWhile p).size > 0) : ¬ (p <| (as.popWhile p).getLast h)

@[simp]
theorem reduction_completeness (h : init.neverFails) :
    (reduction oSpec Statement Witness).perfectCompleteness init impl relIn (toRelOut relIn)

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 degree_bound_bivariate
  (qPoly : Polynomial F)
  (hdeg_q_min : qPoly.natDegree > 0)
  (hdeg_q_max : qPoly.natDegree < Fintype.card F)
  {t : ℕ} (Q : MvPolynomial (Fin 2) F)
  (hdegX : MvPolynomial.degreeOf 0 Q < t)
  (hdegY : MvPolynomial.degreeOf 1 Q < qPoly.natDegree) :
  (MvPolynomial.eval₂Hom (Polynomial.C : F →+* Polynomial F)
      (fun i : Fin 2 => if i = 0 then qPoly else Polynomial.X) Q).natDegree < t * qPoly.natDegree

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₂

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma ℓ_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r}
    : ℓ < r

theorem correlatedAgreement_affine_curves [DecidableEq ι] {k : ℕ} {u : Fin k → ι → F}
  {deg : ℕ} {domain : ι ↪ F} {δ : ℝ≥0}
  (hδ : δ ≤ 1 - ReedSolomonCode.sqrtRate deg domain)
  (hproximity :
    Pr_{let y ← $ᵖ (Curve.parametrisedCurveFinite u)}[
      Code.relHammingDistToCode y.1 (ReedSolomon.code domain deg) ≤ δ
    ] >
      k * (errorBound δ deg domain)) :
  correlatedAgreement (ReedSolomon.code domain deg) δ u

Nat.mul_le_mul_right in Init.Data.Nat.Basic

theorem findIdxRev?_eq_none {cond} {as : Array α} (h : ∀ i, (hi : i < as.size) → ¬ cond as[i]) :
  findIdxRev? cond as = none

lemma concrete_div_eq_mul_inv {k : ℕ} (a b : ConcreteBTField k) : a / b = a * (concrete_inv b)

private lemma Bi_biUnion_F2i :
  Bi B i = Finset.univ.biUnion (F2i B i)

@[simp]
theorem FullData.toLeafData_internal {α} {s_left s_right : Skeleton}
    (value : α) (left : FullData α s_left) (right : FullData α s_right) :
    (FullData.internal value left right).toLeafData =
      LeafData.internal (left.toLeafData) (right.toLeafData)

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

theorem vcons_injective2 : Function.Injective2 (@vcons α n)

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)

@[simp]
theorem distFromCode_of_empty (u : n → R) : Δ₀(u, (∅ : Set (n → R))) = ⊤

lemma getBit_zero_eq_self {n : ℕ} (h_n : n < 2) : getBit 0 n = n

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 generateProof_ofRight {sleft sright : Skeleton}
    (cache_tree : FullData α (Skeleton.internal sleft sright))
    (idxRight : SkeletonLeafIndex sright) :
    generateProof cache_tree (BinaryTree.SkeletonLeafIndex.ofRight idxRight) =
      (cache_tree.leftSubtree).getRootValue ::
        (generateProof cache_tree.rightSubtree idxRight)

theorem hcons_eq_cons {β : Fin n → Sort u} (a : α) (v : (i : Fin n) → β i) :
    hcons a v = cons (α := vcons α β) (hcons a v 0) (fun i => hcons a v i.succ)

theorem BTField.PowerBasis_cast_dest_eq (k n m : ℕ) (h_k_le_n : k ≤ n)
  (h_k_le_m : k ≤ m) (h_eq : m = n) :
  letI instLeftAlgebra := binaryAlgebraTower (l:=k) (r:=m) (h_le:=h_k_le_m)
  letI instRightAlgebra := binaryAlgebraTower (l:=k) (r:=n) (h_le:=h_k_le_n)
  @PowerBasis (BTField k) (BTField m) _ _ instLeftAlgebra =
  @PowerBasis (BTField k) (BTField n) _ _ instRightAlgebra

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

theorem cast_injective : Function.Injective (ChallengeIdx.cast hn hSpec)

@[simp]
lemma ofPolynomialAlgHom_toPolynomialAlgHom_C {r : R} :
    ofPolynomialAlgHom (toPolynomialAlgHom (C r : P)) = (Polynomial.C r : R[X])

@[simp]
theorem cast_val {m n : ℕ} (h : m = n) (a : Fin m) : (Fin.cast h a).val = a.val

private lemma almost_johnson [Zero F]
  (h_n : 0 < n)
  (h_B : 2 ≤ B.card)
  (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)))
  ≤
  choose_2 B.card * (n - d B)

@[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 (1 : Fin 2) = succ 0 zero

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)

theorem linearIndependent_fin2' {f : Fin 2 → V} :
    LinearIndependent K f ↔ f 0 ≠ 0 ∧ ∀ a : K, a • f 0 ≠ f 1

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)

@[simp] lemma toMvPolynomialAlgHom_X (s : σ) :
    toMvPolynomialAlgHom (X s : P) = (MvPolynomial.X s : MvPolynomial σ R)

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

@[simp]
theorem insertNth_apply_succAbove : insertNth p y s (p.succAbove i) = s i

lemma getBit_of_highBits {n: ℕ} (numLowBits : ℕ) : ∀ k, getBit k (getHighBits numLowBits n) =
    if k < numLowBits then 0 else getBit (k) (n)

theorem knowledgeSoundness_implies_soundness (relIn : Set (StmtIn × WitIn))
    (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (knowledgeError : ℝ≥0) (hLt : knowledgeError < 1) :
      knowledgeSoundness init impl relIn relOut verifier knowledgeError →
        soundness init impl relIn.language relOut.language verifier knowledgeError

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

lemma one_bitvec_shiftRight {d : ℕ} (h_d : d > 0) : 1 >>> d = 0

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]
lemma liftF'_liftF_eq : liftF' (liftF f') = f'

lemma add_comm {k : ℕ} (a b : ConcreteBTField k) : a + b = b + a

theorem dext_iff {α : Fin n → Sort u} {v w : (i : Fin n) → α i} :
    v = w ↔ ∀ i, v i = w i

theorem singleEqPolynomial_symm (r : R) (s : R) :
    (singleEqPolynomial r (C s) : MvPolynomial σ R) = singleEqPolynomial s (C r)

theorem canonical_nonempty_iff [LawfulBEq R] {p : UniPoly R} (hp : p.size > 0) :
  p.trim = p ↔ p.last_nonzero = some ⟨ p.size - 1, Nat.pred_lt_self hp ⟩

omit [Finite F] in
private lemma op_der_eq : Monoid.toMulAction Fˣ = Units.mulAction'

lemma forwardRange_succ_right_ne_empty (n : ℕ) (r : Fin (n - 1)) (l : Fin (r.val + 1)) :
  forwardRange n ⟨r + 1, by omega⟩ ⟨l, by simp only; omega⟩ ≠ []

lemma concrete_mul_one0 (a : ConcreteBTField 0) :
  concrete_mul a (one (k:=0)) = a

lemma getBit_of_lowBits {n: ℕ} (numLowBits : ℕ) : ∀ k, getBit k (getLowBits numLowBits n) =
    if k < numLowBits then getBit k n else 0

theorem append_soundness (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ 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₂)

lemma mca_rsc
  [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ℓ
  hasMutualCorrAgreement
    -- Generator
    Gen
    -- BStar
    ((1 + Gen.rate) / 2)
    -- errStar
    (fun δ => ENNReal.ofReal
        ((Fintype.card parℓ_type - 1) * (2^m / (Gen.rate * (Fintype.card F)))))

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

omit hF₂ in
theorem normalizedW_is_additive (i : Fin r) :
  IsLinearMap 𝔽q (f := fun x ↦ (normalizedW 𝔽q β i).eval x)

@[simp]
theorem fappend_zero {β : Fin m → A} {α : Fin 0 → A}
    (u : (i : Fin m) → F (β i)) :
    fappend u (!h⦃F⦄⟨α⟩[] : (i : Fin 0) → F (α i)) = u

@[simp]
lemma mul_by_empty :
    mul_by_2 ∅ = ∅

theorem ScalarField_is_prime : Nat.Prime scalarFieldSize

@[simp, grind] lemma fin_chunkSize_lt_N (arrSize : Nat) (i : Fin (min arrSize SpongeSize.R)) :
    i < SpongeSize.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)

@[simp]
lemma solutionToE_zero_eq_C {v : Fin (2 * 0 + k) → F} :
  solutionToE 0 k v = C (1 : F)

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

theorem eq_of_lt_dist {C : Set (n → R)} {u v : n → R} (hu : u ∈ C) (hv : v ∈ C)
    (huv : Δ₀(u, v) < ‖C‖₀) : u = v

@[simp]
lemma challengeOracleInterface_append_domain_inl (j : pSpec₁.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.domain (.inl j) = Unit

@[simp]
lemma natDegree_polynomialOfCoeffs_deg_lt_deg
  [NeZero deg] {coeffs : Fin deg → F} :
  (polynomialOfCoeffs coeffs).natDegree < deg

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 hconcat_eq_snoc {α : Fin n → Sort u} {β : Sort u} (v : (i : Fin n) → α i) (b : β) :
    hconcat v b = snoc (α := vconcat α β)
      (fun i => cast (vconcat_castSucc _ _ i).symm (v i))
      (cast (vconcat_last _ _).symm b)

theorem eq_zero_or_eq_one {a : ConcreteBTField 0} : a = zero ∨ a = one

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

theorem GF_2_card : Fintype.card (GF(2)) = 2^(2^0)

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

@[simp]
theorem cast_perfectCompleteness (hComplete : R.perfectCompleteness init impl relIn relOut) :
    (R.cast hn hSpec).perfectCompleteness init impl relIn relOut

private lemma sum_hamming_weight_sum [Zero F]
  :
  ∑ x ∈ B, (‖x‖₀ : ℚ) = n * B.card - ∑ i, K B i 0

theorem eval_comp_eval_C_finSuccEquiv (p : R[X (Fin (n + 1))]) (y : Fin n → R) (x : R) :
    eval y (Polynomial.eval (C x) (finSuccEquiv R n p)) = eval (Fin.cons x y) p

@[simp] theorem toNat_mul (a b : AssocNat) : toNat (mul a b) = toNat a * toNat b

theorem towerEquiv_commutes_left (i j : ℕ) (h : i ≤ j) : ∀ r : ConcreteBTField i,
  (AlgebraTower.algebraMap i j h) ((towerEquiv i).ringEquiv r) =
  (towerEquiv j).ringEquiv ((AlgebraTower.algebraMap i j h) r)

@[simp]
theorem fconcat₂_castSucc {α₁ : Fin n → A} {α₂ : Fin n → B} {β₁ : A} {β₂ : B}
    (v : (i : Fin n) → F₂ (α₁ i) (α₂ i)) (a : F₂ β₁ β₂) (i : Fin n) :
    fconcat₂ (F := F₂) v a (castSucc i) =
      cast (by simp [vconcat_castSucc]) (v i)

theorem join_add_join {k : ℕ} (h_pos : k > 0) (hi₀ lo₀ hi₁ lo₁ : ConcreteBTField (k - 1)) :
  《 hi₀, lo₀ 》 + 《 hi₁, lo₁ 》 = 《 hi₀ + hi₁, lo₀ + lo₁ 》

theorem insertNth_ne_zero_iff : insertNth p y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0

@[simp]
theorem cast_toVerifier (V : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec₁) :
    (OracleVerifier.cast hn hSpec hOₘ V).toVerifier = Verifier.cast hn hSpec V.toVerifier

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)

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)

lemma forwardRange_0_eq_finRange (n : ℕ) [NeZero n] : forwardRange n ⟨n - 1, by
    have h_ne

@[simp, grind =]
theorem monomialXY_add {n m : ℕ} {a b : F} :
  monomialXY n m (a + b) = monomialXY n m a + monomialXY n m b

@[simp]
lemma polynomialOfCoeffs_eq_zero :
  polynomialOfCoeffs coeffs = 0 ↔ ∀ (x : ℕ) (h : x < deg), coeffs ⟨x, h⟩ = 0

theorem eval_zeroOne_eq_MLE_toEvalsZeroOne (p : MvPolynomial σ R) (x : σ → Fin 2) :
    eval (x : σ → R) p = eval (x : σ → R) (MLE p.toEvalsZeroOne)

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)

@[simp]
theorem runWithOracle_pure (f : spec.FunctionType) (a : α) :
    runWithOracle f (pure a) = some a

lemma divide_by_2_def {s : Finset ℕ} :
    divide_by_2 s = (erase_odd s).image (fun n => n / 2)

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

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 dappend_right_of_not_lt {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 + n)) (h : ¬ i.val < m) :
      dappend (motive := motive) u v i = dcast (by ext; simp; omega) (v ⟨i - m, by omega⟩)

@[simp]
theorem add_accepts_iff : (add a b c).accepts x ↔ x c = x a + x b

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

@[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 support_finSuccEquivNth_nonempty {f : MvPolynomial (Fin (n + 1)) R} (h : f ≠ 0) :
    (finSuccEquivNth R p f).support.Nonempty

@[simp]
lemma degree_polynomialOfCoeffs_deg_lt_deg :
  (polynomialOfCoeffs coeffs).degree < deg

@[simp]
theorem dcast₂_eq' (h : a = a) (h' : dcast h b = b) : dcast₂ h h' c = c

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

@[simp]
theorem OracleReduction.id_run (stmt : StmtIn) (oStmt : ∀ i, OStmtIn i) (wit : WitIn) :
    (OracleReduction.id : OracleReduction oSpec StmtIn OStmtIn WitIn _ _ _ _).run stmt oStmt wit =
      pure ⟨⟨default, ⟨stmt, oStmt⟩, wit⟩, ⟨stmt, oStmt⟩⟩

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

@[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⟩, [], []⟩

@[simp]
theorem minPoly_of_powerBasisSucc_generator (k : ℕ) :
  (minpoly (ConcreteBTField k) (powerBasisSucc k).gen) = X^2 + (Z k) • X + 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

@[simp]
theorem cast_idx_symm {i : MessageIdx pSpec₂} :
    pSpec₁.Message (i.cast hn.symm (cast_symm hSpec)) = pSpec₂.Message i

lemma bIdx_succ_mul_ϑ_le_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) : (↑bIdx + 1) * ϑ ≤ ℓ + 1

lemma join_zero_zero {k : ℕ} (h_k : k > 0) :
  《 zero (k:=k - 1), zero (k:=k - 1) 》 = zero (k:=k)

theorem matchSize_comm (l₁ : List α) (l₂ : List α) (unit : α) :
    matchSize l₁ l₂ unit = (matchSize l₂ l₁ unit).swap

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

@[simp]
lemma halfNumFullRounds_mul_2_eq_numFullRounds :
    params.halfNumFullRounds * 2 = params.numFullRounds

@[simp]
theorem acceptRejectOracleRel_language :
    acceptRejectOracleRel.language = { (true, isEmptyElim) }

lemma concrete_one_mul
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul (one (k:=k)) a = a

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)

theorem seqCompose_soundness
    (lang : (i : Fin (m + 1)) → Set (Stmt i × ∀ j, OStmt i j))
    (V : (i : Fin m) →
      OracleVerifier oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Stmt i.succ) (OStmt i.succ)
        (pSpec i))
    (soundnessError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).soundness init impl (lang i.castSucc) (lang i.succ) (soundnessError i)) :
      (OracleVerifier.seqCompose Stmt OStmt V).soundness init impl (lang 0) (lang (Fin.last m))
        (∑ i, soundnessError i)

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

theorem dcast₃_dcast₂ : dcast₃ rfl rfl rfl d = dcast₂ dcast_eq.symm dcast₂_dcast.symm d

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)

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'

lemma towerAlgebraMap_id (k : ℕ) : towerAlgebraMap (h_le:=by omega) = RingHom.id (BTField k)

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]
lemma seqCompose_zero
    (Stmt : Fin 1 → Type)
    {ιₛ : Fin 1 → Type} (OStmt : (i : Fin 1) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    (Wit : Fin 1 → Type)
    {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (R : (i : Fin 0) →
      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 =
      @OracleReduction.id ι oSpec (Stmt 0) (ιₛ 0) (OStmt 0) (Wit 0) (Oₛ 0)

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)

Nat.lt_of_le_of_lt in Init.Prelude

Fin.coe_castSucc in Init.Data.Fin.Lemmas

lemma aeval_apply {A : Type w} [CommSemiring A] [Algebra R A] (s : A) :
    aeval (P := P) s = eval₂AlgHom (Algebra.ofId R A) s

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

@[simp]
lemma erase_odd_empty :
    erase_odd ∅ = ∅

lemma neverFails_map_iff' (oa : OracleComp spec α) (f : α → β) :
    neverFails (f <$> oa) ↔ neverFails oa

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

lemma oracle_block_k_next_le (i : Fin (ℓ + 1)) (j : Fin (toOutCodewordsCount ℓ ϑ i))
    (hj : j.val + 1 < toOutCodewordsCount ℓ ϑ i) : j.val * ϑ + ϑ ≤ i

omit [NeZero ℓ] in
lemma fin_ℓ_steps_lt_ℓ_add_R (i : Fin ℓ) (steps : ℕ) (h : i.val + steps ≤ ℓ)
    : i.val + steps < ℓ + 𝓡

theorem foldl_eq_toList_foldl {α β} {n : ℕ} (f : β → α → β) (init : β) (v : Vector α n) :
  v.foldl (f:=f) (b:=init) = v.toList.foldl (f:=f) (init:=init)

lemma concrete_mul_inv_cancel
  (prevBTFieldResult : ConcreteBTFStepResult (k := k - 1))
  (a : ConcreteBTField k) (h : a ≠ 0) :
  concrete_mul a (concrete_inv a) = one

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

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

@[simp]
lemma not_P_to_V_eq_V_to_P {x : Direction} (h : x ≠ .V_to_P) : x = .P_to_V

lemma eqRec_fun_eqRec_sort_eq_self {α : Sort*} {β : α → Sort u} {a a' : α}
    (h : a = a') (h' : β a = β a') (b : β a) :
  b = h ▸ h' ▸ b

Nat.zero_add in Init.Data.Nat.Basic

theorem non_zero_divisors_iff (M₀ : Type*) [Mul M₀] [Zero M₀] :
    NoZeroDivisors M₀ ↔ ∀ {a b : M₀}, a * b = 0 → a = 0 ∨ b = 0

lemma addSalt_Message (i : pSpec.MessageIdx) :
    (pSpec.addSalt Salt).Message i = (pSpec.Message i × Salt i)

@[simp]
theorem splitSum_succ {n : Fin (m + 1) → ℕ} {k : Fin (vsum n)} :
    splitSum k = Fin.dappend
      (fun k => ⟨0, k⟩)
      (fun k => ⟨(splitSum k).1.succ, (splitSum k).2⟩)
      k

theorem BaseField_is_prime : Nat.Prime baseFieldSize

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R deg D oSpec).perfectCompleteness init impl
      (inputRelation R deg D) (outputRelation R deg)

theorem append_rbrKnowledgeSoundness (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ pSpec₂)
    {rbrKnowledgeError₁ : pSpec₁.ChallengeIdx → ℝ≥0}
    {rbrKnowledgeError₂ : pSpec₂.ChallengeIdx → ℝ≥0}
    (h₁ : V₁.rbrKnowledgeSoundness init impl rel₁ rel₂ rbrKnowledgeError₁)
    (h₂ : V₂.rbrKnowledgeSoundness init impl rel₂ rel₃ rbrKnowledgeError₂) :
      (V₁.append V₂).rbrKnowledgeSoundness init impl rel₁ rel₃
        (Sum.elim rbrKnowledgeError₁ rbrKnowledgeError₂ ∘ ChallengeIdx.sumEquiv.symm)

theorem hcons_left_injective {α : Sort u} {β : Fin n → Sort u} (b : (i : Fin n) → β i) :
    Function.Injective (fun (a : α) => hcons a b)

theorem decoder_mem_impl_dist
  {k r D e : ℕ}
  (h_e : e ≤ n - Real.sqrt (k * n))
  {ωs : Fin n ↪ F}
  {f : Fin n → F}
  {p : F[X]}
  (h_in : p ∈ decoder k r D e ωs f)
  :
  Δ₀(f, p.eval ∘ ωs) ≤ e

theorem evalNormalizedWAt_eq_normalizedW (i : Fin r) (x : L) :
  evalNormalizedWAt (β := β) (ℓ := ℓ) (R_rate := R_rate) (i := i) x
    = (normalizedW (𝔽q := 𝔽q) (β := β) (i := i)).eval x

lemma getBit_of_two_pow_sub_one {i k: ℕ} : getBit k (2^i - 1) =
    if k < i then 1 else 0

lemma evenPart_even {f : Polynomial F} :
    EvenPoly (evenPart f)

lemma oddPart_def :
  oddPart f =
  C (2⁻¹ : F) * (f - f.comp (-X)) /ₘ X

@[simp]
lemma seqCompose_zero (Stmt : Fin 1 → Type)
    {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (V : (i : Fin 0) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i)) :
    seqCompose Stmt V = Verifier.id

@[simp] lemma drop_dir : pSpec⟦m:⟧.dir = pSpec.dir⟦m:⟧

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

@[simp]
theorem vflatten_embedSum {m : ℕ} {n : Fin m → ℕ} (v : (i : Fin m) → Fin (n i) → α) (i : Fin m)
    (j : Fin (n i)) : vflatten v (embedSum i j) = v i j

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 δ

lemma eq_zero_or_eq_one_of_lt_two {n : ℕ} (h_lt : n < 2) : n = 0 ∨ n = 1

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

@[simp]
theorem Reduction.id_perfectCompleteness {rel : Set (StmtIn × WitIn)} (hInit : init.neverFails) :
    (Reduction.id : Reduction oSpec _ _ _ _ _).perfectCompleteness init impl rel rel

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

private lemma evenPart_eq_evenPart' {f : Polynomial F} : evenPart f = evenPart' f

lemma one_bitvec_toNat {width : ℕ} (h_width : width > 0) : (1#width).toNat = 1

@[simp]
theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction oSpec Statement Witness).perfectCompleteness init impl rel rel

@[simp]
theorem cast_perfectCompleteness (hComplete : R.perfectCompleteness init impl relIn relOut) :
    (R.cast hn hSpec hOₘ).perfectCompleteness init impl relIn relOut

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₁

Fin.isLt in Init.Prelude

theorem monomialBasis_getElem {w : Vector R n} (i : Fin (2 ^ n)) :
    (monomialBasis w)[i] = ∏ j : Fin n, if (BitVec.ofFin i).getLsb j then w[j] else 1

omit [SelectableType R] in
@[simp]
lemma reduction_verifier_eq_verifier :
    (reduction R deg D n oSpec).verifier = verifier R deg D n oSpec

theorem one_mul (n : ChurchNat α) : mul one n = n

lemma concrete_zero_mul
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul (zero (k:=k)) a = zero (k:=k)

lemma sum_insertNth [AddCommMonoid M] {n : ℕ} (σ : Fin n →₀ M) (i : M) (p : Fin (n + 1)) :
    (insertNth p i σ).sum (fun _ e ↦ e) = i + σ.sum (fun _ e ↦ e)

theorem append_left_injective (b : Fin n → α) : Function.Injective (@Fin.append m n α · b)

@[simp]
theorem generateProof_leaf (a : α) (idx) :
    generateProof (FullData.leaf a) idx = []

@[csimp]
theorem dcons_eq_cons : @dcons = @cons

theorem Nat.shiftRight_eq_sub_mod_then_div_two_pow {n lo_len : ℕ} :
  n >>> lo_len = (n - n % 2 ^ lo_len) / 2 ^ lo_len

lemma eq_iff_eq_all_getBits {n m : ℕ} : n = m ↔ ∀ k, getBit k n = getBit k m

private lemma cast_eq_cast_same_type {α β : Sort u} (h1 h2 : α = β) {x y : α}
    (h : cast h1 x = cast h2 y) : x = y

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 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]
theorem vcons_zero (a : α) (v : Fin n → α) : (a ::ᵛ v) 0 = a

theorem cast_eq_dcast₂ {hn} {hSpec : pSpec₁.cast hn = pSpec₂} {i : ChallengeIdx pSpec₁}:
    i.cast hn hSpec = dcast₂ hn hSpec i

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)

@[simp, grind =]
theorem monomialXY_eq_zero_iff {n m : ℕ} {a : F} : monomialXY n m a = 0 ↔ a = 0

theorem BitVec.extractLsb_concat_lo {hi_size lo_size : ℕ} (hi : BitVec hi_size)
  (lo : BitVec lo_size) (h_lo : lo_size > 0) : BitVec.extractLsb (hi:=lo_size - 1) (lo:=0)
  (BitVec.append (msbs:=hi) (lsbs:=lo)) = dcast (by
    rw [←Nat.sub_add_comm (h:=by omega), Nat.sub_add_cancel (h:=by omega), Nat.sub_zero]
  ) lo

theorem intermediateNormVpoly_comp_qmap_helper (i : Fin (ℓ))
    (k : Fin (ℓ - (↑i + 1))) :
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate
      ⟨↑i + 1, by omega⟩ (k:=⟨k, by simp only; omega⟩)).comp (qMap 𝔽q β ⟨↑i, by omega⟩) =
    intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate
      ⟨↑i, by omega⟩ ⟨k + 1, by simp only; omega⟩

@[simp]
theorem Basis_cast_index_apply {α β i j : ℕ} {k : Fin j}
    (h_le : α ≤ β) (h_eq : i = j)
    {b : @Basis (Fin (i)) (ConcreteBTField α) (ConcreteBTField β) _ _
      (@ConcreteBTFieldAlgebra (l := α) (r := β) (h_le := h_le)).toModule} :
  let castBasis : @Basis (Fin j) (ConcreteBTField α) (ConcreteBTField β) _ _
    (@ConcreteBTFieldAlgebra (l:=α) (r:=β) (h_le:=h_le)).toModule :=
    cast (by exact Basis_cast_index_eq i j α β h_le h_eq) b
  (castBasis k) = b (Fin.cast (h_eq.symm) k)

omit [NeZero ϑ] hdiv in
lemma toOutCodewordsCountOf0 : toOutCodewordsCount ℓ ϑ 0 = 1

@[simp]
theorem dcast₂_eq : dcast₂ (Eq.refl a) dcast_eq c = c

lemma join_via_add_smul_one_zero_eq_Z {k : ℕ} (h_pos : k > 0) :
  ⋘ 1, 0 ⋙ = Z k

lemma getBit_of_middleBits {n offset len k : ℕ} :
  getBit k (getMiddleBits offset len n) =
    if k < len then getBit (k + offset) n else 0

@[simp]
theorem append_right_cancel_iff {pSpec : ProtocolSpec m} {p1 p2 : ProtocolSpec n} :
    pSpec ++ₚ p1 = pSpec ++ₚ p2 ↔ p1 = p2

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

theorem vconcat_vcons_eq_vcons_vconcat (a : α) (v : Fin n → α) (b : α) :
    vconcat (a ::ᵛ v) b = a ::ᵛ (vconcat v b)

lemma eqRec_fun_eq_eqRec_sort {α : Sort*} {β : α → Sort u} {a a' : α}
    (h : a = a') (h' : β a = β a') (b : β a) :
  h ▸ b = h' ▸ b

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

lemma sub_descends [LawfulBEq R] (a₁ b₁ a₂ b₂ : UniPoly R) :
  equiv a₁ a₂ → equiv b₁ b₂ → sub_descending a₁ b₁ = sub_descending a₂ b₂

@[simp]
theorem removeNth_update : removeNth p (update s p y) = removeNth p s

@[simp]
theorem OracleReduction.id_perfectCompleteness
    {rel : Set ((StmtIn × ∀ i, OStmtIn i) × WitIn)}
    (hInit : init.neverFails) :
    (OracleReduction.id : OracleReduction oSpec _ _ _ _ _ _ _).perfectCompleteness
      init impl rel rel

lemma bIdx_succ_mul_ϑ_lt_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) :
    (↑bIdx + 1) * ϑ < ℓ + 1

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 》

protected lemma johnson_bound_lemma [Field F] {v : Fin n → 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 v / n)) ^ 2
      - (1 - ((Fintype.card F : ℚ) / (Fintype.card F - 1)) * (d B/n)))  ≤
  ((Fintype.card F : ℚ) / (Fintype.card F - 1)) * d B/n

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

@[simp]
theorem snoc_take {pSpec : ProtocolSpec n} (k : ℕ) (h : k < n) :
    (pSpec.take k (Nat.le_of_succ_le h) ++ₚ ⟨![pSpec.dir ⟨k, h⟩], ![pSpec.Type ⟨k, h⟩]⟩)
      = pSpec.take (k + 1) h

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 getLastI_append_single [Inhabited α] (x : α) : (l ++ [x]).getLastI = x

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

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

theorem eq_symm {α : Type u} (mx my : m α) : eq mx my → eq my mx

@[simp]
theorem Prover.run_of_prover_first [ProverOnly pSpec] (stmt : StmtIn) (wit : WitIn)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      prover.run stmt wit = (do
        let state := prover.input (stmt, wit)
        let ⟨msg, state⟩ ← liftComp (prover.sendMessage ⟨0, by simp⟩ state) _
        let ctxOut ← prover.output state
        return ((fun i => match i with | ⟨0, _⟩ => msg), ctxOut))

Nat.zero_le in Init.Prelude

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]

Fin.is_le' in Init.Data.Fin.Lemmas

Nat.le_add_left in Init.Data.Nat.Basic

lemma concentration_bounds {deg : ℕ} {domain : ι ↪ F}
  {U : AffineSubspace F (ι → F)} [Nonempty U]
  (hdiv_pos : 0 < (divergence U (RScodeSet domain deg) : ℝ≥0))
  (hdiv_lt : (divergence U (RScodeSet domain deg) : ℝ≥0) < 1 - ReedSolomonCode.sqrtRate deg domain)
  : let δ' := divergence U (RScodeSet domain deg)
    Pr_{let u ← $ᵖ U}[Code.relHammingDistToCode u (RScodeSet domain deg) ≠ δ']
    ≤ errorBound δ' deg domain

@[simp]
theorem card_univ_filter_eq {e : α} :
  #{x : α | x ≠ e} = #(Finset.univ (α := α)) - 1

lemma E_and_Q_unique
  [NeZero n]
  {e k : ℕ}
  {E Q E' Q' : Polynomial F}
  {ωs f : Fin n → F}
  (he : 2 * e < n - k + 1)
  (hk_n : k ≤ n)
  (h_Q : Q ≠ 0)
  (h_Q' : Q' ≠ 0)
  (h_inj : Function.Injective ωs)
  (h_bw₁ : BerlekampWelchCondition e k ωs f E Q)
  (h_bw₂ : BerlekampWelchCondition e k ωs f E' Q')
: E * Q' = E' * Q

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⟩

theorem monomialToNovel_novelToMonomial_inverse
  (ℓ : ℕ) (h_ℓ : ℓ ≤ r) :
  ∀ coeffs : Fin (2^ℓ) → L,
    novelToMonomialCoeffs 𝔽q β ℓ h_ℓ
    (monomialToNovelCoeffs 𝔽q β ℓ h_ℓ coeffs) = coeffs

lemma twoAdicGenerator_unit_mem_rootsOfUnity
    (bits : Fin (twoAdicity + 1)) (h : twoAdicGenerators[bits] ≠ 0) :
    Units.mk0 (twoAdicGenerators[bits]) h ∈ rootsOfUnity (2 ^ (bits : Nat)) (Field)

theorem induction_append_left {m n : ℕ} {motive : Fin (m + n + 1) → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin (m + n), motive i.castSucc → motive i.succ} {i : Fin (m + 1)} :
      induction (motive := motive) zero succ ⟨i, by omega⟩ =
        @induction m (fun j => motive ⟨j, by omega⟩) zero (fun j x => succ ⟨j, by omega⟩ x) i

lemma toCodewordsCount_mul_ϑ_lt_ℓ (ℓ ϑ : ℕ) [NeZero ϑ] [NeZero ℓ] (i : Fin (ℓ + 1)) :
  ∀ j: Fin (toOutCodewordsCount ℓ ϑ i), j.val * ϑ < ℓ

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

theorem eqPolynomial_symm (x : σ → R) (y : σ → R) :
    MvPolynomial.eval y (eqPolynomial x) = MvPolynomial.eval x (eqPolynomial y)

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

lemma degreesY_nonempty {f : F[X][Y]} (hf : f ≠ 0) : (f.toFinsupp.support).Nonempty

theorem mul_one (n : ChurchNat α) : mul n one = n

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

@[to_additive vsum_castSucc]
lemma vprod_castSucc [CommMonoid α] {a : Fin (n + 1) → α} :
    vprod a = vprod (a ∘ Fin.castSucc) * a (last n)

lemma ConcreteBTFieldAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
    @ConcreteBTFieldAlgebra (l:=l) (r:=r) (h_le:=h_le)
    = (concreteTowerAlgebraMap l r h_le).toAlgebra

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

theorem happend_eq_addCases {α : Fin m → Sort u} {β : Fin n → Sort u}
    (u : (i : Fin m) → α i) (v : (i : Fin n) → β i) :
    happend u v = addCases (motive := vappend α β)
      (fun i => cast (vappend_left α β i).symm (u i))
      (fun i => cast (vappend_right α β i).symm (v i))

private lemma johnson_condition_strong_implies_n_pos
  (h_johnson : JohnsonConditionStrong B v)
  :
  0 < n

lemma Basis.baseChangeRight_repr_tmul (b : Basis ι K Left) (x y i) :
    (Basis.baseChangeRight (b:=b) (Right:=Right)).repr (x ⊗ₜ y) i = b.repr x i • y

@[simp, grind _=_]
theorem monomialXY_pow {n m k : ℕ} {a : F} :
  monomialXY n m a ^ k = monomialXY (n * k) (m * k) (a ^ k)

@[simp]
lemma rank_nonsquare_rows_eq_min (inj : Function.Injective α) :
  (Vandermonde.nonsquare (ι' := n) α).rank = min m n

lemma add_self_cancel {k : ℕ} (a : ConcreteBTField k) : a + a = 0

@[simp]
theorem zero_vappend {u : Fin 0 → α} (v : Fin n → α) :
    vappend u v = v ∘ Fin.cast (Nat.zero_add n)

@[simp]
lemma solutionToE_and_Q_E_and_Q_to_a_solution :
  E_and_Q_to_a_solution e (solutionToE e k v) (solutionToQ e k v) = v

theorem natDegree_finSuccEquivNth (f : MvPolynomial (Fin (n + 1)) R) :
    (finSuccEquivNth R p f).natDegree = degreeOf p f

@[simp]
theorem cast_idx_symm {i : ChallengeIdx pSpec₂} :
    pSpec₁.Challenge (i.cast hn.symm (cast_symm hSpec)) = pSpec₂.Challenge i

theorem ScalarField_is_prime : Nat.Prime SCALAR_FIELD_CARD

@[simp]
theorem oracleReduction_completeness (h : init.neverFails) :
    (oracleReduction oSpec Statement OStatement pred).perfectCompleteness init impl
    (toRelInput pred hPred) Set.univ

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 nsmul_zero [LawfulBEq R] (p : UniPoly R) : nsmul 0 p = 0

theorem comp_x_square_coeff {f : Polynomial F} {n : ℕ} :
  (f.comp (X * X)).coeff n = if Even n then f.coeff (n / 2) else 0

@[simp]
theorem FullData.ofFun_get {α} {s} (tree : FullData α s) :
    FullData.ofFun s (fun idx => tree.get idx) = tree

@[simp]
private lemma E_ne_zero : (E ωs f p e) ≠ 0

@[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 last_nonzero_some [LawfulBEq R] {p : UniPoly R} {i} (hi : i < p.size) (h : p[i] ≠ 0) :
  ∃ k, p.last_nonzero = some k

theorem mul_distrib_add (m n p : ChurchNat α) : mul m (add n p) = add (mul m n) (mul m p)

Nat.pred_lt_self in Init.Data.Nat.Basic

lemma solution_gamma_matches_word_if_subset_large
  {ωs : Fin n ↪ F}
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  {x : Fin n}
  {D : ℕ}
  (hD : D ≥ Bivariate.totalDegree (H k δ x₀ h_gs))
  (hx : (matching_set_at_x k δ h_gs x).card >
    (2 * k + 1)
      * (Bivariate.natDegreeY <| H k δ x₀ h_gs)
      * (Bivariate.natDegreeY <| R k δ x₀ h_gs)
      * D)
  : (P k δ x₀ h_gs).eval (Polynomial.C (ωs x)) =
    (Polynomial.C <| u₀ x) + u₁ x • Polynomial.X

lemma round_bound {n k : ℕ} {s : Fin (k + 1) → ℕ+} {d : ℕ+}
    (domain_size_cond : (2 ^ (∑ i, (s i).1)) * d ≤ 2 ^ n) :
  (∑ i, (s i).1) ≤ n

lemma crs_equiv_rs_random_point_agreement
  {f : ι → F} {m s : ℕ} {φ : ι ↪ F} [Smooth φ] :
  ∀ (r : Fin s → Fin m → F) (δ : ℝ≥0) (hδLe : δ ≤ 1),
    (∃ u u' : smoothCode φ m,
      u.val ≠ u'.val ∧
      u.val ∈ relHammingBall (smoothCode φ m) f δ ∧
      u'.val ∈ relHammingBall (smoothCode φ m) f δ ∧
      ∀ i : Fin s, (mVdecode u).eval (r i) = (mVdecode u').eval (r i))
    ↔
    (∃ σ : Fin s → F,
      let w : Fin s → MvPolynomial (Fin (m + 1)) F :=
        fun i => MvPolynomial.X (Fin.last m) * rename Fin.castSucc (eqPolynomial (r i))
      let multiCRSCode := multiConstrainedCode φ m s w σ
      ∃ u u' : ι → F, u ≠ u' ∧
        u ∈ relHammingBall multiCRSCode f δ ∧
        u' ∈ relHammingBall multiCRSCode f δ)

@[simp]
lemma liftF_succ {f : Fin (n + 1) → α} : liftF f n = f ⟨n, Nat.lt_add_one _⟩

theorem dcast_fun₂ {a₁ a₂ a₁' a₂' : α} {h₁ : a₁ = a₁'} {h₂ : a₂ = a₂'} {f : α → α → α}
    {g : (a₁ : α) → (a₂ : α) → β a₁ → β a₂ → β (f a₁ a₂)} {b₁ : β a₁} {b₂ : β a₂} :
    dcast (by cases h₁; cases h₂; rfl) (g a₁ a₂ b₁ b₂) = g a₁' a₂' (dcast h₁ b₁) (dcast h₂ b₂)

lemma powerBasisSucc_dim (k : ℕ) :
  powerBasisSucc (k:=k).dim = 2

theorem qMap_maps_sDomain (i : Fin r) (h_i_add_1 : i + 1 < r) :
  have q_comp_linear_map := qMap_is_linear_map 𝔽q β i
  have q_eval_linear_map := linear_map_of_comp_to_linear_map_of_eval
    (f:=qMap 𝔽q β i) q_comp_linear_map
  let q_i_map := polyEvalLinearMap (qMap 𝔽q β i) q_eval_linear_map
  let S_i := sDomain 𝔽q β h_ℓ_add_R_rate i
  let S_i_plus_1 := sDomain 𝔽q β h_ℓ_add_R_rate (i+1)
  Submodule.map q_i_map S_i = S_i_plus_1

omit [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 in
lemma get_sDomain_first_basis_eq_1 (i : Fin r) (h_i : i < ℓ + R_rate) :
    (sDomain_basis 𝔽q β h_ℓ_add_R_rate
    i (by omega)) ⟨0, by omega⟩ = (1: L)

theorem sumcheckFoldOracleVerifier_rbrKnowledgeSoundness :
    (sumcheckFoldOracleVerifier 𝔽q β).rbrKnowledgeSoundness init impl
      (pSpec := pSpecSumcheckFold 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
      (relIn := roundRelation (mp := mp) 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) 0)
      (relOut := roundRelation (mp := mp) 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) (Fin.last ℓ))
      (rbrKnowledgeError := sumcheckFoldKnowledgeError 𝔽q β (ϑ:=ϑ))

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

lemma split_join_eq_split {k : ℕ} (h_pos : k > 0)
    (hi_btf lo_btf : ConcreteBTField (k - 1)) :
    split h_pos (《 hi_btf, lo_btf 》) = (hi_btf, lo_btf)

lemma eval₂_eq' {S : Type w} [CommSemiring S] (g : P →+* S) (p : P) :
    g p = eval₂ (g.comp (Algebra.ofId R P)) (g X) p

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

lemma poly_eq_zero_of_dist_lt {n k : ℕ} {F : Type*} [DecidableEq F] [CommRing F] [IsDomain F]
  {p : Polynomial F} {ωs : Fin n → F}
  (h_deg : p.natDegree < k)
  (hn : k ≤ n)
  (h_inj : Function.Injective ωs)
  (h_dist : Δ₀(p.eval ∘ ωs, 0) < n - k + 1)
  : p = 0

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

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 getBit_repr {ℓ : Nat} : ∀ j, j < 2^ℓ →
  j = ∑ k ∈ Finset.Icc 0 (ℓ-1), (getBit k j) * 2^k

@[simp] theorem one_mul {a : AssocNat} : 1 * a = a

theorem queryOracleVerifier_rbrKnowledgeSoundness [Fintype L] {σ : Type} (init : ProbComp σ)
    (impl : QueryImpl []ₒ (StateT σ ProbComp)) :
    (queryOracleVerifier 𝔽q β (ϑ:=ϑ) γ_repetitions).rbrKnowledgeSoundness init impl
    (relIn := finalSumcheckRelOut 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (relOut := acceptRejectOracleRel)
    (rbrKnowledgeError := queryRbrKnowledgeError 𝔽q β γ_repetitions
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate))

theorem intermediateNormVpoly_comp_qmap (i : Fin (ℓ))
    (k : Fin (ℓ - i - 1)) : -- corresponds to intermediateNormVpoly_comp

@[simp]
theorem OracleReduction.runWithLog_eq_runWithLog_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

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

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]
protected lemma elocPolyF_eq_elocPoly :
  ElocPolyF (n := n) (liftF' ωs) (liftF' f) = ElocPoly n ωs f

theorem withBot_lt_one_cases (x : WithBot ℕ) (h : x < (1 : ℕ)) : x = ⊥ ∨ x = (0 : ℕ)

lemma twoAdicGenerators_pow_twoPow_ne_one_of_lt
    {bits : Fin (twoAdicity + 1)} {m : Nat} (hm : m < bits) :
    (twoAdicGenerators[bits]) ^ (2 ^ m) ≠ (1 : Field)

protected lemma a_lemma_im_not_proud_of_OLD {v a : Fin n → F}
  (h_card : 2 ≤ Fintype.card F)
  :
  |(1 : ℚ) - ((1 : ℚ) + (1 : ℚ) / ((Fintype.card F : ℚ) - 1)) * ↑Δ₀(v, a) / ↑n

lemma monoToLagrange_eq_monoToLagrange_segment (n : ℕ) [NeZero n] (v : Vector R (2 ^ n)) :
  have h_n_ne_zero: n ≠ 0

theorem is_prime : Nat.Prime fieldSize

@[simp]
lemma coe_fn_of_coe (f : ∀ a, β a) : (f : F) = inst.equiv.invFun f

theorem happend_left_eq_hcons {α : Fin 1 → Sort u} {β : Fin n → Sort u}
    (a : (i : Fin 1) → α i) (v : (i : Fin n) → β i) :
    True

theorem canonical_ext [LawfulBEq R] {p q : UniPoly R} (hp : p.trim = p) (hq : q.trim = q) :
    equiv p q → p = q

@[simp]
theorem cast_id :
    Prover.cast rfl rfl = (id : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₁ → _)

@[simp]
theorem vcons_succ (a : α) (v : Fin n → α) (i : Fin n) : (a ::ᵛ v) i.succ = v i

Nat.add_sub_cancel in Init.Data.Nat.Basic

theorem vconcat_eq_snoc (v : Fin n → α) (a : α) : vconcat v a = snoc v a

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)

@[to_additive (attr := simp)]
theorem prod_Iic_zero : ∏ j ∈ Iic 0, v j = v 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

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

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

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

lemma aeval_eq' {A : Type y} [CommSemiring A] [Algebra R A] {F : Type z} [FunEquiv F σ A]
    (f : P →ₐ[R] A) (p : P) : f p = aeval (fun s => f (X s) : F) p

lemma toOutCodewordsCount_mul_ϑ_eq_i_succ (i : Fin ℓ) (hCR : isCommitmentRound ℓ ϑ i) :
  (toOutCodewordsCount ℓ ϑ i.castSucc) * ϑ = i.val + 1

omit [Finite F] in
lemma pow_lift : ∀ {a : Fˣ} {i : ℕ} (s : ℕ),
    a ∈ evalDomain D x i → a ^ (2 ^ s) ∈ evalDomain D x (i + s)

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

theorem qMap_total_fiber_disjoint
  (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i + steps ≤ ℓ)
  {y₁ y₂ : sDomain 𝔽q β h_ℓ_add_R_rate ⟨i.val + steps, by omega⟩}
  (hy_ne : y₁ ≠ y₂) :
  Disjoint
    ((qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩) (steps := steps)
      (h_i_add_steps := fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps) y₁ '' Set.univ).toFinset)
    ((qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩) (steps := steps)
      (h_i_add_steps := fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps) y₂ '' Set.univ).toFinset)

lemma getBit_of_and {n m k: ℕ} : getBit k (n &&& m) = getBit k n &&& getBit k m

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

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

theorem toFun_eq_const_plus (t : AssocNat) : ∀ m : Nat, t m = t 0 + m

@[simp]
lemma liftF'_zero_eq_zero
  : liftF' (fun _ ↦ (0 : α)) = (fun (_ : Fin n) ↦ (0 : α))

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)

omit [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 in
lemma eval_point_ω_eq_next_twiddleFactor_comp_qmap

  (i : Fin ℓ) (x : Fin (2 ^ (ℓ + R_rate - (i + 1)))) :
  -- `j = u||b||v` => x here means u at level i
  evaluationPointω 𝔽q β h_ℓ_add_R_rate ⟨i.val+1, by omega⟩ x =
  eval (twiddleFactor 𝔽q β h_ℓ_add_R_rate ⟨i, by omega⟩ ⟨x.val, by
    calc x.val < 2 ^ (ℓ + R_rate - (i.val + 1)) := by omega
      _ = 2 ^ (ℓ + R_rate - i.val - 1) := by rfl
  ⟩) (qMap 𝔽q β ⟨i, by omega⟩)

@[simp]
theorem cast_id : Verifier.cast rfl rfl = (id : Verifier oSpec StmtIn StmtOut pSpec₁ → _)

theorem mca_johnson_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ℓ
  hasMutualCorrAgreement Gen
    -- Conjectured BStar = √ρ
    (Real.sqrt Gen.rate)
    -- Conjectured errStar
    (fun δ =>
      let min_val := min (1 - Real.sqrt Gen.rate - (δ : ℝ)) (Real.sqrt Gen.rate / 20)
      ENNReal.ofReal (
        ((Fintype.card parℓ_type - 1) * 2^(2*m)) /
        ((Fintype.card F) * (2 * min_val)^7)
      )
    )

@[simp]
protected lemma elocPoly_one :
  ElocPoly 1 ωs f p = if f 0 ≠ p.eval (ωs 0) then X - (C (ωs 0)) else 1

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

@[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 johnson_denominator_def :
  JohnsonDenominator B v = ((1 - ((Fintype.card F) / (Fintype.card F - 1)) * (e B v / n)) ^ 2
      - (1 - ((Fintype.card F) / (Fintype.card F - 1)) * (d B/n)))

@[simp]
lemma finite_possibleDeltas : (possibleDeltas U V).Finite

@[simp, grind =]
lemma totalDegree_monomialXY {n m : ℕ} {a : F} (ha : a ≠ 0) :
  totalDegree (monomialXY n m a) = n + m

@[simp]
theorem cast_id : Transcript.cast rfl rfl rfl = (id : pSpec₁.Transcript k → _)

congrArg in Init.Prelude

@[simp]
lemma ConcreteBTField_add_eq (k n m) :
      ConcreteBTField (k + n + m) = ConcreteBTField (k + (n + m))

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)

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

theorem PrattPartList.out {p : ℕ} {a : ZMod p} {n : ℕ} (h : PrattPartList p a n) :
    ∀ q : ℕ, q.Prime → q ∣ n → a ^ ((p - 1) / q) ≠ 1

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

private lemma johnson_condition_strong_implies_2_le_F_card
  (h_johnson : JohnsonConditionStrong B v)
  :
  2 ≤ Fintype.card F

theorem congrArg₃ {α β γ δ : Sort*} {f : α → β → γ → δ} {a a' : α} {b b' : β} {c c' : γ}
    (h : a = a') (h' : b = b') (h'' : c = c') : f a b c = f a' b' c'

@[simp]
theorem drop_apply (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) (i : Fin (n - m)) :
    (drop m h v) i = v (Fin.cast (Nat.sub_add_cancel h) (addNat i m))

@[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 happend_zero {β : Fin m → Sort u} {α : Fin 0 → Sort u} (u : (i : Fin m) → β i) :
    happend u !h⟨α⟩[] = u

theorem dconcat_injective2 {motive : Fin (n + 1) → Sort u} :
    Function.Injective2 (@dconcat n motive)

theorem init_dconcat {motive : Fin (n + 1) → Sort u} (v : (i : Fin n) → motive (castSucc i))
    (a : motive (last n)) : (fun i => (v :+ᵈ⟨motive⟩ a) (castSucc i)) = v

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

@[simp]
lemma natDegree_solutionToE :
  (solutionToE e k v).natDegree = e

theorem FullTranscript.mk2_eq_snoc_snoc {pSpec : ProtocolSpec 2} (msg0 : pSpec.«Type» 0)
    (msg1 : pSpec.«Type» 1) :
      FullTranscript.mk2 msg0 msg1 = ((default : pSpec.Transcript 0).concat msg0).concat msg1

lemma list_0 : list 0 = List.Vector.cons (1 : GF(2)) List.Vector.nil

nonpos_iff_eq_zero in Mathlib.Algebra.Order.Monoid.Canonical.Defs

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

theorem is_prime : Nat.Prime fieldSize

theorem add_zero {n : ℕ} (a : CNat (n + 1)) : a + 0 = a

lemma shiftRight_and_one_distrib {n m k : ℕ} :
    Nat.getBit k (n &&& m) = Nat.getBit k n &&& Nat.getBit k m

@[simp]
theorem OracleSpec.append_range_right {ι₁ ι₂ : Type} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂}
    (i : ι₂) : (spec₁ ++ₒ spec₂).range (Sum.inr i) = spec₂.range i

lemma towerEquiv_commutes_left_diff (i d : ℕ) : ∀ r : ConcreteBTField i,
  (AlgebraTower.algebraMap i (i+d) (by omega)) ((towerEquiv i).ringEquiv r) =
  (towerEquiv (i+d)).ringEquiv ((AlgebraTower.algebraMap i (i+d) (by omega)) r)

theorem prime_5 : Nat.Prime 5

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)

omit [NoZeroDivisors 𝔽] in
lemma foldNth_degree_le' {n : ℕ} {f : 𝔽[X]} {α : 𝔽} [inst : NeZero n] :
    n * (foldNth n f α).natDegree ≤ f.natDegree

pow_one in Mathlib.Algebra.Group.Defs

@[simp]
theorem init_update_last : init (update s (Fin.last n) y) = init s

@[simp]
lemma shift_left_empty :
    shift_left ∅ = ∅

@[simp]
theorem cast_completeness (ε : ℝ≥0) (hComplete : R.completeness init impl relIn relOut ε) :
    (R.cast hn hSpec hOₘ).completeness init impl relIn relOut ε

lemma algebraMap_succ_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField (k - 1)) :
  letI instAlgebra := ConcreteBTFieldAlgebra (l:=k-1) (r:=k) (h_le:=by omega)
  algebraMap (ConcreteBTField (k - 1)) (ConcreteBTField k) x = 《 0, x 》

theorem sum_square_char2 {F : Type*} [Field F] (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y)
  (s : Finset ℕ) (f : ℕ → F) : (∑ j ∈ s, f j)^2 = ∑ j ∈ s, (f j)^2

@[simp]
lemma challengeOracleInterface_append_range_inr (j : pSpec₂.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.range (.inr j) = pSpec₂.Challenge j

@[simp]
theorem hcons_zero {β : Fin n → Sort u} (a : α) (b : (i : Fin n) → β i) :
    hcons a b 0 = cast (vcons_zero α β).symm a

lemma nonsquare_mulVecLin [CommSemiring F] {ι' : ℕ} {α₁ : ι ↪ F} {α₂ : Fin ι' → F} {i : ι} :
  (nonsquare ι' α₁).mulVecLin α₂ i = ∑ x, α₂ x * α₁ i ^ x.1

@[simp]
theorem Reduction.runWithLog_discard_logs_eq_run
    {stmt : StmtIn} {wit : WitIn}
    {reduction : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec} :
      Prod.fst <$>
        reduction.runWithLog stmt wit = reduction.run stmt wit

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]
theorem hconcat_zero {α : Fin 0 → Sort u} {β : Sort u} (a : β) :
    hconcat !h⟨α⟩[] a = fun i => match i with

@[grind]
lemma degreeX_le_degreeX_sub_degreeX [IsDomain F] {f q : F[X][Y]} (hf : f ≠ 0) (hg : q * f ≠ 0) :
  degreeX q ≤ degreeX (q * f) - degreeX f

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

lemma getBit_of_shiftRight {n p : ℕ}:
  ∀ k, getBit k (n >>> p) = getBit (k+p) n

Fin.val_succ in Init.Data.Fin.Lemmas

@[simp]
lemma list_eq (k : ℕ) :
  list (k+1) = (Z (k+1)) ::ᵥ (list k).map (AdjoinRoot.of (poly k))

@[simp]
theorem OracleVerifier.id_soundness {lang : Set (StmtIn × ∀ i, OStmtIn i)} :
    (OracleVerifier.id : OracleVerifier oSpec _ _ _ _ _).soundness
      init impl lang lang 0

@[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 insertNth_apply_same : insertNth p y s p = y

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

@[simp]
theorem take_append_left' : (pSpec₁ ++ₚ pSpec₂)⟦:m⟧ = pSpec₁

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

lemma BTField.cast_BTField_eq (k m : ℕ) (h_eq : k = m) :
  BTField k = BTField m

@[csimp, grind =]
theorem findIdx'_eq_findIdx : @findIdx' = @findIdx

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

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

lemma rank_eq_rowRank : U.rank = rowRank U

Fin.val_injective in Mathlib.Data.Fin.Basic

theorem is_multilinear_iff_eq_evals_zeroOne {p : MvPolynomial σ R} :
    p ∈ R⦃≤ 1⦄[X σ] ↔ MLE p.toEvalsZeroOne = p

private lemma f_convex {x₁ x₂ : ℚ} {α₁ α₂ : ℚ}
  (h_noneg_1 : 0 ≤ α₁)
  (h_noneg_2 : 0 ≤ α₂)
  (h_conv : α₁ + α₂ = 1)
  :
  f (α₁ * x₁ + α₂ * x₂) ≤ α₁ * f x₁ + α₂ * f x₂

@[simp]
theorem hflatten_zero {n : Fin 0 → ℕ} {α : (i : Fin 0) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin 0) → (j : Fin (n i)) → α i j} : hflatten v = !h[]

theorem zero_mul {a : AssocNat} : 0 * a = 0

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

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

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

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 ofFn_rtake_eq_rtake_ofFn {α : Type*} {m : ℕ} (h : m ≤ n) (v : Fin n → α) :
    List.ofFn (rtake m h v) = (List.ofFn v).rtake m

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

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)

theorem finalSumcheckOracleVerifier_rbrKnowledgeSoundness [Fintype L] {σ : Type}
    (init : ProbComp σ) (impl : QueryImpl []ₒ (StateT σ ProbComp)) :
    (finalSumcheckVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).rbrKnowledgeSoundness init impl
      (relIn := roundRelation 𝔽q β (ϑ := ϑ) (𝓑 := 𝓑)
        (mp := BBF_SumcheckMultiplierParam) (Fin.last ℓ))
      (relOut := finalSumcheckRelOut 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
      (rbrKnowledgeError := finalSumcheckKnowledgeError)

theorem PowerBasis_cast_dest_eq (k n m : ℕ) (h_k_le_n : k ≤ n)
  (h_k_le_m : k ≤ m) (h_eq : m = n) :
  letI instLeftAlgebra := ConcreteBTFieldAlgebra (l:=k) (r:=m) (h_le:=h_k_le_m)
  letI instRightAlgebra := ConcreteBTFieldAlgebra (l:=k) (r:=n) (h_le:=h_k_le_n)
  @PowerBasis (ConcreteBTField k) (ConcreteBTField m) _ _ instLeftAlgebra =
  @PowerBasis (ConcreteBTField k) (ConcreteBTField n) _ _ instRightAlgebra

@[simp]
theorem dconcat_zero {motive : Fin 1 → Sort u} (a : motive (last 0)) :
    !d⟨fun _ : Fin 0 => motive (castSucc _)⟩[] :+ᵈ⟨motive⟩ a = !d⟨motive⟩[a]

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

Fin.eta in Init.Data.Fin.Lemmas

Polynomial.degree_sum_le in Mathlib.Algebra.Polynomial.Degree.Definitions

@[simp]
theorem vappend_vcons (a : α) (u : Fin m → α) (v : Fin n → α) :
    vappend (vcons a u) v = (vcons a (vappend u v)) ∘ Fin.cast (Nat.succ_add m n)

@[simp]
theorem FullData.rightSubtree_internal {α} {s_left s_right : Skeleton}
    (value : α) (left : FullData α s_left) (right : FullData α s_right) :
    (FullData.internal value left right).rightSubtree = right

lemma getBit_of_add_distrib {n m k : ℕ}
  (h_n_AND_m : n &&& m = 0) : getBit k (n + m) = getBit k n + getBit k m

@[simp]
theorem cast_id : MessageIdx.cast (Eq.refl n₁) rfl = (id : pSpec₁.MessageIdx → _)

lemma extract_start_zero_eq_take {n : ℕ} {α : Fin n → Sort*} (stop : ℕ) (h : stop ≤ n)
    (v : (i : Fin n) → α i) : extract 0 stop (Nat.zero_le _) h v = take stop h v

@[coe]
theorem BTField_succ_eq_adjoinRoot (k : ℕ) : AdjoinRoot (poly k) = BTField (k+1)

theorem dconcat_init_self {motive : Fin (n + 1) → Sort u} (v : (i : Fin (n + 1)) → motive i) :
    (fun i => v (castSucc i)) :+ᵈ⟨motive⟩ (v (last n)) = 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)))

omit [Finite F] in
private lemma gen_def {i : ℕ} :
    (IsCyclicWithGen.gen : evalDomain D i) =
      ⟨
        DIsCyclicC.gen ^ (2 ^ i),
        by
          apply pow_2_pow_i_mem_Di_of_mem_D
          exact DIsCyclicC.gen.2
      ⟩

theorem completeness [DecidableEq α] [SelectableType α] {s}
    (leaf_data_tree : LeafData α s) (idx : BinaryTree.SkeletonLeafIndex s)
    (preexisting_cache : (spec α).QueryCache) :
    (((do
      let cache ← buildMerkleTree leaf_data_tree
      let proof := generateProof cache idx
      let _ ← verifyProof idx (leaf_data_tree.get idx) (cache.getRootValue) proof
      ).simulateQ (randomOracle)).run preexisting_cache).neverFails

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

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

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

theorem two_le_two_pow_n_plus_1 (n : ℕ) : 2 ≤ 2 ^ (n + 1)

@[simp]
theorem rtake_append_right :
    (pSpec₁ ++ₚ pSpec₂).rtake n (Nat.le_add_left n m) = pSpec₂

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

@[simp]
theorem drop_update_of_lt (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) (i : Fin n)
    (hi : i < m) (x : α i) : drop m h (update v i x) = drop m h v

theorem whir_rbr_soundness
    [SelectableType F] {d dstar : ℕ}
  -- P : set of M + 1 parameters including foldingParamᵢ, varCountᵢ, φᵢ, repeatParamᵢ,
  --

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

@[simp]
theorem toNat_zero : toNat zero = 0

lemma h_middle_sub {k : ℕ} : 2 ^ (k - 1) - 1 - 0 + 1 = 2 ^ (k - 1)

theorem towerAlgebraMap_assoc : ∀ r mid l : ℕ, (h_l_le_mid : l ≤ mid) → (h_mid_le_r : mid ≤ r) →
    towerAlgebraMap (l:=l) (r:=r) (h_le:=by exact Nat.le_trans h_l_le_mid h_mid_le_r) =
    (towerAlgebraMap (l:=mid) (r:=r) (h_le:=h_mid_le_r)).comp
    (towerAlgebraMap (l:=l) (r:=mid) (h_le:=h_l_le_mid))

Fin.ext in Init.Data.Fin.Lemmas

theorem two_pow_ne_zero (n : ℕ) : 2 ^ n ≠ 0

lemma evenize_eval {f : Polynomial F} {s : F} :
    (evenize f).eval s = f.eval (s * s)

@[simp]
lemma relHammingDist_mem_relHammingDistRange [DecidableEq F] : δᵣ(u, v) ∈ relHammingDistRange ι

beq_iff_eq in Init.Core

lemma trim_add_trim [LawfulBEq R] (p q : UniPoly R) : p.trim + q = p + q

theorem evenRefinement_eq_novel_poly_of_0_leading_suffix (i : Fin ℓ) (v : Fin (2 ^ i.val))
    (original_coeffs : Fin (2 ^ ℓ) → L) :
    have h_v: v.val < 2 ^ (i.val + 1) := by
      calc v.val < 2 ^ i.val := by omega
        _ < 2 ^ (i.val + 1) := by apply Nat.pow_lt_pow_right (by omega) (by omega)
    evenRefinement 𝔽q β h_ℓ_add_R_rate i (coeffsBySuffix (r:=r)
      (R_rate:=R_rate) (a:=original_coeffs) ⟨i, by omega⟩ v) =
    intermediateEvaluationPoly 𝔽q β h_ℓ_add_R_rate ⟨i + 1, by omega⟩
      (coeffsBySuffix (r:=r) (R_rate:=R_rate) original_coeffs ⟨i + 1, by omega⟩ ⟨v, h_v⟩)

private lemma choose_2_eq_half_f :
  choose_2 = (1/2) * f

lemma galois_eval_in_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)
    (prevSpecialElementNeZero : t1 ≠ 0)
    (u_plus_inv_eq_t1 : u + u⁻¹ = t1)
    (h_u_square : u^2 = u*t1 + 1)
    (h_t1_pow : t1^(2^(2^k)-1) = 1 ∧ (t1⁻¹)^(2^(2^k)-1) = 1)
    (h_t1_pow_2_pow_2_pow_k :  t1^(2^(2^k)) = t1)
    (h_t1_inv_pow_2_pow_2_pow_k :  (t1⁻¹)^(2^(2^k)) = t1⁻¹)
    (trace_map_at_inv : ∑ i ∈ Finset.range (2 ^ k), t1⁻¹ ^ (2 ^ i) = 1) :
    u^(2^(2^k)) = u⁻¹

lemma and_shl_eq_zero_of_lt_two_pow {a n b : ℕ} (hb : b < 2 ^ n) : (a <<< n) &&& b = 0

@[simp]
theorem Set.not_mem_language_iff {α β} (rel : Set (α × β)) (stmt : α) :
    stmt ∉ rel.language ↔ ∀ wit, (stmt, wit) ∉ rel

@[simp] lemma twoAdicGenerators_length : twoAdicGenerators.length = twoAdicity + 1

theorem dconcat_left_injective {motive : Fin (n + 1) → Sort u} (a : motive (last n)) :
    Function.Injective (fun v => dconcat (motive := motive) v a)

@[simp]
theorem mul_by_2_mem {s : Finset ℕ} {d : ℕ} :
    d ∈ mul_by_2 s ↔ Even d ∧ (d / 2) ∈ s

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

@[simp]
theorem Prover.runToRound_one_of_prover_first [ProverOnly pSpec] (stmt : StmtIn) (wit : WitIn)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      prover.runToRound 1 stmt wit = (do
        let state := prover.input (stmt, wit)
        let ⟨msg, state⟩ ← liftComp (prover.sendMessage ⟨0, by simp⟩ state) _
        return (fun i => match i with | ⟨0, _⟩ => msg, state))

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_steps_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r} (i : Fin ℓ) (steps : ℕ)
    (h : i.val + steps ≤ ℓ) : i.val + steps < r

lemma sDomain_card (i : Fin r) (h_i : i < ℓ + R_rate) :
    Fintype.card (sDomain 𝔽q β h_ℓ_add_R_rate i) = (Fintype.card 𝔽q)^(ℓ + R_rate - i)

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

lemma getHighBits_no_shl_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
  getHighBits_no_shl n (joinBits low high).val = high.val

theorem relayOracleReduction_perfectCompleteness (hInit : init.neverFails) (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
    OracleReduction.perfectCompleteness
      (pSpec := pSpecRelay)
      (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 := relayOracleReduction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        i hNCR)
      (init := init)
      (impl := impl)

theorem happend_hconcat {α : Fin m → Sort u} {β : Fin n → Sort u} {γ : Sort u}
    (u : (i : Fin m) → α i) (v : (i : Fin n) → β i) (c : γ) :
    True

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

@[simp]
lemma challengeOracleInterface_append_range_inl (j : pSpec₁.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.range (.inl j) = pSpec₁.Challenge j

@[simp]
theorem init_apply : init s i = s i.castSucc

@[simp]
theorem ConcreteBTField.RingHom_cast_source_apply (k n m : ℕ) (h_eq : k = n)
  (f : ConcreteBTField k →+* ConcreteBTField m) (x : ConcreteBTField n) :
    (cast (ConcreteBTField.RingHom_eq_of_source_eq (k:=k) (n:=n) (m:=m) h_eq) f) x
    = f (cast (by apply cast_ConcreteBTField_eq (h_eq:=h_eq.symm)) x)

@[simp]
theorem append_snd (T₁ : FullTranscript pSpec₁) (T₂ : FullTranscript pSpec₂) :
    (T₁ ++ₜ T₂).snd = T₂

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

Nat.lt_of_add_right_lt in Init.Data.Nat.Basic

theorem support_C {r : R} [h : Decidable (r = 0)] :
    (@C R σ _ r).support = if r = 0 then ∅ else { 0 }

theorem elim [LawfulBEq R] (p : UniPoly R) :
    (p.trim = #[] ∧  (∀ i, (hi : i < p.size) → p[i] = 0))
  ∨ (∃ k : Fin p.size,
        p.trim = p.extract 0 (k + 1)
      ∧ p[k] ≠ 0
      ∧ (∀ j : ℕ, (hj : j < p.size) → j > k → p[j] = 0))

lemma towerRingHomForwardMap_one {k : ℕ} :
  (towerRingHomForwardMap k) 1 = 1

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 : ℝ) > δ

@[simp]
theorem cast_id :
    Reduction.cast rfl rfl = (id : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec₁ → _)

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

@[simp]
theorem FullData.get_leaf {α} (a : α) :
    (FullData.leaf a).get SkeletonNodeIndex.ofLeaf = 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)

theorem hammingDist_le_of_outer_comp_injective {ι₁ ι₂ : Type*} [Fintype ι₁] [Fintype ι₂]
    {β : ι₂ → Type*} [∀ i, DecidableEq (β i)] [DecidableEq ι₂]
    (x y : ∀ i, β i) (g : ι₁ → ι₂) (hg : Function.Injective g) :
    hammingDist (fun i => x (g i)) (fun i => y (g i)) ≤ hammingDist x y

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 rightpad_eq_self (v : Fin n → α) (a : α) : rightpad n a v = v

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

theorem GF_2_value_eq_zero_or_one (x : GF(2)) : x = 0 ∨ x = 1

lemma addSalt_Challenge (i : pSpec.ChallengeIdx) :
    (pSpec.addSalt Salt).Challenge i = pSpec.Challenge i

lemma concrete_exists_pair_ne {k : ℕ} : ∃ x y : ConcreteBTField k, x ≠ y

Nat.succ_lt_succ_iff in Init.Data.Nat.Basic

lemma getBit_of_or {n m k: ℕ} : getBit k (n ||| m) = getBit k n ||

omit [Fintype F] [DecidableEq F] in
private lemma choose_2_card_ne_zero (h : 2 ≤ B.card) : choose_2 ↑B.card ≠ 0

theorem add_comm : p + q = q + p

@[simp]
theorem vflatten_zero {n : Fin 0 → ℕ} {v : (i : Fin 0) → Fin (n i) → α} : vflatten v = !v[]

lemma sum_of_and_eq_zero_is_xor {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n + m = n ^^^ m

@[simp] theorem join_cons : (l :: ls).join = l ++ ls.join

@[grind _=_]
lemma weightedDegree_eq_natWeightedDegree {u v : ℕ} :
  f ≠ 0 → weightedDegree f u v = natWeightedDegree f u v

lemma getBit_eq_testBit (k n : Nat) : getBit k n = if n.testBit k then 1 else 0

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

lemma toImpl_elim (p : Q[X]) :
    (p = 0 ∧ p.toImpl = #[])
  ∨ (p ≠ 0 ∧ p.toImpl = .ofFn (fun i : Fin (p.natDegree + 1) => p.coeff i))

@[simp] theorem BitVec.dcast_zero {n m : ℕ} (h : n = m) : DCast.dcast h (0#n) = 0#m

@[simp]
theorem vflatten_two_eq_append {n : Fin 2 → ℕ} {v : (i : Fin 2) → Fin (n i) → α} :
    vflatten v = vappend (v 0) (v 1)

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

lemma binaryTowerAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
    @binaryAlgebraTower (l:=l) (r:=r) (h_le:=h_le)
    = (towerAlgebraMap l r h_le).toAlgebra

theorem fcons₂_left_injective {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (b : (i : Fin n) → F₂ (β₁ i) (β₂ i)) :
    Function.Injective (fun a : F₂ α₁ α₂ => fcons₂ (F := F₂) a b)

omit [SelectableType R] in
@[simp]
lemma reduction_verifier_eq_verifier {i : Fin n} :
    (reduction R n deg D oSpec i).verifier = verifier R n deg D oSpec i

lemma xor_eq_sub_iff_submask {n m : ℕ} (h: m ≤ n) : n ^^^ m = n - m ↔ n &&& m = m

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)

lemma zero_def [Zero R] : zero = Vector.replicate (2 ^ n) 0

theorem finrank_degreeLT_n (n : ℕ) : Module.finrank L (L⦃< n⦄[X]) = n

lemma Fin.le_iff_lt_succ (a b : Fin r) (h_b : b + 1 < r) : a ≤ b ↔ a < b + 1

lemma algebraMap_adjacent_tower_def (l : ℕ) :
  (algebraMap (BTField l) (BTField (l + 1))) = canonicalEmbedding l

theorem finalSumcheckOracleReduction_perfectCompleteness {σ : Type}
  (init : ProbComp σ)
  (impl : QueryImpl []ₒ (StateT σ ProbComp))
  (hInit : init.neverFails) :
  OracleReduction.perfectCompleteness
    (pSpec := pSpecFinalSumcheckStep (L := L))
    (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))
    (oracleReduction := finalSumcheckOracleReduction 𝔽q β (ϑ := ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) (init := init) (impl := impl)

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

lemma definingPoly_is_monic {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).Monic

lemma evenize_eq_comp_x_squared {f : Polynomial F} :
    evenize f = f.comp (Polynomial.X * Polynomial.X)

theorem append_right_injective (a : Fin m → α) : Function.Injective (@Fin.append m n α a)

lemma pointToIterateQuotientIndex_qMap_total_fiber_eq_self (i : Fin ℓ) (steps : ℕ)
    (h_i_add_steps : i.val + steps ≤ ℓ)
    (y : (sDomain 𝔽q β h_ℓ_add_R_rate) (i := ⟨i + steps, by omega⟩)) (k : Fin (2 ^ steps)) :
    pointToIterateQuotientIndex (i := ⟨i, by omega⟩) (steps := steps) (h_i_add_steps := by omega)
      (x := ((qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩) (steps := steps)
        (h_i_add_steps := by apply Nat.lt_add_of_pos_right_of_le; omega) (y := y) k):
          sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩))) = k

@[simp]
theorem Set.mem_language_iff {α β} (rel : Set (α × β)) (stmt : α) :
    stmt ∈ rel.language ↔ ∃ wit, (stmt, wit) ∈ rel

@[simp]
private lemma x_times_oddPart'_coeff {f : Polynomial F} {n : ℕ} :
    (x_times_oddPart' f).coeff n = if Odd n then f.coeff n else 0

lemma getBit_zero_of_two_mul {n : ℕ} : getBit 0 (2*n) = 0

@[simp] lemma ofMvPolynomialAlgHom_X (s : σ) :
    ofMvPolynomialAlgHom (MvPolynomial.X s : MvPolynomial σ R) = (X s : P)

lemma concreteTowerAlgebraMap_succ (l r : ℕ) (h_le : l ≤ r) :
  concreteTowerAlgebraMap (l:=l) (r:=r + 1) (h_le:=by omega) =
  (concreteTowerAlgebraMap (l:=r) (r:=r + 1) (h_le:=by omega)).comp
  (concreteTowerAlgebraMap (l:=l) (r:=r) (h_le:=by omega))

theorem vcons_inj (a b : α) (v w : Fin n → α) : a ::ᵛ v = b ::ᵛ w ↔ a = b ∧ v = w

@[simp]
lemma zero_le_relHammingDist : 0 ≤ δᵣ(u, v)

theorem liftContext_soundness
    {soundnessError : ℝ≥0}
    {lens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut}
    (V : OracleVerifier oSpec InnerStmtIn InnerOStmtIn InnerStmtOut InnerOStmtOut pSpec)
    [lensSound : lens.IsSound outerLangIn outerLangOut innerLangIn innerLangOut
      (V.toVerifier.compatStatement lens)]
    (h : V.soundness init impl innerLangIn innerLangOut soundnessError) :
      (V.liftContext lens).soundness init impl outerLangIn outerLangOut soundnessError

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

@[simp]
private lemma leadingCoeff_E : (E ωs f p e).leadingCoeff = 1

lemma domain_injective (i : ℕ) : i ≤ n → Function.Injective (domain D n i)

lemma IsBerlekampWelchSolution_def
  : IsBerlekampWelchSolution e k ωs f v
  ↔ Matrix.mulVec (BerlekampWelchMatrix e k ωs f) v = (Rhs e ωs f)

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

private lemma x_times_oddPart'_eq_x_times_oddPart' {f : Polynomial F} :
    Polynomial.X * (oddPart' f) = x_times_oddPart' f

@[simp]
theorem take_append_left (T : FullTranscript pSpec₁) (T' : FullTranscript pSpec₂) :
    (T ++ₜ T').take m (Nat.le_add_right m n) =
      T.cast rfl (by simp [ProtocolSpec.append])

theorem finSuccEquivNth_eq :
    (finSuccEquivNth R p : MvPolynomial (Fin (n + 1)) R →+* Polynomial (MvPolynomial (Fin n) R)) =
      eval₂Hom (Polynomial.C.comp (C : R →+* MvPolynomial (Fin n) R))
        (Fin.insertNth p Polynomial.X (Polynomial.C ∘ X))

@[simp]
lemma deevenize_coeff {f : Polynomial F} {n : ℕ} :
    (deevenize f).coeff n = f.coeff (2 * n)

@[simp]
lemma ofPolynomialAlgHom_X : ofPolynomialAlgHom (Polynomial.X : R[X]) = (X : P)

lemma BerlekampWelch_Q_ne_zero {e k : ℕ}
  [NeZero n]
  {ωs f : Fin n → F}
  {E Q : Polynomial F}
  (h_bw : BerlekampWelchCondition e k ωs f E Q)
  (h_dist : e < Δ₀(f, 0))
  (h_inj : Function.Injective ωs)
  : Q ≠ 0

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

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

theorem matchSize_eq_iff_forall_eq (l₁ l₂ : List α) (unit : α) :
    (fun (x, y) => x = y) (matchSize l₁ l₂ unit) ↔ ∀ i : Nat, l₁.getD i unit = l₂.getD i unit

@[simp]
theorem LeafData.ofFun_get {α} {s} (tree : LeafData α s) :
    LeafData.ofFun s (fun idx => tree.get idx) = tree

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

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)

lemma getLowBits_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
  getLowBits n (joinBits low high).val = low.val

@[simp]
theorem dist'_empty : ‖(∅ : Set (n → R))‖₀' = ⊤

@[simp]
theorem dcast₂_trans (ha : a = a') (ha' : a' = a'')
    (hb : dcast ha b = b') (hb' : dcast ha' b' = b'') :
      dcast₂ ha' hb' (dcast₂ ha hb c) = dcast₂ (ha.trans ha') (by simp [← hb', ← hb]) c

theorem add_assoc {n : ℕ} (a b c : CNat (n + 1)) : (a + b) + c = a + (b + c)

theorem prime_7 : Nat.Prime 7

lemma testBit_of_sub_two_pow_of_bit_1 {n i : ℕ} (h_testBit_eq_1 : (n).testBit i = true) :
  (n - 2^i).testBit i = false

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

lemma coe_one_succ (l : ℕ) :
    (@ConcreteBTFieldAlgebra (l:=l) (r:=l + 1) (h_le:=by omega)).algebraMap
    (1 : ConcreteBTField l) = (1 : ConcreteBTField (l + 1))

lemma forwardRange_length (n : ℕ) (r : Fin n) (l : Fin (r.val + 1)) :
    (forwardRange n r l).length = r.val - l.val + 1

@[simp]
theorem ranges_succ {a : ℕ} {l : List ℕ} :
    List.ranges (a :: l) = range a :: l.ranges.map (map (a + ·))

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 evenize_is_even {f : Polynomial F} :
    EvenPoly (evenize f)

theorem liftContext_soundness [Inhabited InnerStmtOut]
    {outerLangIn : Set OuterStmtIn} {outerLangOut : Set OuterStmtOut}
    {innerLangIn : Set InnerStmtIn} {innerLangOut : Set InnerStmtOut}
    {soundnessError : ℝ≥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.soundness init impl innerLangIn innerLangOut soundnessError) :
      (V.liftContext lens).soundness init impl outerLangIn outerLangOut soundnessError

lemma eval_normalizedW_succ_at_beta_prev (i : Fin r) (h_i_add_1 : i + 1 < r) :
  (normalizedW 𝔽q β (i + 1)).eval (β i) = 0

@[simp]
lemma invFun_toFun (f : F) : inst.equiv.invFun (inst.equiv.toFun f) = f

lemma rank_eq_colRank : U.rank = colRank U

theorem fconcat₂_right_injective {α₁ : Fin n → A} {α₂ : Fin n → B} {β₁ : A} {β₂ : B}
    (v : (i : Fin n) → F₂ (α₁ i) (α₂ i)) :
    Function.Injective (fconcat₂ (F := F₂) v :
      F₂ β₁ β₂ → (i : Fin (n + 1)) → F₂ (Fin.vconcat α₁ β₁ i) (Fin.vconcat α₂ β₂ i))

theorem fcons₂_inj {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B}
    (a₁ a₂ : F₂ α₁ α₂) (b₁ b₂ : (i : Fin n) → F₂ (β₁ i) (β₂ i)) :
    fcons₂ (F := F₂) a₁ b₁ = fcons₂ (F := F₂) a₂ b₂ ↔ a₁ = a₂ ∧ b₁ = b₂

lemma concrete_inv_zero {k : ℕ} : concrete_inv (k:=k) 0 = 0

@[simp]
theorem finSigmaFinEquiv'_apply {m : ℕ} {n : Fin m → ℕ} (k : (i : Fin m) × Fin (n i)) :
    (finSigmaFinEquiv' k : ℕ) = ∑ i : Fin k.1, n (Fin.castLE k.1.isLt.le i) + k.2

theorem BitVec.extractLsb_eq_shift_ofNat {n : Nat} (x : BitVec n) (l r : Nat) :
    BitVec.extractLsb r l x = BitVec.ofNat (r - l + 1) (x.toNat >>> l)

@[simp]
theorem oracleReduction_perfectCompleteness (hInit : init.neverFails) :
    (oracleReduction oSpec Statement OStatement Witness).perfectCompleteness init impl rel rel

theorem sum_fromNat_eq_from_xor_Nat {k : ℕ} (x y : Nat) :
  fromNat (k:=k) (x ^^^ y) = fromNat (k:=k) x + fromNat (k:=k) y

theorem tail_init_eq_init_tail (s : Fin (n + 2) →₀ M) : tail (init s) = init (tail s)

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

@[simp]
theorem vconcat_last (v : Fin n → α) (a : α) : vconcat v a (Fin.last n) = a

theorem induct [LawfulBEq R] {motive : UniPoly R → Prop}
  (case1 : ∀ p, p.trim = #[] → (∀ i, (hi : i < p.size) → p[i] = 0) → motive p)
  (case2 : ∀ p : UniPoly R, ∀ k : Fin p.size, p.trim = p.extract 0 (k + 1)
    → p[k] ≠ 0 → (∀ j : ℕ, (hj : j < p.size) → j > k → p[j] = 0) → motive p)
  (p : UniPoly R) : motive p

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)

theorem hconcat_init_self {α : Fin n.succ → Sort u} (v : (i : Fin (n + 1)) → α i) :
    True

@[simp]
theorem fcons_one {β : Fin (n + 1) → A} (a : F α) (v : (i : Fin (n + 1)) → F (β i)) :
    fcons a v 1 = v 0

lemma num_eq_highBits_xor_lowBits {n: ℕ} (numLowBits: ℕ) :
  n = getHighBits numLowBits n ^^^ getLowBits numLowBits n

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)

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

lemma lin_shift_d [Field F] [Fintype F]
  (h_B : 2 ≤ B.card)
  :
  d B = d ({x - v | x ∈ B} : Finset _)

@[simp]
theorem verifier_last (pSpec : ProtocolSpec n) [NeZero n] [h : VerifierLast pSpec] :
    pSpec.dir ⟨n - 1, by simp [Nat.pos_of_neZero]⟩ = .V_to_P

@[simp]
lemma coe_toFun_of_coe_apply (f : ∀ a, β a) (a : α) : (f : F) a = f a

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 singleEqPolynomial_nf (r : R) (x : MvPolynomial σ R) :
    singleEqPolynomial r x = (2 * C r - 1) * x + (1 - C r)

@[csimp] lemma dfoldr_eq_dfoldr' : @dfoldr = @dfoldr'

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

lemma add_zero {k : ℕ} (a : ConcreteBTField k) : a + 0 = a

lemma rank_nonsquare_eq_deg_of_ι_le (inj : Function.Injective α) (h : m ≤ n) :
  (Vandermonde.nonsquare (ι' := n) α).rank = m

@[simp]
theorem partialSum_nil : [].partialSum = [0]

Nat.pow_lt_pow_right in Init.Data.Nat.Lemmas

Nat.two_pow_pos in Init.Data.Nat.Basic

lemma principal_is_maximal_iff_irred {F : Type} [Field F] (f : F[X]) :
  (principalIdeal f).IsMaximal ↔ Irreducible f

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

@[simp]
theorem vcons_fin_zero (a : α) (v : Fin 0 → α) : a ::ᵛ v = fun i => match i with

@[simp] theorem equiv_refl (p : UniPoly Q) : equiv p p

@[simp]
theorem fflatten_splitSum {A : Sort u} {F : A → Sort v} {m : ℕ} {n : Fin m → ℕ}
    {α : (i : Fin (vsum n)) → A}
    (v : (k : Fin (vsum n)) → F (α k)) (k : Fin (vsum n)) :
    fflatten (fun i j => v (embedSum i j)) k = cast (by simp) (v 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₁)

NeZero.ne in Init.Data.NeZero

@[simp]
theorem seqCompose_zero {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    {T : ∀ i, FullTranscript (pSpec i)} :
    seqCompose T = !h[]

@[simp]
theorem fflatten₂_embedSum {A : Sort u} {B : Sort v} {F : A → B → Sort w} {m : ℕ} {n : Fin m → ℕ}
    {α : (i : Fin m) → (j : Fin (n i)) → A}
    {β : (i : Fin m) → (j : Fin (n i)) → B}
    (v : (i : Fin m) → (j : Fin (n i)) → F (α i j) (β i j)) (i : Fin m) (j : Fin (n i)) :
    fflatten₂ v (embedSum i j) = cast (by simp) (v i j)

omit [NoZeroDivisors 𝔽] in
lemma splitNth_degree_le {n : ℕ} {f : 𝔽[X]} [inst : NeZero n] :
  ∀ {i}, (splitNth f n i).natDegree ≤ f.natDegree / n

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)

@[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 sDomainBasisVectors_mem_sDomain (i : Fin r) (k : Fin (ℓ + R_rate - i)) :
  sDomainBasisVectors 𝔽q β h_ℓ_add_R_rate i k
    ∈ sDomain 𝔽q β h_ℓ_add_R_rate i

theorem liftContext_run
    {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).run outerStmtIn outerWitIn = do
        let ⟨⟨fullTranscript, innerCtxOut⟩, verInnerStmtOut⟩ ←
          R.run.uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨⟨fullTranscript, lens.lift (outerStmtIn, outerWitIn) innerCtxOut⟩ ,
                lens.stmt.lift outerStmtIn verInnerStmtOut⟩

theorem split_bitvec_eq_iff_fromNat {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
  (hi_btf lo_btf : ConcreteBTField (k - 1)) :
  split h_pos 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 basis_repr_of_sDomain_lift (i j : Fin r) (h_j : j < ℓ + R_rate) (h_le : i ≤ j)
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := j)) :
    let x₀ := sDomain.lift 𝔽q β h_ℓ_add_R_rate i j (by omega) (by omega) y
    ∀ k: Fin (ℓ + R_rate - i),
      (sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := i) (h_i := by omega)).repr x₀ k =
        if hk: k < (j.val - i.val) then 0
        else (sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := j)
          (h_i := by omega)).repr y ⟨k - (j.val - i.val), by omega⟩

lemma liftF_ne_zero_of_lt {i : ℕ} (h : i < n) : liftF f' i ≠ 0 ↔ f' ⟨i, h⟩ ≠ 0

@[simp]
lemma finite_offDiag [Finite F] : C.offDiag.Finite

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

@[simp]
lemma lin_shift_hamming_distance [Field F] {x₁ x₂ v : Fin n → F}
  :
  Δ₀(x₁ - v, x₂ - v) = Δ₀(x₁, x₂)

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

@[simp] theorem ofNat_toNat (t : AssocNat) : ofNat (toNat t) = t

theorem congrArg₄ {α β γ δ ε : Sort*} {f : α → β → γ → δ → ε} {a a' : α} {b b' : β} {c c' : γ}
    {d d' : δ} (h : a = a') (h' : b = b') (h'' : c = c') (h''' : d = d') :
      f a b c d = f a' b' c' d'

@[grind]
lemma quotient_nezero {f q : F[X][Y]} (hg : q * f ≠ 0) : q ≠ 0

@[simp]
theorem fcons_succ {β : Fin n → A} (a : F α) (v : (i : Fin n) → F (β i)) (i : Fin n) :
    fcons a v i.succ = cast (by simp [vcons_succ]) (v i)

@[simp]
theorem seqCompose_zero {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = !p[]

theorem degrees_C_mul_le (p : MvPolynomial σ R) (c : R) : (C c * p).degrees ≤ p.degrees

protected lemma errors_are_roots_of_elocPoly {i : ℕ}
  (hi : i < n) (h : f i ≠ p.eval (ωs i)) : (ElocPoly n ωs f p).eval (ωs i) = 0

@[simp]
theorem ConcreteBTField.RingHom_comp_cast {α β γ δ : ℕ}
    (f : ConcreteBTField α →+* ConcreteBTField β)
    (g : ConcreteBTField β →+* ConcreteBTField γ) (h : γ = δ) :
    ((cast (ConcreteBTField.RingHom_eq_of_dest_eq (k:=β) (m:=γ) (n:=δ) h) g).comp f)
    = cast (ConcreteBTField.RingHom_eq_of_dest_eq (k:=α) (m:=γ) (n:=δ) h) (g.comp f)

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

Nat.sub_lt_left_of_lt_add in Init.Data.Nat.Basic

lemma getMiddleBits_lt_two_pow {n offset len : ℕ} :
  getMiddleBits offset len n < 2 ^ len

@[simp]
theorem BTField.RingHom_cast_dest_AdjoinRoot_apply (k m : ℕ)
  (f : BTField k →+* AdjoinRoot (poly m)) (x : BTField k) :
  (cast (BTField.RingHom_eq_of_dest_AdjoinRoot_eq (k:=k) (m:=m)).symm f) x
  = cast (BTField_succ_eq_adjoinRoot m) (f x)

theorem add_assoc (a b c : AssocNat) : (a + b) + c = a + (b + c)

@[simp]
theorem MLE_eval_zeroOne (x : σ → Fin 2) (evals : (σ → Fin 2) → R) :
    MvPolynomial.eval (x : σ → R) (MLE evals) = evals x

theorem oracleVerifier_rbrKnowledgeSoundness [Fintype R] :
    (oracleReduction R deg oSpec).verifier.rbrKnowledgeSoundness init impl
      (inputRelation R deg D) (outputRelation R deg)
        (fun _ => (deg : ℝ≥0) / (Fintype.card R))

@[simp]
theorem drop_all (v : (i : Fin n) → α i) :
    drop n n.le_refl v = fun i => Fin.elim0 (i.cast (Nat.sub_self n))

@[simp]
lemma numFullRounds_dvd_by_2 : 2 ∣ params.numFullRounds

@[simp]
theorem vflatten_splitSum {m : ℕ} {n : Fin m → ℕ} (v : (k : Fin (vsum n)) → α) (k : Fin (vsum n)) :
    vflatten (fun i j => v (embedSum i j)) k = v k

omit [Finite F] in
lemma domain_surjective (i : ℕ) : i ≤ n → Function.Surjective (domain D n i)

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

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

theorem append_right_injective {pSpec : ProtocolSpec m} :
    Function.Injective (@ProtocolSpec.append m n pSpec)

theorem mul_zero (n : ChurchNat α) : mul n zero = zero

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

lemma rateOfLinearCode_eq_div [NeZero n] (inj : Function.Injective α) (h : n ≤ m) :
  rate (ReedSolomon.code ⟨α, inj⟩ n) = n / m

lemma normalizedW_eq_qMap_composition (ℓ R_rate : ℕ) (i : Fin r) :
    normalizedW 𝔽q β i = qCompositionChain 𝔽q β (ℓ:=ℓ) (R_rate:=R_rate) i
</all_available_lemmas>

<local_ctx>
import ArkLib.Data.MvPolynomial.LinearMvExtension

import ArkLib.Data.Polynomial.Interface

import Mathlib.LinearAlgebra.Lagrange

import Mathlib.RingTheory.Henselian

namespace ReedSolomon

open Polynomial NNReal

variable {F : Type*} {ι : Type*} (domain : ι ↪ F)

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

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

variable [Semiring F]

end ReedSolomon

open Polynomial Matrix Code LinearCode

variable {F ι ι' : Type*}
         {C : Set (ι → F)}

noncomputable section

namespace Vandermonde

def nonsquare [Semiring F] (ι' : ℕ) (α : ι → F) : Matrix ι (Fin ι') F :=
  Matrix.of fun i j => (α i) ^ j.1

section

variable [CommRing F] {m n : ℕ} {α : Fin m → F}

section

variable [IsDomain F]

end

end

end Vandermonde

namespace ReedSolomonCode

section

open Finset Function

open scoped BigOperators

variable {ι : Type*} [Fintype ι] [Nonempty ι]
         {F : Type*} [Field F] [Fintype F]

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

open Classical in

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

end

section

variable {deg m n : ℕ} {α : Fin m → F}

section

variable [Semiring F] {p : F[X]}

end

open LinearCode

section

open NNReal

variable [Field F]

end

section

def constantCode {α : Type*} (x : α) (ι' : Type*) [Fintype ι'] : ι' → α := fun _ ↦ x

variable [Semiring F] {x : F} [Fintype ι] {α : ι ↪ F}

end

open Finset in
</local_ctx>

<target_theorem>
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 :=
</target_theorem>

