/-- **`ℤ/nℤ` is a field if and only if `n` is prime.**
* If `n = p` is prime, Mathlib's instance `Field (ZMod p)` applies (it finds inverses with
Bézout's identity).
* If `n = 0`, `ZMod 0` is `ℤ`, which is not a field; if `n = 1`, `ZMod 1` has only one
element, and a field needs `0 ≠ 1`.
* If `n = m * b` with `2 ≤ m < n`, then `m` and `b` are non-zero in `ZMod n` but `m * b = 0`.
If `m` had an inverse `c`, then `b = (c * m) * b = c * (m * b) = 0`, a contradiction. -/
theorem zmod_isField_iff (n : ℕ) : IsField (ZMod n) ↔ n.Prime := by
constructor
· intro h
by_contra hn
rcases Nat.lt_or_ge n 2 with hlt | hge
· interval_cases n
· exact Int.not_isField h
· exact not_isField_of_subsingleton (ZMod 1) h
· simp only [Nat.prime_def_lt', not_and, not_forall, not_not] at hn
obtain ⟨m, hm2, hmn, hdvd⟩ := hn hge
obtain ⟨b, rfl⟩ := hdvd
have hb1 : 1 < b := by
by_contra hb
interval_cases b <;> omega
have hm0 : (m : ZMod (m * b)) ≠ 0 := by
rw [Ne, ZMod.natCast_eq_zero_iff]
intro hd
have := Nat.le_of_dvd (by omega) hd
omega
have hb0 : (b : ZMod (m * b)) ≠ 0 := by
rw [Ne, ZMod.natCast_eq_zero_iff]
intro hd
have := Nat.le_of_dvd (by omega) hd
nlinarith
have hprod : (m : ZMod (m * b)) * (b : ZMod (m * b)) = 0 := by
rw [← Nat.cast_mul, ZMod.natCast_self]
obtain ⟨c, hc⟩ := h.mul_inv_cancel hm0
apply hb0
calc (b : ZMod (m * b)) = (m * c) * b := by rw [hc, one_mul]
_ = c * (m * b) := by ring
_ = 0 := by rw [hprod, mul_zero]
· intro hp
have : Fact n.Prime := ⟨hp⟩
exact Field.toIsField (ZMod n)