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>
Eq in Init.Prelude
id in Init.Prelude
BitVec in Init.Prelude
Nat in Init.Prelude
BitVec.cast in Init.Data.BitVec.Basic
BitVec.zero in Init.Data.BitVec.Basic
BitVec.extractLsb in Init.Data.BitVec.Basic
BitVec.extractLsb' in Init.Data.BitVec.Basic
Prod in Init.Prelude
BitVec.ofNat in Init.Prelude

class DCast (α : Sort*) (β : α → Sort*) where
  dcast : ∀ {a a' : α}, a = a' → β a → β a'
  dcast_id : ∀ {a : α}, dcast (Eq.refl a) = id

abbrev SEP_CHAR : Char := Char.ofNat 0

absurd in Init.Prelude

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

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

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

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

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

abbrev SEP_BYTE : String := ⟨[SEP_CHAR]⟩

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

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

Set.range in Mathlib.Data.Set.Operations

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

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

Nat.bodd in Mathlib.Data.Nat.Bits

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

def numPermQueriesChallenge (i : pSpec.ChallengeIdx) : Nat :=
  Nat.ceil ((challengeSize i : ℚ) / SpongeSize.R)

alias Lᵥᵢ := numPermQueriesChallenge

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

noncomputable instance : DecidableEq (GF(2)) :=
  fun x y =>
    
    let φ : GF(2) ≃ₐ[ZMod 2] ZMod 2 := GaloisField.equivZmodP 2
    
    if h : φ x = φ y then
      isTrue (by admit /- proof elided -/
        )
    else
      isFalse (by admit /- proof elided -/
        )

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

CommGroup in Mathlib.Algebra.Group.Defs

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

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

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

def combined : Prop :=
  capacitySegmentDup trace ∨ notFunction trace

alias E := combined

Fin.take in Mathlib.Data.Fin.Tuple.Take

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

abbrev Field := ZMod fieldSize

cast in Init.Prelude

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

AddCommGroup in Mathlib.Algebra.Group.Defs

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

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

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

def NestedList (n : ℕ) : Type := dfoldr' n (fun _ => Type) (fun _ T => List T) Nat

example : NestedList 0 = Nat := rfl
example (n : ℕ) : NestedList (n + 1) = List (NestedList n) := rfl

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

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

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

Quotient.lift in Init.Core

Fintype.ofFinite in Mathlib.Data.Fintype.EquivFin

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

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

Polynomial.toFinsupp in Mathlib.Algebra.Polynomial.Basic

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

@[reducible]
noncomputable def fullOracleProof :
  OracleProof []ₒ
    (Statement := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) 0)
    (OStatement := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ 0)
    (Witness := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) 0)
    (pSpec:=fullPSpec 𝔽q β γ_repetitions (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) :=
  fullOracleReduction 𝔽q β γ_repetitions (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑)

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

MvPolynomial.coeff in Mathlib.Algebra.MvPolynomial.Basic

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

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

Finset.sup in Mathlib.Data.Finset.Lattice.Fold

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

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

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

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

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 modSum {m : ℕ} {n : Fin m → ℕ} (k : Fin (∑ j, n j)) : Fin (n (divSum k)) :=
  ⟨k - ∑ j, n (Fin.castLE (divSum k).isLt.le j), by admit /- proof elided -/
    ⟩

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

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

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 δ

def join {k : ℕ} (h_pos : k > 0) (hi lo : ConcreteBTField (k - 1)) : ConcreteBTField k :=

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

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

HMod.hMod in Init.Prelude

noncomputable instance {R : Type u} [CommSemiring R] : PolynomialLike R R[X] where
  X := Polynomial.X
  eval₂ := Polynomial.eval₂RingHom
  eval₂_C := Polynomial.eval₂_C
  eval₂_X := Polynomial.eval₂_X
  eval₂_eq f := by admit /- proof elided -/

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

Units.val in Mathlib.Algebra.Group.Units.Defs

def Straightline :=
  StmtIn → 
  WitOut → 
  FullTranscript pSpec → 
  QueryLog oSpec → 
  QueryLog oSpec → 
  OracleComp oSpec WitIn 

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

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

alias trivial := OracleContext.Lens.id

noncomputable def evenPart (f : Polynomial F) : Polynomial F :=
    C (2⁻¹ : F) * (f + f.comp (-X))

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

@[reducible]
def OracleStatement (ϑ : ℕ) [NeZero ϑ] (i : Fin (ℓ + 1)) :
    Fin (toOutCodewordsCount ℓ ϑ (i:=i)) → Type := fun j =>
  by admit /- proof elided -/

Algebra.cast in Mathlib.Algebra.Algebra.Defs

NoZeroDivisors in Mathlib.Algebra.GroupWithZero.Defs

def Fin.sumCommEquiv (m : ℕ) (n : ℕ) : Fin (m + n) ≃ (Fin n) ⊕ (Fin m) :=
  (@finSumFinEquiv m n).symm.trans (Equiv.sumComm (Fin m) (Fin n))

instance : Field BaseField := ZMod.instField baseFieldSize

Polynomial.leadingCoeff in Mathlib.Algebra.Polynomial.Degree.Definitions

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

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

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

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

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

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

List.length in Init.Prelude

BitVec.zero in Init.Data.BitVec.Basic

toFun in ToMathlib.Control.Monad.Hom

instance {i : Fin (ℓ / ϑ - 1)} : ∀ j, SelectableType ((pSpecFullNonLastBlock 𝔽q β
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i).Challenge j) := instSelectableTypeChallengeAppend

protected def Prover.id : Prover oSpec Statement Witness Statement Witness !p[] where
  PrvState := fun _ => Statement × Witness
  input := _root_.id
  sendMessage := fun i => Fin.elim0 i
  receiveChallenge := fun i => Fin.elim0 i
  output := pure

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

context in Examples.FrankingProtocol

MonomialOrder.lex in Mathlib.Data.Finsupp.MonomialOrder

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

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

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

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

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

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

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

def line [Ring F] (u v : ι → F) : AffineSubspace F (ι → F) :=
  affineSpan _ {u, v}

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

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

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

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

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

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

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)

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 lastBlockOracleReduction :=
  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 wit := fun i: Fin (ϑ + 1) => Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ)
    ⟨bIdx * ϑ + i, by admit /- proof elided -/
    ⟩
  let V:  OracleReduction []ₒ (StmtIn := Statement (L := L) (ℓ := ℓ) Context
    ⟨bIdx * ϑ, by admit /- proof elided -/
    ⟩)
    (OStmtIn := OracleStatement 𝔽q β ϑ
      ⟨bIdx * ϑ, by admit /- proof elided -/
      ⟩)
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ)
      ⟨bIdx * ϑ, by admit /- proof elided -/
      ⟩)
    (StmtOut := Statement (L := L) (ℓ := ℓ) Context (Fin.last ℓ))
    (OStmtOut := OracleStatement 𝔽q β ϑ (Fin.last ℓ))
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) (Fin.last ℓ))
    (pSpec := pSpecLastBlock (L:=L) (ϑ:=ϑ)) := by admit /- proof elided -/

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₁

MonoidHom in Mathlib.Algebra.Group.Hom.Defs

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

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

@[inline]
def ofInputOnly (projWit : OuterStmtIn × OuterWitIn → InnerWitIn) :
    Witness.Lens OuterStmtIn OuterStmtOut OuterWitIn OuterWitOut InnerWitIn OuterWitOut :=
  ⟨projWit, fun _ => Prod.snd⟩

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

toNat in Mathlib.Computability.Reduce

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

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

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

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

ENNReal in Mathlib.Data.ENNReal.Basic

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

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

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

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

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

Units.mulAction' in Mathlib.Algebra.Group.Action.Units

@[reducible]
noncomputable def fullOracleVerifier :
  OracleVerifier (oSpec:=[]ₒ)
    (StmtIn := Statement (L := L) (ℓ:=ℓ) (SumcheckBaseContext L ℓ) 0)
    (OStmtIn:= OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ 0)
    (StmtOut := Bool)
    (OStmtOut := fun _ : Empty => Unit)
    (pSpec := fullPSpec 𝔽q β γ_repetitions (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)) :=
  OracleVerifier.append (oSpec:=[]ₒ)
    (Stmt₁ := Statement (L := L) (SumcheckBaseContext L ℓ) 0)
    (Stmt₂ := FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
    (Stmt₃ := Bool)
    (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₃ := fun _ : Empty => Unit)
    (pSpec₁ := pSpecCoreInteraction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (pSpec₂ := pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (V₁ := CoreInteraction.coreInteractionOracleVerifier 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ϑ:=ϑ))
    (V₂ := QueryPhase.queryOracleVerifier 𝔽q β γ_repetitions
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ϑ:=ϑ))

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

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

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

@[simp]
abbrev Statement.AfterLinearCombination : Type :=
  LinearCombinationChallenge R × Statement.AfterSendEvalClaim R pp

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

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

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

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

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

IsLinearMap in Mathlib.Algebra.Module.LinearMap.Defs

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

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

instance {k : ℕ} : NatCast (ConcreteBTField k) where
  natCast n:= natCast n

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

Ideal in Mathlib.RingTheory.Ideal.Defs

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

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

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

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

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

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

def toOutCodewordsCount (i : Fin (ℓ + 1)) : ℕ :=

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

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

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

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)

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

@[reducible]
def Witness := Fin sz.n_w → R

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

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

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

Sum.inr in Init.Core

Algebra.algebraMap in Mathlib.Algebra.Algebra.Defs

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

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

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

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

noncomputable def qMap_total_fiber
    
      (i : Fin r) (steps : ℕ) (h_i_add_steps : i.val + steps < ℓ + 𝓡)
        (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by admit /- proof elided -/
        ⟩)) :
    Fin (2 ^ steps) → sDomain 𝔽q β h_ℓ_add_R_rate i :=
  if h_steps : steps = 0 then by
    
    subst h_steps
    simp only [add_zero, Fin.eta] at y
    exact fun _ => y
  else by
    
    let basis_y := sDomain_basis 𝔽q β h_ℓ_add_R_rate (i := ⟨i+steps,by admit /- proof elided -/
    ⟩) (by admit /- proof elided -/
    )
    let y_coeffs : Fin (ℓ + 𝓡 - (↑i + steps)) →₀ 𝔽q := basis_y.repr y

    let basis_x := sDomain_basis 𝔽q β h_ℓ_add_R_rate ⟨i, by admit /- proof elided -/
    ⟩ (by admit /- proof elided -/
    )
    exact fun elementIdx => by admit /- proof elided -/

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

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

noncomputable def matching_set
  (ωs : Fin n ↪ F)
  (δ : ℚ)
  (u₀ u₁ : Fin n → F)
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : Finset F := (exists_a_set_and_a_matching_polynomial k h_gs (δ := δ)).choose

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

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

Nat.bit in Mathlib.Data.Nat.BinaryRec

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

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

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

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

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

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

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

IsEmpty in Mathlib.Logic.IsEmpty

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

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

class LawfulToNat (α : Type u) [ToNat α] [Zero α] [HasSucc α] : Prop where
  toNat_zero : ToNat.toNat (0 : α) = 0
  toNat_succ (n : α) : ToNat.toNat (succ' n) = ToNat.toNat n + 1

Nat.reduceAdd in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat

structure HashStateWithInstructions (U : Type) [SpongeUnit U] (H : Type*)
    [DuplexSpongeInterface U H] where
   
  ds : H
   
  stack : Array DomainSeparator.Op
deriving Inhabited, DecidableEq, Repr

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

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

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

noncomputable def xPoly
  {S : Finset ι} (f : ι → F) (φ : ι ↪ F) (k : ℕ) (x : indexPow S φ k) : Polynomial F :=
  let dom := powFiber S φ k x
  let emb : { y // y ∈ dom } → F := φ ∘ Subtype.val
  let g : { y // y ∈ dom } → F := f ∘ Subtype.val
  Lagrange.interpolate univ emb g

def toMessagesChallenges (transcript : Transcript k pSpec) :
    MessagesUpTo k pSpec × ChallengesUpTo k pSpec :=
  (transcript.toMessagesUpTo, transcript.toChallengesUpTo)

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

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

inductive SkeletonNodeIndex : Skeleton → Type
  | ofLeaf : SkeletonNodeIndex Skeleton.leaf
  | ofInternal {left right} :
      SkeletonNodeIndex (Skeleton.internal left right)
  | ofLeft {left right : Skeleton} (idxLeft : SkeletonNodeIndex left) :
      SkeletonNodeIndex (Skeleton.internal left right)
  | ofRight {left right : Skeleton} (idxRight : SkeletonNodeIndex right) :
      SkeletonNodeIndex (Skeleton.internal left right)

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

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

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

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

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

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

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

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

@[ext]
structure OracleVerifier {ι : Type} (oSpec : OracleSpec ι)
    (StmtIn : Type) {ιₛᵢ : Type} (OStmtIn : ιₛᵢ → Type)
    (StmtOut : Type) {ιₛₒ : Type} (OStmtOut : ιₛₒ → Type)
    {n : ℕ} (pSpec : ProtocolSpec n)
    [Oₛᵢ : ∀ i, OracleInterface (OStmtIn i)]
    [Oₘ : ∀ i, OracleInterface (pSpec.Message i)]
    where
    
    

   
  verify : StmtIn → pSpec.Challenges →
    OracleComp (oSpec ++ₒ ([OStmtIn]ₒ ++ₒ [pSpec.Message]ₒ)) StmtOut

  
  
  

  

   
  embed : ιₛₒ ↪ ιₛᵢ ⊕ pSpec.MessageIdx

   
  hEq : ∀ i, OStmtOut i = match embed i with
    | Sum.inl j => OStmtIn j
    | Sum.inr j => pSpec.Message j

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

Finsupp.equivFunOnFinite in Mathlib.Data.Finsupp.Defs

Subtype in Init.Prelude

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

Except in Init.Prelude

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

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

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

noncomputable def fromRowGenMat [Semiring F] (G : Matrix κ ι F) : LinearCode ι F :=
  LinearMap.range G.vecMulLinear

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

noncomputable instance fintype_U (i : Fin r) : Fintype (U 𝔽q β i) :=

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

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

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

List.findIdx in Init.Data.List.Basic

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

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

Matrix.rank in Mathlib.LinearAlgebra.Matrix.Rank

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

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

Finset.product in Mathlib.Data.Finset.Prod

EquivLike in Mathlib.Data.FunLike.Equiv

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

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

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

instance : Zero AssocNat where
  zero := zero

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

LinearIndepOn in Mathlib.LinearAlgebra.LinearIndependent.Defs

MvPolynomial.degreeOf in Mathlib.Algebra.MvPolynomial.Degrees

abbrev BaseField := ZMod baseFieldSize

OracleComp.construct in VCVio.OracleComp.OracleComp

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

DivisionRing in Mathlib.Algebra.Field.Defs

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

def fiberwiseClose (i : Fin ℓ) (steps : ℕ) [NeZero steps] (h_i_add_steps : i.val + steps ≤ ℓ)
    (f : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      ⟨i, by admit /- proof elided -/
      ⟩) : Prop :=
  2 * fiberwiseDistance 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i) steps
    (h_i_add_steps := h_i_add_steps) (f := f) < (BBF_CodeDistance ℓ 𝓡 ⟨i + steps, by admit /- proof elided -/
    ⟩ : ℕ∞)

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

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

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

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

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

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

Equiv in Mathlib.Logic.Equiv.Defs

def BacktrackSequence.Index (trace : QueryLog (duplexSpongeChallengeOracle StmtIn U))
    (state : CanonicalSpongeState U) (seq : BacktrackSequence trace state) :
    Fin trace.length × (Fin seq.inputState.length → Fin trace.length) :=
  
  
  
  (⟨trace.findIdx sorry, sorry⟩, sorry)

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 instCharP2 {k : ℕ} : CharP (ConcreteBTField k) 2 :=
  charP_eq_2_of_add_self_eq_zero (F:=(ConcreteBTField k)) (sumZeroIffEq:=add_eq_zero_iff_eq)

Module.finrank in Mathlib.LinearAlgebra.Dimension.Finrank

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

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)

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

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

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

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

instance : curve.IsShortNF :=

Algebra.TensorProduct.rightAlgebra in Mathlib.RingTheory.TensorProduct.Basic

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

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

def toNum {R : Type _} [Zero R] [DecidableEq R] (a : Array R) : ℕ :=
  (a.map (fun r => if r = 0 then 0 else 1)).reverse.foldl (fun acc elem => (acc * 2) + elem) 0

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

alias trivial := Witness.Lens.id

Coe in Init.Coe

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

CanLift in Mathlib.Tactic.Lift

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

structure ProverPrivateRng (R : Type*) where
   
  ds : Unit 
   
  csrng : R
deriving Repr

instance : Fact (Nat.Prime (PrimeOrder.p G)) :=
  PrimeOrder.hPrime

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)

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

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

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

OracleSpec.QueryCache in VCVio.OracleComp.QueryTracking.Structures

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

Vector.foldl in Init.Data.Vector.Basic

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

alias «𝒟_Σ» := duplexSpongeHybridOracle

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

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

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

Decidable in Init.Prelude

def stirRelation
    {F : Type} [Field F] [Fintype F] [DecidableEq F]
    {ι : Type} [Fintype ι] [Nonempty ι]
    (degree : ℕ) (φ : ι ↪ F) (err : ℝ)
    : Set ((Unit × ∀ i, (OracleStatement ι F i)) × Unit) :=
  fun ⟨⟨_, oracle⟩, _⟩ => δᵣ(oracle (), ReedSolomon.code φ degree) ≤ err

map_pure in ToMathlib.Control.Monad.Hom

instDecidableEqOfLawfulBEq in Init.Core

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

Finsupp.linearCombination in Mathlib.LinearAlgebra.Finsupp.LinearCombination

@[inline]
def zsmul [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 SpecialElementRelation {F_prev : Type*} [Field F_prev] (t1 : F_prev)
  {F_cur : Type*} [Field F_cur] (u : F_cur) [Algebra F_prev F_cur] : Prop where
    sum_inv_eq : u + u⁻¹ = algebraMap F_prev F_cur t1
    h_u_square : u^2 = u * (algebraMap F_prev F_cur t1) + 1

List.cons in Init.Prelude

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

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

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

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

instance instSelectableTypeChallengePSpec [SelectableType R] :
    ∀ i, SelectableType ((pSpec R deg).Challenge i) :=
  instSelectableTypeChallengeAppend

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

@[inline]
def zero [Zero R] : MlPolyEval R n := Vector.replicate (2 ^ n) 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 }

Nat.reduceBeqDiff in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat

USize in Init.Prelude

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

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

@[ext]
structure ProverState (n : ℕ) where
  PrvState : Fin (n + 1) → Type

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

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)

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

structure Distances (M : ℕ) where
  δ : Fin (M + 1) → ℝ≥0
  l : Fin (M + 1) → ℝ≥0

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

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

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

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

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

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

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

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

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

Array.zipWith in Init.Data.Array.Basic

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 toNat (f : ValidChurchNat) : ℕ :=
  ChurchNat.toNat f.1

RatFunc.eval in Mathlib.FieldTheory.RatFunc.AsPolynomial

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

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

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

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

DFunLike in Mathlib.Data.FunLike.Basic

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

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

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

def principalIdeal {F : Type} [Semiring F] (f : F) : Ideal F := Ideal.span {f}

@[inline, reducible]
def proj : OuterStmtIn × (∀ i, OuterOStmtIn i) → InnerStmtIn × (∀ i, InnerOStmtIn i) :=
  lens.toFunA

Div in Init.Prelude

Polynomial.monomial in Mathlib.Algebra.Polynomial.Basic

HSMul.hSMul in Init.Prelude

HMul.hMul in Init.Prelude

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

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

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

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

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

def intCast {k : ℕ} (n : ℤ) : ConcreteBTField k := if n % 2 = 0 then zero else one

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

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

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 churchOr (p q : ChurchBool α) : ChurchBool α :=
  fun x y => p x (q x y)

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

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

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

EmbeddingLike in Mathlib.Data.FunLike.Embedding

FreeMonad.roll in ToMathlib.Control.Monad.Free

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 }

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

Fin.find in Mathlib.Data.Fin.Tuple.Basic

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

Or.inr in Init.Prelude

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

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

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

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

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

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

Polynomial.mapRingHom in Mathlib.Algebra.Polynomial.Eval.Defs

noncomputable def queryRbrExtractor :
  Extractor.RoundByRound []ₒ
    (StmtIn := (FinalSumcheckStatementOut (L:=L) (ℓ:=ℓ))
      × (∀ j, OracleStatement 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ) j))
    (WitIn := Unit)
    Unit
    (pSpec := pSpecQuery 𝔽q β γ_repetitions (h_ℓ_add_R_rate := h_ℓ_add_R_rate))
    (fun _ => Unit) where
  eqIn := rfl
  extractMid := fun _ _ _ witMidSucc => witMidSucc
  extractOut := fun _ _ _ => ()

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

AdjoinRoot.of in Mathlib.RingTheory.AdjoinRoot

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

gen in VCVio.CryptoFoundations.FiatShamir

instance : ∀ j, OracleInterface ((pSpecFinalSumcheckStep (L := L)).Message j) := fun j =>
  match j with
  | ⟨0, _⟩ => OracleInterface.instDefault

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

@[simp]
def evalDomain (i : ℕ) : Subgroup Fˣ :=
  Subgroup.zpowers (DIsCyclicC.gen ^ (2 ^ i))

CommGroupWithZero in Mathlib.Algebra.GroupWithZero.Defs

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

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

AdjoinRoot.instField in Mathlib.RingTheory.AdjoinRoot

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

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

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

RingHom in Mathlib.Algebra.Ring.Hom.Defs

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

instance instOracleInterfaceMessagePSpec : ∀ i, OracleInterface ((pSpec R deg).Message i) :=
  instOracleInterfaceMessageAppend

noncomputable instance changeOfBasisMatrix_invertible
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  Invertible (changeOfBasisMatrix 𝔽q β ℓ h_ℓ) :=

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

Finset.Iic in Mathlib.Order.Interval.Finset.Defs

Multiset.map in Mathlib.Data.Multiset.MapFold

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

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

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

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

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

Mod.mod in Init.Prelude

Module.Basis.smulTower in Mathlib.RingTheory.AlgebraTower

Multiset.count in Mathlib.Data.Multiset.Count

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

MvPolynomial.C in Mathlib.Algebra.MvPolynomial.Basic

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

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

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

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

instance ConcreteBTField.instDCast_local : DCast ℕ ConcreteBTField where
  dcast h_k_eq term_k1 := BitVec.cast (congrArg (fun n => 2 ^ n) h_k_eq) term_k1
  dcast_id := by admit /- proof elided -/

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

Subgroup in Mathlib.Algebra.Group.Subgroup.Defs

Polynomial.evalEvalRingHom in Mathlib.Algebra.Polynomial.Bivariate

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

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

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

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

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

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

MonadLift in Init.Prelude

Quotient.mk in Init.Core

private noncomputable def E (ωs : Fin n → F)
  (f : Fin n → F) (p : Polynomial F) (e : ℕ) : Polynomial F :=
  X ^ (e - (Δ₀(f, p.eval ∘ ωs) : ℕ)) * ElocPolyF ωs f p

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

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

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

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

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

@[reducible]
def foldCommitOracleReduction (i : Fin ℓ)
    (hCR : isCommitmentRound ℓ ϑ i) :
  OracleReduction []ₒ
    (StmtIn := Statement (L := L) Context i.castSucc)
    (OStmtIn := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc)
    (WitIn := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) i.castSucc)
    (StmtOut := Statement (L := L) Context i.succ)
    (OStmtOut := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.succ)
    (WitOut := Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ) i.succ)
    (pSpec := pSpecFoldCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) :=
  OracleReduction.append (oSpec:=[]ₒ)
    (pSpec₁ := pSpecFold (L:=L))
    (pSpec₂ := pSpecCommit 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i)
    (R₁ := foldOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) i)
    (R₂ := commitOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hCR)

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

@[simp]
abbrev Statement.AfterSecondSumcheck : Type :=
  SecondSumcheckChallenge R pp × Statement.AfterLinearCombination R pp

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

OracleComp.simulateQ in VCVio.OracleComp.SimSemantics.SimulateQ

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

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

Fin.castSuccEmb in Mathlib.Data.Fin.Embedding

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

structure PowTwoRepr where
  two_exp : ℕ
  odd_part : ℕ

def new (domainSeparator : DomainSeparator U H) (nargString : ByteArray) :
    FSVerifierState U H :=
  { hashState := HashStateWithInstructions.new domainSeparator,
    nargString := nargString }

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

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

noncomputable def polynomialFromNovelCoeffsF₂
  (ℓ : ℕ) (h_ℓ : ℓ ≤ r) (a : Fin (2 ^ ℓ) → L) : L⦃<2^ℓ⦄[X] :=
  ⟨polynomialFromNovelCoeffs 𝔽q β ℓ h_ℓ a, by
    simp only [mem_degreeLT, Nat.cast_pow, Nat.cast_ofNat]
    apply (Polynomial.degree_sum_le Finset.univ (fun j => C (a j) * Xⱼ 𝔽q β ℓ h_ℓ j)).trans_lt
    apply (Finset.sup_lt_iff ?_).mpr ?_
    · -- ⊢ ⊥ < 2 ^ ℓ
      exact compareOfLessAndEq_eq_lt.mp rfl
    · -- ∀ b ∈ univ, (C (a b) * Xⱼ 𝔽q β ℓ h_ℓ b).degree < 2 ^ ℓ
      intro j _
      -- ⊢ (C (a j) * Xⱼ 𝔽q β ℓ h_ℓ j).degree < 2 ^ ℓ
      calc (C (a j) * Xⱼ 𝔽q β ℓ h_ℓ j).degree
        _ ≤ (C (a j)).degree + (Xⱼ 𝔽q β ℓ h_ℓ j).degree :=

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

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

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

def relHammingBallInterleavedCode [DecidableEq F] (U : Matrix κ ι F)
  (IC : MatrixSubmodule κ ι F) (r : ℝ) :=
    {V | V ∈ IC ∧ relDistCodewords U V < r}

noncomputable def fixFirstVariablesOfMQP (v : Fin (ℓ + 1))
  (H : MvPolynomial (Fin ℓ) L) (challenges : Fin v → L) : MvPolynomial (Fin (ℓ - v)) L :=
  have h_l_eq : ℓ = (ℓ - v) + v := by rw [Nat.add_comm]; exact (Nat.add_sub_of_le v.is_le).symm
  -- Step 1 : Rename L[X Fin ℓ] to L[X (Fin (ℓ - v) ⊕ Fin v)]
  let finEquiv := finSumFinEquiv (m := ℓ - v) (n := v).symm
  let H_sum : L[X (Fin (ℓ - v) ⊕ Fin v)] :=

Vector.insertIdx in Init.Data.Vector.Basic

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

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

Lean.Name in Init.Prelude

def FinalSumcheckWit := fun (m : Fin (1 + 1)) =>
 match m with
 | ⟨0, _⟩ => Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (Fin.last ℓ)
 | ⟨1, _⟩ => Unit

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)

Fin.castSucc in Init.Data.Fin.Basic

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

instance : Field ScalarField := ZMod.instField scalarFieldSize

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

noncomputable instance (ℓ : Nat) : AddCommGroup (CoeffVecSpace L ℓ) :=

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

Module.Basis.mk in Mathlib.LinearAlgebra.Basis.Basic

Nat.card in Mathlib.SetTheory.Cardinal.Finite

List.finRange in Init.Data.List.FinRange

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
  }

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

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

alias trivial := Witness.InvLens.id

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

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

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

instance [Zero T] [ToNat T] : DecidableRel (@LE.le (Cayley T) _) := fun a b =>
  Nat.decLe (↑a) (↑b)

@[inline] def pow [Zero T] [One T] [ToNat T] (a b : Cayley T) : Cayley T :=
  powNat a ↑b

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

def pow (S : Finset ι) (φ : ι ↪ F) (k : ℕ) : indexPow S φ k ↪ F :=
    Function.Embedding.subtype fun y => y ∈ indexPow S φ k

def finalSumcheckKnowledgeError (m : pSpecFinalSumcheckStep (L := L).ChallengeIdx) :
  ℝ≥0 :=
  match m with
  | ⟨0, h0⟩ => nomatch h0

