Section extended_euclid_algorithm.
Variables a b : Z.
(** The specification of Euclid's algorithm is the existence of [u], [v] and [d] such that [ua+vb=d] and [(gcd a b d)]. *)
Inductive Euclid : Set :=
Euclid_intro :
forall u v d:Z, u * a + v * b = d -> Zis_gcd a b d -> Euclid.
(** The recursive part of Euclid's algorithm uses well-founded recursion of non-negative integers. It maintains 6 integers [u1,u2,u3,v1,v2,v3] such that the following invariant holds: [u1*a+u2*b=u3] and [v1*a+v2*b=v3] and [gcd(u3,v3)=gcd(a,b)]. *)
(** We get Euclid's algorithm by applying [euclid_rec] on [1,0,a,0,1,b] when [b>=0] and [1,0,a,0,-1,-b] when [b<0]. *)
End extended_euclid_algorithm.
(** * Bezout's coefficients *)
Inductive Bezout (a b d:Z) : Prop :=
Bezout_intro : forall u v:Z, u * a + v * b = d -> Bezout a b d.
(** Existence of Bezout's coefficients for the [gcd] of [a] and [b] *)
(** gcd of [ca] and [cb] is [c gcd(a,b)]. *)
(** * Relative primality *)
Definition rel_prime (a b:Z) : Prop := Zis_gcd a b 1.
(** Bezout's theorem: [a] and [b] are relatively prime if and only if there exist [u] and [v] such that [ua+vb = 1]. *)
(** Gauss's theorem: if [a] divides [bc] and if [a] and [b] are relatively prime, then [a] divides [c]. *)
(** If [a] is relatively prime to [b] and [c], then it is to [bc] *)
(** After factorization by a gcd, the original numbers are relatively prime. *)
(** * Primality *)
Inductive prime (p:Z) : Prop :=
prime_intro :
1 < p -> (forall n:Z, 1 <= n < p -> rel_prime n p) -> prime p.
(** The sole divisors of a prime number [p] are [-1], [1], [p] and [-p]. *)
(** A prime number is relatively prime with any number it does not divide *)
Hint Resolve prime_rel_prime: zarith.
(** As a consequence, a prime number is relatively prime with smaller numbers *)
(** If a prime [p] divides [ab] then it divides either [a] or [b] *)
Definition prime' p := 1<p /\ (forall n, 1<n<p -> ~ (n|p)).
(** we now prove that [Z.gcd] is indeed a gcd in the sense of [Zis_gcd]. *)
Notation Zgcd_is_pos := Z.gcd_nonneg (only parsing).
Notation Zgcd_inv_0_l := Z.gcd_eq_0_l (only parsing).
Notation Zgcd_inv_0_r := Z.gcd_eq_0_r (only parsing).

Lemma Zgcd_ass a b c : Z.gcd (Z.gcd a b) c = Z.gcd a (Z.gcd b c).