l3lab/ntp-mathlib huggingface dataset:
theorem val_one (n : ℕ) [Fact (1 < n)] : (1 : ZMod n).val = 1 := by
  

Proof state:
n : ℕ
inst✝ : Fact (1 < n)
⊢ val 1 = 1

Next tactic:
rw [val_one_eq_one_mod]
theorem val_one (n : ℕ) [Fact (1 < n)] : (1 : ZMod n).val = 1 := by
  rw [val_one_eq_one_mod]
  

Proof state:
n : ℕ
inst✝ : Fact (1 < n)
⊢ 1 % n = 1

Next tactic:
exact Nat.mod_eq_of_lt Fact.out
theorem val_add {n : ℕ} [NeZero n] (a b : ZMod n) : (a + b).val = (a.val + b.val) % n := by
  

Proof state:
n : ℕ
inst✝ : NeZero n
a b : ZMod n
⊢ val (a + b) = (val a + val b) % n

Next tactic:
cases n
theorem val_add {n : ℕ} [NeZero n] (a b : ZMod n) : (a + b).val = (a.val + b.val) % n := by
  cases n
  · 

Proof state:
case zero
inst✝ : NeZero Nat.zero
a b : ZMod Nat.zero
⊢ val (a + b) = (val a + val b) % Nat.zero

Next tactic:
cases NeZero.ne 0 rfl
theorem val_add {n : ℕ} [NeZero n] (a b : ZMod n) : (a + b).val = (a.val + b.val) % n := by
  cases n
  · cases NeZero.ne 0 rfl
  · 

Proof state:
case succ
n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
a b : ZMod (Nat.succ n✝)
⊢ val (a + b) = (val a + val b) % Nat.succ n✝

Next tactic:
apply Fin.val_add
theorem val_add_of_lt {n : ℕ} {a b : ZMod n} (h : a.val + b.val < n) :
    (a + b).val = a.val + b.val := by
  

Proof state:
n : ℕ
a b : ZMod n
h : val a + val b < n
⊢ val (a + b) = val a + val b

Next tactic:
have : NeZero n := by constructor; rintro rfl; simp at h
theorem val_add_of_lt {n : ℕ} {a b : ZMod n} (h : a.val + b.val < n) :
    (a + b).val = a.val + b.val := by
  have : NeZero n := by 

Proof state:
n : ℕ
a b : ZMod n
h : val a + val b < n
⊢ NeZero n

Next tactic:
constructor
theorem val_add_of_lt {n : ℕ} {a b : ZMod n} (h : a.val + b.val < n) :
    (a + b).val = a.val + b.val := by
  have : NeZero n := by constructor; 

Proof state:
case out
n : ℕ
a b : ZMod n
h : val a + val b < n
⊢ n ≠ 0

Next tactic:
rintro rfl
theorem val_add_of_lt {n : ℕ} {a b : ZMod n} (h : a.val + b.val < n) :
    (a + b).val = a.val + b.val := by
  have : NeZero n := by constructor; rintro rfl; 

Proof state:
case out
a b : ZMod 0
h : val a + val b < 0
⊢ False

Next tactic:
simp at h
theorem val_add_of_lt {n : ℕ} {a b : ZMod n} (h : a.val + b.val < n) :
    (a + b).val = a.val + b.val := by
  have : NeZero n := by constructor; rintro rfl; simp at h
  

Proof state:
n : ℕ
a b : ZMod n
h : val a + val b < n
this : NeZero n
⊢ val (a + b) = val a + val b

Next tactic:
rw [ZMod.val_add, Nat.mod_eq_of_lt h]
theorem val_add_val_of_le {n : ℕ} [NeZero n] {a b : ZMod n} (h : n ≤ a.val + b.val) :
    a.val + b.val = (a + b).val + n := by
  

Proof state:
n : ℕ
inst✝ : NeZero n
a b : ZMod n
h : n ≤ val a + val b
⊢ val a + val b = val (a + b) + n

Next tactic:
rw [val_add, Nat.add_mod_add_of_le_add_mod, Nat.mod_eq_of_lt (val_lt _),
    Nat.mod_eq_of_lt (val_lt _)]
