(* Copyright 2012-2015 by Adam Petcher.				* * Use of this source code is governed by the license described	* * in the LICENSE file at the root of the source tree.		*)
(* Definitions and theory of natural numbers that is useful in cryptographi proofs. *)
Set Implicit Arguments.
Require Export Arith.
Require Export Omega.
Require Export Arith.Div2.
Require Export Coq.Numbers.Natural.Peano.NPeano.
induction n1; destruct n2; intuition; simpl in *.
remember (n2 * n3) as x.
omega.
remember (n1 * n3) as x.
omega.
f_equal.
eapply IHn1; eauto.
eapply plus_reg_l. eauto.
Qed.
intuition.
eapply mult_same_r; eauto.
rewrite mult_comm.
rewrite (mult_comm n2 n3).
trivial.
Qed.
destruct n1; intuition; simpl in *.
remember (n1 * n2) as x.
omega.
Qed.
intuition.
Qed.
intuition.
Qed.
intuition.
Qed.
intuition.
Qed.
intuition.
Qed.
Class nz (a : nat) := {
agz : a > 0
}.
Instance nz_nat : forall (n : nat), nz (S n).
intuition.
econstructor.
omega.
Defined.
Definition posnat := {n : nat | n > 0}.
Definition posnatToNat(p : posnat) :=
match p with
| exist _ n _ => n
end.
Inductive posnatEq : posnat -> posnat -> Prop :=
| posnatEq_intro :
forall (n1 n2 : nat) pf1 pf2,
n1 = n2 ->
posnatEq (exist _ n1 pf1) (exist _ n2 pf2).
Definition posnatMult(p1 p2 : posnat) : posnat :=
match (p1, p2) with
| (exist _ n1 pf1, exist _ n2 pf2) =>
(exist (fun n => n > 0) (n1 * n2) (mult_gt_0 pf1 pf2))
end.
intuition.
unfold posnatMult.
destruct p1; destruct p2.
econstructor.
apply mult_comm.
Qed.
Coercion posnatToNat : posnat >-> nat.
intuition.
destruct p.
unfold posnatToNat.
trivial.
Qed.
Instance nz_posnat : forall (p : posnat),
nz p.
intuition.
econstructor.
eapply posnat_pos.
Qed.
Definition natToPosnat(n : nat)(pf : nz n) :=
(exist (fun x => x > 0) n agz).
Notation "'pos' x" := (@natToPosnat x _) (at level 40).
Fixpoint expnat n1 n2 :=
match n2 with
| 0 => 1
| S n2' =>
n1 * (expnat n1 n2')
end.
induction n; intuition; simpl in *.
remember (x * expnat x n) as y.
assert (y <> 0); try omega.
intuition; subst.
apply mult_is_O in H1.
destruct H1; omega.
Qed.
intuition.
eapply PeanoNat.Nat.div2_decr.
omega.
Qed.
intuition.
destruct (Even.even_odd_dec n).
rewrite (even_double n) at 1.
unfold double.
omega.
trivial.
rewrite (odd_double n) at 1.
unfold double.
omega.
trivial.
Qed.
Local Open Scope N_scope.
Definition modNat (n : nat)(p : posnat) : nat :=
N.to_nat ((N.of_nat n) mod (N.of_nat p)).
intros []; discriminate.
Qed.
unfold modNat.
intuition.
rewrite Nnat.Nat2N.inj_add.
rewrite <- N.add_mod_idemp_l.
f_equal.
rewrite <- (Nnat.Nat2N.id n2) at 2.
rewrite Nnat.Nat2N.inj_add.
repeat rewrite Nnat.N2Nat.id.
trivial.
destruct p.
simpl.
destruct x;
simpl.
omega.
apply Npos_nz.
Qed.
intuition.
unfold modNat.
rewrite N.mod_same.
trivial.
unfold N.of_nat, posnatToNat.
destruct p.
destruct x.
omega.
apply Npos_nz.
Qed.
intuition.
unfold N.of_nat.
destruct n.
intuition.
simpl.
unfold N.le.
case_eq ((0 ?= N.pos (Pos.of_succ_nat n))); intuition;
try discriminate.
Qed.
intuition.
unfold N.of_nat, posnatToNat.
destruct p.
destruct x.
omega.
destruct x; intuition; simpl in *.
case_eq (N.compare 0 1)%N; intuition.
inversion H.
inversion H.
case_eq (N.compare 0 (N.pos (Pos.succ (Pos.of_succ_nat x))))%N; intuition.
inversion H.
inversion H.
Qed.
intuition.
unfold modNat.
assert (N.of_nat x mod N.of_nat p < N.of_nat p)%N.
apply N.mod_bound_pos.
apply of_nat_ge_0.
apply of_posnat_gt_0.
specialize (Nnat.N2Nat.inj_compare); intros H0.
rewrite <- (Nnat.Nat2N.id p) at 2.
apply nat_compare_lt.
rewrite <- H0.
apply N.compare_lt_iff.
trivial.
Qed.
intuition.
unfold modNat.
rewrite N.mod_small.
apply Nnat.Nat2N.id.
specialize (Nnat.N2Nat.inj_compare); intuition.
specialize (N.compare_lt_iff (N.of_nat x) (N.of_nat n)); intuition.
apply H2.
rewrite H0.
repeat rewrite Nnat.Nat2N.id.
apply nat_compare_lt.
trivial.
Qed.
Definition modNatAddInverse (n : nat)(p : posnat) :=
(p - (modNat n p))%nat.
intuition.
unfold modNatAddInverse.
rewrite <- H.
rewrite modNat_plus.
rewrite minus_add_assoc.
rewrite (plus_comm).
rewrite <- minus_add_assoc.
rewrite minus_diag.
rewrite plus_0_r.
apply modNat_arg_eq.
trivial.
assert (modNat x p < p)%nat.
apply modNat_lt.
omega.
Qed.
intuition.
eapply modNatAddInverse_correct_gen.
trivial.
Qed.
intuition.
unfold modNat in *.
assert (p > 0)%nat.
eapply posnat_pos.
assert (posnatToNat p <> 0)%nat.
omega.
assert (N.of_nat p <> 0%N).
intro.
eapply H0.
rewrite <- Nnat.Nat2N.id.
rewrite <- (Nnat.Nat2N.id p).
f_equal.
trivial.
exists (N.to_nat (N.of_nat x / N.of_nat p)).
rewrite N.mod_eq; trivial.
rewrite <- (Nnat.Nat2N.id p) at 2.
rewrite <- Nnat.N2Nat.inj_mul.
rewrite <- Nnat.N2Nat.inj_add.
rewrite N.mul_comm.
remember (N.of_nat p * (N.of_nat x / N.of_nat p)) as z.
rewrite N.add_sub_assoc.
rewrite N.add_comm.
rewrite N.add_sub.
rewrite Nnat.Nat2N.id.
trivial.
subst.
eapply N.mul_div_le.
trivial.
Qed.
intuition.
destruct (modNat_correct x p).
rewrite H in H0.
econstructor.
rewrite plus_0_r in H0.
eauto.
Qed.
Local Open Scope nat_scope.
intuition.
assert (modNat x p < p).
eapply modNat_lt.
assert (modNat y p < p).
eapply modNat_lt.
rewrite modNat_plus in H.
unfold modNatAddInverse in *.
rewrite minus_add_assoc in H; intuition.
rewrite plus_comm in H.
apply modNat_divides in H.
destruct H.
remember (modNat x p) as a.
remember (modNat y p) as b.
assert (p + a >= p).
omega.
assert (p + a < 2 * p)%nat.
omega.
assert (p + a - b < 2 * p).
omega.
assert (p + a - b > 0).
omega.
assert (x0 * p > 0).
omega.
assert (x0 * p < 2 * p).
omega.
destruct x0.
omega.
destruct x0.
simpl in H.
rewrite plus_0_r in H.
omega.
assert (p > 0).
eapply posnat_pos.
simpl in H7.
remember (x0 * p)%nat as c.
omega.
Qed.
induction x; intuition; simpl in *.
subst.
trivial.
assert (x * p + (y + p) = z).
omega.
apply IHx in H0.
rewrite H0.
rewrite plus_comm.
rewrite modNat_plus.
rewrite modNat_arg_eq.
rewrite plus_0_l.
trivial.
Qed.
induction x; intuition; simpl in *.
rewrite modNat_plus.
rewrite modNat_arg_eq.
rewrite plus_0_l.
eauto.
Qed.
induction x; intuition; simpl in *.
assert (S (x + y) = x + S y).
omega.
rewrite H0 in H.
clear H0.
assert (S (x + z) = x + S z).
omega.
rewrite H0 in H.
clear H0.
apply IHx in H.
destruct (modNat_correct (S y) p).
destruct (modNat_correct (S z) p).
rewrite H in H0.
assert (S y - x0 * p = modNat (S z) p).
omega.
assert (S z - x1 * p = modNat (S z) p).
omega.
rewrite <- H2 in H3.
assert (z - x1 * p = y - x0 * p).
omega.
assert (x1 * p + y = x0 * p + z).
omega.
apply modNat_correct_if in H5.
rewrite modNat_plus in H5.
rewrite modNat_mult in H5.
rewrite plus_0_l in H5.
auto.
Qed.

Lemma modNat_add_same_r : forall x y z p,
modNat (y + x) p = modNat (z + x) p ->
modNat y p = modNat z p.