l3lab/ntp-mathlib huggingface dataset:
/-- The order of `ω` in the unit group is exactly `2^p`. -/
theorem order_ω (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    orderOf (ωUnit (p' + 2)) = 2 ^ (p' + 2) := by
  apply Nat.eq_prime_pow_of_dvd_least_prime_pow
  -- the order of ω divides 2^p
  · exact Nat.prime_two
  · intro o
    have ω_pow := orderOf_dvd_iff_pow_eq_one.1 o
    replace ω_pow :=
      congr_arg (Units.coeHom (X (q (p' + 2))) : Units (X (q (p' + 2))) → X (q (p' + 2))) ω_pow
    simp? at ω_pow says simp only [map_pow, Units.coeHom_apply, ωUnit_coe, map_one] at ω_pow
    have h : (1 : ZMod (q (p' + 2))) = -1 :=
      congr_arg Prod.fst (ω_pow.symm.trans (ω_pow_eq_neg_one p' h))
    haveI : Fact (2 < (q (p' + 2) : ℕ)) := ⟨two_lt_q _⟩
    apply ZMod.neg_one_ne_one h.symm
  · apply orderOf_dvd_iff_pow_eq_one.2
    apply Units.ext
    

Proof state:
case h₂.a
p' : ℕ
h : lucasLehmerResidue (p' + 2) = 0
⊢ ↑(ωUnit (p' + 2) ^ 2 ^ (p' + 1 + 1)) = ↑1

Next tactic:
push_cast
/-- The order of `ω` in the unit group is exactly `2^p`. -/
theorem order_ω (p' : ℕ) (h : lucasLehmerResidue (p' + 2) = 0) :
    orderOf (ωUnit (p' + 2)) = 2 ^ (p' + 2) := by
  apply Nat.eq_prime_pow_of_dvd_least_prime_pow
  -- the order of ω divides 2^p
  · exact Nat.prime_two
  · intro o
    have ω_pow := orderOf_dvd_iff_pow_eq_one.1 o
    replace ω_pow :=
      congr_arg (Units.coeHom (X (q (p' + 2))) : Units (X (q (p' + 2))) → X (q (p' + 2))) ω_pow
    simp? at ω_pow says simp only [map_pow, Units.coeHom_apply, ωUnit_coe, map_one] at ω_pow
    have h : (1 : ZMod (q (p' + 2))) = -1 :=
      congr_arg Prod.fst (ω_pow.symm.trans (ω_pow_eq_neg_one p' h))
    haveI : Fact (2 < (q (p' + 2) : ℕ)) := ⟨two_lt_q _⟩
    apply ZMod.neg_one_ne_one h.symm
  · apply orderOf_dvd_iff_pow_eq_one.2
    apply Units.ext
    push_cast
    

Proof state:
case h₂.a
p' : ℕ
h : lucasLehmerResidue (p' + 2) = 0
⊢ ↑(ωUnit (p' + 2)) ^ 2 ^ (p' + 1 + 1) = 1

Next tactic:
exact ω_pow_eq_one p' h
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  

Proof state:
p : ℕ
w : 1 < p
⊢ LucasLehmerTest p → Nat.Prime (mersenne p)

Next tactic:
let p' := p - 2
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  

Proof state:
p : ℕ
w : 1 < p
p' : ℕ := p - 2
⊢ LucasLehmerTest p → Nat.Prime (mersenne p)

Next tactic:
have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  

Proof state:
p : ℕ
w : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
⊢ LucasLehmerTest p → Nat.Prime (mersenne p)

Next tactic:
have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
⊢ LucasLehmerTest p → Nat.Prime (mersenne p)

Next tactic:
contrapose
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
⊢ ¬Nat.Prime (mersenne p) → ¬LucasLehmerTest p

Next tactic:
intro a t
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne p)
t : LucasLehmerTest p
⊢ False

Next tactic:
rw [z] at a
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  rw [z] at a
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne (p' + 2))
t : LucasLehmerTest p
⊢ False

Next tactic:
rw [z] at t
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  rw [z] at a
  rw [z] at t
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne (p' + 2))
t : LucasLehmerTest (p' + 2)
⊢ False

Next tactic:
have h₁ := order_ineq p' t
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  rw [z] at a
  rw [z] at t
  have h₁ := order_ineq p' t
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne (p' + 2))
t : LucasLehmerTest (p' + 2)
h₁ : 2 ^ (p' + 2) < ↑(q (p' + 2)) ^ 2
⊢ False

Next tactic:
have h₂ := Nat.minFac_sq_le_self (mersenne_pos (Nat.lt_of_succ_lt w)) a
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  rw [z] at a
  rw [z] at t
  have h₁ := order_ineq p' t
  have h₂ := Nat.minFac_sq_le_self (mersenne_pos (Nat.lt_of_succ_lt w)) a
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne (p' + 2))
t : LucasLehmerTest (p' + 2)
h₁ : 2 ^ (p' + 2) < ↑(q (p' + 2)) ^ 2
h₂ : Nat.minFac (mersenne (p' + 2)) ^ 2 ≤ mersenne (p' + 2)
⊢ False

Next tactic:
have h := lt_of_lt_of_le h₁ h₂
theorem lucas_lehmer_sufficiency (p : ℕ) (w : 1 < p) : LucasLehmerTest p → (mersenne p).Prime := by
  let p' := p - 2
  have z : p = p' + 2 := (tsub_eq_iff_eq_add_of_le w.nat_succ_le).mp rfl
  have w : 1 < p' + 2 := Nat.lt_of_sub_eq_succ rfl
  contrapose
  intro a t
  rw [z] at a
  rw [z] at t
  have h₁ := order_ineq p' t
  have h₂ := Nat.minFac_sq_le_self (mersenne_pos (Nat.lt_of_succ_lt w)) a
  have h := lt_of_lt_of_le h₁ h₂
  

Proof state:
p : ℕ
w✝ : 1 < p
p' : ℕ := p - 2
z : p = p' + 2
w : 1 < p' + 2
a : ¬Nat.Prime (mersenne (p' + 2))
t : LucasLehmerTest (p' + 2)
h₁ : 2 ^ (p' + 2) < ↑(q (p' + 2)) ^ 2
h₂ : Nat.minFac (mersenne (p' + 2)) ^ 2 ≤ mersenne (p' + 2)
h : 2 ^ (p' + 2) < mersenne (p' + 2)
⊢ False

Next tactic:
exact not_lt_of_ge (Nat.sub_le _ _) h
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  

Proof state:
p k : ℕ
hp : 2 ≤ p
⊢ ↑(sMod' (2 ^ p - 1) k) = sMod p k

Next tactic:
have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by 

Proof state:
p k : ℕ
hp : 2 ≤ p
⊢ 4 = 2 ^ 2

Next tactic:
norm_num
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by 

Proof state:
p k : ℕ
hp : 2 ≤ p
⊢ 2 > 0

Next tactic:
norm_num
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  

Proof state:
p k : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
⊢ ↑(sMod' (2 ^ p - 1) k) = sMod p k

Next tactic:
have h2 : 1 ≤ 2 ^ p := by linarith
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by 

Proof state:
p k : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
⊢ 1 ≤ 2 ^ p

Next tactic:
linarith
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  

Proof state:
p k : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
⊢ ↑(sMod' (2 ^ p - 1) k) = sMod p k

Next tactic:
induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
    zify [h2, h3]
    rw [← add_sub_assoc, sub_eq_add_neg, add_assoc, add_comm _ (-2), ← add_assoc,
      Int.add_emod_self, ← sub_eq_add_neg]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  

Proof state:
case zero
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
⊢ ↑(sMod' (2 ^ p - 1) Nat.zero) = sMod p Nat.zero

Next tactic:
| zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    

Proof state:
case zero
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
⊢ ↑(sMod' (2 ^ p - 1) Nat.zero) = sMod p Nat.zero

Next tactic:
rw [sMod', sMod, Int.ofNat_emod]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    

Proof state:
case zero
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
⊢ ↑4 % ↑(2 ^ p - 1) = 4 % (2 ^ p - 1)

Next tactic:
simp [h2]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  

Proof state:
case succ
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ ↑(sMod' (2 ^ p - 1) (Nat.succ k)) = sMod p (Nat.succ k)

Next tactic:
| succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
    zify [h2, h3]
    rw [← add_sub_assoc, sub_eq_add_neg, add_assoc, add_comm _ (-2), ← add_assoc,
      Int.add_emod_self, ← sub_eq_add_neg]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    

Proof state:
case succ
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ ↑(sMod' (2 ^ p - 1) (Nat.succ k)) = sMod p (Nat.succ k)

Next tactic:
rw [sMod', sMod, ← ih]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    

Proof state:
case succ
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ ↑((sMod' (2 ^ p - 1) k ^ 2 + (2 ^ p - 1 - 2)) % (2 ^ p - 1)) = (↑(sMod' (2 ^ p - 1) k) ^ 2 - 2) % (2 ^ p - 1)

Next tactic:
have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      

Proof state:
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ 2 ≤ 2 ^ p - 1

Next tactic:
zify [h2]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      

Proof state:
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ 2 ≤ 2 ^ p - 1

Next tactic:
calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by 

Proof state:
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ 2 ≤ 4 - 1

Next tactic:
norm_num
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by 

Proof state:
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
⊢ 4 - 1 ≤ 2 ^ p - 1

Next tactic:
zify at h1
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; 

Proof state:
p : ℕ
hp : 2 ≤ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
h1 : 4 ≤ 2 ^ p
⊢ 4 - 1 ≤ 2 ^ p - 1

Next tactic:
exact Int.sub_le_sub_right h1 _
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
    

Proof state:
case succ
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
h3 : 2 ≤ 2 ^ p - 1
⊢ ↑((sMod' (2 ^ p - 1) k ^ 2 + (2 ^ p - 1 - 2)) % (2 ^ p - 1)) = (↑(sMod' (2 ^ p - 1) k) ^ 2 - 2) % (2 ^ p - 1)

Next tactic:
zify [h2, h3]
theorem sMod'_eq_sMod (p k : ℕ) (hp : 2 ≤ p) : (sMod' (2 ^ p - 1) k : ℤ) = sMod p k := by
  have h1 := calc
    4 = 2 ^ 2 := by norm_num
    _ ≤ 2 ^ p := Nat.pow_le_pow_of_le_right (by norm_num) hp
  have h2 : 1 ≤ 2 ^ p := by linarith
  induction k with
  | zero =>
    rw [sMod', sMod, Int.ofNat_emod]
    simp [h2]
  | succ k ih =>
    rw [sMod', sMod, ← ih]
    have h3 : 2 ≤ 2 ^ p - 1 := by
      zify [h2]
      calc
        (2 : Int) ≤ 4 - 1 := by norm_num
        _         ≤ 2 ^ p - 1 := by zify at h1; exact Int.sub_le_sub_right h1 _
    zify [h2, h3]
    

Proof state:
case succ
p : ℕ
hp : 2 ≤ p
h1 : 4 ≤ 2 ^ p
h2 : 1 ≤ 2 ^ p
k : ℕ
ih : ↑(sMod' (2 ^ p - 1) k) = sMod p k
h3 : 2 ≤ 2 ^ p - 1
⊢ (↑(sMod' (2 ^ p - 1) k) ^ 2 + (2 ^ p - 1 - 2)) % (2 ^ p - 1) = (↑(sMod' (2 ^ p - 1) k) ^ 2 - 2) % (2 ^ p - 1)

Next tactic:
rw [← add_sub_assoc, sub_eq_add_neg, add_assoc, add_comm _ (-2), ← add_assoc,
      Int.add_emod_self, ← sub_eq_add_neg]
lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sMod' (2 ^ p - 1) (p - 2) = 0) :
    LucasLehmerTest p := by
  

Proof state:
p : ℕ
hp : Nat.blt 1 p = true
h : sMod' (2 ^ p - 1) (p - 2) = 0
⊢ LucasLehmerTest p

Next tactic:
rw [Nat.blt_eq] at hp
lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sMod' (2 ^ p - 1) (p - 2) = 0) :
    LucasLehmerTest p := by
  rw [Nat.blt_eq] at hp
  

Proof state:
p : ℕ
hp : 1 < p
h : sMod' (2 ^ p - 1) (p - 2) = 0
⊢ LucasLehmerTest p

Next tactic:
rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp, h]
lemma testTrueHelper (p : ℕ) (hp : Nat.blt 1 p = true) (h : sMod' (2 ^ p - 1) (p - 2) = 0) :
    LucasLehmerTest p := by
  rw [Nat.blt_eq] at hp
  rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp, h]
  

Proof state:
p : ℕ
hp : 1 < p
h : sMod' (2 ^ p - 1) (p - 2) = 0
⊢ ↑0 = 0

Next tactic:
rfl
lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true)
    (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by
  

Proof state:
p : ℕ
hp : Nat.blt 1 p = true
h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2)) = true
⊢ ¬LucasLehmerTest p

Next tactic:
rw [Nat.blt_eq] at hp
lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true)
    (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by
  rw [Nat.blt_eq] at hp
  

Proof state:
p : ℕ
hp : 1 < p
h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2)) = true
⊢ ¬LucasLehmerTest p

Next tactic:
rw [Nat.ble_eq, Nat.succ_le, Nat.pos_iff_ne_zero] at h
lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true)
    (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by
  rw [Nat.blt_eq] at hp
  rw [Nat.ble_eq, Nat.succ_le, Nat.pos_iff_ne_zero] at h
  

Proof state:
p : ℕ
hp : 1 < p
h : sMod' (2 ^ p - 1) (p - 2) ≠ 0
⊢ ¬LucasLehmerTest p

Next tactic:
rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp]
lemma testFalseHelper (p : ℕ) (hp : Nat.blt 1 p = true)
    (h : Nat.ble 1 (sMod' (2 ^ p - 1) (p - 2))) : ¬ LucasLehmerTest p := by
  rw [Nat.blt_eq] at hp
  rw [Nat.ble_eq, Nat.succ_le, Nat.pos_iff_ne_zero] at h
  rw [LucasLehmerTest, LucasLehmer.residue_eq_zero_iff_sMod_eq_zero p hp, ← sMod'_eq_sMod p _ hp]
  

Proof state:
p : ℕ
hp : 1 < p
h : sMod' (2 ^ p - 1) (p - 2) ≠ 0
⊢ ¬↑(sMod' (2 ^ p - 1) (p - 2)) = 0

Next tactic:
simpa using h
theorem modEq_mersenne (n k : ℕ) : k ≡ k / 2 ^ n + k % 2 ^ n [MOD 2 ^ n - 1] :=
  -- See https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/help.20finding.20a.20lemma/near/177698446
  calc
    k = 2 ^ n * (k / 2 ^ n) + k % 2 ^ n := (Nat.div_add_mod k (2 ^ n)).symm
    _ ≡ 1 * (k / 2 ^ n) + k % 2 ^ n [MOD 2 ^ n - 1] :=
      ((Nat.modEq_sub <| Nat.succ_le_of_lt <| pow_pos zero_lt_two _).mul_right _).add_right _
    _ = k / 2 ^ n + k % 2 ^ n := by 

Proof state:
n k : ℕ
⊢ 1 * (k / 2 ^ n) + k % 2 ^ n = k / 2 ^ n + k % 2 ^ n

Next tactic:
rw [one_mul]
theorem List.support_sum_subset [AddMonoid M] (l : List (ι →₀ M)) :
    l.sum.support ⊆ l.foldr (Finsupp.support · ⊔ ·) ∅ := by
  

Proof state:
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddMonoid M
l : List (ι →₀ M)
⊢ (sum l).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ l

Next tactic:
induction' l with hd tl IH
theorem List.support_sum_subset [AddMonoid M] (l : List (ι →₀ M)) :
    l.sum.support ⊆ l.foldr (Finsupp.support · ⊔ ·) ∅ := by
  induction' l with hd tl IH
  · 

Proof state:
case nil
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddMonoid M
⊢ (sum []).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ []

Next tactic:
simp
theorem List.support_sum_subset [AddMonoid M] (l : List (ι →₀ M)) :
    l.sum.support ⊆ l.foldr (Finsupp.support · ⊔ ·) ∅ := by
  induction' l with hd tl IH
  · simp
  · 

Proof state:
case cons
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddMonoid M
hd : ι →₀ M
tl : List (ι →₀ M)
IH : (sum tl).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ tl
⊢ (sum (hd :: tl)).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ (hd :: tl)

Next tactic:
simp only [List.sum_cons, Finset.union_comm]
theorem List.support_sum_subset [AddMonoid M] (l : List (ι →₀ M)) :
    l.sum.support ⊆ l.foldr (Finsupp.support · ⊔ ·) ∅ := by
  induction' l with hd tl IH
  · simp
  · simp only [List.sum_cons, Finset.union_comm]
    

Proof state:
case cons
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddMonoid M
hd : ι →₀ M
tl : List (ι →₀ M)
IH : (sum tl).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ tl
⊢ (hd + sum tl).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ (hd :: tl)

Next tactic:
refine' Finsupp.support_add.trans (Finset.union_subset_union _ IH)
theorem List.support_sum_subset [AddMonoid M] (l : List (ι →₀ M)) :
    l.sum.support ⊆ l.foldr (Finsupp.support · ⊔ ·) ∅ := by
  induction' l with hd tl IH
  · simp
  · simp only [List.sum_cons, Finset.union_comm]
    refine' Finsupp.support_add.trans (Finset.union_subset_union _ IH)
    

Proof state:
case cons
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddMonoid M
hd : ι →₀ M
tl : List (ι →₀ M)
IH : (sum tl).support ⊆ foldr (fun x x_1 => x.support ⊔ x_1) ∅ tl
⊢ hd.support ⊆ hd.support

Next tactic:
rfl
theorem Multiset.support_sum_subset [AddCommMonoid M] (s : Multiset (ι →₀ M)) :
    s.sum.support ⊆ (s.map Finsupp.support).sup := by
  

Proof state:
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddCommMonoid M
s : Multiset (ι →₀ M)
⊢ (sum s).support ⊆ sup (map Finsupp.support s)

Next tactic:
induction s using Quot.inductionOn
theorem Multiset.support_sum_subset [AddCommMonoid M] (s : Multiset (ι →₀ M)) :
    s.sum.support ⊆ (s.map Finsupp.support).sup := by
  induction s using Quot.inductionOn
  

Proof state:
case h
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddCommMonoid M
a✝ : List (ι →₀ M)
⊢ (sum (Quot.mk Setoid.r a✝)).support ⊆ sup (map Finsupp.support (Quot.mk Setoid.r a✝))

Next tactic:
simpa only [Multiset.quot_mk_to_coe'', Multiset.coe_sum, Multiset.coe_map, Multiset.sup_coe,
    List.foldr_map] using List.support_sum_subset _
theorem Finset.support_sum_subset [AddCommMonoid M] (s : Finset (ι →₀ M)) :
    (s.sum id).support ⊆ Finset.sup s Finsupp.support := by
  

Proof state:
ι : Type u_1
M : Type u_2
inst✝¹ : DecidableEq ι
inst✝ : AddCommMonoid M
s : Finset (ι →₀ M)
⊢ (Finset.sum s id).support ⊆ sup s Finsupp.support

Next tactic:
classical convert Multiset.support_sum_subset s.1; simp