theorem val_add_val_of_le {n : ℕ} [NeZero n] {a b : ZMod n} (h : n ≤ a.val + b.val) :
    a.val + b.val = (a + b).val + n := by
  rw [val_add, Nat.add_mod_add_of_le_add_mod, Nat.mod_eq_of_lt (val_lt _),
    Nat.mod_eq_of_lt (val_lt _)]
  

Proof state:
n : ℕ
inst✝ : NeZero n
a b : ZMod n
h : n ≤ val a + val b
⊢ n ≤ val a % n + val b % n

Next tactic:
rwa [Nat.mod_eq_of_lt (val_lt _), Nat.mod_eq_of_lt (val_lt _)]
theorem val_add_of_le {n : ℕ} [NeZero n] {a b : ZMod n} (h : n ≤ a.val + b.val) :
    (a + b).val = a.val + b.val - n := by
  

Proof state:
n : ℕ
inst✝ : NeZero n
a b : ZMod n
h : n ≤ val a + val b
⊢ val (a + b) = val a + val b - n

Next tactic:
rw [val_add_val_of_le h]
theorem val_add_of_le {n : ℕ} [NeZero n] {a b : ZMod n} (h : n ≤ a.val + b.val) :
    (a + b).val = a.val + b.val - n := by
  rw [val_add_val_of_le h]
  

Proof state:
n : ℕ
inst✝ : NeZero n
a b : ZMod n
h : n ≤ val a + val b
⊢ val (a + b) = val (a + b) + n - n

Next tactic:
exact eq_tsub_of_add_eq rfl
theorem val_add_le {n : ℕ} (a b : ZMod n) : (a + b).val ≤ a.val + b.val := by
  

Proof state:
n : ℕ
a b : ZMod n
⊢ val (a + b) ≤ val a + val b

Next tactic:
cases n
theorem val_add_le {n : ℕ} (a b : ZMod n) : (a + b).val ≤ a.val + b.val := by
  cases n
  · 

Proof state:
case zero
a b : ZMod Nat.zero
⊢ val (a + b) ≤ val a + val b

Next tactic:
simp [ZMod.val]
theorem val_add_le {n : ℕ} (a b : ZMod n) : (a + b).val ≤ a.val + b.val := by
  cases n
  · simp [ZMod.val]; 

Proof state:
case zero
a b : ZMod Nat.zero
⊢ Int.natAbs (a + b) ≤ Int.natAbs a + Int.natAbs b

Next tactic:
apply Int.natAbs_add_le
theorem val_add_le {n : ℕ} (a b : ZMod n) : (a + b).val ≤ a.val + b.val := by
  cases n
  · simp [ZMod.val]; apply Int.natAbs_add_le
  · 

Proof state:
case succ
n✝ : ℕ
a b : ZMod (Nat.succ n✝)
⊢ val (a + b) ≤ val a + val b

Next tactic:
simp [ZMod.val_add]
theorem val_add_le {n : ℕ} (a b : ZMod n) : (a + b).val ≤ a.val + b.val := by
  cases n
  · simp [ZMod.val]; apply Int.natAbs_add_le
  · simp [ZMod.val_add]; 

Proof state:
case succ
n✝ : ℕ
a b : ZMod (Nat.succ n✝)
⊢ (val a + val b) % Nat.succ n✝ ≤ val a + val b

Next tactic:
apply Nat.mod_le
theorem val_mul {n : ℕ} (a b : ZMod n) : (a * b).val = a.val * b.val % n := by
  

Proof state:
n : ℕ
a b : ZMod n
⊢ val (a * b) = val a * val b % n

Next tactic:
cases n
theorem val_mul {n : ℕ} (a b : ZMod n) : (a * b).val = a.val * b.val % n := by
  cases n
  · 

Proof state:
case zero
a b : ZMod Nat.zero
⊢ val (a * b) = val a * val b % Nat.zero

Next tactic:
rw [Nat.mod_zero]
theorem val_mul {n : ℕ} (a b : ZMod n) : (a * b).val = a.val * b.val % n := by
  cases n
  · rw [Nat.mod_zero]
    

