l3lab/ntp-mathlib huggingface dataset:
@[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
    rfl
  

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) }
h : u = u'
⊢ (↑u)⁻¹ = ↑u⁻¹

Next tactic:
rw [h]
@[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
    rfl
  rw [h]
  

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) }
h : u = u'
⊢ (↑u')⁻¹ = ↑u'⁻¹

Next tactic:
rfl
theorem mul_inv_of_unit {n : ℕ} (a : ZMod n) (h : IsUnit a) : a * a⁻¹ = 1 := by
  

Proof state:
n : ℕ
a : ZMod n
h : IsUnit a
⊢ a * a⁻¹ = 1

Next tactic:
rcases h with ⟨u, rfl⟩
theorem mul_inv_of_unit {n : ℕ} (a : ZMod n) (h : IsUnit a) : a * a⁻¹ = 1 := by
  rcases h with ⟨u, rfl⟩
  

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

Next tactic:
rw [inv_coe_unit, u.mul_inv]
theorem inv_mul_of_unit {n : ℕ} (a : ZMod n) (h : IsUnit a) : a⁻¹ * a = 1 := by
  

Proof state:
n : ℕ
a : ZMod n
h : IsUnit a
⊢ a⁻¹ * a = 1

Next tactic:
rw [mul_comm, mul_inv_of_unit a h]
/-- Equivalence between the units of `ZMod n` and
the subtype of terms `x : ZMod n` for which `x.val` is coprime to `n` -/
def unitsEquivCoprime {n : ℕ} [NeZero n] : (ZMod n)ˣ ≃ { x : ZMod n // Nat.Coprime x.val n }
    where
  toFun x := ⟨x, val_coe_unit_coprime x⟩
  invFun x := unitOfCoprime x.1.val x.2
  left_inv := fun ⟨_, _, _, _⟩ => Units.ext (nat_cast_zmod_val _)
  right_inv := fun ⟨_, _⟩ => by 

Proof state:
n : ℕ
inst✝ : NeZero n
x✝ : { x // Nat.Coprime (val x) n }
val✝ : ZMod n
property✝ : Nat.Coprime (val val✝) n
⊢ (fun x => { val := ↑x, property := (_ : Nat.Coprime (val ↑x) n) })
      ((fun x => unitOfCoprime (val ↑x) (_ : Nat.Coprime (val ↑x) n)) { val := val✝, property := property✝ }) =
    { val := val✝, property := property✝ }

Next tactic:
simp
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by 

Proof state:
m n : ℕ
h : Nat.Coprime m n
⊢ Nat.lcm m n ∣ m * n

Next tactic:
simp [Nat.lcm_dvd_iff]
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      

Proof state:
m n : ℕ
h : Nat.Coprime m n
to_fun : ZMod (m * n) → ZMod m × ZMod n := ⇑(castHom (_ : Nat.lcm m n ∣ m * n) (ZMod m × ZMod n))
inv_fun : ZMod m × ZMod n → ZMod (m * n) :=
  fun x =>
    if m * n = 0 then if m = 1 then ↑((RingHom.snd (ZMod m) (ZMod n)) x) else ↑((RingHom.fst (ZMod m) (ZMod n)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : m * n = 0
⊢ LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun

Next tactic:
rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · 

Proof state:
case inl.intro
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
⊢ LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun

Next tactic:
constructor
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · 

Proof state:
case inl.intro.left
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
⊢ LeftInverse inv_fun to_fun

Next tactic:
intro x
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; 

Proof state:
case inl.intro.left
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
x : ZMod (0 * 1)
⊢ inv_fun (to_fun x) = x

Next tactic:
rfl
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · 

Proof state:
case inl.intro.right
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
⊢ Function.RightInverse inv_fun to_fun

Next tactic:
rintro ⟨x, y⟩
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          

Proof state:
case inl.intro.right.mk
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
x : ZMod 0
y : ZMod 1
⊢ to_fun (inv_fun (x, y)) = (x, y)

Next tactic:
fin_cases y
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          

Proof state:
case inl.intro.right.mk.head
h : Nat.Coprime 0 1
to_fun : ZMod (0 * 1) → ZMod 0 × ZMod 1 := ⇑(castHom (_ : Nat.lcm 0 1 ∣ 0 * 1) (ZMod 0 × ZMod 1))
inv_fun : ZMod 0 × ZMod 1 → ZMod (0 * 1) :=
  fun x =>
    if 0 * 1 = 0 then if 0 = 1 then ↑((RingHom.snd (ZMod 0) (ZMod 1)) x) else ↑((RingHom.fst (ZMod 0) (ZMod 1)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 0 * 1 = 0
x : ZMod 0
⊢ to_fun (inv_fun (x, { val := 0, isLt := (_ : 0 < 0 + 1) })) = (x, { val := 0, isLt := (_ : 0 < 0 + 1) })

Next tactic:
simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · 

Proof state:
case inr.intro
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
⊢ LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun

Next tactic:
constructor
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · 

Proof state:
case inr.intro.left
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
⊢ LeftInverse inv_fun to_fun

Next tactic:
intro x
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; 

Proof state:
case inr.intro.left
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
x : ZMod (1 * 0)
⊢ inv_fun (to_fun x) = x

Next tactic:
rfl
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · 

Proof state:
case inr.intro.right
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
⊢ Function.RightInverse inv_fun to_fun

Next tactic:
rintro ⟨x, y⟩
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          

Proof state:
case inr.intro.right.mk
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
x : ZMod 1
y : ZMod 0
⊢ to_fun (inv_fun (x, y)) = (x, y)

Next tactic:
fin_cases x
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases x
          

Proof state:
case inr.intro.right.mk.head
h : Nat.Coprime 1 0
to_fun : ZMod (1 * 0) → ZMod 1 × ZMod 0 := ⇑(castHom (_ : Nat.lcm 1 0 ∣ 1 * 0) (ZMod 1 × ZMod 0))
inv_fun : ZMod 1 × ZMod 0 → ZMod (1 * 0) :=
  fun x =>
    if 1 * 0 = 0 then if 1 = 1 then ↑((RingHom.snd (ZMod 1) (ZMod 0)) x) else ↑((RingHom.fst (ZMod 1) (ZMod 0)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : 1 * 0 = 0
y : ZMod 0
⊢ to_fun (inv_fun ({ val := 0, isLt := (_ : 0 < 0 + 1) }, y)) = ({ val := 0, isLt := (_ : 0 < 0 + 1) }, y)

Next tactic:
simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases x
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
    else by
      

Proof state:
m n : ℕ
h : Nat.Coprime m n
to_fun : ZMod (m * n) → ZMod m × ZMod n := ⇑(castHom (_ : Nat.lcm m n ∣ m * n) (ZMod m × ZMod n))
inv_fun : ZMod m × ZMod n → ZMod (m * n) :=
  fun x =>
    if m * n = 0 then if m = 1 then ↑((RingHom.snd (ZMod m) (ZMod n)) x) else ↑((RingHom.fst (ZMod m) (ZMod n)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : ¬m * n = 0
⊢ LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun

Next tactic:
haveI : NeZero (m * n) := ⟨hmn0⟩