Definition CoPrime (a b : nat) := gcd (Z_of_nat a) (Z_of_nat b) 1.

(* Specifications: *)
Lemma coPrimeSym : forall a b : nat, CoPrime a b -> CoPrime b a.
Lemma coPrimeMult : forall a b c : nat, CoPrime a b -> Divides a (b * c) -> Divides a c.
Lemma coPrimeMult2 : forall a b c : nat, CoPrime a b -> Divides a c -> Divides b c -> Divides (a * b) c.
Lemma ltgt1 : forall a b : nat, a < b -> b > 0.
Lemma minus_le : forall a b : nat, a - b <= a.
Lemma minus1 : forall a b c : Z, (a - c)%Z = (b - c)%Z -> a = b.
Lemma chRem2 : forall b1 r1 b2 r2 q : Z, (0 <= r1)%Z -> (0 <= r2)%Z -> (r1 < q)%Z -> (r2 < q)%Z -> (b1 * q + r1)%Z = (b2 * q + r2)%Z -> r1 = r2.
Lemma chRem3 : forall a b : nat, Z_of_nat a = Z_of_nat b -> a = b.
Lemma uniqueRem : forall r1 r2 b : nat, b > 0 -> forall a : nat, (exists q : nat, a = q * b + r1 /\ b > r1) -> (exists q : nat, a = q * b + r2 /\ b > r2) -> r1 = r2.
Lemma modulo : forall b : nat, b > 0 -> forall a : nat, {p : nat * nat | a = fst p * b + snd p /\ b > snd p}.
Lemma chRem1 : forall b : nat, b > 0 -> forall a : Z, {p : Z * nat | snd p < b /\ Z_of_nat (snd p) = (fst p * Z_of_nat b + a)%Z}.
Lemma gcd_lincomb_nat_dec : forall x y d : nat, x > 0 -> gcd (Z_of_nat x) (Z_of_nat y) d -> {a : Z * Z | Z_of_nat d = (Z_of_nat x * fst a + Z_of_nat y * snd a)%Z}.
Lemma chineseRemainderTheoremHelp : forall x1 x2 : nat, CoPrime x1 x2 -> forall (a b : nat) (pa : a < x1) (pb : b < x2), a <= b -> {y : nat | y < x1 * x2 /\ a = snd (proj1_sig (modulo x1 (ltgt1 _ _ pa) y)) /\ b = snd (proj1_sig (modulo x2 (ltgt1 _ _ pb) y))}.
Lemma chineseRemainderTheorem : forall x1 x2 : nat, CoPrime x1 x2 -> forall (a b : nat) (pa : a < x1) (pb : b < x2), {y : nat | y < x1 * x2 /\ a = snd (proj1_sig (modulo x1 (ltgt1 _ _ pa) y)) /\ b = snd (proj1_sig (modulo x2 (ltgt1 _ _ pb) y))}.