Proof state:
case zero
a b : ZMod Nat.zero
⊢ val (a * b) = val a * val b

Next tactic:
apply Int.natAbs_mul
theorem val_mul {n : ℕ} (a b : ZMod n) : (a * b).val = a.val * b.val % n := by
  cases n
  · rw [Nat.mod_zero]
    apply Int.natAbs_mul
  · 

Proof state:
case succ
n✝ : ℕ
a b : ZMod (Nat.succ n✝)
⊢ val (a * b) = val a * val b % Nat.succ n✝

Next tactic:
apply Fin.val_mul
theorem val_mul_le {n : ℕ} (a b : ZMod n) : (a * b).val ≤ a.val * b.val := by
  

Proof state:
n : ℕ
a b : ZMod n
⊢ val (a * b) ≤ val a * val b

Next tactic:
rw [val_mul]
theorem val_mul_le {n : ℕ} (a b : ZMod n) : (a * b).val ≤ a.val * b.val := by
  rw [val_mul]
  

Proof state:
n : ℕ
a b : ZMod n
⊢ val a * val b % n ≤ val a * val b

Next tactic:
apply Nat.mod_le
theorem val_mul_of_lt {n : ℕ} {a b : ZMod n} (h : a.val * b.val < n) :
    (a * b).val = a.val * b.val := by
  

Proof state:
n : ℕ
a b : ZMod n
h : val a * val b < n
⊢ val (a * b) = val a * val b

Next tactic:
rw [val_mul]
theorem val_mul_of_lt {n : ℕ} {a b : ZMod n} (h : a.val * b.val < n) :
    (a * b).val = a.val * b.val := by
  rw [val_mul]
  

Proof state:
n : ℕ
a b : ZMod n
h : val a * val b < n
⊢ val a * val b % n = val a * val b

Next tactic:
apply Nat.mod_eq_of_lt h
instance nontrivial (n : ℕ) [Fact (1 < n)] : Nontrivial (ZMod n) :=
  ⟨⟨0, 1, fun h =>
      zero_ne_one <|
        calc
          0 = (0 : ZMod n).val := by 

Proof state:
n : ℕ
inst✝ : Fact (1 < n)
h : 0 = 1
⊢ 0 = val 0

Next tactic:
rw [val_zero]
instance nontrivial' : Nontrivial (ZMod 0) :=
  by 

Proof state:
⊢ Nontrivial (ZMod 0)

Next tactic:
delta ZMod
instance nontrivial' : Nontrivial (ZMod 0) :=
  by delta ZMod; 

Proof state:
⊢ Nontrivial
    (match 0 with
    | 0 => ℤ
    | Nat.succ n => Fin (n + 1))

Next tactic:
infer_instance
@[nolint unusedHavesSuffices]
theorem inv_zero : ∀ n : ℕ, (0 : ZMod n)⁻¹ = 0
  | 0 => Int.sign_zero
  | n + 1 =>
    show (Nat.gcdA _ (n + 1) : ZMod (n + 1)) = 0 by
      

Proof state:
n : ℕ
⊢ ↑(Nat.gcdA (val 0) (n + 1)) = 0

Next tactic:
rw [val_zero]
@[nolint unusedHavesSuffices]
theorem inv_zero : ∀ n : ℕ, (0 : ZMod n)⁻¹ = 0
  | 0 => Int.sign_zero
  | n + 1 =>
    show (Nat.gcdA _ (n + 1) : ZMod (n + 1)) = 0 by
      rw [val_zero]
      

Proof state:
n : ℕ
⊢ ↑(Nat.gcdA 0 (n + 1)) = 0

Next tactic:
unfold Nat.gcdA Nat.xgcd Nat.xgcdAux
@[nolint unusedHavesSuffices]
theorem inv_zero : ∀ n : ℕ, (0 : ZMod n)⁻¹ = 0
  | 0 => Int.sign_zero
  | n + 1 =>
    show (Nat.gcdA _ (n + 1) : ZMod (n + 1)) = 0 by
      rw [val_zero]
      unfold Nat.gcdA Nat.xgcd Nat.xgcdAux
      