@[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 : ∀ i, SelectableType ((pSpecSumcheckFold 𝔽q β (ϑ:=ϑ)
  (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).Challenge i) := instSelectableTypeChallengeAppend

ZMod.charP in Mathlib.Data.ZMod.Basic

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

Algebra.id in Mathlib.Algebra.Algebra.Defs

abbrev Field := ZMod fieldSize

Matrix.of in Mathlib.LinearAlgebra.Matrix.Defs

@[inline, reducible]
def toContext :
    Context.Lens (OuterStmtIn × (∀ i, OuterOStmtIn i)) (OuterStmtOut × (∀ i, OuterOStmtOut i))
                (InnerStmtIn × (∀ i, InnerOStmtIn i)) (InnerStmtOut × (∀ i, InnerOStmtOut i))
                OuterWitIn OuterWitOut InnerWitIn InnerWitOut :=
  ⟨lens.stmt, lens.wit⟩

Polynomial.sum in Mathlib.Algebra.Polynomial.Basic

Algebra.TensorProduct.comm in Mathlib.RingTheory.TensorProduct.Maps

structure PublicParams where
  ℓ_m : ℕ
  ℓ_n : ℕ
  ℓ_w : ℕ
  ℓ_w_le_ℓ_n : ℓ_w ≤ ℓ_n := by admit /- proof elided -/

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

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

def concat {k : Fin n} (challenges : ChallengesUpTo k.castSucc pSpec)
    (h : pSpec.dir k = .V_to_P) (chal : pSpec.Challenge ⟨k, h⟩) : ChallengesUpTo k.succ pSpec :=
  fun ⟨i, h⟩ => (concat' (pSpec := pSpec) (fun i hi => challenges ⟨i, hi⟩) (fun _ => chal)) i h

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

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

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

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

Algebra.ofId in Mathlib.Algebra.Algebra.Hom

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

abbrev PermuteDir := Unit ⊕ Unit

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

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

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

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

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

System.FilePath.fileName in Init.System.FilePath

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

RingHomCompTriple in Mathlib.Algebra.Ring.CompTypeclasses

structure ProverInteractionWithOutput {ι : Type} (oSpec : OracleSpec ι) (Output : Type)
    {n : ℕ} (pSpec : ProtocolSpec n) extends
      ProverState n,
      ProverInit (PrvState 0),
      ProverRound oSpec pSpec,
      ProverOutput oSpec Output (PrvState (Fin.last n))

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

Fin.cast in Init.Data.Fin.Basic

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

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

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

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

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

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

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

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

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

OracleSpec in VCVio.OracleComp.OracleSpec

Int in Init.Data.Int.Basic

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

Real in Mathlib.Data.Real.Basic

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

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

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

EDist in Mathlib.Topology.EMetricSpace.Defs

instance irreducible_quadratic_defining_poly_of_traceMap_eq_1
  {F : Type*} [Field F] [Fintype F] [CharP F 2] (s : F) [NeZero s] (k : ℕ)
  (trace_map_prop : TraceMapProperty F s k)
  (fintypeCard : Fintype.card F = 2 ^ (2 ^ k))
  : Irreducible (definingPoly s) :=

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

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

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

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

LinearIndependent in Mathlib.LinearAlgebra.LinearIndependent.Defs

instance Vector.instFintype {α : Type*} {n : ℕ} [VCVCompatible α] : Fintype (Vector α n) :=
  Fintype.ofEquiv _ (Equiv.rootVectorEquivFin).symm

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

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

def ConcreteBTFieldAlgebra {l r : ℕ} (h_le : l ≤ r) :
    Algebra (ConcreteBTField l) (ConcreteBTField r) := instAlgebraTowerConcreteBTF.toAlgebra h_le

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

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

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

LinearMap in Mathlib.Algebra.Module.LinearMap.Defs

tail in ToMathlib.Control.Comonad.Instances

instance : Mul AssocNat where
  mul := mul

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

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

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

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

noncomputable instance {v : ι → F} {s : AffineSubspace F (ι → F)} [Fintype s] :
    Fintype (v +ᵥ s) := Fintype.ofFinite ↥(v +ᵥ s)

class VerifierFirst (pSpec : ProtocolSpec n) [NeZero n] where
  verifier_first' : pSpec.dir 0 = .V_to_P

@[ext]
structure OracleReduction {ι : 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)]
    where
  prover : OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec
  verifier : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec

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

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

NeZero.mk in Init.Data.NeZero

MvPolynomial.support in Mathlib.Algebra.MvPolynomial.Basic

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

def g (n : ℕ) (c : ℕ) (x : ℕ) := (x * x + c) % n

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

instance : _root_.Field Field := ZMod.instField fieldSize

inductive Program where

Invertible in Mathlib.Algebra.Group.Invertible.Defs

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

def getPutativeRoot {s} (idx : BinaryTree.SkeletonLeafIndex s) (leafValue : α)
    (proof : List α) : OracleComp (spec α) α :=
  match proof with
  | [] => return leafValue 
  | siblingBelowRootHash :: restProof => do
    match idx with
    | BinaryTree.SkeletonLeafIndex.ofLeaf =>
      
      
      
      return leafValue
    | BinaryTree.SkeletonLeafIndex.ofLeft idxLeft =>
      
      let ancestorBelowRootHash ← getPutativeRoot idxLeft leafValue restProof
      singleHash ancestorBelowRootHash siblingBelowRootHash
    | BinaryTree.SkeletonLeafIndex.ofRight idxRight =>
      
      let ancestorBelowRootHash ← getPutativeRoot idxRight leafValue restProof
      singleHash siblingBelowRootHash ancestorBelowRootHash

@[reducible]
def pSpec : ProtocolSpec (Fin.vsum (fun _ : Fin n => 2)) :=
  ProtocolSpec.seqCompose (fun _ => SingleRound.pSpec R deg)

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

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

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

LinearOrder in Mathlib.Order.Defs.LinearOrder

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

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

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

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

def Prover.append (P₁ : Prover oSpec Stmt₁ Wit₁ Stmt₂ Wit₂ pSpec₁)
    (P₂ : Prover oSpec Stmt₂ Wit₂ Stmt₃ Wit₃ pSpec₂) :
      Prover oSpec Stmt₁ Wit₁ Stmt₃ Wit₃ (pSpec₁ ++ₚ pSpec₂) where

   
  PrvState := Fin.append (m := m + 1) P₁.PrvState (Fin.tail P₂.PrvState) ∘ Fin.cast (by admit /- proof elided -/
  )

   
  input := fun ctxIn => by admit /- proof elided -/

protected def cast (R : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec₁) :
    Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec₂ where
  prover := R.prover.cast hn hSpec
  verifier := R.verifier.cast hn hSpec

def joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) : Fin (2 ^ (m+n)) :=
  ⟨(high.val <<< n) ||| low.val, by admit /- proof elided -/
  ⟩

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

Fin in Init.Prelude

protected def Verifier.id : Verifier oSpec Statement Statement !p[] where
  verify := fun stmt _ => pure stmt

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

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 powAlgHom :
  MvPolynomial (Fin m) F →ₐ[F] Polynomial F :=
   aeval fun j => Polynomial.X ^ (2 ^ (j : ℕ))

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

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

structure ModifiedGuruswami
  (m n k : ℕ)
  (ωs : Fin n ↪ F)
  (Q : F[Z][X][Y])
  (u₀ u₁ : Fin n → F)
  where
  Q_ne_0 : Q ≠ 0
   
  Q_deg : natWeightedDegree Q 1 k < D_X ((k + 1) / (n : ℚ)) n m
   
  Q_multiplicity : ∀ i, rootMultiplicity Q
              (Polynomial.C <| ωs i)
              ((Polynomial.C <| u₀ i) + Polynomial.X * (Polynomial.C <| u₁ i))
            ≥ m
   
  Q_deg_X :
    degreeX Q < D_X ((k + 1) / (n : ℚ)) n m
   
  Q_D_Y :
    D_Y Q < D_X (k + 1 / (n : ℚ)) n m / k
   
  Q_D_YZ :
    D_YZ Q ≤ n * (m + 1/(2 : ℚ))^3 / (6 * Real.sqrt ((k + 1) / n))

Fin.snoc in Mathlib.Data.Fin.Tuple.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

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

@[simp]
abbrev Statement.AfterFirstMessage : Type := Statement R pp

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

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

alias E_prp := collisionPerm

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 OracleProver.addSalt (P : OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec)
    (saltComp : (i : pSpec.MessageIdx) → P.PrvState i.1.castSucc → OracleComp oSpec (Salt i)) :
  OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut (pSpec.addSalt Salt) :=
  Prover.addSalt Salt P saltComp

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

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

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

Function.Injective2 in Mathlib.Logic.Function.Basic

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] × ℤ

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

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)

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

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

@[reducible]
def twoAdicity : Nat := 24

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

@[reducible, inline, specialize]
def MessagesUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) : Type :=
  ∀ i, pSpec.MessageUpTo k i

@[reducible, simp]
def relIn : Set (Statement × Unit) := { ⟨stmt, _⟩ | pred stmt }

ConvexOn in Mathlib.Analysis.Convex.Function

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

PFunctor in Mathlib.Data.PFunctor.Univariate.Basic

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

abbrev BTF₃ := ConcreteBTField 3 

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

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

instance {pSpec : ProtocolSpec n} {Statement : Type} [∀ i, VCVCompatible (pSpec.Challenge i)] :
    OracleSpec.FiniteRange (srChallengeOracle Statement pSpec) where
  range_inhabited' := fun i => by admit /- proof elided -/

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

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

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

Module.Basis in Mathlib.LinearAlgebra.Basis.Defs

liftM in Init.Prelude

Finset.Iio in Mathlib.Order.Interval.Finset.Defs

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

UInt8.size in Init.Prelude

noncomputable def distToCode [LinearOrder α] [Zero α]
                             (w : ι → F) (C : Set (ι → F))
                             (δf : (ι → F) → (ι → F) → α)
                             (h : (possibleDistsToCode w C δf).Finite) : WithTop α :=
  haveI := @Fintype.ofFinite _ h
  (possibleDistsToCode w C δf).toFinset.min

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

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

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

DecidableRel in Init.Prelude

noncomputable def decode : (ReedSolomon.code domain deg) →ₗ[F] F[X] :=
  domRestrict
    (interpolate (domain := domain))
    (ReedSolomon.code domain deg)

def PowerType (n : ℕ) : Type := dfoldr' n (fun _ => Type) (fun _ T => T → T) Nat


example : PowerType 0 = Nat := rfl
example (n : ℕ) : PowerType (n + 1) = (PowerType n → PowerType n) := rfl

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

Ring in Mathlib.Algebra.Ring.Defs

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

instance [NeZero k] {f : Fin k → ι → F} : Nonempty (Finset.univ.image f) :=

def localized_fold_eval (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i + steps ≤ ℓ)
    (f : (sDomain 𝔽q β h_ℓ_add_R_rate)
      ⟨i, by exact Nat.lt_of_le_of_lt (n := i) (k := r) (m := ℓ) (h₁ := by
        exact Fin.is_le') (by exact lt_of_add_right_lt h_ℓ_add_R_rate)⟩ → L)
    (r_challenges : Fin steps → L)
    (y : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨↑i + steps, by omega⟩) : L :=

def OracleReduction.liftContext
    (lens : OracleContext.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                              OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut
                              OuterWitIn OuterWitOut InnerWitIn InnerWitOut)
    (R : OracleReduction oSpec InnerStmtIn InnerOStmtIn InnerWitIn
                            InnerStmtOut InnerOStmtOut InnerWitOut pSpec) :
      OracleReduction oSpec OuterStmtIn OuterOStmtIn OuterWitIn
                      OuterStmtOut OuterOStmtOut OuterWitOut pSpec where
  prover := R.prover.liftContext lens
  verifier := R.verifier.liftContext lens.stmt

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

Polynomial.degreeLTEquiv in Mathlib.RingTheory.Polynomial.Basic

inductive ScalarOp where | add | sub | mul | div

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

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

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

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 getRoot {n : ℕ} (cache : Cache α n) : α :=
  (cache 0).get ⟨0, by admit /- proof elided -/
  ⟩

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

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 }

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

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

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

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

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

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

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

UInt64.ofFin in Init.Data.UInt.Basic

List.repr in Init.Data.Repr

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

Nat.reducePow in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat

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

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

System.FilePath in Init.System.FilePath

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

def forwardPermutationOracleImpl {α : Type*} [Permute α] :
    QueryImpl (forwardPermutationOracle α) Id where
  impl | query () q => Permute.permute (α := α) 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⟩, ())

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

class ProverOnly (pSpec : ProtocolSpec 1) extends ProverFirst pSpec

 
alias NonInteractive := ProverOnly

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

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

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

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

IntCast in Init.Data.Int.Basic

noncomputable def commSEquiv : Right ⊗[K] Left ≃ₗ[Right] Left ⊗[K] Right :=
  { Algebra.TensorProduct.comm K Right Left with
    map_smul' := fun s x => by admit /- proof elided -/
      | zero =>
        simp only [AlgEquiv.toEquiv_eq_coe, smul_zero, Equiv.toFun_as_coe, EquivLike.coe_coe,
          map_zero, RingHom.id_apply];
      | tmul s' m =>
        simp only [AlgEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, RingHom.id_apply,
          Algebra.TensorProduct.comm_tmul];
          
          exact comm_map_smul_tmul (Right:=Right) (Left:=Left) s s' m
      | add x y hx hy =>
        simp only [AlgEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, RingHom.id_apply,
          smul_add,
          map_add] at *
        exact comm_map_smul_add (Right:=Right) (Left:=Left) s x y hx hy
   }

NNRat.castRec in Mathlib.Algebra.Field.Defs

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

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

instance {U : Type} {H : Type*} [SpongeUnit U] [DuplexSpongeInterface U H] :
    UnitTranscript (FSVerifierState U H) U where
  publicUnits state input := do
    let newHashState ← state.hashState.absorb input
    .ok { hashState := newHashState, nargString := state.nargString }
  fillChallengeUnits state count := do
    let (newHashState, output) ← state.hashState.squeeze count
    .ok ({ hashState := newHashState, nargString := state.nargString }, output)

Neg in Init.Prelude

IsField in Mathlib.Algebra.Field.IsField

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

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

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

Inv in Init.Prelude

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

setOf in Mathlib.Data.Set.Defs

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

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}

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

def oracleVerifier : OracleVerifier oSpec Statement OStatement Unit (OStatement ⊕ᵥ OStatement)
    (pSpec OStatement) where

  verify := fun stmt _ => relComp stmt

  embed := sorry

  hEq := sorry

hammingDist in Mathlib.InformationTheory.Hamming

Polynomial.erase in Mathlib.Algebra.Polynomial.Basic

noncomputable def toMvPolynomialAlgEquiv : P ≃ₐ[R] MvPolynomial σ R where
  toFun := toMvPolynomialAlgHom
  invFun := ofMvPolynomialAlgHom
  left_inv p := by admit /- proof elided -/

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

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 relOut : Set ((Unit × (∀ i, (Sum.elim OStatement OStatement) i)) × Unit) :=
  setOf (fun ⟨⟨(), oracles⟩, _⟩ => oracles (.inl default) = oracles (.inr default))

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

Equiv.toEmbedding in Mathlib.Logic.Embedding.Basic

class GenMutualCorrParams (S : Finset ι) (φ : ι ↪ F) (k : ℕ) where
  m : ℕ

  inst1 : ∀ i : Fin (k + 1), Fintype (indexPowT S φ i)
  inst2 : ∀ i : Fin (k + 1), Nonempty (indexPowT S φ i)
  inst3 : ∀ i : Fin (k + 1), DecidableEq (indexPowT S φ i)

  φ_i : ∀ i : Fin (k + 1), (indexPowT S φ i) ↪ F
  inst4 : ∀ i : Fin (k + 1), Smooth (φ_i i)

  parℓ_type : ∀ _ : Fin (k + 1), Type
  inst5 : ∀ i : Fin (k + 1), Fintype (parℓ_type i)

  exp : ∀ i : Fin (k + 1), (parℓ_type i) ↪ ℕ

  Gen_α : ∀ i : Fin (k + 1), ProximityGenerator (indexPowT S φ i) F :=
    fun i => RSGenerator.genRSC (parℓ_type i) (φ_i i) (m - i) (exp i)
  inst6 : ∀ i : Fin (k + 1), Fintype (Gen_α i).parℓ

  BStar : ∀ i : Fin (k + 1), (Set (indexPowT S φ i → F)) → Type → ℝ≥0
  errStar : ∀ i : Fin (k + 1), (Set (indexPowT S φ i → F)) → Type → ℝ → ENNReal

  h : ∀ i : Fin (k + 1), hasMutualCorrAgreement (Gen_α i)
                                             (BStar i (Gen_α i).C (Gen_α i).parℓ)
                                             (errStar i (Gen_α i).C (Gen_α i).parℓ)

  hcard : ∀ i : Fin (k + 1), Fintype.card ((Gen_α i).parℓ) = 2
  hcard' : ∀ i : Fin (k + 1), Fintype.card (parℓ_type i) = 2

@[reducible, simp] def WitIn := Unit

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

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

Functor in Init.Prelude

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

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

instance : IsCyclic G :=
  isCyclic_of_prime_card PrimeOrder.hCard

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

PMF.uniformOfFintype in Mathlib.Probability.Distributions.Uniform

PFunctor.Lens in ToMathlib.PFunctor.Basic

instance : HasSucc (Cayley T) where
  succ' := succ

abbrev ScalarField := ZMod SCALAR_FIELD_CARD

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

def β (R : F[X][X][Y]) (t : ℕ) : 𝒪 H :=
  (β_regular R H (Nat.le_refl _) t).choose

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

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

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

Xor' in Mathlib.Logic.Basic

instance {i : Fin (k + 1)} : ∀ j, OracleInterface (OracleStatement D x s i j) :=
  fun _ => inferInstance

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

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

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

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

OneMemClass in Mathlib.Algebra.Group.Submonoid.Defs

DecidablePred in Init.Prelude

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

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

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 

MulOneClass in Mathlib.Algebra.Group.Defs

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

def mkLastOracleIndex (i : Fin (ℓ + 1)) : Fin (toOutCodewordsCount ℓ ϑ i) :=

IsScalarTower in Mathlib.Algebra.Group.Action.Defs

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

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

instance : ∀ j, OracleInterface ((pSpecRelay).Message j)
  | ⟨x, h⟩ => by admit /- proof elided -/

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

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

structure ParamConditions (P : Params ι F) where
  h_deg : ∃ k : ℕ, P.deg = 2^k
  h_foldingParams : ∀ i : Fin (M + 1), ∃ k : ℕ, (P.foldingParam i) = 2^k
  h_deg_ge : P.deg ≥ ∏ i : Fin (M + 1), (P.foldingParam i)
  h_smooth : ∀ i : Fin (M + 1), Smooth (P.φ i)
  h_smooth_le : ∀ i : Fin (M + 1), Fintype.card (ι i) ≤ (degree ι P i)
  h_repeatP_le : ∀ i : Fin (M + 1), P.repeatParam i + 1 ≤ (degree ι P i)

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

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

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

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

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

@[reducible]
def BASE_FIELD_CARD : Nat := 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f

/- Alternative representation -/
example : BASE_FIELD_CARD = 2 ^ 256 - 2 ^ 32 - 2 ^ 9 - 2 ^ 8 - 2 ^ 7 - 2 ^ 6 - 2 ^ 4 - 1 :=

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

Submodule in Mathlib.Algebra.Module.Submodule.Defs

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

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

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

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

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

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

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

protected def OracleVerifier.id :
    OracleVerifier oSpec Statement OStatement Statement OStatement !p[] where
  verify := fun stmt _ => pure stmt
  embed := Function.Embedding.inl
  hEq := fun _ => rfl

Bool in Init.Prelude

noncomputable def weight_Λ_over_𝒪 {H : F[X][Y]} (f : 𝒪 H) (D : ℕ)
  : WithBot ℕ := weight_Λ (canonicalRepOf𝒪 f) H D

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

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

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

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

Polynomial.ofFinsupp in Mathlib.Algebra.Polynomial.Basic

def constantCode {α : Type*} (x : α) (ι' : Type*) [Fintype ι'] : ι' → α := fun _ ↦ x

MvPolynomial.sumToIter in Mathlib.Algebra.MvPolynomial.Equiv

Nat.decEq in Init.Prelude

DivisionSemiring in Mathlib.Algebra.Field.Defs

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

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

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}

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

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

BitVec.xor in Init.Data.BitVec.Basic

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

def run (adversary : Adversary ι G p bitLength α) (table : GroupValTable ι G) : List G × α :=
  sorry

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

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

def getHighBits_no_shl (numLowBits : ℕ) (n : ℕ) : ℕ := n >>> numLowBits

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

MvPolynomial.monomial in Mathlib.Algebra.MvPolynomial.Basic

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

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

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

AlternativeMonad in Batteries.Control.AlternativeMonad

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

instance {pSpec : ProtocolSpec n} {Statement : Type}
    [DecidableEq Statement]
    [∀ i, DecidableEq (pSpec.Message i)]
    [∀ i, DecidableEq (pSpec.Challenge i)] :
    OracleSpec.DecidableEq (srChallengeOracle Statement pSpec) where
  domain_decidableEq' := fun i => by admit /- proof elided -/

def take (j : Fin (k + 1)) (messages : MessagesUpTo k pSpec) :
    MessagesUpTo (j.castLE (by admit /- proof elided -/
    )) pSpec :=
  fun i => messages ⟨i.val.castLE (by admit /- proof elided -/
  ), i.property⟩

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

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

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

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

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

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

Polynomial.support in Mathlib.Algebra.Polynomial.Basic

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

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

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

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

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

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

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

Polynomial.mapAlgEquiv in Mathlib.Algebra.Polynomial.AlgebraMap

UInt32 in Init.Prelude

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

instance : OracleInterface (Witness R pp) where
  Query := Fin pp.ℓ_w → R
  Response := R
  answer := fun 𝕨 evalPoint => (MLE (𝕨 ∘ finFunctionFinEquiv)) ⸨evalPoint⸩

