Library Stdlib.Zmod.ZmodInv

From Stdlib Require Import NArith ZArith ZModOffset Zcong Lia Field_theory.
From Stdlib Require Import Bool.Bool Lists.List Sorting.Permutation.
Import ListNotations.

From Stdlib Require Import Zmod.ZmodDef Zmod.ZstarDef Zmod.ZmodBase Zmod.ZstarBase.
Local Open Scope Z_scope.
Local Coercion ZmodDef.Zmod.to_Z : Zmod >-> Z.
Local Coercion Zstar.to_Zmod : Zstar.Zstar >-> Zmod.Zmod.

Local Hint Extern 0 (?x <-> ?x) => reflexivity : core.

Module Zmod.
Import ZstarDef.Zstar ZstarBase.Zstar ZmodDef.Zmod ZmodBase.Zmod.

Lemma mdiv_same [m] (a : Zmod m) : mdiv a a = of_Z m (Z.gcd a m).

Lemma in_invertibles [m] (x : Zmod m) : List.In x (invertibles m) <-> Z.coprime x m.
Lemma NoDup_invertibles m : List.NoDup (invertibles m).

Lemma mdiv_same_coprime [m] (a : Zmod m) (H : Z.gcd a m = 1) : mdiv a a = one.

Lemma mdiv_same_prime [m] (x : Zmod m) (Hm : Z.prime m) (H : x <> zero) : mdiv x x = one.

Lemma mul_inv_same_l_coprime [m] (x : Zmod m) (H : Z.gcd x m = 1) :
  mul (inv x) x = one.

Lemma mul_inv_same_r_coprime [m] (x : Zmod m) (H : Z.gcd x m = 1) :
  mul x (inv x) = one.

Lemma mul_inv_same_l_prime [m] (x : Zmod m) (Hm : Z.prime m) (H : x <> zero) :
  mul (inv x) x = one.

Lemma mul_inv_same_r_prime [m] (x : Zmod m) (Hm : Z.prime m) (H : x <> zero) :
  mul x (inv x) = one.

Lemma field_theory m (Hm : Z.prime m) :
  @field_theory (Zmod m) zero one add mul sub opp mdiv inv eq.

Lemma inv_nz_prime [m] (x : Zmod m) (Hm : Z.prime m) (Hx : x <> zero) : inv x <> zero.

Lemma inv_inv [m] (x : Zmod m) (H : Z.gcd x m = 1): inv (inv x) = x.

Lemma inv_inv_prime [m] (x : Zmod m) (Hm : Z.prime m): inv (inv x) = x.

Lemma inv_1 m : @inv m one = one.

Lemma div_1_r [m] x : @mdiv m x one = x.

Lemma mul_cancel_l_coprime [m] (a b c : Zmod m)
  (Ha : Z.gcd a m = 1) (H : mul a b = mul a c) : b = c.

Lemma mul_cancel_r_coprime [m] (a b c : Zmod m)
  (Ha : Z.gcd a m = 1) (H : mul b a = mul c a) : b = c.

Lemma mul_cancel_l_prime [m] (a b c : Zmod m) (Hm : Z.prime m) (Ha : a <> zero)
  (H : mul a b = mul a c) : b = c.

Lemma mul_0_iff_prime [p] (Hp : Z.prime p) (a b : Zmod p) :
  mul a b = zero <-> a = zero \/ b = zero.

Lemma pow_succ_r_coprime [m] (x : Zmod m) z (H : Z.gcd x m = 1) : pow x (Z.succ z) = mul x (pow x z).

Lemma pow_pred_r_coprime [m] (x : Zmod m) z (H : Z.gcd x m = 1) : pow x (Z.pred z) = mdiv (pow x z) x.

Lemma pow_add_r_coprime [m] (x : Zmod m) a b (H : Z.gcd x m = 1) : pow x (a + b) = mul (pow x a) (pow x b).

Lemma pow_mul_r_coprime [m] (x : Zmod m) a b (H : Z.gcd x m = 1) : pow x (a * b) = pow (pow x a) b.

Lemma pow_mul_l_coprime [m] (x y : Zmod m) z (Hx : Z.gcd x m = 1) (Hy : Z.gcd y m = 1) :
  pow (mul x y) z = mul (pow x z) (pow y z).

Lemma pow_1_l [m] z : @pow m one z = one.

Lemma pow_mul_r_nonneg [m] (x : Zmod m) a b (Ha : 0 <= a) (Hb : 0 <= b) :
  pow x (a*b) = pow (pow x a) b.

Lemma square_roots_opp_prime [p] (Hp : Z.prime p) (x y : Zmod p) :
  pow x 2 = pow y 2 <-> (x = y \/ x = opp y).

Lemma square_roots_1_prime [p] (Hp : Z.prime p) (x : Zmod p) :
  pow x 2 = one <-> (x = one \/ x = opp one).

Lemma mul_cancel_r_prime [m] (a b c : Zmod m) (Hm : Z.prime m) (Ha : a <> zero)
  (H : mul b a = mul c a) : b = c.

Theorem fermat_nz [m] (a : Zmod m) (Ha : a <> zero) (H : Z.prime m) :
  pow a (Z.pred m) = one.

Theorem fermat [m] (a : Zmod m) (H : Z.prime m) : pow a m = a.
Theorem fermat_inv [m] (a : Zmod m) (Ha : a <> zero) (H : Z.prime m) :
  pow a (m-2) = inv a.
End Zmod.

Module Z.
Import Znumtheory.

Theorem fermat_nz (m a : Z) (Hm : Z.prime m) (Ha : a mod m <> 0) :
  a^(m-1) mod m = 1.

Theorem fermat (m a : Z) (Hm : Z.prime m) : a^m mod m = a mod m.
End Z.