Proof state:
n : ℕ
⊢ ↑(n + 1, 0, 1).2.1 = 0

Next tactic:
rfl
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  

Proof state:
n : ℕ
a : ZMod n
⊢ a * a⁻¹ = ↑(Nat.gcd (val a) n)

Next tactic:
cases' n with n
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · 

Proof state:
case zero
a : ZMod Nat.zero
⊢ a * a⁻¹ = ↑(Nat.gcd (val a) Nat.zero)

Next tactic:
dsimp [ZMod] at a ⊢
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    

Proof state:
case zero
a : ℤ
⊢ a * a⁻¹ = ↑(Nat.gcd (val a) 0)

Next tactic:
calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by 

Proof state:
a : ℤ
⊢ a * Int.sign a = ↑(Int.natAbs a)

Next tactic:
rw [Int.mul_sign]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by 

Proof state:
a : ℤ
⊢ ↑(Int.natAbs a) = ↑(Nat.gcd (Int.natAbs a) 0)

Next tactic:
rw [Nat.gcd_zero_right]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · 

Proof state:
case succ
n : ℕ
a : ZMod (Nat.succ n)
⊢ a * a⁻¹ = ↑(Nat.gcd (val a) (Nat.succ n))

Next tactic:
calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        push_cast
        rw [nat_cast_zmod_val]
        rfl
      _ = Nat.gcd a.val n.succ := by rw [← Nat.gcd_eq_gcd_ab a.val n.succ]; rfl
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ a * a⁻¹ = a * a⁻¹ + ↑(Nat.succ n) * ↑(Nat.gcdB (val a) (Nat.succ n))

Next tactic:
rw [nat_cast_self, zero_mul, add_zero]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ a * a⁻¹ + ↑(Nat.succ n) * ↑(Nat.gcdB (val a) (Nat.succ n)) =
    ↑(↑(val a) * Nat.gcdA (val a) (Nat.succ n) + ↑(Nat.succ n) * Nat.gcdB (val a) (Nat.succ n))

Next tactic:
push_cast
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        push_cast
        

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ a * a⁻¹ + (↑n + 1) * ↑(Nat.gcdB (val a) (Nat.succ n)) =
    ↑(val a) * ↑(Nat.gcdA (val a) (Nat.succ n)) + (↑n + 1) * ↑(Nat.gcdB (val a) (Nat.succ n))

Next tactic:
rw [nat_cast_zmod_val]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        push_cast
        rw [nat_cast_zmod_val]
        

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ a * a⁻¹ + (↑n + 1) * ↑(Nat.gcdB (val a) (Nat.succ n)) =
    a * ↑(Nat.gcdA (val a) (Nat.succ n)) + (↑n + 1) * ↑(Nat.gcdB (val a) (Nat.succ n))

Next tactic:
rfl
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        push_cast
        rw [nat_cast_zmod_val]
        rfl
      _ = Nat.gcd a.val n.succ := by 

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ ↑(↑(val a) * Nat.gcdA (val a) (Nat.succ n) + ↑(Nat.succ n) * Nat.gcdB (val a) (Nat.succ n)) =
    ↑(Nat.gcd (val a) (Nat.succ n))

Next tactic:
rw [← Nat.gcd_eq_gcd_ab a.val n.succ]
theorem mul_inv_eq_gcd {n : ℕ} (a : ZMod n) : a * a⁻¹ = Nat.gcd a.val n := by
  cases' n with n
  · dsimp [ZMod] at a ⊢
    calc
      _ = a * Int.sign a := rfl
      _ = a.natAbs := by rw [Int.mul_sign]
      _ = a.natAbs.gcd 0 := by rw [Nat.gcd_zero_right]
  · calc
      a * a⁻¹ = a * a⁻¹ + n.succ * Nat.gcdB (val a) n.succ := by
        rw [nat_cast_self, zero_mul, add_zero]
      _ = ↑(↑a.val * Nat.gcdA (val a) n.succ + n.succ * Nat.gcdB (val a) n.succ) := by
        push_cast
        rw [nat_cast_zmod_val]
        rfl
      _ = Nat.gcd a.val n.succ := by rw [← Nat.gcd_eq_gcd_ab a.val n.succ]; 

