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:
* <used_lib_defs>...</used_lib_defs>: Imported library definitions directly used by the theorem.
* <used_repo_defs>...</used_repo_defs>: Definitions from the local project (but outside the current file), directly or transitively used by the theorem.
* <lib_lemmas>...</lib_lemmas>: Imported library lemmas/theorems that may assist the proof.
* <repo_lemmas>...</repo_lemmas>: Lemmas/theorems defined in the local project outside this file.
* <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 used definitions and helpful lemmas (used_lib_defs, used_repo_defs, lib_lemmas, repo_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:
<used_lib_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)
</used_lib_defs>

<repo_lemmas>
theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]
</repo_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:
<used_lib_defs>
Nat in Init.Prelude
BEq in Init.Prelude
Nat.testBit in Init.Data.Nat.Bitwise.Basic
Nat.and_distrib_right in Init.Data.Nat.Bitwise.Lemmas
Bool in Init.Prelude
Nat.binaryRec in Mathlib.Data.Nat.BinaryRec
Nat.bit in Mathlib.Data.Nat.BinaryRec
Nat.bodd in Mathlib.Data.Nat.Bits
Nat.boddDiv2 in Mathlib.Data.Nat.Bits
Nat.div2 in Mathlib.Data.Nat.Bits
</used_lib_defs>

<lib_lemmas>
Nat.and_one_is_mod in Init.Data.Nat.Bitwise.Lemmas
Nat.eq_of_testBit_eq in Init.Data.Nat.Bitwise.Lemmas
Nat.mod_two_bne_zero in Init.Data.Nat.Lemmas
Nat.one_and_eq_mod_two in Init.Data.Nat.Bitwise.Lemmas
beq_eq_beq in Mathlib.Logic.Basic
Nat.and_assoc in Init.Data.Nat.Bitwise.Lemmas
Nat.and_comm in Init.Data.Nat.Bitwise.Lemmas
Nat.and_self in Init.Data.Nat.Bitwise.Lemmas
Nat.shiftRight_and_distrib in Init.Data.Nat.Bitwise.Lemmas
Nat.zero_and in Init.Data.Nat.Bitwise.Lemmas
Nat.zero_shiftRight in Init.Data.Nat.Lemmas
Nat.div_eq_zero_iff_lt in Init.Data.Nat.Div.Lemmas
Nat.pow_lt_pow_right in Init.Data.Nat.Lemmas
Nat.shiftLeft_add in Init.Data.Nat.Lemmas
Nat.shiftLeft_eq in Init.Data.Nat.Bitwise.Basic
Nat.shiftLeft_shiftRight in Init.Data.Nat.Lemmas
Nat.shiftRight_add in Init.Data.Nat.Bitwise.Basic
Nat.shiftRight_eq_div_pow in Init.Data.Nat.Bitwise.Basic
Nat.sub_add_cancel in Init.Data.Nat.Basic
Nat.two_pow_mod_two_eq_zero in Init.Data.Nat.Mod
Nat.two_pow_pos in Init.Data.Nat.Basic
beq_iff_eq in Init.Core
gt_iff_lt in Init.Core
one_mul in Mathlib.Algebra.Group.Defs
Nat.and_zero in Init.Data.Nat.Bitwise.Lemmas
Nat.and_xor_distrib_right in Init.Data.Nat.Bitwise.Lemmas
Nat.mod_lt in Init.Prelude
Nat.ofNat_pos in Mathlib.Data.Nat.Cast.Order.Ring
Nat.shiftRight_or_distrib in Init.Data.Nat.Bitwise.Lemmas
Nat.shiftRight_xor_distrib in Init.Data.Nat.Bitwise.Lemmas
Nat.mod_two_not_eq_one in Init.Data.Nat.Lemmas
Nat.testBit_two_pow_sub_one in Init.Data.Nat.Bitwise.Lemmas
beq_eq_false_iff_ne in Init.SimpLemmas
decide_false in Init.Core
decide_true in Init.Core
ne_eq in Init.SimpLemmas
imp_false in Init.Core
ite_eq_left_iff in Init.PropLemmas
ite_eq_right_iff in Init.PropLemmas
not_le in Mathlib.Order.Defs.LinearOrder
not_lt in Mathlib.Order.Defs.LinearOrder
one_ne_zero in Mathlib.Algebra.NeZero
right_eq_ite_iff in Init.PropLemmas
zero_ne_one in Mathlib.Algebra.NeZero
Nat.add_mul_div_left in Init.Data.Nat.Div.Basic
add_comm in Mathlib.Algebra.Group.Defs
mul_comm in Mathlib.Algebra.Group.Defs
Nat.and_div_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.and_mod_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.div_add_mod in Init.Data.Nat.Div.Basic
Nat.mul_add_mod_self_right in Init.Data.Nat.Div.Basic
pow_one in Mathlib.Algebra.Group.Defs
zero_add in Mathlib.Algebra.Group.Defs
Nat.or_div_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.or_mod_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.or_self in Init.Data.Nat.Bitwise.Lemmas
Nat.or_zero in Init.Data.Nat.Bitwise.Lemmas
Nat.zero_or in Init.Data.Nat.Bitwise.Lemmas
Nat.xor_div_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.xor_mod_two_pow in Init.Data.Nat.Bitwise.Lemmas
Nat.xor_self in Init.Data.Nat.Bitwise.Lemmas
Nat.xor_zero in Init.Data.Nat.Bitwise.Lemmas
Nat.zero_xor in Init.Data.Nat.Bitwise.Lemmas
Bool.toNat_lt in Init.Data.Bool
Nat.bit_decomp in Mathlib.Data.Nat.Bits
Nat.bit_val in Mathlib.Data.Nat.BinaryRec
Nat.mul_zero in Init.Data.Nat.Basic
Nat.right_distrib in Init.Data.Nat.Basic
add_assoc in Mathlib.Algebra.Group.Defs
add_zero in Mathlib.Algebra.Group.Defs
Nat.zero_shiftLeft in Init.Data.Nat.Lemmas
lt_add_iff_pos_right in Mathlib.Algebra.Order.Monoid.Unbundled.Basic
lt_self_iff_false in Mathlib.Order.Basic
zero_lt_one in Mathlib.Algebra.Order.ZeroLEOne
</lib_lemmas>

<local_ctx>
import ArkLib.Data.Fin.BigOperators

import Mathlib.Algebra.BigOperators.Ring.Finset

import Mathlib.Algebra.Order.Ring.Star

import Mathlib.Data.Nat.Bitwise

import Mathlib.Data.Nat.Digits.Defs

import Mathlib.Data.Finsupp.Basic

import Mathlib.Algebra.Order.BigOperators.Group.Finset

import Mathlib.Algebra.BigOperators.Fin

namespace Nat

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

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

<target_theorem>
lemma getLowBits_succ {n: ℕ} (numLowBits: ℕ) :
    getLowBits (numLowBits + 1) n = getLowBits numLowBits n
    + (getBit numLowBits n) <<< numLowBits :=
</target_theorem>