def lintStyle : Cmd := `[Cli|
  «lint-style» VIA lintStyleCli; ["0.0.1"]
  "Run text-based style linters on every Lean file in Mathlib/, Archive/ and Counterexamples/.
  Print errors about any unexpected style errors to standard output."

  FLAGS:
    github;     "Print errors in a format suitable for github problem matchers\n\
                 otherwise, produce human-readable output"
    fix;        "Automatically fix the style error, if possible"
]

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

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

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

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

toList in ToMathlib.ProbabilityTheory.FinRatPMF

def pred (n : ChurchNat α) : ChurchNat α := sorry

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

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

CommSemiring in Mathlib.Algebra.Ring.Defs

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

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

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

Mul in Init.Prelude

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

MvPolynomial.totalDegree in Mathlib.Algebra.MvPolynomial.Degrees

def toNat (n : ChurchNat ℕ) : ℕ := n Nat.succ 0

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

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

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

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

List.Vector.cons in Mathlib.Data.Vector.Defs

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

Ideal.Quotient.mk in Mathlib.RingTheory.Ideal.Quotient.Defs

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

def last_nonzero_prop {p : UniPoly R} (k : Fin p.size) : Prop :=
  p[k] ≠ 0 ∧ (∀ j, (hj : j < p.size) → j > k → p[j] = 0)

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

@[inline, specialize]
def add_raw (p q : UniPoly R) : UniPoly R :=
  let ⟨p', q'⟩ := Array.matchSize p q 0
  .mk (Array.zipWith (· + ·) p' q' )

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

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

WithTop in Mathlib.Order.TypeTags

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

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

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

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

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

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

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

@[reducible]
def sumcheckFoldOracleReduction :=
  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 wit := fun i: Fin (ℓ / ϑ - 1 + 1) =>
    Witness (L := L) 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (ℓ:=ℓ)
      ⟨i * ϑ, blockIdx_mul_ϑ_lt_ℓ_succ i⟩
  let nonLastBlocksOracleReduction :=
  OracleReduction.seqCompose (oSpec := []ₒ)
      (Stmt := stmt)
      (OStmt := oStmt) (Wit := wit)
      (pSpec := fun (bIdx: Fin (ℓ / ϑ - 1)) => pSpecFullNonLastBlock 𝔽q β bIdx)
      (R := fun bIdx => nonLastBlockOracleReduction (L:=L) 𝔽q β (ϑ:=ϑ) (𝓑:=𝓑) (bIdx:=bIdx))

  let lastOracleReduction := lastBlockOracleReduction 𝔽q β (ϑ:=ϑ) (𝓑:=𝓑)

  let coreInteractionOracleReduction: OracleReduction []ₒ
    (StmtIn := Statement (L := L) (ℓ := ℓ) Context 0)
    (OStmtIn := OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ 0)
    (WitIn := Witness (L := L) 𝔽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 ℓ))
    (WitOut := Witness (L := L) 𝔽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 -/

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

  input := id

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

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

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

def natCast {k : ℕ} (n : ℕ) : ConcreteBTField k := if n % 2 = 0 then zero else one

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

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

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

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

Nat.mod in Init.Prelude

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)

instance : ∀ i, OracleInterface (Message !p[] i) :=
  fun ⟨i, h⟩ =>
    (Fin.elim0 i : (h' : !p[].dir i = .P_to_V) → OracleInterface (!p[].Message ⟨i, h'⟩)) h

Array.size in Init.Prelude

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

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

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

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

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

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

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

def weightConstraint
  (f : MvPolynomial (Fin m) F)
  (w : MvPolynomial (Fin (m + 1)) F) (σ : F) : Prop :=
    ∑ b : Fin m → Fin 2 , w.eval (toWeightAssignment f b) = σ

Unique in Mathlib.Logic.Unique

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

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

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

Classical.typeDecidableEq in Init.Classical

@[reducible, inline, specialize]
def ChallengesUpTo (k : Fin (n + 1)) (pSpec : ProtocolSpec n) : Type :=
  ∀ i, (pSpec.take k k.is_le).Challenge i

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

MvPolynomial.restrictDegree in Mathlib.RingTheory.MvPolynomial.Basic

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

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

PMF in Mathlib.Probability.ProbabilityMassFunction.Basic

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

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

  return ⟨two_exp, odd_part⟩

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

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

def three : ChurchNat α := succ two

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

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

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

  
  
  verify := fun stmtIn pSpecChallenges => do
    pure stmtIn

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

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

@[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 Function.interleave₂ {α β : Type*} (u v : α → β) : (Fin 2) × α → β :=
  Function.uncurry (fun a => if a = 0 then u else v)

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

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

class SmoothPowerOfTwo (n : ℕ) (G : Type) [Pow G ℤ] [Monoid G] [inst : IsCyclicWithGen G] where
  smooth : orderOf inst.gen = 2 ^ n

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)

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

Finset.range in Mathlib.Data.Finset.Range

def Fin2ToF2 (𝔽q : Type*) [Ring 𝔽q] (k : Fin 2) : 𝔽q :=
  if k = 0 then 0 else 1

class IsKnowledgeSound (relIn : Set (StmtIn × WitIn)) (relOut : Set (StmtOut × WitOut))
    (verifier : Verifier oSpec StmtIn StmtOut pSpec) where
  knowledgeError : ℝ≥0
  is_knowledge_sound : knowledgeSoundness init impl relIn relOut verifier knowledgeError

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

Fintype.piFinset in Mathlib.Data.Fintype.Pi

@[reducible]
def scalarFieldSize : Nat :=
  21888242871839275222246405745257275088548364400416034343698204186575808495617

BitVec.ofNat in Init.Prelude

Nat.cast in Init.Data.Cast

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

ToString in Init.Data.ToString.Basic

Polynomial.C in Mathlib.Algebra.Polynomial.Basic

OneHom in Mathlib.Algebra.Group.Hom.Defs

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

Field in Mathlib.Algebra.Field.Defs

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

Fin.isEmpty' in Mathlib.Logic.IsEmpty

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

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

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

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

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

@[elab_as_elim] def Fin.predRecOnSameFinType {motive : Fin r → Sort _}
    (last : motive (⟨r - 1, by
      have h_r_ne_0: r ≠ 0 := by exact NeZero.ne r
      omega
    ⟩ : Fin r))
    (succ : ∀ i : Fin r, i.val > 0 → motive i → motive (⟨i.val - 1, by omega⟩ : Fin r))
    (i : Fin r): motive i :=

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

noncomputable def embeddingOf𝒪Into𝕃 (H : F[X][Y]) : 𝒪 H →+* 𝕃 H :=
  Ideal.quotientMap
        (I := Ideal.span {H_tilde' H}) (Ideal.span {H_tilde H})
        bivPolyHom sorry

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

noncomputable def Xⱼ (ℓ : ℕ) (h_ℓ : ℓ ≤ r) (j : Fin (2 ^ ℓ)) : L[X] :=
  (Finset.univ : Finset (Fin ℓ)).prod
    (fun i => (normalizedW 𝔽q β (Fin.castLE h_ℓ i))^(Nat.getBit i j))

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

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

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

PowerSeries.mk in Mathlib.RingTheory.PowerSeries.Basic

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

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

Nat.iterate in Mathlib.Logic.Function.Iterate

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

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

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

noncomputable def decodeLT : (ReedSolomon.code domain deg) →ₗ[F] (Polynomial.degreeLT F deg) :=
  codRestrict
    (Polynomial.degreeLT F deg)
    decode
    (fun c => decoded_polynomial_lt_deg c)

@[reducible]
def OracleStatement := fun _ : MatrixIdx => Matrix (Fin sz.m) (Fin sz.n) R

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

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

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

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

Polynomial.coeff in Mathlib.Algebra.Polynomial.Basic

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

tag in Examples.FrankingProtocol

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

  
  
  verify := fun stmtIn pSpecChallenges => do
    
    let h_i : L⦃≤ 2⦄[X] ← query (spec := [(pSpecFold (L := L)).Message]ₒ)
      ⟨0, rfl⟩ ()

    
    let sumcheck_check := h_i.val.eval 0 + h_i.val.eval 1 = stmtIn.sumcheck_target
    unless sumcheck_check do
      
      let dummyStmt : Statement (L := L) Context i.succ := {
        ctx := stmtIn.ctx,
        sumcheck_target := 0,
        challenges := Fin.snoc stmtIn.challenges 0
      }
      return dummyStmt

    
    let r_i' : L := pSpecChallenges ⟨1, rfl⟩  

    
    let stmtOut : Statement (L := L) Context i.succ := {
      ctx := stmtIn.ctx,
      sumcheck_target := h_i.val.eval r_i',
      challenges := Fin.snoc stmtIn.challenges r_i'
    }

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

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

def fork : Prop :=
  
  trace = [] ∧ state = 0

alias E_fork := fork

noncomputable def fieldTo𝕃 {H : F[X][Y]} : F →+* 𝕃 H :=
  RingHom.comp liftToFunctionField Polynomial.C

instance {n : ℕ} : ∀ j, SelectableType ((pSpecFoldRelaySequence (L:=L) n).Challenge j) :=
  instSelectableTypeChallengeSeqCompose

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

OracleComp.neverFailsWhen in VCVio.OracleComp.Traversal

Polynomial.degree in Mathlib.Algebra.Polynomial.Degree.Definitions

ByteArray.empty in Init.Prelude

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

CommMonoidWithZero in Mathlib.Algebra.GroupWithZero.Defs

def powMod (a b m : ℕ) : ℕ := Id.run do
  let mut x := a
  let mut n := b
  let mut res := 1

  while n > 0 do
    if n % 2 == 1 then
      res := (x * res) % m
    x := (x * x) % m
    n := n / 2

  return res

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

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

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

GroupWithZero in Mathlib.Algebra.GroupWithZero.Defs

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

List.mapM in Init.Data.List.Control

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

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

def 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 

@[reducible]
def scalarFieldSize : Nat :=
  8444461749428370424248824938781546531375899335154063827935233455917409239041

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

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

def 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 : Fact (Nat.Prime scalarFieldSize) := ⟨ScalarField_is_prime⟩

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

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)

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

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

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

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

Lean.PrettyPrinter.Unexpander in Init.Prelude

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

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)

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)

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

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

class PolynomialLike (R : outParam (Type u)) [CommSemiring R] (P : Type v) [CommSemiring P]
    extends Algebra R P where

   
  X {R} : P

   
  eval₂ {S : Type w} [CommSemiring S] (f : R →+* S) (x : S) : P →+* S

  eval₂_C {r : R} {S : Type w} [CommSemiring S] (f : R →+* S) (x : S) :
    (eval₂ f x) (_root_.algebraMap R P r) = f r

  eval₂_X {S : Type w} [CommSemiring S] (f : R →+* S) (x : S) : eval₂ f x X = x

  eval₂_eq {S : Type w} [CommSemiring S] (g : P →+* S) :
    g = eval₂ (g.comp (Algebra.ofId R P)) (g X)

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)

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

Function.Surjective in Init.Data.Function

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

Array.mk in Init.Prelude

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

Mathlib.Meta.NormNum.mkOfNat in Mathlib.Tactic.NormNum.Result

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

def weight_Λ (f H : F[X][Y]) (D : ℕ) : WithBot ℕ :=
  Finset.sup
    f.support
    (fun deg =>
      WithBot.some <| deg * (D + 1 - Bivariate.natDegreeY H) + (f.coeff deg).natDegree
    )

noncomputable def fiber_coeff
    (i : Fin r) (steps : ℕ)
    (j : Fin (ℓ + 𝓡 - i)) (elementIdx : Fin (2 ^ steps))
    (y_coeffs : Fin (ℓ + 𝓡 - (i + steps)) →₀ 𝔽q) : 𝔽q :=
  if hj : j.val < steps then
    if Nat.getBit (k := j) (n := elementIdx) = 0 then 0 else 1
  else y_coeffs ⟨j.val - steps, by admit /- proof elided -/
    ⟩

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 getFirstOracle {i : Fin (ℓ + 1)}
    (oStmt : (∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i j)) :
    sDomain 𝔽q β h_ℓ_add_R_rate 0 → L :=

Finset.map in Mathlib.Data.Finset.Image

inferInstanceAs in Init.Prelude

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

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

OracleSpec.FiniteRange in VCVio.OracleComp.OracleSpec

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

instance : Field ScalarField := ZMod.instField scalarFieldSize

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

class DFunEquiv (F : Sort*) (α : outParam (Sort*)) (β : outParam <| α → Sort*) where
  equiv : F ≃ ∀ a : α, β a

invFun in ToMathlib.Control.Monad.Equiv

NatCast in Init.Data.Cast

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

multiplicity in Mathlib.RingTheory.Multiplicity

def isCompliant (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 -/
  ⟩)
  (f_i_plus_steps : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      ⟨i + steps, by admit /- proof elided -/
      ⟩)
  (challenges : Fin steps → L) : Prop :=
  ∃ (h_fw_dist_lt : 2 * fiberwiseDistance 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i)
      (steps := steps) h_i_add_steps f_i < (BBF_CodeDistance ℓ 𝓡 ⟨i + steps, by admit /- proof elided -/
      ⟩ : ℕ∞))
    (h_dist_next_lt : 2 * distFromCode f_i_plus_steps
      (BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i + steps, by admit /- proof elided -/
      ⟩)
      < (BBF_CodeDistance ℓ 𝓡 ⟨i + steps, by admit /- proof elided -/
      ⟩ : ℕ∞)), 
    
    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 h_i_add_steps f_i
      (h_fw_dist_lt := h_fw_dist_lt)
    let f_bar_i := uniqueClosestCodeword 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (i := ⟨i, by admit /- proof elided -/
      ⟩) (h_i := fin_ℓ_lt_ℓ_add_R i) f_i h_dist_curr_lt
    let f_bar_i_plus_steps := uniqueClosestCodeword 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := ⟨i + steps, by admit /- proof elided -/
      ⟩)
      (h_i := fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps)
      f_i_plus_steps h_dist_next_lt
    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 = f_bar_i_plus_steps

instance instAlgebraTowerConcreteBTF : AlgebraTower (ConcreteBTField) where
  algebraMap := concreteTowerAlgebraMap
  commutes' := by admit /- proof elided -/

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

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

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)

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

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

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

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

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

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

Vector.ofFn in Init.Data.Vector.Basic

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

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

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

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

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

def 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 : ℕ∞)

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

Prod.mk in Init.Prelude

class GenMutualCorrParams (P : Params ι F) (S : ∀ i : Fin (M + 1), Finset (ι i)) where

  δ : Fin (M + 1) → ℝ≥0
  dist : (i : Fin (M + 1)) → Fin ((P.foldingParam i) + 1) → ℝ≥0


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

  inst1 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (indexPowT (S i) (P.φ i) j)
  inst2 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    Nonempty (indexPowT (S i) (P.φ i) j)
  inst3 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    DecidableEq (indexPowT (S i) (P.φ i) j)
  inst4 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Smooth (φ i j)

  parℓ_type : ∀ i : Fin (M + 1), ∀ _ : Fin ((P.foldingParam i) + 1), Type
  inst5 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (parℓ_type i j)

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



  Gen_α : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    ProximityGenerator (indexPowT (S i) (P.φ i) j) F :=
      fun i j => RSGenerator.genRSC (parℓ_type i j) (φ i j) (P.varCount i - j) (exp i j)

  inst6 : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1), Fintype (Gen_α i j).parℓ

  BStar : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    (Set ((indexPowT (S i) (P.φ i) j) → F)) → Type → ℝ≥0
  errStar : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    (Set ((indexPowT (S i) (P.φ i) j) → F)) → Type → ℝ → ENNReal

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

  h : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    hasMutualCorrAgreement (Gen_α i j)
      (BStar i j (C i j) (Gen_α i j).parℓ)
      (errStar i j (C i j) (Gen_α i j).parℓ)

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

  hδLe : ∀ i : Fin (M + 1),
    (δ i) ≤ 1 - Finset.univ.sup (fun j => BStar i j (C i j) (Gen_α i j).parℓ)

  hlistDecode : ∀ i : Fin (M + 1), ∀ j : Fin ((P.foldingParam i) + 1),
    listDecodable (C i j) (δ i) (dist i j)

def 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

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

def vconcat {n : ℕ} (v : Fin n → α) (a : α) : Fin (n + 1) → α :=
  dconcat v a

class Extractor.Lens.IsKnowledgeSound
    {OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut : Type}
    {OuterWitIn OuterWitOut InnerWitIn InnerWitOut : Type}
    (outerRelIn : Set (OuterStmtIn × OuterWitIn))
    (innerRelIn : Set (InnerStmtIn × InnerWitIn))
    (outerRelOut : Set (OuterStmtOut × OuterWitOut))
    (innerRelOut : Set (InnerStmtOut × InnerWitOut))
    (compatStmt : OuterStmtIn → InnerStmtOut → Prop)
    (compatWit : OuterWitOut → InnerWitIn → Prop)
    (lens : Extractor.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                            OuterWitIn OuterWitOut InnerWitIn InnerWitOut) where

   
  proj_knowledgeSound : ∀ outerStmtIn innerStmtOut outerWitOut,
    compatStmt outerStmtIn innerStmtOut →
    (lens.stmt.lift outerStmtIn innerStmtOut, outerWitOut) ∈ outerRelOut →
    (innerStmtOut, lens.wit.proj (outerStmtIn, outerWitOut)) ∈ innerRelOut

   
  lift_knowledgeSound : ∀ outerStmtIn outerWitOut innerWitIn,
    compatWit outerWitOut innerWitIn →
    (lens.stmt.proj outerStmtIn, innerWitIn) ∈ innerRelIn →
    (outerStmtIn, lens.wit.lift (outerStmtIn, outerWitOut) innerWitIn) ∈ outerRelIn

NatPow in Init.Prelude

def eval (p : MlPolyEval R n) (x : Vector R n) : R :=
  Vector.dotProduct p (lagrangeBasis x)

@[inline, specialize]
def prover : Prover oSpec Statement Witness (Statement × Witness) Unit (pSpec Witness) where
  PrvState
  | 0 => Statement × Witness
  | 1 => Statement × Witness
  input := id
  sendMessage | ⟨0, _⟩ => fun ⟨stmt, wit⟩ => pure (wit, ⟨stmt, wit⟩)
  receiveChallenge | ⟨0, h⟩ => nomatch h
  output := fun ⟨stmt, wit⟩ => pure (⟨stmt, wit⟩, ())

def widthDiv4 : Nat := params.width / 4

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

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

OracleComp.liftComp in VCVio.OracleComp.Coercions.SubSpec

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

Function.Embedding in Mathlib.Logic.Embedding.Basic

@[app_unexpander Fin.vempty]
def vemptyUnexpander : Lean.PrettyPrinter.Unexpander
  | `($_:ident) => `(!v[])
  | _ => throw ()

def oracleReduction : OracleReduction oSpec (StmtIn R) (OStmtIn R deg) Unit
                                            (StmtOut R) (OStmtOut R deg) Unit (pSpec R deg) where
  prover := prover R deg oSpec
  verifier := oracleVerifier R deg D oSpec

def BTField_succ_alg_equiv_adjoinRoot (k : ℕ) :
  AdjoinRoot (poly k) ≃ₐ[BTField k] BTField (k + 1) :=

Submodule.subtype in Mathlib.Algebra.Module.Submodule.LinearMap

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

def AlgebraTowerEquiv.symm (e : AlgebraTowerEquiv A B) : AlgebraTowerEquiv B A where
  toRingEquiv := fun i => (e.toRingEquiv i).symm
  commutesLeft' := fun i j h r => by admit /- proof elided -/

def RAW_CONSTANTS_24 : Vector KoalaBear.Field 215 := #v[
    487143900,
    1829048205,
    1652578477,
    646002781,
    1044144830,
    53279448,
    1519499836,
    22697702,
    1768655004,
    230479744,
    1484895689,
    705130286,
    1429811285,
    1695785093,
    1417332623,
    1115801016,
    1048199020,
    878062617,
    738518649,
    249004596,
    1601837737,
    24601614,
    245692625,
    364803730,
    1857019234,
    1906668230,
    1916890890,
    835590867,
    557228239,
    352829675,
    515301498,
    973918075,
    954515249,
    1142063750,
    1795549558,
    608869266,
    1850421928,
    2028872854,
    1197543771,
    1027240055,
    1976813168,
    963257461,
    652017844,
    2113212249,
    213459679,
    90747280,
    1540619478,
    324138382,
    1377377119,
    294744504,
    512472871,
    668081958,
    907306515,
    518526882,
    1907091534,
    1152942192,
    1572881424,
    720020214,
    729527057,
    1762035789,
    86171731,
    205890068,
    453077400,
    1201344594,
    986483134,
    125174298,
    2050269685,
    1895332113,
    749706654,
    40566555,
    742540942,
    1735551813,
    162985276,
    1943496073,
    1469312688,
    703013107,
    1979485151,
    1278193166,
    548674995,
    2118718736,
    749596440,
    1476142294,
    1293606474,
    918523452,
    890353212,
    1691895663,
    1932240646,
    1180911992,
    86098300,
    1592168978,
    895077289,
    724819849,
    1697986774,
    1608418116,
    1083269213,
    691256798,
    328586442,
    1572520009,
    1375479591,
    322991001,
    967600467,
    1172861548,
    1973891356,
    1503625929,
    1881993531,
    40601941,
    1155570620,
    571547775,
    1361622243,
    1495024047,
    1733254248,
    964808915,
    763558040,
    1887228519,
    994888261,
    718330940,
    213359415,
    603124968,
    1038411577,
    2099454809,
    949846777,
    630926956,
    1168723439,
    222917504,
    1527025973,
    1009157017,
    2029957881,
    805977836,
    1347511739,
    540019059,
    589807745,
    440771316,
    1530063406,
    761076336,
    87974206,
    1412686751,
    1230318064,
    514464425,
    1469011754,
    1770970737,
    1510972858,
    965357206,
    209398053,
    778802532,
    40567006,
    1984217577,
    1545851069,
    879801839,
    1611910970,
    1215591048,
    330802499,
    1051639108,
    321036,
    511927202,
    591603098,
    1775897642,
    115598532,
    278200718,
    233743176,
    525096211,
    1335507608,
    830017835,
    1380629279,
    560028578,
    598425701,
    302162385,
    567434115,
    1859222575,
    958294793,
    1582225556,
    1781487858,
    1570246000,
    1067748446,
    526608119,
    1666453343,
    1786918381,
    348203640,
    1860035017,
    1489902626,
    1904576699,
    860033965,
    1954077639,
    1685771567,
    971513929,
    1877873770,
    137113380,
    520695829,
    806829080,
    1408699405,
    1613277964,
    793223662,
    648443918,
    893435011,
    403879071,
    1363789863,
    1662900517,
    2043370,
    2109755796,
    931751726,
    2091644718,
    606977583,
    185050397,
    946157136,
    1350065230,
    1625860064,
    122045240,
    880989921,
    145137438,
    1059782436,
    1477755661,
    335465138,
    1640704282,
    1757946479,
    1551204074,
    681266718,
]

Matrix.submatrix in Mathlib.LinearAlgebra.Matrix.Defs

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

Prod in Init.Prelude

Lean.mkRawNatLit in Lean.Expr

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

def new (domainSeparator : DomainSeparator U H) : HashStateWithInstructions U H :=
  letI stack := domainSeparator.finalize
  letI tag := generateTag domainSeparator.asBytes
  { ds := Initialize.new tag, stack := stack }

def ofMessagesChallenges (messages : Messages pSpec) (challenges : Challenges pSpec) :
    FullTranscript pSpec :=

Function.RightInverse in Init.Data.Function

List.replicate in Init.Data.List.Basic

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

@[reducible, simp] def WitOut := Unit

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

OracleSpec.append in VCVio.OracleComp.OracleSpec

evalDist in VCVio.EvalDist.Basic

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

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

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)

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

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

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

@[reducible, simp]
def StmtIn := R

AddMonoidAlgebra in Mathlib.Algebra.MonoidAlgebra.Defs

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
    ⟩

Polynomial.derivative in Mathlib.Algebra.Polynomial.Derivative

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

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

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

def oracleReduction.firstChallenge :
    OracleReduction oSpec
      (Statement.AfterFirstMessage R pp) (OracleStatement.AfterFirstMessage R pp) (Witness R pp)
      (Statement.AfterFirstChallenge R pp) (OracleStatement.AfterFirstChallenge R pp) Unit
      ⟨!v[.V_to_P], !v[FirstChallenge R pp]⟩ :=
  sorry

def smoothCode
  (domain : ι ↪ F) [Smooth domain]
  (m : ℕ) : Submodule F (ι → F) := ReedSolomon.code domain (2^m)

Equiv.piCongr in Mathlib.Logic.Equiv.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) :=
  (Simple.oracleVerifier R deg D oSpec).liftContext (oStmtLens R n deg D i)

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

@[inline, reducible]
def proj : OuterStmtIn → InnerStmtIn :=
  lens.toFunA

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

instance [Zero T] [DecidableEq T] [ToNat T] : Mod (Cayley T) where
  mod := mod

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

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

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

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

  output := fun ⟨stmt, oStmt, wit⟩ => by admit /- proof elided -/

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

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

@[simps!]
def equivMessagesChallenges :
    Transcript k pSpec ≃ (MessagesUpTo k pSpec × ChallengesUpTo k pSpec) where
  toFun := toMessagesChallenges
  invFun := ofMessagesChallenges.uncurry
  left_inv := fun T => by admit /- proof elided -/

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

FreeMonad in ToMathlib.Control.Monad.Free

propext in Init.Core

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

noncomputable def proximity_gap_johnson (rho : ℚ) (m : ℕ) : ℝ :=
  (1 : ℝ) - Real.sqrt rho - Real.sqrt rho / (2 * m)

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

Subtype.mk in Init.Prelude

GaloisField.equivZmodP in Mathlib.FieldTheory.Finite.GaloisField

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

def hammingClose (i : Fin (ℓ + 1)) (f : OracleFunction 𝔽q β
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) : Prop :=
  2 * Code.distFromCode (u := f)
    (C := BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i) <
    (BBF_CodeDistance ℓ 𝓡 i : ℕ∞)

def outOfOrderPerm : Prop :=
  
  trace = [] ∧ state = 0

alias E_time_p := outOfOrderPerm

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

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

Nat.gcd in Init.Data.Nat.Gcd

def sub (a b : AssocNat) : AssocNat :=
  subNat a b.toNat

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

def oracleVerifier : OracleVerifier oSpec (StmtIn R) (OStmtIn R deg) (StmtOut R) (OStmtOut R deg)
    (pSpec R deg) where
  verify := fun target chal => do
    let evals : Vector R m ← (Vector.finRange m).mapM
      (fun i => query (spec := [OStmtIn R deg]ₒ) () (D i))
    guard (evals.sum = target)
    
    pure (sorry, chal default)
  embed := .inl
  hEq := fun i => by admit /- proof elided -/

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

Fintype.decidablePiFintype in Mathlib.Data.Fintype.Defs

Option.bind in Init.Data.Option.Basic

def oStmtLens (i : Fin n) : OracleStatement.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) where

  toFunA := fun ⟨⟨target, challenges⟩, oStmt⟩ =>
    ⟨target, fun _ =>
      match h : n with
      | 0 => ⟨Polynomial.C <| MvPolynomial.isEmptyAlgEquiv R (Fin 0) (oStmt ()), by admit /- proof elided -/
        ⟩
      | n + 1 =>
      ⟨∑ x ∈ (univ.map D) ^ᶠ (n - i), (oStmt ()).val ⸨X ⦃i⦄, challenges, x⸩'(by admit /- proof elided -/
      ),
        sumcheck_roundPoly_degreeLE R n deg D i (oStmt ()).property⟩⟩

  toFunB := fun ⟨⟨_oldTarget, challenges⟩, oStmt⟩ ⟨⟨newTarget, chal⟩, oStmt'⟩ =>
    ⟨⟨newTarget, Fin.snoc challenges chal⟩, oStmt⟩

def ratchet (ds : DomainSeparator U H) : DomainSeparator U H :=
  { io := ds.io ++ SEP_BYTE ++ "R" }

def getFoldingChallenges (i : Fin (ℓ + 1)) (challenges : Fin i → L)
    (k : ℕ) (h : k + ϑ ≤ i) : Fin ϑ → L :=
  fun cId => challenges ⟨k + cId, by admit /- proof elided -/
  ⟩

Infinite in Mathlib.Data.Finite.Defs

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

instance : ∀ j, SelectableType ((pSpecFoldRelay (L:=L)).Challenge j) :=
  instSelectableTypeChallengeAppend

@[reducible]
def GroupExpOracle : OracleSpec Unit := fun _ => (ι × ZMod p × ι, Unit)

Int.negSucc in Init.Data.Int.Basic

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

String in Init.Prelude

noncomputable def polyToPowerSeries𝕃 (H : F[X][Y])
  (P : F[X][Y])
    : PowerSeries (𝕃 H) :=
  PowerSeries.mk <| fun n =>
    liftToFunctionField (P.coeff n)

def getBTFResult (k : ℕ) : ConcreteBTFStepResult k :=
  match k with
  | 0 =>
    let base : ConcreteBTFieldProps 0 := {
      mul_eq := fun a b h_k _ _ _ _ _ _ => by admit /- proof elided -/
| c1_one
        · 
          rw [c1_zero] at h_mul
          
          simp at h_mul
        · 
          rcases c2_cases with c2_zero | c2_one
          · 
            rw [c2_zero] at h_mul
            
            simp at h_mul
          · 
            
            exact ⟨c1_one, c2_one⟩
      
      have specialElement_eq_zero : specialElement = 0 := by admit /- proof elided -/

class VerifierOnly (pSpec : ProtocolSpec 1) extends VerifierFirst pSpec

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

def aeval {A : Type w} [CommSemiring A] [Algebra R A] (s : A) : P →ₐ[R] A :=
  eval₂AlgHom (Algebra.ofId R A) s

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

AdjoinRoot in Mathlib.RingTheory.AdjoinRoot

Id.run in Init.Control.Id

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

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

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

OrderDual.toDual in Mathlib.Order.Synonym

RingEquiv in Mathlib.Algebra.Ring.Equiv

def squeezeUnchecked [Permute C] (sponge : DuplexSponge U C) (arr : Array U) :
    DuplexSponge U C × Array U :=
  simulateQ' (m := Id) forwardPermutationOracleImpl (squeezeInto sponge arr) (by admit /- proof elided -/
  )

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

class ToNat (α : Type u) where
   
  toNat : α → Nat

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

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

Finset.image in Mathlib.Data.Finset.Image

List.dropLast in Init.Data.List.Basic

abbrev Fwd : PermuteDir := Sum.inl ()

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

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

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

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

abbrev ScalarField := ZMod scalarFieldSize

def totalNumQueries (stmt : StmtIn) (challenges : ∀ i, pSpec.Challenge i)
    (naVerifier : OracleVerifier.NonAdaptive oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec) : ℕ :=
  (naVerifier.queryOStmt stmt challenges).length + (naVerifier.queryMsg stmt challenges).length

List.max in Init.Data.List.Basic

UInt8.ofFin in Init.Data.UInt.Basic

Array.zipIdx in Init.Data.Array.Basic

noncomputable def decoder (e k : ℕ) [NeZero n] (ωs f : Fin n → F) : Option (Polynomial F) :=
  if ‖f‖₀ ≤ e
  then some 0
  else
    let x := linsolve (BerlekampWelchMatrix e k ωs f) (Rhs e ωs f)
    match x with
    | none => none
    | some x =>
      let E := solutionToE e k x
      let Q := solutionToQ e k x
      if Q % E = 0 then
        let p := Q / E
        if Δ₀(f, p.eval ∘ ωs) ≤ e then
          some p
        else
          none
      else
        none

protected def Reduction.id : Reduction oSpec Statement Witness Statement Witness !p[] where
  prover := Prover.id
  verifier := Verifier.id

instance [ToString α] (αs : List Type) [HListString (HList αs)] :
    HListString (HList (α :: αs)) where
  toString
  | HList.cons x xs =>
    match xs with
    | HList.nil => toString x
    | HList.cons _ _ => toString x ++ ", " ++ HListString.toString xs

def splitPointIntoCoeffs (i : Fin r) (h_i : i < ℓ + R_rate)
  (x : sDomain 𝔽q β h_ℓ_add_R_rate i) :
  Fin (ℓ + R_rate - i.val) → ℕ := fun j =>
    if ((sDomain_basis 𝔽q β
    h_ℓ_add_R_rate i h_i).repr x j = 0) then
      0 else 1

Set.imageFactorization in Mathlib.Data.Set.Operations

@[elab_as_elim]
def dappend {m n : ℕ} {motive : Fin (m + n) → Sort u}
    (u : (i : Fin m) → motive (Fin.castAdd n i))
    (v : (i : Fin n) → motive (Fin.natAdd m i))
    (i : Fin (m + n)) : motive i :=
  match n with
  | 0 => u i
  | k + 1 => dconcat (dappend u (fun i => v (Fin.castSucc i))) (v (Fin.last k)) i

Vector.take in Init.Data.Vector.Basic

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

instance {α : Type} [Sampleable α] : DecidableEq α := inferInstance

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

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

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

class LawfulHasSucc (T : Type u) [HasSucc T] [Add T] [One T] : Prop where
   
  succ'_eq_add_one : ∀ x : T, succ' x = x + 1

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

Fintype.elems in Mathlib.Data.Fintype.Defs

MvPolynomial in Mathlib.Algebra.MvPolynomial.Basic

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

class Deserialize.CloseToUniform (α : Type u) (β : Type u)
    [Fintype α] [Fintype β] [Nonempty α] [Nonempty β] [Deserialize α β] where
  ε : ℝ≥0
  ε_close : dist (PMF.uniformOfFintype α) (deserialize <$> PMF.uniformOfFintype β) ≤ ε

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

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

@[reducible]
def Statement := Fin sz.n_x → R

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

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

@[simp]
instance CommRing (k : ℕ) : CommRing (BTField k) := Field.toCommRing

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

Id in Init.Control.Id

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

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

Polynomial.div in Mathlib.Algebra.Polynomial.FieldDivision

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

instance (αs : List Type) [HListRepr (HList αs)] : Repr (HList αs) where
  reprPrec
  | v, _ => "[" ++ HListRepr.repr v ++ "]"

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

@[simps]
def subtypeSumComplEquiv {α : Type*} {p : α → Prop} [DecidablePred p] :
    {a // p a} ⊕ {a // ¬ p a} ≃ α where
  toFun := fun x => match x with
    | Sum.inl a => a.1
    | Sum.inr a => a.1
  invFun := fun x =>
    if h : p x then Sum.inl ⟨x, h⟩ else Sum.inr ⟨x, h⟩
  left_inv := fun x => match x with
    | Sum.inl a => by admit /- proof elided -/
    | Sum.inr a => by admit /- proof elided -/

Disjoint in Mathlib.Order.Disjoint

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

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

structure Scheme extends
    Commit oSpec Data Randomness Commitment,
    Opening oSpec Data Randomness Commitment pSpec

class LawfulPermute (α : Type*) [Permute α] where
  permuteInv : α → α
  left_inv : Function.LeftInverse permuteInv Permute.permute
  right_inv : Function.RightInverse permuteInv Permute.permute

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

def runWithOracle (f : spec.FunctionType) : OracleComp spec α → Option α :=
  OracleComp.construct' (spec := spec) (C := fun _ => Option α)
    
    (fun x => some x)
    
    (fun i q _ g => g (f i q))
    
    (none)

List.take in Init.Data.List.Basic

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

def modNat [Zero T] [DecidableEq T] [ToNat T]
    (dividend divisor : Cayley T) : Nat → Cayley T
  | 0        => dividend  
  | .succ fuel =>
    
    if (↑divisor : Nat) = 0 then
      dividend
    else
      
      if (↑divisor : Nat) ≤ (↑dividend : Nat) then
        
        modNat (sub dividend divisor) divisor fuel
      else
        dividend

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

instance : Neg (UniPoly R) := ⟨UniPoly.neg⟩

instance : Mul (UniPoly R) := ⟨UniPoly.mul⟩

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

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

Matrix in Mathlib.LinearAlgebra.Matrix.Defs

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

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

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

noncomputable def π_z_lift {H : F[X][Y]} (z : F) (root : rationalRoot (H_tilde' H) z) :
  F[X][Y] →+* F := Polynomial.evalEvalRingHom z root.1

Mod in Init.Prelude

Subtype.fintype in Mathlib.Data.Fintype.Sets

def InputStatement := R

def sumExceptFirst' (n : ℕ) (h : n > 0) (D : Fin (n - 1) → Finset R) :
    MvPolynomial (Fin n) R →ₗ[R] Polynomial R :=

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

Polynomial.comp in Mathlib.Algebra.Polynomial.Eval.Defs

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

@[simp]
abbrev OracleStatement.AfterSendEvalClaim : R1CS.MatrixIdx ⊕ R1CS.MatrixIdx ⊕ Fin 1 → Type :=
  Sum.elim (EvalClaim R) (OracleStatement.AfterFirstSumcheck R pp)

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

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

Rat.castRec in Mathlib.Algebra.Field.Defs

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

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

@[reducible]
def value (op : MemoryWrite ι α) := op.2

@[simp]
def poly (k : ℕ) : Polynomial (BTField k) := definingPoly (s:=(Z k))

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

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

@[reducible]
def coeffs {R : Type*} (p : UniPoly R) : Array R := p

def dropLastWhile (p : α → Bool) (l : List α) : List α :=
  (l.reverse.dropWhile p).reverse

def oracleFoldingConsistencyProp (i : Fin (ℓ + 1)) (challenges : Fin i → L)
    (oStmt : ∀ j, (OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i) j) : Prop :=
  ∀ (j : Fin (toOutCodewordsCount ℓ ϑ i)) (hj : j.val + 1 < toOutCodewordsCount ℓ ϑ i),
    
    have h_k_bound := oracle_block_k_bound (ℓ := ℓ) (ϑ := ϑ) (i := i) (j := j)
    have h_k_next_le_i := oracle_block_k_next_le (ℓ := ℓ) (ϑ := ϑ) (i := i) (j := j) (hj := hj)
    
    isCompliant (i := ⟨j.val * ϑ, by admit /- proof elided -/
    ⟩) (steps := ϑ)
      (h_i_add_steps := by admit /- proof elided -/
      )
      (f_i := oStmt ⟨j.val, by admit /- proof elided -/
      ⟩)
      (f_i_plus_steps := getNextOracle 𝔽q β i oStmt j hj)
      (challenges := getFoldingChallenges (r := r) (𝓡 := 𝓡) i challenges (k := j.val * ϑ)
        (h := h_k_next_le_i))

AdjoinRoot.powerBasis' in Mathlib.RingTheory.AdjoinRoot

@[reducible]
def Statement (F : Type) (i : Fin (k + 1)) : Type := Fin i.val → F

class DuplexSpongeInterface (U : Type) [SpongeUnit U] (α : Type*)
    extends Inhabited α, Zero α, Initialize α (Vector UInt8 32) where
   
  absorbUnchecked : α × Array U → α

   
  squeezeUnchecked : α × Array U → α × Array U

   
  ratchetUnchecked : α → α

@[reducible, simp]
def OracleContext.Lens.IsComplete {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}
    (outerRelIn : Set ((OuterStmtIn × (∀ i, OuterOStmtIn i)) × OuterWitIn))
    (innerRelIn : Set ((InnerStmtIn × (∀ i, InnerOStmtIn i)) × InnerWitIn))
    (outerRelOut : Set ((OuterStmtOut × (∀ i, OuterOStmtOut i)) × OuterWitOut))
    (innerRelOut : Set ((InnerStmtOut × (∀ i, InnerOStmtOut i)) × InnerWitOut))
    (compat : (OuterStmtIn × (∀ i, OuterOStmtIn i)) × OuterWitIn →
              (InnerStmtOut × (∀ i, InnerOStmtOut i)) × InnerWitOut → Prop)
    (lens : OracleContext.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                    OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut
                                    OuterWitIn OuterWitOut InnerWitIn InnerWitOut) :=
  Context.Lens.IsComplete outerRelIn innerRelIn outerRelOut innerRelOut compat lens.toContext

def rbrSoundness (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0) : Prop :=
  ∃ stateFunction : verifier.StateFunction init impl langIn langOut,
  ∀ stmtIn ∉ langIn,
  ∀ WitIn WitOut : Type,
  ∀ witIn : WitIn,
  ∀ prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec,
  ∀ i : pSpec.ChallengeIdx,
    [fun ⟨transcript, challenge⟩ =>
      ¬ stateFunction i.1.castSucc stmtIn transcript ∧
        stateFunction i.1.succ stmtIn (transcript.concat challenge)
    | do
      (simulateQ (impl ++ₛₒ challengeQueryImpl : QueryImpl _ (StateT σ ProbComp))
        (do
          let ⟨transcript, _⟩ ← prover.runToRound i.1.castSucc stmtIn witIn
          let challenge ← liftComp (pSpec.getChallenge i) _
          return (transcript, challenge))).run' (← init)] ≤
      rbrSoundnessError i

class LawfulHasPred (T : Type u) [HasSucc T] [HasPred T] : Prop where
   
  pred'_succ : ∀ x : T, pred' (succ' x) = x

instance (k : ℕ) : DecidableEq (ConcreteBTField k) :=
  fun x y =>
    let p := BitVec.toNat x = BitVec.toNat y
    let q := x = y
    let hp : Decidable p := Nat.decEq (BitVec.toNat x) (BitVec.toNat y)
    let h_iff_pq : p ↔ q := (BitVec.toNat_eq).symm 
    match hp with
    | isTrue (proof_p : p) =>
      
      
      isTrue (h_iff_pq.mp proof_p)
    | isFalse (nproof_p : ¬p) =>
      
      
      
      
      isFalse (fun (proof_q : q) => nproof_p (h_iff_pq.mpr proof_q))

def OracleVerifier.append (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ pSpec₂) :
      OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₃ OStmt₃ (pSpec₁ ++ₚ pSpec₂) where
  verify := fun stmt challenges => by admit /- proof elided -/
|
    
    .trans (.sumMap V₁.embed (.refl _)) <|
    
    .trans (Equiv.sumAssoc _ _ _).toEmbedding <|
    
    .sumMap (.refl _) MessageIdx.sumEquiv.toEmbedding

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

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

def prover : OracleProver oSpec (StmtIn R) (OStmtIn R deg) Unit (StmtOut R) (OStmtOut R deg) Unit
    (pSpec R deg) where
  PrvState
    | 0 => R⦃≤ deg⦄[X]
    | 1 => R⦃≤ deg⦄[X]
    | 2 => R⦃≤ deg⦄[X] × R

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

  sendMessage
  | ⟨0, _⟩ => fun polyLE => pure ⟨polyLE, polyLE⟩
  | ⟨1, h⟩ => nomatch h

  receiveChallenge
  | ⟨0, h⟩ => nomatch h
  | ⟨1, _⟩ => fun polyLE => pure fun chal => ⟨polyLE, chal⟩

  output := fun ⟨polyLE, chal⟩ => pure (((polyLE.val.eval chal, chal), fun _ => polyLE), ())

AddHom in Mathlib.Algebra.Group.Hom.Defs

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

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

def possibleDistsToCode (w : ι → F) (C : Set (ι → F)) (δf : (ι → F) → (ι → F) → α) : Set α :=
  {d : α | ∃ c ∈ C, c ≠ w ∧ δf w c = d}

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

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

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

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

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

alias trivial := Context.Lens.id

right_inv in ToMathlib.Control.Monad.Equiv

instance instFieldConcrete {k : ℕ} : Field (ConcreteBTField k) :=
  mkFieldInstance (getBTFResult k).toConcreteBTFieldProps

@[inline, specialize]
def oracleProver : OracleProver oSpec
    Statement OStatement Unit Statement OStatement Unit !p[] where
  PrvState := fun _ => Statement × (∀ i, OStatement i)
  input := Prod.fst
  sendMessage := fun i => nomatch i
  receiveChallenge := fun i => nomatch i
  output := fun stmt => pure (stmt, ())

Classical.propDecidable in Init.Classical

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

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

def mulNat [Zero T] (a : Cayley T) : Nat → Cayley T
  | 0        => zero
  | .succ k  => add (mulNat a k) a

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

instance [Zero T] [ToNat T] : LE (Cayley T) where
  le := le

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

class ProverFirst (pSpec : ProtocolSpec n) [NeZero n] where
  prover_first' : pSpec.dir 0 = .P_to_V

def commitmentScheme : Commitment.Scheme (oSpec α β γ) α β γ !p[] where
  commit := fun v r => commit v
  opening := .mk (sorry) (.mk (sorry))

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

reduceCtorEq in Lean.Meta.Tactic.Simp.BuiltinSimprocs.Core

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

MonadLiftT in Init.Prelude

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

Pow in Init.Prelude

instance {i : ℕ} : IsCyclicWithGen (evalDomain D i) :=

USize.ofNat in Init.Data.UInt.BasicAux
</all_available_defs>

<all_available_lemmas>
Nat.ne_zero_of_lt in Init.Data.Nat.Basic
Nat.one_lt_two_pow_iff in Init.Data.Nat.Lemmas
Nat.shiftRight_eq_zero in Init.Data.Nat.Bitwise.Basic
BitVec.toNat_ofNat in Init.Data.BitVec.Bootstrap
Nat.one_mod_two_pow_eq_one in Init.Data.Nat.Lemmas
Nat.add_sub_self_left in Init.Data.Nat.Basic
Nat.mul_two in Init.Data.Nat.Basic
Nat.pow_succ in Init.Data.Nat.Basic
Nat.sub_add_cancel in Init.Data.Nat.Basic
Nat.succ_eq_add_one in Init.Data.Nat.Basic
BitVec.zero_eq in Init.Data.BitVec.Basic
Nat.ofNat_pos in Mathlib.Data.Nat.Cast.Order.Ring
Nat.one_mod_two_pow in Init.Data.Nat.Lemmas
Nat.shiftRight_zero in Init.Data.Nat.Bitwise.Basic
Nat.sub_zero in Init.Data.Nat.Basic
Nat.two_pow_pos in Init.Data.Nat.Basic
Nat.zero_lt_two in Init.Data.Nat.Basic
pow_pos in Mathlib.Algebra.Order.GroupWithZero.Unbundled.Basic

@[simp]
theorem dcast_eq : dcast (Eq.refl a) b = b

theorem one_le_sub_consecutive_two_pow (n : ℕ): 1 ≤ 2^(n+1) - 2^n

theorem zero_lt_pow_n (m : ℕ) (n : ℕ) (h_m : m > 0): 0 < m^n

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

omit [Finite F] in
lemma sqr_mem_D_succ_i_of_mem_D_i : ∀ {a : Fˣ} {i : ℕ},
    a ∈ evalDomain D x i → a ^ 2 ∈ evalDomain D x (i + 1)

@[simp] lemma drop_dir : pSpec⟦m:⟧.dir = pSpec.dir⟦m:⟧

lemma add_self_cancel {k : ℕ} (a : ConcreteBTField k) : a + a = 0

@[simp]
theorem seqCompose_zero {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = !p[]

@[simp]
lemma not_V_to_P_eq_P_to_V {x : Direction} (h : x ≠ .P_to_V) : x = .V_to_P

@[simp]
lemma dist_le_length [DecidableEq F] (inj : Function.Injective α) :
    minDist ((ReedSolomon.code ⟨α, inj⟩ n) : Set (Fin m → F)) ≤ m

lemma add_comm {k : ℕ} (a b : ConcreteBTField k) : a + b = b + a

theorem prime_7 : Nat.Prime 7

theorem ZMod.powNeOfPowMod :
    ∀ {n a' q c : ℕ} (a : ZMod n), (a' : ZMod n) = a → decide (n ≥ 2) = true →
      Nat.mod (Nat.pow a' ((n - 1) / q)) n = c → decide (c ≠ 1) = true → a ^ ((n - 1) / q) ≠ 1

theorem append_getLast_dropLast {α : Type u} (l : List α) (h : l ≠ []) :
  l.dropLast ++ [l.getLast h] = l

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

Finset.sup_lt_iff in Mathlib.Data.Finset.Lattice.Fold

lemma nsmul_succ {k : ℕ} (n : ℕ) (x : ConcreteBTField k) :
  (if ↑n.succ % 2 = 0 then zero else x) = (if ↑n % 2 = 0 then zero else x) + x

lemma 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 splitSum_embedSum {m : ℕ} {n : Fin m → ℕ} (i : Fin m) (j : Fin (n i)) :
    splitSum (embedSum i j) = ⟨i, j⟩

lemma concrete_zero_mul
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul (zero (k:=k)) a = zero (k:=k)

@[simp]
theorem embedSum_zero {n : Fin 0 → ℕ} {i : Fin 0} (j : Fin (n i)) : embedSum i j = i

theorem castSum_castLT {l' : List ℕ} {i : ℕ} (j : Fin i) :
    castSum (i :: l') (by simp) j =
      castLT j (Nat.lt_of_lt_of_le j.isLt (List.le_sum_of_mem (by simp)))

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

lemma eval_normalizedW_succ_at_beta_prev (i : Fin r) (h_i_add_1 : i + 1 < r) :
  (normalizedW 𝔽q β (i + 1)).eval (β i) = 0

theorem split_mul_eq_mul_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₁) =
    (lo₀ * hi₁ + lo₁ * hi₀ + hi₀ * hi₁ * Z (k - 1), lo₀ * lo₁ + hi₀ * hi₁)

lemma and_eq_zero_iff {n m : ℕ} : n &&& m = 0 ↔ ∀ k, (n >>> k) &&& (m >>> k) = 0

theorem trim_twice [LawfulBEq R] (p : UniPoly R) : p.trim.trim = p.trim

lemma add_shiftRight_distrib {n m k : ℕ} (h_and_zero : n &&& m = 0):
  (n + m) >>> k = (n >>> k) + (m >>> k)

Fin.ext in Init.Data.Fin.Lemmas

lemma rounds_sub_steps_lt : ℓ - ϑ < ℓ :=
  Nat.sub_lt (pos_of_neZero ℓ) (folding_steps_pos)

lemma ϑ_sub_one_le_self : ϑ - 1 < ϑ

@[simp]
theorem eq_refl {α : Type u} (mx : m α) : eq mx mx

Nat.add_left_cancel in Init.Data.Nat.Basic

@[simp]
lemma finite_possibleRelHammingDists : (possibleRelHammingDists C).Finite

@[simp]
lemma foldr'_succ {n : ℕ} {α : Type u} (f : (i : Fin (n + 1)) → α → α) (x : α) :
    foldr' (n + 1) f x = f 0 (foldr' n (f ∘ succ) x)

@[simp, grind] lemma R_le_N : sz.R ≤ sz.N

lemma coeff_eq_zero {p : UniPoly Q} :
    (∀ i, (hi : i < p.size) → p[i] = 0) ↔ ∀ i, p.coeff i = 0

@[simp]
lemma dfoldr'_succ {n : ℕ} {α : Fin (n + 1 + 1) → Type u}
    (f : (i : Fin (n + 1)) → α i.succ → α i.castSucc) (x : α (last (n + 1))) :
    dfoldr' (n + 1) α f x = f 0 (dfoldr' n (α ∘ succ) (fun i => f i.succ) x)

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

lemma getMiddleBits_lt_two_pow {n offset len : ℕ} :
  getMiddleBits offset len n < 2 ^ len

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

theorem fcons_left_injective {β : Fin n → A} (b : (i : Fin n) → F (β i)) :
    Function.Injective (fun (a : F α) => fcons a b)

@[simp]
lemma coeff_polynomialOfCoeffs_eq_coeffs'' :
  (polynomialOfCoeffs coeffs).coeff = Fin.liftF coeffs

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

@[simp]
lemma seqCompose_zero
    (Stmt : Fin 1 → Type) (Wit : Fin 1 → Type) {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    (P : (i : Fin 0) →
      Prover oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ) (pSpec i)) :
    seqCompose Stmt Wit P = Prover.id

theorem append_rbrSoundness (V₁ : OracleVerifier oSpec Stmt₁ OStmt₁ Stmt₂ OStmt₂ pSpec₁)
    (V₂ : OracleVerifier oSpec Stmt₂ OStmt₂ Stmt₃ OStmt₃ 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)

@[simp]
lemma coe_fn_of_coe (f : ∀ a, β a) : (f : F) = inst.equiv.invFun f

theorem cast_injective : Function.Injective (ChallengeIdx.cast hn hSpec)

lemma towerRingHomBackwardMap_forwardMap_eq (k : ℕ) (x : ConcreteBTField k) :
  towerRingHomBackwardMap (k:=k) (towerRingHomForwardMap (k:=k) x) = x

@[simp]
lemma liftF'_liftF : Function.LeftInverse liftF' (liftF (α := α) (n := n))

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

theorem dcast₃_eq_dcast₃_iff (ha : a = a') (hb : dcast ha b = b') (hc : dcast₂ ha hb c = c') :
    dcast₃ ha hb hc d = d' ↔ d = dcast₃ ha.symm (dcast_symm ha hb) (dcast₂_symm ha hb hc) d'

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

@[local grind _=_]
private lemma support_eq_support_toFinsupp {f : F[X][Y]} : f.support = f.toFinsupp.support

Nat.lt_of_le_of_lt in Init.Prelude

theorem iteratedQuotientMap_k_eq_1_is_qMap (i : Fin ℓ)
    (h_i_add_1 : i.val + 1 ≤ ℓ) (x : (sDomain 𝔽q β h_ℓ_add_R_rate) ⟨i, by omega⟩) :
    iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate i 1 h_i_add_1 x =
    ⟨(qMap 𝔽q β ⟨i.val, by omega⟩).eval (x.val : L),
      qMap_eval_mem_sDomain_succ 𝔽q β   h_ℓ_add_R_rate i h_i_add_1 x⟩

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 distanceLE_polynomial_degreeLE : distanceLE (R⦃≤ d⦄[X]) d

lemma towerAlgebraMap_id (k : ℕ) : towerAlgebraMap (h_le:=by omega) = RingHom.id (BTField k)

theorem fold_advances_evaluation_poly
  (i : Fin (ℓ)) (h_i_succ_lt : i + 1 < ℓ + 𝓡)
  (coeffs : Fin (2 ^ (ℓ - ↑i)) → L) (r_chal : L) :
  let P_i : L[X] := intermediateEvaluationPoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by
    exact Nat.lt_trans (n := i) (k := ℓ+1) (m := ℓ) (h₁ := i.isLt) (by exact Nat.lt_add_one ℓ)
  ⟩) coeffs
  let f_i

@[simp]
theorem OracleReduction.run_eq_run_reduction [∀ i, OracleInterface (pSpec.Message i)]
    {stmt : StmtIn} {oStmt : ∀ i, OStmtIn i} {wit : WitIn}
    {oracleReduction : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec} :
      oracleReduction.run stmt oStmt wit =
        oracleReduction.toReduction.run ⟨stmt, oStmt⟩ wit

lemma rank_nonsquare_eq_deg_of_deg_le (inj : Function.Injective α) (h : n ≤ m) :
  (Vandermonde.nonsquare (ι' := n) α).rank = n

@[simp]
theorem cast_toReduction
    (R : OracleReduction oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₁) :
    (R.cast hn hSpec hOₘ).toReduction = Reduction.cast hn hSpec R.toReduction

theorem ZMod.powEqOfPowMod :
   ∀ {n a' c : ℕ} (a : ZMod n), (a' : ZMod n) = a →
      Nat.mod (Nat.pow a' (n - 1)) n = c → c = 1 → a ^ (n - 1) = 1

lemma forwardRange_getElem (n : ℕ) (r : Fin n) (l : Fin (r.val + 1)) (k : Fin (r.val - l.val + 1)) :
    (forwardRange n r l).get ⟨k, by
      rw [forwardRange]; simp only [List.length_ofFn]; omega⟩ = ⟨l.val + k, by omega⟩

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

theorem happend_hcons {β : Fin m → Sort u} {γ : Fin n → Sort u}
    (a : α) (u : (i : Fin m) → β i) (v : (i : Fin n) → γ i) :
    True

theorem traceMapProperty_of_quadratic_extension
  (F_prev : Type*) [Field F_prev] [Fintype F_prev] (k : ℕ)
  (fintypeCardPrev : Fintype.card F_prev = 2 ^ (2 ^ k))
  (t1 : F_prev) [instNeZero_t1 : NeZero t1]
  {F_cur : Type*} [Field F_cur] (u : F_cur) [instNeZero_u : NeZero u]
  [Algebra F_prev F_cur]
  (h_rel : SpecialElementRelation (t1 := t1) (u := u))
  (prev_trace_map : TraceMapProperty F_prev t1 (k))
  (sumZeroIffEq : ∀ (x y : F_cur), x + y = 0 ↔ x = y)
  : TraceMapProperty F_cur u (k + 1)

theorem zipWith_cons {α β γ} {n : ℕ} (f : α → β → γ)
    (a : α) (b : Vector α n) (c : β) (d : Vector β n) :
    zipWith f (cons a b) (cons c d) = cons (f a c) (zipWith f b d)

theorem vappend_succ (u : Fin m → α) (v : Fin (n + 1) → α) :
    vappend u v = vconcat (vappend u (v ∘ castSucc)) (v (last n))

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)

theorem concreteTowerAlgebraMap_assoc :
    ∀ r mid l : ℕ, (h_l_le_mid : l ≤ mid) → (h_mid_le_r : mid ≤ r) →
    concreteTowerAlgebraMap (l:=l) (r:=r) (h_le:=by exact Nat.le_trans h_l_le_mid h_mid_le_r) =
    (concreteTowerAlgebraMap (l:=mid) (r:=r) (h_le:=h_mid_le_r)).comp
    (concreteTowerAlgebraMap (l:=l) (r:=mid) (h_le:=h_l_le_mid))

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}

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

theorem inverse_is_root_of_prevPoly
    {prevBTField : Type*} [Field prevBTField]
    {curBTField : Type*} [Field curBTField]
    (of_prev : prevBTField →+* curBTField)
    (u : curBTField) (t1 : prevBTField)
    (specialElementNeZero : u ≠ 0)
    (eval_prevPoly_at_root : u ^ 2 + of_prev t1 * u + 1 = 0)
    (h_eval : ∀ (x : curBTField),
      eval₂ of_prev x (X ^ 2 + (C t1 * X + 1)) = x ^ 2 + of_prev t1 * x + 1) :
    eval₂ of_prev u⁻¹ (X ^ 2 + (C t1 * X + 1)) = 0

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_add_one_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r} (i : Fin (ℓ + 1))
    : i.val < r

@[simp]
theorem fflatten₂_zero {A : Sort u} {B : Sort v} {F : A → B → Sort w} {n : Fin 0 → ℕ}
    {α : (i : Fin 0) → (j : Fin (n i)) → A}
    {β : (i : Fin 0) → (j : Fin (n i)) → B}
    {v : (i : Fin 0) → (j : Fin (n i)) → F (α i j) (β i j)} : fflatten₂ v = !h[]

theorem eq_zero_or_eq_one {a : ConcreteBTField 0} : a = zero ∨ a = one

theorem prime_17 : Nat.Prime 17

@[simp]
lemma runWithLogToRound_discard_log_eq_runToRound (i : Fin (n + 1))
    (stmt : StmtIn) (wit : WitIn) (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      Prod.fst <$> prover.runWithLogToRound i stmt wit =
        prover.runToRound i stmt wit

Nat.pred_lt_self in Init.Data.Nat.Basic

@[simp]
theorem cast_id :
    Reduction.cast rfl rfl = (id : Reduction oSpec StmtIn WitIn StmtOut WitOut pSpec₁ → _)

theorem div_two_pow_lt_two_pow (x i j : ℕ) (h_x_lt_2_pow_i : x < 2 ^ (i + j)): x / 2^j < 2^(i)

@[simp]
lemma challengeOracleInterface_append_domain_inl (j : pSpec₁.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.domain (.inl j) = Unit

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

@[simp]
theorem LeafData.get_internal_ofLeft {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (idxLeft : SkeletonLeafIndex s_left) :
    (LeafData.internal left right).get (SkeletonLeafIndex.ofLeft idxLeft) =
      left.get idxLeft

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

@[simp]
lemma eval_solutionToQ {x : F} :
  eval x (solutionToQ e k v) =
  ∑ i ∈ Finset.range (e + k), liftF v (e + i) * x ^ i

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

lemma comm_map_smul_add (s : Right) (x y : Right ⊗[K] Left)
    (hx : e (s • x) = s • (e x)) (hy : e (s • y) = s • (e y)) :
    e (s • x) + e (s • y) = s • e x + s • e y

theorem natDegree_finSuccEquivNth (f : MvPolynomial (Fin (n + 1)) R) :
    (finSuccEquivNth R p f).natDegree = degreeOf p f

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

lemma sum_of_and_eq_zero_is_xor {n m : ℕ} (h_n_AND_m : n &&& m = 0) : n + m = n ^^^ m

@[simp]
theorem take_append_left :
    (pSpec₁ ++ₚ pSpec₂).take m (Nat.le_add_right m n) = pSpec₁

theorem divSum?_is_some_iff_lt_sum {m : ℕ} {n : Fin m → ℕ} {k : ℕ} :
    (divSum? n k).isSome ↔ k < ∑ i, n i

theorem is_fiber_iff_generates_quotient_point (i : Fin ℓ) (steps : ℕ)
    (h_i_add_steps : i.val + steps ≤ ℓ)
    (x : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩))
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩)) :
    let qMapFiber := 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)
    let k := pointToIterateQuotientIndex (i := ⟨i, by omega⟩) (steps := steps)
      (h_i_add_steps := h_i_add_steps) (x := x)
    y = iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate i (k := steps) (h_bound := h_i_add_steps) x ↔
    qMapFiber k = 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

lemma take_eq_take : transcript⟦:m⟧ = transcript.take m h

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 pow_exp_of_2_repr_given_x_square_repr {F : Type*} [instField : Field F]
  (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y) (x z : F) (h_z_non_zero : z ≠ 0)
  (h_x_square : x ^ 2 = x * z + 1)
  : ∀ i : ℕ, x^(2^i) = x * z^(2^i - 1) + ∑ j ∈ Finset.Icc 1 i, z^(2^i - 2^j)

theorem matchSize_toList {a b : Array α} {unit : α} :
    matchSize a b unit =
      let (a', b') := List.matchSize a.toList b.toList unit
      (mk a', mk b')

private lemma comp_x_square_coeff_pos_deg {f : Polynomial F} {n : ℕ} (h : 0 < f.degree) :
  (f.comp (X * X)).coeff n = if Even n then f.coeff (n / 2) else 0

@[simp]
theorem insertNth_zero_zero : insertNth p 0 (0 : Fin n →₀ M) = 0

theorem append_left_injective (b : Fin n → α) : Function.Injective (@Fin.append m n α · b)

@[simp]
theorem Iio_zero : Iio (0 : Fin (n + 1)) = ∅

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

lemma nonsquare_mulVecLin [CommSemiring F] {ι' : ℕ} {α₁ : ι ↪ F} {α₂ : Fin ι' → F} {i : ι} :
  (nonsquare ι' α₁).mulVecLin α₂ i = ∑ x, α₂ x * α₁ i ^ x.1

@[simp]
theorem vcons_of_one (a : α) {i : Fin 1} : !v[a] i = match i with

theorem seqCompose_perfectCompleteness (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))
    (h : ∀ i, (R i).perfectCompleteness init impl (rel i.castSucc) (rel i.succ)) :
      (OracleReduction.seqCompose Stmt OStmt Wit R).perfectCompleteness
        init impl (rel 0) (rel (Fin.last m))

theorem pow_zero {a : CNat 50} : a ^ 0 = 1

lemma discr_of_irred_components_nonzero
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  : ∃ x₀,
      ∀ R ∈ (irreducible_factorization_of_gs_solution h_gs).choose_spec.choose,
      Bivariate.evalX x₀ (Bivariate.discr_y R) ≠ 0

@[simp]
lemma evenPart_by_2 :
  2 * (evenPart f) = f + f.comp (-X)

theorem FullData.toLeafData_leftSubtree {α} {s_left s_right : Skeleton}
    (tree : FullData α (Skeleton.internal s_left s_right)) :
    tree.toLeafData.leftSubtree =
      tree.leftSubtree.toLeafData

@[simp, grind] lemma C_pos : 0 < sz.C

theorem multilinearBasis_apply (r : ℕ) : ∀ l : ℕ, (h_le : l ≤ r) → ∀ (j : Fin (2  ^ (r - l))),
  multilinearBasis (l:=l) (r:=r) (h_le:=h_le) j =
    (Finset.univ : Finset (Fin (r - l))).prod (fun i =>
      (binaryAlgebraTower (l:=l + i + 1) (r:=r) (h_le:=by omega)).algebraMap (
        (𝕏 (l + i)) ^ (Nat.getBit i j)))

lemma aeval_eq {A : Type w} [CommSemiring A] [Algebra R A] (f : P →ₐ[R] A) : f = aeval (f X)

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]

@[simp]
theorem fflatten_one {A : Sort u} {F : A → Sort v} {n : Fin 1 → ℕ}
    {α : (i : Fin 1) → (j : Fin (n i)) → A}
    {v : (i : Fin 1) → (j : Fin (n i)) → F (α i j)} :
    fflatten v = v 0

theorem foldl_split_inner {α : Type u} {β : Type v} (f : α → β → α) (init : α)
    (l : List β) (h : l ≠ []): foldl (f:=f) (init:=init) (l)
    = foldl (f:=f) (init:=f (init) (l.head (by omega))) (l.tail)

theorem peval_def (f : σ → σ₁ ⊕ σ₂) (x : σ₁ → R) (p : MvPolynomial σ R) :
    peval f x p = eval₂ C (Sum.elim (fun i => C (x i)) X ∘ f) p

omit [DecidableEq L] [DecidableEq 𝔽q] hF₂ hβ_lin_indep h_β₀_eq_1 in
lemma intermediateNormVpoly_eval_is_linear_map (i : Fin (ℓ + 1)) (k : Fin (ℓ - i + 1)) :
  IsLinearMap 𝔽q (fun x : L =>
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate i k).eval x)

theorem hcons_injective2 {α : Sort u} {β : Fin n → Sort u} :
    Function.Injective2 (@hcons n α β)

@[simp]
theorem Verifier.id_knowledgeSoundness {rel : Set (StmtIn × WitIn)} :
    (Verifier.id : Verifier oSpec _ _ _).knowledgeSoundness init impl rel rel 0

@[simp]
lemma widthDiv4_mul_4_eq_width : params.widthDiv4 * 4 = params.width

private lemma sum_sum_K_i_eq_n_sub_d
  (h_B : 2 ≤ B.card)
  :
  ∑ i, sum_choose_K_i B i = choose_2 B.card * (n - d B)

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

@[simp]
theorem vflatten_two_eq_append {n : Fin 2 → ℕ} {v : (i : Fin 2) → Fin (n i) → α} :
    vflatten v = vappend (v 0) (v 1)

@[simp]
theorem eqPolynomial_eval_zeroOne (r x : σ → Fin 2) :
    eval (x : σ → R) (eqPolynomial r) = if x = r then 1 else 0

private lemma k_choose_2 [Zero F] {B : Finset (Fin n → F)}
  (h_n : n ≠ 0)
  (h_B : B.card ≠ 0)
  :
  n * choose_2 (k B) ≤ ∑ i, choose_2 (K B i 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]
lemma toPolynomialAlgHom_X : toPolynomialAlgHom (X : P) = Polynomial.X

lemma U_card (i : Fin r) :
    Fintype.card (U 𝔽q β i) = (Fintype.card 𝔽q)^i.val

@[simp]
private lemma E_ne_zero : (E ωs f p e) ≠ 0

@[simp]
theorem hconcat_last {α : Fin n → Sort u} {β : Sort u} (v : (i : Fin n) → α i) (b : β) :
    hconcat v b (last n) = cast (vconcat_last α β).symm b

lemma zsmul_succ {k : ℕ} (n : ℕ) (x : ConcreteBTField k) :
  (if (↑n.succ : ℤ) % 2 = 0 then zero else x) = (if (↑n : ℤ) % 2 = 0 then zero else x) + x

lemma concrete_mul_left_distrib
  {h_k : k > 0} (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a b c : ConcreteBTField k) :
    concrete_mul a (b + c) = concrete_mul a b + concrete_mul a c

lemma add_descends [LawfulBEq R] (a₁ b₁ a₂ b₂ : UniPoly R) :
  equiv a₁ a₂ → equiv b₁ b₂ → add_descending a₁ b₁ = add_descending a₂ b₂

omit [Fintype F] in
private lemma d_eq_sum {B : Finset (Fin n → F)}
  (h_B : 2 ≤ B.card)
  :
  2 * choose_2 B.card * d B =
  ∑ i, ∑ x ∈ B ×ˢ B with x.1 ≠ x.2, (if x.1 i ≠ x.2 i then 1 else 0)

@[simp]
lemma challengeOracleInterface_append_range_inl (j : pSpec₁.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.range (.inl j) = pSpec₁.Challenge j

theorem hcons_right_injective {β : Fin n → Sort u} (a : α) :
    Function.Injective (hcons a : ((i : Fin n) → β i) → (i : Fin (n + 1)) → vcons α β i)

omit Oₘ in
theorem seqCompose_completeness (hInit : init.neverFails)
    (rel : (i : Fin (m + 1)) → Set (Stmt i × Wit i))
    (R : ∀ i, Reduction oSpec (Stmt i.castSucc) (Wit i.castSucc) (Stmt i.succ) (Wit i.succ)
      (pSpec i))
    (completenessError : Fin m → ℝ≥0)
    (h : ∀ i, (R i).completeness init impl (rel i.castSucc) (rel i.succ) (completenessError i)) :
      (Reduction.seqCompose Stmt Wit R).completeness init impl (rel 0) (rel (Fin.last m))
        (∑ i, completenessError i)

Nat.succ_le_succ in Init.Prelude

theorem get_drop_eq_drop_get_comp_cast {α : Type*} {m : ℕ} (l : List α) (h : m ≤ l.length) :
    (l.drop m).get = drop m h l.get ∘ Fin.cast (List.length_drop)

@[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 fflatten_embedSum {A : Sort u} {F : A → Sort v} {m : ℕ} {n : Fin m → ℕ}
    {α : (i : Fin m) → (j : Fin (n i)) → A}
    (v : (i : Fin m) → (j : Fin (n i)) → F (α i j)) (i : Fin m) (j : Fin (n i)) :
    fflatten v (embedSum i j) = cast (by simp) (v i j)

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

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)

theorem BitVec.dcast_dcast_bitvec_extractLsb_eq {w hi lo : ℕ} (x : BitVec w)
  (h_width_eq : w = hi - lo + 1) : dcast h_width_eq (dcast (h_width_eq.symm)
  (BitVec.extractLsb (hi:=hi) (lo:=lo) x)) = BitVec.extractLsb (hi:=hi) (lo:=lo) x

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

theorem PrattCertificate'.out {p : ℕ} (c : PrattCertificate' p) : p.Prime

theorem append_right_injective {pSpec : ProtocolSpec m} :
    Function.Injective (@ProtocolSpec.append m n pSpec)

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

@[simp]
theorem finSuccEquivNth_X_above {i : Fin n} (h : p < i.succ) :
    finSuccEquivNth R p (X i.succ) = Polynomial.C (X i)

lemma fintype_card_gt_one_of_field (K : Type*) [Field K] [Fintype K] :
  1 < Fintype.card K

theorem oracleVerifier_rbrKnowledgeSoundness [Fintype R] :
    (oracleVerifier R n deg D oSpec i).rbrKnowledgeSoundness init impl
    (relationRound R n deg D i.castSucc) (relationRound R n deg D i.succ)
    (fun _ => (deg : ℝ≥0) / Fintype.card R)

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

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

@[simp]
theorem append_cast_left {n m : ℕ} {pSpec : ProtocolSpec n} {pSpec' : ProtocolSpec m} (n' : ℕ)
    (h : n + m = n' + m) :
      dcast h (pSpec ++ₚ pSpec') = (dcast (Nat.add_right_cancel h) pSpec) ++ₚ pSpec'

lemma coe_one_succ (l : ℕ) :
    (@ConcreteBTFieldAlgebra (l:=l) (r:=l + 1) (h_le:=by omega)).algebraMap
    (1 : ConcreteBTField l) = (1 : ConcreteBTField (l + 1))

private lemma sum_K_eq_card : ∑ (α : F), K B i α = B.card

theorem coeffs_of_comp_minus_x {f : Polynomial F} {n : ℕ} :
    (f.comp (-X)).coeff n = if Even n then f.coeff n else -f.coeff n

lemma qCompositionChain_eq_foldl (i : Fin r) :
  qCompositionChain 𝔽q β (ℓ:=ℓ) (R_rate:=R_rate) i =
  Fin.foldl (n:=i) (fun acc j =>
    (qMap 𝔽q β ⟨j, by omega⟩).comp acc) (X)

omit [NeZero r] in
theorem hβ_lin_indep_concrete (k : ℕ) :
    letI := ConcreteBTFieldAlgebra (l:=0) (r:=k) (h_le:=by omega)
    LinearIndependent (R := ConcreteBTField 0)
      (v := computableBasisExplicit k)

@[simp] theorem leftpad_eq_self (l : List α) (n : Nat) (h : l.length ≥ n) :
    leftpad n unit l = l

@[simp]
theorem fflatten_zero {A : Sort u} {F : A → Sort v} {n : Fin 0 → ℕ}
    {α : (i : Fin 0) → (j : Fin (n i)) → A}
    {v : (i : Fin 0) → (j : Fin (n i)) → F (α i j)} : fflatten v = !h[]

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

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

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 getBit_of_and {n m k: ℕ} : getBit k (n &&& m) = getBit k n &&& getBit k m

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma ℓ_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r}
    : ℓ < r

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)

lemma cons_get_eq {α} {n : ℕ} (hd : α) (tl : Vector α n) (i : Fin (n + 1)) :
    (cons hd tl).get i =
      if hi: i.val == 0 then hd else tl.get (⟨i.val - 1, by
        simp only [beq_iff_eq, Fin.val_eq_zero_iff] at hi
        apply Nat.sub_lt_left_of_lt_add
        · by_contra hi_ne_gt_1
          simp only [not_le, Nat.lt_one_iff, Fin.val_eq_zero_iff] at hi_ne_gt_1
          contradiction
        · have hi_lt:= i.isLt; omega
      ⟩)

@[simp]
theorem runWithOracle_freeMonad_pure_none (f : spec.FunctionType) :
    runWithOracle f (FreeMonad.pure (none : Option α)) = none

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 unique_repr {R : Type*} [CommRing R] {S : Type*} [CommRing S] [Algebra R S]
    (pb : PowerBasis R S) (repr1 repr2 : Fin pb.dim →₀ R)
    (h : ∑ i : Fin pb.dim, repr1 i • pb.basis i = ∑ i : Fin pb.dim, repr2 i • pb.basis i) :
    repr1 = repr2

lemma deevenize_comp_x_squared {f : Polynomial F} (hEven : EvenPoly f) :
    (deevenize f).comp (Polynomial.X * Polynomial.X) = f

lemma isInterleaved_codeOfLinearCode : (codeOfLinearCode κ LC).isInterleaved

@[simp]
theorem dflatten_two_eq_append {n : Fin 2 → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    {v : (i : Fin 2) → (j : Fin (n i)) → motive (embedSum i j)} :
    dflatten (motive := motive) v = dappend (v 0) (v 1)

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

theorem liftContext_perfectCompleteness
    (h : R.perfectCompleteness init impl innerRelIn innerRelOut) :
      (R.liftContext lens).perfectCompleteness init impl outerRelIn outerRelOut

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

omit [Finite F] in
@[simp]
lemma range_lem₂ : [FinalOracleStatement D x s]ₒ.range (Fin.last (k + 1)) = F[X]

@[simp]
theorem Iic_zero : Iic (0 : Fin (n + 1)) = {0}

@[grind _=_]
lemma total_deg_as_weighted_deg :
  totalDegree f = natWeightedDegree f 1 1

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)

theorem stir_main
  (secpar : ℕ) [SelectableType F]
  {ι : Type} [Fintype ι] [Nonempty ι] [DecidableEq ι]
  {φ : ι ↪ F} {degree : ℕ} [hsmooth : Smooth φ]
  {k proofLen qNumtoInput qNumtoProofstr : ℕ}
  (hk : ∃ p, k = 2 ^ p) (hkGe : k ≥ 4)
  (δ : ℝ≥0) (hδub : δ < 1 - 1.05 * Real.sqrt (degree / Fintype.card ι))
  (hF : Fintype.card F ≤
        secpar * 2 ^ secpar * degree ^ 2 * (Fintype.card ι) ^ (7 / 2) /
          Real.log (1 / rate (code φ degree))) :
  ∃ n : ℕ,
  ∃ vPSpec : ProtocolSpec.VectorSpec n,
  ∃ ε_rbr : vPSpec.ChallengeIdx → ℝ≥0,
  ∃ π : VectorIOP Unit (OracleStatement ι F) Unit vPSpec F,
  IsSecureWithGap (stirRelation degree φ 0)
                  (stirRelation degree φ δ)
                  ε_rbr π
  ∧ ∀ i, ε_rbr i ≤ (1 : ℚ≥0) / (2 ^ secpar)
  ∧ ∃ c > 0, M ≤ c * (Real.log degree / Real.log k)
  ∧ ∃ cₖ : ℕ → ℝ, proofLen ≤ (Fintype.card ι) + (cₖ k) * (Real.log degree)
  ∧ qNumtoInput = secpar / (- Real.log (1 - δ))
  ∧ ∃ cₖ : ℕ → ℝ, qNumtoProofstr ≤
    (cₖ k) * ((Real.log degree) +
      secpar * (Real.log ((Real.log degree) / Real.log (1/rate (code φ degree)))))

@[grind =] theorem findIdx'_cons {p : α → Bool} {x : α} {xs : List α} :
    findIdx' p (x :: xs) = bif p x then 0 else findIdx' p xs + 1

@[simp]
theorem verifier_last_of_two (pSpec : ProtocolSpec 2) [VerifierLast pSpec] :
    pSpec.dir 1 = .V_to_P

lemma testBit_true_eq_getBit_eq_1 (k n : Nat) : n.testBit k = ((Nat.getBit k n) = 1)

lemma dist_eq_minWtCodewords [CommRing F] {LC : LinearCode ι F} :
  Code.minDist (LC : Set (ι → F)) = minWtCodewords LC

lemma towerRingHomForwardMap_mul_eq (k : ℕ) (x y : ConcreteBTField k) :
    towerRingHomForwardMap (k:=k) (x * y)
    = towerRingHomForwardMap (k:=k) x * towerRingHomForwardMap (k:=k) y

theorem one_mul (n : ChurchNat α) : mul one n = n

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 succ'_injective : Function.Injective (succ' : Nat → Nat)

lemma binaryTowerAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
    @binaryAlgebraTower (l:=l) (r:=r) (h_le:=h_le)
    = (towerAlgebraMap l r h_le).toAlgebra

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

@[simp]
theorem hflatten_splitSum {m : ℕ} {n : Fin m → ℕ} {α : (k : Fin (vsum n)) → Sort*}
    (v : (k : Fin (vsum n)) → α k) (k : Fin (vsum n)) :
    hflatten (fun i j => v (embedSum i j)) k = cast (vflatten_splitSum α k).symm (v k)

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

theorem degrees_peval {x : σ₁ → R} {f : σ → σ₁ ⊕ σ₂} {p : MvPolynomial σ R} :
    (peval f x p).degrees ≤ (p.degrees.map f).filterMap Sum.getRight?

@[simp]
theorem generateProof_ofLeft {sleft sright : Skeleton}
    (cache_tree : FullData α (Skeleton.internal sleft sright))
    (idxLeft : SkeletonLeafIndex sleft) :
    generateProof cache_tree (BinaryTree.SkeletonLeafIndex.ofLeft idxLeft) =
      (cache_tree.rightSubtree).getRootValue ::
        (generateProof cache_tree.leftSubtree idxLeft)

theorem foldOracleReduction_perfectCompleteness (hInit : init.neverFails) (i : Fin ℓ) :
    OracleReduction.perfectCompleteness
      (pSpec := pSpecFold (L := L))
      (relIn := roundRelation 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i.castSucc (mp := mp))
      (relOut := foldStepRelOut 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑 := 𝓑) i (mp := mp))
      (oracleReduction := foldOracleReduction 𝔽q β (ϑ := ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑 := 𝓑) i)
      (init := init)
      (impl := impl)

lemma rtake_eq_rtake : transcript⟦m:⟧ = transcript.drop m h

@[simp]
theorem InternalData.rightSubtree_internal {α} {s_left s_right : Skeleton}
    (value : α) (left : InternalData α s_left) (right : InternalData α s_right) :
    (InternalData.internal value left right).rightSubtree = right

@[simp]
theorem FullData.ofFun_get {α} {s} (tree : FullData α s) :
    FullData.ofFun s (fun idx => tree.get idx) = tree

theorem prime_5 : Nat.Prime 5

omit [Finite F] in
@[simp]
lemma range_lem₁ {i : Fin (k + 1)} :
    [FinalOracleStatement D x s]ₒ.range ⟨i.1, Nat.lt_succ_of_lt i.2⟩ = F

lemma proximity_gap
  {F : Type} [Field F] [Fintype F] [DecidableEq F]
  {ι : Type} [Fintype ι] [Nonempty ι] {φ : ι ↪ F}
  {degree m : ℕ} {δ : ℝ≥0} {f : Fin m → ι → F} {GenFun : F → Fin m → F}
  (h : ∀ (hδLe : δ < 1 - Bstar (LinearCode.rate (code φ degree))) {f : Fin m → ι → F},
        Pr_{
          let r ← $ᵖ F}[δᵣ((fun x => ∑ j : Fin m, (GenFun r j) * f j x), code φ degree) ≤ (δ : ℝ)]
            > ENNReal.ofReal (proximityError F degree (LinearCode.rate (code φ degree)) δ m)) :

        ∃ S : Finset ι,
          S.card ≥ (1 - δ) * (Fintype.card ι) ∧
        ∃ u : (ι → F),
          u ∈ (code φ degree) ∧ ∀ i : Fin m, ∀ x ∈ S, f i x = u x

theorem add_zero {n : ℕ} (a : CNat (n + 1)) : a + 0 = a

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 trim_equiv [LawfulBEq R] (p : UniPoly R) : equiv p.trim p

lemma getBit_zero_eq_self {n : ℕ} (h_n : n < 2) : getBit 0 n = n

@[simp]
theorem fappend_left {α : Fin m → A} {β : Fin n → A}
    (u : (i : Fin m) → F (α i)) (v : (i : Fin n) → F (β i)) (i : Fin m) :
    fappend u v (castAdd n i) = cast (by simp [vappend_left]) (u i)

@[simp] lemma extract_dir : pSpec⟦start:stop⟧.dir = pSpec.dir⟦start:stop⟧

lemma getLowBits_succ {n: ℕ} (numLowBits: ℕ) :
    getLowBits (numLowBits + 1) n = getLowBits numLowBits n
    + (getBit numLowBits n) <<< numLowBits

lemma pow_2_pow_i_mem_Di_of_mem_D {F : Type} [NonBinaryField F] [Finite F] {D : Subgroup Fˣ}
  [DIsCyclicC : IsCyclicWithGen ↥D] {x : Fˣ} :
  ∀ {a : Fˣ} (i : ℕ),
    a ∈ evalDomain D x 0 → a ^ (2 ^ i) ∈ evalDomain D x i

@[simp]
theorem verifier_rbrKnowledgeSoundness :
    (verifier oSpec Statement).rbrKnowledgeSoundness init impl rel rel 0

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)

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

lemma concrete_exists_pair_ne {k : ℕ} : ∃ x y : ConcreteBTField k, x ≠ y

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

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

lemma concrete_one_ne_zero {k : ℕ} : (one (k:=k)) ≠ (zero (k:=k))

theorem drop_append_left {n' : ℕ} {α : Sort*} (m : ℕ) (h : m ≤ n) (u : (i : Fin n) → α)
    (v : (i : Fin n') → α) :
      drop m (Nat.le_add_right_of_le h) (append u v) =
          append (drop m h u) v ∘ Fin.cast (by omega)

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

@[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 findIdxRev?_eq_none {cond} {as : Array α} (h : ∀ i, (hi : i < as.size) → ¬ cond as[i]) :
  findIdxRev? cond as = none

theorem vcons_inj (a b : α) (v w : Fin n → α) : a ::ᵛ v = b ::ᵛ w ↔ a = b ∧ v = w

@[simp]
lemma toFun_invFun (f : ∀ a, β a) : inst.equiv.toFun (equiv.invFun f : F) = f

theorem add_zero : p + 0 = p

theorem prime_29 : Nat.Prime 29

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

theorem fullOracleVerifier_rbrKnowledgeSoundness :
  (fullOracleVerifier 𝔽q β γ_repetitions (ϑ:=ϑ)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate)).rbrKnowledgeSoundness init impl
    (relIn := roundRelation (mp := BBF_SumcheckMultiplierParam) 𝔽q β (ϑ:=ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (𝓑:=𝓑) 0)
    (relOut := acceptRejectOracleRel)
    (rbrKnowledgeError := fullRbrKnowledgeError 𝔽q β γ_repetitions (ϑ:=ϑ)
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate))

lemma degree_s_smul_X {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (C s * (X : (F)[X])).degree = 1

theorem prime_101 : Nat.Prime 101

theorem BitVec.dcast_id {n : Nat} (bv : BitVec n) :
  DCast.dcast (Eq.refl n) bv = bv

theorem neg_add_cancel [LawfulBEq R] (p : UniPoly R) : -p + p = 0

theorem seqCompose_knowledgeSoundness
    (rel : (i : Fin (m + 1)) → Set ((Stmt i × ∀ j, OStmt i j) × Wit i))
    (V : (i : Fin m) →
      OracleVerifier oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Stmt i.succ) (OStmt i.succ)
        (pSpec i))
    (knowledgeError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).knowledgeSoundness init impl (rel i.castSucc) (rel i.succ) (knowledgeError i)) :
      (OracleVerifier.seqCompose Stmt OStmt V).knowledgeSoundness
        init impl (rel 0) (rel (Fin.last m)) (∑ i, knowledgeError i)

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

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

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

@[csimp, grind =]
theorem idxOf'_eq_idxOf : @idxOf' = @idxOf

theorem singleEqPolynomial_nf (r : R) (x : MvPolynomial σ R) :
    singleEqPolynomial r x = (2 * C r - 1) * x + (1 - C r)

@[simp]
theorem LeafData.rightSubtree_internal {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right) :
    (LeafData.internal left right).rightSubtree = right

@[simp]
lemma ofPolynomialAlgHom_toPolynomialAlgHom_X :
    ofPolynomialAlgHom (toPolynomialAlgHom (X : P)) = (Polynomial.X : R[X])

@[simp]
theorem rdrop_eq_take (m : ℕ) (h : m ≤ n) (v : (i : Fin n) → α i) :
    rdrop m h v = take (n - m) (by omega) v

theorem Iic_castSucc (i : Fin n) : Iic (castSucc i) = (Iic i).map Fin.castSuccEmb

theorem OracleReduction.liftContext_toReduction_comm
    {lens : OracleContext.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                              OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut
                              OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {R : OracleReduction oSpec InnerStmtIn InnerOStmtIn InnerWitIn
                            InnerStmtOut InnerOStmtOut InnerWitOut pSpec} :
      (R.liftContext lens).toReduction = R.toReduction.liftContext lens.toContext

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

@[simp] theorem add_zero {a : AssocNat} : a + 0 = a

Nat.le_trans in Init.Prelude

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

theorem insertNth_zero_eq_cases {n : ℕ} {α : Fin (n + 1) → Sort u} :
    insertNth 0 = cases (motive := α)

theorem dconcat_right_injective {motive : Fin (n + 1) → Sort u}
    (v : (i : Fin n) → motive (castSucc i)) :
    Function.Injective (dconcat (motive := motive) v)

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

lemma folding
  [Nonempty ι] {S : Finset ι} [Fintype ι]
  (φ : ι ↪ F) (f : ι → F) (k : ℕ)
  [Nonempty (indexPow S φ k)]
  {degree : ℕ} (δ : ℚ) (hδPos : δ > 0)
  (hδLt : δ < foldingDistRange degree φ f) :
  let C : Set ((indexPow S φ k) → F) := code (pow S φ k) (degree / k)
  Pr_{ let r ← $ᵖ F }[ δᵣ((fold φ f k r), C) ≤ δ]
    ≤ ENNReal.ofReal (proximityError F (degree / k) (LinearCode.rate (code φ degree)) δ k)

lemma solutionToE_eq_polynomialOfCoeffs
  (h : n < e) : (solutionToE e k v).coeff n = (polynomialOfCoeffs v).coeff n

@[simp]
theorem leftpad_apply_ge (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : n - m ≤ i.val) : leftpad n a v i = v ⟨i.val - (n - m), by omega⟩

theorem oracleVerifier_rbrKnowledgeSoundness [Fintype R] :
    (oracleVerifier R deg D oSpec).rbrKnowledgeSoundness init impl
    (inputRelation R deg D) (outputRelation R deg) (fun _ => (deg : ℝ≥0) / (Fintype.card R))

@[simp]
lemma dfoldl'_zero {α : Fin 1 → Type u}
    (f : (i : Fin 0) → α i.castSucc → α i.succ) (x : α 0) :
    dfoldl' 0 α f x = x

lemma listOfCloseCodewordsRel_eq_zero :
  listOfCloseCodewordsRel C y r = 0 ↔
  IsEmpty (relHammingBall C y r) ∨ Infinite (relHammingBall C y r)

Nat.pos_of_neZero in Init.Data.Nat.Basic

@[simp]
lemma lastBlockIdx_mul_ϑ_add_x_lt_ℓ_succ (x : ℕ) {hx : x ≤ ϑ} :
    (ℓ / ϑ - 1) * ϑ + x < ℓ + 1

Nat.le_of_succ_le in Init.Data.Nat.Basic

@[simp]
theorem distanceLE_polynomial_degreeLT : distanceLE (R⦃< d⦄[X]) (d - 1)

lemma shift_left_def {s : Finset ℕ} :
    shift_left s = s.filterMap
    (fun n => match n with
      | 0 => .none
      | n + 1 => .some n
      )
    (by aesop)

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

lemma vappend_left_of_lt {m n : ℕ} {α : Sort u}
    (u : Fin m → α) (v : Fin n → α) (i : Fin (m + n)) (h : i.val < m) :
      vappend u v i = u ⟨i, h⟩

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

theorem oracleReduction_rbr_knowledge_soundness : True

@[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]
theorem add_accepts_iff : (add a b c).accepts x ↔ x c = x a + x b

theorem cast_injective : Function.Injective (MessageIdx.cast hn hSpec)

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)

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

theorem fcons_right_injective {β : Fin n → A} (a : F α) :
    Function.Injective (fcons a : ((i : Fin n) → F (β i)) → (i : Fin (n + 1)) → _)

theorem dist'_eq_dist : ‖C‖₀'.toNat = ‖C‖₀

omit [DecidableEq L] [Fintype 𝔽q] h_Fq_char_prime hβ_lin_indep in
lemma normalizedW₀_eq_1_div_β₀ : normalizedW (𝔽q := 𝔽q) (β := β) (i :=0) = X * C (1 / (β 0))

theorem BitVec.extractLsb_eq_and_pow_2_minus_1_ofNat {n num_bits : Nat}
  (h_num_bits : num_bits > 0) (x : BitVec n) :
  BitVec.extractLsb (hi:= num_bits - 1) (lo := 0) x =
    BitVec.ofNat (num_bits - 1 - 0 + 1) (x.toNat &&& (2 ^ num_bits - 1))

theorem eval_eq_eval_mv_eval_finSuccEquivNth (s : Fin n → R) (y : R)
    (f : MvPolynomial (Fin (n + 1)) R) :
      eval (Fin.insertNth p y s : Fin (n + 1) → R) f =
        Polynomial.eval y (Polynomial.map (eval s) (finSuccEquivNth R p f))

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

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

@[simp]
theorem ofNat_zero : ofNat 0 = @zero α

omit [Fintype F] [DecidableEq F] in
private lemma choose_2_card_ne_zero (h : 2 ≤ B.card) : choose_2 ↑B.card ≠ 0

@[simp]
theorem rightpad_apply_lt (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : i.val < m) : rightpad n a v i = v ⟨i.val, h⟩

theorem eval_zeroOne_eq_MLE_toEvalsZeroOne (p : MvPolynomial σ R) (x : σ → Fin 2) :
    eval (x : σ → R) p = eval (x : σ → R) (MLE p.toEvalsZeroOne)

@[to_additive (attr := simp)]
theorem prod_insertNth [CommMonoid β] {n : ℕ} (x : β) (f : Fin n → β) (p : Fin (n + 1)) :
    ∏ i, insertNth p x f i = x * ∏ i, f i

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

theorem ZMod.bla : ∀ {n c : ℕ} (a : ZMod n), c = 1 → IsNat (a ^ (n - 1)) c → a ^ (n - 1) = 1

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

@[grind]
lemma degreeY_le_degreeY_sub_degreeY [IsDomain F] {f q : F[X][Y]} (hf : f ≠ 0) (hg : q * f ≠ 0) :
  natDegreeY q ≤ natDegreeY (q * f) - natDegreeY f

@[simp] lemma toMvPolynomialAlgHom_X (s : σ) :
    toMvPolynomialAlgHom (X s : P) = (MvPolynomial.X s : MvPolynomial σ R)

theorem getBit_repr {ℓ : Nat} : ∀ j, j < 2^ℓ →
  j = ∑ k ∈ Finset.Icc 0 (ℓ-1), (getBit k j) * 2^k

lemma evenize_eval {f : Polynomial F} {s : F} :
    (evenize f).eval s = f.eval (s * s)

lemma bwm_of_neg [NeZero n] (h : e ≤ j.1) :
  BerlekampWelchMatrix e k ωs f i j = -(ωs i)^(j - e)

lemma card_le_card_of_count_inj {α β : Type*} [DecidableEq α] [DecidableEq β]
    {s : Multiset α} {s' : Multiset β}
  {f : α → β} (inj : Function.Injective f) (h : ∀ a : α, s.count a ≤ s'.count (f a)) :
  s.card ≤ s'.card

@[simp] theorem join_nil : List.join ([] : List (List α)) = []

lemma W_add_U_invariant
  (i : Fin r) :
  ∀ x : L, ∀ y ∈ U 𝔽q β i, (W 𝔽q β i).eval (x + y) = (W 𝔽q β i).eval x

@[grind]
lemma quotient_nezero {f q : F[X][Y]} (hg : q * f ≠ 0) : q ≠ 0

omit [SelectableType R] in
@[simp]
lemma oracleReduction_verifier_eq_verifier {i : Fin n} :
    (oracleReduction R n deg D oSpec i).verifier = oracleVerifier R n deg D oSpec i

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

lemma getBit_of_middleBits {n offset len k : ℕ} :
  getBit k (getMiddleBits offset len n) =
    if k < len then getBit (k + offset) n else 0

@[to_additive]
theorem prod_Iic_eq_univ (i : Fin (n + 1)) :
    ∏ j ∈ Iic i, v j = ∏ j : Fin (i + 1), v (Fin.castLE i.isLt j)

Nat.sub_mul in Init.Data.Nat.Basic

private lemma le_sum_sum_choose_K [Zero F]
  (h_n : 0 < n)
  (h_B : B.card ≠ 0)
  (h_card : 2 ≤ Fintype.card F)
  :
  n * (choose_2 (k B) + (Fintype.card (α := F) - 1)
    * choose_2 ((B.card - k B) / ((Fintype.card (α := F) - 1))))
  ≤ ∑ i, sum_choose_K_i B i

lemma concrete_pow_base_one
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1)) (n : ℕ) :
  concrete_pow_nat (k:=k) (x:=1) n = 1

lemma algebraMap_succ_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : BTField (k - 1)) :
  letI instAlgebra := binaryAlgebraTower (l:=k-1) (r:=k) (h_le:=by omega)
  algebraMap (BTField (k - 1)) (BTField k) x = ⋘ 0, x ⋙

theorem simulateQ'_eq_simulateQ [AlternativeMonad m] [LawfulMonad m]
    {so : QueryImpl spec m} (oa : OracleComp spec α) (h : oa.neverFails) :
      simulateQ' so oa h = simulateQ so oa

theorem rename_ne_zero_of_injective {τ : Type*} {f : σ → τ} (hf : Function.Injective f)
    {p : MvPolynomial σ R} (h : p ≠ 0) : rename f p ≠ 0

theorem correlatedAgreement_affine_spaces {k : ℕ} [NeZero k] {u : Fin (k + 1) → ι → F}
  {deg : ℕ} {domain : ι ↪ F} {δ : ℝ≥0} (hδ : δ ≤ 1 - (ReedSolomonCode.sqrtRate deg domain))
  (hproximity :
    Pr_{let y ← $ᵖ (u 0 +ᵥ affineSpan F (Finset.univ.image (Fin.tail u)).toSet)}[
        Code.relHammingDistToCode (ι := ι) (F := F) y (ReedSolomon.code domain deg) ≤ δ
    ] > errorBound δ deg domain) :
  correlatedAgreement (ReedSolomon.code domain deg) δ u

lemma natDegree_lt_of_lbounded_zero_coeff {p : F[X]} [NeZero deg]
  (h : ∀ i, deg ≤ i → p.coeff i = 0) : p.natDegree < deg

@[ext] theorem UniPolyC.ext {p q : UniPolyC R} (h : p.val = q.val) : p = q

Fin.is_le in Init.Data.Fin.Lemmas

lemma getBit_eq_zero_or_one {k n : Nat} :
  getBit k n = 0 ∨ getBit k n = 1

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

theorem fconcat_injective2 {α : Fin n → A} {β : A} :
    Function.Injective2 (@fconcat A F n α β)

@[simp]
lemma constantCode_eq_ofNat_zero_iff [Nonempty ι] :
  constantCode x ι = 0 ↔ x = 0

theorem cast_eq_dcast {h : n₁ = n₂} {pSpec : ProtocolSpec n₁} :
    pSpec.cast h = dcast h pSpec

omit [Finite F] in
@[simp]
lemma domain_lem₁ {i : Fin (k + 1)} :
    [FinalOracleStatement D x s]ₒ.domain ⟨i.1, Nat.lt_succ_of_lt i.2⟩ =
      evalDomain D x (∑ j' ∈ finRangeTo i.1, s j')

theorem linearIndependent_fin2' {f : Fin 2 → V} :
    LinearIndependent K f ↔ f 0 ≠ 0 ∧ ∀ a : K, a • f 0 ≠ f 1

omit [CharP L 2] [DecidableEq 𝔽q] h_β₀_eq_1 [NeZero 𝓡] in
lemma firstOracleWitnessConsistencyProp_relay_preserved (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) (wit : Witness (L := L) 𝔽q β
      (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ)
    (oStmt : ∀ j, OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j) :
    firstOracleWitnessConsistencyProp 𝔽q β wit.t (getFirstOracle 𝔽q β oStmt) =
    firstOracleWitnessConsistencyProp 𝔽q β wit.t
      (getFirstOracle 𝔽q β (mapOStmtOutRelayStep 𝔽q β i hNCR oStmt))

omit [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 OracleVerifier.liftContext_toVerifier_comm
    {lens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                              OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut}
    {V : OracleVerifier oSpec InnerStmtIn InnerOStmtIn InnerStmtOut InnerOStmtOut pSpec} :
      (V.liftContext lens).toVerifier = V.toVerifier.liftContext lens

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)

lemma full_row_rank_via_rank_subLeftFull (h : m ≤ n) :
   (subLeftFull U (Fin.castLE h)).rank = m → U.rank = m

@[simp]
theorem vappend_left (u : Fin m → α) (v : Fin n → α) (i : Fin m) :
    vappend u v (castAdd n i) = u i

lemma algebraMap_adjacent_tower_def (l : ℕ) :
    (algebraMap (ConcreteBTField l) (ConcreteBTField (l + 1))) =
    canonicalAlgMap l

theorem dcast_fun {γ : (a : α) → β a → Sort*} {f : (b : β a) → γ a b} :
    f (dcast rfl b) = dcast (α := β a) (β := γ a) dcast_eq.symm (f b)

lemma forwardRange_length (n : ℕ) (r : Fin n) (l : Fin (r.val + 1)) :
    (forwardRange n r l).length = r.val - l.val + 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 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⟩)

theorem support_C_mul_le (p : MvPolynomial σ R) (r : R) : (C r * p).support ⊆ p.support

@[simp]
theorem tail_vcons (a : α) (v : Fin n → α) : tail (a ::ᵛ v) = v

@[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]
theorem oracleVerifier_rbrKnowledgeSoundness (hRel : ∀ stmtIn oStmtIn witOut,
      ((mapStmt stmtIn, mapOStmt embedIdx hEq oStmtIn), witOut) ∈ relOut →
      ((stmtIn, oStmtIn), mapWitInv (stmtIn, oStmtIn) witOut) ∈ relIn) :
    (oracleVerifier oSpec mapStmt embedIdx hEq).rbrKnowledgeSoundness init impl relIn relOut 0

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

theorem split_Z {k : ℕ} (h_pos : k > 0) :
    split h_pos (Z k) = (one (k:=k - 1), zero (k:=k - 1))

theorem mapM_single (f : α → m β) (a : α) : List.mapM f [a] = return [← f a]

lemma not_outOfOrder_of_not_combined (h : ¬ E trace) : ¬ E_time trace state

@[simp]
theorem card_univ_filter_eq {e : α} :
  #{x : α | x ≠ e} = #(Finset.univ (α := α)) - 1

lemma add_eq_zero_iff_eq {k : ℕ} (a b : ConcreteBTField k) : a + b = 0 ↔ a = b

theorem hcons_eq_hcons_iff {β : Fin n → Sort u} (a₁ a₂ : α) (v₁ v₂ : (i : Fin n) → β i) :
    hcons a₁ v₁ = hcons a₂ v₂ ↔ a₁ = a₂ ∧ v₁ = v₂

@[simp]
theorem Verifier.id_soundness {lang : Set StmtIn} :
    (Verifier.id : Verifier oSpec _ _ _).soundness init impl lang lang 0

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)

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

@[simp]
theorem embedSum_succ_zero {n : Fin (m + 1) → ℕ} {j : Fin (n 0)} :
    embedSum 0 j = Fin.castAdd _ j

theorem pow_one {a : CNat 50} : a ^ 1 = a

lemma getBit_eq_succ_getBit_of_mul_two_add_one {n k : ℕ} : getBit (k+1) (2*n + 1) = getBit k n

theorem finSigmaFinEquiv'_pair {m : ℕ} {n : Fin m → ℕ} (i : Fin m) (k : Fin (n i)) :
    (finSigmaFinEquiv' ⟨i, k⟩ : ℕ) = ∑ j, n (Fin.castLE i.isLt.le j) + k

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

omit [NeZero ℓ] in
lemma fin_ℓ_steps_lt_ℓ_add_R (i : Fin ℓ) (steps : ℕ) (h : i.val + steps ≤ ℓ)
    : i.val + steps < ℓ + 𝓡

theorem fconcat_left_injective {α : Fin n → A} {β : A} (a : F β) :
    Function.Injective (fun v : (i : Fin n) → F (α i) => fconcat v a)

Fin.isLt in Init.Prelude

theorem eqPolynomial_expanded (r : σ → R) :
    eqPolynomial r = ∏ i : σ, ((1 - C (r i)) * (1 - X i) + C (r i) * X i)

@[simp]
theorem eval_poly_at_root (k : ℕ) : (Z (k+1))^2 + (Z (k+1)) * Z k + 1 = 0

theorem nsmul_zero [LawfulBEq R] (p : UniPoly R) : nsmul 0 p = 0

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⟩

theorem verifier_rbr_knowledge_soundness :
    (verifier oSpec Statement pred).rbrKnowledgeSoundness init impl
      (relIn Statement pred) (relOut Statement) 0

lemma testBit_false_eq_getBit_eq_0 (k n : Nat) :
  (n.testBit k = false) = ((Nat.getBit k n) = 0)

lemma eq_poly_deg_one {a b c d : F} {x₁ x₂ : F}
  (h1 : a + b * x₁ = c + d * x₁)
  (h2 : a + b * x₂ = c + d * x₂)
  (h1_2 : x₁ ≠ x₂) :
  Polynomial.C a + Polynomial.C b * Polynomial.X
    = Polynomial.C c + Polynomial.C d * Polynomial.X

lemma exists_Pz_of_coeffs_of_close_proximity
  {k : ℕ}
  {z : F}
  (hS : z ∈ coeffs_of_close_proximity (k := k) ωs δ u₀ u₁)
  :
  ∃ Pz : F[X], Pz.natDegree ≤ k ∧ δᵣ(u₀ + z • u₁, Pz.eval ∘ ωs) ≤ δ

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

lemma getBit_of_shiftRight {n p : ℕ}:
  ∀ k, getBit k (n >>> p) = getBit (k+p) n

theorem hconcat_injective2 {α : Fin n → Sort u} {β : Sort u} :
    Function.Injective2 (@hconcat n α β)

@[simp]
theorem insertNth_last : insertNth (Fin.last n) y s = snoc s y

lemma cast_mul (m n : ℕ) {x y : ConcreteBTField m} (h_eq : m = n) :
  (cast (by exact cast_ConcreteBTField_eq m n h_eq) (x * y)) =
  (cast (by exact cast_ConcreteBTField_eq m n h_eq) x) *
  (cast (by exact cast_ConcreteBTField_eq m n h_eq) y)

theorem dcast_eq_root_cast (h : a = a') : dcast h b = _root_.cast (congrArg β h) b

@[simp]
theorem cast_perfectCompleteness (hComplete : R.perfectCompleteness init impl relIn relOut) :
    (R.cast hn hSpec hOₘ).perfectCompleteness init impl relIn relOut

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)

theorem size_le_size (p : UniPoly R) : p.trim.size ≤ p.size

@[simp]
lemma evenize_coeff {f : Polynomial F} {n : ℕ} :
    (evenize f).coeff n = if Even n then f.coeff (n / 2) else 0

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

lemma W_is_additive
  (i : Fin r) :
  IsLinearMap (R := 𝔽q) (M := L) (M₂ := L) (f := fun x ↦ (W 𝔽q β i).eval x)

@[simp]
theorem cast_id : ProtocolSpec.cast (Eq.refl n₁) = id

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]
private lemma evenPart'_coeffs {f : Polynomial F} {n : ℕ} :
    (evenPart' f).coeff n = if Even n then f.coeff n else 0

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

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

lemma getBit_of_lowBits {n: ℕ} (numLowBits : ℕ) : ∀ k, getBit k (getLowBits numLowBits n) =
    if k < numLowBits then getBit k n else 0

Nat.mul_le_mul_right in Init.Data.Nat.Basic

@[simp]
theorem bool_accepts_iff : (bool j).accepts x ↔ x j * (x j - 1) = 0

lemma concrete_mul_one
  (prevBTFieldProps : ConcreteBTFieldProps (k := k - 1))
  (a : ConcreteBTField k) : concrete_mul a (one (k:=k)) = a

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

lemma num_eq_highBits_xor_lowBits {n: ℕ} (numLowBits: ℕ) :
  n = getHighBits numLowBits n ^^^ getLowBits numLowBits n

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 fieldSize_sub_one_factorization : fieldSize - 1 = 2 ^ twoAdicity * 127

theorem GF_2_one_add_one_eq_zero : (1 + 1 : GF(2)) = 0

lemma rank_eq_if_subUpFull_eq (h : n ≤ m) :
   (subUpFull U (Fin.castLE h)).rank = n  → U.rank = n

lemma NTTStage_correctness (i : Fin (ℓ))
    (input_buffer : Fin (2 ^ (ℓ + R_rate)) → L) (original_coeffs : Fin (2 ^ ℓ) → L) :
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (evaluation_buffer:=input_buffer)
      (original_coeffs:=original_coeffs) (i := ⟨i.val+1, by omega⟩) →
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (evaluation_buffer:=NTTStage 𝔽q β h_ℓ_add_R_rate
      ⟨i, by omega⟩ input_buffer) (original_coeffs:=original_coeffs) ⟨i, by omega⟩

@[simp]
lemma finite_possibleDeltas : (possibleDeltas U V).Finite

theorem generator_on_curve : let (x, y) := generator
  y^2 = x^3 + 3

@[simp]
theorem cast_perfectCompleteness (hComplete : R.perfectCompleteness init impl relIn relOut) :
    (R.cast hn hSpec).perfectCompleteness init impl relIn relOut

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

lemma concrete_mul_inv_cancel
  (prevBTFieldResult : ConcreteBTFStepResult (k := k - 1))
  (a : ConcreteBTField k) (h : a ≠ 0) :
  concrete_mul a (concrete_inv a) = one

@[csimp]
theorem dappend_eq_addCases : @dappend = @addCases

theorem append_soundness {lang₁ : Set Stmt₁} {lang₂ : Set Stmt₂} {lang₃ : Set Stmt₃}
    (V₁ : Verifier oSpec Stmt₁ Stmt₂ pSpec₁) (V₂ : Verifier oSpec Stmt₂ Stmt₃ pSpec₂)
    {soundnessError₁ soundnessError₂ : ℝ≥0}
    (h₁ : V₁.soundness init impl lang₁ lang₂ soundnessError₁)
    (h₂ : V₂.soundness init impl lang₂ lang₃ soundnessError₂) :
      (V₁.append V₂).soundness init impl lang₁ lang₃ (soundnessError₁ + soundnessError₂)

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

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

omit [BEq R] in
lemma neg_coeff : ∀ (p : UniPoly R) (i : ℕ), p.neg.coeff i = - p.coeff i

@[simp]
lemma numFullRounds_pos : 0 < params.numFullRounds

theorem nsmul_succ (n : ℕ) (p : UniPolyC R) : nsmul (n + 1) p = nsmul n p + p

@[simp]
lemma eval_solutionToQ_zero {x : F} {v} : eval x (solutionToQ 0 k v) =
                                          ∑ a ∈ Finset.range k, liftF v a * x ^ a

lemma smul_Z_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField (k - 1)) :
  letI instAlgebra := ConcreteBTFieldAlgebra (l:=k-1) (r:=k) (h_le:=by omega)
  x • Z k = 《 x, 0 》

omit [NoZeroDivisors 𝔽] in
lemma foldNth_degree_le' {n : ℕ} {f : 𝔽[X]} {α : 𝔽} [inst : NeZero n] :
    n * (foldNth n f α).natDegree ≤ f.natDegree

lemma split_algebraMap_eq_zero_x {k : ℕ} (h_pos : k > 0) (x : BTField (k - 1)) :
  letI instAlgebra := binaryAlgebraTower (l:=k-1) (r:=k) (h_le:=by omega)
  split (k:=k) (h_k:=h_pos) (algebraMap (BTField (k - 1)) (BTField k) x) = (0, x)

lemma liftF_ne_zero_of_lt {i : ℕ} (h : i < n) : liftF f' i ≠ 0 ↔ f' ⟨i, h⟩ ≠ 0

theorem singleton_subset_Icc (n : ℕ) : {1} ⊆ Finset.Icc 1 (n + 1)

theorem insertNth_ne_zero_iff : insertNth p y s ≠ 0 ↔ y ≠ 0 ∨ s ≠ 0

theorem liftContext_completeness
    (h : R.completeness init impl innerRelIn innerRelOut completenessError) :
      (R.liftContext lens).completeness init impl outerRelIn outerRelOut completenessError

@[simp] lemma my_neg_mod_two (m : ℤ) : ( - m) % 2 = if m % 2 = 0 then 0 else 1

lemma bIdx_succ_mul_ϑ_le_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) : (↑bIdx + 1) * ϑ ≤ ℓ + 1

@[simp]
theorem singleEqPolynomial_one (x : MvPolynomial σ R) : singleEqPolynomial (1 : R) x = x

@[simp] theorem rightpad_prefix (n : Nat) (unit : α) (l : List α) :
    l <+: rightpad n unit l

@[simp]
theorem cast_dir_idx {hn} (hSpec : pSpec₁.cast hn = pSpec₂) {i : Fin n₁} :
    pSpec₂.dir (Fin.cast hn i) = pSpec₁.dir i

@[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 folding_steps_pos : (ϑ : ℕ) > 0

@[simp]
private lemma leadingCoeff_E : (E ωs f p e).leadingCoeff = 1

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₂

theorem induction_tail {n : ℕ} {motive : Fin (n + 2) → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin (n + 1), motive i.castSucc → motive i.succ} {i : Fin (n + 1)} :
      induction (motive := motive) zero succ i.succ =
        induction (motive := Fin.tail motive) (succ 0 zero) (fun j x => succ j.succ x) i

@[simp]
lemma getTypes_eq_get_fst (l : HList) (i : Fin l.length) : l.getTypes[i] = l[i].1

theorem relayOracleVerifier_rbrKnowledgeSoundness (i : Fin ℓ)
    (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
    (relayOracleVerifier 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        i hNCR).rbrKnowledgeSoundness 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)
      (relayKnowledgeError)

theorem split_zero {k : ℕ} (h_pos : k > 0) : split h_pos zero = (zero, zero)

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

lemma lastBlockIdx_isNeCommitmentRound (i : Fin ϑ) :
    ¬isCommitmentRound ℓ ϑ ⟨(ℓ / ϑ - 1) * ϑ + ↑i, lastBlockIdx_mul_ϑ_add_fin_lt_ℓ i⟩

@[simp]
lemma runWithLog_discard_log_eq_run (stmt : StmtIn) (wit : WitIn)
    (prover : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec) :
      Prod.fst <$> prover.runWithLog stmt wit = prover.run stmt wit

private lemma BerlekampWelchCondition_to_Solution [NeZero n]
  (hk_or_e : 1 ≤ k ∨ 1 ≤ e)
  (h : BerlekampWelchCondition e k ωs f E Q)
  : IsBerlekampWelchSolution e k ωs f (E_and_Q_to_a_solution e E Q)

lemma join_eq_join_iff (k : ℕ) (h_pos : k > 0) (hi₁ hi₀ lo₁ lo₀ : BTField (k - 1)) :
    ⋘ hi₁, lo₁ ⋙ = ⋘ hi₀, lo₀ ⋙ ↔
  hi₁ = hi₀ ∧ lo₁ = lo₀

theorem mul_two_eq_add {a : CNat 50} : a * 2 = a + a

theorem dcast₃_symm (ha : a = a') (hb : dcast ha b = b') (hc : dcast₂ ha hb c = c')
    (hd : dcast₃ ha hb hc d = d') :
    dcast₃ ha.symm (dcast_symm ha hb) (dcast₂_symm ha hb hc) d' = d

@[simp]
theorem Ici_succ (i : Fin n) : Ici i.succ = (Ici i).map (Fin.succEmb _)

Nat.zero_add in Init.Data.Nat.Basic

@[simp]
theorem splitSum_zero {n : Fin 0 → ℕ} {k : Fin (vsum n)} : splitSum k = Fin.elim0 k

theorem BaseField_is_prime : Nat.Prime BASE_FIELD_CARD

@[simp, grind] lemma absorbPos_lt_N (sponge : DuplexSponge U C) :
    sponge.absorbPos < SpongeSize.N

theorem two_eq_zero_in_char2_field {F : Type*} [Field F]
  (sumZeroIffEq : ∀ (x y : F), x + y = 0 ↔ x = y) : (2 : F) = 0

theorem rightpad_eq_rightpad_max (l : List α) (n : Nat) :
    rightpad n unit l = rightpad (max n l.length) unit l

@[simp] theorem ofNat_succ (n : Nat) : ofNat n.succ = succ (ofNat n)

@[simp]
protected lemma elocPoly_two :
  ElocPoly 2 ωs f p =
  if f 1 = eval (ωs 1) p
  then if f 0 = eval (ωs 0) p then 1
       else X - C (ωs 0)
  else if f 0 = eval (ωs 0) p then X - C (ωs 1)
       else (X - C (ωs 0)) * (X - C (ωs 1))

theorem degrees_C_mul_le (p : MvPolynomial σ R) (c : R) : (C c * p).degrees ≤ p.degrees

theorem toNat_ofNat (n : ℕ) : toNat (ofNat n) = n

lemma roots_comp_X_sub_C (p : L[X]) (a : L) :
    (p.comp (X - C a)).roots = p.roots.map (fun r => r + 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))

@[simp] theorem equiv_refl (p : UniPoly Q) : equiv p p

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

theorem buildLayer_neverFails (α : Type) [inst : DecidableEq α] [inst_1 : SelectableType α]
    (preexisting_cache : (spec α).QueryCache) (n : ℕ)
    (leaves : List.Vector α (2 ^ (n + 1))) :
    ((simulateQ randomOracle (buildLayer α n leaves)).run preexisting_cache).neverFails

lemma cRank_rank_conversion :
  ↑(U.rank) = U.cRank

theorem dcast_symm (ha : a = a') (hb : dcast ha b = b') : dcast (ha.symm) b' = b

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

omit h_Fq_char_prime in
theorem changeOfBasisMatrix_diag_ne_zero
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
  (∀ i, (changeOfBasisMatrix 𝔽q β ℓ h_ℓ) i i ≠ 0)

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 take_drop_append {α : Sort*} (m : ℕ) (h : m ≤ n) (v : Fin n → α) :
    Fin.append (take m h v) (drop m h v) = fun i => v (i.cast (by omega))

omit [NeZero ℓ] [NeZero r] [NeZero 𝓡] in
lemma fin_ℓ_lt_r {h_ℓ_add_R_rate : ℓ + 𝓡 < r} (i : Fin ℓ)
    : i.val < r

theorem frobenius_identity_in_algebra [Fact (Nat.Prime (ringChar Fq))]
  (f g : L[X]) : (f + g)^(Fintype.card Fq) = f^(Fintype.card Fq) + g^(Fintype.card Fq)

theorem one_le_two_pow_n (n : ℕ) : 1 ≤ 2 ^ n

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

@[to_additive vsum_eq_univ_sum]
lemma vprod_eq_univ_prod [CommMonoid α] {a : Fin n → α} : vprod a = ∏ i, a i

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

lemma lifted_trace_map_eval_at_roots_prev_BTField
  {curBTField : Type*} [Field curBTField]
  (u : curBTField) (t1 : curBTField) -- here t1 is already lifted to curBTField
  (k : ℕ)
  (sumZeroIffEq : ∀ (x y : curBTField), x + y = 0 ↔ x = y)
  (u_plus_inv_eq_t1 : u + u⁻¹ = t1)
  (galois_automorphism : u^(2^(2^k)) = u⁻¹ ∧ (u⁻¹)^(2^(2^k)) = u)
  (trace_map_at_prev_root : ∑ i ∈ Finset.range (2 ^ k), t1 ^ (2 ^ i) = 1) :
  ∑ i ∈ Finset.range (2 ^ (k+1)), u ^ (2 ^ i) = 1

theorem 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

@[simp]
theorem drop_zero (v : (i : Fin n) → α i) : drop 0 n.zero_le v = v

lemma concrete_div_eq_mul_inv {k : ℕ} (a b : ConcreteBTField k) : a / b = a * (concrete_inv b)

lemma inv_eq_pow (a : Field) (ha : a ≠ 0) : a⁻¹ = a ^ (fieldSize - 2)

lemma mul_by_2_def {s : Finset ℕ} :
    mul_by_2 s = s.map ⟨fun n => 2 * n, by {
      intro a b
      simp
    }⟩

theorem simulateQ_bind_fst_comp (oa : OracleComp spec α) (f : α → OracleComp spec β) :
    (do let a ← (simulateQ loggingOracle oa).run; f a.1) = (do let a ← oa; f a)

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

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R deg D n oSpec).perfectCompleteness init impl
      (relationRound R n deg D 0) (relationRound R n deg D (.last n))

lemma xor_eq_sub_iff_submask {n m : ℕ} (h: m ≤ n) : n ^^^ m = n - m ↔ n &&& m = m

theorem commitOracleVerifier_rbrKnowledgeSoundness (i : Fin ℓ)
    (hCR : isCommitmentRound ℓ ϑ i) :
    (commitOracleVerifier 𝔽q β (ϑ := ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      i hCR).rbrKnowledgeSoundness 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)
      (commitKnowledgeError 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate))

lemma erase_odd_def {s : Finset ℕ} :
    erase_odd s = s.filter Even

lemma addSalt_Challenge (i : pSpec.ChallengeIdx) :
    (pSpec.addSalt Salt).Challenge i = pSpec.Challenge i

lemma solution_gamma_is_linear_in_Z
  (h_gs : ModifiedGuruswami m n k ωs Q u₀ u₁)
  :
  ∃ (v₀ v₁ : F[X]),
    γ' x₀ (R k δ x₀ h_gs) (irreducible_H k (x₀ := x₀) (δ := δ) h_gs) =
        AppendixA.polyToPowerSeries𝕃 _
          (
            (Polynomial.map Polynomial.C v₀) +
            (Polynomial.C Polynomial.X) * (Polynomial.map Polynomial.C v₁)
          )

omit [Fintype σ] in
theorem singleEqPolynomial_degreeOf (r : R) (i j : σ) :
    degreeOf i (singleEqPolynomial r (X j)) ≤ if i = j then 1 else 0

lemma is_berlekamp_welch_solution_ext
  (h : ∀ i, (Matrix.mulVec (BerlekampWelchMatrix e k ωs f) v) i = -(f i) * (ωs i) ^ e)
  : IsBerlekampWelchSolution e k ωs f v

@[simp]
lemma dfoldlM'_zero {α : Fin 1 → Type u} (f : (i : Fin 0) → α i.castSucc → m (α i.succ)) (x : α 0) :
    dfoldlM' 0 α f x = pure x

@[simp]
theorem FullData.get_leaf {α} (a : α) :
    (FullData.leaf a).get SkeletonNodeIndex.ofLeaf = a

@[simp]
theorem simulateQ_bind_fst (oa : OracleComp spec α) (f : α → OracleComp spec β) :
    (do let a ← (simulateQ loggingOracle oa).run; f a.1) = oa >>= f

theorem Basis_cast_dest_eq {ι : Type*} (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)
  @Basis ι (ConcreteBTField k) (ConcreteBTField m) _ _ instLeftAlgebra.toModule =
  @Basis ι (ConcreteBTField k) (ConcreteBTField n) _ _ instRightAlgebra.toModule

theorem degreeOf_X_of_ne (i j : σ) (h : i ≠ j) : degreeOf i (X (R := R) j) = 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

lemma resultant_is_divisible_by_leadingCoeff {F : Type} [CommRing F] [Inhabited F] (f : F[X])
  : ∃ r',
    Polynomial.resultant f (Polynomial.derivative f) = f.leadingCoeff * r'

theorem eq_trans {α : Type u} (mx my mz : m α) (hxy : eq mx my) (hyz : eq my mz) : eq mx mz

lemma erase_even_def {s : Finset ℕ} :
    erase_even s = s.filter Odd

theorem vconcat_eq_snoc (v : Fin n → α) (a : α) : vconcat v a = snoc v a

omit [NeZero ϑ] hdiv in
lemma toOutCodewordsCountOf0 : toOutCodewordsCount ℓ ϑ 0 = 1

theorem rbrKnowledgeSoundness_implies_rbrSoundness
    {relIn : Set (StmtIn × WitIn)} {relOut : Set (StmtOut × WitOut)}
    {verifier : Verifier oSpec StmtIn StmtOut pSpec}
    {rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0}
    (h : verifier.rbrKnowledgeSoundness init impl relIn relOut rbrKnowledgeError) :
    verifier.rbrSoundness init impl relIn.language relOut.language rbrKnowledgeError

theorem mul_assoc (m n p : ChurchNat α) : mul (mul m n) p = mul m (mul n p)

@[simp]
theorem prover_last_of_two (pSpec : ProtocolSpec 2) [ProverLast pSpec] :
    pSpec.dir 1 = .P_to_V

private lemma solutionToQ_from_Q
  (h_p_deg : p.natDegree < k)
  (h_dist : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  : solutionToQ e k (E_and_Q_to_a_solution e (E ωs f p e) (Q ωs f p e)) = Q ωs f p e

lemma ConcreteBTFieldAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
    @ConcreteBTFieldAlgebra (l:=l) (r:=r) (h_le:=h_le)
    = (concreteTowerAlgebraMap l r h_le).toAlgebra

Nat.zero_le in Init.Prelude

Fin.coe_castSucc in Init.Data.Fin.Lemmas

@[simp]
theorem cast_id : Verifier.cast rfl rfl = (id : Verifier oSpec StmtIn StmtOut pSpec₁ → _)

lemma bIdx_succ_mul_ϑ_lt_ℓ_succ (bIdx : Fin (ℓ / ϑ - 1)) :
    (↑bIdx + 1) * ϑ < ℓ + 1

@[simp]
lemma list_length (k : ℕ) : (list k).length = k + 1

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⟩

@[simp]
theorem ConcreteBTField.RingHom_cast_dest_apply (k m n : ℕ) (h_eq : m = n)
  (f : ConcreteBTField k →+* ConcreteBTField m) (x : ConcreteBTField k) :
    (cast (ConcreteBTField.RingHom_eq_of_dest_eq (k:=k) (m:=m) (n:=n) h_eq) f) x
    = cast (by apply cast_ConcreteBTField_eq (h_eq:=h_eq)) (f x)

@[simp]
theorem fappend₂_zero {α₁ : Fin m → A} {α₂ : Fin m → B} {β₁ : Fin 0 → A} {β₂ : Fin 0 → B}
    (u : (i : Fin m) → F₂ (α₁ i) (α₂ i)) :
    fappend₂ (F := F₂) u (!h⦃F₂⦄⟨β₁⟩⟨β₂⟩[] : (i : Fin 0) → F₂ (β₁ i) (β₂ i)) = u

omit [DecidableEq L] [DecidableEq 𝔽q] h_Fq_char_prime hF₂ hβ_lin_indep h_β₀_eq_1 in
theorem intermediateNormVpoly_comp (i : Fin ℓ) (k : Fin (ℓ - i + 1))
  (l : Fin (ℓ - (i.val + k.val) + 1)) :
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (k:=⟨k + l, by
      simp only; omega⟩) =
    (intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i+k, by omega⟩) (k:=⟨l, by
      simp only; omega⟩)).comp (
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) (k:=⟨k, by
      simp only; omega⟩)
  )

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⟩

lemma degree_definingPoly {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).degree = 2

theorem decoder_dist_impl_mem
  {k r D e : ℕ}
  (h_e : e ≤ n - Real.sqrt (k * n))
  {ωs : Fin n ↪ F}
  {f : Fin n → F}
  {p : F[X]}
  (h_dist : Δ₀(f, p.eval ∘ ωs) ≤ e)
  :
  p ∈ decoder k r D e ωs f

private lemma Fis_cover_B : B = Finset.univ.biUnion (Fi B i)

lemma le_sInf_of_LB {S : Set ℕ} (hne : S.Nonempty) {i : ℕ}
    (hLB : ∀ s ∈ S, i ≤ s) : i ≤ sInf S

theorem BitVec.eq_mp_eq_dcast {w w2 : ℕ} (x : BitVec w) (h_width_eq : w = w2)
  (h_bitvec_eq : BitVec w = BitVec w2 := by rw [h_width_eq]) :
  Eq.mp (h:=h_bitvec_eq) (a:=x) = dcast (h_width_eq) (x)

lemma concrete_zero_mul0 (b : ConcreteBTField 0) :
  concrete_mul (zero (k:=0)) b = zero (k:=0)

Fin.is_le' in Init.Data.Fin.Lemmas

Nat.le_add_left in Init.Data.Nat.Basic

@[simp]
lemma Fintype.zero_lt_card {ι : Type*} [Fintype ι] [Nonempty ι] : 0 < Fintype.card ι

lemma lin_shift_d [Field F] [Fintype F]
  (h_B : 2 ≤ B.card)
  :
  d B = d ({x - v | x ∈ B} : Finset _)

@[simp]
lemma deevenize_coeff {f : Polynomial F} {n : ℕ} :
    (deevenize f).coeff n = f.coeff (2 * n)

theorem base_intermediateNormVpoly
  (k : Fin (ℓ + 1)) :
  intermediateNormVpoly 𝔽q β h_ℓ_add_R_rate ⟨0, by
    by_contra ht
    simp only [not_lt, nonpos_iff_eq_zero] at ht
    contradiction
  ⟩ ⟨k, by simp only [tsub_zero]; omega⟩ =
  normalizedW 𝔽q β ⟨k, by omega⟩

lemma join_via_add_smul_one {k : ℕ} (h_pos : k > 0) :
  ⋘ 0, 1 ⋙ = 1

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

lemma AlgebraTowerEquiv.commutesRight' (e : AlgebraTowerEquiv A B)
    {i j : ι} (h : i ≤ j) (r : B i) :
  AlgebraTower.algebraMap (AT:=A) (i:=i) (j:=j) (h:=h) ((e.toRingEquiv i).symm r) =
  (e.toRingEquiv j).symm (AlgebraTower.algebraMap (AT:=B) (i:=i) (j:=j) (h:=h) r)

theorem cast_symm {α β : Sort u} {h : α = β} {a : α} {b : β} :
    cast h a = b ↔ a = cast h.symm b

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

theorem vcons_injective2 : Function.Injective2 (@vcons α n)

lemma sqrt_le_J {q δ : ℚ} (hq : q > 1) (hx0 : 0 ≤ δ) (hx1 : δ ≤ 1) (hqx : q / (q - 1) * δ ≤ 1) :
  1 - ((1-δ) : ℝ).sqrt ≤ J q δ

@[simp]
lemma degreeX_monomialXY {n m : ℕ} {a : F} (ha : a ≠ 0) :
    degreeX (monomialXY n m a) = n

private lemma Fis_pairwise_disjoint : Set.PairwiseDisjoint Set.univ (Fi B i)

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

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)

lemma getBit_of_lt_two_pow {n: ℕ} (a: Fin (2^n)) (k: ℕ) :
  getBit k a = if k < n then getBit k a else 0

@[simp]
theorem hflatten_succ {m : ℕ} {n : Fin (m + 1) → ℕ}
    {α : (i : Fin (m + 1)) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin (m + 1)) → (j : Fin (n i)) → α i j} :
    hflatten v = happend (v 0) (hflatten (fun i => v i.succ))

theorem vcons_left_injective (v : Fin n → α) : Function.Injective (fun a => a ::ᵛ v)

theorem reduction_perfectCompleteness (hInit : init.neverFails) :
    (reduction R n deg D oSpec i).perfectCompleteness init impl
    (relationRound R n deg D i.castSucc) (relationRound R n deg D i.succ)

@[simp, grind _=_]
theorem monomialXY_pow {n m k : ℕ} {a : F} :
  monomialXY n m a ^ k = monomialXY (n * k) (m * k) (a ^ k)

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)

lemma h_sum_two_same_pow2 {k : ℕ} (h_pos : k > 0) : 2 ^ (k - 1) + 2 ^ (k - 1) = 2 ^ k

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

@[csimp] lemma dfoldl_eq_dfoldl' : @dfoldl = @dfoldl'

@[simp]
lemma mul_by_empty :
    mul_by_2 ∅ = ∅

theorem PrattPartList.out {p : ℕ} {a : ZMod p} {n : ℕ} (h : PrattPartList p a n) :
    ∀ q : ℕ, q.Prime → q ∣ n → a ^ ((p - 1) / q) ≠ 1

List.length_drop in Init.Data.List.TakeDrop

@[simp]
lemma append_zero_of_succ_left {u : Fin (m + 1) → α} {v : Fin n → α} :
    (append u v) 0 = u 0

theorem join_eq_join_iff {k : ℕ} (h_pos : k > 0) (hi₀ lo₀ hi₁ lo₁ : ConcreteBTField (k - 1)) :
  《 hi₀, lo₀ 》 = 《 hi₁, lo₁ 》 ↔ (hi₀ = hi₁ ∧ lo₀ = lo₁)

lemma toImpl_nonzero {p : Q[X]} (hp : p ≠ 0) : p.toImpl.size > 0

theorem foldRelayOracleVerifier_rbrKnowledgeSoundness
    (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
    (foldRelayOracleVerifier 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i hNCR).rbrKnowledgeSoundness
      init impl
      (relIn := roundRelation 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑:=𝓑) i.castSucc (mp := mp))
      (relOut := roundRelation 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
        (𝓑:=𝓑) i.succ (mp := mp))
      (rbrKnowledgeError := fun m => foldKnowledgeError 𝔽q β (ϑ:=ϑ)
        (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i ⟨m, by
        match m with
        | ⟨0, h0⟩ => nomatch h0
        | ⟨1, h1⟩ => rfl
      ⟩)

theorem vappend_assoc {p : ℕ} (u : Fin m → α) (v : Fin n → α) (w : Fin p → α) :
    (vappend (vappend u v) w) = (vappend u (vappend v w)) ∘ Fin.cast (add_assoc m n p)

@[simp]
theorem LeafData.leftSubtree_internal {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right) :
    (LeafData.internal left right).leftSubtree = left

@[simp]
lemma addSalt_dir : (pSpec.addSalt Salt).dir = pSpec.dir

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

theorem computableAdditiveNTT_eq_additiveNTT (a : Fin (2 ^ ℓ) → L) :
  computableAdditiveNTT (𝔽q := 𝔽q) (β := β) (ℓ := ℓ) (R_rate := R_rate)
    (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (a := a) =
  additiveNTT (𝔽q := 𝔽q) (L := L) (β := β) (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (a := a)

@[simp]
lemma width_pos : 0 < params.width

lemma liftF'_liftF_of_lt {k : Fin m} (h : k < n) :
  liftF' (n := m) (liftF (n := n) f') k = f' ⟨k, by omega⟩

lemma eq_evenize_deevenize {f : Polynomial F} (hEven : EvenPoly f) :
    evenize (deevenize f) = f

theorem generates_quotient_point_if_is_fiber_of_y
    (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i.val + steps ≤ ℓ)
    (x : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩))
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩))
    (hx_is_fiber : ∃ (k : Fin (2 ^ steps)), x = qMap_total_fiber 𝔽q β (i := ⟨i, by omega⟩)
      (steps := steps) (h_i_add_steps := by
        simp only; exact fin_ℓ_steps_lt_ℓ_add_R i steps h_i_add_steps) (y := y) k) :
    y = iteratedQuotientMap 𝔽q β h_ℓ_add_R_rate i (k := steps) (h_bound := h_i_add_steps) x

Fin.val_succ in Init.Data.Fin.Lemmas

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)

@[simp]
theorem hcons_one {β : Fin (n + 1) → Sort u} (a : α) (v : (i : Fin (n + 1)) → β i) :
    hcons a v 1 = cast (vcons_succ α β 0).symm (v 0)

theorem FullData.map_getRootValue {α β : Type} {s : Skeleton}
    (f : α → β) (tree : FullData α s) :
    (tree.map f).getRootValue = f (tree.getRootValue)

@[simp]
theorem reduction_completeness (h : init.neverFails) :
    (reduction oSpec Statement Witness).perfectCompleteness init impl relIn (toRelOut relIn)

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

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

@[simp] theorem rightpadPowerOfTwo_size (unit : α) (a : Array α) :
    (a.rightpadPowerOfTwo unit).size = 2 ^ (Nat.clog 2 a.size)

lemma coeff_vectors_linear_independent
  (ℓ : Nat) (h_ℓ : ℓ ≤ r) :
    LinearIndependent L (toCoeffsVec (ℓ := ℓ) ∘ (basisVectors 𝔽q β ℓ h_ℓ))

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

@[simp]
theorem happend_left {α : Fin m → Sort u} {β : Fin n → Sort u}
    (u : (i : Fin m) → α i) (v : (i : Fin n) → β i) (i : Fin m) :
    happend u v (castAdd n i) = cast (vappend_left α β i).symm (u i)

theorem intermediateNormVpoly_comp_qmap (i : Fin (ℓ))
    (k : Fin (ℓ - i - 1)) : -- corresponds to intermediateNormVpoly_comp

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

theorem cast_eq_dcast₂ {hn} {hSpec : pSpec₁.cast hn = pSpec₂} {i : MessageIdx pSpec₁}:
    i.cast hn hSpec = dcast₂ hn hSpec i

theorem rightpad_getElem_eq_getD {a : Array α} {n : Nat} {unit : α} {i : Nat}
    (h : i < (a.rightpad n unit).size) : (a.rightpad n unit)[i] = a.getD i unit

lemma twoAdicGenerators_order (bits : Fin (twoAdicity + 1)) :
    orderOf (twoAdicGenerators[bits]) = 2 ^ (bits : Nat)

Fin.eta in Init.Data.Fin.Lemmas

@[simp]
theorem oracleReduction_completeness (hInit : init.neverFails) :
    (oracleReduction oSpec OStatement).perfectCompleteness
      init impl (relIn OStatement) (relOut OStatement)

lemma Fin.le_iff_lt_succ (a b : Fin r) (h_b : b + 1 < r) : a ≤ b ↔ a < b + 1

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

theorem snoc_ne_zero_of_left (h : s ≠ 0) : snoc s y ≠ 0

@[simp]
theorem dist_subsingleton {C : Set (n → R)} [Subsingleton C] : ‖C‖₀ = 0

@[simp]
theorem Set.not_mem_language_iff {α β} (rel : Set (α × β)) (stmt : α) :
    stmt ∉ rel.language ↔ ∀ wit, (stmt, wit) ∉ rel

@[simp]
theorem removeNth_update : removeNth p (update s p y) = removeNth p s

private lemma x_times_oddPart'_eq_x_times_oddPart' {f : Polynomial F} :
    Polynomial.X * (oddPart' f) = x_times_oddPart' f

lemma getBit_of_sub_two_pow_of_bit_1 {n i j: ℕ} (h_getBit_eq_1: getBit i n = 1) :
  getBit j (n - 2^i) = (if j = i then 0 else getBit j n)

lemma liftF_eq_of_lt {i : ℕ} (h : i < n) : liftF f' i = f' ⟨i, h⟩

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

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

@[simp]
lemma Rhs_add_one : Rhs (e + 1) ωs f = fun i ↦ Rhs e ωs f i * ωs i

lemma folding_preserves_listdecoding_base_ne_subset
  {S : Finset ι} {k m : ℕ} (hm : 1 ≤ m) {φ : ι ↪ F} [Smooth φ] {δ : ℝ≥0}
  {S_0 : Finset (indexPowT S φ 0)} {S_1 : Finset (indexPowT S φ 1)}
  {φ_0 : (indexPowT S φ 0) ↪ F} {φ_1 : (indexPowT S φ 1) ↪ F}
  [∀ i : ℕ, Fintype (indexPowT S φ i)] [∀ i : ℕ, DecidableEq (indexPowT S φ i)]
  [Smooth φ_0] [Smooth φ_1]
  [h : ∀ {f : (indexPowT S φ 0) → F}, DecidableBlockDisagreement 0 k f S_0 φ_0]
  [h : ∀ {f : (indexPowT S φ 1) → F}, DecidableBlockDisagreement 1 k f S_1 φ_1]
  [∀ i : ℕ, Neg (indexPowT S φ i)]
  {C : Set ((indexPowT S φ 0) → F)} (hcode : C = smoothCode φ_0 m)
  (C' : Set ((indexPowT S φ 1) → F)) (hcode' : C' = smoothCode φ_1 (m-1))
  {BStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0}
  {errStar : (Set (indexPowT S φ 1 → F)) → ℕ → ℝ≥0 → ℝ≥0} :
    Pr_{let α ←$ᵖ F}[ ∀ { f : (indexPowT S φ 0) → F} (hδLe: δ ≤ 1 - (BStar C' 2)),
                      let listBlock : Set ((indexPowT S φ 0) → F) := Λᵣ(0, k, f, S_0, C, hcode, δ)
                      let vec_α : Fin 1 → F := (fun _ : Fin 1 => α)
                      let foldSet := fold_k_set listBlock vec_α hm
                      let fold := fold_k f vec_α hm
                      let listBlock' : Set ((indexPowT S φ 1) → F)
                        := Λᵣ(1, k, fold, S_1, C', hcode', δ)
                      ¬ (listBlock' ⊆ foldSet)
                    ] < errStar C' 2 δ

lemma C_injective : Function.Injective (C : R → P)

lemma algebraMap_binaryTowerAlgebra_def (l r : ℕ) (h_le : l ≤ r) :
  (@binaryAlgebraTower (l:=l) (r:=r) (h_le:=h_le)).algebraMap = towerAlgebraMap l r h_le

Nat.add_sub_cancel in Init.Data.Nat.Basic

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

@[simp]
theorem PowerBasis.cast_basis_succ_of_eq_rec_apply
    (r1 r : ℕ) (h_r : r = r1 + 1)
    (k : Fin 2) :
    letI instAlgebra : Algebra (ConcreteBTField r1) (ConcreteBTField r) :=
      ConcreteBTFieldAlgebra (l:=r1) (r:=r) (h_le:=by omega)
    letI instAlgebraSucc : Algebra (ConcreteBTField (r1 + 1)) (ConcreteBTField (r)) :=
      ConcreteBTFieldAlgebra (l:=r1 + 1) (r:=r) (h_le:=by omega)
    let b : PowerBasis (ConcreteBTField r1) (ConcreteBTField (r1 + 1))
      := powerBasisSucc (k:=r1)
    let bCast : PowerBasis (ConcreteBTField r1) (ConcreteBTField r) := Eq.rec (motive:=
      fun (x : ℕ) (_ : r1 + 1 = x) => by
        letI instAlgebraCur : Algebra (ConcreteBTField r1) (ConcreteBTField x) :=
          ConcreteBTFieldAlgebra (l:=r1) (r:=x) (h_le:=by omega)
        exact PowerBasis (ConcreteBTField r1) (ConcreteBTField x)) (refl:=b) (t:=h_r.symm)
    have h_pb_dim : b.dim = 2 := by
      exact powerBasisSucc_dim r1

    have h_pb'_dim : bCast.dim = 2 := by
      dsimp [bCast]
      rw [PowerBasis.dim_of_eq_rec (r1:=r1) (r:=r) (h_r:=h_r) (b:=b)]
      exact h_pb_dim

    have h_pb_type_eq : Basis (Fin bCast.dim) (ConcreteBTField r1) (ConcreteBTField r) =
      Basis (Fin 2) (ConcreteBTField r1) (ConcreteBTField r) := by
      congr

   -- The `cast` needs a proof that `bCast.dim = 2`. We construct it here.
    let left : Basis (Fin 2) (ConcreteBTField r1) (ConcreteBTField r)
      := cast (by exact h_pb_type_eq) bCast.basis
    let right := (algebraMap (ConcreteBTField (r1 + 1)) (ConcreteBTField r))
      (b.basis (Fin.cast h_pb_dim.symm k))
    left k = right

@[simp]
lemma not_P_to_V_eq_V_to_P {x : Direction} (h : x ≠ .V_to_P) : x = .P_to_V

lemma evenPart_even {f : Polynomial F} :
    EvenPoly (evenPart f)

lemma h_middle_sub {k : ℕ} : 2 ^ (k - 1) - 1 - 0 + 1 = 2 ^ (k - 1)

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

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

theorem seqCompose_soundness
    (lang : (i : Fin (m + 1)) → Set (Stmt i))
    (V : (i : Fin m) → Verifier oSpec (Stmt i.castSucc) (Stmt i.succ) (pSpec i))
    (soundnessError : Fin m → ℝ≥0)
    (h : ∀ i, (V i).soundness init impl (lang i.castSucc) (lang i.succ) (soundnessError i)) :
      (Verifier.seqCompose Stmt V).soundness init impl (lang 0) (lang (Fin.last m))
        (∑ i, soundnessError i)

theorem liftContext_runToRound
    {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).runToRound i outerStmtIn outerWitIn
      = do
        let ⟨transcript, prvState⟩ ←
          (P.runToRound i).uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨transcript, ⟨prvState, outerStmtIn, outerWitIn⟩⟩

theorem vcons_eq_const (a : α) : a ::ᵛ (fun _ : Fin n => a) = fun _ => a

theorem succ_eq_one_add (n : ChurchNat α) : succ n = add one n

private lemma natDegree_E
  (h : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e) :
  (E (ωs := ωs) f p e).natDegree = e

lemma one_bitvec_shiftRight {d : ℕ} (h_d : d > 0) : 1 >>> d = 0

lemma qMap_total_fiber_basis_sum_repr (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)) :
    let x : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i, by omega⟩) := 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)
    let basis_x := sDomain_basis 𝔽q β h_ℓ_add_R_rate ⟨i, by omega⟩
      (by simp only; apply Nat.lt_add_of_pos_right_of_le; omega)
    let basis_y := sDomain_basis 𝔽q β h_ℓ_add_R_rate ⟨i + steps, by omega⟩
      (h_i := by apply Nat.lt_add_of_pos_right_of_le; omega)
    let y_coeffs := basis_y.repr y
    x = ∑ j : Fin (ℓ + 𝓡 - i), (
      fiber_coeff (i := i) (steps := steps) (j := j) (elementIdx := k) (y_coeffs := y_coeffs)
    ) • (basis_x j)

lemma and_by_split_lowBits {n m n1 m1 bn bm : ℕ} (h_bn : bn < 2) (h_bm : bm < 2)
  (h_n : n = n1 * 2 + bn) (h_m : m = m1 * 2 + bm):
  n &&& m = (n1 &&& m1) * 2 + (bn &&& bm)

theorem funext₂_heq_iff {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v}
    {γ : (a : α) → β a → Sort w} {γ' : (a : α') → β' a → Sort w}
    {f : (a : α) → (b : β a) → γ a b} {g : (a : α') → (b : β' a) → γ' a b}
    (ha : α = α') (hb : ∀ a, β a = β' (cast ha a))
    (hc : ∀ a b, γ a b = γ' (cast ha a) (cast (hb a) b)) :
      HEq f g ↔ ∀ a b, HEq (f a b) (g (cast ha a) (cast (hb a) b))

@[simp]
theorem Vector.ofFn_get {α : Type*} {n : ℕ} (v : Vector α n) : Vector.ofFn (Vector.get v) = v

@[grind _=_]
lemma weightedDegree_eq_natWeightedDegree {u v : ℕ} :
  f ≠ 0 → weightedDegree f u v = natWeightedDegree f u v

lemma oracle_block_k_next_le (i : Fin (ℓ + 1)) (j : Fin (toOutCodewordsCount ℓ ϑ i))
    (hj : j.val + 1 < toOutCodewordsCount ℓ ϑ i) : j.val * ϑ + ϑ ≤ i

theorem insertNth_ne_zero_of_right (h : s ≠ 0) : insertNth p y s ≠ 0

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

theorem eqPolynomial_symm (x : σ → R) (y : σ → R) :
    MvPolynomial.eval y (eqPolynomial x) = MvPolynomial.eval x (eqPolynomial y)

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

theorem unique_linear_decomposition_succ (k : ℕ) :
  letI : Algebra (ConcreteBTField k) (ConcreteBTField (k+1)) :=
    ConcreteBTFieldAlgebra (l:=k) (r:=k+1) (h_le:=by omega)
  ∀ (x : ConcreteBTField (k+1)), ∃! (p : ConcreteBTField k × ConcreteBTField k),
    x = join_via_add_smul (k+1) (by omega) p.1 p.2

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)

omit [DecidableEq 𝔽q] hF₂ in
lemma initial_tiled_coeffs_correctness (h_ℓ : ℓ ≤ r) (a : Fin (2 ^ ℓ) → L) :
    let b: Fin (2^(ℓ + R_rate)) → L := tileCoeffs a
    additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate b a (i := ⟨ℓ, by omega⟩)

@[simp]
theorem cast_id :
    OracleProver.cast rfl rfl =
      (id : OracleProver oSpec StmtIn OStmtIn WitIn StmtOut OStmtOut WitOut pSpec₁ → _)

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

theorem vcons_right_injective (a : α) :
    Function.Injective (vcons a : (Fin n → α) → Fin (n + 1) → α)

@[simp]
theorem seqCompose_zero {n : Fin 0 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    {T : ∀ i, FullTranscript (pSpec i)} :
    seqCompose T = !h[]

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)

@[simp]
theorem snoc_castSucc : snoc s y i.castSucc = s i

lemma coeff_eq_getElem {p : UniPoly Q} {i} (hp : i < p.size) :
  p.coeff i = p[i]

Nat.lt_trans in Init.Prelude

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

@[simp]
theorem cast_dir_idx_symm {hn} (hSpec : pSpec₁.cast hn = pSpec₂) {i : Fin n₂} :
    pSpec₁.dir (Fin.cast hn.symm i) = pSpec₂.dir i

@[simp]
theorem cast_id :
    OracleVerifier.cast rfl rfl (fun i => rfl) =
      (id : OracleVerifier oSpec StmtIn OStmtIn StmtOut OStmtOut pSpec₁ → _)

lemma mulVec_BerlekampWelchMatrix_eq :
  (BerlekampWelchMatrix e k ωs f).mulVec v i =
  ∑ x : Fin (2 * e + k), v x * if x < e then f i * ωs i ^ x.1 else -ωs i ^ (x - e)

Nat.sub_lt_left_of_lt_add in Init.Data.Nat.Basic

lemma div_2_form {nD2 b : ℕ} (h_b : b < 2):
  (nD2 * 2 + b) / 2 = nD2

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ᵢ

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

@[simp]
lemma dotProduct_cons [AddCommMonoid R] [Mul R] (a : R) (b : Vector R n) (c : R) (d : Vector R n) :
  dotProduct (cons a b) (cons c d) = a * c + dotProduct b d

lemma zero_def [Zero R] : zero = Vector.replicate (2 ^ n) 0

@[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 lin_shift_e [Field F] [Fintype F]
  (h_B : B.card ≠ 0)
  :
  e B v = e ({ x - v | x ∈ B} : Finset _) 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]
lemma numPartialRounds_pos : 0 < params.numPartialRounds

lemma algebraMap_adjacent_tower_def (l : ℕ) :
  (algebraMap (BTField l) (BTField (l + 1))) = canonicalEmbedding l

nonpos_iff_eq_zero in Mathlib.Algebra.Order.Monoid.Canonical.Defs

@[simp]
lemma getTypes_nil : getTypes [] = []

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 cube_map_bijective :
    Function.Bijective (fun x : (Field)ˣ => x ^ (3 : Nat))

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

@[simp]
theorem simulateQ'_bind (oa : OracleComp spec α) (ob : α → OracleComp spec β)
    -- Could potentially be weakened to `∀ x ∈ oa.support, (ob x).neverFails`
    -- Would require `bindOnSupport` instead of just `bind`
    (ha : oa.neverFails) (hb : ∀ x, (ob x).neverFails) :
      simulateQ' so (oa >>= ob) (by simp; exact ⟨ha, fun x _ => hb x⟩) =
      simulateQ' so oa ha >>= fun x ↦ simulateQ' so (ob x) (hb x)

lemma getBit_two_pow {i k : ℕ} : (getBit k (2^i) = if i == k then 1 else 0)

@[simp]
lemma relHammingDist_le_one : δᵣ(u, v) ≤ 1

theorem Nat.reconstruct_from_hi_and_lo_parts_or_ver (n hi_len lo_len : ℕ)
  (h_n : n < 2 ^ (hi_len + lo_len)) :
    n = (((n >>> lo_len) % (2 ^ hi_len)) <<< lo_len) ||

theorem prime_11 : Nat.Prime 11

@[simp]
theorem vconcat_zero (a : α) : vconcat !v[] a = !v[a]

lemma min_dist_le_d [Field F] {B : Finset (Fin n → F)} (v : Fin n → F)
  :
  sInf { d | ∃ u ∈ B, ∃ v ∈ B, u ≠ v ∧ hammingDist u v = d } ≤ d B

lemma powerBasisSucc_gen (k : ℕ) :
  (powerBasisSucc k).gen = (Z (k+1))

@[simp] theorem mul_one {a : AssocNat} : a * 1 = a

theorem drop_repeat {α : Type*} {n' : ℕ} (m : ℕ) (h : m ≤ n) (a : Fin n' → α) :
    drop (m * n') (Nat.mul_le_mul_right n' h) (Fin.repeat n a) =
      fun i : Fin (n * n' - m * n') =>
          (Fin.repeat (n - m) a (i.cast (Nat.sub_mul n m n').symm))

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

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'

lemma domain_injective {i : ℕ} : i ≤ n → Function.Injective (domain D x n i)

theorem fappend_ext {α : Fin m → A} {β : Fin n → A}
    (u₁ u₂ : (i : Fin m) → F (α i)) (v₁ v₂ : (i : Fin n) → F (β i)) :
    fappend u₁ v₁ = fappend u₂ v₂ ↔ u₁ = u₂ ∧ v₁ = v₂

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

protected lemma abs_one_sub_div_le_one {v a : Fin n → F}
  (h_card : 2 ≤ Fintype.card F)
  :
  |1 - (1 + 1 / ((Fintype.card F : ℚ) - 1)) * Δ₀(v, a) / n

@[simp]
theorem append_fst (T₁ : FullTranscript pSpec₁) (T₂ : FullTranscript pSpec₂) :
    (T₁ ++ₜ T₂).fst = T₁

lemma algebraMap_adjacent_tower_succ_eq_Adjoin_of (k : ℕ) :
  (algebraMap (BTField k) (BTField (k + 1))) = of (poly k)

theorem evalNormalizedWAt_eq_normalizedW (i : Fin r) (x : L) :
  evalNormalizedWAt (β := β) (ℓ := ℓ) (R_rate := R_rate) (i := i) x
    = (normalizedW (𝔽q := 𝔽q) (β := β) (i := i)).eval x

@[simp]
theorem cast_id : Transcript.cast rfl rfl rfl = (id : pSpec₁.Transcript k → _)

@[simp]
theorem dcons_zero {motive : Fin (n + 1) → Sort u} (a : motive 0)
    (v : (i : Fin n) → motive i.succ) : (a ::ᵈ⟨motive⟩ v) 0 = a

@[simp]
theorem LeafData.optionComposeBuild_internal {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (compose : α → α → Option α) :
    (LeafData.internal left right).optionComposeBuild compose =
      FullData.internal
        (Option.doubleBind compose
          (left.optionComposeBuild compose).getRootValue
          (right.optionComposeBuild compose).getRootValue)
        (left.optionComposeBuild compose)
        (right.optionComposeBuild compose)

theorem cast_processRound (j : Fin n₁)
    (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₁)
    (currentResult : OracleComp (oSpec ++ₒ [pSpec₁.Challenge]ₒ)
      (Transcript j.castSucc pSpec₁ × P.PrvState j.castSucc)) :
    P.processRound j currentResult =
      cast (sorry) ((P.cast hn hSpec).processRound (Fin.cast hn j) sorry)

@[simp]
theorem Reduction.id_runWithLog (stmt : StmtIn) (wit : WitIn) :
    (Reduction.id : Reduction oSpec StmtIn WitIn _ _ _).runWithLog stmt wit =
      pure ⟨⟨⟨default, stmt, wit⟩, stmt⟩, [], []⟩

@[simp]
theorem fflatten₂_one {A : Sort u} {B : Sort v} {F : A → B → Sort w} {n : Fin 1 → ℕ}
    {α : (i : Fin 1) → (j : Fin (n i)) → A}
    {β : (i : Fin 1) → (j : Fin (n i)) → B}
    {v : (i : Fin 1) → (j : Fin (n i)) → F (α i j) (β i j)} :
    fflatten₂ v = v 0

theorem support_finSuccEquivNth_nonempty {f : MvPolynomial (Fin (n + 1)) R} (h : f ≠ 0) :
    (finSuccEquivNth R p f).support.Nonempty

private lemma almost_johnson_lhs_div_B_card [Zero F]
  (h_n : 0 < n)
  (h_B : 2 ≤ B.card)
  :
  (k B * (k B - 1)  +
    (B.card - k B) * ((B.card - k B)/(Fintype.card F - 1) - 1)) / B.card
  =
  (1 - e B 0 / n) ^ 2 * B.card + B.card * (e B 0) ^ 2 / ((Fintype.card F - 1) * n^2) - 1

theorem nsmul_raw_succ (n : ℕ) (p : UniPoly Q) :
  nsmul_raw (n + 1) p = add_raw (nsmul_raw n p) p

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)

lemma rank_eq_colRank : U.rank = colRank U

Fin.val_injective in Mathlib.Data.Fin.Basic

theorem rightpad_eq_if_rightpad_eq_of_ge (l l' : List α) (m n n' : Nat) (h : n ≤ m) (h' : n' ≤ m) :
    rightpad n unit l = rightpad n' unit l' →
        rightpad m unit l = rightpad m unit l'

theorem fcons_injective2 {β : Fin n → A} :
    Function.Injective2 (@fcons A F n α β)

theorem degreeOf_eval_C_finSuccEquiv (p : MvPolynomial (Fin (n + 1)) R) (j : Fin n) (x : R) :
    degreeOf j (Polynomial.eval (C x) (finSuccEquiv R n p)) ≤ degreeOf j.succ p

@[simp] theorem toNat_mul (a b : AssocNat) : toNat (mul a b) = toNat a * toNat b

lemma f_eq_evenPart_plus_x_oddPart {f : Polynomial F} :
  f = evenPart f + Polynomial.X * oddPart f

@[simp, grind =]
theorem leadingCoeffY_eq_zero (f : F[X][Y]) : leadingCoeffY f = 0 ↔ f = 0

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 idxOf'_nil [BEq α] {a : α} : idxOf' a [] = 0

lemma eqRec_fun_eqRec_sort_eq_self {α : Sort*} {β : α → Sort u} {a a' : α}
    (h : a = a') (h' : β a = β a') (b : β a) :
  b = h ▸ h' ▸ b

theorem BerlekampWelchCondition_iff_Solution {e k : ℕ} [NeZero n]
  {ωs f : Fin n → F} {v : Fin (2 * e + k) → F}
  :
  IsBerlekampWelchSolution e k ωs f v
  ↔
  (BerlekampWelchCondition e k ωs f (solutionToE e k v) (solutionToQ e k v))

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

@[simp]
lemma finite_possibleRelHammingDistsToCode [Nonempty ι] [DecidableEq F] :
  (possibleDistsToCode w C relHammingDist).Finite

@[simp]
theorem happend_empty {α : Fin m → Sort u} {β : Fin 0 → Sort u} (v : (i : Fin m) → α i) :
    happend v !h⟨β⟩[] = v

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

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

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)

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 concrete_eq_zero_or_eq_one {k : ℕ} {a : ConcreteBTField k} (h_k_zero : k = 0)
 : a = zero ∨ a = one

theorem liftContext_rbr_knowledgeSoundness [Inhabited InnerWitIn]
    {rbrKnowledgeError : pSpec.ChallengeIdx → ℝ≥0}
    {stmtLens : OracleStatement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                                OuterOStmtIn OuterOStmtOut InnerOStmtIn InnerOStmtOut}
    {witLens : Witness.InvLens (OuterStmtIn × ∀ i, OuterOStmtIn i)
                            OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    (V : OracleVerifier oSpec InnerStmtIn InnerOStmtIn InnerStmtOut InnerOStmtOut pSpec)
    [lensKS : Extractor.Lens.IsKnowledgeSound
      outerRelIn innerRelIn outerRelOut innerRelOut
      (V.toVerifier.compatStatement stmtLens) (fun _ _ => True) ⟨stmtLens, witLens⟩]
    (h : V.rbrKnowledgeSoundness init impl innerRelIn innerRelOut rbrKnowledgeError) :
      (V.liftContext stmtLens).rbrKnowledgeSoundness init impl outerRelIn outerRelOut
        rbrKnowledgeError

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

theorem take_drop_eq_drop_take (m₁ m₂ : ℕ) (h₁ : m₁ ≤ m₂) (h₂ : m₂ ≤ n) (v : (i : Fin n) → α i) :
    take (m₂ - m₁) (by omega) (drop m₁ (by omega) v) =
      drop m₁ (by omega) (take m₂ h₂ v)

omit [Finite F] in
private lemma op_der_eq : Monoid.toMulAction Fˣ = Units.mulAction'

@[simp]
theorem init_update_castSucc : init (update s i.castSucc y) = update (init s) i y

theorem support_C_subset {r : R} : (@C R σ _ r).support ⊆ { 0 }

lemma degree_W (i : Fin r) : (W 𝔽q β i).degree = (Fintype.card 𝔽q)^i.val

lemma twoAdicity_maximal : ¬ (2 ^ (twoAdicity + 1)) ∣ (fieldSize - 1)

lemma getBit_eq_testBit (k n : Nat) : getBit k n = if n.testBit k then 1 else 0

@[simp]
lemma truncate_zero_eq_zero : (truncate p 0) = 0

lemma natDegree_definingPoly {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  (definingPoly s).natDegree = 2

theorem size_eq_degree (p : UniPoly R) : p.trim.size = p.degree

lemma eval_trim_eq_eval [LawfulBEq R] (x : R) (p : UniPoly R) : p.trim.eval x = p.eval x

theorem buildMerkleTree_neverFails (α : Type) [DecidableEq α] [SelectableType α] {n : ℕ}
    (leaves : List.Vector α (2 ^ n)) (preexisting_cache : (spec α).QueryCache) :
    ((simulateQ randomOracle (buildMerkleTree α n leaves)).run preexisting_cache).neverFails

theorem Fin.sum_univ_odd_even {n : ℕ} {M : Type*} [AddCommMonoid M] (f : ℕ → M) :
    (∑ i : Fin (2 ^ n), f (2 * i)) + (∑ i : Fin (2 ^ n), f (2 * i + 1))
    = ∑ i: Fin (2 ^ (n+1)), f i

theorem linear_map_of_comp_to_linear_map_of_eval (f : L[X])
  (h_f_linear : IsLinearMap (R := Fq) (M := L[X]) (M₂ := L[X])
    (f := fun inner_p ↦ f.comp inner_p)) :
    IsLinearMap (R := Fq) (M := L) (M₂ := L) (f := fun x ↦ f.eval x)

lemma sub_middle_of_pow2_with_one_canceled {k : ℕ} (h_k : 1 ≤ k) : 2 ^ k - 1 - 2 ^ (k - 1) + 1
  = 2 ^ (k - 1)

theorem append_perfectCompleteness (R₁ : Reduction oSpec Stmt₁ Wit₁ Stmt₂ Wit₂ pSpec₁)
    (R₂ : Reduction oSpec Stmt₂ Wit₂ Stmt₃ Wit₃ pSpec₂)
    (h₁ : R₁.perfectCompleteness init impl rel₁ rel₂)
    (h₂ : R₂.perfectCompleteness init impl rel₂ rel₃) :
      (R₁.append R₂).perfectCompleteness init impl rel₁ rel₃

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

@[simp]
theorem mul_accepts_iff : (mul a b c).accepts x ↔ x c = x a * x b

@[simp]
theorem divide_by_2_mem {s : Finset ℕ} {d : ℕ} :
  d ∈ divide_by_2 s ↔ 2 * d ∈ s

theorem mul_distrib_add {a b : CNat 1} : a * (b + 1) = a * b + a

@[simp]
protected lemma elocPoly_succ :
  ElocPoly (n + 1) ωs f p =
  ElocPoly n ωs f p *
    if f n = p.eval (ωs n)
    then 1
    else X - C (ωs n)

lemma distInterleavedCodeToCodeLB
  {IC : LawfulInterleavedCode κ ι F} {U : Matrix κ ι F} {e : ℕ}
  (hF : Fintype.card F ≥ e)
  (he : (e : ℚ) ≤ (minDist (IC.1.LC : Set (ι → F)) / 3)) (hU : e < Δ(U,IC.1.MF)) :
  ∃ v ∈ Matrix.rowSpan U , e < distFromCode v IC.1.LC

Fin.append_left in Mathlib.Data.Fin.Tuple.Basic

@[simp]
theorem LeafData.map_internal {α β} {s_left s_right : Skeleton}
    (f : α → β) (left : LeafData α s_left) (right : LeafData α s_right) :
    (LeafData.internal left right).map f =
      LeafData.internal (left.map f) (right.map f)

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

lemma zero_def [Zero R] : zero = Vector.replicate (2 ^ n) 0

lemma getLowBits_joinBits {n m : ℕ} (low : Fin (2 ^ n)) (high : Fin (2 ^ m)) :
  getLowBits n (joinBits low high).val = low.val

private lemma natDegree_Q
  (h : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e) :
  (Q ωs f p e).natDegree ≤ e + p.natDegree

@[simp]
theorem cast_id : ChallengeIdx.cast (Eq.refl n₁) rfl = (id : pSpec₁.ChallengeIdx → _)

theorem two_le_two_pow_n_plus_1 (n : ℕ) : 2 ≤ 2 ^ (n + 1)

lemma add_zero {k : ℕ} (a : ConcreteBTField k) : a + 0 = a

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)

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)

theorem is_unit_iff_deg_0 {R : Type*} [Field R] {p : R[X]} : p.degree = 0 ↔ IsUnit p

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⟩ ≠ []

@[simp]
theorem erase_odd_mem
  {s : Finset ℕ}
  {n : ℕ}
  : n ∈ (erase_odd s) ↔ Even n ∧ n ∈ s

lemma powContraction_is_right_inverse_to_linearMvExtension
  (p : Polynomial.degreeLT F (2^m)) :
    powContraction.comp linearMvExtension p = p

omit [Finite F] in
lemma dom_n_eq_triv : evalDomain D n = ⊥

theorem insertNth_support :
    (insertNth p y s).support ⊆ insert p (s.support.map (Fin.succAboveEmb p))

@[simp]
theorem oracleReduction_completeness (h : init.neverFails) :
    (oracleReduction oSpec Statement OStatement Witness).perfectCompleteness init impl oRelIn
    (toORelOut oRelIn)

lemma dist_UB [CommRing F] {LC : LinearCode ι F} :
    Code.minDist (LC : Set (ι → F)) ≤ length LC

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

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

theorem minDist [Field F] [DecidableEq F] (inj : Function.Injective α) [NeZero n] (h : n ≤ m) :
  minDist ((ReedSolomon.code ⟨α, inj⟩ n) : Set (Fin m → F)) = m - n + 1

theorem eq_zero_of_degreeOf_lt_card_of_eval_eq_zero {p : R[X σ]} (S : σ → Finset R)
    (hDegree : ∀ i, p.degreeOf i < #(S i))
    (hEval : ∀ x ∈ piFinset fun i ↦ S i, eval x p = 0) : p = 0

theorem zero_add {n : ℕ} (a : CNat (n + 1)) : 0 + a = a

@[simp]
lemma isRoot_polynomialsOfCoeffs {x : F} :
  IsRoot (polynomialOfCoeffs coeffs) x ↔ eval x (polynomialOfCoeffs coeffs) = 0

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

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

@[simp] theorem ofNat_toNat (t : AssocNat) : ofNat (toNat t) = t

theorem oracleReduction_perfectCompleteness (hInit : init.neverFails) :
    (oracleReduction R deg D oSpec).perfectCompleteness init impl
      (inputRelation R deg D) (outputRelation R deg)

private lemma solutionToE_from_E
  (h_p_deg : p.natDegree < k)
  (h_dist : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  : solutionToE e k (E_and_Q_to_a_solution e (E ωs f p e) (Q ωs f p e)) = E ωs f p e

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

@[simp]
protected lemma elocPolyF_leading_coeff_one {ωs f : Fin n → F}
  : (ElocPolyF ωs f p).leadingCoeff = 1

theorem self_sum_eq_zero
    {prevBTField : Type*} [CommRing prevBTField]
    (sumZeroIffEqPrev : ∀ (x y : prevBTField), x + y = 0 ↔ x = y)
    (prevPoly : Polynomial prevBTField)
    (hf_deg : prevPoly.natDegree = 2)
    (hf_monic : Monic prevPoly) :
    ∀ (x : AdjoinRoot prevPoly), x + x = 0

@[simp]
theorem cast_id : MessageIdx.cast (Eq.refl n₁) rfl = (id : pSpec₁.MessageIdx → _)

lemma add_eq_one_iff (a b : ConcreteBTField 0) :
  a + b = 1 ↔ (a = 0 ∧ b = 1) ∨ (a = 1 ∧ b = 0)

@[simp]
lemma aeval_X {A : Type y} [CommSemiring A] [Algebra R A] {F : Type z} [FunEquiv F σ A] (g : F)
    (s : σ) : aeval g (X s : P) = g s

@[simp]
lemma finite_relHammingDistRange [Nonempty ι] : (relHammingDistRange ι).Finite

Nat.succ_lt_succ_iff in Init.Data.Nat.Basic

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

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 seqCompose_two_eq_append {n : Fin 2 → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)} :
    seqCompose pSpec = append (pSpec 0) (pSpec 1)

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

@[simp]
theorem ConcreteBTField.RingHom_eq_of_source_eq (k n m : ℕ) (h_eq : k = n) :
    (ConcreteBTField k →+* ConcreteBTField m)
    = (ConcreteBTField n →+* ConcreteBTField m)

theorem happend_singleton {α : Fin m → Sort u} {β : Sort u} (u : (i : Fin m) → α i) (a : β) :
    True

omit [CharP L 2] [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 [NeZero ℓ] in
theorem card_qMap_total_fiber (i : Fin ℓ) (steps : ℕ) (h_i_add_steps : i.val + steps ≤ ℓ)
    (y : sDomain 𝔽q β h_ℓ_add_R_rate (i := ⟨i.val + steps, by omega⟩)) :
    Fintype.card (Set.image (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)) Set.univ) = 2 ^ steps

lemma fold_f_g
  {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) :
  let f_fun := (f : (indexPowT S φ 0) → F)
  let g := fold_k f_fun αs hk
  g ∈ smoothCode φ_k (m - k)

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

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

lemma add_two_pow_of_getBit_eq_zero_lt_two_pow {n m i : ℕ} (h_n: n < 2^m) (h_i: i < m)
  (h_getBit_at_i_eq_zero: getBit i n = 0) :
  n + 2^i < 2^m

@[simp]
lemma solutionToE_ne_zero : (solutionToE e k v) ≠ 0

private lemma sum_of_not_equals :
  ∑ x ∈ B ×ˢ B with x.1 ≠ x.2, (if x.1 i ≠ x.2 i then 1 else 0)
  =
  2 * choose_2 #B - 2 * ∑ α, choose_2 (K B i α)

theorem foldRelayOracleReduction_perfectCompleteness
    (hInit : init.neverFails) (i : Fin ℓ) (hNCR : ¬ isCommitmentRound ℓ ϑ i) :
  OracleReduction.perfectCompleteness
    (pSpec := pSpecFoldRelay (L:=L))
    (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)
    (oracleReduction := foldRelayOracleReduction 𝔽q β (ϑ:=ϑ) (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
      (𝓑:=𝓑) i hNCR) (init := init) (impl := impl)

lemma algebra_adjacent_tower_eq_AdjoinRoot_algebra (k : ℕ) :
  (algebra_adjacent_tower k) = (AdjoinRoot.instAlgebra (poly k))

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 PowerBasis.cast_basis_succ_of_eq_rec_apply
    (r1 r : ℕ) (h_r : r = r1 + 1)
    (k : Fin 2) :
    letI instAlgebra : Algebra (BTField r1) (BTField r) :=
      binaryAlgebraTower (l:=r1) (r:=r) (h_le:=by omega)
    letI instAlgebraSucc : Algebra (BTField (r1 + 1)) (BTField (r)) :=
      binaryAlgebraTower (l:=r1 + 1) (r:=r) (h_le:=by omega)
    let b : PowerBasis (BTField r1) (BTField (r1 + 1)) := powerBasisSucc (k:=r1)
    let bCast : PowerBasis (BTField r1) (BTField r) := Eq.rec (motive:=
      fun (x : ℕ) (_ : r1 + 1 = x) => by
        letI instAlgebraCur : Algebra (BTField r1) (BTField x) :=
          binaryAlgebraTower (l:=r1) (r:=x) (h_le:=by omega)
        exact PowerBasis (BTField r1) (BTField x)) (refl:=b) (t:=h_r.symm)
    have h_pb_dim : b.dim = 2 := by
      exact powerBasisSucc_dim r1

    have h_pb'_dim : bCast.dim = 2 := by
      dsimp [bCast]
      rw [BTField.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) (BTField r1) (BTField r) =
      Basis (Fin 2) (BTField r1) (BTField r) := by
      congr

   -- The `cast` needs a proof that `bCast.dim = 2`. We construct it here.
    let left : Basis (Fin 2) (BTField r1) (BTField r) := cast (by exact h_pb_type_eq) bCast.basis
    let right := (algebraMap (BTField (r1 + 1)) (BTField r))
      (b.basis (Fin.cast h_pb_dim.symm k))
    left k = right

theorem mul_two_add_bit_lt_two_pow (a b c : ℕ) (i : Fin 2)
    (h_a : a < 2 ^ b) (h_b : b < c) :
    a * 2 + i.val < 2^c

Polynomial.degree_sum_le in Mathlib.Algebra.Polynomial.Degree.Definitions

lemma eval_solutionToQ_cast {x : F} (h : e = 0) :
  eval x (solutionToQ e k v) = ∑ i ∈ Finset.range k, liftF v i * x ^ i

lemma getBit_of_shiftLeft {n p : ℕ}:
  ∀ k, getBit (k) (n <<< p) = if k < p then 0 else getBit (k - p) n

lemma Z_square_eq (k : ℕ) (prevBTFieldProps : ConcreteBTFieldProps (k := k))
    (curBTFieldProps : ConcreteBTFieldProps (k := (k + 1))) :
  letI : Field (ConcreteBTField (k + 1)) := mkFieldInstance curBTFieldProps
  (Z (k + 1)) ^ 2 = 《 Z (k), 1 》

@[simp]
lemma foldr'_zero {α : Type u} (f : (i : Fin 0) → α → α) (x : α) :
    foldr' 0 f x = x

@[simp]
lemma divide_by_2_empty :
    divide_by_2 ∅ = ∅

theorem BitVec.dcast_bitvec_eq {l r val : ℕ} (h_width_eq : l = r) :
    dcast h_width_eq (BitVec.ofNat l val) = BitVec.ofNat r val

@[simp]
theorem rightpad_apply_ge (n : ℕ) (a : α) (v : Fin m → α) (i : Fin n)
    (h : m ≤ i.val) : rightpad n a v i = a

@[simp]
theorem BTField.RingHom_comp_cast {α β γ δ : ℕ} (f : BTField α →+* BTField β)
  (g : BTField β →+* BTField γ) (h : γ = δ) :
    ((cast (BTField.RingHom_eq_of_dest_eq (k:=β) (m:=γ) (n:=δ) h) g).comp f)
    = cast (BTField.RingHom_eq_of_dest_eq (k:=α) (m:=γ) (n:=δ) h) (g.comp f)

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

theorem sum_Icc_split {α : Type*} [AddCommMonoid α] (f : ℕ → α) (a b c : ℕ)
    (h₁ : a ≤ b) (h₂ : b ≤ c):
    ∑ i ∈ Finset.Icc a c, f i = ∑ i ∈ Finset.Icc a b, f i + ∑ i ∈ Finset.Icc (b+1) c, f i

@[simp] lemma ofMvPolynomialAlgHom_X (s : σ) :
    ofMvPolynomialAlgHom (MvPolynomial.X s : MvPolynomial σ R) = (X s : P)

@[simp]
lemma support_polynomialOfCoeffs : (polynomialOfCoeffs coeffs).support =
  Finset.map ⟨Fin.val, Fin.val_injective⟩ {i | coeffs i ≠ 0}

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

@[simp]
theorem vappend_right (u : Fin m → α) (v : Fin n → α) (i : Fin n) :
    vappend u v (natAdd m i) = v i

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

theorem coeff_eq_getElem_of_lt [LawfulBEq R] {p : UniPoly R} {i} (hi : i < p.size) :
  p.trim.coeff i = p[i]

@[simp]
theorem Reduction.id_run (stmt : StmtIn) (wit : WitIn) :
    (Reduction.id : Reduction oSpec StmtIn WitIn _ _ _).run stmt wit =
      pure ⟨⟨default, stmt, wit⟩, stmt⟩

theorem reduction_rbr_knowledge_soundness : True

theorem funext₂_iff {α : Sort u} {β : α → Sort v} {γ : (a : α) → β a → Sort w}
    {f g : (a : α) → (b : β a) → γ a b} : f = g ↔ ∀ a b, f a b = g a b

@[simp]
lemma erase_odd_empty :
    erase_odd ∅ = ∅

Nat.add_zero in Init.Core

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 castSum_castAdd {n m : ℕ} (i : Fin n) : castSum [n, m] (by simp) i = castAdd m i

private lemma aux_sum [Zero F]
  (h_n : 0 < n)
  : n * choose_2 (aux_frac B (k B)) ≤ ∑ i, choose_2 (aux_frac B (K B i 0))

@[simp]
theorem LeafData.get_internal_ofRight {α} {s_left s_right : Skeleton}
    (left : LeafData α s_left) (right : LeafData α s_right)
    (idxRight : SkeletonLeafIndex s_right) :
    (LeafData.internal left right).get (SkeletonLeafIndex.ofRight idxRight) =
      right.get idxRight

@[simp]
theorem removeNth_apply : removeNth p s i = s (p.succAbove i)

theorem non_zero_divisors_iff (M₀ : Type*) [Mul M₀] [Zero M₀] :
    NoZeroDivisors M₀ ↔ ∀ {a b : M₀}, a * b = 0 → a = 0 ∨ b = 0

@[simp]
theorem init_apply : init s i = s i.castSucc

theorem liftContext_rbr_soundness [Inhabited InnerStmtOut]
    {outerLangIn : Set OuterStmtIn} {outerLangOut : Set OuterStmtOut}
    {innerLangIn : Set InnerStmtIn} {innerLangOut : Set InnerStmtOut}
    {rbrSoundnessError : pSpec.ChallengeIdx → ℝ≥0}
    {lens : Statement.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut}
    (V : Verifier oSpec InnerStmtIn InnerStmtOut pSpec)
    -- TODO: figure out the right compatibility relation for the IsSound condition
    [lensSound : lens.IsSound outerLangIn outerLangOut innerLangIn innerLangOut
      (V.compatStatement lens)]
    (h : V.rbrSoundness init impl innerLangIn innerLangOut rbrSoundnessError) :
      (V.liftContext lens).rbrSoundness init impl outerLangIn outerLangOut rbrSoundnessError

@[simp]
theorem hflatten_one {n : Fin 1 → ℕ} {α : (i : Fin 1) → (j : Fin (n i)) → Sort*}
    {v : (i : Fin 1) → (j : Fin (n i)) → α i j} : hflatten v = v 0

theorem 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 [CharP L 2] [DecidableEq 𝔽q] hF₂ h_β₀_eq_1 [NeZero 𝓡] in
lemma take_snoc_oracle_eq_oStmtIn (i : Fin ℓ)
    (oStmtIn : (j : Fin (toOutCodewordsCount ℓ ϑ i.castSucc)) →
      OracleStatement 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ϑ i.castSucc j)
    (newOracleFn : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) i.succ) :
    (take_snoc_oracle 𝔽q β i oStmtIn newOracleFn) = oStmtIn

theorem mul_one {a : CNat 50} : a * 1 = a

theorem dconcat_dcons_eq_dcons_dconcat {motive : Fin (n + 2) → Sort u} (a : motive 0)
    (v : (i : Fin n) → motive (succ (castSucc i))) (b : motive (last (n + 1))) :
    (a ::ᵈ v) :+ᵈ⟨motive⟩ b = a ::ᵈ⟨motive⟩ (v :+ᵈ b)

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)

@[simp]
theorem dflatten_succ {m : ℕ} {n : Fin (m + 1) → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    {v : (i : Fin (m + 1)) → (j : Fin (n i)) → motive (embedSum i j)} :
    dflatten (motive := motive) v = dappend (v 0) (dflatten (fun i => v i.succ))

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

@[simp]
theorem shift_left_mem {s : Finset ℕ} {d : ℕ} : d ∈ shift_left s ↔ (d + 1) ∈ s

@[to_additive vsum_castSucc]
lemma vprod_castSucc [CommMonoid α] {a : Fin (n + 1) → α} :
    vprod a = vprod (a ∘ Fin.castSucc) * a (last n)

Nat.lt_of_add_right_lt in Init.Data.Nat.Basic

theorem induction_init {n : ℕ} {motive : Fin (n + 2) → Sort*} {zero : motive 0}
    {succ : ∀ i : Fin (n + 1), motive i.castSucc → motive i.succ} {i : Fin (n + 1)} :
      induction (motive := motive) zero succ i.castSucc =
        induction (motive := Fin.init motive) zero (fun j x => succ j.castSucc x) i

lemma degree_normalizedW (i : Fin r) :
  (normalizedW 𝔽q β i).degree = (Fintype.card 𝔽q)^(i.val)

@[simp]
lemma invFun_toFun (f : F) : inst.equiv.invFun (inst.equiv.toFun f) = f

theorem hconcat_left_injective {α : Fin n → Sort u} {β : Sort u} (a : β) :
    Function.Injective (fun v : (i : Fin n) → α i => hconcat v a)

lemma not_inv_of_not_combined (h : ¬ E trace) : ¬ E_inv trace state

theorem fcons₂_injective2 {α₁ : A} {α₂ : B} {β₁ : Fin n → A} {β₂ : Fin n → B} :
    Function.Injective2 (@fcons₂ A B F₂ n α₁ β₁ α₂ β₂)

theorem srSoundness_implies_soundness
    (langIn : Set StmtIn) (langOut : Set StmtOut)
    (verifier : Verifier oSpec StmtIn StmtOut pSpec)
    (srInit : ProbComp (srChallengeOracle StmtIn pSpec).FunctionType)
    (srImpl : QueryImpl oSpec (StateT (srChallengeOracle StmtIn pSpec).FunctionType ProbComp))
    (srSoundnessError : ℝ≥0) :
      Verifier.StateRestoration.soundness srInit srImpl langIn langOut verifier srSoundnessError →
        soundness init impl langIn langOut verifier srSoundnessError

@[grind _=_]
lemma degreeY_as_weighted_deg (hf : f ≠ 0) :
  natDegreeY f = natWeightedDegree f 0 1

@[simp]
theorem oracleReduction_perfectCompleteness (hInit : init.neverFails) :
    (oracleReduction oSpec Statement OStatement Witness).perfectCompleteness init impl rel rel

theorem FullData.toLeafData_rightSubtree {α} {s_left s_right : Skeleton}
    (tree : FullData α (Skeleton.internal s_left s_right)) :
    tree.toLeafData.rightSubtree =
      tree.rightSubtree.toLeafData

lemma definingPoly_is_not_unit {F : Type*} [Field F] [Fintype F] (s : F) [NeZero s] :
  ¬IsUnit (definingPoly s)

theorem vconcat_right_injective (v : Fin n → α) : Function.Injective (vconcat v)

lemma sum_insertNth' [AddCommMonoid M] [AddCommMonoid N] {n : ℕ} (σ : Fin n →₀ M) (i : M)
    (p : Fin (n + 1)) (f : Fin (n+1) → M → N) (h : ∀ x, f x 0 = 0) :
    sum (insertNth p i σ) f = f p i + sum σ (Fin.removeNth p f)

theorem singleEqPolynomial_zeroOne_C (r : Fin 2) (x : Fin 2) :
    (singleEqPolynomial (r : R) (C x) : MvPolynomial σ R) = if x = r then 1 else 0

theorem split_of_join {k : ℕ} (h_pos : k > 0) (x : ConcreteBTField k)
    (hi_btf lo_btf : ConcreteBTField (k - 1))
    (h_join : x = 《hi_btf, lo_btf》) :
    (hi_btf, lo_btf) = split h_pos x

lemma split_join_via_add_smul_eq_iff_split (k : ℕ) (h_pos : k > 0)
    (hi_btf lo_btf : BTField (k - 1)) :
    split (k:=k) (h_k:=h_pos) (⋘ hi_btf, lo_btf ⋙) = (hi_btf, lo_btf)

theorem dinit_hconcat {α : Fin n → Sort u} {β : Sort u} (v : (i : Fin n) → α i) (b : β) :
    True

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

lemma getBit_of_highBits_no_shl {n: ℕ} (numLowBits : ℕ) :
    ∀ k, getBit k (getHighBits_no_shl numLowBits n)
  = getBit (k + numLowBits) (n)

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

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

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

lemma vappend_right_of_not_lt {m n : ℕ} {α : Sort u}
    (u : Fin m → α) (v : Fin n → α) (i : Fin (m + n)) (h : ¬ i.val < m) :
      vappend u v i = v ⟨i - m, by omega⟩

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

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

theorem eqPolynomial_degreeOf (r : σ → R) (i : σ) : degreeOf i (eqPolynomial r) ≤ 1

@[simp]
theorem dflatten_zero {n : Fin 0 → ℕ} {motive : (k : Fin (vsum n)) → Sort*}
    {v : (i : Fin 0) → (j : Fin (n i)) → motive (embedSum i j)} :
    dflatten (motive := motive) v = fun k => Fin.elim0 k

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

theorem mulVecLin_coeff_vandermondens_eq_eval_matrixOfPolynomials
  {n : ℕ} [NeZero n] {v : ι ↪ F} {p : F[X]} (h_deg : p.natDegree < n) :
  (Vandermonde.nonsquare (ι' := n) v).mulVecLin (Fin.liftF' p.coeff) =
  fun i => p.eval (v i)

theorem liftContext_runWithLog
    {lens : Context.Lens OuterStmtIn OuterStmtOut InnerStmtIn InnerStmtOut
                        OuterWitIn OuterWitOut InnerWitIn InnerWitOut}
    {outerStmtIn : OuterStmtIn} {outerWitIn : OuterWitIn}
    {P : Prover oSpec InnerStmtIn InnerWitIn InnerStmtOut InnerWitOut pSpec} :
      (P.liftContext lens).runWithLog outerStmtIn outerWitIn
      = do
        let ⟨⟨fullTranscript, innerCtxOut⟩, queryLog⟩ ←
          P.runWithLog.uncurry (lens.proj (outerStmtIn, outerWitIn))
        return ⟨⟨fullTranscript, lens.lift (outerStmtIn, outerWitIn) innerCtxOut⟩, queryLog⟩

lemma concrete_mul_one0 (a : ConcreteBTField 0) :
  concrete_mul a (one (k:=0)) = a

Nat.pow_lt_pow_right in Init.Data.Nat.Lemmas

lemma Q'_div_E'_eq_p
  [NeZero n]
  {E' Q' : Polynomial F}
  {ωs f : Fin n → F}
  (hp_deg : p.natDegree < k)
  (he : 2 * e < n - k + 1)
  (hk_n : k ≤ n)
  (h_ham : (Δ₀(f, p.eval ∘ ωs) : ℕ) ≤ e)
  (h_diff : Function.Injective ωs)
  (h_Q' : Q' ≠ 0)
  (hp : p ≠ 0)
  (h_cond : BerlekampWelchCondition e k ωs f E' Q')
  : E' ∣ Q' ∧ Q' / E' = p

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

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 novelToMonomial_monomialToNovel_inverse
  (ℓ : ℕ) (h_ℓ : ℓ ≤ r) :
  ∀ coeffs : Fin (2^ℓ) → L,
    monomialToNovelCoeffs 𝔽q β ℓ h_ℓ
      (novelToMonomialCoeffs 𝔽q β ℓ h_ℓ coeffs) = coeffs

theorem mul_zero (n : ChurchNat α) : mul n zero = zero

@[simp]
theorem vcons_one (a : α) (v : Fin (n + 1) → α) : (a ::ᵛ v) 1 = v 0

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 》

lemma neverFails_map_iff' (oa : OracleComp spec α) (f : α → β) :
    neverFails (f <$> oa) ↔ neverFails oa

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)

@[simp]
lemma aeval_X {A : Type w} [CommSemiring A] [Algebra R A] (s : A) : aeval s X (P := P) = s

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

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)

@[csimp]
theorem dconcat_eq_snoc : @dconcat = @snoc

@[grind =]
theorem monomialXY_eq_monomialXY_iff {n m p q : ℕ} {a b : F} :
  monomialXY n m a = monomialXY p q b ↔ n = p ∧ m = q ∧ a = b ∨ a = 0 ∧ b = 0

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 dcast₃_dcast₂ : dcast₃ rfl rfl rfl d = dcast₂ dcast_eq.symm dcast₂_dcast.symm d

lemma getBit_of_or {n m k: ℕ} : getBit k (n ||| m) = getBit k n ||

theorem succ_mul {a b : AssocNat} : (succ a) * b = a * b + b

@[simp]
lemma seqCompose_succ {m : ℕ}
    (Stmt : Fin (m + 2) → Type)
    {ιₛ : Fin (m + 2) → Type} (OStmt : (i : Fin (m + 2)) → ιₛ i → Type)
    [Oₛ : ∀ i, ∀ j, OracleInterface (OStmt i j)]
    (Wit : Fin (m + 2) → Type)
    {n : Fin (m + 1) → ℕ} {pSpec : ∀ i, ProtocolSpec (n i)}
    [Oₘ : ∀ i, ∀ j, OracleInterface ((pSpec i).Message j)]
    (R : (i : Fin (m + 1)) →
      OracleReduction oSpec (Stmt i.castSucc) (OStmt i.castSucc) (Wit i.castSucc)
        (Stmt i.succ) (OStmt i.succ) (Wit i.succ) (pSpec i)) :
    seqCompose Stmt OStmt Wit R =
      append (R 0) (seqCompose (Stmt ∘ Fin.succ) (fun i => OStmt (Fin.succ i)) (Wit ∘ Fin.succ)
        (Oₛ := fun i => Oₛ (Fin.succ i)) (Oₘ := fun i => Oₘ (Fin.succ i))
          (fun i => R (Fin.succ i)))

@[simp]
lemma oddPart_coeff {f : Polynomial F} {n : ℕ} :
    (oddPart f).coeff n = if Even n then f.coeff (n + 1) else 0

lemma getBit_of_two_pow_sub_one {i k: ℕ} : getBit k (2^i - 1) =
    if k < i then 1 else 0

theorem FullData.toLeafData_eq_leaf {α} (a : α) (tree)
    (h : LeafData.leaf a = tree.toLeafData) :
    tree = FullData.leaf a

@[simp]
theorem oracleVerifier_rbrKnowledgeSoundness [Nonempty (Query OStatement)]
    {d : ℕ} (hDist : distanceLE OStatement d) :
    (oracleVerifier oSpec OStatement).rbrKnowledgeSoundness init impl
      (relIn OStatement)
      (relOut OStatement)
      (fun _ => (d : ℝ≥0) / (Fintype.card (Query OStatement) : ℝ≥0))

private lemma oddPart_eq_oddPart' {f : Polynomial F} : oddPart f = oddPart' f

@[simp]
theorem vcons_fin_zero (a : α) (v : Fin 0 → α) : a ::ᵛ v = fun i => match i with

theorem cast_runToRound (j : Fin (n₁ + 1)) (stmt : StmtIn) (wit : WitIn)
    (P : Prover oSpec StmtIn WitIn StmtOut WitOut pSpec₁) :
    P.runToRound j stmt wit =
      cast (sorry) ((P.cast hn hSpec).runToRound (Fin.cast (congrArg (· + 1) hn) j) stmt wit)

omit [Finite F] in
lemma domain_surjective (i : ℕ) : i ≤ n → Function.Surjective (domain D n i)

lemma even_index_intermediate_novel_basis_decomposition (i : Fin ℓ) (j : Fin (2 ^ (ℓ - i - 1))) :
  intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i, by omega⟩ ⟨j * 2, by
    apply mul_two_add_bit_lt_two_pow j (ℓ-i-1) (ℓ-i) ⟨0, by omega⟩ (by omega) (by omega)
  ⟩  = (intermediateNovelBasisX 𝔽q β h_ℓ_add_R_rate ⟨i+1, by omega⟩ ⟨j, by
    apply lt_two_pow_of_lt_two_pow_exp_le j (ℓ-i-1) (ℓ-(i+1)) (by omega) (by omega)
  ⟩).comp (qMap 𝔽q β ⟨i, by omega⟩)

lemma mca_list_decoding
  [Fintype ι] [Nonempty ι]
  (Gen : ProximityGenerator ι F) [Fintype Gen.parℓ]
  (δ BStar : ℝ) (errStar : ℝ → ENNReal)
  (fs us : Matrix Gen.parℓ ι F)
  (IC : InterleavedCode Gen.parℓ ι F)
  (haveIC : IC = codeOfLinearCode Gen.parℓ Gen.C)
      (hGen : hasMutualCorrAgreement Gen BStar errStar)
  (C : Set (ι → F)) (hC : C = Gen.C) :
    haveI := Gen.Gen_nonempty
    ∀ {fs : Matrix Gen.parℓ ι F}
    (hδPos : δ > 0) (hδLt : δ < min (δᵣ C : ℝ) (1 - BStar)),
      Pr_{let r ←$ᵖ Gen.Gen}[ proximityListDecodingCondition Gen.C r δ fs IC ]
        ≤ errStar δ

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

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

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

theorem 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

lemma exists_points_with_large_matching_subset
  {ω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))
  :
  ∃ Dtop : Finset (Fin n),
    Dtop.card = k + 1 ∧
    ∀ x ∈ Dtop,
      (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

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

@[simp]
theorem getLastI_append_single [Inhabited α] (x : α) : (l ++ [x]).getLastI = x

lemma farness_implies_non_compliance (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 omega⟩)
  (f_i_plus_steps : OracleFunction 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate)
    ⟨i + steps, by omega⟩)
  (challenges : Fin steps → L)
  (h_far : 2 * Code.distFromCode f_i
      (BBF_Code 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) ⟨i, by omega⟩)
    ≥ (BBF_CodeDistance ℓ 𝓡 ⟨i, by omega⟩ : ℕ∞)) :
  ¬ isCompliant 𝔽q β (h_ℓ_add_R_rate := h_ℓ_add_R_rate) (i := i) (steps := steps)
    h_i_add_steps f_i f_i_plus_steps challenges

theorem foldl_eq_toList_foldl {α β} {n : ℕ} (f : β → α → β) (init : β) (v : Vector α n) :
  v.foldl (f:=f) (b:=init) = v.toList.foldl (f:=f) (init:=init)

theorem last_nonzero_none [LawfulBEq R] {p : UniPoly R} :
  (∀ i, (hi : i < p.size) → p[i] = 0) → p.last_nonzero = none

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

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

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 pred_succ {T : Type u} [HasSucc T] [Zero T] [ToNat T] (x : Cayley T) :
    pred (succ x) = x

lemma genMatIsVandermonde [Fintype ι] [Field F] [DecidableEq F] [inst : NeZero m] {α : ι ↪ F} :
  fromColGenMat (Vandermonde.nonsquare (ι' := m) α) = ReedSolomon.code α m

@[simp]
lemma challengeOracleInterface_append_range_inr (j : pSpec₂.ChallengeIdx) :
    [(pSpec₁ ++ₚ pSpec₂).Challenge]ₒ.range (.inr j) = pSpec₂.Challenge j

theorem canonical_of_size_zero {p : UniPoly R} : p.size = 0 → p.trim = p

lemma mul_trans_inequality {k : ℕ} (x : ℕ) (h_k : k ≤ 2) (h_x : x ≤ 2 ^ (2 ^ k) - 1) : x < 16
</all_available_lemmas>

<local_ctx>
import ArkLib.Data.Classes.DCast

import ArkLib.Data.FieldTheory.BinaryField.Tower.Basic

namespace ConcreteBinaryTower

open Polynomial

def ConcreteBTField : ℕ → Type := fun k => BitVec (2 ^ k)

section BitVecDCast

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

end BitVecDCast

section ConversionUtils

instance ConcreteBTField.instDCast_local : DCast ℕ ConcreteBTField where
  dcast h_k_eq term_k1 := BitVec.cast (congrArg (fun n => 2 ^ n) h_k_eq) term_k1
  dcast_id := by admit /- proof elided -/

end ConversionUtils

section NumericLemmas

end NumericLemmas

section FieldOperationsAndInstances

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

def one {k : ℕ} : ConcreteBTField k := 1#(2 ^ k)

def split {k : ℕ} (h : k > 0) (x : ConcreteBTField k) :
    ConcreteBTField (k - 1) × ConcreteBTField (k - 1) :=
  let lo_bits : BitVec (2 ^ (k - 1) - 1 - 0 + 1) :=
    BitVec.extractLsb (hi := 2 ^ (k - 1) - 1) (lo := 0) x
  let hi_bits : BitVec (2 ^ k - 1 - 2 ^ (k - 1) + 1) :=
    BitVec.extractLsb (hi := 2 ^ k - 1) (lo := 2 ^ (k - 1)) x
  have h_lo : 2 ^ (k - 1) - 1 - 0 + 1 = 2 ^ (k - 1) := by admit /- proof elided -/
</local_ctx>

<target_theorem>
lemma split_one {k : ℕ} (h_k : k > 0) :
    split h_k (one (k:=k)) = (zero (k:=k - 1), one (k:=k - 1)) :=
</target_theorem>