Proof state:
n : ℕ
a : ZMod (Nat.succ n)
⊢ ↑↑(Nat.gcd (val a) (Nat.succ n)) = ↑(Nat.gcd (val a) (Nat.succ n))

Next tactic:
rfl
@[simp]
theorem nat_cast_mod (a : ℕ) (n : ℕ) : ((a % n : ℕ) : ZMod n) = a := by
  

Proof state:
a n : ℕ
⊢ ↑(a % n) = ↑a

Next tactic:
conv =>
      rhs
      rw [← Nat.mod_add_div a n]
@[simp]
theorem nat_cast_mod (a : ℕ) (n : ℕ) : ((a % n : ℕ) : ZMod n) = a := by
  conv =>
      

Proof state:
a n : ℕ
| ↑(a % n) = ↑a

Next tactic:
rhs
      rw [← Nat.mod_add_div a n]
@[simp]
theorem nat_cast_mod (a : ℕ) (n : ℕ) : ((a % n : ℕ) : ZMod n) = a := by
  conv =>
      

Proof state:
a n : ℕ
| ↑(a % n) = ↑a

Next tactic:
rhs
@[simp]
theorem nat_cast_mod (a : ℕ) (n : ℕ) : ((a % n : ℕ) : ZMod n) = a := by
  conv =>
      rhs
      

Proof state:
a n : ℕ
| ↑a

Next tactic:
rw [← Nat.mod_add_div a n]
@[simp]
theorem nat_cast_mod (a : ℕ) (n : ℕ) : ((a % n : ℕ) : ZMod n) = a := by
  conv =>
      rhs
      rw [← Nat.mod_add_div a n]
  

Proof state:
a n : ℕ
⊢ ↑(a % n) = ↑(a % n + n * (a / n))

Next tactic:
simp
theorem eq_iff_modEq_nat (n : ℕ) {a b : ℕ} : (a : ZMod n) = b ↔ a ≡ b [MOD n] := by
  

Proof state:
n a b : ℕ
⊢ ↑a = ↑b ↔ a ≡ b [MOD n]

Next tactic:
cases n
theorem eq_iff_modEq_nat (n : ℕ) {a b : ℕ} : (a : ZMod n) = b ↔ a ≡ b [MOD n] := by
  cases n
  · 

Proof state:
case zero
a b : ℕ
⊢ ↑a = ↑b ↔ a ≡ b [MOD Nat.zero]

Next tactic:
simp [Nat.ModEq, Int.coe_nat_inj', Nat.mod_zero]
theorem eq_iff_modEq_nat (n : ℕ) {a b : ℕ} : (a : ZMod n) = b ↔ a ≡ b [MOD n] := by
  cases n
  · simp [Nat.ModEq, Int.coe_nat_inj', Nat.mod_zero]
  · 

Proof state:
case succ
a b n✝ : ℕ
⊢ ↑a = ↑b ↔ a ≡ b [MOD Nat.succ n✝]

Next tactic:
rw [Fin.ext_iff, Nat.ModEq, ← val_nat_cast, ← val_nat_cast]
theorem eq_iff_modEq_nat (n : ℕ) {a b : ℕ} : (a : ZMod n) = b ↔ a ≡ b [MOD n] := by
  cases n
  · simp [Nat.ModEq, Int.coe_nat_inj', Nat.mod_zero]
  · rw [Fin.ext_iff, Nat.ModEq, ← val_nat_cast, ← val_nat_cast]
    

Proof state:
case succ
a b n✝ : ℕ
⊢ ↑↑a = ↑↑b ↔ val ↑a = val ↑b

Next tactic:
exact Iff.rfl
theorem coe_mul_inv_eq_one {n : ℕ} (x : ℕ) (h : Nat.Coprime x n) :
    ((x : ZMod n) * (x : ZMod n)⁻¹) = 1 := by
  

Proof state:
n x : ℕ
h : Nat.Coprime x n
⊢ ↑x * (↑x)⁻¹ = 1

Next tactic:
rw [Nat.Coprime, Nat.gcd_comm, Nat.gcd_rec] at h
theorem coe_mul_inv_eq_one {n : ℕ} (x : ℕ) (h : Nat.Coprime x n) :
    ((x : ZMod n) * (x : ZMod n)⁻¹) = 1 := by
  rw [Nat.Coprime, Nat.gcd_comm, Nat.gcd_rec] at h
  

Proof state:
n x : ℕ
h : Nat.gcd (x % n) n = 1
⊢ ↑x * (↑x)⁻¹ = 1

Next tactic:
rw [mul_inv_eq_gcd, val_nat_cast, h, Nat.cast_one]
/-- `unitOfCoprime` makes an element of `(ZMod n)ˣ` given
  a natural number `x` and a proof that `x` is coprime to `n`  -/
def unitOfCoprime {n : ℕ} (x : ℕ) (h : Nat.Coprime x n) : (ZMod n)ˣ :=
  ⟨x, x⁻¹, coe_mul_inv_eq_one x h, by 

Proof state:
n x : ℕ
h : Nat.Coprime x n
⊢ (↑x)⁻¹ * ↑x = 1

Next tactic:
rw [mul_comm, coe_mul_inv_eq_one x h]
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  

Proof state:
n : ℕ
u : (ZMod n)ˣ
⊢ Nat.Coprime (val ↑u) n

Next tactic:
cases' n with n
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · 

Proof state:
case zero
u : (ZMod Nat.zero)ˣ
⊢ Nat.Coprime (val ↑u) Nat.zero

Next tactic:
rcases Int.units_eq_one_or u with (rfl | rfl)
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> 

Proof state:
case zero.inl
⊢ Nat.Coprime (val ↑1) Nat.zero

Next tactic:
simp
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> 

Proof state:
case zero.inr
⊢ Nat.Coprime (val ↑(-1)) Nat.zero

Next tactic:
simp
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
⊢ Nat.Coprime (val ↑u) (Nat.succ n)

Next tactic:
apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
⊢ val ↑u * val ↑u⁻¹ ≡ 1 [MOD Nat.succ n]

Next tactic:
have := Units.ext_iff.1 (mul_right_inv u)
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  have := Units.ext_iff.1 (mul_right_inv u)
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
this : ↑(u * u⁻¹) = ↑1
⊢ val ↑u * val ↑u⁻¹ ≡ 1 [MOD Nat.succ n]

Next tactic:
rw [Units.val_one] at this
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  have := Units.ext_iff.1 (mul_right_inv u)
  rw [Units.val_one] at this
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
this : ↑(u * u⁻¹) = 1
⊢ val ↑u * val ↑u⁻¹ ≡ 1 [MOD Nat.succ n]

Next tactic:
rw [← eq_iff_modEq_nat, Nat.cast_one, ← this]
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  have := Units.ext_iff.1 (mul_right_inv u)
  rw [Units.val_one] at this
  rw [← eq_iff_modEq_nat, Nat.cast_one, ← this]; 

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
this : ↑(u * u⁻¹) = 1
⊢ ↑(val ↑u * val ↑u⁻¹) = ↑(u * u⁻¹)

Next tactic:
clear this
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  have := Units.ext_iff.1 (mul_right_inv u)
  rw [Units.val_one] at this
  rw [← eq_iff_modEq_nat, Nat.cast_one, ← this]; clear this
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
⊢ ↑(val ↑u * val ↑u⁻¹) = ↑(u * u⁻¹)

Next tactic:
rw [← nat_cast_zmod_val ((u * u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1))]
theorem val_coe_unit_coprime {n : ℕ} (u : (ZMod n)ˣ) : Nat.Coprime (u : ZMod n).val n := by
  cases' n with n
  · rcases Int.units_eq_one_or u with (rfl | rfl) <;> simp
  apply Nat.coprime_of_mul_modEq_one ((u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1)).val
  have := Units.ext_iff.1 (mul_right_inv u)
  rw [Units.val_one] at this
  rw [← eq_iff_modEq_nat, Nat.cast_one, ← this]; clear this
  rw [← nat_cast_zmod_val ((u * u⁻¹ : Units (ZMod (n + 1))) : ZMod (n + 1))]
  

Proof state:
case succ
n : ℕ
u : (ZMod (Nat.succ n))ˣ
⊢ ↑(val ↑u * val ↑u⁻¹) = ↑(val ↑(u * u⁻¹))

Next tactic:
rw [Units.val_mul, val_mul, nat_cast_mod]
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  

Proof state:
n : ℕ
u : (ZMod n)ˣ
⊢ (↑u)⁻¹ = ↑u⁻¹

Next tactic:
have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  

Proof state:
n : ℕ
u : (ZMod n)ˣ
this : ↑(Nat.gcd (val ↑u) n) = ↑1
⊢ (↑u)⁻¹ = ↑u⁻¹

Next tactic:
rw [← mul_inv_eq_gcd, Nat.cast_one] at this
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  rw [← mul_inv_eq_gcd, Nat.cast_one] at this
  

Proof state:
n : ℕ
u : (ZMod n)ˣ
this : ↑u * (↑u)⁻¹ = 1
⊢ (↑u)⁻¹ = ↑u⁻¹

Next tactic:
let u' : (ZMod n)ˣ := ⟨u, (u : ZMod n)⁻¹, this, by rwa [mul_comm]⟩
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  rw [← mul_inv_eq_gcd, Nat.cast_one] at this
  let u' : (ZMod n)ˣ := ⟨u, (u : ZMod n)⁻¹, this, by 

Proof state:
n : ℕ
u : (ZMod n)ˣ
this : ↑u * (↑u)⁻¹ = 1
⊢ (↑u)⁻¹ * ↑u = 1

Next tactic:
rwa [mul_comm]
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  rw [← mul_inv_eq_gcd, Nat.cast_one] at this
  let u' : (ZMod n)ˣ := ⟨u, (u : ZMod n)⁻¹, this, by rwa [mul_comm]⟩
  

Proof state:
n : ℕ
u : (ZMod n)ˣ
this : ↑u * (↑u)⁻¹ = 1
u' : (ZMod n)ˣ := { val := ↑u, inv := (↑u)⁻¹, val_inv := this, inv_val := (_ : (↑u)⁻¹ * ↑u = 1) }
⊢ (↑u)⁻¹ = ↑u⁻¹

Next tactic:
have h : u = u' := by
    apply Units.ext
    rfl
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  rw [← mul_inv_eq_gcd, Nat.cast_one] at this
  let u' : (ZMod n)ˣ := ⟨u, (u : ZMod n)⁻¹, this, by rwa [mul_comm]⟩
  have h : u = u' := by
    

Proof state:
n : ℕ
u : (ZMod n)ˣ
this : ↑u * (↑u)⁻¹ = 1
u' : (ZMod n)ˣ := { val := ↑u, inv := (↑u)⁻¹, val_inv := this, inv_val := (_ : (↑u)⁻¹ * ↑u = 1) }
⊢ u = u'

Next tactic:
apply Units.ext
@[simp]
theorem inv_coe_unit {n : ℕ} (u : (ZMod n)ˣ) : (u : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ) := by
  have := congr_arg ((↑) : ℕ → ZMod n) (val_coe_unit_coprime u)
  rw [← mul_inv_eq_gcd, Nat.cast_one] at this
  let u' : (ZMod n)ˣ := ⟨u, (u : ZMod n)⁻¹, this, by rwa [mul_comm]⟩
  have h : u = u' := by
    apply Units.ext
    

Proof state:
case a
n : ℕ
u : (ZMod n)ˣ
this : ↑u * (↑u)⁻¹ = 1
u' : (ZMod n)ˣ := { val := ↑u, inv := (↑u)⁻¹, val_inv := this, inv_val := (_ : (↑u)⁻¹ * ↑u = 1) }
⊢ ↑u = ↑u'

Next tactic:
rfl