From ea11b13892c52ddcfce22b5fc18e53a7ddd6fa80 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 6 Jun 2016 23:13:50 -0400 Subject: generic field definition --- _CoqProject | 1 + 1 file changed, 1 insertion(+) (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index 416b29176..de22ff9d4 100644 --- a/_CoqProject +++ b/_CoqProject @@ -2,6 +2,7 @@ src/BaseSystem.v src/BaseSystemProofs.v src/EdDSAProofs.v +src/Field.v src/Rep.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v -- cgit v1.2.3 From 8d4f4adf80c7fdaa8021b283526ab1592ee13600 Mon Sep 17 00:00:00 2001 From: Jason Gross Date: Fri, 10 Jun 2016 15:01:26 -0400 Subject: Add coqprime that works with 8.5, bundle bedrock This simplifes the build process, and also allows us to try to build with 8.5. We autodetect the version of Coq in the Makefile to decide which version of coqprime to build. --- .gitignore | 2 + Bedrock/Nomega.v | 71 ++ Bedrock/Word.v | 1178 +++++++++++++++++++++++++ Makefile | 18 +- README.md | 5 +- _CoqProject | 3 + coqprime-8.5/Coqprime/Cyclic.v | 244 +++++ coqprime-8.5/Coqprime/EGroup.v | 605 +++++++++++++ coqprime-8.5/Coqprime/Euler.v | 88 ++ coqprime-8.5/Coqprime/FGroup.v | 123 +++ coqprime-8.5/Coqprime/IGroup.v | 253 ++++++ coqprime-8.5/Coqprime/Iterator.v | 180 ++++ coqprime-8.5/Coqprime/Lagrange.v | 179 ++++ coqprime-8.5/Coqprime/ListAux.v | 271 ++++++ coqprime-8.5/Coqprime/LucasLehmer.v | 597 +++++++++++++ coqprime-8.5/Coqprime/NatAux.v | 72 ++ coqprime-8.5/Coqprime/PGroup.v | 347 ++++++++ coqprime-8.5/Coqprime/Permutation.v | 506 +++++++++++ coqprime-8.5/Coqprime/Pmod.v | 617 +++++++++++++ coqprime-8.5/Coqprime/Pocklington.v | 261 ++++++ coqprime-8.5/Coqprime/PocklingtonCertificat.v | 756 ++++++++++++++++ coqprime-8.5/Coqprime/Root.v | 239 +++++ coqprime-8.5/Coqprime/Tactic.v | 84 ++ coqprime-8.5/Coqprime/UList.v | 286 ++++++ coqprime-8.5/Coqprime/ZCAux.v | 295 +++++++ coqprime-8.5/Coqprime/ZCmisc.v | 186 ++++ coqprime-8.5/Coqprime/ZProgression.v | 104 +++ coqprime-8.5/Coqprime/ZSum.v | 335 +++++++ coqprime-8.5/Coqprime/Zp.v | 411 +++++++++ coqprime-8.5/Makefile | 319 +++++++ coqprime-8.5/README.md | 9 + coqprime-8.5/_CoqProject | 24 + 32 files changed, 8661 insertions(+), 7 deletions(-) create mode 100644 Bedrock/Nomega.v create mode 100644 Bedrock/Word.v create mode 100644 coqprime-8.5/Coqprime/Cyclic.v create mode 100644 coqprime-8.5/Coqprime/EGroup.v create mode 100644 coqprime-8.5/Coqprime/Euler.v create mode 100644 coqprime-8.5/Coqprime/FGroup.v create mode 100644 coqprime-8.5/Coqprime/IGroup.v create mode 100644 coqprime-8.5/Coqprime/Iterator.v create mode 100644 coqprime-8.5/Coqprime/Lagrange.v create mode 100644 coqprime-8.5/Coqprime/ListAux.v create mode 100644 coqprime-8.5/Coqprime/LucasLehmer.v create mode 100644 coqprime-8.5/Coqprime/NatAux.v create mode 100644 coqprime-8.5/Coqprime/PGroup.v create mode 100644 coqprime-8.5/Coqprime/Permutation.v create mode 100644 coqprime-8.5/Coqprime/Pmod.v create mode 100644 coqprime-8.5/Coqprime/Pocklington.v create mode 100644 coqprime-8.5/Coqprime/PocklingtonCertificat.v create mode 100644 coqprime-8.5/Coqprime/Root.v create mode 100644 coqprime-8.5/Coqprime/Tactic.v create mode 100644 coqprime-8.5/Coqprime/UList.v create mode 100644 coqprime-8.5/Coqprime/ZCAux.v create mode 100644 coqprime-8.5/Coqprime/ZCmisc.v create mode 100644 coqprime-8.5/Coqprime/ZProgression.v create mode 100644 coqprime-8.5/Coqprime/ZSum.v create mode 100644 coqprime-8.5/Coqprime/Zp.v create mode 100644 coqprime-8.5/Makefile create mode 100644 coqprime-8.5/README.md create mode 100644 coqprime-8.5/_CoqProject (limited to '_CoqProject') diff --git a/.gitignore b/.gitignore index 423261343..8726df21c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ fiat *.vo *.d *.glob +*.aux +*.vio Makefile.coq Makefile.bak diff --git a/Bedrock/Nomega.v b/Bedrock/Nomega.v new file mode 100644 index 000000000..2535cd217 --- /dev/null +++ b/Bedrock/Nomega.v @@ -0,0 +1,71 @@ +(* Make [omega] work for [N] *) + +Require Import Coq.Arith.Arith Coq.omega.Omega Coq.NArith.NArith. + +Local Open Scope N_scope. + +Hint Rewrite Nplus_0_r nat_of_Nsucc nat_of_Nplus nat_of_Nminus + N_of_nat_of_N nat_of_N_of_nat + nat_of_P_o_P_of_succ_nat_eq_succ nat_of_P_succ_morphism : N. + +Theorem nat_of_N_eq : forall n m, + nat_of_N n = nat_of_N m + -> n = m. + intros ? ? H; apply (f_equal N_of_nat) in H; + autorewrite with N in *; assumption. +Qed. + +Theorem Nneq_in : forall n m, + nat_of_N n <> nat_of_N m + -> n <> m. + congruence. +Qed. + +Theorem Nneq_out : forall n m, + n <> m + -> nat_of_N n <> nat_of_N m. + intuition. + apply nat_of_N_eq in H0; tauto. +Qed. + +Theorem Nlt_out : forall n m, n < m + -> (nat_of_N n < nat_of_N m)%nat. + unfold Nlt; intros. + rewrite nat_of_Ncompare in H. + apply nat_compare_Lt_lt; assumption. +Qed. + +Theorem Nlt_in : forall n m, (nat_of_N n < nat_of_N m)%nat + -> n < m. + unfold Nlt; intros. + rewrite nat_of_Ncompare. + apply (proj1 (nat_compare_lt _ _)); assumption. +Qed. + +Theorem Nge_out : forall n m, n >= m + -> (nat_of_N n >= nat_of_N m)%nat. + unfold Nge; intros. + rewrite nat_of_Ncompare in H. + apply nat_compare_ge; assumption. +Qed. + +Theorem Nge_in : forall n m, (nat_of_N n >= nat_of_N m)%nat + -> n >= m. + unfold Nge; intros. + rewrite nat_of_Ncompare. + apply nat_compare_ge; assumption. +Qed. + +Ltac nsimp H := simpl in H; repeat progress (autorewrite with N in H; simpl in H). + +Ltac pre_nomega := + try (apply nat_of_N_eq || apply Nneq_in || apply Nlt_in || apply Nge_in); simpl; + repeat (progress autorewrite with N; simpl); + repeat match goal with + | [ H : _ <> _ |- _ ] => apply Nneq_out in H; nsimp H + | [ H : _ = _ -> False |- _ ] => apply Nneq_out in H; nsimp H + | [ H : _ |- _ ] => (apply (f_equal nat_of_N) in H + || apply Nlt_out in H || apply Nge_out in H); nsimp H + end. + +Ltac nomega := pre_nomega; omega || (unfold nat_of_P in *; simpl in *; omega). diff --git a/Bedrock/Word.v b/Bedrock/Word.v new file mode 100644 index 000000000..a33d108fb --- /dev/null +++ b/Bedrock/Word.v @@ -0,0 +1,1178 @@ +(** Fixed precision machine words *) + +Require Import Coq.Arith.Arith Coq.Arith.Div2 Coq.NArith.NArith Coq.Bool.Bool Coq.omega.Omega. +Require Import Bedrock.Nomega. + +Set Implicit Arguments. + + +(** * Basic definitions and conversion to and from [nat] *) + +Inductive word : nat -> Set := +| WO : word O +| WS : bool -> forall n, word n -> word (S n). + +Fixpoint wordToNat sz (w : word sz) : nat := + match w with + | WO => O + | WS false _ w' => (wordToNat w') * 2 + | WS true _ w' => S (wordToNat w' * 2) + end. + +Fixpoint wordToNat' sz (w : word sz) : nat := + match w with + | WO => O + | WS false _ w' => 2 * wordToNat w' + | WS true _ w' => S (2 * wordToNat w') + end. + +Theorem wordToNat_wordToNat' : forall sz (w : word sz), + wordToNat w = wordToNat' w. +Proof. + induction w. auto. simpl. rewrite mult_comm. reflexivity. +Qed. + +Fixpoint mod2 (n : nat) : bool := + match n with + | 0 => false + | 1 => true + | S (S n') => mod2 n' + end. + +Fixpoint natToWord (sz n : nat) : word sz := + match sz with + | O => WO + | S sz' => WS (mod2 n) (natToWord sz' (div2 n)) + end. + +Fixpoint wordToN sz (w : word sz) : N := + match w with + | WO => 0 + | WS false _ w' => 2 * wordToN w' + | WS true _ w' => Nsucc (2 * wordToN w') + end%N. + +Definition Nmod2 (n : N) : bool := + match n with + | N0 => false + | Npos (xO _) => false + | _ => true + end. + +Definition wzero sz := natToWord sz 0. + +Fixpoint wzero' (sz : nat) : word sz := + match sz with + | O => WO + | S sz' => WS false (wzero' sz') + end. + +Fixpoint posToWord (sz : nat) (p : positive) {struct p} : word sz := + match sz with + | O => WO + | S sz' => + match p with + | xI p' => WS true (posToWord sz' p') + | xO p' => WS false (posToWord sz' p') + | xH => WS true (wzero' sz') + end + end. + +Definition NToWord (sz : nat) (n : N) : word sz := + match n with + | N0 => wzero' sz + | Npos p => posToWord sz p + end. + +Fixpoint Npow2 (n : nat) : N := + match n with + | O => 1 + | S n' => 2 * Npow2 n' + end%N. + + +Ltac rethink := + match goal with + | [ H : ?f ?n = _ |- ?f ?m = _ ] => replace m with n; simpl; auto + end. + +Theorem mod2_S_double : forall n, mod2 (S (2 * n)) = true. + induction n; simpl; intuition; rethink. +Qed. + +Theorem mod2_double : forall n, mod2 (2 * n) = false. + induction n; simpl; intuition; rewrite <- plus_n_Sm; rethink. +Qed. + +Local Hint Resolve mod2_S_double mod2_double. + +Theorem div2_double : forall n, div2 (2 * n) = n. + induction n; simpl; intuition; rewrite <- plus_n_Sm; f_equal; rethink. +Qed. + +Theorem div2_S_double : forall n, div2 (S (2 * n)) = n. + induction n; simpl; intuition; f_equal; rethink. +Qed. + +Hint Rewrite div2_double div2_S_double : div2. + +Theorem natToWord_wordToNat : forall sz w, natToWord sz (wordToNat w) = w. + induction w; rewrite wordToNat_wordToNat'; intuition; f_equal; unfold natToWord, wordToNat'; fold natToWord; fold wordToNat'; + destruct b; f_equal; autorewrite with div2; intuition. +Qed. + +Fixpoint pow2 (n : nat) : nat := + match n with + | O => 1 + | S n' => 2 * pow2 n' + end. + +Theorem roundTrip_0 : forall sz, wordToNat (natToWord sz 0) = 0. + induction sz; simpl; intuition. +Qed. + +Hint Rewrite roundTrip_0 : wordToNat. + +Local Hint Extern 1 (@eq nat _ _) => omega. + +Theorem untimes2 : forall n, n + (n + 0) = 2 * n. + auto. +Qed. + +Section strong. + Variable P : nat -> Prop. + + Hypothesis PH : forall n, (forall m, m < n -> P m) -> P n. + + Lemma strong' : forall n m, m <= n -> P m. + induction n; simpl; intuition; apply PH; intuition. + elimtype False; omega. + Qed. + + Theorem strong : forall n, P n. + intros; eapply strong'; eauto. + Qed. +End strong. + +Theorem div2_odd : forall n, + mod2 n = true + -> n = S (2 * div2 n). + induction n using strong; simpl; intuition. + + destruct n; simpl in *; intuition. + discriminate. + destruct n; simpl in *; intuition. + do 2 f_equal. + replace (div2 n + S (div2 n + 0)) with (S (div2 n + (div2 n + 0))); auto. +Qed. + +Theorem div2_even : forall n, + mod2 n = false + -> n = 2 * div2 n. + induction n using strong; simpl; intuition. + + destruct n; simpl in *; intuition. + destruct n; simpl in *; intuition. + discriminate. + f_equal. + replace (div2 n + S (div2 n + 0)) with (S (div2 n + (div2 n + 0))); auto. +Qed. + +Lemma wordToNat_natToWord' : forall sz w, exists k, wordToNat (natToWord sz w) + k * pow2 sz = w. + induction sz; simpl; intuition; repeat rewrite untimes2. + + exists w; intuition. + + case_eq (mod2 w); intro Hmw. + + specialize (IHsz (div2 w)); firstorder. + rewrite wordToNat_wordToNat' in *. + exists x; intuition. + rewrite mult_assoc. + rewrite (mult_comm x 2). + rewrite mult_comm. simpl mult at 1. + rewrite (plus_Sn_m (2 * wordToNat' (natToWord sz (div2 w)))). + rewrite <- mult_assoc. + rewrite <- mult_plus_distr_l. + rewrite H; clear H. + symmetry; apply div2_odd; auto. + + specialize (IHsz (div2 w)); firstorder. + exists x; intuition. + rewrite mult_assoc. + rewrite (mult_comm x 2). + rewrite <- mult_assoc. + rewrite mult_comm. + rewrite <- mult_plus_distr_l. + rewrite H; clear H. + symmetry; apply div2_even; auto. +Qed. + +Theorem wordToNat_natToWord : forall sz w, exists k, wordToNat (natToWord sz w) = w - k * pow2 sz /\ k * pow2 sz <= w. + intros; destruct (wordToNat_natToWord' sz w) as [k]; exists k; intuition. +Qed. + +Definition wone sz := natToWord sz 1. + +Fixpoint wones (sz : nat) : word sz := + match sz with + | O => WO + | S sz' => WS true (wones sz') + end. + + +(** Comparisons *) + +Fixpoint wmsb sz (w : word sz) (a : bool) : bool := + match w with + | WO => a + | WS b _ x => wmsb x b + end. + +Definition whd sz (w : word (S sz)) : bool := + match w in word sz' return match sz' with + | O => unit + | S _ => bool + end with + | WO => tt + | WS b _ _ => b + end. + +Definition wtl sz (w : word (S sz)) : word sz := + match w in word sz' return match sz' with + | O => unit + | S sz'' => word sz'' + end with + | WO => tt + | WS _ _ w' => w' + end. + +Theorem WS_neq : forall b1 b2 sz (w1 w2 : word sz), + (b1 <> b2 \/ w1 <> w2) + -> WS b1 w1 <> WS b2 w2. + intuition. + apply (f_equal (@whd _)) in H0; tauto. + apply (f_equal (@wtl _)) in H0; tauto. +Qed. + + +(** Shattering **) + +Lemma shatter_word : forall n (a : word n), + match n return word n -> Prop with + | O => fun a => a = WO + | S _ => fun a => a = WS (whd a) (wtl a) + end a. + destruct a; eauto. +Qed. + +Lemma shatter_word_S : forall n (a : word (S n)), + exists b, exists c, a = WS b c. +Proof. + intros; repeat eexists; apply (shatter_word a). +Qed. +Lemma shatter_word_0 : forall a : word 0, + a = WO. +Proof. + intros; apply (shatter_word a). +Qed. + +Hint Resolve shatter_word_0. + +Require Import Coq.Logic.Eqdep_dec. + +Definition weq : forall sz (x y : word sz), {x = y} + {x <> y}. + refine (fix weq sz (x : word sz) : forall y : word sz, {x = y} + {x <> y} := + match x in word sz return forall y : word sz, {x = y} + {x <> y} with + | WO => fun _ => left _ _ + | WS b _ x' => fun y => if bool_dec b (whd y) + then if weq _ x' (wtl y) then left _ _ else right _ _ + else right _ _ + end); clear weq. + + abstract (symmetry; apply shatter_word_0). + + abstract (subst; symmetry; apply (shatter_word y)). + + abstract (rewrite (shatter_word y); simpl; intro; injection H; intros; + eauto using inj_pair2_eq_dec, eq_nat_dec). + + abstract (rewrite (shatter_word y); simpl; intro; injection H; auto). +Defined. + +Fixpoint weqb sz (x : word sz) : word sz -> bool := + match x in word sz return word sz -> bool with + | WO => fun _ => true + | WS b _ x' => fun y => + if eqb b (whd y) + then if @weqb _ x' (wtl y) then true else false + else false + end. + +Theorem weqb_true_iff : forall sz x y, + @weqb sz x y = true <-> x = y. +Proof. + induction x; simpl; intros. + { split; auto. } + { rewrite (shatter_word y) in *. simpl in *. + case_eq (eqb b (whd y)); intros. + case_eq (weqb x (wtl y)); intros. + split; auto; intros. rewrite eqb_true_iff in H. f_equal; eauto. eapply IHx; eauto. + split; intros; try congruence. inversion H1; clear H1; subst. + eapply inj_pair2_eq_dec in H4. eapply IHx in H4. congruence. + eapply Peano_dec.eq_nat_dec. + split; intros; try congruence. + inversion H0. apply eqb_false_iff in H. congruence. } +Qed. + +(** * Combining and splitting *) + +Fixpoint combine (sz1 : nat) (w : word sz1) : forall sz2, word sz2 -> word (sz1 + sz2) := + match w in word sz1 return forall sz2, word sz2 -> word (sz1 + sz2) with + | WO => fun _ w' => w' + | WS b _ w' => fun _ w'' => WS b (combine w' w'') + end. + +Fixpoint split1 (sz1 sz2 : nat) : word (sz1 + sz2) -> word sz1 := + match sz1 with + | O => fun _ => WO + | S sz1' => fun w => WS (whd w) (split1 sz1' sz2 (wtl w)) + end. + +Fixpoint split2 (sz1 sz2 : nat) : word (sz1 + sz2) -> word sz2 := + match sz1 with + | O => fun w => w + | S sz1' => fun w => split2 sz1' sz2 (wtl w) + end. + +Ltac shatterer := simpl; intuition; + match goal with + | [ w : _ |- _ ] => rewrite (shatter_word w); simpl + end; f_equal; auto. + +Theorem combine_split : forall sz1 sz2 (w : word (sz1 + sz2)), + combine (split1 sz1 sz2 w) (split2 sz1 sz2 w) = w. + induction sz1; shatterer. +Qed. + +Theorem split1_combine : forall sz1 sz2 (w : word sz1) (z : word sz2), + split1 sz1 sz2 (combine w z) = w. + induction sz1; shatterer. +Qed. + +Theorem split2_combine : forall sz1 sz2 (w : word sz1) (z : word sz2), + split2 sz1 sz2 (combine w z) = z. + induction sz1; shatterer. +Qed. + +Require Import Coq.Logic.Eqdep_dec. + + +Theorem combine_assoc : forall n1 (w1 : word n1) n2 n3 (w2 : word n2) (w3 : word n3) Heq, + combine (combine w1 w2) w3 + = match Heq in _ = N return word N with + | refl_equal => combine w1 (combine w2 w3) + end. + induction w1; simpl; intuition. + + rewrite (UIP_dec eq_nat_dec Heq (refl_equal _)); reflexivity. + + rewrite (IHw1 _ _ _ _ (plus_assoc _ _ _)); clear IHw1. + repeat match goal with + | [ |- context[match ?pf with refl_equal => _ end] ] => generalize pf + end. + generalize dependent (combine w1 (combine w2 w3)). + rewrite plus_assoc; intros. + rewrite (UIP_dec eq_nat_dec e (refl_equal _)). + rewrite (UIP_dec eq_nat_dec Heq0 (refl_equal _)). + reflexivity. +Qed. + +Theorem split2_iter : forall n1 n2 n3 Heq w, + split2 n2 n3 (split2 n1 (n2 + n3) w) + = split2 (n1 + n2) n3 (match Heq in _ = N return word N with + | refl_equal => w + end). + induction n1; simpl; intuition. + + rewrite (UIP_dec eq_nat_dec Heq (refl_equal _)); reflexivity. + + rewrite (IHn1 _ _ (plus_assoc _ _ _)). + f_equal. + repeat match goal with + | [ |- context[match ?pf with refl_equal => _ end] ] => generalize pf + end. + generalize dependent w. + simpl. + fold plus. + generalize (n1 + (n2 + n3)); clear. + intros. + generalize Heq e. + subst. + intros. + rewrite (UIP_dec eq_nat_dec e (refl_equal _)). + rewrite (UIP_dec eq_nat_dec Heq0 (refl_equal _)). + reflexivity. +Qed. + +Theorem combine_end : forall n1 n2 n3 Heq w, + combine (split1 n2 n3 (split2 n1 (n2 + n3) w)) + (split2 (n1 + n2) n3 (match Heq in _ = N return word N with + | refl_equal => w + end)) + = split2 n1 (n2 + n3) w. + induction n1; simpl; intros. + + rewrite (UIP_dec eq_nat_dec Heq (refl_equal _)). + apply combine_split. + + rewrite (shatter_word w) in *. + simpl. + eapply trans_eq; [ | apply IHn1 with (Heq := plus_assoc _ _ _) ]; clear IHn1. + repeat f_equal. + repeat match goal with + | [ |- context[match ?pf with refl_equal => _ end] ] => generalize pf + end. + simpl. + generalize dependent w. + rewrite plus_assoc. + intros. + rewrite (UIP_dec eq_nat_dec e (refl_equal _)). + rewrite (UIP_dec eq_nat_dec Heq0 (refl_equal _)). + reflexivity. +Qed. + + +(** * Extension operators *) + +Definition sext (sz : nat) (w : word sz) (sz' : nat) : word (sz + sz') := + if wmsb w false then + combine w (wones sz') + else + combine w (wzero sz'). + +Definition zext (sz : nat) (w : word sz) (sz' : nat) : word (sz + sz') := + combine w (wzero sz'). + + +(** * Arithmetic *) + +Definition wneg sz (x : word sz) : word sz := + NToWord sz (Npow2 sz - wordToN x). + +Definition wordBin (f : N -> N -> N) sz (x y : word sz) : word sz := + NToWord sz (f (wordToN x) (wordToN y)). + +Definition wplus := wordBin Nplus. +Definition wmult := wordBin Nmult. +Definition wmult' sz (x y : word sz) : word sz := + split2 sz sz (NToWord (sz + sz) (Nmult (wordToN x) (wordToN y))). +Definition wminus sz (x y : word sz) : word sz := wplus x (wneg y). + +Definition wnegN sz (x : word sz) : word sz := + natToWord sz (pow2 sz - wordToNat x). + +Definition wordBinN (f : nat -> nat -> nat) sz (x y : word sz) : word sz := + natToWord sz (f (wordToNat x) (wordToNat y)). + +Definition wplusN := wordBinN plus. + +Definition wmultN := wordBinN mult. +Definition wmultN' sz (x y : word sz) : word sz := + split2 sz sz (natToWord (sz + sz) (mult (wordToNat x) (wordToNat y))). + +Definition wminusN sz (x y : word sz) : word sz := wplusN x (wnegN y). + +(** * Notations *) + +Delimit Scope word_scope with word. +Bind Scope word_scope with word. + +Notation "w ~ 1" := (WS true w) + (at level 7, left associativity, format "w '~' '1'") : word_scope. +Notation "w ~ 0" := (WS false w) + (at level 7, left associativity, format "w '~' '0'") : word_scope. + +Notation "^~" := wneg. +Notation "l ^+ r" := (@wplus _ l%word r%word) (at level 50, left associativity). +Notation "l ^* r" := (@wmult _ l%word r%word) (at level 40, left associativity). +Notation "l ^- r" := (@wminus _ l%word r%word) (at level 50, left associativity). + +Theorem wordToN_nat : forall sz (w : word sz), wordToN w = N_of_nat (wordToNat w). + induction w; intuition. + destruct b; unfold wordToN, wordToNat; fold wordToN; fold wordToNat. + + rewrite N_of_S. + rewrite N_of_mult. + rewrite <- IHw. + rewrite Nmult_comm. + reflexivity. + + rewrite N_of_mult. + rewrite <- IHw. + rewrite Nmult_comm. + reflexivity. +Qed. + +Theorem mod2_S : forall n k, + 2 * k = S n + -> mod2 n = true. + induction n using strong; intros. + destruct n; simpl in *. + elimtype False; omega. + destruct n; simpl in *; auto. + destruct k; simpl in *. + discriminate. + apply H with k; auto. +Qed. + +Theorem wzero'_def : forall sz, wzero' sz = wzero sz. + unfold wzero; induction sz; simpl; intuition. + congruence. +Qed. + +Theorem posToWord_nat : forall p sz, posToWord sz p = natToWord sz (nat_of_P p). + induction p; destruct sz; simpl; intuition; f_equal; try rewrite wzero'_def in *. + + rewrite ZL6. + destruct (ZL4 p) as [? Heq]; rewrite Heq; simpl. + replace (x + S x) with (S (2 * x)) by omega. + symmetry; apply mod2_S_double. + + rewrite IHp. + rewrite ZL6. + destruct (nat_of_P p); simpl; intuition. + replace (n + S n) with (S (2 * n)) by omega. + rewrite div2_S_double; auto. + + unfold nat_of_P; simpl. + rewrite ZL6. + replace (nat_of_P p + nat_of_P p) with (2 * nat_of_P p) by omega. + symmetry; apply mod2_double. + + rewrite IHp. + unfold nat_of_P; simpl. + rewrite ZL6. + replace (nat_of_P p + nat_of_P p) with (2 * nat_of_P p) by omega. + rewrite div2_double. + auto. + auto. +Qed. + +Theorem NToWord_nat : forall sz n, NToWord sz n = natToWord sz (nat_of_N n). + destruct n; simpl; intuition; try rewrite wzero'_def in *. + auto. + apply posToWord_nat. +Qed. + +Theorem wplus_alt : forall sz (x y : word sz), wplus x y = wplusN x y. + unfold wplusN, wplus, wordBinN, wordBin; intros. + + repeat rewrite wordToN_nat; repeat rewrite NToWord_nat. + rewrite nat_of_Nplus. + repeat rewrite nat_of_N_of_nat. + reflexivity. +Qed. + +Theorem wmult_alt : forall sz (x y : word sz), wmult x y = wmultN x y. + unfold wmultN, wmult, wordBinN, wordBin; intros. + + repeat rewrite wordToN_nat; repeat rewrite NToWord_nat. + rewrite nat_of_Nmult. + repeat rewrite nat_of_N_of_nat. + reflexivity. +Qed. + +Theorem Npow2_nat : forall n, nat_of_N (Npow2 n) = pow2 n. + induction n; simpl; intuition. + rewrite <- IHn; clear IHn. + case_eq (Npow2 n); intuition. + rewrite untimes2. + replace (Npos p~0) with (Ndouble (Npos p)) by reflexivity. + apply nat_of_Ndouble. +Qed. + +Theorem wneg_alt : forall sz (x : word sz), wneg x = wnegN x. + unfold wnegN, wneg; intros. + repeat rewrite wordToN_nat; repeat rewrite NToWord_nat. + rewrite nat_of_Nminus. + do 2 f_equal. + apply Npow2_nat. + apply nat_of_N_of_nat. +Qed. + +Theorem wminus_Alt : forall sz (x y : word sz), wminus x y = wminusN x y. + intros; unfold wminusN, wminus; rewrite wneg_alt; apply wplus_alt. +Qed. + +Theorem wplus_unit : forall sz (x : word sz), natToWord sz 0 ^+ x = x. + intros; rewrite wplus_alt; unfold wplusN, wordBinN; intros. + rewrite roundTrip_0; apply natToWord_wordToNat. +Qed. + +Theorem wplus_comm : forall sz (x y : word sz), x ^+ y = y ^+ x. + intros; repeat rewrite wplus_alt; unfold wplusN, wordBinN; f_equal; auto. +Qed. + +Theorem drop_mod2 : forall n k, + 2 * k <= n + -> mod2 (n - 2 * k) = mod2 n. + induction n using strong; intros. + + do 2 (destruct n; simpl in *; repeat rewrite untimes2 in *; intuition). + + destruct k; simpl in *; intuition. + + destruct k; simpl; intuition. + rewrite <- plus_n_Sm. + repeat rewrite untimes2 in *. + simpl; auto. + apply H; omega. +Qed. + +Theorem div2_minus_2 : forall n k, + 2 * k <= n + -> div2 (n - 2 * k) = div2 n - k. + induction n using strong; intros. + + do 2 (destruct n; simpl in *; intuition; repeat rewrite untimes2 in *). + destruct k; simpl in *; intuition. + + destruct k; simpl in *; intuition. + rewrite <- plus_n_Sm. + apply H; omega. +Qed. + +Theorem div2_bound : forall k n, + 2 * k <= n + -> k <= div2 n. + intros; case_eq (mod2 n); intro Heq. + + rewrite (div2_odd _ Heq) in H. + omega. + + rewrite (div2_even _ Heq) in H. + omega. +Qed. + +Theorem drop_sub : forall sz n k, + k * pow2 sz <= n + -> natToWord sz (n - k * pow2 sz) = natToWord sz n. + induction sz; simpl; intuition; repeat rewrite untimes2 in *; f_equal. + + rewrite mult_assoc. + rewrite (mult_comm k). + rewrite <- mult_assoc. + apply drop_mod2. + rewrite mult_assoc. + rewrite (mult_comm 2). + rewrite <- mult_assoc. + auto. + + rewrite <- (IHsz (div2 n) k). + rewrite mult_assoc. + rewrite (mult_comm k). + rewrite <- mult_assoc. + rewrite div2_minus_2. + reflexivity. + rewrite mult_assoc. + rewrite (mult_comm 2). + rewrite <- mult_assoc. + auto. + + apply div2_bound. + rewrite mult_assoc. + rewrite (mult_comm 2). + rewrite <- mult_assoc. + auto. +Qed. + +Local Hint Extern 1 (_ <= _) => omega. + +Theorem wplus_assoc : forall sz (x y z : word sz), x ^+ (y ^+ z) = x ^+ y ^+ z. + intros; repeat rewrite wplus_alt; unfold wplusN, wordBinN; intros. + + repeat match goal with + | [ |- context[wordToNat (natToWord ?sz ?w)] ] => + let Heq := fresh "Heq" in + destruct (wordToNat_natToWord sz w) as [? [Heq ?]]; rewrite Heq + end. + + replace (wordToNat x + wordToNat y - x1 * pow2 sz + wordToNat z) + with (wordToNat x + wordToNat y + wordToNat z - x1 * pow2 sz) by auto. + replace (wordToNat x + (wordToNat y + wordToNat z - x0 * pow2 sz)) + with (wordToNat x + wordToNat y + wordToNat z - x0 * pow2 sz) by auto. + repeat rewrite drop_sub; auto. +Qed. + +Theorem roundTrip_1 : forall sz, wordToNat (natToWord (S sz) 1) = 1. + induction sz; simpl in *; intuition. +Qed. + +Theorem mod2_WS : forall sz (x : word sz) b, mod2 (wordToNat (WS b x)) = b. + intros. rewrite wordToNat_wordToNat'. + destruct b; simpl. + + rewrite untimes2. + case_eq (2 * wordToNat x); intuition. + eapply mod2_S; eauto. + rewrite <- (mod2_double (wordToNat x)); f_equal; omega. +Qed. + +Theorem div2_WS : forall sz (x : word sz) b, div2 (wordToNat (WS b x)) = wordToNat x. + destruct b; rewrite wordToNat_wordToNat'; unfold wordToNat'; fold wordToNat'. + apply div2_S_double. + apply div2_double. +Qed. + +Theorem wmult_unit : forall sz (x : word sz), natToWord sz 1 ^* x = x. + intros; rewrite wmult_alt; unfold wmultN, wordBinN; intros. + destruct sz; simpl. + rewrite (shatter_word x); reflexivity. + rewrite roundTrip_0; simpl. + rewrite plus_0_r. + rewrite (shatter_word x). + f_equal. + + apply mod2_WS. + + rewrite div2_WS. + apply natToWord_wordToNat. +Qed. + +Theorem wmult_comm : forall sz (x y : word sz), x ^* y = y ^* x. + intros; repeat rewrite wmult_alt; unfold wmultN, wordBinN; auto with arith. +Qed. + +Theorem wmult_assoc : forall sz (x y z : word sz), x ^* (y ^* z) = x ^* y ^* z. + intros; repeat rewrite wmult_alt; unfold wmultN, wordBinN; intros. + + repeat match goal with + | [ |- context[wordToNat (natToWord ?sz ?w)] ] => + let Heq := fresh "Heq" in + destruct (wordToNat_natToWord sz w) as [? [Heq ?]]; rewrite Heq + end. + + rewrite mult_minus_distr_l. + rewrite mult_minus_distr_r. + rewrite (mult_assoc (wordToNat x) x0). + rewrite <- (mult_assoc x1). + rewrite (mult_comm (pow2 sz)). + rewrite (mult_assoc x1). + repeat rewrite drop_sub; auto with arith. + rewrite (mult_comm x1). + rewrite <- (mult_assoc (wordToNat x)). + rewrite (mult_comm (wordToNat y)). + rewrite mult_assoc. + rewrite (mult_comm (wordToNat x)). + repeat rewrite <- mult_assoc. + auto with arith. + repeat rewrite <- mult_assoc. + auto with arith. +Qed. + +Theorem wmult_plus_distr : forall sz (x y z : word sz), (x ^+ y) ^* z = (x ^* z) ^+ (y ^* z). + intros; repeat rewrite wmult_alt; repeat rewrite wplus_alt; unfold wmultN, wplusN, wordBinN; intros. + + repeat match goal with + | [ |- context[wordToNat (natToWord ?sz ?w)] ] => + let Heq := fresh "Heq" in + destruct (wordToNat_natToWord sz w) as [? [Heq ?]]; rewrite Heq + end. + + rewrite mult_minus_distr_r. + rewrite <- (mult_assoc x0). + rewrite (mult_comm (pow2 sz)). + rewrite (mult_assoc x0). + + replace (wordToNat x * wordToNat z - x1 * pow2 sz + + (wordToNat y * wordToNat z - x2 * pow2 sz)) + with (wordToNat x * wordToNat z + wordToNat y * wordToNat z - x1 * pow2 sz - x2 * pow2 sz). + repeat rewrite drop_sub; auto with arith. + rewrite (mult_comm x0). + rewrite (mult_comm (wordToNat x + wordToNat y)). + rewrite <- (mult_assoc (wordToNat z)). + auto with arith. + generalize dependent (wordToNat x * wordToNat z). + generalize dependent (wordToNat y * wordToNat z). + intros. + omega. +Qed. + +Theorem wminus_def : forall sz (x y : word sz), x ^- y = x ^+ ^~ y. + reflexivity. +Qed. + +Theorem wordToNat_bound : forall sz (w : word sz), wordToNat w < pow2 sz. + induction w; simpl; intuition. + destruct b; simpl; omega. +Qed. + +Theorem natToWord_pow2 : forall sz, natToWord sz (pow2 sz) = natToWord sz 0. + induction sz; simpl; intuition. + + generalize (div2_double (pow2 sz)); simpl; intro Hr; rewrite Hr; clear Hr. + f_equal. + generalize (mod2_double (pow2 sz)); auto. + auto. +Qed. + +Theorem wminus_inv : forall sz (x : word sz), x ^+ ^~ x = wzero sz. + intros; rewrite wneg_alt; rewrite wplus_alt; unfold wnegN, wplusN, wzero, wordBinN; intros. + + repeat match goal with + | [ |- context[wordToNat (natToWord ?sz ?w)] ] => + let Heq := fresh "Heq" in + destruct (wordToNat_natToWord sz w) as [? [Heq ?]]; rewrite Heq + end. + + replace (wordToNat x + (pow2 sz - wordToNat x - x0 * pow2 sz)) + with (pow2 sz - x0 * pow2 sz). + rewrite drop_sub; auto with arith. + apply natToWord_pow2. + generalize (wordToNat_bound x). + omega. +Qed. + +Definition wring (sz : nat) : ring_theory (wzero sz) (wone sz) (@wplus sz) (@wmult sz) (@wminus sz) (@wneg sz) (@eq _) := + mk_rt _ _ _ _ _ _ _ + (@wplus_unit _) (@wplus_comm _) (@wplus_assoc _) + (@wmult_unit _) (@wmult_comm _) (@wmult_assoc _) + (@wmult_plus_distr _) (@wminus_def _) (@wminus_inv _). + +Theorem weqb_sound : forall sz (x y : word sz), weqb x y = true -> x = y. +Proof. + eapply weqb_true_iff. +Qed. + +Implicit Arguments weqb_sound []. + +Ltac isWcst w := + match eval hnf in w with + | WO => constr:true + | WS ?b ?w' => + match eval hnf in b with + | true => isWcst w' + | false => isWcst w' + | _ => constr:false + end + | _ => constr:false + end. + +Ltac wcst w := + let b := isWcst w in + match b with + | true => w + | _ => constr:NotConstant + end. + +(* Here's how you can add a ring for a specific bit-width. + There doesn't seem to be a polymorphic method, so this code really does need to be copied. *) + +(* +Definition wring8 := wring 8. +Add Ring wring8 : wring8 (decidable (weqb_sound 8), constants [wcst]). +*) + + +(** * Bitwise operators *) + +Fixpoint wnot sz (w : word sz) : word sz := + match w with + | WO => WO + | WS b _ w' => WS (negb b) (wnot w') + end. + +Fixpoint bitwp (f : bool -> bool -> bool) sz (w1 : word sz) : word sz -> word sz := + match w1 with + | WO => fun _ => WO + | WS b _ w1' => fun w2 => WS (f b (whd w2)) (bitwp f w1' (wtl w2)) + end. + +Definition wor := bitwp orb. +Definition wand := bitwp andb. +Definition wxor := bitwp xorb. + +Notation "l ^| r" := (@wor _ l%word r%word) (at level 50, left associativity). +Notation "l ^& r" := (@wand _ l%word r%word) (at level 40, left associativity). + +Theorem wor_unit : forall sz (x : word sz), wzero sz ^| x = x. + unfold wzero, wor; induction x; simpl; intuition congruence. +Qed. + +Theorem wor_comm : forall sz (x y : word sz), x ^| y = y ^| x. + unfold wor; induction x; intro y; rewrite (shatter_word y); simpl; intuition; f_equal; auto with bool. +Qed. + +Theorem wor_assoc : forall sz (x y z : word sz), x ^| (y ^| z) = x ^| y ^| z. + unfold wor; induction x; intro y; rewrite (shatter_word y); simpl; intuition; f_equal; auto with bool. +Qed. + +Theorem wand_unit : forall sz (x : word sz), wones sz ^& x = x. + unfold wand; induction x; simpl; intuition congruence. +Qed. + +Theorem wand_kill : forall sz (x : word sz), wzero sz ^& x = wzero sz. + unfold wzero, wand; induction x; simpl; intuition congruence. +Qed. + +Theorem wand_comm : forall sz (x y : word sz), x ^& y = y ^& x. + unfold wand; induction x; intro y; rewrite (shatter_word y); simpl; intuition; f_equal; auto with bool. +Qed. + +Theorem wand_assoc : forall sz (x y z : word sz), x ^& (y ^& z) = x ^& y ^& z. + unfold wand; induction x; intro y; rewrite (shatter_word y); simpl; intuition; f_equal; auto with bool. +Qed. + +Theorem wand_or_distr : forall sz (x y z : word sz), (x ^| y) ^& z = (x ^& z) ^| (y ^& z). + unfold wand, wor; induction x; intro y; rewrite (shatter_word y); intro z; rewrite (shatter_word z); simpl; intuition; f_equal; auto with bool. + destruct (whd y); destruct (whd z); destruct b; reflexivity. +Qed. + +Definition wbring (sz : nat) : semi_ring_theory (wzero sz) (wones sz) (@wor sz) (@wand sz) (@eq _) := + mk_srt _ _ _ _ _ + (@wor_unit _) (@wor_comm _) (@wor_assoc _) + (@wand_unit _) (@wand_kill _) (@wand_comm _) (@wand_assoc _) + (@wand_or_distr _). + + +(** * Inequality proofs *) + +Ltac word_simpl := unfold sext, zext, wzero in *; simpl in *. + +Ltac word_eq := ring. + +Ltac word_eq1 := match goal with + | _ => ring + | [ H : _ = _ |- _ ] => ring [H] + end. + +Theorem word_neq : forall sz (w1 w2 : word sz), + w1 ^- w2 <> wzero sz + -> w1 <> w2. + intros; intro; subst. + unfold wminus in H. + rewrite wminus_inv in H. + tauto. +Qed. + +Ltac word_neq := apply word_neq; let H := fresh "H" in intro H; simpl in H; ring_simplify in H; try discriminate. + +Ltac word_contra := match goal with + | [ H : _ <> _ |- False ] => apply H; ring + end. + +Ltac word_contra1 := match goal with + | [ H : _ <> _ |- False ] => apply H; + match goal with + | _ => ring + | [ H' : _ = _ |- _ ] => ring [H'] + end + end. + +Open Scope word_scope. + +(** * Signed Logic **) +Fixpoint wordToZ sz (w : word sz) : Z := + if wmsb w true then + (** Negative **) + match wordToN (wneg w) with + | N0 => 0%Z + | Npos x => Zneg x + end + else + (** Positive **) + match wordToN w with + | N0 => 0%Z + | Npos x => Zpos x + end. + +(** * Comparison Predicates and Deciders **) +Definition wlt sz (l r : word sz) : Prop := + Nlt (wordToN l) (wordToN r). +Definition wslt sz (l r : word sz) : Prop := + Zlt (wordToZ l) (wordToZ r). + +Notation "w1 > w2" := (@wlt _ w2%word w1%word) : word_scope. +Notation "w1 >= w2" := (~(@wlt _ w1%word w2%word)) : word_scope. +Notation "w1 < w2" := (@wlt _ w1%word w2%word) : word_scope. +Notation "w1 <= w2" := (~(@wlt _ w2%word w1%word)) : word_scope. + +Notation "w1 '>s' w2" := (@wslt _ w2%word w1%word) (at level 70) : word_scope. +Notation "w1 '>s=' w2" := (~(@wslt _ w1%word w2%word)) (at level 70) : word_scope. +Notation "w1 ' (n < pow2 sz)%nat + -> (m < pow2 sz)%nat + -> n = m. + intros. + apply (f_equal (@wordToNat _)) in H. + destruct (wordToNat_natToWord sz n). + destruct (wordToNat_natToWord sz m). + intuition. + rewrite H4 in H; rewrite H2 in H; clear H4 H2. + assert (x = 0). + destruct x; auto. + simpl in *. + generalize dependent (x * pow2 sz). + intros. + omega. + assert (x0 = 0). + destruct x0; auto. + simpl in *. + generalize dependent (x0 * pow2 sz). + intros. + omega. + subst; simpl in *; omega. +Qed. + +Lemma wordToNat_natToWord_idempotent : forall sz n, + (N.of_nat n < Npow2 sz)%N + -> wordToNat (natToWord sz n) = n. + intros. + destruct (wordToNat_natToWord sz n); intuition. + destruct x. + simpl in *; omega. + simpl in *. + apply Nlt_out in H. + autorewrite with N in *. + rewrite Npow2_nat in *. + generalize dependent (x * pow2 sz). + intros; omega. +Qed. + +Lemma wplus_cancel : forall sz (a b c : word sz), + a ^+ c = b ^+ c + -> a = b. + intros. + apply (f_equal (fun x => x ^+ ^~ c)) in H. + repeat rewrite <- wplus_assoc in H. + rewrite wminus_inv in H. + repeat rewrite (wplus_comm _ (wzero sz)) in H. + repeat rewrite wplus_unit in H. + assumption. +Qed. diff --git a/Makefile b/Makefile index 890d2384e..04df08ae3 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,32 @@ MOD_NAME := Crypto SRC_DIR := src -.PHONY: coq clean install coqprime update-_CoqProject +.PHONY: coq clean install coqprime-8.4 coqprime-8.5 coqprime update-_CoqProject .DEFAULT_GOAL := coq SORT_COQPROJECT = sed 's,[^/]*/,~&,g' | env LC_COLLATE=C sort | sed 's,~,,g' update-_CoqProject:: - (echo '-R $(SRC_DIR) $(MOD_NAME)'; (git ls-files 'src/*.v' | $(SORT_COQPROJECT))) > _CoqProject + (echo '-R $(SRC_DIR) $(MOD_NAME)'; echo '-R Bedrock Bedrock'; (git ls-files 'src/*.v' 'Bedrock/*.v' | $(SORT_COQPROJECT))) > _CoqProject coq: coqprime Makefile.coq $(MAKE) -f Makefile.coq -coqprime: +COQ_VERSION_PREFIX = The Coq Proof Assistant, version +COQ_VERSION := $(firstword $(subst $(COQ_VERSION_PREFIX),,$(shell $(COQBIN)coqc --version 2>/dev/null))) + +ifneq ($(filter 8.5%,$(COQ_VERSION)),) # 8.5 +coqprime: coqprime-8.5 +else +coqprime: coqprime-8.4 +endif + +coqprime-8.4: $(MAKE) -C coqprime +coqprime-8.5: + $(MAKE) -C coqprime-8.5 + Makefile.coq: Makefile _CoqProject coq_makefile -f _CoqProject -o Makefile.coq diff --git a/README.md b/README.md index 9144b03a1..4486c7f76 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,5 @@ Synthesizing Correct-by-Construction Assembly for Cryptographic Primitives To build: - git clone git@github.mit.edu:plv/bedrock.git - ( cd bedrock && make Bedrock/Word.vo ) - ( cd coqprime && make ) - export COQPATH="$(pwd)/bedrock:$(pwd)/coqprime${COQPATH:+:}$COQPATH" + export COQPATH="$(pwd)/coqprime${COQPATH:+:}$COQPATH" make diff --git a/_CoqProject b/_CoqProject index 416b29176..4b36c103b 100644 --- a/_CoqProject +++ b/_CoqProject @@ -1,4 +1,7 @@ -R src Crypto +-R Bedrock Bedrock +Bedrock/Nomega.v +Bedrock/Word.v src/BaseSystem.v src/BaseSystemProofs.v src/EdDSAProofs.v diff --git a/coqprime-8.5/Coqprime/Cyclic.v b/coqprime-8.5/Coqprime/Cyclic.v new file mode 100644 index 000000000..c25f683ca --- /dev/null +++ b/coqprime-8.5/Coqprime/Cyclic.v @@ -0,0 +1,244 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(*********************************************************************** + Cyclic.v + + Proof that an abelien ring is cyclic + ************************************************************************) +Require Import ZCAux. +Require Import List. +Require Import Root. +Require Import UList. +Require Import IGroup. +Require Import EGroup. +Require Import FGroup. + +Open Scope Z_scope. + +Section Cyclic. + +Variable A: Set. +Variable plus mult: A -> A -> A. +Variable op: A -> A. +Variable zero one: A. +Variable support: list A. +Variable e: A. + +Hypothesis A_dec: forall a b: A, {a = b} + {a <> b}. +Hypothesis e_not_zero: zero <> e. +Hypothesis support_ulist: ulist support. +Hypothesis e_in_support: In e support. +Hypothesis zero_in_support: In zero support. +Hypothesis mult_internal: forall a b, In a support -> In b support -> In (mult a b) support. +Hypothesis mult_assoc: forall a b c, In a support -> In b support -> In c support -> mult a (mult b c) = mult (mult a b) c. +Hypothesis e_is_zero_l: forall a, In a support -> mult e a = a. +Hypothesis e_is_zero_r: forall a, In a support -> mult a e = a. +Hypothesis plus_internal: forall a b, In a support -> In b support -> In (plus a b) support. +Hypothesis plus_zero: forall a, In a support -> plus zero a = a. +Hypothesis plus_comm: forall a b, In a support -> In b support -> plus a b = plus b a. +Hypothesis plus_assoc: forall a b c, In a support -> In b support -> In c support -> plus a (plus b c) = plus (plus a b) c. +Hypothesis mult_zero: forall a, In a support -> mult zero a = zero. +Hypothesis mult_comm: forall a b, In a support -> In b support ->mult a b = mult b a. +Hypothesis mult_plus_distr: forall a b c, In a support -> In b support -> In c support -> mult a (plus b c) = plus (mult a b) (mult a c). +Hypothesis op_internal: forall a, In a support -> In (op a) support. +Hypothesis plus_op_zero: forall a, In a support -> plus a (op a) = zero. +Hypothesis mult_integral: forall a b, In a support -> In b support -> mult a b = zero -> a = zero \/ b = zero. + +Definition IA := (IGroup A mult support e A_dec support_ulist e_in_support mult_internal + mult_assoc + e_is_zero_l e_is_zero_r). + +Hint Resolve (fun x => isupport_incl _ mult support e A_dec x). + +Theorem gpow_evaln: forall n, 0 < n -> + exists p, (length p <= Zabs_nat n)%nat /\ (forall i, In i p -> In i support) /\ + forall x, In x IA.(s) -> eval A plus mult zero (zero::p) x = gpow x IA n. +intros n Hn; generalize Hn; pattern n; apply natlike_ind; auto with zarith. +intros H1; contradict H1; auto with zarith. +intros x Hx Rec _. +case Zle_lt_or_eq with (1 := Hx); clear Hx; intros Hx; subst; simpl. +case Rec; auto; simpl; intros p (Hp1, (Hp2, Hp3)); clear Rec. +exists (zero::p); split; simpl. +rewrite Zabs_nat_Zsucc; auto with arith zarith. +split. +intros i [Hi | Hi]; try rewrite <- Hi; auto. +intros x1 Hx1; simpl. +rewrite Hp3; repeat rewrite plus_zero; unfold Zsucc; try rewrite gpow_add; auto with zarith. +rewrite gpow_1; try apply mult_comm; auto. +apply (fun x => isupport_incl _ mult support e A_dec x); auto. +change (In (gpow x1 IA x) IA.(s)). +apply gpow_in; auto. +apply mult_internal; auto. +apply (fun x => isupport_incl _ mult support e A_dec x); auto. +change (In (gpow x1 IA x) IA.(s)). +apply gpow_in; auto. +exists (e:: nil); split; simpl. +compute; auto with arith. +split. +intros i [Hi | Hi]; try rewrite <- Hi; auto; case Hi. +intros x Hx; simpl. +rewrite plus_zero; rewrite (fun x => mult_comm x zero); try rewrite mult_zero; auto. +rewrite plus_comm; try rewrite plus_zero; auto. +Qed. + +Definition check_list_gpow: forall l n, (incl l IA.(s)) -> {forall a, In a l -> gpow a IA n = e} + {exists a, In a l /\ gpow a IA n <> e}. +intros l n; elim l; simpl; auto. +intros H; left; intros a H1; case H1. +intros a l1 Rec H. +case (A_dec (gpow a IA n) e); intros H2. +case Rec; try intros H3. +apply incl_tran with (2 := H); auto with datatypes. +left; intros a1 H4; case H4; auto. +intros H5; rewrite <- H5; auto. +right; case H3; clear H3; intros a1 (H3, H4). +exists a1; auto. +right; exists a; auto. +Defined. + + +Theorem prime_power_div: forall p q i, prime p -> 0 <= q -> 0 <= i -> (q | p ^ i) -> exists j, 0 <= j <= i /\ q = p ^ j. +intros p q i Hp Hq Hi H. +assert (Hp1: 0 < p). +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +pattern q; apply prime_div_induction with (p ^ i); auto with zarith. +exists 0; rewrite Zpower_0_r; auto with zarith. +intros p1 i1 Hp2 Hi1 H1. +case Zle_lt_or_eq with (1 := Hi1); clear Hi1; intros Hi1; subst. +assert (Heq: p1 = p). +apply prime_div_Zpower_prime with i; auto. +apply Zdivide_trans with (2 := H1). +apply Zpower_divide; auto with zarith. +exists i1; split; auto; try split; auto with zarith. +case (Zle_or_lt i1 i); auto; intros H2. +absurd (p1 ^ i1 <= p ^ i). +apply Zlt_not_le; rewrite Heq; apply Zpower_lt_monotone; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +apply Zdivide_le; auto with zarith. +rewrite Heq; auto. +exists 0; repeat rewrite Zpower_exp_0; auto with zarith. +intros p1 q1 Hpq (j1,((Hj1, Hj2), Hj3)) (j2, ((Hj4, Hj5), Hj6)). +case Zle_lt_or_eq with (1 := Hj1); clear Hj1; intros Hj1; subst. +case Zle_lt_or_eq with (1 := Hj4); clear Hj4; intros Hj4; subst. +inversion Hpq as [ H0 H1 H2]. +absurd (p | 1). +intros H3; absurd (1 < p). +apply Zle_not_lt; apply Zdivide_le; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +apply H2; apply Zpower_divide; auto with zarith. +exists j1; rewrite Zpower_0_r; auto with zarith. +exists j2; rewrite Zpower_0_r; auto with zarith. +Qed. + +Theorem inj_lt_inv: forall n m : nat, Z_of_nat n < Z_of_nat m -> (n < m)%nat. +intros n m H; case (le_or_lt m n); auto; intros H1; contradict H. +apply Zle_not_lt; apply inj_le; auto. +Qed. + +Theorem not_all_solutions: forall i, 0 < i < g_order IA -> exists a, In a IA.(s) /\ gpow a IA i <> e. +intros i (Hi, Hi2). +case (check_list_gpow IA.(s) i); try intros H; auto with datatypes. +case (gpow_evaln i); auto; intros p (Hp1, (Hp2, Hp3)). +absurd ((op e) = zero). +intros H1; case e_not_zero. +rewrite <- (plus_op_zero e); try rewrite H1; auto. +rewrite plus_comm; auto. +apply (root_max_is_zero _ (fun x => In x support) plus mult op zero) with (l := IA.(s)) (p := op e :: p); auto with datatypes. +simpl; intros x [Hx | Hx]; try rewrite <- Hx; auto. +intros x Hx. +generalize (Hp3 _ Hx); simpl; rewrite plus_zero; auto. +intros tmp; rewrite tmp; clear tmp. +rewrite H; auto; rewrite plus_comm; auto with datatypes. +apply mult_internal; auto. +apply eval_P; auto. +simpl; apply lt_le_S; apply le_lt_trans with (1 := Hp1). +apply inj_lt_inv. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem divide_g_order_e_order: forall n, 0 <= n -> (n | g_order IA) -> exists a, In a IA.(s) /\ e_order A_dec a IA = n. +intros n Hn H. +assert (Hg: 0 < g_order IA). +apply g_order_pos. +assert (He: forall a, 0 <= e_order A_dec a IA). +intros a; apply Zlt_le_weak; apply e_order_pos. +pattern n; apply prime_div_induction with (n := g_order IA); auto. +exists e; split; auto. +apply IA.(e_in_s). +apply Zle_antisym. +apply Zdivide_le; auto with zarith. +apply e_order_divide_gpow; auto with zarith. +apply IA.(e_in_s). +rewrite gpow_1; auto. +apply IA.(e_in_s). +match goal with |- (_ <= ?X) => assert (0 < X) end; try apply e_order_pos; auto with zarith. +intros p i Hp Hi K. +assert (Hp1: 0 < p). +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +assert (Hi1: 0 < p ^ i). +apply Zpower_gt_0; auto. +case Zle_lt_or_eq with (1 := Hi); clear Hi; intros Hi; subst. +case (not_all_solutions (g_order IA / p)). +apply Zdivide_Zdiv_lt_pos; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +apply Zdivide_trans with (2 := K). +apply Zpower_divide; auto. +intros a (Ha1, Ha2). +exists (gpow a IA (g_order IA / p ^ i)); split. +apply gpow_in; auto. +match goal with |- ?X = ?Y => assert (H1: (X | Y) ) end; auto. +apply e_order_divide_gpow; auto with zarith. +apply gpow_in; auto. +rewrite <- gpow_gpow; auto with zarith. +rewrite Zmult_comm; rewrite <- Zdivide_Zdiv_eq; auto with zarith. +apply fermat_gen; auto. +apply Z_div_pos; auto with zarith. +case prime_power_div with (4 := H1); auto with zarith. +intros j ((Hj1, Hj2), Hj3). +case Zle_lt_or_eq with (1 := Hj2); intros Hj4; subst; auto. +case Ha2. +replace (g_order IA) with (((g_order IA / p ^i) * p ^ j) * p ^ (i - j - 1) * p). +rewrite Z_div_mult; auto with zarith. +repeat rewrite gpow_gpow; auto with zarith. +rewrite <- Hj3. +rewrite gpow_e_order_is_e; auto with zarith. +rewrite gpow_e; auto. +apply Zlt_le_weak; apply Zpower_gt_0; auto with zarith. +apply gpow_in; auto. +apply Z_div_pos; auto with zarith. +apply Zmult_le_0_compat; try apply Z_div_pos; auto with zarith. +pattern p at 4; rewrite <- Zpower_1_r. +repeat rewrite <- Zmult_assoc; repeat rewrite <- Zpower_exp; auto with zarith. +replace (j + (i - j - 1 + 1)) with i; auto with zarith. +apply sym_equal; rewrite Zmult_comm; apply Zdivide_Zdiv_eq; auto with zarith. +rewrite Zpower_0_r; exists e; split. +apply IA.(e_in_s). +match goal with |- ?X = 1 => assert (tmp: 0 < X); try apply e_order_pos; +case Zle_lt_or_eq with 1 X; auto with zarith; clear tmp; intros H1 end. +absurd (gpow IA.(FGroup.e) IA 1 = IA.(FGroup.e)). +apply gpow_e_order_lt_is_not_e with A_dec; auto with zarith. +apply gpow_e; auto with zarith. +intros p q H1 (a, (Ha1, Ha2)) (b, (Hb1, Hb2)). +exists (mult a b); split. +apply IA.(internal); auto. +rewrite <- Ha2; rewrite <- Hb2; apply order_mult; auto. +rewrite Ha2; rewrite Hb2; auto. +Qed. + +Set Implicit Arguments. +Definition cyclic (A: Set) A_dec (op: A -> A -> A) (G: FGroup op):= exists a, In a G.(s) /\ e_order A_dec a G = g_order G. +Unset Implicit Arguments. + +Theorem cyclic_field: cyclic A_dec IA. +red; apply divide_g_order_e_order; auto. +apply Zlt_le_weak; apply g_order_pos. +exists 1; ring. +Qed. + +End Cyclic. diff --git a/coqprime-8.5/Coqprime/EGroup.v b/coqprime-8.5/Coqprime/EGroup.v new file mode 100644 index 000000000..933176abd --- /dev/null +++ b/coqprime-8.5/Coqprime/EGroup.v @@ -0,0 +1,605 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + EGroup.v + + Given an element a, create the group {e, a, a^2, ..., a^n} + **********************************************************************) +Require Import ZArith. +Require Import Tactic. +Require Import List. +Require Import ZCAux. +Require Import ZArith Znumtheory. +Require Import Wf_nat. +Require Import UList. +Require Import FGroup. +Require Import Lagrange. + +Open Scope Z_scope. + +Section EGroup. + +Variable A: Set. + +Variable A_dec: forall a b: A, {a = b} + {~ a = b}. + +Variable op: A -> A -> A. + +Variable a: A. + +Variable G: FGroup op. + +Hypothesis a_in_G: In a G.(s). + + +(************************************** + The power function for the group + **************************************) + +Set Implicit Arguments. +Definition gpow n := match n with Zpos p => iter_pos _ (op a) G.(e) p | _ => G.(e) end. +Unset Implicit Arguments. + +Theorem gpow_0: gpow 0 = G.(e). +simpl; sauto. +Qed. + +Theorem gpow_1 : gpow 1 = a. +simpl; sauto. +Qed. + +(************************************** + Some properties of the power function + **************************************) + +Theorem gpow_in: forall n, In (gpow n) G.(s). +intros n; case n; simpl; auto. +intros p; apply iter_pos_invariant with (Inv := fun x => In x G.(s)); auto. +Qed. + +Theorem gpow_op: forall b p, In b G.(s) -> iter_pos _ (op a) b p = op (iter_pos _ (op a) G.(e) p) b. +intros b p; generalize b; elim p; simpl; auto; clear b p. +intros p Rec b Hb. +assert (H: In (gpow (Zpos p)) G.(s)). +apply gpow_in. +rewrite (Rec b); try rewrite (fun x y => Rec (op x y)); try rewrite (fun x y => Rec (iter_pos A x y p)); auto. +repeat rewrite G.(assoc); auto. +intros p Rec b Hb. +assert (H: In (gpow (Zpos p)) G.(s)). +apply gpow_in. +rewrite (Rec b); try rewrite (fun x y => Rec (op x y)); try rewrite (fun x y => Rec (iter_pos A x y p)); auto. +repeat rewrite G.(assoc); auto. +intros b H; rewrite e_is_zero_r; auto. +Qed. + +Theorem gpow_add: forall n m, 0 <= n -> 0 <= m -> gpow (n + m) = op (gpow n) (gpow m). +intros n; case n. +intros m _ _; simpl; apply sym_equal; apply e_is_zero_l; apply gpow_in. +2: intros p m H; contradict H; auto with zarith. +intros p1 m; case m. +intros _ _; simpl; apply sym_equal; apply e_is_zero_r. +exact (gpow_in (Zpos p1)). +2: intros p2 _ H; contradict H; auto with zarith. +intros p2 _ _; simpl. +rewrite iter_pos_plus; rewrite (fun x y => gpow_op (iter_pos A x y p2)); auto. +exact (gpow_in (Zpos p2)). +Qed. + +Theorem gpow_1_more: + forall n, 0 < n -> gpow n = G.(e) -> forall m, 0 <= m -> exists p, 0 <= p < n /\ gpow m = gpow p. +intros n H1 H2 m Hm; generalize Hm; pattern m; apply Z_lt_induction; auto with zarith; clear m Hm. +intros m Rec Hm. +case (Zle_or_lt n m); intros H3. +case (Rec (m - n)); auto with zarith. +intros p (H4,H5); exists p; split; auto. +replace m with (n + (m - n)); auto with zarith. +rewrite gpow_add; try rewrite H2; try rewrite H5; sauto; auto with zarith. +generalize gpow_in; sauto. +exists m; auto. +Qed. + +Theorem gpow_i: forall n m, 0 <= n -> 0 <= m -> gpow n = gpow (n + m) -> gpow m = G.(e). +intros n m H1 H2 H3; generalize gpow_in; intro PI. +apply g_cancel_l with (g:= G) (a := gpow n); sauto. +rewrite <- gpow_add; try rewrite <- H3; sauto. +Qed. + +(************************************** + We build the support by iterating the power function + **************************************) + +Set Implicit Arguments. + +Fixpoint support_aux (b: A) (n: nat) {struct n}: list A := +b::let c := op a b in + match n with + O => nil | + (S n1) =>if A_dec c G.(e) then nil else support_aux c n1 + end. + +Definition support := support_aux G.(e) (Zabs_nat (g_order G)). + +Unset Implicit Arguments. + +(************************************** + Some properties of the support that helps to prove that we have a group + **************************************) + +Theorem support_aux_gpow: + forall n m b, 0 <= m -> In b (support_aux (gpow m) n) -> + exists p, (0 <= p < length (support_aux (gpow m) n))%nat /\ b = gpow (m + Z_of_nat p). +intros n; elim n; simpl. +intros n1 b Hm [H1 | H1]; exists 0%nat; simpl; rewrite Zplus_0_r; auto; case H1. +intros n1 Rec m b Hm [H1 | H1]. +exists 0%nat; simpl; rewrite Zplus_0_r; auto; auto with arith. +generalize H1; case (A_dec (op a (gpow m)) G.(e)); clear H1; simpl; intros H1 H2. +case H2. +case (Rec (1 + m) b); auto with zarith. +rewrite gpow_add; auto with zarith. +rewrite gpow_1; auto. +intros p (Hp1, Hp2); exists (S p); split; auto with zarith. +rewrite <- gpow_1. +rewrite <- gpow_add; auto with zarith. +rewrite inj_S; rewrite Hp2; eq_tac; auto with zarith. +Qed. + +Theorem gpow_support_aux_not_e: + forall n m p, 0 <= m -> m < p < m + Z_of_nat (length (support_aux (gpow m) n)) -> gpow p <> G.(e). +intros n; elim n; simpl. +intros m p Hm (H1, H2); contradict H2; auto with zarith. +intros n1 Rec m p Hm; case (A_dec (op a (gpow m)) G.(e)); simpl. +intros _ (H1, H2); contradict H2; auto with zarith. +assert (tmp: forall p, Zpos (P_of_succ_nat p) = 1 + Z_of_nat p). +intros p1; apply trans_equal with (Z_of_nat (S p1)); auto; rewrite inj_S; auto with zarith. +rewrite tmp. +intros H1 (H2, H3); case (Zle_lt_or_eq (1 + m) p); auto with zarith; intros H4; subst. +apply (Rec (1 + m)); try split; auto with zarith. +rewrite gpow_add; auto with zarith. +rewrite gpow_1; auto with zarith. +rewrite gpow_add; try rewrite gpow_1; auto with zarith. +Qed. + +Theorem support_aux_not_e: forall n m b, 0 <= m -> In b (tail (support_aux (gpow m) n)) -> ~ b = G.(e). +intros n; elim n; simpl. +intros m b Hm H; case H. +intros n1 Rec m b Hm; case (A_dec (op a (gpow m)) G.(e)); intros H1 H2; simpl; auto. +assert (Hm1: 0 <= 1 + m); auto with zarith. +generalize( Rec (1 + m) b Hm1) H2; case n1; auto; clear Hm1. +intros _ [H3 | H3]; auto. +contradict H1; subst; auto. +rewrite gpow_add; simpl; try rewrite e_is_zero_r; auto with zarith. +intros n2; case (A_dec (op a (op a (gpow m))) G.(e)); intros H3. +intros _ [H4 | H4]. +contradict H1; subst; auto. +case H4. +intros H4 [H5 | H5]; subst; auto. +Qed. + +Theorem support_aux_length_le: forall n a, (length (support_aux a n) <= n + 1)%nat. +intros n; elim n; simpl; auto. +intros n1 Rec a1; case (A_dec (op a a1) G.(e)); simpl; auto with arith. +Qed. + +Theorem support_aux_length_le_is_e: + forall n m, 0 <= m -> (length (support_aux (gpow m) n) <= n)%nat -> + gpow (m + Z_of_nat (length (support_aux (gpow m) n))) = G.(e) . +intros n; elim n; simpl; auto. +intros m _ H1; contradict H1; auto with arith. +intros n1 Rec m Hm; case (A_dec (op a (gpow m)) G.(e)); simpl; intros H1. +intros H2; rewrite Zplus_comm; rewrite gpow_add; simpl; try rewrite e_is_zero_r; auto with zarith. +assert (tmp: forall p, Zpos (P_of_succ_nat p) = 1 + Z_of_nat p). +intros p1; apply trans_equal with (Z_of_nat (S p1)); auto; rewrite inj_S; auto with zarith. +rewrite tmp; clear tmp. +rewrite <- gpow_1. +rewrite <- gpow_add; auto with zarith. +rewrite Zplus_assoc; rewrite (Zplus_comm 1); intros H2; apply Rec; auto with zarith. +Qed. + +Theorem support_aux_in: + forall n m p, 0 <= m -> (p < length (support_aux (gpow m) n))% nat -> + (In (gpow (m + Z_of_nat p)) (support_aux (gpow m) n)). +intros n; elim n; simpl; auto; clear n. +intros m p Hm H1; replace p with 0%nat. +left; eq_tac; auto with zarith. +generalize H1; case p; simpl; auto with arith. +intros n H2; contradict H2; apply le_not_lt; auto with arith. +intros n1 Rec m p Hm; case (A_dec (op a (gpow m)) G.(e)); simpl; intros H1 H2; auto. +replace p with 0%nat. +left; eq_tac; auto with zarith. +generalize H2; case p; simpl; auto with arith. +intros n H3; contradict H3; apply le_not_lt; auto with arith. +generalize H2; case p; simpl; clear H2. +rewrite Zplus_0_r; auto. +intros n. +assert (tmp: forall p, Zpos (P_of_succ_nat p) = 1 + Z_of_nat p). +intros p1; apply trans_equal with (Z_of_nat (S p1)); auto; rewrite inj_S; auto with zarith. +rewrite tmp; clear tmp. +rewrite <- gpow_1; rewrite <- gpow_add; auto with zarith. +rewrite Zplus_assoc; rewrite (Zplus_comm 1); intros H2; right; apply Rec; auto with zarith. +Qed. + +Theorem support_aux_ulist: + forall n m, 0 <= m -> (forall p, 0 <= p < m -> gpow (1 + p) <> G.(e)) -> ulist (support_aux (gpow m) n). +intros n; elim n; auto; clear n. +intros m _ _; auto. +simpl; apply ulist_cons; auto. +intros n1 Rec m Hm H. +simpl; case (A_dec (op a (gpow m)) G.(e)); auto. +intros He; apply ulist_cons; auto. +intros H1; case (support_aux_gpow n1 (1 + m) (gpow m)); auto with zarith. +rewrite gpow_add; try rewrite gpow_1; auto with zarith. +intros p (Hp1, Hp2). +assert (H2: gpow (1 + Z_of_nat p) = G.(e)). +apply gpow_i with m; auto with zarith. +rewrite Hp2; eq_tac; auto with zarith. +case (Zle_or_lt m (Z_of_nat p)); intros H3; auto. +2: case (H (Z_of_nat p)); auto with zarith. +case (support_aux_not_e (S n1) m (gpow (1 + Z_of_nat p))); auto. +rewrite gpow_add; auto with zarith; simpl; rewrite e_is_zero_r; auto. +case (A_dec (op a (gpow m)) G.(e)); auto. +intros _; rewrite <- gpow_1; repeat rewrite <- gpow_add; auto with zarith. +replace (1 + Z_of_nat p) with ((1 + m) + (Z_of_nat (p - Zabs_nat m))); auto with zarith. +apply support_aux_in; auto with zarith. +rewrite inj_minus1; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply inj_le_rev. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +rewrite <- gpow_1; repeat rewrite <- gpow_add; auto with zarith. +apply (Rec (1 + m)); auto with zarith. +intros p H1; case (Zle_lt_or_eq p m); intros; subst; auto with zarith. +rewrite gpow_add; auto with zarith. +rewrite gpow_1; auto. +Qed. + +Theorem support_gpow: forall b, (In b support) -> exists p, 0 <= p < Z_of_nat (length support) /\ b = gpow p. +intros b H; case (support_aux_gpow (Zabs_nat (g_order G)) 0 b); auto with zarith. +intros p ((H1, H2), H3); exists (Z_of_nat p); repeat split; auto with zarith. +apply inj_lt; auto. +Qed. + +Theorem support_incl_G: incl support G.(s). +intros a1 H; case (support_gpow a1); auto; intros p (H1, H2); subst; apply gpow_in. +Qed. + +Theorem gpow_support_not_e: forall p, 0 < p < Z_of_nat (length support) -> gpow p <> G.(e). +intros p (H1, H2); apply gpow_support_aux_not_e with (m := 0) (n := length G.(s)); simpl; + try split; auto with zarith. +rewrite <- (Zabs_nat_Z_of_nat (length G.(s))); auto. +Qed. + +Theorem support_not_e: forall b, In b (tail support) -> ~ b = G.(e). +intros b H; apply (support_aux_not_e (Zabs_nat (g_order G)) 0); auto with zarith. +Qed. + +Theorem support_ulist: ulist support. +apply (support_aux_ulist (Zabs_nat (g_order G)) 0); auto with zarith. +Qed. + +Theorem support_in_e: In G.(e) support. +unfold support; case (Zabs_nat (g_order G)); simpl; auto with zarith. +Qed. + +Theorem gpow_length_support_is_e: gpow (Z_of_nat (length support)) = G.(e). +apply (support_aux_length_le_is_e (Zabs_nat (g_order G)) 0); simpl; auto with zarith. +unfold g_order; rewrite Zabs_nat_Z_of_nat; apply ulist_incl_length. +rewrite <- (Zabs_nat_Z_of_nat (length G.(s))); auto. +exact support_ulist. +rewrite <- (Zabs_nat_Z_of_nat (length G.(s))); auto. +exact support_incl_G. +Qed. + +Theorem support_in: forall p, 0 <= p < Z_of_nat (length support) -> In (gpow p) support. +intros p (H, H1); unfold support. +rewrite <- (Zabs_eq p); auto with zarith. +rewrite <- (inj_Zabs_nat p); auto. +generalize (support_aux_in (Zabs_nat (g_order G)) 0); simpl; intros H2; apply H2; auto with zarith. +rewrite <- (fun x => Zabs_nat_Z_of_nat (@length A x)); auto. +apply Zabs_nat_lt; split; auto. +Qed. + +Theorem support_internal: forall a b, In a support -> In b support -> In (op a b) support. +intros a1 b1 H1 H2. +case support_gpow with (1 := H1); auto; intros p1 ((H3, H4), H5); subst. +case support_gpow with (1 := H2); auto; intros p2 ((H5, H6), H7); subst. +rewrite <- gpow_add; auto with zarith. +case gpow_1_more with (m:= p1 + p2) (2 := gpow_length_support_is_e); auto with zarith. +intros p3 ((H8, H9), H10); rewrite H10; apply support_in; auto with zarith. +Qed. + +Theorem support_i_internal: forall a, In a support -> In (G.(i) a) support. +generalize gpow_in; intros Hp. +intros a1 H1. +case support_gpow with (1 := H1); auto. +intros p1 ((H2, H3), H4); case Zle_lt_or_eq with (1 := H2); clear H2; intros H2; subst. +2: rewrite gpow_0; rewrite i_e; apply support_in_e. +replace (G.(i) (gpow p1)) with (gpow (Z_of_nat (length support - Zabs_nat p1))). +apply support_in; auto with zarith. +rewrite inj_minus1. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply inj_le_rev; rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply g_cancel_l with (g:= G) (a := gpow p1); sauto. +rewrite <- gpow_add; auto with zarith. +replace (p1 + Z_of_nat (length support - Zabs_nat p1)) with (Z_of_nat (length support)). +rewrite gpow_length_support_is_e; sauto. +rewrite inj_minus1; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply inj_le_rev; rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +Qed. + +(************************************** + We are now ready to build the group + **************************************) + +Definition Gsupport: (FGroup op). +generalize support_incl_G; unfold incl; intros Ho. +apply mkGroup with support G.(e) G.(i); sauto. +apply support_ulist. +apply support_internal. +intros a1 b1 c1 H1 H2 H3; apply G.(assoc); sauto. +apply support_in_e. +apply support_i_internal. +Defined. + +(************************************** + Definition of the order of an element + **************************************) +Set Implicit Arguments. + +Definition e_order := Z_of_nat (length support). + +Unset Implicit Arguments. + +(************************************** + Some properties of the order of an element + **************************************) + +Theorem gpow_e_order_is_e: gpow e_order = G.(e). +apply (support_aux_length_le_is_e (Zabs_nat (g_order G)) 0); simpl; auto with zarith. +unfold g_order; rewrite Zabs_nat_Z_of_nat; apply ulist_incl_length. +rewrite <- (Zabs_nat_Z_of_nat (length G.(s))); auto. +exact support_ulist. +rewrite <- (Zabs_nat_Z_of_nat (length G.(s))); auto. +exact support_incl_G. +Qed. + +Theorem gpow_e_order_lt_is_not_e: forall n, 1 <= n < e_order -> gpow n <> G.(e). +intros n (H1, H2); apply gpow_support_not_e; auto with zarith. +Qed. + +Theorem e_order_divide_g_order: (e_order | g_order G). +change ((g_order Gsupport) | g_order G). +apply lagrange; auto. +exact support_incl_G. +Qed. + +Theorem e_order_pos: 0 < e_order. +unfold e_order, support; case (Zabs_nat (g_order G)); simpl; auto with zarith. +Qed. + +Theorem e_order_divide_gpow: forall n, 0 <= n -> gpow n = G.(e) -> (e_order | n). +generalize gpow_in; intros Hp. +generalize e_order_pos; intros Hp1. +intros n Hn; generalize Hn; pattern n; apply Z_lt_induction; auto; clear n Hn. +intros n Rec Hn H. +case (Zle_or_lt e_order n); intros H1. +case (Rec (n - e_order)); auto with zarith. +apply g_cancel_l with (g:= G) (a := gpow e_order); sauto. +rewrite G.(e_is_zero_r); auto with zarith. +rewrite <- gpow_add; try (rewrite gpow_e_order_is_e; rewrite <- H; eq_tac); auto with zarith. +intros k Hk; exists (1 + k). +rewrite Zmult_plus_distr_l; rewrite <- Hk; auto with zarith. +case (Zle_lt_or_eq 0 n); auto with arith; intros H2; subst. +contradict H; apply support_not_e. +generalize H1; unfold e_order, support. +case (Zabs_nat (g_order G)); simpl; auto. +intros H3; contradict H3; auto with zarith. +intros n1; case (A_dec (op a G.(e)) G.(e)); simpl; intros _ H3. +contradict H3; auto with zarith. +generalize H3; clear H3. +assert (tmp: forall p, Zpos (P_of_succ_nat p) = 1 + Z_of_nat p). +intros p1; apply trans_equal with (Z_of_nat (S p1)); auto; rewrite inj_S; auto with zarith. +rewrite tmp; clear tmp; intros H3. +change (In (gpow n) (support_aux (gpow 1) n1)). +replace n with (1 + Z_of_nat (Zabs_nat n - 1)). +apply support_aux_in; auto with zarith. +rewrite <- (fun x => Zabs_nat_Z_of_nat (@length A x)). +replace (Zabs_nat n - 1)%nat with (Zabs_nat (n - 1)). +apply Zabs_nat_lt; split; auto with zarith. +rewrite G.(e_is_zero_r) in H3; try rewrite gpow_1; auto with zarith. +apply inj_eq_rev; rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +rewrite inj_minus1; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply inj_le_rev; rewrite inj_Zabs_nat; simpl; auto with zarith. +rewrite Zabs_eq; auto with zarith. +rewrite inj_minus1; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +rewrite Zplus_comm; simpl; auto with zarith. +apply inj_le_rev; rewrite inj_Zabs_nat; simpl; auto with zarith. +rewrite Zabs_eq; auto with zarith. +exists 0; auto with arith. +Qed. + +End EGroup. + +Theorem gpow_gpow: forall (A : Set) (op : A -> A -> A) (a : A) (G : FGroup op), + In a (s G) -> forall n m, 0 <= n -> 0 <= m -> gpow a G (n * m ) = gpow (gpow a G n) G m. +intros A op a G H n m; case n. +simpl; intros _ H1; generalize H1. +pattern m; apply natlike_ind; simpl; auto. +intros x H2 Rec _; unfold Zsucc; rewrite gpow_add; simpl; auto with zarith. +repeat rewrite G.(e_is_zero_r); auto with zarith. +apply gpow_in; sauto. +intros p1 _; case m; simpl; auto. +assert(H1: In (iter_pos A (op a) (e G) p1) (s G)). +refine (gpow_in _ _ _ _ _ (Zpos p1)); auto. +intros p2 _; pattern p2; apply Pind; simpl; auto. +rewrite Pmult_1_r; rewrite G.(e_is_zero_r); try rewrite G.(e_is_zero_r); auto. +intros p3 Rec; rewrite Pplus_one_succ_r; rewrite Pmult_plus_distr_l. +rewrite Pmult_1_r. +simpl; repeat rewrite iter_pos_plus; simpl. +rewrite G.(e_is_zero_r); auto. +rewrite gpow_op with (G:= G); try rewrite Rec; auto. +apply sym_equal; apply gpow_op; auto. +intros p Hp; contradict Hp; auto with zarith. +Qed. + +Theorem gpow_e: forall (A : Set) (op : A -> A -> A) (G : FGroup op) n, 0 <= n -> gpow G.(e) G n = G.(e). +intros A op G n; case n; simpl; auto with zarith. +intros p _; elim p; simpl; auto; intros p1 Rec; repeat rewrite Rec; auto. +Qed. + +Theorem gpow_pow: forall (A : Set) (op : A -> A -> A) (a : A) (G : FGroup op), + In a (s G) -> forall n, 0 <= n -> gpow a G (2 ^ n) = G.(e) -> forall m, n <= m -> gpow a G (2 ^ m) = G.(e). +intros A op a G H n H1 H2 m Hm. +replace m with (n + (m - n)); auto with zarith. +rewrite Zpower_exp; auto with zarith. +rewrite gpow_gpow; auto with zarith. +rewrite H2; apply gpow_e. +apply Zpower_ge_0; auto with zarith. +Qed. + +Theorem gpow_mult: forall (A : Set) (op : A -> A -> A) (a b: A) (G : FGroup op) + (comm: forall a b, In a (s G) -> In b (s G) -> op a b = op b a), + In a (s G) -> In b (s G) -> forall n, 0 <= n -> gpow (op a b) G n = op (gpow a G n) (gpow b G n). +intros A op a b G comm Ha Hb n; case n; simpl; auto. +intros _; rewrite G.(e_is_zero_r); auto. +2: intros p Hp; contradict Hp; auto with zarith. +intros p _; pattern p; apply Pind; simpl; auto. +repeat rewrite G.(e_is_zero_r); auto. +intros p3 Rec; rewrite Pplus_one_succ_r. +repeat rewrite iter_pos_plus; simpl. +repeat rewrite (fun x y H z => gpow_op A op x G H (op y z)) ; auto. +rewrite Rec. +repeat rewrite G.(e_is_zero_r); auto. +assert(H1: In (iter_pos A (op a) (e G) p3) (s G)). +refine (gpow_in _ _ _ _ _ (Zpos p3)); auto. +assert(H2: In (iter_pos A (op b) (e G) p3) (s G)). +refine (gpow_in _ _ _ _ _ (Zpos p3)); auto. +repeat rewrite <- G.(assoc); try eq_tac; auto. +rewrite (fun x y => comm (iter_pos A x y p3) b); auto. +rewrite (G.(assoc) a); try apply comm; auto. +Qed. + +Theorem Zdivide_mult_rel_prime: forall a b c : Z, (a | c) -> (b | c) -> rel_prime a b -> (a * b | c). +intros a b c (q1, H1) (q2, H2) H3. +assert (H4: (a | q2)). +apply Gauss with (2 := H3). +exists q1; rewrite <- H1; rewrite H2; auto with zarith. +case H4; intros q3 H5; exists q3; rewrite H2; rewrite H5; auto with zarith. +Qed. + +Theorem order_mult: forall (A : Set) (op : A -> A -> A) (A_dec: forall a b: A, {a = b} + {~ a = b}) (G : FGroup op) + (comm: forall a b, In a (s G) -> In b (s G) -> op a b = op b a) (a b: A), + In a (s G) -> In b (s G) -> rel_prime (e_order A_dec a G) (e_order A_dec b G) -> + e_order A_dec (op a b) G = e_order A_dec a G * e_order A_dec b G. +intros A op A_dec G comm a b Ha Hb Hab. +assert (Hoat: 0 < e_order A_dec a G); try apply e_order_pos. +assert (Hobt: 0 < e_order A_dec b G); try apply e_order_pos. +assert (Hoabt: 0 < e_order A_dec (op a b) G); try apply e_order_pos. +assert (Hoa: 0 <= e_order A_dec a G); auto with zarith. +assert (Hob: 0 <= e_order A_dec b G); auto with zarith. +apply Zle_antisym; apply Zdivide_le; auto with zarith. +apply Zmult_lt_O_compat; auto. +apply e_order_divide_gpow; sauto; auto with zarith. +rewrite gpow_mult; auto with zarith. +rewrite gpow_gpow; auto with zarith. +rewrite gpow_e_order_is_e; auto with zarith. +rewrite gpow_e; auto. +rewrite Zmult_comm. +rewrite gpow_gpow; auto with zarith. +rewrite gpow_e_order_is_e; auto with zarith. +rewrite gpow_e; auto. +apply Zdivide_mult_rel_prime; auto. +apply Gauss with (2 := Hab). +apply e_order_divide_gpow; auto with zarith. +rewrite <- (gpow_e _ _ G (e_order A_dec b G)); auto. +rewrite <- (gpow_e_order_is_e _ A_dec _ (op a b) G); auto with zarith. +rewrite <- gpow_gpow; auto with zarith. +rewrite (Zmult_comm (e_order A_dec (op a b) G)). +rewrite gpow_mult; auto with zarith. +rewrite gpow_gpow with (a := b); auto with zarith. +rewrite gpow_e_order_is_e; auto with zarith. +rewrite gpow_e; auto with zarith. +rewrite G.(e_is_zero_r); auto with zarith. +apply gpow_in; auto. +apply Gauss with (2 := rel_prime_sym _ _ Hab). +apply e_order_divide_gpow; auto with zarith. +rewrite <- (gpow_e _ _ G (e_order A_dec a G)); auto. +rewrite <- (gpow_e_order_is_e _ A_dec _ (op a b) G); auto with zarith. +rewrite <- gpow_gpow; auto with zarith. +rewrite (Zmult_comm (e_order A_dec (op a b) G)). +rewrite gpow_mult; auto with zarith. +rewrite gpow_gpow with (a := a); auto with zarith. +rewrite gpow_e_order_is_e; auto with zarith. +rewrite gpow_e; auto with zarith. +rewrite G.(e_is_zero_l); auto with zarith. +apply gpow_in; auto. +Qed. + +Theorem fermat_gen: forall (A : Set) (A_dec: forall (a b: A), {a = b} + {a <>b}) (op : A -> A -> A) (a: A) (G : FGroup op), + In a G.(s) -> gpow a G (g_order G) = G.(e). +intros A A_dec op a G H. +assert (H1: (e_order A_dec a G | g_order G)). +apply e_order_divide_g_order; auto. +case H1; intros q; intros Hq; rewrite Hq. +assert (Hq1: 0 <= q). +apply Zmult_le_reg_r with (e_order A_dec a G); auto with zarith. +apply Zlt_gt; apply e_order_pos. +rewrite Zmult_0_l; rewrite <- Hq; apply Zlt_le_weak; apply g_order_pos. +rewrite Zmult_comm; rewrite gpow_gpow; auto with zarith. +rewrite gpow_e_order_is_e; auto with zarith. +apply gpow_e; auto. +apply Zlt_le_weak; apply e_order_pos. +Qed. + +Theorem order_div: forall (A : Set) (A_dec: forall (a b: A), {a = b} + {a <>b}) (op : A -> A -> A) (a: A) (G : FGroup op) m, + 0 < m -> (forall p, prime p -> (p | m) -> gpow a G (m / p) <> G.(e)) -> + In a G.(s) -> gpow a G m = G.(e) -> e_order A_dec a G = m. +intros A Adec op a G m Hm H H1 H2. +assert (F1: 0 <= m); auto with zarith. +case (e_order_divide_gpow A Adec op a G H1 m F1 H2); intros q Hq. +assert (F2: 1 <= q). + case (Zle_or_lt 0 q); intros HH. + case (Zle_lt_or_eq _ _ HH); auto with zarith. + intros HH1; generalize Hm; rewrite Hq; rewrite <- HH1; + auto with zarith. + assert (F2: 0 <= (- q) * e_order Adec a G); auto with zarith. + apply Zmult_le_0_compat; auto with zarith. + apply Zlt_le_weak; apply e_order_pos. + generalize F2; rewrite Zopp_mult_distr_l_reverse; + rewrite <- Hq; auto with zarith. +case (Zle_lt_or_eq _ _ F2); intros H3; subst; auto with zarith. +case (prime_dec q); intros Hq. + case (H q); auto with zarith. + rewrite Zmult_comm; rewrite Z_div_mult; auto with zarith. + apply gpow_e_order_is_e; auto. +case (Zdivide_div_prime_le_square _ H3 Hq); intros r (Hr1, (Hr2, Hr3)). +case (H _ Hr1); auto. + apply Zdivide_trans with (1 := Hr2). + apply Zdivide_factor_r. +case Hr2; intros q1 Hq1; subst. +assert (F3: 0 < r). + generalize (prime_ge_2 _ Hr1); auto with zarith. +rewrite <- Zmult_assoc; rewrite Zmult_comm; rewrite <- Zmult_assoc; + rewrite Zmult_comm; rewrite Z_div_mult; auto with zarith. +rewrite gpow_gpow; auto with zarith. + rewrite gpow_e_order_is_e; try rewrite gpow_e; auto. + apply Zmult_le_reg_r with r; auto with zarith. + apply Zlt_le_weak; apply e_order_pos. +apply Zmult_le_reg_r with r; auto with zarith. +Qed. diff --git a/coqprime-8.5/Coqprime/Euler.v b/coqprime-8.5/Coqprime/Euler.v new file mode 100644 index 000000000..06d92ce57 --- /dev/null +++ b/coqprime-8.5/Coqprime/Euler.v @@ -0,0 +1,88 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(************************************************************************ + + Definition of the Euler Totient function + +*************************************************************************) +Require Import ZArith. +Require Export Znumtheory. +Require Import Tactic. +Require Export ZSum. + +Open Scope Z_scope. + +Definition phi n := Zsum 1 (n - 1) (fun x => if rel_prime_dec x n then 1 else 0). + +Theorem phi_def_with_0: + forall n, 1< n -> phi n = Zsum 0 (n - 1) (fun x => if rel_prime_dec x n then 1 else 0). +intros n H; rewrite Zsum_S_left; auto with zarith. +case (rel_prime_dec 0 n); intros H2. +contradict H2; apply not_rel_prime_0; auto. +rewrite Zplus_0_l; auto. +Qed. + +Theorem phi_pos: forall n, 1 < n -> 0 < phi n. +intros n H; unfold phi. +case (Zle_lt_or_eq 2 n); auto with zarith; intros H1; subst. +rewrite Zsum_S_left; simpl; auto with zarith. +case (rel_prime_dec 1 n); intros H2. +apply Zlt_le_trans with (1 + 0); auto with zarith. +apply Zplus_le_compat_l. +pattern 0 at 1; replace 0 with ((1 + (n - 1) - 2) * 0); auto with zarith. +rewrite <- Zsum_c; auto with zarith. +apply Zsum_le; auto with zarith. +intros x H3; case (rel_prime_dec x n); auto with zarith. +case H2; apply rel_prime_1; auto with zarith. +rewrite Zsum_nn. +case (rel_prime_dec (2 - 1) 2); auto with zarith. +intros H1; contradict H1; apply rel_prime_1; auto with zarith. +Qed. + +Theorem phi_le_n_minus_1: forall n, 1 < n -> phi n <= n - 1. +intros n H; replace (n-1) with ((1 + (n - 1) - 1) * 1); auto with zarith. +rewrite <- Zsum_c; auto with zarith. +unfold phi; apply Zsum_le; auto with zarith. +intros x H1; case (rel_prime_dec x n); auto with zarith. +Qed. + +Theorem prime_phi_n_minus_1: forall n, prime n -> phi n = n - 1. +intros n H; replace (n-1) with ((1 + (n - 1) - 1) * 1); auto with zarith. +assert (Hu: 1 <= n - 1). +assert (2 <= n); auto with zarith. +apply prime_ge_2; auto. +rewrite <- Zsum_c; auto with zarith; unfold phi; apply Zsum_ext; auto. +intros x (H2, H3); case H; clear H; intros H H1. +generalize (H1 x); case (rel_prime_dec x n); auto with zarith. +intros H6 H7; contradict H6; apply H7; split; auto with zarith. +Qed. + +Theorem phi_n_minus_1_prime: forall n, 1 < n -> phi n = n - 1 -> prime n. +intros n H H1; case (prime_dec n); auto; intros H2. +assert (H3: phi n < n - 1); auto with zarith. +replace (n-1) with ((1 + (n - 1) - 1) * 1); auto with zarith. +assert (Hu: 1 <= n - 1); auto with zarith. +rewrite <- Zsum_c; auto with zarith; unfold phi; apply Zsum_lt; auto. +intros x _; case (rel_prime_dec x n); auto with zarith. +case not_prime_divide with n; auto. +intros x (H3, H4); exists x; repeat split; auto with zarith. +case (rel_prime_dec x n); auto with zarith. +intros H5; absurd (x = 1 \/ x = -1); auto with zarith. +case (Zis_gcd_unique x n x 1); auto. +apply Zis_gcd_intro; auto; exists 1; auto with zarith. +contradict H3; rewrite H1; auto with zarith. +Qed. + +Theorem phi_divide_prime: forall n, 1 < n -> (n - 1 | phi n) -> prime n. +intros n H1 H2; apply phi_n_minus_1_prime; auto. +apply Zle_antisym. +apply phi_le_n_minus_1; auto. +apply Zdivide_le; auto; auto with zarith. +apply phi_pos; auto. +Qed. diff --git a/coqprime-8.5/Coqprime/FGroup.v b/coqprime-8.5/Coqprime/FGroup.v new file mode 100644 index 000000000..a55710e7c --- /dev/null +++ b/coqprime-8.5/Coqprime/FGroup.v @@ -0,0 +1,123 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + FGroup.v + + Defintion and properties of finite groups + + Definition: FGroup + **********************************************************************) +Require Import List. +Require Import UList. +Require Import Tactic. +Require Import ZArith. + +Open Scope Z_scope. + +Set Implicit Arguments. + +(************************************** + A finite group is defined for an operation op + it has a support (s) + op operates inside the group (internal) + op is associative (assoc) + it has an element (e) that is neutral (e_is_zero_l e_is_zero_r) + it has an inverse operator (i) + the inverse operates inside the group (i_internal) + it gives an inverse (i_is_inverse_l is_is_inverse_r) + **************************************) + +Record FGroup (A: Set) (op: A -> A -> A): Set := mkGroup + {s : (list A); + unique_s: ulist s; + internal: forall a b, In a s -> In b s -> In (op a b) s; + assoc: forall a b c, In a s -> In b s -> In c s -> op a (op b c) = op (op a b) c; + e: A; + e_in_s: In e s; + e_is_zero_l: forall a, In a s -> op e a = a; + e_is_zero_r: forall a, In a s -> op a e = a; + i: A -> A; + i_internal: forall a, In a s -> In (i a) s; + i_is_inverse_l: forall a, (In a s) -> op (i a) a = e; + i_is_inverse_r: forall a, (In a s) -> op a (i a) = e +}. + +(************************************** + The order of a group is the lengh of the support + **************************************) + +Definition g_order (A: Set) (op: A -> A -> A) (g: FGroup op) := Z_of_nat (length g.(s)). + +Unset Implicit Arguments. + +Hint Resolve unique_s internal e_in_s e_is_zero_l e_is_zero_r i_internal + i_is_inverse_l i_is_inverse_r assoc. + + +Section FGroup. + +Variable A: Set. +Variable op: A -> A -> A. + +(************************************** + Some properties of a finite group + **************************************) + +Theorem g_cancel_l: forall (g : FGroup op), forall a b c, In a g.(s) -> In b g.(s) -> In c g.(s) -> op a b = op a c -> b = c. +intros g a b c H1 H2 H3 H4; apply trans_equal with (op g.(e) b); sauto. +replace (g.(e)) with (op (g.(i) a) a); sauto. +apply trans_equal with (op (i g a) (op a b)); sauto. +apply sym_equal; apply assoc with g; auto. +rewrite H4. +apply trans_equal with (op (op (i g a) a) c); sauto. +apply assoc with g; auto. +replace (op (g.(i) a) a) with g.(e); sauto. +Qed. + +Theorem g_cancel_r: forall (g : FGroup op), forall a b c, In a g.(s) -> In b g.(s) -> In c g.(s) -> op b a = op c a -> b = c. +intros g a b c H1 H2 H3 H4; apply trans_equal with (op b g.(e)); sauto. +replace (g.(e)) with (op a (g.(i) a)); sauto. +apply trans_equal with (op (op b a) (i g a)); sauto. +apply assoc with g; auto. +rewrite H4. +apply trans_equal with (op c (op a (i g a))); sauto. +apply sym_equal; apply assoc with g; sauto. +replace (op a (g.(i) a)) with g.(e); sauto. +Qed. + +Theorem e_unique: forall (g : FGroup op), forall e1, In e1 g.(s) -> (forall a, In a g.(s) -> op e1 a = a) -> e1 = g.(e). +intros g e1 He1 H2. +apply trans_equal with (op e1 g.(e)); sauto. +Qed. + +Theorem inv_op: forall (g: FGroup op) a b, In a g.(s) -> In b g.(s) -> g.(i) (op a b) = op (g.(i) b) (g.(i) a). +intros g a1 b1 H1 H2; apply g_cancel_l with (g := g) (a := op a1 b1); sauto. +repeat rewrite g.(assoc); sauto. +apply trans_equal with g.(e); sauto. +rewrite <- g.(assoc) with (a := a1); sauto. +rewrite g.(i_is_inverse_r); sauto. +rewrite g.(e_is_zero_r); sauto. +Qed. + +Theorem i_e: forall (g: FGroup op), g.(i) g.(e) = g.(e). +intro g; apply g_cancel_l with (g:= g) (a := g.(e)); sauto. +apply trans_equal with g.(e); sauto. +Qed. + +(************************************** + A group has at least one element + **************************************) + +Theorem g_order_pos: forall g: FGroup op, 0 < g_order g. +intro g; generalize g.(e_in_s); unfold g_order; case g.(s); simpl; auto with zarith. +Qed. + + + +End FGroup. diff --git a/coqprime-8.5/Coqprime/IGroup.v b/coqprime-8.5/Coqprime/IGroup.v new file mode 100644 index 000000000..11a73d414 --- /dev/null +++ b/coqprime-8.5/Coqprime/IGroup.v @@ -0,0 +1,253 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Igroup + + Build the group of the inversible elements for the operation + + Definition: ZpGroup + **********************************************************************) +Require Import ZArith. +Require Import Tactic. +Require Import Wf_nat. +Require Import UList. +Require Import ListAux. +Require Import FGroup. + +Open Scope Z_scope. + +Section IG. + +Variable A: Set. +Variable op: A -> A -> A. +Variable support: list A. +Variable e: A. + +Hypothesis A_dec: forall a b: A, {a = b} + {a <> b}. +Hypothesis support_ulist: ulist support. +Hypothesis e_in_support: In e support. +Hypothesis op_internal: forall a b, In a support -> In b support -> In (op a b) support. +Hypothesis op_assoc: forall a b c, In a support -> In b support -> In c support -> op a (op b c) = op (op a b) c. +Hypothesis e_is_zero_l: forall a, In a support -> op e a = a. +Hypothesis e_is_zero_r: forall a, In a support -> op a e = a. + +(************************************** + is_inv_aux tests if there is an inverse of a for op in l + **************************************) + +Fixpoint is_inv_aux (l: list A) (a: A) {struct l}: bool := + match l with nil => false | cons b l1 => + if (A_dec (op a b) e) then if (A_dec (op b a) e) then true else is_inv_aux l1 a else is_inv_aux l1 a + end. + +Theorem is_inv_aux_false: forall b l, (forall a, (In a l) -> op b a <> e \/ op a b <> e) -> is_inv_aux l b = false. +intros b l; elim l; simpl; auto. +intros a l1 Rec H; case (A_dec (op a b) e); case (A_dec (op b a) e); auto. +intros H1 H2; case (H a); auto; intros H3; case H3; auto. +Qed. + +(************************************** + is_inv tests if there is an inverse in support + **************************************) +Definition is_inv := is_inv_aux support. + +(************************************** + isupport_aux returns the sublist of inversible element of support + **************************************) + +Fixpoint isupport_aux (l: list A) : list A := + match l with nil => nil | cons a l1 => if is_inv a then a::isupport_aux l1 else isupport_aux l1 end. + +(************************************** + Some properties of isupport_aux + **************************************) + +Theorem isupport_aux_is_inv_true: forall l a, In a (isupport_aux l) -> is_inv a = true. +intros l a; elim l; simpl; auto. +intros b l1 H; case_eq (is_inv b); intros H1; simpl; auto. +intros [H2 | H2]; subst; auto. +Qed. + +Theorem isupport_aux_is_in: forall l a, is_inv a = true -> In a l -> In a (isupport_aux l). +intros l a; elim l; simpl; auto. +intros b l1 Rec H [H1 | H1]; subst. +rewrite H; auto with datatypes. +case (is_inv b); auto with datatypes. +Qed. + + +Theorem isupport_aux_not_in: + forall b l, (forall a, (In a support) -> op b a <> e \/ op a b <> e) -> ~ In b (isupport_aux l). +intros b l; elim l; simpl; simpl; auto. +intros a l1 H; case_eq (is_inv a); intros H1; simpl; auto. +intros H2 [H3 | H3]; subst. +contradict H1. +unfold is_inv; rewrite is_inv_aux_false; auto. +case H; auto; apply isupport_aux_is_in; auto. +Qed. + +Theorem isupport_aux_incl: forall l, incl (isupport_aux l) l. +intros l; elim l; simpl; auto with datatypes. +intros a l1 H1; case (is_inv a); auto with datatypes. +Qed. + +Theorem isupport_aux_ulist: forall l, ulist l -> ulist (isupport_aux l). +intros l; elim l; simpl; auto with datatypes. +intros a l1 H1 H2; case_eq (is_inv a); intros H3; auto with datatypes. +apply ulist_cons; auto with datatypes. +intros H4; apply (ulist_app_inv _ (a::nil) l1 a); auto with datatypes. +apply (isupport_aux_incl l1 a); auto. +apply H1; apply ulist_app_inv_r with (a:: nil); auto. +apply H1; apply ulist_app_inv_r with (a:: nil); auto. +Qed. + +(************************************** + isupport is the sublist of inversible element of support + **************************************) + +Definition isupport := isupport_aux support. + +(************************************** + Some properties of isupport + **************************************) + +Theorem isupport_is_inv_true: forall a, In a isupport -> is_inv a = true. +unfold isupport; intros a H; apply isupport_aux_is_inv_true with (1 := H). +Qed. + +Theorem isupport_is_in: forall a, is_inv a = true -> In a support -> In a isupport. +intros a H H1; unfold isupport; apply isupport_aux_is_in; auto. +Qed. + +Theorem isupport_incl: incl isupport support. +unfold isupport; apply isupport_aux_incl. +Qed. + +Theorem isupport_ulist: ulist isupport. +unfold isupport; apply isupport_aux_ulist. +apply support_ulist. +Qed. + +Theorem isupport_length: (length isupport <= length support)%nat. +apply ulist_incl_length. +apply isupport_ulist. +apply isupport_incl. +Qed. + +Theorem isupport_length_strict: + forall b, (In b support) -> (forall a, (In a support) -> op b a <> e \/ op a b <> e) -> + (length isupport < length support)%nat. +intros b H H1; apply ulist_incl_length_strict. +apply isupport_ulist. +apply isupport_incl. +intros H2; case (isupport_aux_not_in b support); auto. +Qed. + +Fixpoint inv_aux (l: list A) (a: A) {struct l}: A := + match l with nil => e | cons b l1 => + if A_dec (op a b) e then if (A_dec (op b a) e) then b else inv_aux l1 a else inv_aux l1 a + end. + +Theorem inv_aux_prop_r: forall l a, is_inv_aux l a = true -> op a (inv_aux l a) = e. +intros l a; elim l; simpl. +intros; discriminate. +intros b l1 H1; case (A_dec (op a b) e); case (A_dec (op b a) e); intros H3 H4; subst; auto. +Qed. + +Theorem inv_aux_prop_l: forall l a, is_inv_aux l a = true -> op (inv_aux l a) a = e. +intros l a; elim l; simpl. +intros; discriminate. +intros b l1 H1; case (A_dec (op a b) e); case (A_dec (op b a) e); intros H3 H4; subst; auto. +Qed. + +Theorem inv_aux_inv: forall l a b, op a b = e -> op b a = e -> (In a l) -> is_inv_aux l b = true. +intros l a b; elim l; simpl. +intros _ _ H; case H. +intros c l1 Rec H H0 H1; case H1; clear H1; intros H1; subst; rewrite H. +case (A_dec (op b a) e); case (A_dec e e); auto. +intros H1 H2; contradict H2; rewrite H0; auto. +case (A_dec (op b c) e); case (A_dec (op c b) e); auto. +Qed. + +Theorem inv_aux_in: forall l a, In (inv_aux l a) l \/ inv_aux l a = e. +intros l a; elim l; simpl; auto. +intros b l1; case (A_dec (op a b) e); case (A_dec (op b a) e); intros _ _ [H1 | H1]; auto. +Qed. + +(************************************** + The inverse function + **************************************) + +Definition inv := inv_aux support. + +(************************************** + Some properties of inv + **************************************) + +Theorem inv_prop_r: forall a, In a isupport -> op a (inv a) = e. +intros a H; unfold inv; apply inv_aux_prop_r with (l := support). +change (is_inv a = true). +apply isupport_is_inv_true; auto. +Qed. + +Theorem inv_prop_l: forall a, In a isupport -> op (inv a) a = e. +intros a H; unfold inv; apply inv_aux_prop_l with (l := support). +change (is_inv a = true). +apply isupport_is_inv_true; auto. +Qed. + +Theorem is_inv_true: forall a b, op b a = e -> op a b = e -> (In a support) -> is_inv b = true. +intros a b H H1 H2; unfold is_inv; apply inv_aux_inv with a; auto. +Qed. + +Theorem is_inv_false: forall b, (forall a, (In a support) -> op b a <> e \/ op a b <> e) -> is_inv b = false. +intros b H; unfold is_inv; apply is_inv_aux_false; auto. +Qed. + +Theorem inv_internal: forall a, In a isupport -> In (inv a) isupport. +intros a H; apply isupport_is_in. +apply is_inv_true with a; auto. +apply inv_prop_l; auto. +apply inv_prop_r; auto. +apply (isupport_incl a); auto. +case (inv_aux_in support a); unfold inv; auto. +intros H1; rewrite H1; apply e_in_support; auto with zarith. +Qed. + +(************************************** + We are now ready to build our group + **************************************) + +Definition IGroup : (FGroup op). +generalize (fun x=> (isupport_incl x)); intros Hx. +apply mkGroup with (s := isupport) (e := e) (i := inv); auto. +apply isupport_ulist. +intros a b H H1. +assert (Haii: In (inv a) isupport); try apply inv_internal; auto. +assert (Hbii: In (inv b) isupport); try apply inv_internal; auto. +apply isupport_is_in; auto. +apply is_inv_true with (op (inv b) (inv a)); auto. +rewrite op_assoc; auto. +rewrite <- (op_assoc a); auto. +rewrite inv_prop_r; auto. +rewrite e_is_zero_r; auto. +apply inv_prop_r; auto. +rewrite <- (op_assoc (inv b)); auto. +rewrite (op_assoc (inv a)); auto. +rewrite inv_prop_l; auto. +rewrite e_is_zero_l; auto. +apply inv_prop_l; auto. +apply isupport_is_in; auto. +apply is_inv_true with e; auto. +intros a H; apply inv_internal; auto. +intros; apply inv_prop_l; auto. +intros; apply inv_prop_r; auto. +Defined. + +End IG. diff --git a/coqprime-8.5/Coqprime/Iterator.v b/coqprime-8.5/Coqprime/Iterator.v new file mode 100644 index 000000000..96d3e5655 --- /dev/null +++ b/coqprime-8.5/Coqprime/Iterator.v @@ -0,0 +1,180 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Export List. +Require Export Permutation. +Require Import Arith. + +Section Iterator. +Variables A B : Set. +Variable zero : B. +Variable f : A -> B. +Variable g : B -> B -> B. +Hypothesis g_zero : forall a, g a zero = a. +Hypothesis g_trans : forall a b c, g a (g b c) = g (g a b) c. +Hypothesis g_sym : forall a b, g a b = g b a. + +Definition iter := fold_right (fun a r => g (f a) r) zero. +Hint Unfold iter . + +Theorem iter_app: forall l1 l2, iter (app l1 l2) = g (iter l1) (iter l2). +intros l1; elim l1; simpl; auto. +intros l2; rewrite g_sym; auto. +intros a l H l2; rewrite H. +rewrite g_trans; auto. +Qed. + +Theorem iter_permutation: forall l1 l2, permutation l1 l2 -> iter l1 = iter l2. +intros l1 l2 H; elim H; simpl; auto; clear H l1 l2. +intros a l1 l2 H1 H2; apply f_equal2 with ( f := g ); auto. +intros a b l; (repeat rewrite g_trans). +apply f_equal2 with ( f := g ); auto. +intros l1 l2 l3 H H0 H1 H2; apply trans_equal with ( 1 := H0 ); auto. +Qed. + +Lemma iter_inv: + forall P l, + P zero -> + (forall a b, P a -> P b -> P (g a b)) -> + (forall x, In x l -> P (f x)) -> P (iter l). +intros P l H H0; (elim l; simpl; auto). +Qed. +Variable next : A -> A. + +Fixpoint progression (m : A) (n : nat) {struct n} : list A := + match n with 0 => nil + | S n1 => cons m (progression (next m) n1) end. + +Fixpoint next_n (c : A) (n : nat) {struct n} : A := + match n with 0 => c | S n1 => next_n (next c) n1 end. + +Theorem progression_app: + forall a b n m, + le m n -> + b = next_n a m -> + progression a n = app (progression a m) (progression b (n - m)). +intros a b n m; generalize a b n; clear a b n; elim m; clear m; simpl. +intros a b n H H0; apply f_equal2 with ( f := progression ); auto with arith. +intros m H a b n; case n; simpl; clear n. +intros H1; absurd (0 < 1 + m); auto with arith. +intros n H0 H1; apply f_equal2 with ( f := @cons A ); auto with arith. +Qed. + +Let iter_progression := fun m n => iter (progression m n). + +Theorem iter_progression_app: + forall a b n m, + le m n -> + b = next_n a m -> + iter (progression a n) = + g (iter (progression a m)) (iter (progression b (n - m))). +intros a b n m H H0; unfold iter_progression; rewrite (progression_app a b n m); + (try apply iter_app); auto. +Qed. + +Theorem length_progression: forall z n, length (progression z n) = n. +intros z n; generalize z; elim n; simpl; auto. +Qed. + +End Iterator. +Implicit Arguments iter [A B]. +Implicit Arguments progression [A]. +Implicit Arguments next_n [A]. +Hint Unfold iter . +Hint Unfold progression . +Hint Unfold next_n . + +Theorem iter_ext: + forall (A B : Set) zero (f1 : A -> B) f2 g l, + (forall a, In a l -> f1 a = f2 a) -> iter zero f1 g l = iter zero f2 g l. +intros A B zero f1 f2 g l; elim l; simpl; auto. +intros a l0 H H0; apply f_equal2 with ( f := g ); auto. +Qed. + +Theorem iter_map: + forall (A B C : Set) zero (f : B -> C) g (k : A -> B) l, + iter zero f g (map k l) = iter zero (fun x => f (k x)) g l. +intros A B C zero f g k l; elim l; simpl; auto. +intros; apply f_equal2 with ( f := g ); auto with arith. +Qed. + +Theorem iter_comp: + forall (A B : Set) zero (f1 f2 : A -> B) g l, + (forall a, g a zero = a) -> + (forall a b c, g a (g b c) = g (g a b) c) -> + (forall a b, g a b = g b a) -> + g (iter zero f1 g l) (iter zero f2 g l) = + iter zero (fun x => g (f1 x) (f2 x)) g l. +intros A B zero f1 f2 g l g_zero g_trans g_sym; elim l; simpl; auto. +intros a l0 H; rewrite <- H; (repeat rewrite <- g_trans). +apply f_equal2 with ( f := g ); auto. +(repeat rewrite g_trans); apply f_equal2 with ( f := g ); auto. +Qed. + +Theorem iter_com: + forall (A B : Set) zero (f : A -> A -> B) g l1 l2, + (forall a, g a zero = a) -> + (forall a b c, g a (g b c) = g (g a b) c) -> + (forall a b, g a b = g b a) -> + iter zero (fun x => iter zero (fun y => f x y) g l1) g l2 = + iter zero (fun y => iter zero (fun x => f x y) g l2) g l1. +intros A B zero f g l1 l2 H H0 H1; generalize l2; elim l1; simpl; auto; + clear l1 l2. +intros l2; elim l2; simpl; auto with arith. +intros; rewrite H1; rewrite H; auto with arith. +intros a l1 H2 l2; case l2; clear l2; simpl; auto. +elim l1; simpl; auto with arith. +intros; rewrite H1; rewrite H; auto with arith. +intros b l2. +rewrite <- (iter_comp + _ _ zero (fun x => f x a) + (fun x => iter zero (fun (y : A) => f x y) g l1)); auto with arith. +rewrite <- (iter_comp + _ _ zero (fun y => f b y) + (fun y => iter zero (fun (x : A) => f x y) g l2)); auto with arith. +(repeat rewrite H0); auto. +apply f_equal2 with ( f := g ); auto. +(repeat rewrite <- H0); auto. +apply f_equal2 with ( f := g ); auto. +Qed. + +Theorem iter_comp_const: + forall (A B : Set) zero (f : A -> B) g k l, + k zero = zero -> + (forall a b, k (g a b) = g (k a) (k b)) -> + k (iter zero f g l) = iter zero (fun x => k (f x)) g l. +intros A B zero f g k l H H0; elim l; simpl; auto. +intros a l0 H1; rewrite H0; apply f_equal2 with ( f := g ); auto. +Qed. + +Lemma next_n_S: forall n m, next_n S n m = plus n m. +intros n m; generalize n; elim m; clear n m; simpl; auto with arith. +intros m H n; case n; simpl; auto with arith. +rewrite H; auto with arith. +intros n1; rewrite H; simpl; auto with arith. +Qed. + +Theorem progression_S_le_init: + forall n m p, In p (progression S n m) -> le n p. +intros n m; generalize n; elim m; clear n m; simpl; auto. +intros; contradiction. +intros m H n p [H1|H1]; auto with arith. +subst n; auto. +apply le_S_n; auto with arith. +Qed. + +Theorem progression_S_le_end: + forall n m p, In p (progression S n m) -> lt p (n + m). +intros n m; generalize n; elim m; clear n m; simpl; auto. +intros; contradiction. +intros m H n p [H1|H1]; auto with arith. +subst n; auto with arith. +rewrite <- plus_n_Sm; auto with arith. +rewrite <- plus_n_Sm; auto with arith. +generalize (H (S n) p); auto with arith. +Qed. diff --git a/coqprime-8.5/Coqprime/Lagrange.v b/coqprime-8.5/Coqprime/Lagrange.v new file mode 100644 index 000000000..b35460bad --- /dev/null +++ b/coqprime-8.5/Coqprime/Lagrange.v @@ -0,0 +1,179 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Lagrange.v + + Proof of Lagrange theorem: + the oder of a subgroup divides the order of a group + + Definition: lagrange + **********************************************************************) +Require Import List. +Require Import UList. +Require Import ListAux. +Require Import ZArith Znumtheory. +Require Import NatAux. +Require Import FGroup. + +Open Scope Z_scope. + +Section Lagrange. + +Variable A: Set. + +Variable A_dec: forall a b: A, {a = b} + {~ a = b}. + +Variable op: A -> A -> A. + +Variable G: (FGroup op). + +Variable H:(FGroup op). + +Hypothesis G_in_H: (incl G.(s) H.(s)). + +(************************************** + A group and a subgroup have the same neutral element + **************************************) + +Theorem same_e_for_H_and_G: H.(e) = G.(e). +apply trans_equal with (op H.(e) H.(e)); sauto. +apply trans_equal with (op H.(e) (op G.(e) (H.(i) G.(e)))); sauto. +eq_tac; sauto. +apply trans_equal with (op G.(e) (op G.(e) (H.(i) G.(e)))); sauto. +repeat rewrite H.(assoc); sauto. +eq_tac; sauto. +apply trans_equal with G.(e); sauto. +apply trans_equal with (op G.(e) H.(e)); sauto. +eq_tac; sauto. +Qed. + +(************************************** + The proof works like this. + If G = {e, g1, g2, g3, .., gn} and {e, h1, h2, h3, ..., hm} + we construct the list mkGH + {e, g1, g2, g3, ...., gn + hi*e, hi * g1, hi * g2, ..., hi * gn if hi does not appear before + .... + hk*e, hk * g1, hk * g2, ..., hk * gn if hk does not appear before + } + that contains all the element of H. + We show that this list does not contain double (ulist). + **************************************) + +Fixpoint mkList (base l: (list A)) { struct l} : (list A) := + match l with + nil => nil + | cons a l1 => let r1 := mkList base l1 in + if (In_dec A_dec a r1) then r1 else + (map (op a) base) ++ r1 + end. + +Definition mkGH := mkList G.(s) H.(s). + +Theorem mkGH_length: divide (length G.(s)) (length mkGH). +unfold mkGH; elim H.(s); simpl. +exists 0%nat; auto with arith. +intros a l1 (c, H1); case (In_dec A_dec a (mkList G.(s) l1)); intros H2. +exists c; auto. +exists (1 + c)%nat; rewrite ListAux.length_app; rewrite ListAux.length_map; rewrite H1; ring. +Qed. + +Theorem mkGH_incl: incl H.(s) mkGH. +assert (H1: forall l, incl l H.(s) -> incl l (mkList G.(s) l)). +intros l; elim l; simpl; auto with datatypes. +intros a l1 H1 H2. +case (In_dec A_dec a (mkList (s G) l1)); auto with datatypes. +intros H3; assert (H4: incl l1 (mkList (s G) l1)). +apply H1; auto with datatypes. +intros b H4; apply H2; auto with datatypes. +intros b; simpl; intros [H5 | H5]; subst; auto. +intros _ b; simpl; intros [H3 | H3]; subst; auto. +apply in_or_app; left. +cut (In H.(e) G.(s)). +elim (s G); simpl; auto. +intros c l2 Hl2 [H3 | H3]; subst; sauto. +assert (In b H.(s)); sauto. +apply (H2 b); auto with datatypes. +rewrite same_e_for_H_and_G; sauto. +apply in_or_app; right. +apply H1; auto with datatypes. +apply incl_tran with (2:= H2); auto with datatypes. +unfold mkGH; apply H1; auto with datatypes. +Qed. + +Theorem incl_mkGH: incl mkGH H.(s). +assert (H1: forall l, incl l H.(s) -> incl (mkList G.(s) l) H.(s)). +intros l; elim l; simpl; auto with datatypes. +intros a l1 H1 H2. +case (In_dec A_dec a (mkList (s G) l1)); intros H3; auto with datatypes. +apply H1; apply incl_tran with (2 := H2); auto with datatypes. +apply incl_app. +intros b H4. +case ListAux.in_map_inv with (1:= H4); auto. +intros c (Hc1, Hc2); subst; sauto. +apply internal; auto with datatypes. +apply H1; apply incl_tran with (2 := H2); auto with datatypes. +unfold mkGH; apply H1; auto with datatypes. +Qed. + +Theorem ulist_mkGH: ulist mkGH. +assert (H1: forall l, incl l H.(s) -> ulist (mkList G.(s) l)). +intros l; elim l; simpl; auto with datatypes. +intros a l1 H1 H2. +case (In_dec A_dec a (mkList (s G) l1)); intros H3; auto with datatypes. +apply H1; apply incl_tran with (2 := H2); auto with datatypes. +apply ulist_app; auto. +apply ulist_map; sauto. +intros x y H4 H5 H6; apply g_cancel_l with (g:= H) (a := a); sauto. +apply H2; auto with datatypes. +apply H1; apply incl_tran with (2 := H2); auto with datatypes. +intros b H4 H5. +case ListAux.in_map_inv with (1:= H4); auto. +intros c (Hc, Hc1); subst. +assert (H6: forall l a b, In b G.(s) -> incl l H.(s) -> In a (mkList G.(s) l) -> In (op a b) (mkList G.(s) l)). +intros ll u v; elim ll; simpl; auto with datatypes. +intros w ll1 T0 T1 T2. +case (In_dec A_dec w (mkList (s G) ll1)); intros T3 T4; auto with datatypes. +apply T0; auto; apply incl_tran with (2:= T2); auto with datatypes. +case in_app_or with (1 := T4); intros T5; auto with datatypes. +apply in_or_app; left. +case ListAux.in_map_inv with (1:= T5); auto. +intros z (Hz1, Hz2); subst. +replace (op (op w z) v) with (op w (op z v)); sauto. +apply in_map; sauto. +apply assoc with H; auto with datatypes. +apply in_or_app; right; auto with datatypes. +apply T0; try apply incl_tran with (2 := T2); auto with datatypes. +case H3; replace a with (op (op a c) (G.(i) c)); auto with datatypes. +apply H6; sauto. +apply incl_tran with (2 := H2); auto with datatypes. +apply trans_equal with (op a (op c (G.(i) c))); sauto. +apply sym_equal; apply assoc with H; auto with datatypes. +replace (op c (G.(i) c)) with (G.(e)); sauto. +rewrite <- same_e_for_H_and_G. +assert (In a H.(s)); sauto; apply (H2 a); auto with datatypes. +unfold mkGH; apply H1; auto with datatypes. +Qed. + +(************************************** + Lagrange theorem + **************************************) + +Theorem lagrange: (g_order G | (g_order H)). +unfold g_order. +rewrite Permutation.permutation_length with (l := H.(s)) (m:= mkGH). +case mkGH_length; intros x H1; exists (Z_of_nat x). +rewrite H1; rewrite Zmult_comm; apply inj_mult. +apply ulist_incl2_permutation; auto. +apply ulist_mkGH. +apply mkGH_incl. +apply incl_mkGH. +Qed. + +End Lagrange. diff --git a/coqprime-8.5/Coqprime/ListAux.v b/coqprime-8.5/Coqprime/ListAux.v new file mode 100644 index 000000000..c3c9602bd --- /dev/null +++ b/coqprime-8.5/Coqprime/ListAux.v @@ -0,0 +1,271 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Aux.v + + Auxillary functions & Theorems + **********************************************************************) +Require Export List. +Require Export Arith. +Require Export Tactic. +Require Import Inverse_Image. +Require Import Wf_nat. + +(************************************** + Some properties on list operators: app, map,... +**************************************) + +Section List. +Variables (A : Set) (B : Set) (C : Set). +Variable f : A -> B. + +(************************************** + An induction theorem for list based on length +**************************************) + +Theorem list_length_ind: + forall (P : list A -> Prop), + (forall (l1 : list A), + (forall (l2 : list A), length l2 < length l1 -> P l2) -> P l1) -> + forall (l : list A), P l. +intros P H l; + apply well_founded_ind with ( R := fun (x y : list A) => length x < length y ); + auto. +apply wf_inverse_image with ( R := lt ); auto. +apply lt_wf. +Qed. + +Definition list_length_induction: + forall (P : list A -> Set), + (forall (l1 : list A), + (forall (l2 : list A), length l2 < length l1 -> P l2) -> P l1) -> + forall (l : list A), P l. +intros P H l; + apply well_founded_induction + with ( R := fun (x y : list A) => length x < length y ); auto. +apply wf_inverse_image with ( R := lt ); auto. +apply lt_wf. +Qed. + +Theorem in_ex_app: + forall (a : A) (l : list A), + In a l -> (exists l1 : list A , exists l2 : list A , l = l1 ++ (a :: l2) ). +intros a l; elim l; clear l; simpl; auto. +intros H; case H. +intros a1 l H [H1|H1]; auto. +exists (nil (A:=A)); exists l; simpl; auto. +rewrite H1; auto. +case H; auto; intros l1 [l2 Hl2]; exists (a1 :: l1); exists l2; simpl; auto. +rewrite Hl2; auto. +Qed. + +(************************************** + Properties on app +**************************************) + +Theorem length_app: + forall (l1 l2 : list A), length (l1 ++ l2) = length l1 + length l2. +intros l1; elim l1; simpl; auto. +Qed. + +Theorem app_inv_head: + forall (l1 l2 l3 : list A), l1 ++ l2 = l1 ++ l3 -> l2 = l3. +intros l1; elim l1; simpl; auto. +intros a l H l2 l3 H0; apply H; injection H0; auto. +Qed. + +Theorem app_inv_tail: + forall (l1 l2 l3 : list A), l2 ++ l1 = l3 ++ l1 -> l2 = l3. +intros l1 l2; generalize l1; elim l2; clear l1 l2; simpl; auto. +intros l1 l3; case l3; auto. +intros b l H; absurd (length ((b :: l) ++ l1) <= length l1). +simpl; rewrite length_app; auto with arith. +rewrite <- H; auto with arith. +intros a l H l1 l3; case l3. +simpl; intros H1; absurd (length (a :: (l ++ l1)) <= length l1). +simpl; rewrite length_app; auto with arith. +rewrite H1; auto with arith. +simpl; intros b l0 H0; injection H0. +intros H1 H2; rewrite H2, (H _ _ H1); auto. +Qed. + +Theorem app_inv_app: + forall l1 l2 l3 l4 a, + l1 ++ l2 = l3 ++ (a :: l4) -> + (exists l5 : list A , l1 = l3 ++ (a :: l5) ) \/ + (exists l5 , l2 = l5 ++ (a :: l4) ). +intros l1; elim l1; simpl; auto. +intros l2 l3 l4 a H; right; exists l3; auto. +intros a l H l2 l3 l4 a0; case l3; simpl. +intros H0; left; exists l; injection H0; intros; subst; auto. +intros b l0 H0; case (H l2 l0 l4 a0); auto. +injection H0; auto. +intros [l5 H1]. +left; exists l5; injection H0; intros; subst; auto. +Qed. + +Theorem app_inv_app2: + forall l1 l2 l3 l4 a b, + l1 ++ l2 = l3 ++ (a :: (b :: l4)) -> + (exists l5 : list A , l1 = l3 ++ (a :: (b :: l5)) ) \/ + ((exists l5 , l2 = l5 ++ (a :: (b :: l4)) ) \/ + l1 = l3 ++ (a :: nil) /\ l2 = b :: l4). +intros l1; elim l1; simpl; auto. +intros l2 l3 l4 a b H; right; left; exists l3; auto. +intros a l H l2 l3 l4 a0 b; case l3; simpl. +case l; simpl. +intros H0; right; right; injection H0; split; auto. +rewrite H2; auto. +intros b0 l0 H0; left; exists l0; injection H0; intros; subst; auto. +intros b0 l0 H0; case (H l2 l0 l4 a0 b); auto. +injection H0; auto. +intros [l5 HH1]; left; exists l5; injection H0; intros; subst; auto. +intros [H1|[H1 H2]]; auto. +right; right; split; auto; injection H0; intros; subst; auto. +Qed. + +Theorem same_length_ex: + forall (a : A) l1 l2 l3, + length (l1 ++ (a :: l2)) = length l3 -> + (exists l4 , + exists l5 , + exists b : B , + length l1 = length l4 /\ (length l2 = length l5 /\ l3 = l4 ++ (b :: l5)) ). +intros a l1; elim l1; simpl; auto. +intros l2 l3; case l3; simpl; (try (intros; discriminate)). +intros b l H; exists (nil (A:=B)); exists l; exists b; (repeat (split; auto)). +intros a0 l H l2 l3; case l3; simpl; (try (intros; discriminate)). +intros b l0 H0. +case (H l2 l0); auto. +intros l4 [l5 [b1 [HH1 [HH2 HH3]]]]. +exists (b :: l4); exists l5; exists b1; (repeat (simpl; split; auto)). +rewrite HH3; auto. +Qed. + +(************************************** + Properties on map +**************************************) + +Theorem in_map_inv: + forall (b : B) (l : list A), + In b (map f l) -> (exists a : A , In a l /\ b = f a ). +intros b l; elim l; simpl; auto. +intros tmp; case tmp. +intros a0 l0 H [H1|H1]; auto. +exists a0; auto. +case (H H1); intros a1 [H2 H3]; exists a1; auto. +Qed. + +Theorem in_map_fst_inv: + forall a (l : list (B * C)), + In a (map (fst (B:=_)) l) -> (exists c , In (a, c) l ). +intros a l; elim l; simpl; auto. +intros H; case H. +intros a0 l0 H [H0|H0]; auto. +exists (snd a0); left; rewrite <- H0; case a0; simpl; auto. +case H; auto; intros l1 Hl1; exists l1; auto. +Qed. + +Theorem length_map: forall l, length (map f l) = length l. +intros l; elim l; simpl; auto. +Qed. + +Theorem map_app: forall l1 l2, map f (l1 ++ l2) = map f l1 ++ map f l2. +intros l; elim l; simpl; auto. +intros a l0 H l2; rewrite H; auto. +Qed. + +Theorem map_length_decompose: + forall l1 l2 l3 l4, + length l1 = length l2 -> + map f (app l1 l3) = app l2 l4 -> map f l1 = l2 /\ map f l3 = l4. +intros l1; elim l1; simpl; auto; clear l1. +intros l2; case l2; simpl; auto. +intros; discriminate. +intros a l1 Rec l2; case l2; simpl; clear l2; auto. +intros; discriminate. +intros b l2 l3 l4 H1 H2. +injection H2; clear H2; intros H2 H3. +case (Rec l2 l3 l4); auto. +intros H4 H5; split; auto. +subst; auto. +Qed. + +(************************************** + Properties of flat_map +**************************************) + +Theorem in_flat_map: + forall (l : list B) (f : B -> list C) a b, + In a (f b) -> In b l -> In a (flat_map f l). +intros l g; elim l; simpl; auto. +intros a l0 H a0 b H0 [H1|H1]; apply in_or_app; auto. +left; rewrite H1; auto. +right; apply H with ( b := b ); auto. +Qed. + +Theorem in_flat_map_ex: + forall (l : list B) (f : B -> list C) a, + In a (flat_map f l) -> (exists b , In b l /\ In a (f b) ). +intros l g; elim l; simpl; auto. +intros a H; case H. +intros a l0 H a0 H0; case in_app_or with ( 1 := H0 ); simpl; auto. +intros H1; exists a; auto. +intros H1; case H with ( 1 := H1 ). +intros b [H2 H3]; exists b; simpl; auto. +Qed. + +(************************************** + Properties of fold_left +**************************************) + +Theorem fold_left_invol: + forall (f: A -> B -> A) (P: A -> Prop) l a, + P a -> (forall x y, P x -> P (f x y)) -> P (fold_left f l a). +intros f1 P l; elim l; simpl; auto. +Qed. + +Theorem fold_left_invol_in: + forall (f: A -> B -> A) (P: A -> Prop) l a b, + In b l -> (forall x, P (f x b)) -> (forall x y, P x -> P (f x y)) -> + P (fold_left f l a). +intros f1 P l; elim l; simpl; auto. +intros a1 b HH; case HH. +intros a1 l1 Rec a2 b [V|V] V1 V2; subst; auto. +apply fold_left_invol; auto. +apply Rec with (b := b); auto. +Qed. + +End List. + + +(************************************** + Propertie of list_prod +**************************************) + +Theorem length_list_prod: + forall (A : Set) (l1 l2 : list A), + length (list_prod l1 l2) = length l1 * length l2. +intros A l1 l2; elim l1; simpl; auto. +intros a l H; rewrite length_app; rewrite length_map; rewrite H; auto. +Qed. + +Theorem in_list_prod_inv: + forall (A B : Set) a l1 l2, + In a (list_prod l1 l2) -> + (exists b : A , exists c : B , a = (b, c) /\ (In b l1 /\ In c l2) ). +intros A B a l1 l2; elim l1; simpl; auto; clear l1. +intros H; case H. +intros a1 l1 H1 H2. +case in_app_or with ( 1 := H2 ); intros H3; auto. +case in_map_inv with ( 1 := H3 ); intros b1 [Hb1 Hb2]; auto. +exists a1; exists b1; split; auto. +case H1; auto; intros b1 [c1 [Hb1 [Hb2 Hb3]]]. +exists b1; exists c1; split; auto. +Qed. diff --git a/coqprime-8.5/Coqprime/LucasLehmer.v b/coqprime-8.5/Coqprime/LucasLehmer.v new file mode 100644 index 000000000..a0e3b8e46 --- /dev/null +++ b/coqprime-8.5/Coqprime/LucasLehmer.v @@ -0,0 +1,597 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + LucasLehamer.v + + Build the sequence for the primality test of Mersenne numbers + + Definition: LucasLehmer + **********************************************************************) +Require Import ZArith. +Require Import ZCAux. +Require Import Tactic. +Require Import Wf_nat. +Require Import NatAux. +Require Import UList. +Require Import ListAux. +Require Import FGroup. +Require Import EGroup. +Require Import PGroup. +Require Import IGroup. + +Open Scope Z_scope. + +(************************************** + The seeds of the serie + **************************************) + +Definition w := (2, 1). + +Definition v := (2, -1). + +Theorem w_plus_v: pplus w v = (4, 0). +simpl; auto. +Qed. + +Theorem w_mult_v : pmult w v = (1, 0). +simpl; auto. +Qed. + +(************************************** + Definition of the power function for pairs p^n + **************************************) + +Definition ppow p n := match n with Zpos q => iter_pos _ (pmult p) (1, 0) q | _ => (1, 0) end. + +(************************************** + Some properties of ppow + **************************************) + +Theorem ppow_0: forall n, ppow n 0 = (1, 0). +simpl; auto. +Qed. + +Theorem ppow_1: forall n, ppow (1, 0) n = (1, 0). +intros n; case n; simpl; auto. +intros p; apply iter_pos_invariant with (Inv := fun x => x = (1, 0)); auto. +intros x H; rewrite H; auto. +Qed. + +Theorem ppow_op: forall a b p, iter_pos _ (pmult a) b p = pmult (iter_pos _ (pmult a) (1, 0) p) b. +intros a b p; generalize b; elim p; simpl; auto; clear b p. +intros p Rec b. +rewrite (Rec b). +try rewrite (fun x y => Rec (pmult x y)); try rewrite (fun x y => Rec (iter_pos _ x y p)); auto. +repeat rewrite pmult_assoc; auto. +intros p Rec b. +rewrite (Rec b); try rewrite (fun x y => Rec (pmult x y)); try rewrite (fun x y => Rec (iter_pos _ x y p)); auto. +repeat rewrite pmult_assoc; auto. +intros b; rewrite pmult_1_r; auto. +Qed. + +Theorem ppow_add: forall n m p, 0 <= m -> 0 <= p -> ppow n (m + p) = pmult (ppow n m) (ppow n p). +intros n m; case m; clear m. +intros p _ _; rewrite ppow_0; rewrite pmult_1_l; auto. +2: intros p m H; contradict H; auto with zarith. +intros p1 m _; case m. +intros _; rewrite Zplus_0_r; simpl; apply sym_equal; apply pmult_1_r. +2: intros p2 H; contradict H; auto with zarith. +intros p2 _; simpl. +rewrite iter_pos_plus. +rewrite ppow_op; auto. +Qed. + +Theorem ppow_ppow: forall n m p, 0 <= n -> 0 <= m -> ppow p (n * m ) = ppow (ppow p n) m. +intros n m; case n. +intros p _ Hm; rewrite Zmult_0_l. +rewrite ppow_0; apply sym_equal; apply ppow_1. +2: intros p p1 H; contradict H; auto with zarith. +intros p1 p _; case m; simpl; auto. +intros p2 _; pattern p2; apply Pind; simpl; auto. +rewrite Pmult_1_r; rewrite pmult_1_r; auto. +intros p3 Rec; rewrite Pplus_one_succ_r; rewrite Pmult_plus_distr_l. +rewrite Pmult_1_r. +simpl; repeat rewrite iter_pos_plus; simpl. +rewrite pmult_1_r. +rewrite ppow_op; try rewrite Rec; auto. +apply sym_equal; apply ppow_op; auto. +Qed. + + +Theorem ppow_mult: forall n m p, 0 <= n -> ppow (pmult m p) n = pmult (ppow m n) (ppow p n). +intros n m p; case n; simpl; auto. +intros p1 _; pattern p1; apply Pind; simpl; auto. +repeat rewrite pmult_1_r; auto. +intros p3 Rec; rewrite Pplus_one_succ_r. +repeat rewrite iter_pos_plus; simpl. +repeat rewrite (fun x y z => ppow_op x (pmult y z)) ; auto. +rewrite Rec. +repeat rewrite pmult_1_r; auto. +repeat rewrite <- pmult_assoc; try eq_tac; auto. +rewrite (fun x y => pmult_comm (iter_pos _ x y p3) p); auto. +rewrite (pmult_assoc m); try apply pmult_comm; auto. +Qed. + +(************************************** + We can now define our series of pairs s + **************************************) + +Definition s n := pplus (ppow w (2 ^ n)) (ppow v (2 ^ n)). + +(************************************** + Some properties of s + **************************************) + +Theorem s0 : s 0 = (4, 0). +simpl; auto. +Qed. + +Theorem sn_aux: forall n, 0 <= n -> s (n+1) = (pplus (pmult (s n) (s n)) (-2, 0)). +intros n Hn. +assert (Hu: 0 <= 2 ^n); auto with zarith. +set (y := (fst (s n) * fst (s n) - 2, 0)). +unfold s; simpl; rewrite Zpower_exp; auto with zarith. +rewrite Zpower_1_r; rewrite ppow_ppow; auto with zarith. +repeat rewrite pplus_pmult_dist_r || rewrite pplus_pmult_dist_l. +repeat rewrite <- pplus_assoc. +eq_tac; auto. +pattern 2 at 2; replace 2 with (1 + 1); auto with zarith. +rewrite ppow_add; auto with zarith; simpl. +rewrite pmult_1_r; auto. +rewrite Zmult_comm; rewrite ppow_ppow; simpl; auto with zarith. +repeat rewrite <- ppow_mult; auto with zarith. +rewrite (pmult_comm v w); rewrite w_mult_v. +rewrite ppow_1. +repeat rewrite tpower_1. +rewrite pplus_comm; repeat rewrite <- pplus_assoc; +rewrite pplus_comm; repeat rewrite <- pplus_assoc. +simpl; case (ppow (7, -4) (2 ^n)); simpl; intros z1 z2; eq_tac; auto with zarith. +Qed. + +Theorem sn_snd: forall n, snd (s n) = 0. +intros n; case n; simpl; auto. +intros p; pattern p; apply Pind; auto. +intros p1 H; rewrite Zpos_succ_morphism; unfold Zsucc. +rewrite sn_aux; auto with zarith. +generalize H; case (s (Zpos p1)); simpl. +intros x y H1; rewrite H1; auto with zarith. +Qed. + +Theorem sn: forall n, 0 <= n -> s (n+1) = (fst (s n) * fst (s n) -2, 0). +intros n Hn; rewrite sn_aux; generalize (sn_snd n); case (s n); auto. +intros x y H; simpl in H; rewrite H; simpl. +eq_tac; ring. +Qed. + +Theorem sn_w: forall n, 0 <= n -> ppow w (2 ^ (n + 1)) = pplus (pmult (s n) (ppow w (2 ^ n))) (- 1, 0). +intros n H; unfold s; simpl; rewrite Zpower_exp; auto with zarith. +assert (Hu: 0 <= 2 ^n); auto with zarith. +rewrite Zpower_1_r; rewrite ppow_ppow; auto with zarith. +repeat rewrite pplus_pmult_dist_r || rewrite pplus_pmult_dist_l. +pattern 2 at 2; replace 2 with (1 + 1); auto with zarith. +rewrite ppow_add; auto with zarith; simpl. +rewrite pmult_1_r; auto. +repeat rewrite <- ppow_mult; auto with zarith. +rewrite (pmult_comm v w); rewrite w_mult_v. +rewrite ppow_1; simpl. +simpl; case (ppow (7, 4) (2 ^n)); simpl; intros z1 z2; eq_tac; auto with zarith. +Qed. + +Theorem sn_w_next: forall n, 0 <= n -> ppow w (2 ^ (n + 1)) = pplus (pmult (s n) (ppow w (2 ^ n))) (- 1, 0). +intros n H; unfold s; simpl; rewrite Zpower_exp; auto with zarith. +assert (Hu: 0 <= 2 ^n); auto with zarith. +rewrite Zpower_1_r; rewrite ppow_ppow; auto with zarith. +repeat rewrite pplus_pmult_dist_r || rewrite pplus_pmult_dist_l. +pattern 2 at 2; replace 2 with (1 + 1); auto with zarith. +rewrite ppow_add; auto with zarith; simpl. +rewrite pmult_1_r; auto. +repeat rewrite <- ppow_mult; auto with zarith. +rewrite (pmult_comm v w); rewrite w_mult_v. +rewrite ppow_1; simpl. +simpl; case (ppow (7, 4) (2 ^n)); simpl; intros z1 z2; eq_tac; auto with zarith. +Qed. + +Section Lucas. + +Variable p: Z. + +(************************************** + Definition of the mersenne number + **************************************) + +Definition Mp := 2^p -1. + +Theorem mersenne_pos: 1 < p -> 1 < Mp. +intros H; unfold Mp; assert (2 < 2 ^p); auto with zarith. +apply Zlt_le_trans with (2^2); auto with zarith. +refine (refl_equal _). +apply Zpower_le_monotone; auto with zarith. +Qed. + +Hypothesis p_pos2: 2 < p. + +(************************************** + We suppose that the mersenne number divides s + **************************************) + +Hypothesis Mp_divide_sn: (Mp | fst (s (p - 2))). + +Variable q: Z. + +(************************************** + We take a divisor of Mp and shows that Mp <= q^2, hence Mp is prime + **************************************) + +Hypothesis q_divide_Mp: (q | Mp). + +Hypothesis q_pos2: 2 < q. + +Theorem q_pos: 1 < q. +apply Zlt_trans with (2 := q_pos2); auto with zarith. +Qed. + +(************************************** + The definition of the groups of inversible pairs + **************************************) + +Definition pgroup := PGroup q q_pos. + +Theorem w_in_pgroup: (In w pgroup.(FGroup.s)). +generalize q_pos; intros HM. +generalize q_pos2; intros HM2. +assert (H0: 0 < q); auto with zarith. +simpl; apply isupport_is_in; auto. +assert (zpmult q w (2, q - 1) = (1, 0)). +unfold zpmult, w, pmult, base; repeat (rewrite Zmult_1_r || rewrite Zmult_1_l). +eq_tac. +apply trans_equal with ((3 * q + 1) mod q). +eq_tac; auto with zarith. +rewrite Zplus_mod; auto. +rewrite Zmult_mod; auto. +rewrite Z_mod_same; auto with zarith. +rewrite Zmult_0_r; repeat rewrite Zmod_small; auto with zarith. +apply trans_equal with (2 * q mod q). +eq_tac; auto with zarith. +apply Zdivide_mod; auto with zarith; exists 2; auto with zarith. +apply is_inv_true with (2, q - 1); auto. +apply mL_in; auto with zarith. +intros; apply zpmult_1_l; auto with zarith. +intros; apply zpmult_1_r; auto with zarith. +rewrite zpmult_comm; auto. +apply mL_in; auto with zarith. +unfold w; apply mL_in; auto with zarith. +Qed. + +Theorem e_order_divide_order: (e_order P_dec w pgroup | g_order pgroup). +apply e_order_divide_g_order. +apply w_in_pgroup. +Qed. + +Theorem order_lt: g_order pgroup < q * q. +unfold g_order, pgroup, PGroup; simpl. +rewrite <- (Zabs_eq (q * q)); auto with zarith. +rewrite <- (inj_Zabs_nat (q * q)); auto with zarith. +rewrite <- mL_length; auto with zarith. +apply inj_lt; apply isupport_length_strict with (0, 0). +apply mL_ulist. +apply mL_in; auto with zarith. +intros a _; left; rewrite zpmult_0_l; auto with zarith. +intros; discriminate. +Qed. + +(************************************** + The power function zpow: a^n + **************************************) + +Definition zpow a := gpow a pgroup. + +(************************************** + Some properties of zpow + **************************************) + +Theorem zpow_def: + forall a b, In a pgroup.(FGroup.s) -> 0 <= b -> + zpow a b = ((fst (ppow a b)) mod q, (snd (ppow a b)) mod q). +generalize q_pos; intros HM. +generalize q_pos2; intros HM2. +assert (H0: 0 < q); auto with zarith. +intros a b Ha Hb; generalize Hb; pattern b; apply natlike_ind; auto. +intros _; repeat rewrite Zmod_small; auto with zarith. +rewrite ppow_0; simpl; auto with zarith. +unfold zpow; intros n1 H Rec _; unfold Zsucc. +rewrite gpow_add; auto with zarith. +rewrite ppow_add; simpl; try rewrite pmult_1_r; auto with zarith. +rewrite Rec; unfold zpmult; auto with zarith. +case (ppow a n1); case a; unfold pmult, fst, snd. +intros x y z t. +repeat (rewrite Zmult_1_r || rewrite Zmult_0_r || rewrite Zplus_0_r || rewrite Zplus_0_l); eq_tac. +repeat rewrite (fun u v => Zplus_mod (u * v)); auto. +eq_tac; try eq_tac; auto. +repeat rewrite (Zmult_mod z); auto with zarith. +repeat rewrite (fun u v => Zmult_mod (u * v)); auto. +eq_tac; try eq_tac; auto with zarith. +repeat rewrite (Zmult_mod base); auto with zarith. +eq_tac; try eq_tac; auto with zarith. +apply Zmod_mod; auto. +apply Zmod_mod; auto. +repeat rewrite (fun u v => Zplus_mod (u * v)); auto. +eq_tac; try eq_tac; auto. +repeat rewrite (Zmult_mod z); auto with zarith. +repeat rewrite (Zmult_mod t); auto with zarith. +Qed. + +Theorem zpow_w_n_minus_1: zpow w (2 ^ (p - 1)) = (-1 mod q, 0). +generalize q_pos; intros HM. +generalize q_pos2; intros HM2. +assert (H0: 0 < q); auto with zarith. +rewrite zpow_def. +replace (p - 1) with ((p - 2) + 1); auto with zarith. +rewrite sn_w; auto with zarith. +generalize Mp_divide_sn (sn_snd (p - 2)); case (s (p -2)); case (ppow w (2 ^ (p -2))). +unfold fst, snd; intros x y z t H1 H2; unfold pmult, pplus; subst. +repeat (rewrite Zmult_0_l || rewrite Zmult_0_r || rewrite Zplus_0_l || rewrite Zplus_0_r). +assert (H2: z mod q = 0). +case H1; intros q1 Hq1; rewrite Hq1. +case q_divide_Mp; intros q2 Hq2; rewrite Hq2. +rewrite Zmult_mod; auto. +rewrite (Zmult_mod q2); auto. +rewrite Z_mod_same; auto with zarith. +repeat (rewrite Zmult_0_r; rewrite (Zmod_small 0)); auto with zarith. +assert (H3: forall x, (z * x) mod q = 0). +intros y1; rewrite Zmult_mod; try rewrite H2; auto. +assert (H4: forall x y, (z * x + y) mod q = y mod q). +intros x1 y1; rewrite Zplus_mod; try rewrite H3; auto. +rewrite Zplus_0_l; apply Zmod_mod; auto. +eq_tac; auto. +apply w_in_pgroup. +apply Zlt_le_weak; apply Zpower_gt_0; auto with zarith. +Qed. + +Theorem zpow_w_n: zpow w (2 ^ p) = (1, 0). +generalize q_pos; intros HM. +generalize q_pos2; intros HM2. +assert (H0: 0 < q); auto with zarith. +replace p with ((p - 1) + 1); auto with zarith. +rewrite Zpower_exp; try rewrite Zpower_exp_1; auto with zarith. +unfold zpow; rewrite gpow_gpow; auto with zarith. +generalize zpow_w_n_minus_1; unfold zpow; intros H1; rewrite H1; clear H1. +simpl; unfold zpmult, pmult. +repeat (rewrite Zmult_0_l || rewrite Zmult_0_r || rewrite Zplus_0_l || + rewrite Zplus_0_r || rewrite Zmult_1_r). +eq_tac; auto. +pattern (-1 mod q) at 1; rewrite <- (Zmod_mod (-1) q); auto with zarith. +repeat rewrite <- Zmult_mod; auto. +rewrite Zmod_small; auto with zarith. +apply w_in_pgroup. +Qed. + +(************************************** + As e = (1, 0), the previous equation implies that the order of the group divide 2^p + **************************************) + +Theorem e_order_divide_pow: (e_order P_dec w pgroup | 2 ^ p). +generalize q_pos; intros HM. +generalize q_pos2; intros HM2. +assert (H0: 0 < q); auto with zarith. +apply e_order_divide_gpow. +apply w_in_pgroup. +apply Zlt_le_weak; apply Zpower_gt_0; auto with zarith. +exact zpow_w_n. +Qed. + +(************************************** + So it is less than equal + **************************************) + +Theorem e_order_le_pow : e_order P_dec w pgroup <= 2 ^ p. +apply Zdivide_le. +apply Zlt_le_weak; apply e_order_pos. +apply Zpower_gt_0; auto with zarith. +apply e_order_divide_pow. +Qed. + +(************************************** + So order(w) must be 2^q + **************************************) + +Theorem e_order_eq_pow: exists q, (e_order P_dec w pgroup) = 2 ^ q. +case (Zdivide_power_2 (e_order P_dec w pgroup) 2 p); auto with zarith. +apply Zlt_le_weak; apply e_order_pos. +apply prime_2. +apply e_order_divide_pow; auto. +intros x H; exists x; auto with zarith. +Qed. + +(************************************** + Buth this q can only be p otherwise it would contradict w^2^(p -1) = (-1, 0) + **************************************) + +Theorem e_order_eq_p: e_order P_dec w pgroup = 2 ^ p. +case (Zdivide_power_2 (e_order P_dec w pgroup) 2 p); auto with zarith. +apply Zlt_le_weak; apply e_order_pos. +apply prime_2. +apply e_order_divide_pow; auto. +intros p1 Hp1. +case (Zle_lt_or_eq p1 p); try (intro H1; subst; auto; fail). +case (Zle_or_lt p1 p); auto; intros H1. +absurd (2 ^ p1 <= 2 ^ p); auto with zarith. +apply Zlt_not_le; apply Zpower_lt_monotone; auto with zarith. +apply Zdivide_le. +apply Zlt_le_weak; apply Zpower_gt_0; auto with zarith. +apply Zpower_gt_0; auto with zarith. +rewrite <- Hp1; apply e_order_divide_pow. +intros H1. +assert (Hu: 0 <= p1). +generalize Hp1; case p1; simpl; auto with zarith. +intros p2 Hu; absurd (0 < e_order P_dec w pgroup). +rewrite Hu; auto with zarith. +apply e_order_pos. +absurd (zpow w (2 ^ (p - 1)) = (1, 0)). +rewrite zpow_w_n_minus_1. +intros H2; injection H2; clear H2; intros H2. +assert (H0: 0 < q); auto with zarith. +absurd (0 mod q = 0). +pattern 0 at 1; replace 0 with (-1 + 1); auto with zarith. +rewrite Zplus_mod; auto with zarith. +rewrite H2; rewrite (Zmod_small 1); auto with zarith. +rewrite Zmod_small; auto with zarith. +rewrite Zmod_small; auto with zarith. +unfold zpow; apply (gpow_pow _ _ w pgroup) with p1; auto with zarith. +apply w_in_pgroup. +rewrite <- Hp1. +apply (gpow_e_order_is_e _ P_dec _ w pgroup). +apply w_in_pgroup. +Qed. + +(************************************** + We have then the expected conclusion + **************************************) + +Theorem q_more_than_square: Mp < q * q. +unfold Mp. +assert (2 ^ p <= q * q); auto with zarith. +rewrite <- e_order_eq_p. +apply Zle_trans with (g_order pgroup). +apply Zdivide_le; auto with zarith. +apply Zlt_le_weak; apply e_order_pos; auto with zarith. +2: apply e_order_divide_order. +2: apply Zlt_le_weak; apply order_lt. +apply Zlt_le_trans with 2; auto with zarith. +replace 2 with (Z_of_nat (length ((1, 0)::w::nil))); auto. +unfold g_order; apply inj_le. +apply ulist_incl_length. +apply ulist_cons; simpl; auto. +unfold w; intros [H2 | H2]; try (case H2; fail); discriminate. +intro a; simpl; intros [H1 | [H1 | H1]]; subst. +assert (In (1, 0) (mL q)). +apply mL_in; auto with zarith. +apply isupport_is_in; auto. +apply is_inv_true with (1, 0); simpl; auto. +intros; apply zpmult_1_l; auto with zarith. +intros; apply zpmult_1_r; auto with zarith. +rewrite zpmult_1_r; auto with zarith. +rewrite zpmult_1_r; auto with zarith. +exact w_in_pgroup. +case H1. +Qed. + +End Lucas. + +(************************************** + We build the sequence in Z + **************************************) + +Definition SS p := + let n := Mp p in + match p - 2 with + Zpos p1 => iter_pos _ (fun x => Zmodd (Zsquare x - 2) n) (Zmodd 4 n) p1 + | _ => (Zmodd 4 n) + end. + +Theorem SS_aux_correct: + forall p z1 z2 n, 0 <= n -> 0 < z1 -> z2 = fst (s n) mod z1 -> + iter_pos _ (fun x => Zmodd (Zsquare x - 2) z1) z2 p = fst (s (n + Zpos p)) mod z1. +intros p; pattern p; apply Pind. +simpl. +intros z1 z2 n Hn H H1; rewrite sn; auto; rewrite H1; rewrite Zmodd_correct; rewrite Zsquare_correct; simpl. +unfold Zminus; rewrite Zplus_mod; auto. +rewrite (Zplus_mod (fst (s n) * fst (s n))); auto with zarith. +eq_tac; auto. +eq_tac; auto. +apply sym_equal; apply Zmult_mod; auto. +intros n Rec z1 z2 n1 Hn1 H1 H2. +rewrite Pplus_one_succ_l; rewrite iter_pos_plus. +rewrite Rec with (n0 := n1); auto. +replace (n1 + Zpos (1 + n)) with ((n1 + Zpos n) + 1); auto with zarith. +rewrite sn; simpl; try rewrite Zmodd_correct; try rewrite Zsquare_correct; simpl; auto with zarith. +unfold Zminus; rewrite Zplus_mod; auto. +unfold Zmodd. +rewrite (Zplus_mod (fst (s (n1 + Zpos n)) * fst (s (n1 + Zpos n)))); auto with zarith. +eq_tac; auto. +eq_tac; auto. +apply sym_equal; apply Zmult_mod; auto. +rewrite Zpos_plus_distr; auto with zarith. +Qed. + +Theorem SS_prop: forall n, 1 < n -> SS n = fst(s (n -2)) mod (Mp n). +intros n Hn; unfold SS. +cut (0 <= n - 2); auto with zarith. +case (n - 2). +intros _; rewrite Zmodd_correct; rewrite s0; auto. +intros p1 H2; rewrite SS_aux_correct with (n := 0); auto with zarith. +apply Zle_lt_trans with 1; try apply mersenne_pos; auto with zarith. +rewrite Zmodd_correct; rewrite s0; auto. +intros p1 H2; case H2; auto. +Qed. + +Theorem SS_prop_cor: forall p, 1 < p -> SS p = 0 -> (Mp p | fst(s (p -2))). +intros p H H1. +apply Zmod_divide. +generalize (mersenne_pos _ H); auto with zarith. +apply trans_equal with (2:= H1); apply sym_equal; apply SS_prop; auto. +Qed. + +Theorem LucasLehmer: forall p, 2 < p -> SS p = 0 -> prime (Mp p). +intros p H H1; case (prime_dec (Mp p)); auto; intros H2. +case Zdivide_div_prime_le_square with (2 := H2). +apply mersenne_pos; apply Zlt_trans with 2; auto with zarith. +intros q (H3, (H4, H5)). +contradict H5; apply Zlt_not_le. +apply q_more_than_square; auto. +apply SS_prop_cor; auto. +apply Zlt_trans with 2; auto with zarith. +case (Zle_lt_or_eq 2 q); auto. +apply prime_ge_2; auto. +intros H5; subst. +absurd (2 <= 1); auto with arith. +apply Zdivide_le; auto with zarith. +case H4; intros x Hx. +exists (2 ^ (p -1) - x). +rewrite Zmult_minus_distr_r; rewrite <- Hx; unfold Mp. +pattern 2 at 2; rewrite <- Zpower_1_r; rewrite <- Zpower_exp; auto with zarith. +replace (p - 1 + 1) with p; auto with zarith. +Qed. + +(************************************** + The test + **************************************) + +Definition lucas_test n := + if Z_lt_dec 2 n then if Z_eq_dec (SS n) 0 then true else false else false. + +Theorem LucasTest: forall n, lucas_test n = true -> prime (Mp n). +intros n; unfold lucas_test; case (Z_lt_dec 2 n); intros H1; try (intros; discriminate). +case (Z_eq_dec (SS n) 0); intros H2; try (intros; discriminate). +intros _; apply LucasLehmer; auto. +Qed. + +Theorem prime7: prime 7. +exact (LucasTest 3 (refl_equal _)). +Qed. + +Theorem prime31: prime 31. +exact (LucasTest 5 (refl_equal _)). +Qed. + +Theorem prime127: prime 127. +exact (LucasTest 7 (refl_equal _)). +Qed. + +Theorem prime8191: prime 8191. +exact (LucasTest 13 (refl_equal _)). +Qed. + +Theorem prime131071: prime 131071. +exact (LucasTest 17 (refl_equal _)). +Qed. + +Theorem prime524287: prime 524287. +exact (LucasTest 19 (refl_equal _)). +Qed. + diff --git a/coqprime-8.5/Coqprime/NatAux.v b/coqprime-8.5/Coqprime/NatAux.v new file mode 100644 index 000000000..eab09150c --- /dev/null +++ b/coqprime-8.5/Coqprime/NatAux.v @@ -0,0 +1,72 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Aux.v + + Auxillary functions & Theorems + **********************************************************************) +Require Export Arith. + +(************************************** + Some properties of minus +**************************************) + +Theorem minus_O : forall a b : nat, a <= b -> a - b = 0. +intros a; elim a; simpl in |- *; auto with arith. +intros a1 Rec b; case b; elim b; auto with arith. +Qed. + + +(************************************** + Definitions and properties of the power for nat +**************************************) + +Fixpoint pow (n m: nat) {struct m} : nat := match m with O => 1%nat | (S m1) => (n * pow n m1)%nat end. + +Theorem pow_add: forall n m p, pow n (m + p) = (pow n m * pow n p)%nat. +intros n m; elim m; simpl. +intros p; rewrite plus_0_r; auto. +intros m1 Rec p; rewrite Rec; auto with arith. +Qed. + + +Theorem pow_pos: forall p n, (0 < p)%nat -> (0 < pow p n)%nat. +intros p1 n H; elim n; simpl; auto with arith. +intros n1 H1; replace 0%nat with (p1 * 0)%nat; auto with arith. +repeat rewrite (mult_comm p1); apply mult_lt_compat_r; auto with arith. +Qed. + + +Theorem pow_monotone: forall n p q, (1 < n)%nat -> (p < q)%nat -> (pow n p < pow n q)%nat. +intros n p1 q1 H H1; elim H1; simpl. +pattern (pow n p1) at 1; rewrite <- (mult_1_l (pow n p1)). +apply mult_lt_compat_r; auto. +apply pow_pos; auto with arith. +intros n1 H2 H3. +apply lt_trans with (1 := H3). +pattern (pow n n1) at 1; rewrite <- (mult_1_l (pow n n1)). +apply mult_lt_compat_r; auto. +apply pow_pos; auto with arith. +Qed. + +(************************************ + Definition of the divisibility for nat +**************************************) + +Definition divide a b := exists c, b = a * c. + + +Theorem divide_le: forall p q, (1 < q)%nat -> divide p q -> (p <= q)%nat. +intros p1 q1 H (x, H1); subst. +apply le_trans with (p1 * 1)%nat; auto with arith. +rewrite mult_1_r; auto with arith. +apply mult_le_compat_l. +case (le_lt_or_eq 0 x); auto with arith. +intros H2; subst; contradict H; rewrite mult_0_r; auto with arith. +Qed. diff --git a/coqprime-8.5/Coqprime/PGroup.v b/coqprime-8.5/Coqprime/PGroup.v new file mode 100644 index 000000000..e9c1b2f47 --- /dev/null +++ b/coqprime-8.5/Coqprime/PGroup.v @@ -0,0 +1,347 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + PGroup.v + + Build the group of pairs modulo needed for the theorem of + lucas lehmer + + Definition: PGroup + **********************************************************************) +Require Import ZArith. +Require Import Znumtheory. +Require Import Tactic. +Require Import Wf_nat. +Require Import ListAux. +Require Import UList. +Require Import FGroup. +Require Import EGroup. +Require Import IGroup. + +Open Scope Z_scope. + +Definition base := 3. + + +(************************************** + Equality is decidable on pairs + **************************************) + +Definition P_dec: forall p q: Z * Z, {p = q} + {p <> q}. +intros p1 q1; case p1; case q1; intros z t x y; case (Z_eq_dec x z); intros H1. +case (Z_eq_dec y t); intros H2. +left; eq_tac; auto. +right; contradict H2; injection H2; auto. +right; contradict H1; injection H1; auto. +Defined. + + +(************************************** + Addition of two pairs + **************************************) + +Definition pplus (p q: Z * Z) := let (x ,y) := p in let (z,t) := q in (x + z, y + t). + +(************************************** + Properties of addition + **************************************) + +Theorem pplus_assoc: forall p q r, (pplus p (pplus q r)) = (pplus (pplus p q) r). +intros p q r; case p; case q; case r; intros r1 r2 q1 q2 p1 p2; unfold pplus. +eq_tac; ring. +Qed. + +Theorem pplus_comm: forall p q, (pplus p q) = (pplus q p). +intros p q; case p; case q; intros q1 q2 p1 p2; unfold pplus. +eq_tac; ring. +Qed. + +(************************************** + Multiplication of two pairs + **************************************) + +Definition pmult (p q: Z * Z) := let (x ,y) := p in let (z,t) := q in (x * z + base * y * t, x * t + y * z). + +(************************************** + Properties of multiplication + **************************************) + +Theorem pmult_assoc: forall p q r, (pmult p (pmult q r)) = (pmult (pmult p q) r). +intros p q r; case p; case q; case r; intros r1 r2 q1 q2 p1 p2; unfold pmult. +eq_tac; ring. +Qed. + +Theorem pmult_0_l: forall p, (pmult (0, 0) p) = (0, 0). +intros p; case p; intros x y; unfold pmult; eq_tac; ring. +Qed. + +Theorem pmult_0_r: forall p, (pmult p (0, 0)) = (0, 0). +intros p; case p; intros x y; unfold pmult; eq_tac; ring. +Qed. + +Theorem pmult_1_l: forall p, (pmult (1, 0) p) = p. +intros p; case p; intros x y; unfold pmult; eq_tac; ring. +Qed. + +Theorem pmult_1_r: forall p, (pmult p (1, 0)) = p. +intros p; case p; intros x y; unfold pmult; eq_tac; ring. +Qed. + +Theorem pmult_comm: forall p q, (pmult p q) = (pmult q p). +intros p q; case p; case q; intros q1 q2 p1 p2; unfold pmult. +eq_tac; ring. +Qed. + +Theorem pplus_pmult_dist_l: forall p q r, (pmult p (pplus q r)) = (pplus (pmult p q) (pmult p r)). +intros p q r; case p; case q; case r; intros r1 r2 q1 q2 p1 p2; unfold pplus, pmult. +eq_tac; ring. +Qed. + + +Theorem pplus_pmult_dist_r: forall p q r, (pmult (pplus q r) p) = (pplus (pmult q p) (pmult r p)). +intros p q r; case p; case q; case r; intros r1 r2 q1 q2 p1 p2; unfold pplus, pmult. +eq_tac; ring. +Qed. + +(************************************** + In this section we create the group PGroup of inversible elements {(p, q) | 0 <= p < m /\ 0 <= q < m} + **************************************) +Section Mod. + +Variable m : Z. + +Hypothesis m_pos: 1 < m. + +(************************************** + mkLine creates {(a, p) | 0 <= p < n} + **************************************) + +Fixpoint mkLine (a: Z) (n: nat) {struct n} : list (Z * Z) := + (a, Z_of_nat n) :: match n with O => nil | (S n1) => mkLine a n1 end. + +(************************************** + Some properties of mkLine + **************************************) + +Theorem mkLine_length: forall a n, length (mkLine a n) = (n + 1)%nat. +intros a n; elim n; simpl; auto. +Qed. + +Theorem mkLine_in: forall a n p, 0 <= p <= Z_of_nat n -> (In (a, p) (mkLine a n)). +intros a n; elim n. +simpl; auto with zarith. +intros p (H1, H2); replace p with 0; auto with zarith. +intros n1 Rec p (H1, H2). +case (Zle_lt_or_eq p (Z_of_nat (S n1))); auto with zarith. +rewrite inj_S in H2; auto with zarith. +rewrite inj_S; auto with zarith. +intros H3; right; apply Rec; auto with zarith. +intros H3; subst; simpl; auto. +Qed. + +Theorem in_mkLine: forall a n p, In p (mkLine a n) -> exists q, 0 <= q <= Z_of_nat n /\ p = (a, q). +intros a n p; elim n; clear n. +simpl; intros [H1 | H1]; exists 0; auto with zarith; case H1. +simpl; intros n Rec [H1 | H1]; auto. +exists (Z_of_nat (S n)); auto with zarith. +case Rec; auto; intros q ((H2, H3), H4); exists q; repeat split; auto with zarith. +change (q <= Z_of_nat (S n)). +rewrite inj_S; auto with zarith. +Qed. + +Theorem mkLine_ulist: forall a n, ulist (mkLine a n). +intros a n; elim n; simpl; auto. +intros n1 H; apply ulist_cons; auto. +change (~ In (a, Z_of_nat (S n1)) (mkLine a n1)). +rewrite inj_S; intros H1. +case in_mkLine with (1 := H1); auto with zarith. +intros x ((H2, H3), H4); injection H4. +intros H5; subst; auto with zarith. +Qed. + +(************************************** + mkRect creates the list {(p, q) | 0 <= p < n /\ 0 <= q < m} + **************************************) + +Fixpoint mkRect (n m: nat) {struct n} : list (Z * Z) := + (mkLine (Z_of_nat n) m) ++ match n with O => nil | (S n1) => mkRect n1 m end. + +(************************************** + Some properties of mkRect + **************************************) + +Theorem mkRect_length: forall n m, length (mkRect n m) = ((n + 1) * (m + 1))%nat. +intros n; elim n; simpl; auto. +intros n1; rewrite <- app_nil_end; rewrite mkLine_length; rewrite plus_0_r; auto. +intros n1 Rec m1; rewrite length_app; rewrite Rec; rewrite mkLine_length; auto. +Qed. + +Theorem mkRect_in: forall n m p q, 0 <= p <= Z_of_nat n -> 0 <= q <= Z_of_nat m -> (In (p, q) (mkRect n m)). +intros n m1; elim n; simpl. +intros p q (H1, H2) (H3, H4); replace p with 0; auto with zarith. +rewrite <- app_nil_end; apply mkLine_in; auto. +intros n1 Rec p q (H1, H2) (H3, H4). +case (Zle_lt_or_eq p (Z_of_nat (S n1))); auto with zarith; intros H5. +rewrite inj_S in H5; apply in_or_app; auto with zarith. +apply in_or_app; left; subst; apply mkLine_in; auto with zarith. +Qed. + +Theorem in_mkRect: forall n m p, In p (mkRect n m) -> exists p1, exists p2, 0 <= p1 <= Z_of_nat n /\ 0 <= p2 <= Z_of_nat m /\ p = (p1, p2). +intros n m1 p; elim n; clear n; simpl. +rewrite <- app_nil_end; intros H1. +case in_mkLine with (1 := H1). +intros p2 (H2, H3); exists 0; exists p2; auto with zarith. +intros n Rec H1. +case in_app_or with (1 := H1); intros H2. +case in_mkLine with (1 := H2). +intros p2 (H3, H4); exists (Z_of_nat (S n)); exists p2; subst; simpl; auto with zarith. +case Rec with (1 := H2); auto. +intros p1 (p2, (H3, (H4, H5))); exists p1; exists p2; repeat split; auto with zarith. +change (p1 <= Z_of_nat (S n)). +rewrite inj_S; auto with zarith. +Qed. + +Theorem mkRect_ulist: forall n m, ulist (mkRect n m). +intros n; elim n; simpl; auto. +intros n1; rewrite <- app_nil_end; apply mkLine_ulist; auto. +intros n1 Rec m1; apply ulist_app; auto. +apply mkLine_ulist. +intros a H1 H2. +case in_mkLine with (1 := H1); intros p1 ((H3, H4), H5). +case in_mkRect with (1 := H2); intros p2 (p3, ((H6, H7), ((H8, H9), H10))). +subst; injection H10; clear H10; intros; subst. +contradict H7. +change (~ Z_of_nat (S n1) <= Z_of_nat n1). +rewrite inj_S; auto with zarith. +Qed. + +(************************************** + mL is the list {(p, q) | 0 <= p < m-1 /\ 0 <= q < m - 1} + **************************************) +Definition mL := mkRect (Zabs_nat (m - 1)) (Zabs_nat (m -1)). + +(************************************** + Some properties of mL + **************************************) + +Theorem mL_length : length mL = Zabs_nat (m * m). +unfold mL; rewrite mkRect_length; simpl; apply inj_eq_rev. +repeat (rewrite inj_mult || rewrite inj_plus || rewrite inj_Zabs_nat || rewrite Zabs_eq); simpl; auto with zarith. +eq_tac; auto with zarith. +Qed. + +Theorem mL_in: forall p q, 0 <= p < m -> 0 <= q < m -> (In (p, q) mL). +intros p q (H1, H2) (H3, H4); unfold mL; apply mkRect_in; rewrite inj_Zabs_nat; + rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem in_mL: forall p, In p mL-> exists p1, exists p2, 0 <= p1 < m /\ 0 <= p2 < m /\ p = (p1, p2). +unfold mL; intros p H1; case in_mkRect with (1 := H1). +repeat (rewrite inj_Zabs_nat || rewrite Zabs_eq); auto with zarith. +intros p1 (p2, ((H2, H3), ((H4, H5), H6))); exists p1; exists p2; repeat split; auto with zarith. +Qed. + +Theorem mL_ulist: ulist mL. +unfold mL; apply mkRect_ulist; auto. +Qed. + +(************************************** + We define zpmult the multiplication of pairs module m + **************************************) + +Definition zpmult (p q: Z * Z) := let (x ,y) := pmult p q in (Zmod x m, Zmod y m). + +(************************************** + Some properties of zpmult + **************************************) + +Theorem zpmult_internal: forall p q, (In (zpmult p q) mL). +intros p q; unfold zpmult; case (pmult p q); intros z y; apply mL_in; auto with zarith. +apply Z_mod_lt; auto with zarith. +apply Z_mod_lt; auto with zarith. +Qed. + +Theorem zpmult_assoc: forall p q r, (zpmult p (zpmult q r)) = (zpmult (zpmult p q) r). +assert (U: 0 < m); auto with zarith. +intros p q r; unfold zpmult. +generalize (pmult_assoc p q r). +case (pmult p q); intros x1 x2. +case (pmult q r); intros y1 y2. +case p; case r; unfold pmult. +intros z1 z2 t1 t2 H. +match goal with + H: (?X, ?Y) = (?Z, ?T) |- _ => + assert (H1: X = Z); assert (H2: Y = T); try (injection H; simpl; auto; fail); clear H +end. +eq_tac. +generalize (f_equal (fun x => x mod m) H1). +repeat rewrite <- Zmult_assoc. +repeat (rewrite (fun x => Zplus_mod (t1 * x))); auto. +repeat (rewrite (fun x => Zplus_mod (x1 * x))); auto. +repeat (rewrite (fun x => Zplus_mod (x1 mod m * x))); auto. +repeat (rewrite (Zmult_mod t1)); auto. +repeat (rewrite (Zmult_mod x1)); auto. +repeat (rewrite (Zmult_mod base)); auto. +repeat (rewrite (Zmult_mod t2)); auto. +repeat (rewrite (Zmult_mod x2)); auto. +repeat (rewrite (Zmult_mod (t2 mod m))); auto. +repeat (rewrite (Zmult_mod (x1 mod m))); auto. +repeat (rewrite (Zmult_mod (x2 mod m))); auto. +repeat (rewrite Zmod_mod); auto. +generalize (f_equal (fun x => x mod m) H2). +repeat (rewrite (fun x => Zplus_mod (t1 * x))); auto. +repeat (rewrite (fun x => Zplus_mod (x1 * x))); auto. +repeat (rewrite (fun x => Zplus_mod (x1 mod m * x))); auto. +repeat (rewrite (Zmult_mod t1)); auto. +repeat (rewrite (Zmult_mod x1)); auto. +repeat (rewrite (Zmult_mod t2)); auto. +repeat (rewrite (Zmult_mod x2)); auto. +repeat (rewrite (Zmult_mod (t2 mod m))); auto. +repeat (rewrite (Zmult_mod (x1 mod m))); auto. +repeat (rewrite (Zmult_mod (x2 mod m))); auto. +repeat (rewrite Zmod_mod); auto. +Qed. + +Theorem zpmult_0_l: forall p, (zpmult (0, 0) p) = (0, 0). +intros p; case p; intros x y; unfold zpmult, pmult; simpl. +rewrite Zmod_small; auto with zarith. +Qed. + +Theorem zpmult_1_l: forall p, In p mL -> zpmult (1, 0) p = p. +intros p H; case in_mL with (1 := H); clear H; intros p1 (p2, ((H1, H2), (H3, H4))); subst. +unfold zpmult; rewrite pmult_1_l. +repeat rewrite Zmod_small; auto with zarith. +Qed. + +Theorem zpmult_1_r: forall p, In p mL -> zpmult p (1, 0) = p. +intros p H; case in_mL with (1 := H); clear H; intros p1 (p2, ((H1, H2), (H3, H4))); subst. +unfold zpmult; rewrite pmult_1_r. +repeat rewrite Zmod_small; auto with zarith. +Qed. + +Theorem zpmult_comm: forall p q, zpmult p q = zpmult q p. +intros p q; unfold zpmult; rewrite pmult_comm; auto. +Qed. + +(************************************** + We are now ready to build our group + **************************************) + +Definition PGroup : (FGroup zpmult). +apply IGroup with (support := mL) (e:= (1, 0)). +exact P_dec. +apply mL_ulist. +apply mL_in; auto with zarith. +intros; apply zpmult_internal. +intros; apply zpmult_assoc. +exact zpmult_1_l. +exact zpmult_1_r. +Defined. + +End Mod. diff --git a/coqprime-8.5/Coqprime/Permutation.v b/coqprime-8.5/Coqprime/Permutation.v new file mode 100644 index 000000000..a06693f89 --- /dev/null +++ b/coqprime-8.5/Coqprime/Permutation.v @@ -0,0 +1,506 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Permutation.v + + Defintion and properties of permutations + **********************************************************************) +Require Export List. +Require Export ListAux. + +Section permutation. +Variable A : Set. + +(************************************** + Definition of permutations as sequences of adjacent transpositions + **************************************) + +Inductive permutation : list A -> list A -> Prop := + | permutation_nil : permutation nil nil + | permutation_skip : + forall (a : A) (l1 l2 : list A), + permutation l2 l1 -> permutation (a :: l2) (a :: l1) + | permutation_swap : + forall (a b : A) (l : list A), permutation (a :: b :: l) (b :: a :: l) + | permutation_trans : + forall l1 l2 l3 : list A, + permutation l1 l2 -> permutation l2 l3 -> permutation l1 l3. +Hint Constructors permutation. + +(************************************** + Reflexivity + **************************************) + +Theorem permutation_refl : forall l : list A, permutation l l. +simple induction l. +apply permutation_nil. +intros a l1 H. +apply permutation_skip with (1 := H). +Qed. +Hint Resolve permutation_refl. + +(************************************** + Symmetry + **************************************) + +Theorem permutation_sym : + forall l m : list A, permutation l m -> permutation m l. +intros l1 l2 H'; elim H'. +apply permutation_nil. +intros a l1' l2' H1 H2. +apply permutation_skip with (1 := H2). +intros a b l1'. +apply permutation_swap. +intros l1' l2' l3' H1 H2 H3 H4. +apply permutation_trans with (1 := H4) (2 := H2). +Qed. + +(************************************** + Compatibility with list length + **************************************) + +Theorem permutation_length : + forall l m : list A, permutation l m -> length l = length m. +intros l m H'; elim H'; simpl in |- *; auto. +intros l1 l2 l3 H'0 H'1 H'2 H'3. +rewrite <- H'3; auto. +Qed. + +(************************************** + A permutation of the nil list is the nil list + **************************************) + +Theorem permutation_nil_inv : forall l : list A, permutation l nil -> l = nil. +intros l H; generalize (permutation_length _ _ H); case l; simpl in |- *; + auto. +intros; discriminate. +Qed. + +(************************************** + A permutation of the singleton list is the singleton list + **************************************) + +Let permutation_one_inv_aux : + forall l1 l2 : list A, + permutation l1 l2 -> forall a : A, l1 = a :: nil -> l2 = a :: nil. +intros l1 l2 H; elim H; clear H l1 l2; auto. +intros a l3 l4 H0 H1 b H2. +injection H2; intros; subst; auto. +rewrite (permutation_nil_inv _ (permutation_sym _ _ H0)); auto. +intros; discriminate. +Qed. + +Theorem permutation_one_inv : + forall (a : A) (l : list A), permutation (a :: nil) l -> l = a :: nil. +intros a l H; apply permutation_one_inv_aux with (l1 := a :: nil); auto. +Qed. + +(************************************** + Compatibility with the belonging + **************************************) + +Theorem permutation_in : + forall (a : A) (l m : list A), permutation l m -> In a l -> In a m. +intros a l m H; elim H; simpl in |- *; auto; intuition. +Qed. + +(************************************** + Compatibility with the append function + **************************************) + +Theorem permutation_app_comp : + forall l1 l2 l3 l4, + permutation l1 l2 -> permutation l3 l4 -> permutation (l1 ++ l3) (l2 ++ l4). +intros l1 l2 l3 l4 H1; generalize l3 l4; elim H1; clear H1 l1 l2 l3 l4; + simpl in |- *; auto. +intros a b l l3 l4 H. +cut (permutation (l ++ l3) (l ++ l4)); auto. +intros; apply permutation_trans with (a :: b :: l ++ l4); auto. +elim l; simpl in |- *; auto. +intros l1 l2 l3 H H0 H1 H2 l4 l5 H3. +apply permutation_trans with (l2 ++ l4); auto. +Qed. +Hint Resolve permutation_app_comp. + +(************************************** + Swap two sublists + **************************************) + +Theorem permutation_app_swap : + forall l1 l2, permutation (l1 ++ l2) (l2 ++ l1). +intros l1; elim l1; auto. +intros; rewrite <- app_nil_end; auto. +intros a l H l2. +replace (l2 ++ a :: l) with ((l2 ++ a :: nil) ++ l). +apply permutation_trans with (l ++ l2 ++ a :: nil); auto. +apply permutation_trans with (((a :: nil) ++ l2) ++ l); auto. +simpl in |- *; auto. +apply permutation_trans with (l ++ (a :: nil) ++ l2); auto. +apply permutation_sym; auto. +replace (l2 ++ a :: l) with ((l2 ++ a :: nil) ++ l). +apply permutation_app_comp; auto. +elim l2; simpl in |- *; auto. +intros a0 l0 H0. +apply permutation_trans with (a0 :: a :: l0); auto. +apply (app_ass l2 (a :: nil) l). +apply (app_ass l2 (a :: nil) l). +Qed. + +(************************************** + A transposition is a permutation + **************************************) + +Theorem permutation_transposition : + forall a b l1 l2 l3, + permutation (l1 ++ a :: l2 ++ b :: l3) (l1 ++ b :: l2 ++ a :: l3). +intros a b l1 l2 l3. +apply permutation_app_comp; auto. +change + (permutation ((a :: nil) ++ l2 ++ (b :: nil) ++ l3) + ((b :: nil) ++ l2 ++ (a :: nil) ++ l3)) in |- *. +repeat rewrite <- app_ass. +apply permutation_app_comp; auto. +apply permutation_trans with ((b :: nil) ++ (a :: nil) ++ l2); auto. +apply permutation_app_swap; auto. +repeat rewrite app_ass. +apply permutation_app_comp; auto. +apply permutation_app_swap; auto. +Qed. + +(************************************** + An element of a list can be put on top of the list to get a permutation + **************************************) + +Theorem in_permutation_ex : + forall a l, In a l -> exists l1 : list A, permutation (a :: l1) l. +intros a l; elim l; simpl in |- *; auto. +intros H; case H; auto. +intros a0 l0 H [H0| H0]. +exists l0; rewrite H0; auto. +case H; auto; intros l1 Hl1; exists (a0 :: l1). +apply permutation_trans with (a0 :: a :: l1); auto. +Qed. + +(************************************** + A permutation of a cons can be inverted + **************************************) + +Let permutation_cons_ex_aux : + forall (a : A) (l1 l2 : list A), + permutation l1 l2 -> + forall l11 l12 : list A, + l1 = l11 ++ a :: l12 -> + exists l3 : list A, + (exists l4 : list A, + l2 = l3 ++ a :: l4 /\ permutation (l11 ++ l12) (l3 ++ l4)). +intros a l1 l2 H; elim H; clear H l1 l2. +intros l11 l12; case l11; simpl in |- *; intros; discriminate. +intros a0 l1 l2 H H0 l11 l12; case l11; simpl in |- *. +exists (nil (A:=A)); exists l1; simpl in |- *; split; auto. +injection H1; intros; subst; auto. +injection H1; intros H2 H3; rewrite <- H2; auto. +intros a1 l111 H1. +case (H0 l111 l12); auto. +injection H1; auto. +intros l3 (l4, (Hl1, Hl2)). +exists (a0 :: l3); exists l4; split; simpl in |- *; auto. +injection H1; intros; subst; auto. +injection H1; intros H2 H3; rewrite H3; auto. +intros a0 b l l11 l12; case l11; simpl in |- *. +case l12; try (intros; discriminate). +intros a1 l0 H; exists (b :: nil); exists l0; simpl in |- *; split; auto. +injection H; intros; subst; auto. +injection H; intros H1 H2 H3; rewrite H2; auto. +intros a1 l111; case l111; simpl in |- *. +intros H; exists (nil (A:=A)); exists (a0 :: l12); simpl in |- *; split; auto. +injection H; intros; subst; auto. +injection H; intros H1 H2 H3; rewrite H3; auto. +intros a2 H1111 H; exists (a2 :: a1 :: H1111); exists l12; simpl in |- *; + split; auto. +injection H; intros; subst; auto. +intros l1 l2 l3 H H0 H1 H2 l11 l12 H3. +case H0 with (1 := H3). +intros l4 (l5, (Hl1, Hl2)). +case H2 with (1 := Hl1). +intros l6 (l7, (Hl3, Hl4)). +exists l6; exists l7; split; auto. +apply permutation_trans with (1 := Hl2); auto. +Qed. + +Theorem permutation_cons_ex : + forall (a : A) (l1 l2 : list A), + permutation (a :: l1) l2 -> + exists l3 : list A, + (exists l4 : list A, l2 = l3 ++ a :: l4 /\ permutation l1 (l3 ++ l4)). +intros a l1 l2 H. +apply (permutation_cons_ex_aux a (a :: l1) l2 H nil l1); simpl in |- *; auto. +Qed. + +(************************************** + A permutation can be simply inverted if the two list starts with a cons + **************************************) + +Theorem permutation_inv : + forall (a : A) (l1 l2 : list A), + permutation (a :: l1) (a :: l2) -> permutation l1 l2. +intros a l1 l2 H; case permutation_cons_ex with (1 := H). +intros l3 (l4, (Hl1, Hl2)). +apply permutation_trans with (1 := Hl2). +generalize Hl1; case l3; simpl in |- *; auto. +intros H1; injection H1; intros H2; rewrite H2; auto. +intros a0 l5 H1; injection H1; intros H2 H3; rewrite H2; rewrite H3; auto. +apply permutation_trans with (a0 :: l4 ++ l5); auto. +apply permutation_skip; apply permutation_app_swap. +apply (permutation_app_swap (a0 :: l4) l5). +Qed. + +(************************************** + Take a list and return tle list of all pairs of an element of the + list and the remaining list + **************************************) + +Fixpoint split_one (l : list A) : list (A * list A) := + match l with + | nil => nil (A:=A * list A) + | a :: l1 => + (a, l1) + :: map (fun p : A * list A => (fst p, a :: snd p)) (split_one l1) + end. + +(************************************** + The pairs of the list are a permutation + **************************************) + +Theorem split_one_permutation : + forall (a : A) (l1 l2 : list A), + In (a, l1) (split_one l2) -> permutation (a :: l1) l2. +intros a l1 l2; generalize a l1; elim l2; clear a l1 l2; simpl in |- *; auto. +intros a l1 H1; case H1. +intros a l H a0 l1 [H0| H0]. +injection H0; intros H1 H2; rewrite H2; rewrite H1; auto. +generalize H H0; elim (split_one l); simpl in |- *; auto. +intros H1 H2; case H2. +intros a1 l0 H1 H2 [H3| H3]; auto. +injection H3; intros H4 H5; (rewrite <- H4; rewrite <- H5). +apply permutation_trans with (a :: fst a1 :: snd a1); auto. +apply permutation_skip. +apply H2; auto. +case a1; simpl in |- *; auto. +Qed. + +(************************************** + All elements of the list are there + **************************************) + +Theorem split_one_in_ex : + forall (a : A) (l1 : list A), + In a l1 -> exists l2 : list A, In (a, l2) (split_one l1). +intros a l1; elim l1; simpl in |- *; auto. +intros H; case H. +intros a0 l H [H0| H0]; auto. +exists l; left; subst; auto. +case H; auto. +intros x H1; exists (a0 :: x); right; auto. +apply + (in_map (fun p : A * list A => (fst p, a0 :: snd p)) (split_one l) (a, x)); + auto. +Qed. + +(************************************** + An auxillary function to generate all permutations + **************************************) + +Fixpoint all_permutations_aux (l : list A) (n : nat) {struct n} : + list (list A) := + match n with + | O => nil :: nil + | S n1 => + flat_map + (fun p : A * list A => + map (cons (fst p)) (all_permutations_aux (snd p) n1)) ( + split_one l) + end. +(************************************** + Generate all the permutations + **************************************) + +Definition all_permutations (l : list A) := all_permutations_aux l (length l). + +(************************************** + All the elements of the list are permutations + **************************************) + +Let all_permutations_aux_permutation : + forall (n : nat) (l1 l2 : list A), + n = length l2 -> In l1 (all_permutations_aux l2 n) -> permutation l1 l2. +intros n; elim n; simpl in |- *; auto. +intros l1 l2; case l2. +simpl in |- *; intros H0 [H1| H1]. +rewrite <- H1; auto. +case H1. +simpl in |- *; intros; discriminate. +intros n0 H l1 l2 H0 H1. +case in_flat_map_ex with (1 := H1). +clear H1; intros x; case x; clear x; intros a1 l3 (H1, H2). +case in_map_inv with (1 := H2). +simpl in |- *; intros y (H3, H4). +rewrite H4; auto. +apply permutation_trans with (a1 :: l3); auto. +apply permutation_skip; auto. +apply H with (2 := H3). +apply eq_add_S. +apply trans_equal with (1 := H0). +change (length l2 = length (a1 :: l3)) in |- *. +apply permutation_length; auto. +apply permutation_sym; apply split_one_permutation; auto. +apply split_one_permutation; auto. +Qed. + +Theorem all_permutations_permutation : + forall l1 l2 : list A, In l1 (all_permutations l2) -> permutation l1 l2. +intros l1 l2 H; apply all_permutations_aux_permutation with (n := length l2); + auto. +Qed. + +(************************************** + A permutation is in the list + **************************************) + +Let permutation_all_permutations_aux : + forall (n : nat) (l1 l2 : list A), + n = length l2 -> permutation l1 l2 -> In l1 (all_permutations_aux l2 n). +intros n; elim n; simpl in |- *; auto. +intros l1 l2; case l2. +intros H H0; rewrite permutation_nil_inv with (1 := H0); auto with datatypes. +simpl in |- *; intros; discriminate. +intros n0 H l1; case l1. +intros l2 H0 H1; + rewrite permutation_nil_inv with (1 := permutation_sym _ _ H1) in H0; + discriminate. +clear l1; intros a1 l1 l2 H1 H2. +case (split_one_in_ex a1 l2); auto. +apply permutation_in with (1 := H2); auto with datatypes. +intros x H0. +apply in_flat_map with (b := (a1, x)); auto. +apply in_map; simpl in |- *. +apply H; auto. +apply eq_add_S. +apply trans_equal with (1 := H1). +change (length l2 = length (a1 :: x)) in |- *. +apply permutation_length; auto. +apply permutation_sym; apply split_one_permutation; auto. +apply permutation_inv with (a := a1). +apply permutation_trans with (1 := H2). +apply permutation_sym; apply split_one_permutation; auto. +Qed. + +Theorem permutation_all_permutations : + forall l1 l2 : list A, permutation l1 l2 -> In l1 (all_permutations l2). +intros l1 l2 H; unfold all_permutations in |- *; + apply permutation_all_permutations_aux; auto. +Qed. + +(************************************** + Permutation is decidable + **************************************) + +Definition permutation_dec : + (forall a b : A, {a = b} + {a <> b}) -> + forall l1 l2 : list A, {permutation l1 l2} + {~ permutation l1 l2}. +intros H l1 l2. +case (In_dec (list_eq_dec H) l1 (all_permutations l2)). +intros i; left; apply all_permutations_permutation; auto. +intros i; right; contradict i; apply permutation_all_permutations; auto. +Defined. + +End permutation. + +(************************************** + Hints + **************************************) + +Hint Constructors permutation. +Hint Resolve permutation_refl. +Hint Resolve permutation_app_comp. +Hint Resolve permutation_app_swap. + +(************************************** + Implicits + **************************************) + +Implicit Arguments permutation [A]. +Implicit Arguments split_one [A]. +Implicit Arguments all_permutations [A]. +Implicit Arguments permutation_dec [A]. + +(************************************** + Permutation is compatible with map + **************************************) + +Theorem permutation_map : + forall (A B : Set) (f : A -> B) l1 l2, + permutation l1 l2 -> permutation (map f l1) (map f l2). +intros A B f l1 l2 H; elim H; simpl in |- *; auto. +intros l0 l3 l4 H0 H1 H2 H3; apply permutation_trans with (2 := H3); auto. +Qed. +Hint Resolve permutation_map. + +(************************************** + Permutation of a map can be inverted + *************************************) + +Let permutation_map_ex_aux : + forall (A B : Set) (f : A -> B) l1 l2 l3, + permutation l1 l2 -> + l1 = map f l3 -> exists l4, permutation l4 l3 /\ l2 = map f l4. +intros A1 B1 f l1 l2 l3 H; generalize l3; elim H; clear H l1 l2 l3. +intros l3; case l3; simpl in |- *; auto. +intros H; exists (nil (A:=A1)); auto. +intros; discriminate. +intros a0 l1 l2 H H0 l3; case l3; simpl in |- *; auto. +intros; discriminate. +intros a1 l H1; case (H0 l); auto. +injection H1; auto. +intros l5 (H2, H3); exists (a1 :: l5); split; simpl in |- *; auto. +injection H1; intros; subst; auto. +intros a0 b l l3; case l3. +intros; discriminate. +intros a1 l0; case l0; simpl in |- *. +intros; discriminate. +intros a2 l1 H; exists (a2 :: a1 :: l1); split; simpl in |- *; auto. +injection H; intros; subst; auto. +intros l1 l2 l3 H H0 H1 H2 l0 H3. +case H0 with (1 := H3); auto. +intros l4 (HH1, HH2). +case H2 with (1 := HH2); auto. +intros l5 (HH3, HH4); exists l5; split; auto. +apply permutation_trans with (1 := HH3); auto. +Qed. + +Theorem permutation_map_ex : + forall (A B : Set) (f : A -> B) l1 l2, + permutation (map f l1) l2 -> + exists l3, permutation l3 l1 /\ l2 = map f l3. +intros A0 B f l1 l2 H; apply permutation_map_ex_aux with (l1 := map f l1); + auto. +Qed. + +(************************************** + Permutation is compatible with flat_map + **************************************) + +Theorem permutation_flat_map : + forall (A B : Set) (f : A -> list B) l1 l2, + permutation l1 l2 -> permutation (flat_map f l1) (flat_map f l2). +intros A B f l1 l2 H; elim H; simpl in |- *; auto. +intros a b l; auto. +repeat rewrite <- app_ass. +apply permutation_app_comp; auto. +intros k3 l4 l5 H0 H1 H2 H3; apply permutation_trans with (1 := H1); auto. +Qed. diff --git a/coqprime-8.5/Coqprime/Pmod.v b/coqprime-8.5/Coqprime/Pmod.v new file mode 100644 index 000000000..f64af48e3 --- /dev/null +++ b/coqprime-8.5/Coqprime/Pmod.v @@ -0,0 +1,617 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Export ZArith. +Require Export ZCmisc. + +Open Local Scope positive_scope. + +Open Local Scope P_scope. + +(* [div_eucl a b] return [(q,r)] such that a = q*b + r *) +Fixpoint div_eucl (a b : positive) {struct a} : N * N := + match a with + | xH => if 1 ?< b then (0%N, 1%N) else (1%N, 0%N) + | xO a' => + let (q, r) := div_eucl a' b in + match q, r with + | N0, N0 => (0%N, 0%N) (* n'arrive jamais *) + | N0, Npos r => + if (xO r) ?< b then (0%N, Npos (xO r)) + else (1%N,PminusN (xO r) b) + | Npos q, N0 => (Npos (xO q), 0%N) + | Npos q, Npos r => + if (xO r) ?< b then (Npos (xO q), Npos (xO r)) + else (Npos (xI q),PminusN (xO r) b) + end + | xI a' => + let (q, r) := div_eucl a' b in + match q, r with + | N0, N0 => (0%N, 0%N) (* Impossible *) + | N0, Npos r => + if (xI r) ?< b then (0%N, Npos (xI r)) + else (1%N,PminusN (xI r) b) + | Npos q, N0 => if 1 ?< b then (Npos (xO q), 1%N) else (Npos (xI q), 0%N) + | Npos q, Npos r => + if (xI r) ?< b then (Npos (xO q), Npos (xI r)) + else (Npos (xI q),PminusN (xI r) b) + end + end. +Infix "/" := div_eucl : P_scope. + +Open Scope Z_scope. +Opaque Zmult. +Lemma div_eucl_spec : forall a b, + Zpos a = fst (a/b)%P * b + snd (a/b)%P + /\ snd (a/b)%P < b. +Proof with zsimpl;try apply Zlt_0_pos;try ((ring;fail) || omega). + intros a b;generalize a;clear a;induction a;simpl;zsimpl. + case IHa; destruct (a/b)%P as [q r]. + case q; case r; simpl fst; simpl snd. + rewrite Zmult_0_l; rewrite Zplus_0_r; intros HH; discriminate HH. + intros p H; rewrite H; + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl; intros H1 H2; split; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + intros p H; rewrite H; + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl; intros H1 H2; split; zsimpl; auto; try ring. + ring_simplify. + case (Zle_lt_or_eq _ _ H1); auto with zarith. + intros p p1 H; rewrite H. + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl; intros H1 H2; split; zsimpl; auto; try ring. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + case IHa; destruct (a/b)%P as [q r]. + case q; case r; simpl fst; simpl snd. + rewrite Zmult_0_l; rewrite Zplus_0_r; intros HH; discriminate HH. + intros p H; rewrite H; + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl; intros H1 H2; split; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + intros p H; rewrite H; simpl; intros H1; split; auto. + zsimpl; ring. + intros p p1 H; rewrite H. + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl; intros H1 H2; split; zsimpl; auto; try ring. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + rewrite PminusN_le... + generalize H1; zsimpl; auto. + match goal with + | [|- context [ ?xx ?< b ]] => + generalize (is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end; zsimpl; simpl. + split; auto. + case (Zle_lt_or_eq 1 b); auto with zarith. + generalize (Zlt_0_pos b); auto with zarith. +Qed. +Transparent Zmult. + +(******** Definition du modulo ************) + +(* [mod a b] return [a] modulo [b] *) +Fixpoint Pmod (a b : positive) {struct a} : N := + match a with + | xH => if 1 ?< b then 1%N else 0%N + | xO a' => + let r := Pmod a' b in + match r with + | N0 => 0%N + | Npos r' => + if (xO r') ?< b then Npos (xO r') + else PminusN (xO r') b + end + | xI a' => + let r := Pmod a' b in + match r with + | N0 => if 1 ?< b then 1%N else 0%N + | Npos r' => + if (xI r') ?< b then Npos (xI r') + else PminusN (xI r') b + end + end. + +Infix "mod" := Pmod (at level 40, no associativity) : P_scope. +Open Local Scope P_scope. + +Lemma Pmod_div_eucl : forall a b, a mod b = snd (a/b). +Proof with auto. + intros a b;generalize a;clear a;induction a;simpl; + try (rewrite IHa; + assert (H1 := div_eucl_spec a b); destruct (a/b) as [q r]; + destruct q as [|q];destruct r as [|r];simpl in *; + match goal with + | [|- context [ ?xx ?< b ]] => + assert (H2 := is_lt_spec xx b);destruct (xx ?< b) + | _ => idtac + end;simpl) ... + destruct H1 as [H3 H4];discriminate H3. + destruct (1 ?< b);simpl ... +Qed. + +Lemma mod1: forall a, a mod 1 = 0%N. +Proof. induction a;simpl;try rewrite IHa;trivial. Qed. + +Lemma mod_a_a_0 : forall a, a mod a = N0. +Proof. + intros a;generalize (div_eucl_spec a a);rewrite <- Pmod_div_eucl. + destruct (fst (a / a));unfold Z_of_N at 1. + rewrite Zmult_0_l;intros (H1,H2);elimtype False;omega. + assert (a<=p*a). + pattern (Zpos a) at 1;rewrite <- (Zmult_1_l a). + assert (H1:= Zlt_0_pos p);assert (H2:= Zle_0_pos a); + apply Zmult_le_compat;trivial;try omega. + destruct (a mod a)%P;auto with zarith. + unfold Z_of_N;assert (H1:= Zlt_0_pos p0);intros (H2,H3);elimtype False;omega. +Qed. + +Lemma mod_le_2r : forall (a b r: positive) (q:N), + Zpos a = b*q + r -> b <= a -> r < b -> 2*r <= a. +Proof. + intros a b r q H0 H1 H2. + assert (H3:=Zlt_0_pos a). assert (H4:=Zlt_0_pos b). assert (H5:=Zlt_0_pos r). + destruct q as [|q]. rewrite Zmult_0_r in H0. elimtype False;omega. + assert (H6:=Zlt_0_pos q). unfold Z_of_N in H0. + assert (Zpos r = a - b*q). omega. + simpl;zsimpl. pattern r at 2;rewrite H. + assert (b <= b * q). + pattern (Zpos b) at 1;rewrite <- (Zmult_1_r b). + apply Zmult_le_compat;try omega. + apply Zle_trans with (a - b * q + b). omega. + apply Zle_trans with (a - b + b);omega. +Qed. + +Lemma mod_lt : forall a b r, a mod b = Npos r -> r < b. +Proof. + intros a b r H;generalize (div_eucl_spec a b);rewrite <- Pmod_div_eucl; + rewrite H;simpl;intros (H1,H2);omega. +Qed. + +Lemma mod_le : forall a b r, a mod b = Npos r -> r <= b. +Proof. intros a b r H;assert (H1:= mod_lt _ _ _ H);omega. Qed. + +Lemma mod_le_a : forall a b r, a mod b = r -> r <= a. +Proof. + intros a b r H;generalize (div_eucl_spec a b);rewrite <- Pmod_div_eucl; + rewrite H;simpl;intros (H1,H2). + assert (0 <= fst (a / b) * b). + destruct (fst (a / b));simpl;auto with zarith. + auto with zarith. +Qed. + +Lemma lt_mod : forall a b, Zpos a < Zpos b -> (a mod b)%P = Npos a. +Proof. + intros a b H; rewrite Pmod_div_eucl. case (div_eucl_spec a b). + assert (0 <= snd(a/b)). destruct (snd(a/b));simpl;auto with zarith. + destruct (fst (a/b)). + unfold Z_of_N at 1;rewrite Zmult_0_l;rewrite Zplus_0_l. + destruct (snd (a/b));simpl; intros H1 H2;inversion H1;trivial. + unfold Z_of_N at 1;assert (b <= p*b). + pattern (Zpos b) at 1; rewrite <- (Zmult_1_l (Zpos b)). + assert (H1 := Zlt_0_pos p);apply Zmult_le_compat;try omega. + apply Zle_0_pos. + intros;elimtype False;omega. +Qed. + +Fixpoint gcd_log2 (a b c:positive) {struct c}: option positive := + match a mod b with + | N0 => Some b + | Npos r => + match b mod r, c with + | N0, _ => Some r + | Npos r', xH => None + | Npos r', xO c' => gcd_log2 r r' c' + | Npos r', xI c' => gcd_log2 r r' c' + end + end. + +Fixpoint egcd_log2 (a b c:positive) {struct c}: + option (Z * Z * positive) := + match a/b with + | (_, N0) => Some (0, 1, b) + | (q, Npos r) => + match b/r, c with + | (_, N0), _ => Some (1, -q, r) + | (q', Npos r'), xH => None + | (q', Npos r'), xO c' => + match egcd_log2 r r' c' with + None => None + | Some (u', v', w') => + let u := u' - v' * q' in + Some (u, v' - q * u, w') + end + | (q', Npos r'), xI c' => + match egcd_log2 r r' c' with + None => None + | Some (u', v', w') => + let u := u' - v' * q' in + Some (u, v' - q * u, w') + end + end + end. + +Lemma egcd_gcd_log2: forall c a b, + match egcd_log2 a b c, gcd_log2 a b c with + None, None => True + | Some (u,v,r), Some r' => r = r' + | _, _ => False + end. +induction c; simpl; auto; try + (intros a b; generalize (Pmod_div_eucl a b); case (a/b); simpl; + intros q r1 H; subst; case (a mod b); auto; + intros r; generalize (Pmod_div_eucl b r); case (b/r); simpl; + intros q' r1 H; subst; case (b mod r); auto; + intros r'; generalize (IHc r r'); case egcd_log2; auto; + intros ((p1,p2),p3); case gcd_log2; auto). +Qed. + +Ltac rw l := + match l with + | (?r, ?r1) => + match type of r with + True => rewrite <- r1 + | _ => rw r; rw r1 + end + | ?r => rewrite r + end. + +Lemma egcd_log2_ok: forall c a b, + match egcd_log2 a b c with + None => True + | Some (u,v,r) => u * a + v * b = r + end. +induction c; simpl; auto; + intros a b; generalize (div_eucl_spec a b); case (a/b); + simpl fst; simpl snd; intros q r1; case r1; try (intros; ring); + simpl; intros r (Hr1, Hr2); clear r1; + generalize (div_eucl_spec b r); case (b/r); + simpl fst; simpl snd; intros q' r1; case r1; + try (intros; rewrite Hr1; ring); + simpl; intros r' (Hr'1, Hr'2); clear r1; auto; + generalize (IHc r r'); case egcd_log2; auto; + intros ((u',v'),w'); case gcd_log2; auto; intros; + rw ((I, H), Hr1, Hr'1); ring. +Qed. + + +Fixpoint log2 (a:positive) : positive := + match a with + | xH => xH + | xO a => Psucc (log2 a) + | xI a => Psucc (log2 a) + end. + +Lemma gcd_log2_1: forall a c, gcd_log2 a xH c = Some xH. +Proof. destruct c;simpl;try rewrite mod1;trivial. Qed. + +Lemma log2_Zle :forall a b, Zpos a <= Zpos b -> log2 a <= log2 b. +Proof with zsimpl;try omega. + induction a;destruct b;zsimpl;intros;simpl ... + assert (log2 a <= log2 b) ... apply IHa ... + assert (log2 a <= log2 b) ... apply IHa ... + assert (H1 := Zlt_0_pos a);elimtype False;omega. + assert (log2 a <= log2 b) ... apply IHa ... + assert (log2 a <= log2 b) ... apply IHa ... + assert (H1 := Zlt_0_pos a);elimtype False;omega. + assert (H1 := Zlt_0_pos (log2 b)) ... + assert (H1 := Zlt_0_pos (log2 b)) ... +Qed. + +Lemma log2_1_inv : forall a, Zpos (log2 a) = 1 -> a = xH. +Proof. + destruct a;simpl;zsimpl;intros;trivial. + assert (H1:= Zlt_0_pos (log2 a));elimtype False;omega. + assert (H1:= Zlt_0_pos (log2 a));elimtype False;omega. +Qed. + +Lemma mod_log2 : + forall a b r:positive, a mod b = Npos r -> b <= a -> log2 r + 1 <= log2 a. +Proof. + intros; cut (log2 (xO r) <= log2 a). simpl;zsimpl;trivial. + apply log2_Zle. + replace (Zpos (xO r)) with (2 * r)%Z;trivial. + generalize (div_eucl_spec a b);rewrite <- Pmod_div_eucl;rewrite H. + rewrite Zmult_comm;intros [H1 H2];apply mod_le_2r with b (fst (a/b));trivial. +Qed. + +Lemma gcd_log2_None_aux : + forall c a b, Zpos b <= Zpos a -> log2 b <= log2 c -> + gcd_log2 a b c <> None. +Proof. + induction c;simpl;intros; + (CaseEq (a mod b);[intros Heq|intros r Heq];try (intro;discriminate)); + (CaseEq (b mod r);[intros Heq'|intros r' Heq'];try (intro;discriminate)). + apply IHc. apply mod_le with b;trivial. + generalize H0 (mod_log2 _ _ _ Heq' (mod_le _ _ _ Heq));zsimpl;intros;omega. + apply IHc. apply mod_le with b;trivial. + generalize H0 (mod_log2 _ _ _ Heq' (mod_le _ _ _ Heq));zsimpl;intros;omega. + assert (Zpos (log2 b) = 1). + assert (H1 := Zlt_0_pos (log2 b));omega. + rewrite (log2_1_inv _ H1) in Heq;rewrite mod1 in Heq;discriminate Heq. +Qed. + +Lemma gcd_log2_None : forall a b, Zpos b <= Zpos a -> gcd_log2 a b b <> None. +Proof. intros;apply gcd_log2_None_aux;auto with zarith. Qed. + +Lemma gcd_log2_Zle : + forall c1 c2 a b, log2 c1 <= log2 c2 -> + gcd_log2 a b c1 <> None -> gcd_log2 a b c2 = gcd_log2 a b c1. +Proof with zsimpl;trivial;try omega. + induction c1;destruct c2;simpl;intros; + (destruct (a mod b) as [|r];[idtac | destruct (b mod r)]) ... + apply IHc1;trivial. generalize H;zsimpl;intros;omega. + apply IHc1;trivial. generalize H;zsimpl;intros;omega. + elim H;destruct (log2 c1);trivial. + apply IHc1;trivial. generalize H;zsimpl;intros;omega. + apply IHc1;trivial. generalize H;zsimpl;intros;omega. + elim H;destruct (log2 c1);trivial. + elim H0;trivial. elim H0;trivial. +Qed. + +Lemma gcd_log2_Zle_log : + forall a b c, log2 b <= log2 c -> Zpos b <= Zpos a -> + gcd_log2 a b c = gcd_log2 a b b. +Proof. + intros a b c H1 H2; apply gcd_log2_Zle; trivial. + apply gcd_log2_None; trivial. +Qed. + +Lemma gcd_log2_mod0 : + forall a b c, a mod b = N0 -> gcd_log2 a b c = Some b. +Proof. intros a b c H;destruct c;simpl;rewrite H;trivial. Qed. + + +Require Import Zwf. + +Lemma Zwf_pos : well_founded (fun x y => Zpos x < Zpos y). +Proof. + unfold well_founded. + assert (forall x a ,x = Zpos a -> Acc (fun x y : positive => x < y) a). + intros x;assert (Hacc := Zwf_well_founded 0 x);induction Hacc;intros;subst x. + constructor;intros. apply H0 with (Zpos y);trivial. + split;auto with zarith. + intros a;apply H with (Zpos a);trivial. +Qed. + +Opaque Pmod. +Lemma gcd_log2_mod : forall a b, Zpos b <= Zpos a -> + forall r, a mod b = Npos r -> gcd_log2 a b b = gcd_log2 b r r. +Proof. + intros a b;generalize a;clear a; assert (Hacc := Zwf_pos b). + induction Hacc; intros a Hle r Hmod. + rename x into b. destruct b;simpl;rewrite Hmod. + CaseEq (xI b mod r)%P;intros. rewrite gcd_log2_mod0;trivial. + assert (H2 := mod_le _ _ _ H1);assert (H3 := mod_lt _ _ _ Hmod); + assert (H4 := mod_le _ _ _ Hmod). + rewrite (gcd_log2_Zle_log r p b);trivial. + symmetry;apply H0;trivial. + generalize (mod_log2 _ _ _ H1 H4);simpl;zsimpl;intros;omega. + CaseEq (xO b mod r)%P;intros. rewrite gcd_log2_mod0;trivial. + assert (H2 := mod_le _ _ _ H1);assert (H3 := mod_lt _ _ _ Hmod); + assert (H4 := mod_le _ _ _ Hmod). + rewrite (gcd_log2_Zle_log r p b);trivial. + symmetry;apply H0;trivial. + generalize (mod_log2 _ _ _ H1 H4);simpl;zsimpl;intros;omega. + rewrite mod1 in Hmod;discriminate Hmod. +Qed. + +Lemma gcd_log2_xO_Zle : + forall a b, Zpos b <= Zpos a -> gcd_log2 a b (xO b) = gcd_log2 a b b. +Proof. + intros a b Hle;apply gcd_log2_Zle. + simpl;zsimpl;auto with zarith. + apply gcd_log2_None_aux;auto with zarith. +Qed. + +Lemma gcd_log2_xO_Zlt : + forall a b, Zpos a < Zpos b -> gcd_log2 a b (xO b) = gcd_log2 b a a. +Proof. + intros a b H;simpl. assert (Hlt := Zlt_0_pos a). + assert (H0 := lt_mod _ _ H). + rewrite H0;simpl. + CaseEq (b mod a)%P;intros;simpl. + symmetry;apply gcd_log2_mod0;trivial. + assert (H2 := mod_lt _ _ _ H1). + rewrite (gcd_log2_Zle_log a p b);auto with zarith. + symmetry;apply gcd_log2_mod;auto with zarith. + apply log2_Zle. + replace (Zpos p) with (Z_of_N (Npos p));trivial. + apply mod_le_a with a;trivial. +Qed. + +Lemma gcd_log2_x0 : forall a b, gcd_log2 a b (xO b) <> None. +Proof. + intros;simpl;CaseEq (a mod b)%P;intros. intro;discriminate. + CaseEq (b mod p)%P;intros. intro;discriminate. + assert (H1 := mod_le_a _ _ _ H0). unfold Z_of_N in H1. + assert (H2 := mod_le _ _ _ H0). + apply gcd_log2_None_aux. trivial. + apply log2_Zle. trivial. +Qed. + +Lemma egcd_log2_x0 : forall a b, egcd_log2 a b (xO b) <> None. +Proof. +intros a b H; generalize (egcd_gcd_log2 (xO b) a b) (gcd_log2_x0 a b); + rw H; case gcd_log2; auto. +Qed. + +Definition gcd a b := + match gcd_log2 a b (xO b) with + | Some p => p + | None => (* can not appear *) 1%positive + end. + +Definition egcd a b := + match egcd_log2 a b (xO b) with + | Some p => p + | None => (* can not appear *) (1,1,1%positive) + end. + + +Lemma gcd_mod0 : forall a b, (a mod b)%P = N0 -> gcd a b = b. +Proof. + intros a b H;unfold gcd. + pattern (gcd_log2 a b (xO b)) at 1; + rewrite (gcd_log2_mod0 _ _ (xO b) H);trivial. +Qed. + +Lemma gcd1 : forall a, gcd a xH = xH. +Proof. intros a;rewrite gcd_mod0;[trivial|apply mod1]. Qed. + +Lemma gcd_mod : forall a b r, (a mod b)%P = Npos r -> + gcd a b = gcd b r. +Proof. + intros a b r H;unfold gcd. + assert (log2 r <= log2 (xO r)). simpl;zsimpl;omega. + assert (H1 := mod_lt _ _ _ H). + pattern (gcd_log2 b r (xO r)) at 1; rewrite gcd_log2_Zle_log;auto with zarith. + destruct (Z_lt_le_dec a b) as [z|z]. + pattern (gcd_log2 a b (xO b)) at 1; rewrite gcd_log2_xO_Zlt;trivial. + rewrite (lt_mod _ _ z) in H;inversion H. + assert (r <= b). omega. + generalize (gcd_log2_None _ _ H2). + destruct (gcd_log2 b r r);intros;trivial. + assert (log2 b <= log2 (xO b)). simpl;zsimpl;omega. + pattern (gcd_log2 a b (xO b)) at 1; rewrite gcd_log2_Zle_log;auto with zarith. + pattern (gcd_log2 a b b) at 1;rewrite (gcd_log2_mod _ _ z _ H). + assert (r <= b). omega. + generalize (gcd_log2_None _ _ H3). + destruct (gcd_log2 b r r);intros;trivial. +Qed. + +Require Import ZArith. +Require Import Znumtheory. + +Hint Rewrite Zpos_mult times_Zmult square_Zmult Psucc_Zplus: zmisc. + +Ltac mauto := + trivial;autorewrite with zmisc;trivial;auto with zarith. + +Lemma gcd_Zis_gcd : forall a b:positive, (Zis_gcd b a (gcd b a)%P). +Proof with mauto. + intros a;assert (Hacc := Zwf_pos a);induction Hacc;rename x into a;intros. + generalize (div_eucl_spec b a)... + rewrite <- (Pmod_div_eucl b a). + CaseEq (b mod a)%P;[intros Heq|intros r Heq]; intros (H1,H2). + simpl in H1;rewrite Zplus_0_r in H1. + rewrite (gcd_mod0 _ _ Heq). + constructor;mauto. + apply Zdivide_intro with (fst (b/a)%P);trivial. + rewrite (gcd_mod _ _ _ Heq). + rewrite H1;apply Zis_gcd_sym. + rewrite Zmult_comm;apply Zis_gcd_for_euclid2;simpl in *. + apply Zis_gcd_sym;auto. +Qed. + +Lemma egcd_Zis_gcd : forall a b:positive, + let (uv,w) := egcd a b in + let (u,v) := uv in + u * a + v * b = w /\ (Zis_gcd b a w). +Proof with mauto. + intros a b; unfold egcd. + generalize (egcd_log2_ok (xO b) a b) (egcd_gcd_log2 (xO b) a b) + (egcd_log2_x0 a b) (gcd_Zis_gcd b a); unfold egcd, gcd. + case egcd_log2; try (intros ((u,v),w)); case gcd_log2; + try (intros; match goal with H: False |- _ => case H end); + try (intros _ _ H1; case H1; auto; fail). + intros; subst; split; try apply Zis_gcd_sym; auto. +Qed. + +Definition Zgcd a b := + match a, b with + | Z0, _ => b + | _, Z0 => a + | Zpos a, Zneg b => Zpos (gcd a b) + | Zneg a, Zpos b => Zpos (gcd a b) + | Zpos a, Zpos b => Zpos (gcd a b) + | Zneg a, Zneg b => Zpos (gcd a b) + end. + + +Lemma Zgcd_is_gcd : forall x y, Zis_gcd x y (Zgcd x y). +Proof. + destruct x;destruct y;simpl. + apply Zis_gcd_0. + apply Zis_gcd_sym;apply Zis_gcd_0. + apply Zis_gcd_sym;apply Zis_gcd_0. + apply Zis_gcd_0. + apply gcd_Zis_gcd. + apply Zis_gcd_sym;apply Zis_gcd_minus;simpl;apply gcd_Zis_gcd. + apply Zis_gcd_0. + apply Zis_gcd_minus;simpl;apply Zis_gcd_sym;apply gcd_Zis_gcd. + apply Zis_gcd_minus;apply Zis_gcd_minus;simpl;apply gcd_Zis_gcd. +Qed. + +Definition Zegcd a b := + match a, b with + | Z0, Z0 => (0,0,0) + | Zpos _, Z0 => (1,0,a) + | Zneg _, Z0 => (-1,0,-a) + | Z0, Zpos _ => (0,1,b) + | Z0, Zneg _ => (0,-1,-b) + | Zpos a, Zneg b => + match egcd a b with (u,v,w) => (u,-v, Zpos w) end + | Zneg a, Zpos b => + match egcd a b with (u,v,w) => (-u,v, Zpos w) end + | Zpos a, Zpos b => + match egcd a b with (u,v,w) => (u,v, Zpos w) end + | Zneg a, Zneg b => + match egcd a b with (u,v,w) => (-u,-v, Zpos w) end + end. + +Lemma Zegcd_is_egcd : forall x y, + match Zegcd x y with + (u,v,w) => u * x + v * y = w /\ Zis_gcd x y w /\ 0 <= w + end. +Proof. + assert (zx0: forall x, Zneg x = -x). + simpl; auto. + assert (zx1: forall x, -(-x) = x). + intro x; case x; simpl; auto. + destruct x;destruct y;simpl; try (split; [idtac|split]); + auto; try (red; simpl; intros; discriminate); + try (rewrite zx0; apply Zis_gcd_minus; try rewrite zx1; auto; + apply Zis_gcd_minus; try rewrite zx1; simpl; auto); + try apply Zis_gcd_0; try (apply Zis_gcd_sym;apply Zis_gcd_0); + generalize (egcd_Zis_gcd p p0); case egcd; intros (u,v) w (H1, H2); + split; repeat rewrite zx0; try (rewrite <- H1; ring); auto; + (split; [idtac | red; intros; discriminate]). + apply Zis_gcd_sym; auto. + apply Zis_gcd_sym; apply Zis_gcd_minus; rw zx1; + apply Zis_gcd_sym; auto. + apply Zis_gcd_minus; rw zx1; auto. + apply Zis_gcd_minus; rw zx1; auto. + apply Zis_gcd_minus; rw zx1; auto. + apply Zis_gcd_sym; auto. +Qed. diff --git a/coqprime-8.5/Coqprime/Pocklington.v b/coqprime-8.5/Coqprime/Pocklington.v new file mode 100644 index 000000000..9871cd3e6 --- /dev/null +++ b/coqprime-8.5/Coqprime/Pocklington.v @@ -0,0 +1,261 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Import ZArith. +Require Export Znumtheory. +Require Import Tactic. +Require Import ZCAux. +Require Import Zp. +Require Import FGroup. +Require Import EGroup. +Require Import Euler. + +Open Scope Z_scope. + +Theorem Pocklington: +forall N F1 R1, 1 < F1 -> 0 < R1 -> N - 1 = F1 * R1 -> + (forall p, prime p -> (p | F1) -> exists a, 1 < a /\ a^(N - 1) mod N = 1 /\ Zgcd (a ^ ((N - 1)/ p) - 1) N = 1) -> + forall n, prime n -> (n | N) -> n mod F1 = 1. +intros N F1 R1 HF1 HR1 Neq Rec n Hn H. +assert (HN: 1 < N). +assert (0 < N - 1); auto with zarith. +rewrite Neq; auto with zarith. +apply Zlt_le_trans with (1* R1); auto with zarith. +assert (Hn1: 1 < n); auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +assert (H1: (F1 | n - 1)). +2: rewrite <- (Zmod_small 1 F1); auto with zarith. +2: case H1; intros k H1'. +2: replace n with (1 + (n - 1)); auto with zarith. +2: rewrite H1'; apply Z_mod_plus; auto with zarith. +apply Zdivide_Zpower; auto with zarith. +intros p i Hp Hi HiF1. +case (Rec p); auto. +apply Zdivide_trans with (2 := HiF1). +apply Zpower_divide; auto with zarith. +intros a (Ha1, (Ha2, Ha3)). +assert (HNn: a ^ (N - 1) mod n = 1). +apply Zdivide_mod_minus; auto with zarith. +apply Zdivide_trans with (1 := H). +apply Zmod_divide_minus; auto with zarith. +assert (~(n | a)). +intros H1; absurd (0 = 1); auto with zarith. +rewrite <- HNn; auto. +apply sym_equal; apply Zdivide_mod; auto with zarith. +apply Zdivide_trans with (1 := H1); apply Zpower_divide; auto with zarith. +assert (Hr: rel_prime a n). +apply rel_prime_sym; apply prime_rel_prime; auto. +assert (Hz: 0 < Zorder a n). +apply Zorder_power_pos; auto. +apply Zdivide_trans with (Zorder a n). +apply prime_divide_Zpower_Zdiv with (N - 1); auto with zarith. +apply Zorder_div_power; auto with zarith. +intros H1; absurd (1 < n); auto; apply Zle_not_lt; apply Zdivide_le; auto with zarith. +rewrite <- Ha3; apply Zdivide_Zgcd; auto with zarith. +apply Zmod_divide_minus; auto with zarith. +case H1; intros t Ht; rewrite Ht. +assert (Ht1: 0 <= t). +apply Zmult_le_reg_r with (Zorder a n); auto with zarith. +rewrite Zmult_0_l; rewrite <- Ht. +apply Zge_le; apply Z_div_ge0; auto with zarith. +apply Zlt_gt; apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +rewrite Zmult_comm; rewrite Zpower_mult; auto with zarith. +rewrite Zpower_mod; auto with zarith. +rewrite Zorder_power_is_1; auto with zarith. +rewrite Zpower_1_l; auto with zarith. +apply Zmod_small; auto with zarith. +apply Zdivide_trans with (1:= HiF1); rewrite Neq; apply Zdivide_factor_r. +apply Zorder_div; auto. +Qed. + +Theorem PocklingtonCorollary1: +forall N F1 R1, 1 < F1 -> 0 < R1 -> N - 1 = F1 * R1 -> N < F1 * F1 -> + (forall p, prime p -> (p | F1) -> exists a, 1 < a /\ a^(N - 1) mod N = 1 /\ Zgcd (a ^ ((N - 1)/ p) - 1) N = 1) -> + prime N. +intros N F1 R1 H H1 H2 H3 H4; case (prime_dec N); intros H5; auto. +assert (HN: 1 < N). +assert (0 < N - 1); auto with zarith. +rewrite H2; auto with zarith. +apply Zlt_le_trans with (1* R1); auto with zarith. +case Zdivide_div_prime_le_square with (2:= H5); auto with zarith. +intros n (Hn, (Hn1, Hn2)). +assert (Hn3: 0 <= n). +apply Zle_trans with 2; try apply prime_ge_2; auto with zarith. +absurd (n = 1). +intros H6; contradict Hn; subst; apply not_prime_1. +rewrite <- (Zmod_small n F1); try split; auto. +apply Pocklington with (R1 := R1) (4 := H4); auto. +apply Zlt_square_mult_inv; auto with zarith. +Qed. + +Theorem PocklingtonCorollary2: +forall N F1 R1, 1 < F1 -> 0 < R1 -> N - 1 = F1 * R1 -> + (forall p, prime p -> (p | F1) -> exists a, 1 < a /\ a^(N - 1) mod N = 1 /\ Zgcd (a ^ ((N - 1)/ p) - 1) N = 1) -> + forall n, 0 <= n -> (n | N) -> n mod F1 = 1. +intros N F1 R1 H1 H2 H3 H4 n H5; pattern n; apply prime_induction; auto. +assert (HN: 1 < N). +assert (0 < N - 1); auto with zarith. +rewrite H3; auto with zarith. +apply Zlt_le_trans with (1* R1); auto with zarith. +intros (u, Hu); contradict HN; subst; rewrite Zmult_0_r; auto with zarith. +intro H6; rewrite Zmod_small; auto with zarith. +intros p q Hp Hp1 Hp2; rewrite Zmult_mod; auto with zarith. +rewrite Pocklington with (n := p) (R1 := R1) (4 := H4); auto. +rewrite Hp1. +rewrite Zmult_1_r; rewrite Zmod_small; auto with zarith. +apply Zdivide_trans with (2 := Hp2); apply Zdivide_factor_l. +apply Zdivide_trans with (2 := Hp2); apply Zdivide_factor_r; auto. +Qed. + +Definition isSquare x := exists y, x = y * y. + +Theorem PocklingtonExtra: +forall N F1 R1, 1 < F1 -> 0 < R1 -> N - 1 = F1 * R1 -> Zeven F1 -> Zodd R1 -> + (forall p, prime p -> (p | F1) -> exists a, 1 < a /\ a^(N - 1) mod N = 1 /\ Zgcd (a ^ ((N - 1)/ p) - 1) N = 1) -> + forall m, 1 <= m -> (forall l, 1 <= l < m -> ~((l * F1 + 1) | N)) -> + let s := (R1 / (2 * F1)) in + let r := (R1 mod (2 * F1)) in + N < (m * F1 + 1) * (2 * F1 * F1 + (r - m) * F1 + 1) -> + (s = 0 \/ ~ isSquare (r * r - 8 * s)) -> prime N. +intros N F1 R1 H1 H2 H3 OF1 ER1 H4 m H5 H6 s r H7 H8. +case (prime_dec N); auto; intros H9. +assert (HN: 1 < N). +assert (0 < N - 1); auto with zarith. +rewrite H3; auto with zarith. +apply Zlt_le_trans with (1* R1); auto with zarith. +case Zdivide_div_prime_le_square with N; auto. +intros X (Hx1, (Hx2, Hx3)). +assert (Hx0: 1 < X). +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +pose (c := (X / F1)). +assert(Hc1: 0 <= c); auto with zarith. +apply Zge_le; unfold c; apply Z_div_ge0; auto with zarith. +assert (Hc2: X = c * F1 + 1). +rewrite (Z_div_mod_eq X F1); auto with zarith. +eq_tac; auto. +rewrite (Zmult_comm F1); auto. +apply PocklingtonCorollary2 with (R1 := R1) (4 := H4); auto with zarith. +case Zle_lt_or_eq with (1 := Hc1); clear Hc1; intros Hc1. +2: contradict Hx0; rewrite Hc2; try rewrite <- Hc1; auto with zarith. +case (Zle_or_lt m c); intros Hc3. +2: case Zle_lt_or_eq with (1 := H5); clear H5; intros H5; auto with zarith. +2: case (H6 c); auto with zarith; rewrite <- Hc2; auto. +2: contradict Hc3; rewrite <- H5; auto with zarith. +pose (d := ((N / X) / F1)). +assert(Hd0: 0 <= N / X); try apply Z_div_pos; auto with zarith. +(* +apply Zge_le; unfold d; repeat apply Z_div_ge0; auto with zarith. +*) +assert(Hd1: 0 <= d); auto with zarith. +apply Zge_le; unfold d; repeat apply Z_div_ge0; auto with zarith. +assert (Hd2: N / X = d * F1 + 1). +rewrite (Z_div_mod_eq (N / X) F1); auto with zarith. +eq_tac; auto. +rewrite (Zmult_comm F1); auto. +apply PocklingtonCorollary2 with (R1 := R1) (4 := H4); auto with zarith. +exists X; auto with zarith. +apply Zdivide_Zdiv_eq; auto with zarith. +case Zle_lt_or_eq with (1 := Hd0); clear Hd0; intros Hd0. +2: contradict HN; rewrite (Zdivide_Zdiv_eq X N); auto with zarith. +2: rewrite <- Hd0; auto with zarith. +case (Zle_lt_or_eq 1 (N / X)); auto with zarith; clear Hd0; intros Hd0. +2: contradict H9; rewrite (Zdivide_Zdiv_eq X N); auto with zarith. +2: rewrite <- Hd0; rewrite Zmult_1_r; auto with zarith. +case Zle_lt_or_eq with (1 := Hd1); clear Hd1; intros Hd1. +2: contradict Hd0; rewrite Hd2; try rewrite <- Hd1; auto with zarith. +case (Zle_or_lt m d); intros Hd3. +2: case Zle_lt_or_eq with (1 := H5); clear H5; intros H5; auto with zarith. +2: case (H6 d); auto with zarith; rewrite <- Hd2; auto. +2: exists X; auto with zarith. +2: apply Zdivide_Zdiv_eq; auto with zarith. +2: contradict Hd3; rewrite <- H5; auto with zarith. +assert (L5: N = (c * F1 + 1) * (d * F1 + 1)). +rewrite <- Hc2; rewrite <- Hd2; apply Zdivide_Zdiv_eq; auto with zarith. +assert (L6: R1 = c * d * F1 + c + d). +apply trans_equal with ((N - 1) / F1). +rewrite H3; rewrite Zmult_comm; apply sym_equal; apply Z_div_mult; auto with zarith. +rewrite L5. +match goal with |- (?X / ?Y = ?Z) => replace X with (Z * Y) end; try ring; apply Z_div_mult; auto with zarith. +assert (L6_1: Zodd (c + d)). +case (Zeven_odd_dec (c + d)); auto; intros O1. +contradict ER1; apply Zeven_not_Zodd; rewrite L6; rewrite <- Zplus_assoc; apply Zeven_plus_Zeven; auto. +apply Zeven_mult_Zeven_r; auto. +assert (L6_2: Zeven (c * d)). +case (Zeven_odd_dec c); intros HH1. +apply Zeven_mult_Zeven_l; auto. +case (Zeven_odd_dec d); intros HH2. +apply Zeven_mult_Zeven_r; auto. +contradict L6_1; apply Zeven_not_Zodd; apply Zodd_plus_Zodd; auto. +assert ((c + d) mod (2 * F1) = r). +rewrite <- Z_mod_plus with (b := Zdiv2 (c * d)); auto with zarith. +match goal with |- ?X mod _ = _ => replace X with R1 end; auto. +rewrite L6; pattern (c * d) at 1. +rewrite Zeven_div2 with (1 := L6_2); ring. +assert (L9: c + d - r < 2 * F1). +apply Zplus_lt_reg_r with (r - m). +apply Zmult_lt_reg_r with (F1); auto with zarith. +apply Zplus_lt_reg_r with 1. +match goal with |- ?X < ?Y => + replace Y with (2 * F1 * F1 + (r - m) * F1 + 1); try ring; + replace X with ((((c + d) - m) * F1) + 1); try ring +end. +apply Zmult_lt_reg_r with (m * F1 + 1); auto with zarith. +apply Zlt_trans with (m * F1 + 0); auto with zarith. +rewrite Zplus_0_r; apply Zmult_lt_O_compat; auto with zarith. +repeat rewrite (fun x => Zmult_comm x (m * F1 + 1)). +apply Zle_lt_trans with (2 := H7). +rewrite L5. +match goal with |- ?X <= ?Y => + replace X with ((m * (c + d) - m * m ) * F1 * F1 + (c + d) * F1 + 1); try ring; + replace Y with ((c * d) * F1 * F1 + (c + d) * F1 + 1); try ring +end. +repeat apply Zplus_le_compat_r. +repeat apply Zmult_le_compat_r; auto with zarith. +assert (tmp: forall p q, 0 <= p - q -> q <= p); auto with zarith; try apply tmp. +match goal with |- _ <= ?X => + replace X with ((c - m) * (d - m)); try ring; auto with zarith +end. +assert (L10: c + d = r). +apply Zmod_closeby_eq with (2 * F1); auto with zarith. +unfold r; apply Z_mod_lt; auto with zarith. +assert (L11: 2 * s = c * d). +apply Zmult_reg_r with F1; auto with zarith. +apply trans_equal with (R1 - (c + d)). +rewrite L10; rewrite (Z_div_mod_eq R1 (2 * F1)); auto with zarith. +unfold s, r; ring. +rewrite L6; ring. +case H8; intro H10. +absurd (0 < c * d); auto with zarith. +apply Zmult_lt_O_compat; auto with zarith. +case H10; exists (c - d); auto with zarith. +rewrite <- L10. +replace (8 * s) with (4 * (2 * s)); auto with zarith; try rewrite L11; ring. +Qed. + +Theorem PocklingtonExtraCorollary: +forall N F1 R1, 1 < F1 -> 0 < R1 -> N - 1 = F1 * R1 -> Zeven F1 -> Zodd R1 -> + (forall p, prime p -> (p | F1) -> exists a, 1 < a /\ a^(N - 1) mod N = 1 /\ Zgcd (a ^ ((N - 1)/ p) - 1) N = 1) -> + let s := (R1 / (2 * F1)) in + let r := (R1 mod (2 * F1)) in + N < 2 * F1 * F1 * F1 -> (s = 0 \/ ~ isSquare (r * r - 8 * s)) -> prime N. +intros N F1 R1 H1 H2 H3 OF1 ER1 H4 s r H5 H6. +apply PocklingtonExtra with (6 := H4) (R1 := R1) (m := 1); auto with zarith. +apply Zlt_le_trans with (1 := H5). +match goal with |- ?X <= ?K * ((?Y + ?Z) + ?T) => + rewrite <- (Zplus_0_l X); + replace (K * ((Y + Z) + T)) with ((F1 * (Z + T) + Y + Z + T) + X);[idtac | ring] +end. +apply Zplus_le_compat_r. +case (Zle_lt_or_eq 0 r); unfold r; auto with zarith. +case (Z_mod_lt R1 (2 * F1)); auto with zarith. +intros HH; repeat ((rewrite <- (Zplus_0_r 0); apply Zplus_le_compat)); auto with zarith. +intros HH; contradict ER1; apply Zeven_not_Zodd. +rewrite (Z_div_mod_eq R1 (2 * F1)); auto with zarith. +rewrite <- HH; rewrite Zplus_0_r. +rewrite <- Zmult_assoc; apply Zeven_2p. +Qed. diff --git a/coqprime-8.5/Coqprime/PocklingtonCertificat.v b/coqprime-8.5/Coqprime/PocklingtonCertificat.v new file mode 100644 index 000000000..ecf4462ed --- /dev/null +++ b/coqprime-8.5/Coqprime/PocklingtonCertificat.v @@ -0,0 +1,756 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Import List. +Require Import ZArith. +Require Import Zorder. +Require Import ZCAux. +Require Import LucasLehmer. +Require Import Pocklington. +Require Import ZCmisc. +Require Import Pmod. + +Definition dec_prime := list (positive * positive). + +Inductive singleCertif : Set := + | Proof_certif : forall N:positive, prime N -> singleCertif + | Lucas_certif : forall (n:positive) (p: Z), singleCertif + | Pock_certif : forall N a : positive, dec_prime -> positive -> singleCertif + | SPock_certif : forall N a : positive, dec_prime -> singleCertif + | Ell_certif: forall (N S: positive) (l: list (positive * positive)) + (A B x y: Z), singleCertif. + +Definition Certif := list singleCertif. + +Definition nprim sc := + match sc with + | Proof_certif n _ => n + | Lucas_certif n _ => n + | Pock_certif n _ _ _ => n + | SPock_certif n _ _ => n + | Ell_certif n _ _ _ _ _ _ => n + + end. + +Open Scope positive_scope. +Open Scope P_scope. + +Fixpoint pow (a p:positive) {struct p} : positive := + match p with + | xH => a + | xO p' =>let z := pow a p' in square z + | xI p' => let z := pow a p' in square z * a + end. + +Definition mkProd' (l:dec_prime) := + fold_right (fun (k:positive*positive) r => times (fst k) r) 1%positive l. + +Definition mkProd_pred (l:dec_prime) := + fold_right (fun (k:positive*positive) r => + if ((snd k) ?= 1)%P then r else times (pow (fst k) (Ppred (snd k))) r) + 1%positive l. + +Definition mkProd (l:dec_prime) := + fold_right (fun (k:positive*positive) r => times (pow (fst k) (snd k)) r) 1%positive l. + +(* [pow_mod a m n] return [a^m mod n] *) +Fixpoint pow_mod (a m n : positive) {struct m} : N := + match m with + | xH => (a mod n)%P + | xO m' => + let z := pow_mod a m' n in + match z with + | N0 => 0%N + | Npos z' => ((square z') mod n)%P + end + | xI m' => + let z := pow_mod a m' n in + match z with + | N0 => 0%N + | Npos z' => (((square z') * a)%P mod n)%P + end + end. + +Definition Npow_mod a m n := + match a with + | N0 => 0%N + | Npos a => pow_mod a m n + end. + +(* [fold_pow_mod a [q1,_;...;qn,_]] b = a ^(q1*...*qn) mod b *) +(* invariant a mod N = a *) +Definition fold_pow_mod a l n := + fold_left + (fun a' (qp:positive*positive) => Npow_mod a' (fst qp) n) + l a. + +Definition times_mod x y n := + match x, y with + | N0, _ => N0 + | _, N0 => N0 + | Npos x, Npos y => ((x * y)%P mod n) + end. + +Definition Npred_mod p n := + match p with + | N0 => Npos (Ppred n) + | Npos p => + if (p ?= 1) then N0 + else Npos (Ppred p) + end. + +Fixpoint all_pow_mod (prod a : N) (l:dec_prime) (n:positive) {struct l}: N*N := + match l with + | nil => (prod,a) + | (q,_) :: l => + let m := Npred_mod (fold_pow_mod a l n) n in + all_pow_mod (times_mod prod m n) (Npow_mod a q n) l n + end. + +Fixpoint pow_mod_pred (a:N) (l:dec_prime) (n:positive) {struct l} : N := + match l with + | nil => a + | (q,p)::l => + if (p ?= 1) then pow_mod_pred a l n + else + let a' := iter_pos _ (fun x => Npow_mod x q n) a (Ppred p) in + pow_mod_pred a' l n + end. + +Definition is_odd p := + match p with + | xO _ => false + | _ => true + end. + +Definition is_even p := + match p with + | xO _ => true + | _ => false + end. + +Definition check_s_r s r sqrt := + match s with + | N0 => true + | Npos p => + match (Zminus (square r) (xO (xO (xO p)))) with + | Zpos x => + let sqrt2 := square sqrt in + let sqrt12 := square (Psucc sqrt) in + if sqrt2 ?< x then x ?< sqrt12 + else false + | Zneg _ => true + | Z0 => false + end + end. + +Definition test_pock N a dec sqrt := + if (2 ?< N) then + let Nm1 := Ppred N in + let F1 := mkProd dec in + match Nm1 / F1 with + | (Npos R1, N0) => + if is_odd R1 then + if is_even F1 then + if (1 ?< a) then + let (s,r') := (R1 / (xO F1))in + match r' with + | Npos r => + let A := pow_mod_pred (pow_mod a R1 N) dec N in + match all_pow_mod 1%N A dec N with + | (Npos p, Npos aNm1) => + if (aNm1 ?= 1) then + if gcd p N ?= 1 then + if check_s_r s r sqrt then + (N ?< (times ((times ((xO F1)+r+1) F1) + r) F1) + 1) + else false + else false + else false + | _ => false + end + | _ => false + end + else false + else false + else false + | _=> false + end + else false. + +Fixpoint is_in (p : positive) (lc : Certif) {struct lc} : bool := + match lc with + | nil => false + | c :: l => if p ?= (nprim c) then true else is_in p l + end. + +Fixpoint all_in (lc : Certif) (lp : dec_prime) {struct lp} : bool := + match lp with + | nil => true + | (p,_) :: lp => + if all_in lc lp + then is_in p lc + else false + end. + +Definition gt2 n := + match n with + | Zpos p => (2 ?< p)%positive + | _ => false + end. + +Fixpoint test_Certif (lc : Certif) : bool := + match lc with + | nil => true + | (Proof_certif _ _) :: lc => test_Certif lc + | (Lucas_certif n p) :: lc => + if test_Certif lc then + if gt2 p then + match Mp p with + | Zpos n' => + if (n ?= n') then + match SS p with + | Z0 => true + | _ => false + end + else false + | _ => false + end + else false + else false + | (Pock_certif n a dec sqrt) :: lc => + if test_pock n a dec sqrt then + if all_in lc dec then test_Certif lc else false + else false +(* Shoudl be done later to do it with Z *) + | (SPock_certif n a dec) :: lc => false + | (Ell_certif _ _ _ _ _ _ _):: lc => false + end. + +Lemma pos_eq_1_spec : + forall p, + if (p ?= 1)%P then p = xH + else (1 < p). +Proof. + unfold Zlt;destruct p;simpl; auto; red;reflexivity. +Qed. + +Open Scope Z_scope. +Lemma mod_unique : forall b q1 r1 q2 r2, + 0 <= r1 < b -> + 0 <= r2 < b -> + b * q1 + r1 = b * q2 + r2 -> + q1 = q2 /\ r1 = r2. +Proof with auto with zarith. + intros b q1 r1 q2 r2 H1 H2 H3. + assert (r2 = (b * q1 + r1) -b*q2). rewrite H3;ring. + assert (b*(q2 - q1) = r1 - r2 ). rewrite H;ring. + assert (-b < r1 - r2 < b). omega. + destruct (Ztrichotomy q1 q2) as [H5 | [H5 | H5]]. + assert (q2 - q1 >= 1). omega. + assert (r1- r2 >= b). + rewrite <- H0. + pattern b at 2; replace b with (b*1). + apply Zmult_ge_compat_l; omega. ring. + elimtype False; omega. + split;trivial. rewrite H;rewrite H5;ring. + assert (r1- r2 <= -b). + rewrite <- H0. + replace (-b) with (b*(-1)); try (ring;fail). + apply Zmult_le_compat_l; omega. + elimtype False; omega. +Qed. + +Lemma Zge_0_pos : forall p:positive, p>= 0. +Proof. + intros;unfold Zge;simpl;intro;discriminate. +Qed. + +Lemma Zge_0_pos_add : forall p:positive, p+p>= 0. +Proof. + intros;simpl;apply Zge_0_pos. +Qed. + +Hint Resolve Zpower_gt_0 Zlt_0_pos Zge_0_pos Zlt_le_weak Zge_0_pos_add: zmisc. + +Hint Rewrite Zpos_mult Zpower_mult Zpower_1_r Zmod_mod Zpower_exp + times_Zmult square_Zmult Psucc_Zplus: zmisc. + +Ltac mauto := + trivial;autorewrite with zmisc;trivial;auto with zmisc zarith. + +Lemma mod_lt : forall a (b:positive), a mod b < b. +Proof. + intros a b;destruct (Z_mod_lt a b);mauto. +Qed. +Hint Resolve mod_lt : zmisc. + +Lemma Zmult_mod_l : forall (n:positive) a b, (a mod n * b) mod n = (a * b) mod n. +Proof with mauto. + intros;rewrite Zmult_mod ... rewrite (Zmult_mod a) ... +Qed. + +Lemma Zmult_mod_r : forall (n:positive) a b, (a * (b mod n)) mod n = (a * b) mod n. +Proof with mauto. + intros;rewrite Zmult_mod ... rewrite (Zmult_mod a) ... +Qed. + +Lemma Zminus_mod_l : forall (n:positive) a b, (a mod n - b) mod n = (a - b) mod n. +Proof with mauto. + intros;rewrite Zminus_mod ... rewrite (Zminus_mod a) ... +Qed. + +Lemma Zminus_mod_r : forall (n:positive) a b, (a - (b mod n)) mod n = (a - b) mod n. +Proof with mauto. + intros;rewrite Zminus_mod ... rewrite (Zminus_mod a) ... +Qed. + +Hint Rewrite Zmult_mod_l Zmult_mod_r Zminus_mod_l Zminus_mod_r : zmisc. +Hint Rewrite <- Zpower_mod : zmisc. + +Lemma Pmod_Zmod : forall a b, Z_of_N (a mod b)%P = a mod b. +Proof. + intros a b; rewrite Pmod_div_eucl. + assert (b>0). mauto. + unfold Zmod; assert (H1 := Z_div_mod a b H). + destruct (Zdiv_eucl a b) as (q2, r2). + assert (H2 := div_eucl_spec a b). + assert (Z_of_N (fst (a / b)%P) = q2 /\ Z_of_N (snd (a/b)%P) = r2). + destruct H1;destruct H2. + apply mod_unique with b;mauto. + split;mauto. + unfold Zle;destruct (snd (a / b)%P);intro;discriminate. + rewrite <- H0;symmetry;rewrite Zmult_comm;trivial. + destruct H0;auto. +Qed. +Hint Rewrite Pmod_Zmod : zmisc. + +Lemma Zpower_0 : forall p : positive, 0^p = 0. +Proof. + intros;simpl;destruct p;unfold Zpower_pos;simpl;trivial. + generalize (iter_pos Z (Z.mul 0) 1 p). + induction p;simpl;trivial. +Qed. + +Lemma pow_Zpower : forall a p, Zpos (pow a p) = a ^ p. +Proof. + induction p; mauto; simpl; mauto; rewrite IHp; mauto. +Qed. +Hint Rewrite pow_Zpower : zmisc. + +Lemma pow_mod_spec : forall n a m, Z_of_N (pow_mod a m n) = a^m mod n. +Proof. + induction m; mauto; simpl; intros; mauto. + rewrite Zmult_mod; auto with zmisc. + rewrite (Zmult_mod (a^m)(a^m)); auto with zmisc. + rewrite <- IHm; mauto. + destruct (pow_mod a m n); mauto. + rewrite (Zmult_mod (a^m)(a^m)); auto with zmisc. + rewrite <- IHm. destruct (pow_mod a m n);simpl; mauto. +Qed. +Hint Rewrite pow_mod_spec Zpower_0 : zmisc. + +Lemma Npow_mod_spec : forall a p n, Z_of_N (Npow_mod a p n) = a^p mod n. +Proof. + intros a p n;destruct a; mauto; simpl; mauto. +Qed. +Hint Rewrite Npow_mod_spec : zmisc. + +Lemma iter_Npow_mod_spec : forall n q p a, + Z_of_N (iter_pos N (fun x : N => Npow_mod x q n) a p) = a^q^p mod n. +Proof. + induction p; mauto; intros; simpl Pos.iter; mauto; repeat rewrite IHp. + rewrite (Zpower_mod ((a ^ q ^ p) ^ q ^ p));auto with zmisc. + rewrite (Zpower_mod (a ^ q ^ p)); mauto. + mauto. +Qed. +Hint Rewrite iter_Npow_mod_spec : zmisc. + +Lemma fold_pow_mod_spec : forall (n:positive) l (a:N), + Z_of_N a = a mod n -> + Z_of_N (fold_pow_mod a l n) = a^(mkProd' l) mod n. +Proof. + unfold fold_pow_mod;induction l; simpl fold_left; simpl mkProd'; + intros; mauto. + rewrite IHl; mauto. +Qed. +Hint Rewrite fold_pow_mod_spec : zmisc. + +Lemma pow_mod_pred_spec : forall (n:positive) l (a:N), + Z_of_N a = a mod n -> + Z_of_N (pow_mod_pred a l n) = a^(mkProd_pred l) mod n. +Proof. + unfold pow_mod_pred;induction l;simpl mkProd;intros; mauto. + destruct a as (q,p). + simpl mkProd_pred. + destruct (p ?= 1)%P; rewrite IHl; mauto; simpl. +Qed. +Hint Rewrite pow_mod_pred_spec : zmisc. + +Lemma mkProd_pred_mkProd : forall l, + (mkProd_pred l)*(mkProd' l) = mkProd l. +Proof. + induction l;simpl;intros; mauto. + generalize (pos_eq_1_spec (snd a)); destruct (snd a ?= 1)%P;intros. + rewrite H; mauto. + replace (mkProd_pred l * (fst a * mkProd' l)) with + (fst a *(mkProd_pred l * mkProd' l));try ring. + rewrite IHl; mauto. + rewrite Zmult_assoc. rewrite times_Zmult. + rewrite (Zmult_comm (pow (fst a) (Ppred (snd a)) * mkProd_pred l)). + rewrite Zmult_assoc. rewrite pow_Zpower. rewrite <-Ppred_Zminus;trivial. + rewrite <- Zpower_Zsucc; try omega. + replace (Zsucc (snd a - 1)) with ((snd a - 1)+1). + replace ((snd a - 1)+1) with (Zpos (snd a)); mauto. + rewrite <- IHl;repeat rewrite Zmult_assoc; mauto. + destruct (snd a - 1);trivial. + assert (1 < snd a); auto with zarith. +Qed. +Hint Rewrite mkProd_pred_mkProd : zmisc. + +Lemma lt_Zmod : forall p n, 0 <= p < n -> p mod n = p. +Proof. + intros a b H. + assert ( 0 <= a mod b < b). + apply Z_mod_lt; mauto. + destruct (mod_unique b (a/b) (a mod b) 0 a H0 H); mauto. + rewrite <- Z_div_mod_eq; mauto. +Qed. + +Lemma Npred_mod_spec : forall p n, Z_of_N p < Zpos n -> + 1 < Zpos n -> Z_of_N (Npred_mod p n) = (p - 1) mod n. +Proof. + destruct p;intros;simpl. + rewrite <- Ppred_Zminus; auto. + apply Zmod_unique with (q := -1); mauto. + assert (H1 := pos_eq_1_spec p);destruct (p?=1)%P. + rewrite H1; mauto. + unfold Z_of_N;rewrite <- Ppred_Zminus; auto. + simpl in H;symmetry; apply (lt_Zmod (p-1) n). + assert (1 < p); auto with zarith. +Qed. +Hint Rewrite Npred_mod_spec : zmisc. + +Lemma times_mod_spec : forall x y n, Z_of_N (times_mod x y n) = (x * y) mod n. +Proof. + intros; destruct x; mauto. + destruct y;simpl; mauto. +Qed. +Hint Rewrite times_mod_spec : zmisc. + +Lemma snd_all_pow_mod : + forall n l (prod a :N), + a mod (Zpos n) = a -> + Z_of_N (snd (all_pow_mod prod a l n)) = (a^(mkProd' l)) mod n. +Proof. + induction l; simpl all_pow_mod; simpl mkProd';intros; mauto. + destruct a as (q,p). + rewrite IHl; mauto. +Qed. + +Lemma fold_aux : forall a N (n:positive) l prod, + fold_left + (fun (r : Z) (k : positive * positive) => + r * (a ^(N / fst k) - 1) mod n) l (prod mod n) mod n = + fold_left + (fun (r : Z) (k : positive * positive) => + r * (a^(N / fst k) - 1)) l prod mod n. +Proof. + induction l;simpl;intros; mauto. +Qed. + +Lemma fst_all_pow_mod : + forall (n a:positive) l (R:positive) (prod A :N), + 1 < n -> + Z_of_N prod = prod mod n -> + Z_of_N A = a^R mod n -> + Z_of_N (fst (all_pow_mod prod A l n)) = + (fold_left + (fun r (k:positive*positive) => + (r * (a ^ (R* mkProd' l / (fst k)) - 1))) l prod) mod n. +Proof. + induction l;simpl;intros; mauto. + destruct a0 as (q,p);simpl. + assert (Z_of_N A = A mod n). + rewrite H1; mauto. + rewrite (IHl (R * q)%positive); mauto; mauto. + pattern (q * mkProd' l) at 2;rewrite (Zmult_comm q). + repeat rewrite Zmult_assoc. + rewrite Z_div_mult;auto with zmisc zarith. + rewrite <- fold_aux. + rewrite <- (fold_aux a (R * q * mkProd' l) n l (prod * (a ^ (R * mkProd' l) - 1)))... + assert ( ((prod * (A ^ mkProd' l - 1)) mod n) = + ((prod * ((a ^ R) ^ mkProd' l - 1)) mod n)). + repeat rewrite (Zmult_mod prod);auto with zmisc. + rewrite Zminus_mod;auto with zmisc. + rewrite (Zminus_mod ((a ^ R) ^ mkProd' l));auto with zmisc. + rewrite (Zpower_mod (a^R));auto with zmisc. rewrite H1; mauto. + rewrite H3; mauto. + rewrite H1; mauto. +Qed. + +Lemma is_odd_Zodd : forall p, is_odd p = true -> Zodd p. +Proof. + destruct p;intros;simpl;trivial;discriminate. +Qed. + +Lemma is_even_Zeven : forall p, is_even p = true -> Zeven p. +Proof. + destruct p;intros;simpl;trivial;discriminate. +Qed. + +Lemma lt_square : forall x y, 0 < x -> x < y -> x*x < y*y. +Proof. + intros; apply Zlt_trans with (x*y). + apply Zmult_lt_compat_l;trivial. + apply Zmult_lt_compat_r;trivial. omega. +Qed. + +Lemma le_square : forall x y, 0 <= x -> x <= y -> x*x <= y*y. +Proof. + intros; apply Zle_trans with (x*y). + apply Zmult_le_compat_l;trivial. + apply Zmult_le_compat_r;trivial. omega. +Qed. + +Lemma borned_square : forall x y, 0 <= x -> 0 <= y -> + x*x < y*y < (x+1)*(x+1) -> False. +Proof. + intros;destruct (Z_lt_ge_dec x y) as [z|z]. + assert (x + 1 <= y). omega. + assert (0 <= x+1). omega. + assert (H4 := le_square _ _ H3 H2). omega. + assert (H4 := le_square _ _ H0 (Zge_le _ _ z)). omega. +Qed. + +Lemma not_square : forall (sqrt:positive) n, sqrt * sqrt < n < (sqrt+1)*(sqrt + 1) -> ~(isSquare n). +Proof. + intros sqrt n H (y,H0). + destruct (Z_lt_ge_dec 0 y). + apply (borned_square sqrt y);mauto. + assert (y*y = (-y)*(-y)). ring. rewrite H1 in H0;clear H1. + apply (borned_square sqrt (-y));mauto. +Qed. + +Ltac spec_dec := + repeat match goal with + | [H:(?x ?= ?y)%P = _ |- _] => + generalize (is_eq_spec x y); + rewrite H;clear H; autorewrite with zmisc; + intro + | [H:(?x ?< ?y)%P = _ |- _] => + generalize (is_lt_spec x y); + rewrite H; clear H; autorewrite with zmisc; + intro + end. + +Ltac elimif := + match goal with + | [H: (if ?b then _ else _) = _ |- _] => + let H1 := fresh "H" in + (CaseEq b;intros H1; rewrite H1 in H; + try discriminate H); elimif + | _ => spec_dec + end. + +Lemma check_s_r_correct : forall s r sqrt, check_s_r s r sqrt = true -> + Z_of_N s = 0 \/ ~ isSquare (r * r - 8 * s). +Proof. + unfold check_s_r;intros. + destruct s as [|s]; trivial;auto. + right;CaseEq (square r - xO (xO (xO s)));[intros H1|intros p1 H1| intros p1 H1]; + rewrite H1 in H;try discriminate H. + elimif. + assert (Zpos (xO (xO (xO s))) = 8 * s). repeat rewrite Zpos_xO_add;ring. + generalizeclear H1; rewrite H2;mauto;intros. + apply (not_square sqrt). + simpl Z.of_N; rewrite H1;auto. + intros (y,Heq). + generalize H1 Heq;mauto. + unfold Z_of_N. + match goal with |- ?x = _ -> ?y = _ -> _ => + replace x with y; try ring + end. + intros Heq1;rewrite Heq1;intros Heq2. + destruct y;discriminate Heq2. +Qed. + +Lemma in_mkProd_prime_div_in : + forall p:positive, prime p -> + forall (l:dec_prime), + (forall k, In k l -> prime (fst k)) -> + Zdivide p (mkProd l) -> exists n,In (p, n) l. +Proof. + induction l;simpl mkProd; simpl In; mauto. + intros _ H1; absurd (p <= 1). + apply Zlt_not_le; apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. + apply Zdivide_le; auto with zarith. + intros. + case prime_mult with (2 := H1); auto with zarith; intros H2. + exists (snd a);left. + destruct a;simpl in *. + assert (Zpos p = Zpos p0). + rewrite (prime_div_Zpower_prime p1 p p0); mauto. + apply (H0 (p0,p1));auto. + inversion H3; auto. + destruct IHl as (n,H3); mauto. + exists n; auto. +Qed. + +Lemma gcd_Zis_gcd : forall a b:positive, (Zis_gcd b a (gcd b a)%P). +Proof. + intros a;assert (Hacc := Zwf_pos a);induction Hacc;rename x into a;intros. + generalize (div_eucl_spec b a); mauto. + rewrite <- (Pmod_div_eucl b a). + CaseEq (b mod a)%P;[intros Heq|intros r Heq]; intros (H1,H2). + simpl in H1;rewrite Zplus_0_r in H1. + rewrite (gcd_mod0 _ _ Heq). + constructor;mauto. + apply Zdivide_intro with (fst (b/a)%P);trivial. + rewrite (gcd_mod _ _ _ Heq). + rewrite H1;apply Zis_gcd_sym. + rewrite Zmult_comm;apply Zis_gcd_for_euclid2;simpl in *. + apply Zis_gcd_sym;auto. +Qed. + +Lemma test_pock_correct : forall N a dec sqrt, + (forall k, In k dec -> prime (Zpos (fst k))) -> + test_pock N a dec sqrt = true -> + prime N. +Proof. + unfold test_pock;intros. + elimif. + generalize (div_eucl_spec (Ppred N) (mkProd dec)); + destruct ((Ppred N) / (mkProd dec))%P as (R1,n); mauto;intros (H2,H3). + destruct R1 as [|R1];try discriminate H0. + destruct n;try discriminate H0. + elimif. + generalize (div_eucl_spec R1 (xO (mkProd dec))); + destruct ((R1 / xO (mkProd dec))%P) as (s,r'); mauto;intros (H7,H8). + destruct r' as [|r];try discriminate H0. + generalize (fst_all_pow_mod N a dec (R1*mkProd_pred dec) 1 + (pow_mod_pred (pow_mod a R1 N) dec N)). + generalize (snd_all_pow_mod N dec 1 (pow_mod_pred (pow_mod a R1 N) dec N)). + destruct (all_pow_mod 1 (pow_mod_pred (pow_mod a R1 N) dec N) dec N) as + (prod,aNm1); mauto; simpl Z_of_N. + destruct prod as [|prod];try discriminate H0. + destruct aNm1 as [|aNm1];try discriminate H0;elimif. + simpl in H3; simpl in H2. + rewrite <- Ppred_Zminus in H2;try omega. + rewrite <- Zmult_assoc;rewrite mkProd_pred_mkProd. + intros H12;assert (a^(N-1) mod N = 1). + pattern 1 at 2;rewrite <- H9;symmetry. + simpl Z.of_N in H12. + rewrite H2; rewrite H12; mauto. + rewrite <- Zpower_mult; mauto. + clear H12. + intros H14. + match type of H14 with _ -> _ -> _ -> ?X => + assert (H12:X); try apply H14; clear H14 + end; mauto. + rewrite Zmod_small; mauto. + assert (1 < mkProd dec). + assert (H14 := Zlt_0_pos (mkProd dec)). + assert (1 <= mkProd dec); mauto. + destruct (Zle_lt_or_eq _ _ H15); mauto. + inversion H16. rewrite <- H18 in H5;discriminate H5. + simpl in H8. + assert (Z_of_N s = R1 / (2 * mkProd dec) /\ Zpos r = R1 mod (2 * mkProd dec)). + apply mod_unique with (2 * mkProd dec);auto with zarith. + revert H8; mauto. + apply Z_mod_lt; mauto. + rewrite <- Z_div_mod_eq; mauto; rewrite H7. + simpl fst; simpl snd; simpl Z_of_N. + ring. + destruct H15 as (H15,Heqr). + apply PocklingtonExtra with (F1:=mkProd dec) (R1:=R1) (m:=1); + auto with zmisc zarith. + rewrite H2; mauto. + apply is_even_Zeven; auto. + apply is_odd_Zodd; auto. + intros p; case p; clear p. + intros HH; contradict HH. + apply not_prime_0. + 2: intros p (V1, _); contradict V1; apply Zle_not_lt; red; simpl; intros; + discriminate. + intros p Hprime Hdec; exists (Zpos a);repeat split; auto with zarith. + apply Zis_gcd_gcd; auto with zarith. + change (rel_prime (a ^ ((N - 1) / p) - 1) N). + match type of H12 with _ = ?X mod _ => + apply rel_prime_div with (p := X); auto with zarith + end. + apply rel_prime_mod_rev; auto with zarith. + red. + pattern 1 at 3; rewrite <- H10; rewrite <- H12. + apply Pmod.gcd_Zis_gcd. + destruct (in_mkProd_prime_div_in _ Hprime _ H Hdec) as (q,Hin). + revert H2; mauto; intro H2. + rewrite <- H2. + match goal with |- context [fold_left ?f _ _] => + apply (ListAux.fold_left_invol_in _ _ f (fun k => Zdivide (a ^ ((N - 1) / p) - 1) k)) + with (b := (p, q)); auto with zarith + end. + rewrite <- Heqr. + generalizeclear H0; ring_simplify + (((mkProd dec + mkProd dec + r + 1) * mkProd dec + r) * mkProd dec + 1) + ((1 * mkProd dec + 1) * (2 * mkProd dec * mkProd dec + (r - 1) * mkProd dec + 1)); mauto. + rewrite <- H15;rewrite <- Heqr. + apply check_s_r_correct with sqrt; mauto. +Qed. + +Lemma is_in_In : + forall p lc, is_in p lc = true -> exists c, In c lc /\ p = nprim c. +Proof. + induction lc;simpl;try (intros;discriminate). + intros;elimif. + exists a;split;auto. inversion H0;trivial. + destruct (IHlc H) as [c [H1 H2]];exists c;auto. +Qed. + +Lemma all_in_In : + forall lc lp, all_in lc lp = true -> + forall pq, In pq lp -> exists c, In c lc /\ fst pq = nprim c. +Proof. + induction lp;simpl. intros H pq HF;elim HF. + intros;destruct a;elimif. + destruct H0;auto. + rewrite <- H0;simpl;apply is_in_In;trivial. +Qed. + +Lemma test_Certif_In_Prime : + forall lc, test_Certif lc = true -> + forall c, In c lc -> prime (nprim c). +Proof with mauto. + induction lc;simpl;intros. elim H0. + destruct H0. + subst c;destruct a;simpl... + elimif. + CaseEq (Mp p);[intros Heq|intros N' Heq|intros N' Heq];rewrite Heq in H; + try discriminate H. elimif. + CaseEq (SS p);[intros Heq'|intros N'' Heq'|intros N'' Heq'];rewrite Heq' in H; + try discriminate H. + rewrite H2;rewrite <- Heq. +apply LucasLehmer;trivial. +(destruct p; try discriminate H1). +simpl in H1; generalize (is_lt_spec 2 p); rewrite H1; auto. +elimif. +apply (test_pock_correct N a d p); mauto. + intros k Hin;destruct (all_in_In _ _ H1 _ Hin) as (c,(H2,H3)). + rewrite H3;auto. +discriminate. +discriminate. + destruct a;elimif;auto. +discriminate. +discriminate. +Qed. + +Lemma Pocklington_refl : + forall c lc, test_Certif (c::lc) = true -> prime (nprim c). +Proof. + intros c lc Heq;apply test_Certif_In_Prime with (c::lc);trivial;simpl;auto. +Qed. + diff --git a/coqprime-8.5/Coqprime/Root.v b/coqprime-8.5/Coqprime/Root.v new file mode 100644 index 000000000..2f65790d6 --- /dev/null +++ b/coqprime-8.5/Coqprime/Root.v @@ -0,0 +1,239 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(*********************************************************************** + Root.v + + Proof that a polynomial has at most n roots +************************************************************************) +Require Import ZArith. +Require Import List. +Require Import UList. +Require Import Tactic. +Require Import Permutation. + +Open Scope Z_scope. + +Section Root. + +Variable A: Set. +Variable P: A -> Prop. +Variable plus mult: A -> A -> A. +Variable op: A -> A. +Variable zero one: A. + + +Let pol := list A. + +Definition toA z := +match z with + Z0 => zero +| Zpos p => iter_pos _ (plus one) zero p +| Zneg p => op (iter_pos _ (plus one) zero p) +end. + +Fixpoint eval (p: pol) (x: A) {struct p} : A := +match p with + nil => zero +| a::p1 => plus a (mult x (eval p1 x)) +end. + +Fixpoint div (p: pol) (x: A) {struct p} : pol * A := +match p with + nil => (nil, zero) +| a::nil => (nil, a) +| a::p1 => + (snd (div p1 x)::fst (div p1 x), + (plus a (mult x (snd (div p1 x))))) +end. + +Hypothesis Pzero: P zero. +Hypothesis Pplus: forall x y, P x -> P y -> P (plus x y). +Hypothesis Pmult: forall x y, P x -> P y -> P (mult x y). +Hypothesis Pop: forall x, P x -> P (op x). +Hypothesis plus_zero: forall a, P a -> plus zero a = a. +Hypothesis plus_comm: forall a b, P a -> P b -> plus a b = plus b a. +Hypothesis plus_assoc: forall a b c, P a -> P b -> P c -> plus a (plus b c) = plus (plus a b) c. +Hypothesis mult_zero: forall a, P a -> mult zero a = zero. +Hypothesis mult_comm: forall a b, P a -> P b -> mult a b = mult b a. +Hypothesis mult_assoc: forall a b c, P a -> P b -> P c -> mult a (mult b c) = mult (mult a b) c. +Hypothesis mult_plus_distr: forall a b c, P a -> P b -> P c -> mult a (plus b c) = plus (mult a b) (mult a c). +Hypothesis plus_op_zero: forall a, P a -> plus a (op a) = zero. +Hypothesis mult_integral: forall a b, P a -> P b -> mult a b = zero -> a = zero \/ b = zero. +(* Not necessary in Set just handy *) +Hypothesis A_dec: forall a b: A, {a = b} + {a <> b}. + +Theorem eval_P: forall p a, P a -> (forall i, In i p -> P i) -> P (eval p a). +intros p a Pa; elim p; simpl; auto with datatypes. +intros a1 l1 Rec H; apply Pplus; auto. +Qed. + +Hint Resolve eval_P. + +Theorem div_P: forall p a, P a -> (forall i, In i p -> P i) -> (forall i, In i (fst (div p a)) -> P i) /\ P (snd (div p a)). +intros p a Pa; elim p; auto with datatypes. +intros a1 l1; case l1. +simpl; intuition. +intros a2 p2 Rec Hi; split. +case Rec; auto with datatypes. +intros H H1 i. +replace (In i (fst (div (a1 :: a2 :: p2) a))) with + (snd (div (a2::p2) a) = i \/ In i (fst (div (a2::p2) a))); auto. +intros [Hi1 | Hi1]; auto. +rewrite <- Hi1; auto. +change ( P (plus a1 (mult a (snd (div (a2::p2) a))))); auto with datatypes. +apply Pplus; auto with datatypes. +apply Pmult; auto with datatypes. +case Rec; auto with datatypes. +Qed. + + +Theorem div_correct: + forall p x y, P x -> P y -> (forall i, In i p -> P i) -> eval p y = plus (mult (eval (fst (div p x)) y) (plus y (op x))) (snd (div p x)). +intros p x y; elim p; simpl. +intros; rewrite mult_zero; try rewrite plus_zero; auto. +intros a l; case l; simpl; auto. +intros _ px py pa; rewrite (fun x => mult_comm x zero); repeat rewrite mult_zero; try apply plus_comm; auto. +intros a1 l1. +generalize (div_P (a1::l1) x); simpl. +match goal with |- context[fst ?A] => case A end; simpl. +intros q r Hd Rec px py pi. +assert (pr: P r). +case Hd; auto. +assert (pa1: P a1). +case Hd; auto. +assert (pey: P (eval q y)). +apply eval_P; auto. +case Hd; auto. +rewrite Rec; auto with datatypes. +rewrite (fun x y => plus_comm x (plus a y)); try rewrite <- plus_assoc; auto. +apply f_equal2 with (f := plus); auto. +repeat rewrite mult_plus_distr; auto. +repeat (rewrite (fun x y => (mult_comm (plus x y))) || rewrite mult_plus_distr); auto. +rewrite (fun x => (plus_comm x (mult y r))); auto. +repeat rewrite plus_assoc; try apply f_equal2 with (f := plus); auto. +2: repeat rewrite mult_assoc; try rewrite (fun y => mult_comm y (op x)); + repeat rewrite mult_assoc; auto. +rewrite (fun z => (plus_comm z (mult (op x) r))); auto. +repeat rewrite plus_assoc; try apply f_equal2 with (f := plus); auto. +2: apply f_equal2 with (f := mult); auto. +repeat rewrite (fun x => mult_comm x r); try rewrite <- mult_plus_distr; auto. +rewrite (plus_comm (op x)); try rewrite plus_op_zero; auto. +rewrite (fun x => mult_comm x zero); try rewrite mult_zero; try rewrite plus_zero; auto. +Qed. + +Theorem div_correct_factor: + forall p a, (forall i, In i p -> P i) -> P a -> + eval p a = zero -> forall x, P x -> eval p x = (mult (eval (fst (div p a)) x) (plus x (op a))). +intros p a Hp Ha H x px. +case (div_P p a); auto; intros Hd1 Hd2. +rewrite (div_correct p a x); auto. +generalize (div_correct p a a). +rewrite plus_op_zero; try rewrite (fun x => mult_comm x zero); try rewrite mult_zero; try rewrite plus_zero; try rewrite H; auto. +intros H1; rewrite <- H1; auto. +rewrite (fun x => plus_comm x zero); auto. +Qed. + +Theorem length_decrease: forall p x, p <> nil -> (length (fst (div p x)) < length p)%nat. +intros p x; elim p; simpl; auto. +intros H1; case H1; auto. +intros a l; case l; simpl; auto. +intros a1 l1. +match goal with |- context[fst ?A] => case A end; simpl; auto with zarith. +intros p1 _ H H1. +apply lt_n_S; apply H; intros; discriminate. +Qed. + +Theorem root_max: +forall p l, ulist l -> (forall i, In i p -> P i) -> (forall i, In i l -> P i) -> + (forall x, In x l -> eval p x = zero) -> (length p <= length l)%nat -> forall x, P x -> eval p x = zero. +intros p l; generalize p; elim l; clear l p; simpl; auto. +intros p; case p; simpl; auto. +intros a p1 _ _ _ _ H; contradict H; auto with arith. +intros a p1 Rec p; case p. +simpl; auto. +intros a1 p2 H H1 H2 H3 H4 x px. +assert (Hu: eval (a1 :: p2) a = zero); auto with datatypes. +rewrite (div_correct_factor (a1 :: p2) a); auto with datatypes. +match goal with |- mult ?X _ = _ => replace X with zero end; try apply mult_zero; auto. +apply sym_equal; apply Rec; auto with datatypes. +apply ulist_inv with (1 := H). +intros i Hi; case (div_P (a1 :: p2) a); auto. +intros x1 H5; case (mult_integral (eval (fst (div (a1 :: p2) a)) x1) (plus x1 (op a))); auto. +apply eval_P; auto. +intros i Hi; case (div_P (a1 :: p2) a); auto. +rewrite <- div_correct_factor; auto. +intros H6; case (ulist_app_inv _ (a::nil) p1 x1); simpl; auto. +left. +apply trans_equal with (plus zero x1); auto. +rewrite <- (plus_op_zero a); try rewrite <- plus_assoc; auto. +rewrite (fun x => plus_comm (op x)); try rewrite H6; try rewrite plus_comm; auto. +apply sym_equal; apply plus_zero; auto. +apply lt_n_Sm_le;apply lt_le_trans with (length (a1 :: p2)); auto with zarith. +apply length_decrease; auto with datatypes. +Qed. + +Theorem root_max_is_zero: +forall p l, ulist l -> (forall i, In i p -> P i) -> (forall i, In i l -> P i) -> + (forall x, In x l -> eval p x = zero) -> (length p <= length l)%nat -> forall x, (In x p) -> x = zero. +intros p l; generalize p; elim l; clear l p; simpl; auto. +intros p; case p; simpl; auto. +intros _ _ _ _ _ x H; case H. +intros a p1 _ _ _ _ H; contradict H; auto with arith. +intros a p1 Rec p; case p. +simpl; auto. +intros _ _ _ _ _ x H; case H. +simpl; intros a1 p2 H H1 H2 H3 H4 x H5. +assert (Ha1: a1 = zero). +assert (Hu: (eval (a1::p2) zero = zero)). +apply root_max with (l := a :: p1); auto. +rewrite <- Hu; simpl; rewrite mult_zero; try rewrite plus_comm; sauto. +case H5; clear H5; intros H5; subst; auto. +apply Rec with p2; auto with arith. +apply ulist_inv with (1 := H). +intros x1 Hx1. +case (In_dec A_dec zero p1); intros Hz. +case (in_permutation_ex _ zero p1); auto; intros p3 Hp3. +apply root_max with (l := a::p3); auto. +apply ulist_inv with zero. +apply ulist_perm with (a::p1); auto. +apply permutation_trans with (a:: (zero:: p3)); auto. +apply permutation_skip; auto. +apply permutation_sym; auto. +simpl; intros x2 [Hx2 | Hx2]; subst; auto. +apply H2; right; apply permutation_in with (1 := Hp3); auto with datatypes. +simpl; intros x2 [Hx2 | Hx2]; subst. +case (mult_integral x2 (eval p2 x2)); auto. +rewrite <- H3 with x2; sauto. +rewrite plus_zero; auto. +intros H6; case (ulist_app_inv _ (x2::nil) p1 x2) ; auto with datatypes. +rewrite H6; apply permutation_in with (1 := Hp3); auto with datatypes. +case (mult_integral x2 (eval p2 x2)); auto. +apply H2; right; apply permutation_in with (1 := Hp3); auto with datatypes. +apply eval_P; auto. +apply H2; right; apply permutation_in with (1 := Hp3); auto with datatypes. +rewrite <- H3 with x2; sauto; try right. +apply sym_equal; apply plus_zero; auto. +apply Pmult; auto. +apply H2; right; apply permutation_in with (1 := Hp3); auto with datatypes. +apply eval_P; auto. +apply H2; right; apply permutation_in with (1 := Hp3); auto with datatypes. +apply permutation_in with (1 := Hp3); auto with datatypes. +intros H6; case (ulist_app_inv _ (zero::nil) p3 x2) ; auto with datatypes. +simpl; apply ulist_perm with (1:= (permutation_sym _ _ _ Hp3)). +apply ulist_inv with (1 := H). +rewrite H6; auto with datatypes. +replace (length (a :: p3)) with (length (zero::p3)); auto. +rewrite permutation_length with (1 := Hp3); auto with arith. +case (mult_integral x1 (eval p2 x1)); auto. +rewrite <- H3 with x1; sauto; try right. +apply sym_equal; apply plus_zero; auto. +intros HH; case Hz; rewrite <- HH; auto. +Qed. + +End Root. \ No newline at end of file diff --git a/coqprime-8.5/Coqprime/Tactic.v b/coqprime-8.5/Coqprime/Tactic.v new file mode 100644 index 000000000..93a244149 --- /dev/null +++ b/coqprime-8.5/Coqprime/Tactic.v @@ -0,0 +1,84 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + + +(********************************************************************** + Tactic.v + Useful tactics + **********************************************************************) + +(************************************** + A simple tactic to end a proof +**************************************) +Ltac finish := intros; auto; trivial; discriminate. + + +(************************************** + A tactic for proof by contradiction + with contradict H + H: ~A |- B gives |- A + H: ~A |- ~ B gives H: B |- A + H: A |- B gives |- ~ A + H: A |- B gives |- ~ A + H: A |- ~ B gives H: A |- ~ A +**************************************) + +Ltac contradict name := + let term := type of name in ( + match term with + (~_) => + match goal with + |- ~ _ => let x := fresh in + (intros x; case name; + generalize x; clear x name; + intro name) + | |- _ => case name; clear name + end + | _ => + match goal with + |- ~ _ => let x := fresh in + (intros x; absurd term; + [idtac | exact name]; generalize x; clear x name; + intros name) + | |- _ => generalize name; absurd term; + [idtac | exact name]; clear name + end + end). + + +(************************************** + A tactic to do case analysis keeping the equality +**************************************) + +Ltac case_eq name := + generalize (refl_equal name); pattern name at -1 in |- *; case name. + + +(************************************** + A tactic to use f_equal? theorems +**************************************) + +Ltac eq_tac := + match goal with + |- (?g _ = ?g _) => apply f_equal with (f := g) + | |- (?g ?X _ = ?g ?X _) => apply f_equal with (f := g X) + | |- (?g _ _ = ?g _ _) => apply f_equal2 with (f := g) + | |- (?g ?X ?Y _ = ?g ?X ?Y _) => apply f_equal with (f := g X Y) + | |- (?g ?X _ _ = ?g ?X _ _) => apply f_equal2 with (f := g X) + | |- (?g _ _ _ = ?g _ _ _) => apply f_equal3 with (f := g) + | |- (?g ?X ?Y ?Z _ = ?g ?X ?Y ?Z _) => apply f_equal with (f := g X Y Z) + | |- (?g ?X ?Y _ _ = ?g ?X ?Y _ _) => apply f_equal2 with (f := g X Y) + | |- (?g ?X _ _ _ = ?g ?X _ _ _) => apply f_equal3 with (f := g X) + | |- (?g _ _ _ _ _ = ?g _ _ _ _) => apply f_equal4 with (f := g) + end. + +(************************************** + A stupid tactic that tries auto also after applying sym_equal +**************************************) + +Ltac sauto := (intros; apply sym_equal; auto; fail) || auto. diff --git a/coqprime-8.5/Coqprime/UList.v b/coqprime-8.5/Coqprime/UList.v new file mode 100644 index 000000000..7b9d982ea --- /dev/null +++ b/coqprime-8.5/Coqprime/UList.v @@ -0,0 +1,286 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(*********************************************************************** + UList.v + + Definition of list with distinct elements + + Definition: ulist +************************************************************************) +Require Import List. +Require Import Arith. +Require Import Permutation. +Require Import ListSet. + +Section UniqueList. +Variable A : Set. +Variable eqA_dec : forall (a b : A), ({ a = b }) + ({ a <> b }). +(* A list is unique if there is not twice the same element in the list *) + +Inductive ulist : list A -> Prop := + ulist_nil: ulist nil + | ulist_cons: forall a l, ~ In a l -> ulist l -> ulist (a :: l) . +Hint Constructors ulist . +(* Inversion theorem *) + +Theorem ulist_inv: forall a l, ulist (a :: l) -> ulist l. +intros a l H; inversion H; auto. +Qed. +(* The append of two unique list is unique if the list are distinct *) + +Theorem ulist_app: + forall l1 l2, + ulist l1 -> + ulist l2 -> (forall (a : A), In a l1 -> In a l2 -> False) -> ulist (l1 ++ l2). +intros L1; elim L1; simpl; auto. +intros a l H l2 H0 H1 H2; apply ulist_cons; simpl; auto. +red; intros H3; case in_app_or with ( 1 := H3 ); auto; intros H4. +inversion H0; auto. +apply H2 with a; auto. +apply H; auto. +apply ulist_inv with ( 1 := H0 ); auto. +intros a0 H3 H4; apply (H2 a0); auto. +Qed. +(* Iinversion theorem the appended list *) + +Theorem ulist_app_inv: + forall l1 l2 (a : A), ulist (l1 ++ l2) -> In a l1 -> In a l2 -> False. +intros l1; elim l1; simpl; auto. +intros a l H l2 a0 H0 [H1|H1] H2. +inversion H0 as [|a1 l0 H3 H4 H5]; auto. +case H3; rewrite H1; auto with datatypes. +apply (H l2 a0); auto. +apply ulist_inv with ( 1 := H0 ); auto. +Qed. +(* Iinversion theorem the appended list *) + +Theorem ulist_app_inv_l: forall (l1 l2 : list A), ulist (l1 ++ l2) -> ulist l1. +intros l1; elim l1; simpl; auto. +intros a l H l2 H0. +inversion H0 as [|il1 iH1 iH2 il2 [iH4 iH5]]; apply ulist_cons; auto. +intros H5; case iH2; auto with datatypes. +apply H with l2; auto. +Qed. +(* Iinversion theorem the appended list *) + +Theorem ulist_app_inv_r: forall (l1 l2 : list A), ulist (l1 ++ l2) -> ulist l2. +intros l1; elim l1; simpl; auto. +intros a l H l2 H0; inversion H0; auto. +Qed. +(* Uniqueness is decidable *) + +Definition ulist_dec: forall l, ({ ulist l }) + ({ ~ ulist l }). +intros l; elim l; auto. +intros a l1 [H|H]; auto. +case (In_dec eqA_dec a l1); intros H2; auto. +right; red; intros H1; inversion H1; auto. +right; intros H1; case H; apply ulist_inv with ( 1 := H1 ). +Defined. +(* Uniqueness is compatible with permutation *) + +Theorem ulist_perm: + forall (l1 l2 : list A), permutation l1 l2 -> ulist l1 -> ulist l2. +intros l1 l2 H; elim H; clear H l1 l2; simpl; auto. +intros a l1 l2 H0 H1 H2; apply ulist_cons; auto. +inversion_clear H2 as [|ia il iH1 iH2 [iH3 iH4]]; auto. +intros H3; case iH1; + apply permutation_in with ( 1 := permutation_sym _ _ _ H0 ); auto. +inversion H2; auto. +intros a b L H0; apply ulist_cons; auto. +inversion_clear H0 as [|ia il iH1 iH2]; auto. +inversion_clear iH2 as [|ia il iH3 iH4]; auto. +intros H; case H; auto. +intros H1; case iH1; rewrite H1; simpl; auto. +apply ulist_cons; auto. +inversion_clear H0 as [|ia il iH1 iH2]; auto. +intros H; case iH1; simpl; auto. +inversion_clear H0 as [|ia il iH1 iH2]; auto. +inversion iH2; auto. +Qed. + +Theorem ulist_def: + forall l a, + In a l -> ulist l -> ~ (exists l1 , permutation l (a :: (a :: l1)) ). +intros l a H H0 [l1 H1]. +absurd (ulist (a :: (a :: l1))); auto. +intros H2; inversion_clear H2; simpl; auto with datatypes. +apply ulist_perm with ( 1 := H1 ); auto. +Qed. + +Theorem ulist_incl_permutation: + forall (l1 l2 : list A), + ulist l1 -> incl l1 l2 -> (exists l3 , permutation l2 (l1 ++ l3) ). +intros l1; elim l1; simpl; auto. +intros l2 H H0; exists l2; simpl; auto. +intros a l H l2 H0 H1; auto. +case (in_permutation_ex _ a l2); auto with datatypes. +intros l3 Hl3. +case (H l3); auto. +apply ulist_inv with ( 1 := H0 ); auto. +intros b Hb. +assert (H2: In b (a :: l3)). +apply permutation_in with ( 1 := permutation_sym _ _ _ Hl3 ); + auto with datatypes. +simpl in H2 |-; case H2; intros H3; simpl; auto. +inversion_clear H0 as [|c lc Hk1]; auto. +case Hk1; subst a; auto. +intros l4 H4; exists l4. +apply permutation_trans with (a :: l3); auto. +apply permutation_sym; auto. +Qed. + +Theorem ulist_eq_permutation: + forall (l1 l2 : list A), + ulist l1 -> incl l1 l2 -> length l1 = length l2 -> permutation l1 l2. +intros l1 l2 H1 H2 H3. +case (ulist_incl_permutation l1 l2); auto. +intros l3 H4. +assert (H5: l3 = @nil A). +generalize (permutation_length _ _ _ H4); rewrite length_app; rewrite H3. +rewrite plus_comm; case l3; simpl; auto. +intros a l H5; absurd (lt (length l2) (length l2)); auto with arith. +pattern (length l2) at 2; rewrite H5; auto with arith. +replace l1 with (app l1 l3); auto. +apply permutation_sym; auto. +rewrite H5; rewrite app_nil_end; auto. +Qed. + + +Theorem ulist_incl_length: + forall (l1 l2 : list A), ulist l1 -> incl l1 l2 -> le (length l1) (length l2). +intros l1 l2 H1 Hi; case ulist_incl_permutation with ( 2 := Hi ); auto. +intros l3 Hl3; rewrite permutation_length with ( 1 := Hl3 ); auto. +rewrite length_app; simpl; auto with arith. +Qed. + +Theorem ulist_incl2_permutation: + forall (l1 l2 : list A), + ulist l1 -> ulist l2 -> incl l1 l2 -> incl l2 l1 -> permutation l1 l2. +intros l1 l2 H1 H2 H3 H4. +apply ulist_eq_permutation; auto. +apply le_antisym; apply ulist_incl_length; auto. +Qed. + + +Theorem ulist_incl_length_strict: + forall (l1 l2 : list A), + ulist l1 -> incl l1 l2 -> ~ incl l2 l1 -> lt (length l1) (length l2). +intros l1 l2 H1 Hi Hi0; case ulist_incl_permutation with ( 2 := Hi ); auto. +intros l3 Hl3; rewrite permutation_length with ( 1 := Hl3 ); auto. +rewrite length_app; simpl; auto with arith. +generalize Hl3; case l3; simpl; auto with arith. +rewrite <- app_nil_end; auto. +intros H2; case Hi0; auto. +intros a HH; apply permutation_in with ( 1 := H2 ); auto. +intros a l Hl0; (rewrite plus_comm; simpl; rewrite plus_comm; auto with arith). +Qed. + +Theorem in_inv_dec: + forall (a b : A) l, In a (cons b l) -> a = b \/ ~ a = b /\ In a l. +intros a b l H; case (eqA_dec a b); auto; intros H1. +right; split; auto; inversion H; auto. +case H1; auto. +Qed. + +Theorem in_ex_app_first: + forall (a : A) (l : list A), + In a l -> + (exists l1 : list A , exists l2 : list A , l = l1 ++ (a :: l2) /\ ~ In a l1 ). +intros a l; elim l; clear l; auto. +intros H; case H. +intros a1 l H H1; auto. +generalize (in_inv_dec _ _ _ H1); intros [H2|[H2 H3]]. +exists (nil (A:=A)); exists l; simpl; split; auto. +subst; auto. +case H; auto; intros l1 [l2 [Hl2 Hl3]]; exists (a1 :: l1); exists l2; simpl; + split; auto. +subst; auto. +intros H4; case H4; auto. +Qed. + +Theorem ulist_inv_ulist: + forall (l : list A), + ~ ulist l -> + (exists a , + exists l1 , + exists l2 , + exists l3 , l = l1 ++ ((a :: l2) ++ (a :: l3)) /\ ulist (l1 ++ (a :: l2)) ). +intros l; elim l using list_length_ind; clear l. +intros l; case l; simpl; auto; clear l. +intros Rec H0; case H0; auto. +intros a l H H0. +case (In_dec eqA_dec a l); intros H1; auto. +case in_ex_app_first with ( 1 := H1 ); intros l1 [l2 [Hl1 Hl2]]; subst l. +case (ulist_dec l1); intros H2. +exists a; exists (@nil A); exists l1; exists l2; split; auto. +simpl; apply ulist_cons; auto. +case (H l1); auto. +rewrite length_app; auto with arith. +intros b [l3 [l4 [l5 [Hl3 Hl4]]]]; subst l1. +exists b; exists (a :: l3); exists l4; exists (l5 ++ (a :: l2)); split; simpl; + auto. +(repeat (rewrite <- ass_app; simpl)); auto. +apply ulist_cons; auto. +contradict Hl2; auto. +replace (l3 ++ (b :: (l4 ++ (b :: l5)))) with ((l3 ++ (b :: l4)) ++ (b :: l5)); + auto with datatypes. +(repeat (rewrite <- ass_app; simpl)); auto. +case (H l); auto; intros a1 [l1 [l2 [l3 [Hl3 Hl4]]]]; subst l. +exists a1; exists (a :: l1); exists l2; exists l3; split; auto. +simpl; apply ulist_cons; auto. +contradict H1. +replace (l1 ++ (a1 :: (l2 ++ (a1 :: l3)))) + with ((l1 ++ (a1 :: l2)) ++ (a1 :: l3)); auto with datatypes. +(repeat (rewrite <- ass_app; simpl)); auto. +Qed. + +Theorem incl_length_repetition: + forall (l1 l2 : list A), + incl l1 l2 -> + lt (length l2) (length l1) -> + (exists a , + exists ll1 , + exists ll2 , + exists ll3 , + l1 = ll1 ++ ((a :: ll2) ++ (a :: ll3)) /\ ulist (ll1 ++ (a :: ll2)) ). +intros l1 l2 H H0; apply ulist_inv_ulist. +intros H1; absurd (le (length l1) (length l2)); auto with arith. +apply ulist_incl_length; auto. +Qed. + +End UniqueList. +Implicit Arguments ulist [A]. +Hint Constructors ulist . + +Theorem ulist_map: + forall (A B : Set) (f : A -> B) l, + (forall x y, (In x l) -> (In y l) -> f x = f y -> x = y) -> ulist l -> ulist (map f l). +intros a b f l Hf Hl; generalize Hf; elim Hl; clear Hf; auto. +simpl; auto. +intros a1 l1 H1 H2 H3 Hf; simpl. +apply ulist_cons; auto with datatypes. +contradict H1. +case in_map_inv with ( 1 := H1 ); auto with datatypes. +intros b1 [Hb1 Hb2]. +replace a1 with b1; auto with datatypes. +Qed. + +Theorem ulist_list_prod: + forall (A : Set) (l1 l2 : list A), + ulist l1 -> ulist l2 -> ulist (list_prod l1 l2). +intros A l1 l2 Hl1 Hl2; elim Hl1; simpl; auto. +intros a l H1 H2 H3; apply ulist_app; auto. +apply ulist_map; auto. +intros x y _ _ H; inversion H; auto. +intros p Hp1 Hp2; case H1. +case in_map_inv with ( 1 := Hp1 ); intros a1 [Ha1 Ha2]; auto. +case in_list_prod_inv with ( 1 := Hp2 ); intros b1 [c1 [Hb1 [Hb2 Hb3]]]; auto. +replace a with b1; auto. +rewrite Ha2 in Hb1; injection Hb1; auto. +Qed. diff --git a/coqprime-8.5/Coqprime/ZCAux.v b/coqprime-8.5/Coqprime/ZCAux.v new file mode 100644 index 000000000..de03a2fe2 --- /dev/null +++ b/coqprime-8.5/Coqprime/ZCAux.v @@ -0,0 +1,295 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + ZCAux.v + + Auxillary functions & Theorems + **********************************************************************) + +Require Import ArithRing. +Require Export ZArith Zpow_facts. +Require Export Znumtheory. +Require Export Tactic. + +Theorem Zdivide_div_prime_le_square: forall x, 1 < x -> ~prime x -> exists p, prime p /\ (p | x) /\ p * p <= x. +intros x Hx; generalize Hx; pattern x; apply Z_lt_induction; auto with zarith. +clear x Hx; intros x Rec H H1. +case (not_prime_divide x); auto. +intros x1 ((H2, H3), H4); case (prime_dec x1); intros H5. +case (Zle_or_lt (x1 * x1) x); intros H6. +exists x1; auto. +case H4; clear H4; intros x2 H4; subst. +assert (Hx2: x2 <= x1). +case (Zle_or_lt x2 x1); auto; intros H8; contradict H6; apply Zle_not_lt. +apply Zmult_le_compat_r; auto with zarith. +case (prime_dec x2); intros H7. +exists x2; repeat (split; auto with zarith). +apply Zmult_le_compat_l; auto with zarith. +apply Zle_trans with 2%Z; try apply prime_ge_2; auto with zarith. +case (Zle_or_lt 0 x2); intros H8. +case Zle_lt_or_eq with (1 := H8); auto with zarith; clear H8; intros H8; subst; auto with zarith. +case (Zle_lt_or_eq 1 x2); auto with zarith; clear H8; intros H8; subst; auto with zarith. +case (Rec x2); try split; auto with zarith. +intros x3 (H9, (H10, H11)). +exists x3; repeat (split; auto with zarith). +contradict H; apply Zle_not_lt; auto with zarith. +apply Zle_trans with (0 * x1); auto with zarith. +case (Rec x1); try split; auto with zarith. +intros x3 (H9, (H10, H11)). +exists x3; repeat (split; auto with zarith). +apply Zdivide_trans with x1; auto with zarith. +Qed. + + +Theorem Zmult_interval: forall p q, 0 < p * q -> 1 < p -> 0 < q < p * q. +intros p q H1 H2; assert (0 < q). +case (Zle_or_lt q 0); auto; intros H3; contradict H1; apply Zle_not_lt. +rewrite <- (Zmult_0_r p). +apply Zmult_le_compat_l; auto with zarith. +split; auto. +pattern q at 1; rewrite <- (Zmult_1_l q). +apply Zmult_lt_compat_r; auto with zarith. +Qed. + +Theorem prime_induction: forall (P: Z -> Prop), P 0 -> P 1 -> (forall p q, prime p -> P q -> P (p * q)) -> forall p, 0 <= p -> P p. +intros P H H1 H2 p Hp. +generalize Hp; pattern p; apply Z_lt_induction; auto; clear p Hp. +intros p Rec Hp. +case Zle_lt_or_eq with (1 := Hp); clear Hp; intros Hp; subst; auto. +case (Zle_lt_or_eq 1 p); auto with zarith; clear Hp; intros Hp; subst; auto. +case (prime_dec p); intros H3. +rewrite <- (Zmult_1_r p); apply H2; auto. + case (Zdivide_div_prime_le_square p); auto. +intros q (Hq1, ((q2, Hq2), Hq3)); subst. +case (Zmult_interval q q2). +rewrite Zmult_comm; apply Zlt_trans with 1; auto with zarith. +apply Zlt_le_trans with 2; auto with zarith; apply prime_ge_2; auto. +intros H4 H5; rewrite Zmult_comm; apply H2; auto. +apply Rec; try split; auto with zarith. +rewrite Zmult_comm; auto. +Qed. + +Theorem div_power_max: forall p q, 1 < p -> 0 < q -> exists n, 0 <= n /\ (p ^n | q) /\ ~(p ^(1 + n) | q). +intros p q H1 H2; generalize H2; pattern q; apply Z_lt_induction; auto with zarith; clear q H2. +intros q Rec H2. +case (Zdivide_dec p q); intros H3. +case (Zdivide_Zdiv_lt_pos p q); auto with zarith; intros H4 H5. +case (Rec (Zdiv q p)); auto with zarith. +intros n (Ha1, (Ha2, Ha3)); exists (n + 1); split; auto with zarith; split. +case Ha2; intros q1 Hq; exists q1. +rewrite Zpower_exp; try rewrite Zpower_1_r; auto with zarith. +rewrite Zmult_assoc; rewrite <- Hq. +rewrite Zmult_comm; apply Zdivide_Zdiv_eq; auto with zarith. +intros (q1, Hu); case Ha3; exists q1. +apply Zmult_reg_r with p; auto with zarith. +rewrite (Zmult_comm (q / p)); rewrite <- Zdivide_Zdiv_eq; auto with zarith. +apply trans_equal with (1 := Hu); repeat rewrite Zpower_exp; try rewrite Zpower_exp_1; auto with zarith. +ring. +exists 0; repeat split; try rewrite Zpower_1_r; try rewrite Zpower_exp_0; auto with zarith. +Qed. + +Theorem prime_div_induction: + forall (P: Z -> Prop) n, + 0 < n -> + (P 1) -> + (forall p i, prime p -> 0 <= i -> (p^i | n) -> P (p^i)) -> + (forall p q, rel_prime p q -> P p -> P q -> P (p * q)) -> + forall m, 0 <= m -> (m | n) -> P m. +intros P n P1 Hn H H1 m Hm. +generalize Hm; pattern m; apply Z_lt_induction; auto; clear m Hm. +intros m Rec Hm H2. +case (prime_dec m); intros Hm1. +rewrite <- Zpower_1_r; apply H; auto with zarith. +rewrite Zpower_1_r; auto. +case Zle_lt_or_eq with (1 := Hm); clear Hm; intros Hm; subst. +2: contradict P1; case H2; intros; subst; auto with zarith. +case (Zle_lt_or_eq 1 m); auto with zarith; clear Hm; intros Hm; subst; auto. +case Zdivide_div_prime_le_square with m; auto. +intros p (Hp1, (Hp2, Hp3)). +case (div_power_max p m); auto with zarith. +generalize (prime_ge_2 p Hp1); auto with zarith. +intros i (Hi, (Hi1, Hi2)). +case Zle_lt_or_eq with (1 := Hi); clear Hi; intros Hi. +assert (Hpi: 0 < p ^ i). +apply Zpower_gt_0; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +rewrite (Z_div_exact_2 m (p ^ i)); auto with zarith. +apply H1; auto with zarith. +apply rel_prime_sym; apply rel_prime_Zpower_r; auto with zarith. +apply rel_prime_sym. +apply prime_rel_prime; auto. +contradict Hi2. +case Hi1; intros; subst. +rewrite Z_div_mult in Hi2; auto with zarith. +case Hi2; intros q0 Hq0; subst. +exists q0; rewrite Zpower_exp; try rewrite Zpower_1_r; auto with zarith. +apply H; auto with zarith. +apply Zdivide_trans with (1 := Hi1); auto. +apply Rec; auto with zarith. +split; auto with zarith. +apply Z_div_pos; auto with zarith. +apply Z_div_lt; auto with zarith. +apply Zle_ge; apply Zle_trans with p. +apply prime_ge_2; auto. +pattern p at 1; rewrite <- Zpower_1_r; apply Zpower_le_monotone; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +apply Z_div_pos; auto with zarith. +apply Zdivide_trans with (2 := H2); auto. +exists (p ^ i); apply Z_div_exact_2; auto with zarith. +apply Zdivide_mod; auto with zarith. +apply Zdivide_mod; auto with zarith. +case Hi2; rewrite <- Hi; rewrite Zplus_0_r; rewrite Zpower_1_r; auto. +Qed. + +Theorem prime_div_Zpower_prime: forall n p q, 0 <= n -> prime p -> prime q -> (p | q ^ n) -> p = q. +intros n p q Hp Hq; generalize p q Hq; pattern n; apply natlike_ind; auto; clear n p q Hp Hq. +intros p q Hp Hq; rewrite Zpower_0_r. +intros (r, H); subst. +case (Zmult_interval p r); auto; try rewrite Zmult_comm. +rewrite <- H; auto with zarith. +apply Zlt_le_trans with 2; try apply prime_ge_2; auto with zarith. +rewrite <- H; intros H1 H2; contradict H2; auto with zarith. +intros n1 H Rec p q Hp Hq; try rewrite Zpower_Zsucc; auto with zarith; intros H1. +case prime_mult with (2 := H1); auto. +intros H2; apply prime_div_prime; auto. +Qed. + +Definition Zmodd a b := +match a with +| Z0 => 0 +| Zpos a' => + match b with + | Z0 => 0 + | Zpos _ => Zmod_POS a' b + | Zneg b' => + let r := Zmod_POS a' (Zpos b') in + match r with Z0 => 0 | _ => b + r end + end +| Zneg a' => + match b with + | Z0 => 0 + | Zpos _ => + let r := Zmod_POS a' b in + match r with Z0 => 0 | _ => b - r end + | Zneg b' => - (Zmod_POS a' (Zpos b')) + end +end. + +Theorem Zmodd_correct: forall a b, Zmodd a b = Zmod a b. +intros a b; unfold Zmod; case a; simpl; auto. +intros p; case b; simpl; auto. +intros p1; refine (Zmod_POS_correct _ _); auto. +intros p1; rewrite Zmod_POS_correct; auto. +case (Zdiv_eucl_POS p (Zpos p1)); simpl; intros z1 z2; case z2; auto. +intros p; case b; simpl; auto. +intros p1; rewrite Zmod_POS_correct; auto. +case (Zdiv_eucl_POS p (Zpos p1)); simpl; intros z1 z2; case z2; auto. +intros p1; rewrite Zmod_POS_correct; simpl; auto. +case (Zdiv_eucl_POS p (Zpos p1)); auto. +Qed. + +Theorem prime_divide_prime_eq: + forall p1 p2, prime p1 -> prime p2 -> Zdivide p1 p2 -> p1 = p2. +intros p1 p2 Hp1 Hp2 Hp3. +assert (Ha: 1 < p1). +inversion Hp1; auto. +assert (Ha1: 1 < p2). +inversion Hp2; auto. +case (Zle_lt_or_eq p1 p2); auto with zarith. +apply Zdivide_le; auto with zarith. +intros Hp4. +case (prime_div_prime p1 p2); auto with zarith. +Qed. + +Theorem Zdivide_Zpower: forall n m, 0 < n -> (forall p i, prime p -> 0 < i -> (p^i | n) -> (p^i | m)) -> (n | m). +intros n m Hn; generalize m Hn; pattern n; apply prime_induction; auto with zarith; clear n m Hn. +intros m H1; contradict H1; auto with zarith. +intros p q H Rec m H1 H2. +assert (H3: (p | m)). +rewrite <- (Zpower_1_r p); apply H2; auto with zarith; rewrite Zpower_1_r; apply Zdivide_factor_r. +case (Zmult_interval p q); auto. +apply Zlt_le_trans with 2; auto with zarith; apply prime_ge_2; auto. +case H3; intros k Hk; subst. +intros Hq Hq1. +rewrite (Zmult_comm k); apply Zmult_divide_compat_l. +apply Rec; auto. +intros p1 i Hp1 Hp2 Hp3. +case (Z_eq_dec p p1); intros Hpp1; subst. +case (H2 p1 (Zsucc i)); auto with zarith. +rewrite Zpower_Zsucc; try apply Zmult_divide_compat_l; auto with zarith. +intros q2 Hq2; exists q2. +apply Zmult_reg_r with p1. +contradict H; subst; apply not_prime_0. +rewrite Hq2; rewrite Zpower_Zsucc; try ring; auto with zarith. +apply Gauss with p. +rewrite Zmult_comm; apply H2; auto. +apply Zdivide_trans with (1:= Hp3). +apply Zdivide_factor_l. +apply rel_prime_sym; apply rel_prime_Zpower_r; auto with zarith. +apply prime_rel_prime; auto. +contradict Hpp1; apply prime_divide_prime_eq; auto. +Qed. + +Theorem prime_divide_Zpower_Zdiv: forall m a p i, 0 <= i -> prime p -> (m | a) -> ~(m | (a/p)) -> (p^i | a) -> (p^i | m). +intros m a p i Hi Hp (k, Hk) H (l, Hl); subst. +case (Zle_lt_or_eq 0 i); auto with arith; intros Hi1; subst. +assert (Hp0: 0 < p). +apply Zlt_le_trans with 2; auto with zarith; apply prime_ge_2; auto. +case (Zdivide_dec p k); intros H1. +case H1; intros k' H2; subst. +case H; replace (k' * p * m) with ((k' * m) * p); try ring; rewrite Z_div_mult; auto with zarith. +apply Gauss with k. +exists l; rewrite Hl; ring. +apply rel_prime_sym; apply rel_prime_Zpower_r; auto. +apply rel_prime_sym; apply prime_rel_prime; auto. +rewrite Zpower_0_r; apply Zone_divide. +Qed. + +Theorem Zle_square_mult: forall a b, 0 <= a <= b -> a * a <= b * b. +intros a b (H1, H2); apply Zle_trans with (a * b); auto with zarith. +Qed. + +Theorem Zlt_square_mult_inv: forall a b, 0 <= a -> 0 <= b -> a * a < b * b -> a < b. +intros a b H1 H2 H3; case (Zle_or_lt b a); auto; intros H4; apply Zmult_lt_reg_r with a; + contradict H3; apply Zle_not_lt; apply Zle_square_mult; auto. +Qed. + + +Theorem Zmod_closeby_eq: forall a b n, 0 <= a -> 0 <= b < n -> a - b < n -> a mod n = b -> a = b. +intros a b n H H1 H2 H3. +case (Zle_or_lt 0 (a - b)); intros H4. +case Zle_lt_or_eq with (1 := H4); clear H4; intros H4; auto with zarith. +contradict H2; apply Zle_not_lt; apply Zdivide_le; auto with zarith. +apply Zmod_divide_minus; auto with zarith. +rewrite <- (Zmod_small a n); try split; auto with zarith. +Qed. + + +Theorem Zpow_mod_pos_Zpower_pos_correct: forall a m n, 0 < n -> Zpow_mod_pos a m n = (Zpower_pos a m) mod n. +intros a m; elim m; simpl; auto. +intros p Rec n H1; rewrite xI_succ_xO; rewrite Pplus_one_succ_r; rewrite <- Pplus_diag; auto. +repeat rewrite Zpower_pos_is_exp; auto. +repeat rewrite Rec; auto. +replace (Zpower_pos a 1) with a; auto. +2: unfold Zpower_pos; simpl; auto with zarith. +repeat rewrite (fun x => (Zmult_mod x a)); auto. +rewrite (Zmult_mod (Zpower_pos a p)); auto. +case (Zpower_pos a p mod n); auto. +intros p Rec n H1; rewrite <- Pplus_diag; auto. +repeat rewrite Zpower_pos_is_exp; auto. +repeat rewrite Rec; auto. +rewrite (Zmult_mod (Zpower_pos a p)); auto. +case (Zpower_pos a p mod n); auto. +unfold Zpower_pos; simpl; rewrite Zmult_1_r; auto with zarith. +Qed. + +Theorem Zpow_mod_Zpower_correct: forall a m n, 1 < n -> 0 <= m -> Zpow_mod a m n = (a ^ m) mod n. +intros a m n; case m; simpl; auto. +intros; apply Zpow_mod_pos_Zpower_pos_correct; auto with zarith. +Qed. diff --git a/coqprime-8.5/Coqprime/ZCmisc.v b/coqprime-8.5/Coqprime/ZCmisc.v new file mode 100644 index 000000000..c1bdacc63 --- /dev/null +++ b/coqprime-8.5/Coqprime/ZCmisc.v @@ -0,0 +1,186 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Export ZArith. +Open Local Scope Z_scope. + +Coercion Zpos : positive >-> Z. +Coercion Z_of_N : N >-> Z. + +Lemma Zpos_plus : forall p q, Zpos (p + q) = p + q. +Proof. intros;trivial. Qed. + +Lemma Zpos_mult : forall p q, Zpos (p * q) = p * q. +Proof. intros;trivial. Qed. + +Lemma Zpos_xI_add : forall p, Zpos (xI p) = Zpos p + Zpos p + Zpos 1. +Proof. intros p;rewrite Zpos_xI;ring. Qed. + +Lemma Zpos_xO_add : forall p, Zpos (xO p) = Zpos p + Zpos p. +Proof. intros p;rewrite Zpos_xO;ring. Qed. + +Lemma Psucc_Zplus : forall p, Zpos (Psucc p) = p + 1. +Proof. intros p;rewrite Zpos_succ_morphism;unfold Zsucc;trivial. Qed. + +Hint Rewrite Zpos_xI_add Zpos_xO_add Pplus_carry_spec + Psucc_Zplus Zpos_plus : zmisc. + +Lemma Zlt_0_pos : forall p, 0 < Zpos p. +Proof. unfold Zlt;trivial. Qed. + + +Lemma Pminus_mask_carry_spec : forall p q, + Pminus_mask_carry p q = Pminus_mask p (Psucc q). +Proof. + intros p q;generalize q p;clear q p. + induction q;destruct p;simpl;try rewrite IHq;trivial. + destruct p;trivial. destruct p;trivial. +Qed. + +Hint Rewrite Pminus_mask_carry_spec : zmisc. + +Ltac zsimpl := autorewrite with zmisc. +Ltac CaseEq t := generalize (refl_equal t);pattern t at -1;case t. +Ltac generalizeclear H := generalize H;clear H. + +Lemma Pminus_mask_spec : + forall p q, + match Pminus_mask p q with + | IsNul => Zpos p = Zpos q + | IsPos k => Zpos p = q + k + | IsNeq => p < q + end. +Proof with zsimpl;auto with zarith. + induction p;destruct q;simpl;zsimpl; + match goal with + | [|- context [(Pminus_mask ?p1 ?q1)]] => + assert (H1 := IHp q1);destruct (Pminus_mask p1 q1) + | _ => idtac + end;simpl ... + inversion H1 ... inversion H1 ... + rewrite Psucc_Zplus in H1 ... + clear IHp;induction p;simpl ... + rewrite IHp;destruct (Pdouble_minus_one p) ... + assert (H:= Zlt_0_pos q) ... assert (H:= Zlt_0_pos q) ... +Qed. + +Definition PminusN x y := + match Pminus_mask x y with + | IsPos k => Npos k + | _ => N0 + end. + +Lemma PminusN_le : forall x y:positive, x <= y -> Z_of_N (PminusN y x) = y - x. +Proof. + intros x y Hle;unfold PminusN. + assert (H := Pminus_mask_spec y x);destruct (Pminus_mask y x). + rewrite H;unfold Z_of_N;auto with zarith. + rewrite H;unfold Z_of_N;auto with zarith. + elimtype False;omega. +Qed. + +Lemma Ppred_Zminus : forall p, 1< Zpos p -> (p-1)%Z = Ppred p. +Proof. destruct p;simpl;trivial. intros;elimtype False;omega. Qed. + + +Open Local Scope positive_scope. + +Delimit Scope P_scope with P. +Open Local Scope P_scope. + +Definition is_lt (n m : positive) := + match (n ?= m) with + | Lt => true + | _ => false + end. +Infix "?<" := is_lt (at level 70, no associativity) : P_scope. + +Lemma is_lt_spec : forall n m, if n ?< m then (n < m)%Z else (m <= n)%Z. +Proof. +intros n m; unfold is_lt, Zlt, Zle, Zcompare. +rewrite Pos.compare_antisym. +case (m ?= n); simpl; auto; intros HH; discriminate HH. +Qed. + +Definition is_eq a b := + match (a ?= b) with + | Eq => true + | _ => false + end. +Infix "?=" := is_eq (at level 70, no associativity) : P_scope. + +Lemma is_eq_refl : forall n, n ?= n = true. +Proof. intros n;unfold is_eq;rewrite Pos.compare_refl;trivial. Qed. + +Lemma is_eq_eq : forall n m, n ?= m = true -> n = m. +Proof. + unfold is_eq;intros n m H; apply Pos.compare_eq. +destruct (n ?= m)%positive;trivial;try discriminate. +Qed. + +Lemma is_eq_spec_pos : forall n m, if n ?= m then n = m else m <> n. +Proof. + intros n m; CaseEq (n ?= m);intro H. + rewrite (is_eq_eq _ _ H);trivial. + intro H1;rewrite H1 in H;rewrite is_eq_refl in H;discriminate H. +Qed. + +Lemma is_eq_spec : forall n m, if n ?= m then Zpos n = m else Zpos m <> n. +Proof. + intros n m; CaseEq (n ?= m);intro H. + rewrite (is_eq_eq _ _ H);trivial. + intro H1;inversion H1. + rewrite H2 in H;rewrite is_eq_refl in H;discriminate H. +Qed. + +Definition is_Eq a b := + match a, b with + | N0, N0 => true + | Npos a', Npos b' => a' ?= b' + | _, _ => false + end. + +Lemma is_Eq_spec : + forall n m, if is_Eq n m then Z_of_N n = m else Z_of_N m <> n. +Proof. + destruct n;destruct m;simpl;trivial;try (intro;discriminate). + apply is_eq_spec. +Qed. + +(* [times x y] return [x * y], a litle bit more efficiant *) +Fixpoint times (x y : positive) {struct y} : positive := + match x, y with + | xH, _ => y + | _, xH => x + | xO x', xO y' => xO (xO (times x' y')) + | xO x', xI y' => xO (x' + xO (times x' y')) + | xI x', xO y' => xO (y' + xO (times x' y')) + | xI x', xI y' => xI (x' + y' + xO (times x' y')) + end. + +Infix "*" := times : P_scope. + +Lemma times_Zmult : forall p q, Zpos (p * q)%P = (p * q)%Z. +Proof. + intros p q;generalize q p;clear p q. + induction q;destruct p; unfold times; try fold (times p q); + autorewrite with zmisc; try rewrite IHq; ring. +Qed. + +Fixpoint square (x:positive) : positive := + match x with + | xH => xH + | xO x => xO (xO (square x)) + | xI x => xI (xO (square x + x)) + end. + +Lemma square_Zmult : forall x, Zpos (square x) = (x * x) %Z. +Proof. + induction x as [x IHx|x IHx |];unfold square;try (fold (square x)); + autorewrite with zmisc; try rewrite IHx; ring. +Qed. diff --git a/coqprime-8.5/Coqprime/ZProgression.v b/coqprime-8.5/Coqprime/ZProgression.v new file mode 100644 index 000000000..51ce91cdc --- /dev/null +++ b/coqprime-8.5/Coqprime/ZProgression.v @@ -0,0 +1,104 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +Require Export Iterator. +Require Import ZArith. +Require Export UList. +Open Scope Z_scope. + +Theorem next_n_Z: forall n m, next_n Zsucc n m = n + Z_of_nat m. +intros n m; generalize n; elim m; clear n m. +intros n; simpl; auto with zarith. +intros m H n. +replace (n + Z_of_nat (S m)) with (Zsucc n + Z_of_nat m); auto with zarith. +rewrite <- H; auto with zarith. +rewrite inj_S; auto with zarith. +Qed. + +Theorem Zprogression_end: + forall n m, + progression Zsucc n (S m) = + app (progression Zsucc n m) (cons (n + Z_of_nat m) nil). +intros n m; generalize n; elim m; clear n m. +simpl; intros; apply f_equal2 with ( f := @cons Z ); auto with zarith. +intros m1 Hm1 n1. +apply trans_equal with (cons n1 (progression Zsucc (Zsucc n1) (S m1))); auto. +rewrite Hm1. +replace (Zsucc n1 + Z_of_nat m1) with (n1 + Z_of_nat (S m1)); auto with zarith. +replace (Z_of_nat (S m1)) with (1 + Z_of_nat m1); auto with zarith. +rewrite inj_S; auto with zarith. +Qed. + +Theorem Zprogression_pred_end: + forall n m, + progression Zpred n (S m) = + app (progression Zpred n m) (cons (n - Z_of_nat m) nil). +intros n m; generalize n; elim m; clear n m. +simpl; intros; apply f_equal2 with ( f := @cons Z ); auto with zarith. +intros m1 Hm1 n1. +apply trans_equal with (cons n1 (progression Zpred (Zpred n1) (S m1))); auto. +rewrite Hm1. +replace (Zpred n1 - Z_of_nat m1) with (n1 - Z_of_nat (S m1)); auto with zarith. +replace (Z_of_nat (S m1)) with (1 + Z_of_nat m1); auto with zarith. +rewrite inj_S; auto with zarith. +Qed. + +Theorem Zprogression_opp: + forall n m, + rev (progression Zsucc n m) = progression Zpred (n + Z_of_nat (pred m)) m. +intros n m; generalize n; elim m; clear n m. +simpl; auto. +intros m Hm n. +rewrite (Zprogression_end n); auto. +rewrite distr_rev. +rewrite Hm; simpl; auto. +case m. +simpl; auto. +intros m1; + replace (n + Z_of_nat (pred (S m1))) with (Zpred (n + Z_of_nat (S m1))); auto. +rewrite inj_S; simpl; (unfold Zpred; unfold Zsucc); auto with zarith. +Qed. + +Theorem Zprogression_le_init: + forall n m p, In p (progression Zsucc n m) -> (n <= p). +intros n m; generalize n; elim m; clear n m; simpl; auto. +intros; contradiction. +intros m H n p [H1|H1]; auto with zarith. +generalize (H _ _ H1); auto with zarith. +Qed. + +Theorem Zprogression_le_end: + forall n m p, In p (progression Zsucc n m) -> (p < n + Z_of_nat m). +intros n m; generalize n; elim m; clear n m; auto. +intros; contradiction. +intros m H n p H1; simpl in H1 |-; case H1; clear H1; intros H1; + auto with zarith. +subst n; auto with zarith. +apply Zle_lt_trans with (p + 0); auto with zarith. +apply Zplus_lt_compat_l; red; simpl; auto with zarith. +apply Zlt_le_trans with (Zsucc n + Z_of_nat m); auto with zarith. +rewrite inj_S; rewrite Zplus_succ_comm; auto with zarith. +Qed. + +Theorem ulist_Zprogression: forall a n, ulist (progression Zsucc a n). +intros a n; generalize a; elim n; clear a n; simpl; auto with zarith. +intros n H1 a; apply ulist_cons; auto. +intros H2; absurd (Zsucc a <= a); auto with zarith. +apply Zprogression_le_init with ( 1 := H2 ). +Qed. + +Theorem in_Zprogression: + forall a b n, ( a <= b < a + Z_of_nat n ) -> In b (progression Zsucc a n). +intros a b n; generalize a b; elim n; clear a b n; auto with zarith. +simpl; auto with zarith. +intros n H a b. +replace (a + Z_of_nat (S n)) with (Zsucc a + Z_of_nat n); auto with zarith. +intros [H1 H2]; simpl; auto with zarith. +case (Zle_lt_or_eq _ _ H1); auto with zarith. +rewrite inj_S; auto with zarith. +Qed. diff --git a/coqprime-8.5/Coqprime/ZSum.v b/coqprime-8.5/Coqprime/ZSum.v new file mode 100644 index 000000000..3a7f14065 --- /dev/null +++ b/coqprime-8.5/Coqprime/ZSum.v @@ -0,0 +1,335 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(*********************************************************************** + Summation.v from Z to Z + *********************************************************************) +Require Import Arith. +Require Import ArithRing. +Require Import ListAux. +Require Import ZArith. +Require Import Iterator. +Require Import ZProgression. + + +Open Scope Z_scope. +(* Iterated Sum *) + +Definition Zsum := + fun n m f => + if Zle_bool n m + then iter 0 f Zplus (progression Zsucc n (Zabs_nat ((1 + m) - n))) + else iter 0 f Zplus (progression Zpred n (Zabs_nat ((1 + n) - m))). +Hint Unfold Zsum . + +Lemma Zsum_nn: forall n f, Zsum n n f = f n. +intros n f; unfold Zsum; rewrite Zle_bool_refl. +replace ((1 + n) - n) with 1; auto with zarith. +simpl; ring. +Qed. + +Theorem permutation_rev: forall (A:Set) (l : list A), permutation (rev l) l. +intros a l; elim l; simpl; auto. +intros a1 l1 Hl1. +apply permutation_trans with (cons a1 (rev l1)); auto. +change (permutation (rev l1 ++ (a1 :: nil)) (app (cons a1 nil) (rev l1))); auto. +Qed. + +Lemma Zsum_swap: forall (n m : Z) (f : Z -> Z), Zsum n m f = Zsum m n f. +intros n m f; unfold Zsum. +generalize (Zle_cases n m) (Zle_cases m n); case (Zle_bool n m); + case (Zle_bool m n); auto with arith. +intros; replace n with m; auto with zarith. +3:intros H1 H2; contradict H2; auto with zarith. +intros H1 H2; apply iter_permutation; auto with zarith. +apply permutation_trans + with (rev (progression Zsucc n (Zabs_nat ((1 + m) - n)))). +apply permutation_sym; apply permutation_rev. +rewrite Zprogression_opp; auto with zarith. +replace (n + Z_of_nat (pred (Zabs_nat ((1 + m) - n)))) with m; auto. +replace (Zabs_nat ((1 + m) - n)) with (S (Zabs_nat (m - n))); auto with zarith. +simpl. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +replace ((1 + m) - n) with (1 + (m - n)); auto with zarith. +cut (0 <= m - n); auto with zarith; unfold Zabs_nat. +case (m - n); auto with zarith. +intros p; case p; simpl; auto with zarith. +intros p1 Hp1; rewrite nat_of_P_xO; rewrite nat_of_P_xI; + rewrite nat_of_P_succ_morphism. +simpl; repeat rewrite plus_0_r. +repeat rewrite <- plus_n_Sm; simpl; auto. +intros p H3; contradict H3; auto with zarith. +intros H1 H2; apply iter_permutation; auto with zarith. +apply permutation_trans + with (rev (progression Zsucc m (Zabs_nat ((1 + n) - m)))). +rewrite Zprogression_opp; auto with zarith. +replace (m + Z_of_nat (pred (Zabs_nat ((1 + n) - m)))) with n; auto. +replace (Zabs_nat ((1 + n) - m)) with (S (Zabs_nat (n - m))); auto with zarith. +simpl. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +replace ((1 + n) - m) with (1 + (n - m)); auto with zarith. +cut (0 <= n - m); auto with zarith; unfold Zabs_nat. +case (n - m); auto with zarith. +intros p; case p; simpl; auto with zarith. +intros p1 Hp1; rewrite nat_of_P_xO; rewrite nat_of_P_xI; + rewrite nat_of_P_succ_morphism. +simpl; repeat rewrite plus_0_r. +repeat rewrite <- plus_n_Sm; simpl; auto. +intros p H3; contradict H3; auto with zarith. +apply permutation_rev. +Qed. + +Lemma Zsum_split_up: + forall (n m p : Z) (f : Z -> Z), + ( n <= m < p ) -> Zsum n p f = Zsum n m f + Zsum (m + 1) p f. +intros n m p f [H H0]. +case (Zle_lt_or_eq _ _ H); clear H; intros H. +unfold Zsum; (repeat rewrite Zle_imp_le_bool); auto with zarith. +assert (H1: n < p). +apply Zlt_trans with ( 1 := H ); auto with zarith. +assert (H2: m < 1 + p). +apply Zlt_trans with ( 1 := H0 ); auto with zarith. +assert (H3: n < 1 + m). +apply Zlt_trans with ( 1 := H ); auto with zarith. +assert (H4: n < 1 + p). +apply Zlt_trans with ( 1 := H1 ); auto with zarith. +replace (Zabs_nat ((1 + p) - (m + 1))) + with (minus (Zabs_nat ((1 + p) - n)) (Zabs_nat ((1 + m) - n))). +apply iter_progression_app; auto with zarith. +apply inj_le_rev. +(repeat rewrite inj_Zabs_nat); auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +rewrite next_n_Z; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply inj_eq_rev; auto with zarith. +rewrite inj_minus1; auto with zarith. +(repeat rewrite inj_Zabs_nat); auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +apply inj_le_rev. +(repeat rewrite inj_Zabs_nat); auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +subst m. +rewrite Zsum_nn; auto with zarith. +unfold Zsum; generalize (Zle_cases n p); generalize (Zle_cases (n + 1) p); + case (Zle_bool n p); case (Zle_bool (n + 1) p); auto with zarith. +intros H1 H2. +replace (Zabs_nat ((1 + p) - n)) with (S (Zabs_nat (p - n))); auto with zarith. +replace (n + 1) with (Zsucc n); auto with zarith. +replace ((1 + p) - Zsucc n) with (p - n); auto with zarith. +apply inj_eq_rev; auto with zarith. +rewrite inj_S; (repeat rewrite inj_Zabs_nat); auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +Qed. + +Lemma Zsum_S_left: + forall (n m : Z) (f : Z -> Z), n < m -> Zsum n m f = f n + Zsum (n + 1) m f. +intros n m f H; rewrite (Zsum_split_up n n m f); auto with zarith. +rewrite Zsum_nn; auto with zarith. +Qed. + +Lemma Zsum_S_right: + forall (n m : Z) (f : Z -> Z), + n <= m -> Zsum n (m + 1) f = Zsum n m f + f (m + 1). +intros n m f H; rewrite (Zsum_split_up n m (m + 1) f); auto with zarith. +rewrite Zsum_nn; auto with zarith. +Qed. + +Lemma Zsum_split_down: + forall (n m p : Z) (f : Z -> Z), + ( p < m <= n ) -> Zsum n p f = Zsum n m f + Zsum (m - 1) p f. +intros n m p f [H H0]. +case (Zle_lt_or_eq p (m - 1)); auto with zarith; intros H1. +pattern m at 1; replace m with ((m - 1) + 1); auto with zarith. +repeat rewrite (Zsum_swap n). +rewrite (Zsum_swap (m - 1)). +rewrite Zplus_comm. +apply Zsum_split_up; auto with zarith. +subst p. +repeat rewrite (Zsum_swap n). +rewrite Zsum_nn. +unfold Zsum; (repeat rewrite Zle_imp_le_bool); auto with zarith. +replace (Zabs_nat ((1 + n) - (m - 1))) with (S (Zabs_nat (n - (m - 1)))). +rewrite Zplus_comm. +replace (Zabs_nat ((1 + n) - m)) with (Zabs_nat (n - (m - 1))); auto with zarith. +pattern m at 4; replace m with (Zsucc (m - 1)); auto with zarith. +apply f_equal with ( f := Zabs_nat ); auto with zarith. +apply inj_eq_rev; auto with zarith. +rewrite inj_S. +(repeat rewrite inj_Zabs_nat); auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +Qed. + + +Lemma Zsum_ext: + forall (n m : Z) (f g : Z -> Z), + n <= m -> + (forall (x : Z), ( n <= x <= m ) -> f x = g x) -> Zsum n m f = Zsum n m g. +intros n m f g HH H. +unfold Zsum; auto. +unfold Zsum; (repeat rewrite Zle_imp_le_bool); auto with zarith. +apply iter_ext; auto with zarith. +intros a H1; apply H; auto; split. +apply Zprogression_le_init with ( 1 := H1 ). +cut (a < Zsucc m); auto with zarith. +replace (Zsucc m) with (n + Z_of_nat (Zabs_nat ((1 + m) - n))); auto with zarith. +apply Zprogression_le_end; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +Qed. + +Lemma Zsum_add: + forall (n m : Z) (f g : Z -> Z), + Zsum n m f + Zsum n m g = Zsum n m (fun (i : Z) => f i + g i). +intros n m f g; unfold Zsum; case (Zle_bool n m); apply iter_comp; + auto with zarith. +Qed. + +Lemma Zsum_times: + forall n m x f, x * Zsum n m f = Zsum n m (fun i=> x * f i). +intros n m x f. +unfold Zsum. case (Zle_bool n m); intros; apply iter_comp_const with (k := (fun y : Z => x * y)); auto with zarith. +Qed. + +Lemma inv_Zsum: + forall (P : Z -> Prop) (n m : Z) (f : Z -> Z), + n <= m -> + P 0 -> + (forall (a b : Z), P a -> P b -> P (a + b)) -> + (forall (x : Z), ( n <= x <= m ) -> P (f x)) -> P (Zsum n m f). +intros P n m f HH H H0 H1. +unfold Zsum; rewrite Zle_imp_le_bool; auto with zarith; apply iter_inv; auto. +intros x H3; apply H1; auto; split. +apply Zprogression_le_init with ( 1 := H3 ). +cut (x < Zsucc m); auto with zarith. +replace (Zsucc m) with (n + Z_of_nat (Zabs_nat ((1 + m) - n))); auto with zarith. +apply Zprogression_le_end; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +(repeat rewrite Zabs_eq); auto with zarith. +Qed. + + +Lemma Zsum_pred: + forall (n m : Z) (f : Z -> Z), + Zsum n m f = Zsum (n + 1) (m + 1) (fun (i : Z) => f (Zpred i)). +intros n m f. +unfold Zsum. +generalize (Zle_cases n m); generalize (Zle_cases (n + 1) (m + 1)); + case (Zle_bool n m); case (Zle_bool (n + 1) (m + 1)); auto with zarith. +replace ((1 + (m + 1)) - (n + 1)) with ((1 + m) - n); auto with zarith. +intros H1 H2; cut (exists c , c = Zabs_nat ((1 + m) - n) ). +intros [c H3]; rewrite <- H3. +generalize n; elim c; auto with zarith; clear H1 H2 H3 c n. +intros c H n; simpl; eq_tac; auto with zarith. +eq_tac; unfold Zpred; auto with zarith. +replace (Zsucc (n + 1)) with (Zsucc n + 1); auto with zarith. +exists (Zabs_nat ((1 + m) - n)); auto. +replace ((1 + (n + 1)) - (m + 1)) with ((1 + n) - m); auto with zarith. +intros H1 H2; cut (exists c , c = Zabs_nat ((1 + n) - m) ). +intros [c H3]; rewrite <- H3. +generalize n; elim c; auto with zarith; clear H1 H2 H3 c n. +intros c H n; simpl; (eq_tac; auto with zarith). +eq_tac; unfold Zpred; auto with zarith. +replace (Zpred (n + 1)) with (Zpred n + 1); auto with zarith. +unfold Zpred; auto with zarith. +exists (Zabs_nat ((1 + n) - m)); auto. +Qed. + +Theorem Zsum_c: + forall (c p q : Z), p <= q -> Zsum p q (fun x => c) = ((1 + q) - p) * c. +intros c p q Hq; unfold Zsum. +rewrite Zle_imp_le_bool; auto with zarith. +pattern ((1 + q) - p) at 2. + rewrite <- Zabs_eq; auto with zarith. + rewrite <- inj_Zabs_nat; auto with zarith. +cut (exists r , r = Zabs_nat ((1 + q) - p) ); + [intros [r H1]; rewrite <- H1 | exists (Zabs_nat ((1 + q) - p))]; auto. +generalize p; elim r; auto with zarith. +intros n H p0; replace (Z_of_nat (S n)) with (Z_of_nat n + 1); auto with zarith. +simpl; rewrite H; ring. +rewrite inj_S; auto with zarith. +Qed. + +Theorem Zsum_Zsum_f: + forall (i j k l : Z) (f : Z -> Z -> Z), + i <= j -> + k < l -> + Zsum i j (fun x => Zsum k (l + 1) (fun y => f x y)) = + Zsum i j (fun x => Zsum k l (fun y => f x y) + f x (l + 1)). +intros; apply Zsum_ext; intros; auto with zarith. +rewrite Zsum_S_right; auto with zarith. +Qed. + +Theorem Zsum_com: + forall (i j k l : Z) (f : Z -> Z -> Z), + Zsum i j (fun x => Zsum k l (fun y => f x y)) = + Zsum k l (fun y => Zsum i j (fun x => f x y)). +intros; unfold Zsum; case (Zle_bool i j); case (Zle_bool k l); apply iter_com; + auto with zarith. +Qed. + +Theorem Zsum_le: + forall (n m : Z) (f g : Z -> Z), + n <= m -> + (forall (x : Z), ( n <= x <= m ) -> (f x <= g x )) -> + (Zsum n m f <= Zsum n m g ). +intros n m f g Hl H. +unfold Zsum; rewrite Zle_imp_le_bool; auto with zarith. +unfold Zsum; + cut + (forall x, + In x (progression Zsucc n (Zabs_nat ((1 + m) - n))) -> ( f x <= g x )). +elim (progression Zsucc n (Zabs_nat ((1 + m) - n))); simpl; auto with zarith. +intros x H1; apply H; split. +apply Zprogression_le_init with ( 1 := H1 ); auto. +cut (x < m + 1); auto with zarith. +replace (m + 1) with (n + Z_of_nat (Zabs_nat ((1 + m) - n))); auto with zarith. +apply Zprogression_le_end; auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem iter_le: +forall (f g: Z -> Z) l, (forall a, In a l -> f a <= g a) -> + iter 0 f Zplus l <= iter 0 g Zplus l. +intros f g l; elim l; simpl; auto with zarith. +Qed. + +Theorem Zsum_lt: + forall n m f g, + (forall x, n <= x -> x <= m -> f x <= g x) -> + (exists x, n <= x /\ x <= m /\ f x < g x) -> + Zsum n m f < Zsum n m g. +intros n m f g H (d, (Hd1, (Hd2, Hd3))); unfold Zsum; rewrite Zle_imp_le_bool; auto with zarith. +cut (In d (progression Zsucc n (Zabs_nat (1 + m - n)))). +cut (forall x, In x (progression Zsucc n (Zabs_nat (1 + m - n)))-> f x <= g x). +elim (progression Zsucc n (Zabs_nat (1 + m - n))); simpl; auto with zarith. +intros a l Rec H0 [H1 | H1]; subst; auto. +apply Zle_lt_trans with (f d + iter 0 g Zplus l); auto with zarith. +apply Zplus_le_compat_l. +apply iter_le; auto. +apply Zlt_le_trans with (f a + iter 0 g Zplus l); auto with zarith. +intros x H1; apply H. +apply Zprogression_le_init with ( 1 := H1 ); auto. +cut (x < m + 1); auto with zarith. +replace (m + 1) with (n + Z_of_nat (Zabs_nat ((1 + m) - n))); auto with zarith. +apply Zprogression_le_end with ( 1 := H1 ); auto with arith. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +apply in_Zprogression. +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem Zsum_minus: + forall n m f g, Zsum n m f - Zsum n m g = Zsum n m (fun x => f x - g x). +intros n m f g; apply trans_equal with (Zsum n m f + (-1) * Zsum n m g); auto with zarith. +rewrite Zsum_times; rewrite Zsum_add; auto with zarith. +Qed. diff --git a/coqprime-8.5/Coqprime/Zp.v b/coqprime-8.5/Coqprime/Zp.v new file mode 100644 index 000000000..1e5295191 --- /dev/null +++ b/coqprime-8.5/Coqprime/Zp.v @@ -0,0 +1,411 @@ + +(*************************************************************) +(* This file is distributed under the terms of the *) +(* GNU Lesser General Public License Version 2.1 *) +(*************************************************************) +(* Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr *) +(*************************************************************) + +(********************************************************************** + Zp.v + + Build the group of the inversible element on {1, 2, .., n-1} + for the multiplication modulo n + + Definition: ZpGroup + **********************************************************************) +Require Import ZArith Znumtheory Zpow_facts. +Require Import Tactic. +Require Import Wf_nat. +Require Import UList. +Require Import FGroup. +Require Import EGroup. +Require Import IGroup. +Require Import Cyclic. +Require Import Euler. +Require Import ZProgression. + +Open Scope Z_scope. + +Section Zp. + +Variable n: Z. + +Hypothesis n_pos: 1 < n. + + +(************************************** + mkZp m creates {m, m - 1, ..., 0} + **************************************) + +Fixpoint mkZp_aux (m: nat): list Z:= + Z_of_nat m :: match m with O => nil | (S m1) => mkZp_aux m1 end. + +(************************************** + Some properties of mkZp_aux + **************************************) + +Theorem mkZp_aux_length: forall m, length (mkZp_aux m) = (m + 1)%nat. +intros m; elim m; simpl; auto. +Qed. + +Theorem mkZp_aux_in: forall m p, 0 <= p <= Z_of_nat m -> In p (mkZp_aux m). +intros m; elim m. +simpl; auto with zarith. +intros n1 Rec p (H1, H2); case Zle_lt_or_eq with (1 := H2); clear H2; intro H2. +rewrite inj_S in H2. +simpl; right; apply Rec; split; auto with zarith. +rewrite H2; simpl; auto. +Qed. + +Theorem in_mkZp_aux: forall m p, In p (mkZp_aux m) -> 0 <= p <= Z_of_nat m. +intros m; elim m; clear m. +simpl; intros p H1; case H1; clear H1; intros H1; subst; auto with zarith. +intros m1; generalize (inj_S m1); simpl. +intros H Rec p [H1 | H1]. +rewrite <- H1; rewrite H; auto with zarith. +rewrite H; case (Rec p); auto with zarith. +Qed. + +Theorem mkZp_aux_ulist: forall m, ulist (mkZp_aux m). +intros m; elim m; simpl; auto. +intros m1 H; apply ulist_cons; auto. +change (~ In (Z_of_nat (S m1)) (mkZp_aux m1)). +rewrite inj_S; intros H1. +case in_mkZp_aux with (1 := H1); auto with zarith. +Qed. + +(************************************** + mkZp creates {n - 1, ..., 1, 0} + **************************************) + +Definition mkZp := mkZp_aux (Zabs_nat (n - 1)). + +(************************************** + Some properties of mkZp + **************************************) + +Theorem mkZp_length: length mkZp = Zabs_nat n. +unfold mkZp; rewrite mkZp_aux_length. +apply inj_eq_rev. +rewrite inj_plus. +simpl; repeat rewrite inj_Zabs_nat; auto with zarith. +repeat rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem mkZp_in: forall p, 0 <= p < n -> In p mkZp. +intros p (H1, H2); unfold mkZp; apply mkZp_aux_in. +rewrite inj_Zabs_nat; auto with zarith. +repeat rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem in_mkZp: forall p, In p mkZp -> 0 <= p < n. +intros p H; case (in_mkZp_aux (Zabs_nat (n - 1)) p); auto with zarith. +rewrite inj_Zabs_nat; auto with zarith. +repeat rewrite Zabs_eq; auto with zarith. +Qed. + +Theorem mkZp_ulist: ulist mkZp. +unfold mkZp; apply mkZp_aux_ulist; auto. +Qed. + +(************************************** + Multiplication of two pairs + **************************************) + +Definition pmult (p q: Z) := (p * q) mod n. + +(************************************** + Properties of multiplication + **************************************) + +Theorem pmult_assoc: forall p q r, (pmult p (pmult q r)) = (pmult (pmult p q) r). +assert (Hu: 0 < n); try apply Zlt_trans with 1; auto with zarith. +generalize Zmod_mod; intros H. +intros p q r; unfold pmult. +rewrite (Zmult_mod p); auto. +repeat rewrite Zmod_mod; auto. +rewrite (Zmult_mod q); auto. +rewrite <- Zmult_mod; auto. +rewrite Zmult_assoc. +rewrite (Zmult_mod (p * (q mod n))); auto. +rewrite (Zmult_mod ((p * q) mod n)); auto. +eq_tac; auto. +eq_tac; auto. +rewrite (Zmult_mod p); sauto. +rewrite Zmod_mod; auto. +rewrite <- Zmult_mod; sauto. +Qed. + +Theorem pmult_1_l: forall p, In p mkZp -> pmult 1 p = p. +intros p H; unfold pmult; rewrite Zmult_1_l. +apply Zmod_small. +case (in_mkZp p); auto with zarith. +Qed. + +Theorem pmult_1_r: forall p, In p mkZp -> pmult p 1 = p. +intros p H; unfold pmult; rewrite Zmult_1_r. +apply Zmod_small. +case (in_mkZp p); auto with zarith. +Qed. + +Theorem pmult_comm: forall p q, pmult p q = pmult q p. +intros p q; unfold pmult; rewrite Zmult_comm; auto. +Qed. + +Definition Lrel := isupport_aux _ pmult mkZp 1 Z_eq_dec (progression Zsucc 0 (Zabs_nat n)). + +Theorem rel_prime_is_inv: + forall a, is_inv Z pmult mkZp 1 Z_eq_dec a = if (rel_prime_dec a n) then true else false. +assert (Hu: 0 < n); try apply Zlt_trans with 1; auto with zarith. +intros a; case (rel_prime_dec a n); intros H. +assert (H1: Bezout a n 1); try apply rel_prime_bezout; auto. +inversion H1 as [c d Hcd]; clear H1. +assert (pmult (c mod n) a = 1). +unfold pmult; rewrite Zmult_mod; try rewrite Zmod_mod; auto. +rewrite <- Zmult_mod; auto. +replace (c * a) with (1 + (-d) * n). +rewrite Z_mod_plus; auto with zarith. +rewrite Zmod_small; auto with zarith. +rewrite <- Hcd; ring. +apply is_inv_true with (a := (c mod n)); auto. +apply mkZp_in; auto with zarith. +exact pmult_1_l. +exact pmult_1_r. +rewrite pmult_comm; auto. +apply mkZp_in; auto with zarith. +apply Z_mod_lt; auto with zarith. +apply is_inv_false. +intros c H1; left; intros H2; contradict H. +apply bezout_rel_prime. +apply Bezout_intro with c (- (Zdiv (c * a) n)). +pattern (c * a) at 1; rewrite (Z_div_mod_eq (c * a) n); auto with zarith. +unfold pmult in H2; rewrite (Zmult_comm c); try rewrite H2. +ring. +Qed. + +(************************************** + We are now ready to build our group + **************************************) + +Definition ZPGroup : (FGroup pmult). +apply IGroup with (support := mkZp) (e:= 1). +exact Z_eq_dec. +apply mkZp_ulist. +apply mkZp_in; auto with zarith. +intros a b H1 H2; apply mkZp_in. +unfold pmult; apply Z_mod_lt; auto with zarith. +intros; apply pmult_assoc. +exact pmult_1_l. +exact pmult_1_r. +Defined. + +Theorem in_ZPGroup: forall p, rel_prime p n -> 0 <= p < n -> In p ZPGroup.(s). +intros p H (H1, H2); unfold ZPGroup; simpl. +apply isupport_is_in. +generalize (rel_prime_is_inv p); case (rel_prime_dec p); auto. +apply mkZp_in; auto with zarith. +Qed. + + +Theorem phi_is_length: phi n = Z_of_nat (length Lrel). +assert (Hu: 0 < n); try apply Zlt_trans with 1; auto with zarith. +rewrite phi_def_with_0; auto. +unfold Zsum, Lrel; rewrite Zle_imp_le_bool; auto with zarith. +replace (1 + (n - 1) - 0) with n; auto with zarith. +elim (progression Zsucc 0 (Zabs_nat n)); simpl; auto. +intros a l1 Rec. +rewrite Rec. +rewrite rel_prime_is_inv. +case (rel_prime_dec a n); auto with zarith. +simpl length; rewrite inj_S; auto with zarith. +Qed. + +Theorem phi_is_order: phi n = g_order ZPGroup. +unfold g_order; rewrite phi_is_length. +eq_tac; apply permutation_length. +apply ulist_incl2_permutation. +unfold Lrel; apply isupport_aux_ulist. +apply ulist_Zprogression; auto. +apply ZPGroup.(unique_s). +intros a H; unfold ZPGroup; simpl. +apply isupport_is_in. +unfold Lrel in H; apply isupport_aux_is_inv_true with (1 := H). +apply mkZp_in; auto. +assert (In a (progression Zsucc 0 (Zabs_nat n))). +apply (isupport_aux_incl _ pmult mkZp 1 Z_eq_dec); auto. +split. +apply Zprogression_le_init with (1 := H0). +replace n with (0 + Z_of_nat (Zabs_nat n)). +apply Zprogression_le_end with (1 := H0). +rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +intros a H; unfold Lrel; simpl. +apply isupport_aux_is_in. +simpl in H; apply isupport_is_inv_true with (1 := H). +apply in_Zprogression. +rewrite Zplus_0_l; rewrite inj_Zabs_nat; auto with zarith. +rewrite Zabs_eq; auto with zarith. +assert (In a mkZp). +apply (isupport_aux_incl _ pmult mkZp 1 Z_eq_dec); auto. +apply in_mkZp; auto. +Qed. + +Theorem Zp_cyclic: prime n -> cyclic Z_eq_dec ZPGroup. +intros H1. +unfold ZPGroup, pmult; +generalize (cyclic_field _ (fun x y => (x + y) mod n) (fun x y => (x * y) mod n) (fun x => (-x) mod n) 0); +unfold IA; intros tmp; apply tmp; clear tmp; auto. +intros; discriminate. +apply mkZp_in; auto with zarith. +intros; apply mkZp_in; auto with zarith. +apply Z_mod_lt; auto with zarith. +intros; rewrite Zplus_0_l; auto. +apply Zmod_small; auto. +apply in_mkZp; auto. +intros; rewrite Zplus_comm; auto. +intros a b c Ha Hb Hc. +pattern a at 1; rewrite <- (Zmod_small a n); auto with zarith. +pattern c at 2; rewrite <- (Zmod_small c n); auto with zarith. +repeat rewrite <- Zplus_mod; auto with zarith. +eq_tac; auto with zarith. +apply in_mkZp; auto. +apply in_mkZp; auto. +intros; eq_tac; auto with zarith. +intros a b c Ha Hb Hc. +pattern a at 1; rewrite <- (Zmod_small a n); auto with zarith. +repeat rewrite <- Zmult_mod; auto with zarith. +repeat rewrite <- Zplus_mod; auto with zarith. +eq_tac; auto with zarith. +apply in_mkZp; auto. +intros; apply mkZp_in; apply Z_mod_lt; auto with zarith. +intros a Ha. +pattern a at 1; rewrite <- (Zmod_small a n); auto with zarith. +repeat rewrite <- Zplus_mod; auto with zarith. +rewrite <- (Zmod_small 0 n); auto with zarith. +eq_tac; auto with zarith. +apply in_mkZp; auto. +intros a b Ha Hb H; case (prime_mult n H1 a b). +apply Zmod_divide; auto with zarith. +intros H2; left. +case (Zle_lt_or_eq 0 a); auto. +case (in_mkZp a); auto. +intros H3; absurd (n <= a). +apply Zlt_not_le. +case (in_mkZp a); auto. +apply Zdivide_le; auto with zarith. +intros H2; right. +case (Zle_lt_or_eq 0 b); auto. +case (in_mkZp b); auto. +intros H3; absurd (n <= b). +apply Zlt_not_le. +case (in_mkZp b); auto. +apply Zdivide_le; auto with zarith. +Qed. + +End Zp. + +(* Definition of the order (0 for q < 1) *) + +Definition Zorder: Z -> Z -> Z. +intros p q; case (Z_le_dec q 1); intros H. +exact 0. +refine (e_order Z_eq_dec (p mod q) (ZPGroup q _)); auto with zarith. +Defined. + +Theorem Zorder_pos: forall p n, 0 <= Zorder p n. +intros p n; unfold Zorder. +case (Z_le_dec n 1); auto with zarith. +intros n1. +apply Zlt_le_weak; apply e_order_pos. +Qed. + +Theorem in_mod_ZPGroup + : forall (n : Z) (n_pos : 1 < n) (p : Z), + rel_prime p n -> In (p mod n) (s (ZPGroup n n_pos)). +intros n H p H1. +apply in_ZPGroup; auto. +apply rel_prime_mod; auto with zarith. +apply Z_mod_lt; auto with zarith. +Qed. + + +Theorem Zpower_mod_is_gpow: + forall p q n (Hn: 1 < n), rel_prime p n -> 0 <= q -> p ^ q mod n = gpow (p mod n) (ZPGroup n Hn) q. +intros p q n H Hp H1; generalize H1; pattern q; apply natlike_ind; simpl; auto. +intros _; apply Zmod_small; auto with zarith. +intros n1 Hn1 Rec _; simpl. +generalize (in_mod_ZPGroup _ H _ Hp); intros Hu. +unfold Zsucc; rewrite Zpower_exp; try rewrite Zpower_1_r; auto with zarith. +rewrite gpow_add; auto with zarith. +rewrite gpow_1; auto; rewrite <- Rec; auto. +rewrite Zmult_mod; auto. +Qed. + + +Theorem Zorder_div_power: forall p q n, 1 < n -> rel_prime p n -> p ^ q mod n = 1 -> (Zorder p n | q). +intros p q n H H1 H2. +assert (Hq: 0 <= q). +generalize H2; case q; simpl; auto with zarith. +intros p1 H3; contradict H3; rewrite Zmod_small; auto with zarith. +unfold Zorder; case (Z_le_dec n 1). +intros H3; contradict H; auto with zarith. +intros H3; apply e_order_divide_gpow; auto. +apply in_mod_ZPGroup; auto. +rewrite <- Zpower_mod_is_gpow; auto with zarith. +Qed. + +Theorem Zorder_div: forall p n, prime n -> ~(n | p) -> (Zorder p n | n - 1). +intros p n H; unfold Zorder. +case (Z_le_dec n 1); intros H1 H2. +contradict H1; generalize (prime_ge_2 n H); auto with zarith. +rewrite <- prime_phi_n_minus_1; auto. +match goal with |- context[ZPGroup _ ?H2] => rewrite phi_is_order with (n_pos := H2) end. +apply e_order_divide_g_order; auto. +apply in_mod_ZPGroup; auto. +apply rel_prime_sym; apply prime_rel_prime; auto. +Qed. + + +Theorem Zorder_power_is_1: forall p n, 1 < n -> rel_prime p n -> p ^ (Zorder p n) mod n = 1. +intros p n H H1; unfold Zorder. +case (Z_le_dec n 1); intros H2. +contradict H; auto with zarith. +let x := match goal with |- context[ZPGroup _ ?X] => X end in rewrite Zpower_mod_is_gpow with (Hn := x); auto with zarith. +rewrite gpow_e_order_is_e. +reflexivity. +apply in_mod_ZPGroup; auto. +apply Zlt_le_weak; apply e_order_pos. +Qed. + +Theorem Zorder_power_pos: forall p n, 1 < n -> rel_prime p n -> 0 < Zorder p n. +intros p n H H1; unfold Zorder. +case (Z_le_dec n 1); intros H2. +contradict H; auto with zarith. +apply e_order_pos. +Qed. + +Theorem phi_power_is_1: forall p n, 1 < n -> rel_prime p n -> p ^ (phi n) mod n = 1. +intros p n H H1. +assert (V1:= Zorder_power_pos p n H H1). +assert (H2: (Zorder p n | phi n)). +unfold Zorder. +case (Z_le_dec n 1); intros H2. +contradict H; auto with zarith. +match goal with |- context[ZPGroup n ?H] => +rewrite phi_is_order with (n_pos := H) +end. +apply e_order_divide_g_order. +apply in_mod_ZPGroup; auto. +case H2; clear H2; intros q H2; rewrite H2. +rewrite Zmult_comm. +assert (V2 := (phi_pos _ H)). +assert (V3: 0 <= q). +rewrite H2 in V2. +apply Zlt_le_weak; apply Zmult_lt_0_reg_r with (2 := V2); auto with zarith. +rewrite Zpower_mult; auto with zarith. +rewrite Zpower_mod; auto with zarith. +rewrite Zorder_power_is_1; auto. +rewrite Zpower_1_l; auto with zarith. +apply Zmod_small; auto with zarith. +Qed. diff --git a/coqprime-8.5/Makefile b/coqprime-8.5/Makefile new file mode 100644 index 000000000..c8e44a658 --- /dev/null +++ b/coqprime-8.5/Makefile @@ -0,0 +1,319 @@ +############################################################################# +## v # The Coq Proof Assistant ## +## $@ + printf 'cd "$${DSTROOT}"$(COQLIBINSTALL)/Coqprime && rm -f $(NATIVEFILES1) $(GLOBFILES1) $(VFILES1) $(VOFILES1) && find . -type d -and -empty -delete\ncd "$${DSTROOT}"$(COQLIBINSTALL) && find "Coqprime" -maxdepth 0 -and -empty -exec rmdir -p \{\} \;\n' >> "$@" + printf 'cd "$${DSTROOT}"$(COQDOCINSTALL)/Coqprime \\\n' >> "$@" + printf '&& rm -f $(shell find "html" -maxdepth 1 -and -type f -print)\n' >> "$@" + printf 'cd "$${DSTROOT}"$(COQDOCINSTALL) && find Coqprime/html -maxdepth 0 -and -empty -exec rmdir -p \{\} \;\n' >> "$@" + chmod +x $@ + +uninstall: uninstall_me.sh + sh $< + +.merlin: + @echo 'FLG -rectypes' > .merlin + @echo "B $(COQLIB) kernel" >> .merlin + @echo "B $(COQLIB) lib" >> .merlin + @echo "B $(COQLIB) library" >> .merlin + @echo "B $(COQLIB) parsing" >> .merlin + @echo "B $(COQLIB) pretyping" >> .merlin + @echo "B $(COQLIB) interp" >> .merlin + @echo "B $(COQLIB) printing" >> .merlin + @echo "B $(COQLIB) intf" >> .merlin + @echo "B $(COQLIB) proofs" >> .merlin + @echo "B $(COQLIB) tactics" >> .merlin + @echo "B $(COQLIB) tools" >> .merlin + @echo "B $(COQLIB) toplevel" >> .merlin + @echo "B $(COQLIB) stm" >> .merlin + @echo "B $(COQLIB) grammar" >> .merlin + @echo "B $(COQLIB) config" >> .merlin + +clean:: + rm -f $(OBJFILES) $(OBJFILES:.o=.native) $(NATIVEFILES) + find . -name .coq-native -type d -empty -delete + rm -f $(VOFILES) $(VOFILES:.vo=.vio) $(GFILES) $(VFILES:.v=.v.d) $(VFILES:=.beautified) $(VFILES:=.old) + rm -f all.ps all-gal.ps all.pdf all-gal.pdf all.glob $(VFILES:.v=.glob) $(VFILES:.v=.tex) $(VFILES:.v=.g.tex) all-mli.tex + - rm -rf html mlihtml uninstall_me.sh + +cleanall:: clean + rm -f $(patsubst %.v,.%.aux,$(VFILES)) + +archclean:: + rm -f *.cmx *.o + +printenv: + @"$(COQBIN)coqtop" -config + @echo 'CAMLC = $(CAMLC)' + @echo 'CAMLOPTC = $(CAMLOPTC)' + @echo 'PP = $(PP)' + @echo 'COQFLAGS = $(COQFLAGS)' + @echo 'COQLIBINSTALL = $(COQLIBINSTALL)' + @echo 'COQDOCINSTALL = $(COQDOCINSTALL)' + +Makefile: _CoqProject + mv -f $@ $@.bak + "$(COQBIN)coq_makefile" -f $< -o $@ + + +################### +# # +# Implicit rules. # +# # +################### + +$(VOFILES): %.vo: %.v + $(COQC) $(COQDEBUG) $(COQFLAGS) $* + +$(GLOBFILES): %.glob: %.v + $(COQC) $(COQDEBUG) $(COQFLAGS) $* + +$(VFILES:.v=.vio): %.vio: %.v + $(COQC) -quick $(COQDEBUG) $(COQFLAGS) $* + +$(GFILES): %.g: %.v + $(GALLINA) $< + +$(VFILES:.v=.tex): %.tex: %.v + $(COQDOC) $(COQDOCFLAGS) -latex $< -o $@ + +$(HTMLFILES): %.html: %.v %.glob + $(COQDOC) $(COQDOCFLAGS) -html $< -o $@ + +$(VFILES:.v=.g.tex): %.g.tex: %.v + $(COQDOC) $(COQDOCFLAGS) -latex -g $< -o $@ + +$(GHTMLFILES): %.g.html: %.v %.glob + $(COQDOC) $(COQDOCFLAGS) -html -g $< -o $@ + +$(addsuffix .d,$(VFILES)): %.v.d: %.v + $(COQDEP) $(COQLIBS) "$<" > "$@" || ( RV=$$?; rm -f "$@"; exit $${RV} ) + +$(addsuffix .beautified,$(VFILES)): %.v.beautified: + $(COQC) $(COQDEBUG) $(COQFLAGS) -beautify $* + +# WARNING +# +# This Makefile has been automagically generated +# Edit at your own risks ! +# +# END OF WARNING + diff --git a/coqprime-8.5/README.md b/coqprime-8.5/README.md new file mode 100644 index 000000000..9c317fb00 --- /dev/null +++ b/coqprime-8.5/README.md @@ -0,0 +1,9 @@ +# Coqprime (LGPL subset) + +This is a mirror of the LGPL-licensed and autogenerated files from [Coqprime](http://coqprime.gforge.inria.fr/) for Coq 8.5. It was generated from [coqprime_8.5b.zip](https://gforge.inria.fr/frs/download.php/file/35520/coqprime_8.5b.zip). Due to the removal of files that are missing license headers in the upstream source, `make` no longer completes successfully. However, a large part of the codebase does build and contains theorems useful to us. Fixing the build system would be nice, but is not a priority for us. + +## Usage + + make PrimalityTest/Zp.vo PrimalityTest/PocklingtonCertificat.vo + cd .. + coqide -R coqprime/Tactic Coqprime -R coqprime/N Coqprime -R coqprime/Z Coqprime -R coqprime/List Coqprime -R coqprime/PrimalityTest Coqprime YOUR_FILE.v # these are the dependencies for PrimalityTest/Zp, other modules can be added in a similar fashion diff --git a/coqprime-8.5/_CoqProject b/coqprime-8.5/_CoqProject new file mode 100644 index 000000000..95b224864 --- /dev/null +++ b/coqprime-8.5/_CoqProject @@ -0,0 +1,24 @@ +-R Coqprime Coqprime +Coqprime/Cyclic.v +Coqprime/EGroup.v +Coqprime/Euler.v +Coqprime/FGroup.v +Coqprime/IGroup.v +Coqprime/Iterator.v +Coqprime/Lagrange.v +Coqprime/ListAux.v +Coqprime/LucasLehmer.v +Coqprime/NatAux.v +Coqprime/PGroup.v +Coqprime/Permutation.v +Coqprime/Pmod.v +Coqprime/Pocklington.v +Coqprime/PocklingtonCertificat.v +Coqprime/Root.v +Coqprime/Tactic.v +Coqprime/UList.v +Coqprime/ZCAux.v +Coqprime/ZCmisc.v +Coqprime/ZProgression.v +Coqprime/ZSum.v +Coqprime/Zp.v -- cgit v1.2.3 From 4ec00e8ee78c1c7fa1f94d429b3b113bcf698e5b Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Tue, 14 Jun 2016 00:09:19 -0400 Subject: [field] and [nsatz] do things now again --- _CoqProject | 1 + src/CompleteEdwardsCurve/Pre.v | 156 +++++++++++---------- src/SaneField.v | 307 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 394 insertions(+), 70 deletions(-) create mode 100644 src/SaneField.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index de22ff9d4..4ad320808 100644 --- a/_CoqProject +++ b/_CoqProject @@ -4,6 +4,7 @@ src/BaseSystemProofs.v src/EdDSAProofs.v src/Field.v src/Rep.v +src/SaneField.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v src/CompleteEdwardsCurve/DoubleAndAdd.v diff --git a/src/CompleteEdwardsCurve/Pre.v b/src/CompleteEdwardsCurve/Pre.v index f0754f7a0..4d9085a21 100644 --- a/src/CompleteEdwardsCurve/Pre.v +++ b/src/CompleteEdwardsCurve/Pre.v @@ -1,40 +1,88 @@ -Require Import Crypto.Field. Import Crypto.Field.F. +Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. +Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. +Require Import Crypto.SaneField. + +Module NsatzExportGuarantine. + Require Import Coq.nsatz.Nsatz. + Ltac sane_nsatz := + let H := fresh "HRingOps" in + let carrierType := lazymatch goal with |- ?R ?x _ => type of x end in + let inst := constr:(_:Ncring.Ring (T:=carrierType)) in + lazymatch type of inst with + | @Ncring.Ring _ _ _ _ _ _ _ _ ?ops => + lazymatch type of ops with + @Ncring.Ring_ops ?F ?zero ?one ?add ?mul ?sub ?opp ?eq + => + pose ops as H; + (* (* apparently [nsatz] matches the goal to look for equalitites, so [eq] will need to become + [Algebra_syntax.equality]. However, reification is done using typeclasses so definitional + equality is enough (and faster) *) + change zero with (@Algebra_syntax.zero F (@Ncring.zero_notation F zero one add mul sub opp eq ops)) in *; + change one with (@Algebra_syntax.one F (@Ncring.one_notation F zero one add mul sub opp eq ops)) in *; + change add with (@Algebra_syntax.addition F (@Ncring.add_notation F zero one add mul sub opp eq ops)) in *; + change mul with (@Algebra_syntax.multiplication F F (@Ncring.mul_notation F zero one add mul sub opp eq ops)) in *; + change opp with (@Algebra_syntax.opposite F (@Ncring.opp_notation F zero one add mul sub opp eq ops)) in *; + change eq with (@Algebra_syntax.equality F (@Ncring.eq_notation F zero one add mul sub opp eq ops)) in *; + *) + move H at top (* [nsatz] requires equalities to be continuously at the bottom of the hypothesis list *) + end + end; + nsatz; + clear H. +End NsatzExportGuarantine. +Import NsatzExportGuarantine. +Ltac nsatz := sane_nsatz. + +Require Import Util.Tactics. +Inductive field_simplify_done {T} : T -> Type := + Field_simplify_done : forall H, field_simplify_done H. + +Require Import Coq.setoid_ring.Field_tac. +Ltac field_simplify_eq_all := + repeat match goal with + [ H: _ |- _ ] => + match goal with + | [ Ha : field_simplify_done H |- _ ] => fail + | _ => idtac + end; + field_simplify_eq in H; + unique pose proof (Field_simplify_done H) + end; + repeat match goal with [ H: field_simplify_done _ |- _] => clear H end. +Ltac field_nsatz := + field_simplify_eq_all; + try field_simplify_eq; + try nsatz. Generalizable All Variables. Section Pre. - Context `{Field}. - Local Notation "0" := ring0. - Local Notation "1" := ring1. - Local Notation "a = b" := (ring_eq a b). - Local Notation "a <> b" := (not (ring_eq a b)). - Local Notation "a = b" := (ring_eq a b) : type_scope. - Local Notation "a <> b" := (not (ring_eq a b)) : type_scope. - Local Infix "+" := add. - Local Infix "*" := mul. - Local Infix "-" := sub. - Local Infix "/" := div. - Local Infix "^" := powZ. + Context {F eq zero one opp add sub mul inv div} `{field F eq zero one opp add sub mul inv div}. + Local Infix "=" := eq. Local Notation "a <> b" := (not (a = b)). + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "*" := mul. + Local Infix "-" := sub. Local Infix "/" := div. + Local Notation "x '^' 2" := (x*x) (at level 30). + + Add Field EdwardsCurveField : (Field.field_theory_for_stdlib_tactic (T:=F)). + + Goal forall x y z, y <> 0 -> x/y = z -> z*y + y = x + y. intros; field_nsatz; auto. Qed. - Context {a:F} {a_nonzero : not(a<>0)} {a_square : exists sqrt_a, sqrt_a^2 = a}. + Context {a:F} {a_nonzero : a<>0} {a_square : exists sqrt_a, sqrt_a^2 = a}. Context {d:F} {d_nonsquare : forall x, x^2 <> d}. Context {char_gt_2 : 1+1 <> 0}. - - (*CRUFT - Require Import Coq.setoid_ring.Field_tac. - Add Field EdwardsCurveField : (Field_theory_for_tactic F). - *) (* the canonical definitions are in Spec *) - Definition onCurve P := let '(x, y) := P in a*x^2 + y^2 = 1 + d*x^2*y^2. - Definition unifiedAdd' P1' P2' := - let '(x1, y1) := P1' in - let '(x2, y2) := P2' in - (((x1*y2 + y1*x2)/(1 + d*x1*x2*y1*y2)) , ((y1*y2 - a*x1*x2)/(1 - d*x1*x2*y1*y2))). + Definition onCurve (P:F*F) := let (x, y) := P in a*x^2 + y^2 = 1 + d*x^2*y^2. + Definition unifiedAdd' (P1' P2':F*F) : F*F := + let (x1, y1) := P1' in + let (x2, y2) := P2' in + pair (((x1*y2 + y1*x2)/(1 + d*x1*x2*y1*y2))) (((y1*y2 - a*x1*x2)/(1 - d*x1*x2*y1*y2))). - (*CRUFT Ltac rewriteAny := match goal with [H: _ = _ |- _ ] => rewrite H end. Ltac rewriteLeftAny := match goal with [H: _ = _ |- _ ] => rewrite <- H end. + (*CRUFT Ltac whatsNotZero := repeat match goal with | [H: ?lhs = ?rhs |- _ ] => @@ -58,55 +106,23 @@ Section Pre. end. *) + Ltac admit_nonzero := abstract (repeat split; match goal with |- not (eq _ 0) => admit end). + Lemma edwardsAddComplete' x1 y1 x2 y2 : - onCurve (x1, y1) -> - onCurve (x2, y2) -> + onCurve (pair x1 y1) -> + onCurve (pair x2 y2) -> (d*x1*x2*y1*y2)^2 <> 1. Proof. - unfold onCurve; intros Hc1 Hc2. - simpl in Hc1, Hc2. - Fail idtac. - Set Printing All. - Locate "*". - - pose proof char_gt_2. pose proof a_nonzero as Ha_nonzero. - destruct a_square as [sqrt_a a_square']. - rewrite <-a_square' in *. - - (* Furthermore... *) - pose proof (eq_refl (d*x1^2*y1^2*(sqrt_a^2*x2^2 + y2^2))) as Heqt. - rewrite Hc2 in Heqt at 2. - replace (d * x1 ^ 2 * y1 ^ 2 * (1 + d * x2 ^ 2 * y2 ^ 2)) - with (d*x1^2*y1^2 + (d*x1*x2*y1*y2)^2) in Heqt by field. - rewrite Hcontra in Heqt. - replace (d * x1 ^ 2 * y1 ^ 2 + 1) with (1 + d * x1 ^ 2 * y1 ^ 2) in Heqt by field. - rewrite <-Hc1 in Heqt. - - (* main equation for both potentially nonzero denominators *) - destruct (F_eq_dec (sqrt_a*x2 + y2) 0); destruct (F_eq_dec (sqrt_a*x2 - y2) 0); - try lazymatch goal with [H: ?f (sqrt_a * x2) y2 <> 0 |- _ ] => - assert ((f (sqrt_a*x1) (d * x1 * x2 * y1 * y2*y1))^2 = - f ((sqrt_a^2)*x1^2 + (d * x1 * x2 * y1 * y2)^2*y1^2) - (d * x1 * x2 * y1 * y2*sqrt_a*(ZToField 2)*x1*y1)) as Heqw1 by field; - rewrite Hcontra in Heqw1; - replace (1 * y1^2) with (y1^2) in * by field; - rewrite <- Heqt in *; - assert (d = (f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1))^2 / - (x1 * y1 * (f (sqrt_a * x2) y2))^2) - by (rewriteAny; field; auto); - match goal with [H: d = (?n^2)/(?l^2) |- _ ] => - destruct (d_nonsquare (n/l)); (remember n; rewriteAny; field; auto) - end + unfold onCurve; intros Hc1 Hc2 Hcontra. + assert (d * x1 ^2 * y1 ^2 * (a * x2 ^2 + y2 ^2) = a * x1 ^2 + y1 ^2) as Heqt by nsatz. + destruct a_square as [sqrt_a a_square']; rewrite <-a_square' in *. + destruct (eq_dec (sqrt_a*x2 + y2) 0); destruct (eq_dec (sqrt_a*x2 - y2) 0); + lazymatch goal with + | [H: not (eq (?f (sqrt_a * x2) y2) 0) |- _ ] + => eapply (d_nonsquare ((f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1)) / (x1 * y1 * (f (sqrt_a * x2) y2)) )); + field_nsatz; admit_nonzero + | _ => apply a_nonzero; nsatz end. - - assert (Hc: (sqrt_a * x2 + y2) + (sqrt_a * x2 - y2) = 0) by (repeat rewriteAny; field). - - replace (sqrt_a * x2 + y2 + (sqrt_a * x2 - y2)) with (ZToField 2 * sqrt_a * x2) in Hc by field. - - (* contradiction: product of nonzero things is zero *) - destruct (Fq_mul_zero_why _ _ Hc) as [Hcc|Hcc]; subst; intuition. - destruct (Fq_mul_zero_why _ _ Hcc) as [Hccc|Hccc]; subst; intuition. - apply Ha_nonzero; field. Qed. Lemma edwardsAddCompletePlus x1 y1 x2 y2 : diff --git a/src/SaneField.v b/src/SaneField.v new file mode 100644 index 000000000..91c1ef9b8 --- /dev/null +++ b/src/SaneField.v @@ -0,0 +1,307 @@ +Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. +Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. + +Section Algebra. + Context {T:Type} {eq:T->T->Prop}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + + Class is_eq_dec := { eq_dec : forall x y : T, {x=y} + {x<>y} }. + + Section SingleOperation. + Context {op:T->T->T}. + + Class is_associative := { associative : forall x y z, op x (op y z) = op (op x y) z }. + + Context {id:T}. + + Class is_left_identity := { left_identity : forall x, op id x = x }. + Class is_right_identity := { right_identity : forall x, op x id = x }. + + Class monoid := + { + monoid_is_associative : is_associative; + monoid_is_left_identity : is_left_identity; + monoid_is_right_identity : is_right_identity + }. + Global Existing Instance monoid_is_associative. + Global Existing Instance monoid_is_left_identity. + Global Existing Instance monoid_is_right_identity. + + Context {inv:T->T}. + Class is_left_inverse := { left_inverse : forall x, op (inv x) x = id }. + Class is_right_inverse := { right_inverse : forall x, op x (inv x) = id }. + + Class group := + { + group_monoid : monoid; + group_is_left_inverse : is_left_inverse; + group_is_right_inverse : is_right_inverse; + + group_Equivalence : Equivalence eq; + group_is_eq_dec : is_eq_dec; + group_op_Proper: Proper (respectful eq (respectful eq eq)) op; + group_inv_Proper: Proper (respectful eq eq) inv + }. + Global Existing Instance group_monoid. + Global Existing Instance group_is_left_inverse. + Global Existing Instance group_is_right_inverse. + Global Existing Instance group_Equivalence. + Global Existing Instance group_is_eq_dec. + Global Existing Instance group_op_Proper. + Global Existing Instance group_inv_Proper. + + Class is_commutative := { commutative : forall x y, op x y = op y x }. + + Record abelian_group := + { + abelian_group_group : group; + abelian_group_is_commutative : is_commutative + }. + Existing Class abelian_group. + Global Existing Instance abelian_group_group. + Global Existing Instance abelian_group_is_commutative. + End SingleOperation. + + Section AddMul. + Context {zero one:T}. Local Notation "0" := zero. Local Notation "1" := one. + Context {opp:T->T}. Local Notation "- x" := (opp x). + Context {add:T->T->T} {sub:T->T->T} {mul:T->T->T}. + Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. + + Class is_left_distributive := { left_distributive : forall a b c, a * (b + c) = a * b + a * c }. + Class is_right_distributive := { right_distributive : forall a b c, (b + c) * a = b * a + c * a }. + + + Class ring := + { + ring_abelian_group_add : abelian_group (op:=add) (id:=zero) (inv:=opp); + ring_monoid_mul : monoid (op:=mul) (id:=one); + ring_is_left_distributive : is_left_distributive; + ring_is_right_distributive : is_right_distributive; + + ring_sub_definition : forall x y, x - y = x + opp y; + + ring_mul_Proper : Proper (respectful eq (respectful eq eq)) mul; + ring_sub_Proper : Proper(respectful eq (respectful eq eq)) sub + }. + Global Existing Instance ring_abelian_group_add. + Global Existing Instance ring_monoid_mul. + Global Existing Instance ring_is_left_distributive. + Global Existing Instance ring_is_right_distributive. + Global Existing Instance ring_mul_Proper. + Global Existing Instance ring_sub_Proper. + + Class commutative_ring := + { + commutative_ring_ring : ring; + commutative_ring_is_commutative : is_commutative (op:=mul) + }. + Global Existing Instance commutative_ring_ring. + Global Existing Instance commutative_ring_is_commutative. + + Class is_mul_nonzero_nonzero := { mul_nonzero_nonzero : forall x y, x<>0 -> y<>0 -> x*y<>0 }. + + Class is_zero_neq_one := { zero_neq_one : zero <> one }. + + Class integral_domain := + { + integral_domain_commutative_ring : commutative_ring; + integral_domain_is_mul_nonzero_nonzero : is_mul_nonzero_nonzero; + integral_domain_is_zero_neq_one : is_zero_neq_one + }. + Global Existing Instance integral_domain_commutative_ring. + Global Existing Instance integral_domain_is_mul_nonzero_nonzero. + Global Existing Instance integral_domain_is_zero_neq_one. + + Context {inv:T->T} {div:T->T->T}. + Class is_left_multiplicative_inverse := { left_multiplicative_inverse : forall x, x<>0 -> (inv x) * x = 1 }. + + Class field := + { + field_commutative_ring : commutative_ring; + field_is_left_multiplicative_inverse : is_left_multiplicative_inverse; + field_domain_is_zero_neq_one : is_zero_neq_one; + + field_div_definition : forall x y , div x y = x * inv y; + + field_inv_Proper : Proper (respectful eq eq) inv; + field_div_Proper : Proper (respectful eq (respectful eq eq)) div + }. + Global Existing Instance field_commutative_ring. + Global Existing Instance field_is_left_multiplicative_inverse. + Global Existing Instance field_domain_is_zero_neq_one. + Global Existing Instance field_inv_Proper. + Global Existing Instance field_div_Proper. + End AddMul. +End Algebra. + + +Section GenericCancellation. + Context {T:Type} {eq:T->T->Prop} {Equivalence_eq : Equivalence eq}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Context {op:T->T->T} {Proper_op : Proper(respectful eq (respectful eq eq)) op}. + Context {id:T}. + + Context {Hassoc: is_associative (op:=op) (eq:=eq)}. + Context {Hrid: is_right_identity (op:=op) (eq:=eq) (id := id)}. + Context {Hlid: is_left_identity (op:=op) (eq:=eq) (id:=id) }. + + Lemma cancel_right z iz (Hinv:op z iz = id) : + forall x y, op x z = op y z <-> x = y. + Proof. + split; intros. + { assert (op (op x z) iz = op (op y z) iz) as Hcut by (f_equiv; assumption). + rewrite <-associative in Hcut. + rewrite <-!associative, !Hinv, !right_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. + + Lemma cancel_left z iz (Hinv:op iz z = id) : + forall x y, op z x = op z y <-> x = y. + Proof. + split; intros. + { assert (op iz (op z x) = op iz (op z y)) as Hcut by (f_equiv; assumption). + rewrite !associative, !Hinv, !left_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. +End GenericCancellation. + +Module Group. + Section BasicProperties. + Context {T eq op id inv} `{@group T eq op id inv}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + + Lemma cancel_left : forall z x y, op z x = op z y <-> x = y. + Proof. eauto using cancel_left, left_inverse. Qed. + Lemma cancel_right : forall z x y, op x z = op y z <-> x = y. + Proof. eauto using cancel_right, right_inverse. Qed. + End BasicProperties. +End Group. + +Require Coq.nsatz.Nsatz. + +Ltac dropAlgebraSyntax := + cbv beta delta [ + Algebra_syntax.zero + Algebra_syntax.one + Algebra_syntax.addition + Algebra_syntax.multiplication + Algebra_syntax.subtraction + Algebra_syntax.opposite + Algebra_syntax.equality + Algebra_syntax.bracket + Algebra_syntax.power + ] in *. + +Ltac dropRingSyntax := + dropAlgebraSyntax; + cbv beta delta [ + Ncring.zero_notation + Ncring.one_notation + Ncring.add_notation + Ncring.mul_notation + Ncring.sub_notation + Ncring.opp_notation + Ncring.eq_notation + ] in *. + +Module Ring. + Section Ring. + Context {T eq zero one opp add sub mul} `{@ring T eq zero one opp add sub mul}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. + + Lemma mul_0_r : forall x, x * 0 = 0. + Proof. + intros. + assert (x*0 = x*0) as Hx by reflexivity. + rewrite <-(left_identity 0), left_distributive in Hx at 1. + assert (x*0 + x*0 - x*0 = x*0 - x*0) as Hxx by (f_equiv; exact Hx). + rewrite !ring_sub_definition, <-associative, right_inverse, right_identity in Hxx; exact Hxx. + Qed. + + Lemma mul_0_l : forall x, x * 0 = 0. + Proof. + intros. + assert (x*0 = x*0) as Hx by reflexivity. + rewrite <-(left_identity 0), left_distributive in Hx at 1. + assert (opp (x*0) + (x*0 + x*0) = opp (x*0) + x*0) as Hxx by (f_equiv; exact Hx). + rewrite associative, left_inverse, left_identity in Hxx; exact Hxx. + Qed. + + Global Instance Ncring_Ring_ops : @Ncring.Ring_ops T zero one add mul sub opp eq. + Global Instance Ncring_Ring : @Ncring.Ring T zero one add mul sub opp eq Ncring_Ring_ops. + Proof. + split; dropRingSyntax; eauto using left_identity, right_identity, commutative, associative, right_inverse, left_distributive, right_distributive, ring_sub_definition with core typeclass_instances. + - (* TODO: why does [eauto using @left_identity with typeclass_instances] not work? *) + eapply @left_identity; eauto with typeclass_instances. + - eapply @right_identity; eauto with typeclass_instances. + - eapply associative. + Qed. + End Ring. + + Section TacticSupportCommutative. + Context {T eq zero one opp add sub mul} `{@commutative_ring T eq zero one opp add sub mul}. + + Global Instance Cring_Cring_commutative_ring : + @Cring.Cring T zero one add mul sub opp eq Ring.Ncring_Ring_ops Ring.Ncring_Ring. + Proof. unfold Cring.Cring; intros; dropRingSyntax. eapply commutative. Qed. + End TacticSupportCommutative. +End Ring. + +Module IntegralDomain. + Section CommutativeRing. + Context {T eq zero one opp add sub mul} `{@integral_domain T eq zero one opp add sub mul}. + + Lemma mul_nonzero_nonzero_cases (x y : T) + : eq (mul x y) zero -> eq x zero \/ eq y zero. + Proof. + pose proof mul_nonzero_nonzero x y. + destruct (eq_dec x zero); destruct (eq_dec y zero); intuition. + Qed. + + Global Instance Integral_domain : + @Integral_domain.Integral_domain T zero one add mul sub opp eq Ring.Ncring_Ring_ops + Ring.Ncring_Ring Ring.Cring_Cring_commutative_ring. + Proof. + split; dropRingSyntax. + - auto using mul_nonzero_nonzero_cases. + - intro bad; symmetry in bad; auto using zero_neq_one. + Qed. + End CommutativeRing. +End IntegralDomain. + +Module Field. + Section Field. + Context {T eq zero one opp add mul sub inv div} `{@field T eq zero one opp add sub mul inv div}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "*" := mul. + + Global Instance is_mul_nonzero_nonzero : @is_mul_nonzero_nonzero T eq 0 mul. + Proof. + constructor. intros x y Hx Hy Hxy. + assert (0 = (inv y * (inv x * x)) * y) as H00 by (rewrite <-!associative, Hxy, !Ring.mul_0_r; reflexivity). + rewrite left_multiplicative_inverse in H00 by assumption. + rewrite right_identity in H00. + rewrite left_multiplicative_inverse in H00 by assumption. + auto using zero_neq_one. + Qed. + + Global Instance integral_domain : @integral_domain T eq zero one opp add sub mul. + Proof. + split; auto using field_commutative_ring, field_domain_is_zero_neq_one, is_mul_nonzero_nonzero. + Qed. + + Require Coq.setoid_ring.Field_theory. + Lemma field_theory_for_stdlib_tactic : Field_theory.field_theory 0 1 add mul sub opp div inv eq. + Proof. + constructor. + admit. + { intro H01. symmetry in H01. auto using zero_neq_one. } + { apply field_div_definition. } + { apply left_multiplicative_inverse. } + Qed. + End Field. +End Field. \ No newline at end of file -- cgit v1.2.3 From b3f932ed66422e62bb720ee862dc99e9ae6592a4 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Wed, 15 Jun 2016 18:04:38 -0400 Subject: nsatz: reimplement, integrate, demonstrate --- _CoqProject | 2 +- src/Algebra.v | 511 +++++++++++++++++++++++++++++++++++++++++ src/CompleteEdwardsCurve/Pre.v | 37 ++- src/SaneField.v | 370 ----------------------------- 4 files changed, 528 insertions(+), 392 deletions(-) create mode 100644 src/Algebra.v delete mode 100644 src/SaneField.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index 4ad320808..2fc5b1b90 100644 --- a/_CoqProject +++ b/_CoqProject @@ -1,10 +1,10 @@ -R src Crypto +src/Algebra.v src/BaseSystem.v src/BaseSystemProofs.v src/EdDSAProofs.v src/Field.v src/Rep.v -src/SaneField.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v src/CompleteEdwardsCurve/DoubleAndAdd.v diff --git a/src/Algebra.v b/src/Algebra.v new file mode 100644 index 000000000..85602e64a --- /dev/null +++ b/src/Algebra.v @@ -0,0 +1,511 @@ +Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. +Require Import Util.Tactics. +Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. + +Section Algebra. + Context {T:Type} {eq:T->T->Prop}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + + Class is_eq_dec := { eq_dec : forall x y : T, {x=y} + {x<>y} }. + + Section SingleOperation. + Context {op:T->T->T}. + + Class is_associative := { associative : forall x y z, op x (op y z) = op (op x y) z }. + + Context {id:T}. + + Class is_left_identity := { left_identity : forall x, op id x = x }. + Class is_right_identity := { right_identity : forall x, op x id = x }. + + Class monoid := + { + monoid_is_associative : is_associative; + monoid_is_left_identity : is_left_identity; + monoid_is_right_identity : is_right_identity + }. + Global Existing Instance monoid_is_associative. + Global Existing Instance monoid_is_left_identity. + Global Existing Instance monoid_is_right_identity. + + Context {inv:T->T}. + Class is_left_inverse := { left_inverse : forall x, op (inv x) x = id }. + Class is_right_inverse := { right_inverse : forall x, op x (inv x) = id }. + + Class group := + { + group_monoid : monoid; + group_is_left_inverse : is_left_inverse; + group_is_right_inverse : is_right_inverse; + + group_Equivalence : Equivalence eq; + group_is_eq_dec : is_eq_dec; + group_op_Proper: Proper (respectful eq (respectful eq eq)) op; + group_inv_Proper: Proper (respectful eq eq) inv + }. + Global Existing Instance group_monoid. + Global Existing Instance group_is_left_inverse. + Global Existing Instance group_is_right_inverse. + Global Existing Instance group_Equivalence. + Global Existing Instance group_is_eq_dec. + Global Existing Instance group_op_Proper. + Global Existing Instance group_inv_Proper. + + Class is_commutative := { commutative : forall x y, op x y = op y x }. + + Record abelian_group := + { + abelian_group_group : group; + abelian_group_is_commutative : is_commutative + }. + Existing Class abelian_group. + Global Existing Instance abelian_group_group. + Global Existing Instance abelian_group_is_commutative. + End SingleOperation. + + Section AddMul. + Context {zero one:T}. Local Notation "0" := zero. Local Notation "1" := one. + Context {opp:T->T}. Local Notation "- x" := (opp x). + Context {add:T->T->T} {sub:T->T->T} {mul:T->T->T}. + Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. + + Class is_left_distributive := { left_distributive : forall a b c, a * (b + c) = a * b + a * c }. + Class is_right_distributive := { right_distributive : forall a b c, (b + c) * a = b * a + c * a }. + + + Class ring := + { + ring_abelian_group_add : abelian_group (op:=add) (id:=zero) (inv:=opp); + ring_monoid_mul : monoid (op:=mul) (id:=one); + ring_is_left_distributive : is_left_distributive; + ring_is_right_distributive : is_right_distributive; + + ring_sub_definition : forall x y, x - y = x + opp y; + + ring_mul_Proper : Proper (respectful eq (respectful eq eq)) mul; + ring_sub_Proper : Proper(respectful eq (respectful eq eq)) sub + }. + Global Existing Instance ring_abelian_group_add. + Global Existing Instance ring_monoid_mul. + Global Existing Instance ring_is_left_distributive. + Global Existing Instance ring_is_right_distributive. + Global Existing Instance ring_mul_Proper. + Global Existing Instance ring_sub_Proper. + + Class commutative_ring := + { + commutative_ring_ring : ring; + commutative_ring_is_commutative : is_commutative (op:=mul) + }. + Global Existing Instance commutative_ring_ring. + Global Existing Instance commutative_ring_is_commutative. + + Class is_mul_nonzero_nonzero := { mul_nonzero_nonzero : forall x y, x<>0 -> y<>0 -> x*y<>0 }. + + Class is_zero_neq_one := { zero_neq_one : zero <> one }. + + Class integral_domain := + { + integral_domain_commutative_ring : commutative_ring; + integral_domain_is_mul_nonzero_nonzero : is_mul_nonzero_nonzero; + integral_domain_is_zero_neq_one : is_zero_neq_one + }. + Global Existing Instance integral_domain_commutative_ring. + Global Existing Instance integral_domain_is_mul_nonzero_nonzero. + Global Existing Instance integral_domain_is_zero_neq_one. + + Context {inv:T->T} {div:T->T->T}. + Class is_left_multiplicative_inverse := { left_multiplicative_inverse : forall x, x<>0 -> (inv x) * x = 1 }. + + Class field := + { + field_commutative_ring : commutative_ring; + field_is_left_multiplicative_inverse : is_left_multiplicative_inverse; + field_domain_is_zero_neq_one : is_zero_neq_one; + + field_div_definition : forall x y , div x y = x * inv y; + + field_inv_Proper : Proper (respectful eq eq) inv; + field_div_Proper : Proper (respectful eq (respectful eq eq)) div + }. + Global Existing Instance field_commutative_ring. + Global Existing Instance field_is_left_multiplicative_inverse. + Global Existing Instance field_domain_is_zero_neq_one. + Global Existing Instance field_inv_Proper. + Global Existing Instance field_div_Proper. + End AddMul. +End Algebra. + + +Section GenericCancellation. + Context {T:Type} {eq:T->T->Prop} {Equivalence_eq : Equivalence eq}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Context {op:T->T->T} {Proper_op : Proper(respectful eq (respectful eq eq)) op}. + Context {id:T}. + + Context {Hassoc: is_associative (op:=op) (eq:=eq)}. + Context {Hrid: is_right_identity (op:=op) (eq:=eq) (id := id)}. + Context {Hlid: is_left_identity (op:=op) (eq:=eq) (id:=id) }. + + Lemma cancel_right z iz (Hinv:op z iz = id) : + forall x y, op x z = op y z <-> x = y. + Proof. + split; intros. + { assert (op (op x z) iz = op (op y z) iz) as Hcut by (f_equiv; assumption). + rewrite <-associative in Hcut. + rewrite <-!associative, !Hinv, !right_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. + + Lemma cancel_left z iz (Hinv:op iz z = id) : + forall x y, op z x = op z y <-> x = y. + Proof. + split; intros. + { assert (op iz (op z x) = op iz (op z y)) as Hcut by (f_equiv; assumption). + rewrite !associative, !Hinv, !left_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. +End GenericCancellation. + +Module Group. + Section BasicProperties. + Context {T eq op id inv} `{@group T eq op id inv}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + + Lemma cancel_left : forall z x y, op z x = op z y <-> x = y. + Proof. eauto using cancel_left, left_inverse. Qed. + Lemma cancel_right : forall z x y, op x z = op y z <-> x = y. + Proof. eauto using cancel_right, right_inverse. Qed. + End BasicProperties. +End Group. + +Require Coq.nsatz.Nsatz. + +Ltac dropAlgebraSyntax := + cbv beta delta [ + Algebra_syntax.zero + Algebra_syntax.one + Algebra_syntax.addition + Algebra_syntax.multiplication + Algebra_syntax.subtraction + Algebra_syntax.opposite + Algebra_syntax.equality + Algebra_syntax.bracket + Algebra_syntax.power + ] in *. + +Ltac dropRingSyntax := + dropAlgebraSyntax; + cbv beta delta [ + Ncring.zero_notation + Ncring.one_notation + Ncring.add_notation + Ncring.mul_notation + Ncring.sub_notation + Ncring.opp_notation + Ncring.eq_notation + ] in *. + +Module Ring. + Section Ring. + Context {T eq zero one opp add sub mul} `{@ring T eq zero one opp add sub mul}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. + + Lemma mul_0_r : forall x, x * 0 = 0. + Proof. + intros. + assert (x*0 = x*0) as Hx by reflexivity. + rewrite <-(left_identity 0), left_distributive in Hx at 1. + assert (x*0 + x*0 - x*0 = x*0 - x*0) as Hxx by (f_equiv; exact Hx). + rewrite !ring_sub_definition, <-associative, right_inverse, right_identity in Hxx; exact Hxx. + Qed. + + Lemma mul_0_l : forall x, x * 0 = 0. + Proof. + intros. + assert (x*0 = x*0) as Hx by reflexivity. + rewrite <-(left_identity 0), left_distributive in Hx at 1. + assert (opp (x*0) + (x*0 + x*0) = opp (x*0) + x*0) as Hxx by (f_equiv; exact Hx). + rewrite associative, left_inverse, left_identity in Hxx; exact Hxx. + Qed. + + Global Instance Ncring_Ring_ops : @Ncring.Ring_ops T zero one add mul sub opp eq. + Global Instance Ncring_Ring : @Ncring.Ring T zero one add mul sub opp eq Ncring_Ring_ops. + Proof. + split; dropRingSyntax; eauto using left_identity, right_identity, commutative, associative, right_inverse, left_distributive, right_distributive, ring_sub_definition with core typeclass_instances. + - (* TODO: why does [eauto using @left_identity with typeclass_instances] not work? *) + eapply @left_identity; eauto with typeclass_instances. + - eapply @right_identity; eauto with typeclass_instances. + - eapply associative. + Qed. + End Ring. + + Section TacticSupportCommutative. + Context {T eq zero one opp add sub mul} `{@commutative_ring T eq zero one opp add sub mul}. + + Global Instance Cring_Cring_commutative_ring : + @Cring.Cring T zero one add mul sub opp eq Ring.Ncring_Ring_ops Ring.Ncring_Ring. + Proof. unfold Cring.Cring; intros; dropRingSyntax. eapply commutative. Qed. + End TacticSupportCommutative. +End Ring. + +Module IntegralDomain. + Section CommutativeRing. + Context {T eq zero one opp add sub mul} `{@integral_domain T eq zero one opp add sub mul}. + + Lemma mul_nonzero_nonzero_cases (x y : T) + : eq (mul x y) zero -> eq x zero \/ eq y zero. + Proof. + pose proof mul_nonzero_nonzero x y. + destruct (eq_dec x zero); destruct (eq_dec y zero); intuition. + Qed. + + Global Instance Integral_domain : + @Integral_domain.Integral_domain T zero one add mul sub opp eq Ring.Ncring_Ring_ops + Ring.Ncring_Ring Ring.Cring_Cring_commutative_ring. + Proof. + split; dropRingSyntax. + - auto using mul_nonzero_nonzero_cases. + - intro bad; symmetry in bad; auto using zero_neq_one. + Qed. + End CommutativeRing. +End IntegralDomain. + +Module Field. + Section Field. + Context {T eq zero one opp add mul sub inv div} `{@field T eq zero one opp add sub mul inv div}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := zero. Local Notation "1" := one. + Local Infix "+" := add. Local Infix "*" := mul. + + Global Instance is_mul_nonzero_nonzero : @is_mul_nonzero_nonzero T eq 0 mul. + Proof. + constructor. intros x y Hx Hy Hxy. + assert (0 = (inv y * (inv x * x)) * y) as H00 by (rewrite <-!associative, Hxy, !Ring.mul_0_r; reflexivity). + rewrite left_multiplicative_inverse in H00 by assumption. + rewrite right_identity in H00. + rewrite left_multiplicative_inverse in H00 by assumption. + auto using zero_neq_one. + Qed. + + Global Instance integral_domain : @integral_domain T eq zero one opp add sub mul. + Proof. + split; auto using field_commutative_ring, field_domain_is_zero_neq_one, is_mul_nonzero_nonzero. + Qed. + + Require Coq.setoid_ring.Field_theory. + Lemma field_theory_for_stdlib_tactic : Field_theory.field_theory 0 1 add mul sub opp div inv eq. + Proof. + constructor. + admit. + { intro H01. symmetry in H01. auto using zero_neq_one. } + { apply field_div_definition. } + { apply left_multiplicative_inverse. } + Qed. + End Field. +End Field. + + +(*** Tactics for manipulating field equations *) +Require Import Coq.setoid_ring.Field_tac. + +Ltac guess_field := + match goal with + | |- ?eq _ _ => constr:(_:field (eq:=eq)) + | |- not (?eq _ _) => constr:(_:field (eq:=eq)) + | [H: ?eq _ _ |- _ ] => constr:(_:field (eq:=eq)) + | [H: not (?eq _ _) |- _] => constr:(_:field (eq:=eq)) + end. + +Ltac common_denominator := + let fld := guess_field in + lazymatch type of fld with + field (div:=?div) => + lazymatch goal with + | |- appcontext[div] => field_simplify_eq + | |- _ => idtac + end + end. + +Ltac common_denominator_in H := + let fld := guess_field in + lazymatch type of fld with + field (div:=?div) => + lazymatch type of H with + | appcontext[div] => field_simplify_eq in H + | _ => idtac + end + end. + +Ltac common_denominator_all := + common_denominator; + repeat match goal with [H: _ |- _ _ _ ] => common_denominator_in H end. + +Inductive field_simplify_done {T} : T -> Type := + Field_simplify_done : forall H, field_simplify_done H. + +Ltac field_simplify_eq_hyps := + repeat match goal with + [ H: _ |- _ ] => + match goal with + | [ Ha : field_simplify_done H |- _ ] => fail + | _ => idtac + end; + field_simplify_eq in H; + unique pose proof (Field_simplify_done H) + end; + repeat match goal with [ H: field_simplify_done _ |- _] => clear H end. + +Ltac field_simplify_eq_all := field_simplify_eq_hyps; try field_simplify_eq. + + +(*** Tactics for manipulating polynomial equations *) +Require Nsatz. +Require Import List. +Open Scope core_scope. + +Generalizable All Variables. +Lemma cring_sub_diag_iff {R zero eq sub} `{cring:Cring.Cring (R:=R) (ring0:=zero) (ring_eq:=eq) (sub:=sub)} + : forall x y, eq (sub x y) zero <-> eq x y. +Proof. + split;intros Hx. + { eapply Nsatz.psos_r1b. eapply Hx. } + { eapply Nsatz.psos_r1. eapply Hx. } +Qed. + +Ltac get_goal := lazymatch goal with |- ?g => g end. + +Ltac nsatz_equation_implications_to_list eq zero g := + lazymatch g with + | eq ?p zero => constr:(p::nil) + | eq ?p zero -> ?g => let l := nsatz_equation_implications_to_list eq zero g in constr:(p::l) + end. + +Ltac nsatz_reify_equations eq zero := + let g := get_goal in + let lb := nsatz_equation_implications_to_list eq zero g in + lazymatch (eval red in (Ncring_tac.list_reifyl (lterm:=lb))) with + (?variables, ?le) => + lazymatch (eval compute in (List.rev le)) with + | ?reified_goal::?reified_givens => constr:(variables, reified_givens, reified_goal) + end + end. + +Ltac nsatz_get_free_variables reified_package := + lazymatch reified_package with (?fv, _, _) => fv end. + +Ltac nsatz_get_reified_givens reified_package := + lazymatch reified_package with (_, ?givens, _) => givens end. + +Ltac nsatz_get_reified_goal reified_package := + lazymatch reified_package with (_, _, ?goal) => goal end. + +Require Import Coq.setoid_ring.Ring_polynom. +Ltac nsatz_compute_to_goal sugar nparams reified_goal power reified_givens := + nsatz_compute (PEc sugar :: PEc nparams :: PEpow reified_goal power :: reified_givens). + +Ltac nsatz_compute_get_leading_coefficient := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => a + end. + +Ltac nsatz_compute_get_certificate := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => constr:(c,b) + end. + +Ltac nsatz_rewrite_and_revert domain := + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + lazymatch goal with + | |- eq _ zero => idtac + | |- eq _ _ => rewrite <-(cring_sub_diag_iff (cring:=FCring)) + end; + repeat match goal with + | [H : eq _ zero |- _ ] => revert H + | [H : eq _ _ |- _ ] => rewrite <-(cring_sub_diag_iff (cring:=FCring)) in H; revert H + end + end. + +Ltac nsatz_nonzero := + try solve [apply Integral_domain.integral_domain_one_zero + |apply Integral_domain.integral_domain_minus_one_zero + |trivial]. + +Ltac nsatz_domain_sugar_power domain sugar power := + let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + nsatz_rewrite_and_revert domain; + let reified_package := nsatz_reify_equations eq zero in + let fv := nsatz_get_free_variables reified_package in + let interp := constr:(@Nsatz.PEevalR _ _ _ _ _ _ _ _ Fops fv) in + let reified_givens := nsatz_get_reified_givens reified_package in + let reified_goal := nsatz_get_reified_goal reified_package in + nsatz_compute_to_goal sugar nparams reified_goal power reified_givens; + let a := nsatz_compute_get_leading_coefficient in + let crt := nsatz_compute_get_certificate in + intros _ (* discard [nsatz_compute] output *); intros; + apply (fun Haa refl cond => @Integral_domain.Rintegral_domain_pow _ _ _ _ _ _ _ _ _ _ _ domain (interp a) _ (BinNat.N.to_nat power) Haa (@Nsatz.check_correct _ _ _ _ _ _ _ _ _ _ FCring fv reified_givens (PEmul a (PEpow reified_goal power)) crt refl cond)); + [ nsatz_nonzero; cbv iota beta delta [Nsatz.PEevalR PEeval InitialRing.gen_phiZ InitialRing.gen_phiPOS] + | solve [vm_compute; exact (eq_refl true)] (* exact_no_check (eq_refl true) *) + | solve [repeat (split; [assumption|]); exact I] ] + end. + +Ltac nsatz_guess_domain := + match goal with + | |- ?eq _ _ => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | |- not (?eq _ _) => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: ?eq _ _ |- _ ] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: not (?eq _ _) |- _] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + end. + +Ltac nsatz_sugar_power sugar power := + let domain := nsatz_guess_domain in + nsatz_domain_sugar_power domain sugar power. + +Tactic Notation "nsatz" constr(n) := + let nn := (eval compute in (BinNat.N.of_nat n)) in + nsatz_sugar_power BinInt.Z0 nn. + +Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. + +Ltac nsatz_contradict := + intros; + let domain := nsatz_guess_domain in + lazymatch type of domain with + | @Integral_domain.Integral_domain _ ?zero ?one _ _ _ _ ?eq ?Fops ?FRing ?FCring => + assert (eq one zero) as Hbad; + [nsatz; nsatz_nonzero + |destruct (Integral_domain.integral_domain_one_zero (Integral_domain:=domain) Hbad)] + end. + +(*** Polynomial equations over fields *) + +Ltac field_algebra := + intros; + common_denominator_all; + try (nsatz; dropRingSyntax); + repeat (apply conj); + try solve + [unfold not; intro; nsatz_contradict + |nsatz_nonzero]. + +Section Example. + Context {F zero one opp add sub mul inv div} `{F_field:field F eq zero one opp add sub mul inv div}. + Local Infix "+" := add. Local Infix "*" := mul. Local Infix "-" := sub. Local Infix "/" := div. + Local Notation "0" := zero. Local Notation "1" := one. + + Add Field _ExampleField : (Field.field_theory_for_stdlib_tactic (T:=F)). + + Example _example_nsatz x y : 1+1 <> 0 -> x + y = 0 -> x - y = 0 -> x = 0. + Proof. field_algebra. Qed. + + Example _example_field_nsatz x y z : y <> 0 -> x/y = z -> z*y + y = x + y. + Proof. field_algebra. Qed. + + Example _example_nonzero_nsatz_contradict x y : x * y = 1 -> not (x = 0). + Proof. intros. intro. nsatz_contradict. Qed. +End Example. \ No newline at end of file diff --git a/src/CompleteEdwardsCurve/Pre.v b/src/CompleteEdwardsCurve/Pre.v index 7cb05158d..e63aad34d 100644 --- a/src/CompleteEdwardsCurve/Pre.v +++ b/src/CompleteEdwardsCurve/Pre.v @@ -1,6 +1,5 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. -Require Import Crypto.SaneField. +Require Import Crypto.Algebra. Generalizable All Variables. Section Pre. @@ -15,7 +14,7 @@ Section Pre. Add Field EdwardsCurveField : (Field.field_theory_for_stdlib_tactic (T:=F)). Context {a:F} {a_nonzero : a<>0} {a_square : exists sqrt_a, sqrt_a^2 = a}. - Context {d:F} {d_nonsquare : forall x, x^2 <> d}. + Context {d:F} {d_nonsquare : forall sqrt_d, sqrt_d^2 <> d}. Context {char_gt_2 : 1+1 <> 0}. (* the canonical definitions are in Spec *) @@ -25,23 +24,24 @@ Section Pre. let (x2, y2) := P2' in pair (((x1*y2 + y1*x2)/(1 + d*x1*x2*y1*y2))) (((y1*y2 - a*x1*x2)/(1 - d*x1*x2*y1*y2))). - Ltac admit_nonzero := abstract (repeat split; match goal with |- not (eq _ 0) => admit end). + Lemma opp_nonzero_nonzero : forall x, x <> 0 -> opp x <> 0. Admitted. + + Hint Extern 0 (not (eq _ 0)) => apply opp_nonzero_nonzero : field_algebra. + + Ltac use_sqrt_a := destruct a_square as [sqrt_a a_square']; rewrite <-a_square' in *. Lemma edwardsAddComplete' x1 y1 x2 y2 : onCurve (pair x1 y1) -> onCurve (pair x2 y2) -> (d*x1*x2*y1*y2)^2 <> 1. Proof. - unfold onCurve, not; intros. - assert (d * x1 ^2 * y1 ^2 * (a * x2 ^2 + y2 ^2) = a * x1 ^2 + y1 ^2) as Heqt by nsatz. - destruct a_square as [sqrt_a a_square']; rewrite <-a_square' in *. + unfold onCurve, not; use_sqrt_a; intros. destruct (eq_dec (sqrt_a*x2 + y2) 0); destruct (eq_dec (sqrt_a*x2 - y2) 0); lazymatch goal with | [H: not (eq (?f (sqrt_a * x2) y2) 0) |- _ ] - => eapply (d_nonsquare ((f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1)) / (x1 * y1 * (f (sqrt_a * x2) y2)) )); - nsatz; admit_nonzero - | _ => apply a_nonzero; (do 2 nsatz) (* TODO: why does it not win on the first call? *) - end. + => apply d_nonsquare with (sqrt_d:=(f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1)) / (x1 * y1 * (f (sqrt_a * x2) y2))) + | _ => apply a_nonzero + end; field_algebra; auto using opp_nonzero_nonzero. Qed. Lemma edwardsAddCompletePlus x1 y1 x2 y2 : @@ -49,11 +49,7 @@ Section Pre. onCurve (x2, y2) -> (1 + d*x1*x2*y1*y2) <> 0. Proof. - intros Hc1 Hc2; simpl in Hc1, Hc2. - intros; destruct (F_eq_dec (d*x1*x2*y1*y2) (0-1)) as [H|H]. - - assert ((d*x1*x2*y1*y2)^2 = 1) by (rewriteAny; field). destruct (edwardsAddComplete' x1 y1 x2 y2); auto. - - replace (d * x1 * x2 * y1 * y2) with (1+d * x1 * x2 * y1 * y2-1) in H by field. - intro Hz; rewrite Hz in H; intuition. + intros H1 H2 ?. apply (edwardsAddComplete' x1 y1 x2 y2 H1 H2); field_algebra. Qed. Lemma edwardsAddCompleteMinus x1 y1 x2 y2 : @@ -61,16 +57,14 @@ Section Pre. onCurve (x2, y2) -> (1 - d*x1*x2*y1*y2) <> 0. Proof. - intros Hc1 Hc2. destruct (F_eq_dec (d*x1*x2*y1*y2) 1) as [H|H]. - - assert ((d*x1*x2*y1*y2)^2 = 1) by (rewriteAny; field). destruct (edwardsAddComplete' x1 y1 x2 y2); auto. - - replace (d * x1 * x2 * y1 * y2) with ((1-(1-d * x1 * x2 * y1 * y2))) in H by field. - intro Hz; rewrite Hz in H; apply H; field. + intros H1 H2 ?. apply (edwardsAddComplete' x1 y1 x2 y2 H1 H2); field_algebra. Qed. Definition zeroOnCurve : onCurve (0, 1). - simpl. field. + simpl. field_algebra. Qed. + (* TODO: port Lemma unifiedAdd'_onCurve' x1 y1 x2 y2 x3 y3 (H: (x3, y3) = unifiedAdd' (x1, y1) (x2, y2)) : onCurve (x1, y1) -> onCurve (x2, y2) -> onCurve (x3, y3). @@ -119,4 +113,5 @@ Section Pre. remember (unifiedAdd' (f, f0) (f1, f2)) as r; destruct r. eapply unifiedAdd'_onCurve'; eauto. Qed. + *) End Pre. \ No newline at end of file diff --git a/src/SaneField.v b/src/SaneField.v deleted file mode 100644 index 4149e2fd1..000000000 --- a/src/SaneField.v +++ /dev/null @@ -1,370 +0,0 @@ -Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Require Import Util.Tactics. -Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. - -Section Algebra. - Context {T:Type} {eq:T->T->Prop}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - - Class is_eq_dec := { eq_dec : forall x y : T, {x=y} + {x<>y} }. - - Section SingleOperation. - Context {op:T->T->T}. - - Class is_associative := { associative : forall x y z, op x (op y z) = op (op x y) z }. - - Context {id:T}. - - Class is_left_identity := { left_identity : forall x, op id x = x }. - Class is_right_identity := { right_identity : forall x, op x id = x }. - - Class monoid := - { - monoid_is_associative : is_associative; - monoid_is_left_identity : is_left_identity; - monoid_is_right_identity : is_right_identity - }. - Global Existing Instance monoid_is_associative. - Global Existing Instance monoid_is_left_identity. - Global Existing Instance monoid_is_right_identity. - - Context {inv:T->T}. - Class is_left_inverse := { left_inverse : forall x, op (inv x) x = id }. - Class is_right_inverse := { right_inverse : forall x, op x (inv x) = id }. - - Class group := - { - group_monoid : monoid; - group_is_left_inverse : is_left_inverse; - group_is_right_inverse : is_right_inverse; - - group_Equivalence : Equivalence eq; - group_is_eq_dec : is_eq_dec; - group_op_Proper: Proper (respectful eq (respectful eq eq)) op; - group_inv_Proper: Proper (respectful eq eq) inv - }. - Global Existing Instance group_monoid. - Global Existing Instance group_is_left_inverse. - Global Existing Instance group_is_right_inverse. - Global Existing Instance group_Equivalence. - Global Existing Instance group_is_eq_dec. - Global Existing Instance group_op_Proper. - Global Existing Instance group_inv_Proper. - - Class is_commutative := { commutative : forall x y, op x y = op y x }. - - Record abelian_group := - { - abelian_group_group : group; - abelian_group_is_commutative : is_commutative - }. - Existing Class abelian_group. - Global Existing Instance abelian_group_group. - Global Existing Instance abelian_group_is_commutative. - End SingleOperation. - - Section AddMul. - Context {zero one:T}. Local Notation "0" := zero. Local Notation "1" := one. - Context {opp:T->T}. Local Notation "- x" := (opp x). - Context {add:T->T->T} {sub:T->T->T} {mul:T->T->T}. - Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. - - Class is_left_distributive := { left_distributive : forall a b c, a * (b + c) = a * b + a * c }. - Class is_right_distributive := { right_distributive : forall a b c, (b + c) * a = b * a + c * a }. - - - Class ring := - { - ring_abelian_group_add : abelian_group (op:=add) (id:=zero) (inv:=opp); - ring_monoid_mul : monoid (op:=mul) (id:=one); - ring_is_left_distributive : is_left_distributive; - ring_is_right_distributive : is_right_distributive; - - ring_sub_definition : forall x y, x - y = x + opp y; - - ring_mul_Proper : Proper (respectful eq (respectful eq eq)) mul; - ring_sub_Proper : Proper(respectful eq (respectful eq eq)) sub - }. - Global Existing Instance ring_abelian_group_add. - Global Existing Instance ring_monoid_mul. - Global Existing Instance ring_is_left_distributive. - Global Existing Instance ring_is_right_distributive. - Global Existing Instance ring_mul_Proper. - Global Existing Instance ring_sub_Proper. - - Class commutative_ring := - { - commutative_ring_ring : ring; - commutative_ring_is_commutative : is_commutative (op:=mul) - }. - Global Existing Instance commutative_ring_ring. - Global Existing Instance commutative_ring_is_commutative. - - Class is_mul_nonzero_nonzero := { mul_nonzero_nonzero : forall x y, x<>0 -> y<>0 -> x*y<>0 }. - - Class is_zero_neq_one := { zero_neq_one : zero <> one }. - - Class integral_domain := - { - integral_domain_commutative_ring : commutative_ring; - integral_domain_is_mul_nonzero_nonzero : is_mul_nonzero_nonzero; - integral_domain_is_zero_neq_one : is_zero_neq_one - }. - Global Existing Instance integral_domain_commutative_ring. - Global Existing Instance integral_domain_is_mul_nonzero_nonzero. - Global Existing Instance integral_domain_is_zero_neq_one. - - Context {inv:T->T} {div:T->T->T}. - Class is_left_multiplicative_inverse := { left_multiplicative_inverse : forall x, x<>0 -> (inv x) * x = 1 }. - - Class field := - { - field_commutative_ring : commutative_ring; - field_is_left_multiplicative_inverse : is_left_multiplicative_inverse; - field_domain_is_zero_neq_one : is_zero_neq_one; - - field_div_definition : forall x y , div x y = x * inv y; - - field_inv_Proper : Proper (respectful eq eq) inv; - field_div_Proper : Proper (respectful eq (respectful eq eq)) div - }. - Global Existing Instance field_commutative_ring. - Global Existing Instance field_is_left_multiplicative_inverse. - Global Existing Instance field_domain_is_zero_neq_one. - Global Existing Instance field_inv_Proper. - Global Existing Instance field_div_Proper. - End AddMul. -End Algebra. - - -Section GenericCancellation. - Context {T:Type} {eq:T->T->Prop} {Equivalence_eq : Equivalence eq}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Context {op:T->T->T} {Proper_op : Proper(respectful eq (respectful eq eq)) op}. - Context {id:T}. - - Context {Hassoc: is_associative (op:=op) (eq:=eq)}. - Context {Hrid: is_right_identity (op:=op) (eq:=eq) (id := id)}. - Context {Hlid: is_left_identity (op:=op) (eq:=eq) (id:=id) }. - - Lemma cancel_right z iz (Hinv:op z iz = id) : - forall x y, op x z = op y z <-> x = y. - Proof. - split; intros. - { assert (op (op x z) iz = op (op y z) iz) as Hcut by (f_equiv; assumption). - rewrite <-associative in Hcut. - rewrite <-!associative, !Hinv, !right_identity in Hcut; exact Hcut. } - { f_equiv; assumption. } - Qed. - - Lemma cancel_left z iz (Hinv:op iz z = id) : - forall x y, op z x = op z y <-> x = y. - Proof. - split; intros. - { assert (op iz (op z x) = op iz (op z y)) as Hcut by (f_equiv; assumption). - rewrite !associative, !Hinv, !left_identity in Hcut; exact Hcut. } - { f_equiv; assumption. } - Qed. -End GenericCancellation. - -Module Group. - Section BasicProperties. - Context {T eq op id inv} `{@group T eq op id inv}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - - Lemma cancel_left : forall z x y, op z x = op z y <-> x = y. - Proof. eauto using cancel_left, left_inverse. Qed. - Lemma cancel_right : forall z x y, op x z = op y z <-> x = y. - Proof. eauto using cancel_right, right_inverse. Qed. - End BasicProperties. -End Group. - -Require Coq.nsatz.Nsatz. - -Ltac dropAlgebraSyntax := - cbv beta delta [ - Algebra_syntax.zero - Algebra_syntax.one - Algebra_syntax.addition - Algebra_syntax.multiplication - Algebra_syntax.subtraction - Algebra_syntax.opposite - Algebra_syntax.equality - Algebra_syntax.bracket - Algebra_syntax.power - ] in *. - -Ltac dropRingSyntax := - dropAlgebraSyntax; - cbv beta delta [ - Ncring.zero_notation - Ncring.one_notation - Ncring.add_notation - Ncring.mul_notation - Ncring.sub_notation - Ncring.opp_notation - Ncring.eq_notation - ] in *. - -Module Ring. - Section Ring. - Context {T eq zero one opp add sub mul} `{@ring T eq zero one opp add sub mul}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Local Notation "0" := zero. Local Notation "1" := one. - Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. - - Lemma mul_0_r : forall x, x * 0 = 0. - Proof. - intros. - assert (x*0 = x*0) as Hx by reflexivity. - rewrite <-(left_identity 0), left_distributive in Hx at 1. - assert (x*0 + x*0 - x*0 = x*0 - x*0) as Hxx by (f_equiv; exact Hx). - rewrite !ring_sub_definition, <-associative, right_inverse, right_identity in Hxx; exact Hxx. - Qed. - - Lemma mul_0_l : forall x, x * 0 = 0. - Proof. - intros. - assert (x*0 = x*0) as Hx by reflexivity. - rewrite <-(left_identity 0), left_distributive in Hx at 1. - assert (opp (x*0) + (x*0 + x*0) = opp (x*0) + x*0) as Hxx by (f_equiv; exact Hx). - rewrite associative, left_inverse, left_identity in Hxx; exact Hxx. - Qed. - - Global Instance Ncring_Ring_ops : @Ncring.Ring_ops T zero one add mul sub opp eq. - Global Instance Ncring_Ring : @Ncring.Ring T zero one add mul sub opp eq Ncring_Ring_ops. - Proof. - split; dropRingSyntax; eauto using left_identity, right_identity, commutative, associative, right_inverse, left_distributive, right_distributive, ring_sub_definition with core typeclass_instances. - - (* TODO: why does [eauto using @left_identity with typeclass_instances] not work? *) - eapply @left_identity; eauto with typeclass_instances. - - eapply @right_identity; eauto with typeclass_instances. - - eapply associative. - Qed. - End Ring. - - Section TacticSupportCommutative. - Context {T eq zero one opp add sub mul} `{@commutative_ring T eq zero one opp add sub mul}. - - Global Instance Cring_Cring_commutative_ring : - @Cring.Cring T zero one add mul sub opp eq Ring.Ncring_Ring_ops Ring.Ncring_Ring. - Proof. unfold Cring.Cring; intros; dropRingSyntax. eapply commutative. Qed. - End TacticSupportCommutative. -End Ring. - -Module IntegralDomain. - Section CommutativeRing. - Context {T eq zero one opp add sub mul} `{@integral_domain T eq zero one opp add sub mul}. - - Lemma mul_nonzero_nonzero_cases (x y : T) - : eq (mul x y) zero -> eq x zero \/ eq y zero. - Proof. - pose proof mul_nonzero_nonzero x y. - destruct (eq_dec x zero); destruct (eq_dec y zero); intuition. - Qed. - - Global Instance Integral_domain : - @Integral_domain.Integral_domain T zero one add mul sub opp eq Ring.Ncring_Ring_ops - Ring.Ncring_Ring Ring.Cring_Cring_commutative_ring. - Proof. - split; dropRingSyntax. - - auto using mul_nonzero_nonzero_cases. - - intro bad; symmetry in bad; auto using zero_neq_one. - Qed. - End CommutativeRing. -End IntegralDomain. - -Module Field. - Section Field. - Context {T eq zero one opp add mul sub inv div} `{@field T eq zero one opp add sub mul inv div}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Local Notation "0" := zero. Local Notation "1" := one. - Local Infix "+" := add. Local Infix "*" := mul. - - Global Instance is_mul_nonzero_nonzero : @is_mul_nonzero_nonzero T eq 0 mul. - Proof. - constructor. intros x y Hx Hy Hxy. - assert (0 = (inv y * (inv x * x)) * y) as H00 by (rewrite <-!associative, Hxy, !Ring.mul_0_r; reflexivity). - rewrite left_multiplicative_inverse in H00 by assumption. - rewrite right_identity in H00. - rewrite left_multiplicative_inverse in H00 by assumption. - auto using zero_neq_one. - Qed. - - Global Instance integral_domain : @integral_domain T eq zero one opp add sub mul. - Proof. - split; auto using field_commutative_ring, field_domain_is_zero_neq_one, is_mul_nonzero_nonzero. - Qed. - - Require Coq.setoid_ring.Field_theory. - Lemma field_theory_for_stdlib_tactic : Field_theory.field_theory 0 1 add mul sub opp div inv eq. - Proof. - constructor. - admit. - { intro H01. symmetry in H01. auto using zero_neq_one. } - { apply field_div_definition. } - { apply left_multiplicative_inverse. } - Qed. - End Field. -End Field. - -Module _NsatzExportGuarantine. - Require Import Coq.nsatz.Nsatz. - Ltac sane_nsatz := - let Hops := fresh "HRingOps" in - let carrierType := lazymatch goal with |- ?R ?x _ => type of x end in - let inst := constr:(_:Ncring.Ring (T:=carrierType)) in - lazymatch type of inst with - | @Ncring.Ring _ _ _ _ _ _ _ _ ?ops => - lazymatch type of ops with - @Ncring.Ring_ops ?F ?zero ?one ?add ?mul ?sub ?opp ?eq - => - pose ops as Hops; - (* (* apparently [nsatz] matches the goal to look for equalitites, so [eq] will need to become - [Algebra_syntax.equality]. However, reification is done using typeclasses so definitional - equality is enough (and faster) *) - change zero with (@Algebra_syntax.zero F (@Ncring.zero_notation F zero one add mul sub opp eq ops)) in *; - change one with (@Algebra_syntax.one F (@Ncring.one_notation F zero one add mul sub opp eq ops)) in *; - change add with (@Algebra_syntax.addition F (@Ncring.add_notation F zero one add mul sub opp eq ops)) in *; - change mul with (@Algebra_syntax.multiplication F F (@Ncring.mul_notation F zero one add mul sub opp eq ops)) in *; - change opp with (@Algebra_syntax.opposite F (@Ncring.opp_notation F zero one add mul sub opp eq ops)) in *; - change eq with (@Algebra_syntax.equality F (@Ncring.eq_notation F zero one add mul sub opp eq ops)) in *; - *) - move Hops at top (* [nsatz] requires equalities to be continuously at the bottom of the hypothesis list *) - end - end; - nsatz; - clear Hops. -End _NsatzExportGuarantine. -Import _NsatzExportGuarantine. -Ltac nsatz_without_field := sane_nsatz. - -Inductive field_simplify_done {T} : T -> Type := - Field_simplify_done : forall H, field_simplify_done H. - -Require Import Coq.setoid_ring.Field_tac. -Ltac field_simplify_eq_all := - repeat match goal with - [ H: _ |- _ ] => - match goal with - | [ Ha : field_simplify_done H |- _ ] => fail - | _ => idtac - end; - field_simplify_eq in H; - unique pose proof (Field_simplify_done H) - end; - repeat match goal with [ H: field_simplify_done _ |- _] => clear H end. - -Ltac nsatz := - field_simplify_eq_all; - try field_simplify_eq; - try nsatz_without_field. - -Section Example. - Context {F zero one opp add sub mul inv div} `{field F eq zero one opp add sub mul inv div}. - Local Infix "+" := add. Local Infix "*" := mul. Local Infix "-" := sub. Local Infix "/" := div. - - Add Field _ExampleField : (Field.field_theory_for_stdlib_tactic (T:=F)). - - Example _example_field_nsatz x y z : y <> zero -> x/y = z -> z*y + y = x + y. - Proof. intros. nsatz. assumption. Qed. -End Example. \ No newline at end of file -- cgit v1.2.3 From 39ec94341fa3a30d97d4462e9c9d481ada2c8d3d Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Fri, 17 Jun 2016 13:33:17 -0400 Subject: move nsatz out of algebra, improve algebra, port CompleteEdwardsCurveTheorems --- _CoqProject | 1 + src/Algebra.v | 267 +++++++----------- .../CompleteEdwardsCurveTheorems.v | 314 ++++++--------------- src/ModularArithmetic/ModularArithmeticTheorems.v | 3 +- src/Nsatz.v | 119 ++++++++ src/Spec/CompleteEdwardsCurve.v | 8 +- 6 files changed, 318 insertions(+), 394 deletions(-) create mode 100644 src/Nsatz.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index 2fc5b1b90..a0fbc5401 100644 --- a/_CoqProject +++ b/_CoqProject @@ -4,6 +4,7 @@ src/BaseSystem.v src/BaseSystemProofs.v src/EdDSAProofs.v src/Field.v +src/Nsatz.v src/Rep.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v diff --git a/src/Algebra.v b/src/Algebra.v index b5eb4a7f5..f6b2fa330 100644 --- a/src/Algebra.v +++ b/src/Algebra.v @@ -1,6 +1,6 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Require Import Util.Tactics. -Close Scope nat_scope. Close Scope type_scope. Close Scope core_scope. +Require Import Crypto.Util.Tactics Crypto.Nsatz. +Local Close Scope nat_scope. Local Close Scope type_scope. Local Close Scope core_scope. Section Algebra. Context {T:Type} {eq:T->T->Prop}. @@ -22,11 +22,18 @@ Section Algebra. { monoid_is_associative : is_associative; monoid_is_left_identity : is_left_identity; - monoid_is_right_identity : is_right_identity + monoid_is_right_identity : is_right_identity; + + monoid_op_Proper: Proper (respectful eq (respectful eq eq)) op; + monoid_Equivalence : Equivalence eq; + monoid_is_eq_dec : is_eq_dec }. Global Existing Instance monoid_is_associative. Global Existing Instance monoid_is_left_identity. Global Existing Instance monoid_is_right_identity. + Global Existing Instance monoid_Equivalence. + Global Existing Instance monoid_is_eq_dec. + Global Existing Instance monoid_op_Proper. Context {inv:T->T}. Class is_left_inverse := { left_inverse : forall x, op (inv x) x = id }. @@ -38,17 +45,11 @@ Section Algebra. group_is_left_inverse : is_left_inverse; group_is_right_inverse : is_right_inverse; - group_Equivalence : Equivalence eq; - group_is_eq_dec : is_eq_dec; - group_op_Proper: Proper (respectful eq (respectful eq eq)) op; group_inv_Proper: Proper (respectful eq eq) inv }. Global Existing Instance group_monoid. Global Existing Instance group_is_left_inverse. Global Existing Instance group_is_right_inverse. - Global Existing Instance group_Equivalence. - Global Existing Instance group_is_eq_dec. - Global Existing Instance group_op_Proper. Global Existing Instance group_inv_Proper. Class is_commutative := { commutative : forall x y, op x y = op y x }. @@ -137,45 +138,63 @@ Section Algebra. End Algebra. -Section GenericCancellation. - Context {T:Type} {eq:T->T->Prop} {Equivalence_eq : Equivalence eq}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Context {op:T->T->T} {Proper_op : Proper(respectful eq (respectful eq eq)) op}. - Context {id:T}. - - Context {Hassoc: is_associative (op:=op) (eq:=eq)}. - Context {Hrid: is_right_identity (op:=op) (eq:=eq) (id := id)}. - Context {Hlid: is_left_identity (op:=op) (eq:=eq) (id:=id) }. +Module Monoid. + Section Monoid. + Context {T eq op id} {monoid:@monoid T eq op id}. + Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Infix "*" := op. - Lemma cancel_right z iz (Hinv:op z iz = id) : - forall x y, op x z = op y z <-> x = y. - Proof. - split; intros. - { assert (op (op x z) iz = op (op y z) iz) as Hcut by (f_equiv; assumption). - rewrite <-associative in Hcut. - rewrite <-!associative, !Hinv, !right_identity in Hcut; exact Hcut. } - { f_equiv; assumption. } - Qed. + Lemma cancel_right z iz (Hinv:op z iz = id) : + forall x y, x * z = y * z <-> x = y. + Proof. + split; intros. + { assert (op (op x z) iz = op (op y z) iz) as Hcut by (f_equiv; assumption). + rewrite <-associative in Hcut. + rewrite <-!associative, !Hinv, !right_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. - Lemma cancel_left z iz (Hinv:op iz z = id) : - forall x y, op z x = op z y <-> x = y. - Proof. - split; intros. - { assert (op iz (op z x) = op iz (op z y)) as Hcut by (f_equiv; assumption). - rewrite !associative, !Hinv, !left_identity in Hcut; exact Hcut. } - { f_equiv; assumption. } - Qed. -End GenericCancellation. + Lemma cancel_left z iz (Hinv:op iz z = id) : + forall x y, z * x = z * y <-> x = y. + Proof. + split; intros. + { assert (op iz (op z x) = op iz (op z y)) as Hcut by (f_equiv; assumption). + rewrite !associative, !Hinv, !left_identity in Hcut; exact Hcut. } + { f_equiv; assumption. } + Qed. + + Lemma inv_inv x ix iix : ix*x = id -> iix*ix = id -> iix = x. + Proof. + intros Hi Hii. + assert (H:op iix id = op iix (op ix x)) by (rewrite Hi; reflexivity). + rewrite associative, Hii, left_identity, right_identity in H; exact H. + Qed. + + Lemma inv_op x y ix iy : ix*x = id -> iy*y = id -> (iy*ix)*(x*y) =id. + Proof. + intros Hx Hy. + cut (iy * (ix*x) * y = id); try intro H. + { rewrite <-!associative; rewrite <-!associative in H; exact H. } + rewrite Hx, right_identity, Hy. reflexivity. + Qed. + + End Monoid. +End Monoid. Module Group. Section BasicProperties. Context {T eq op id inv} `{@group T eq op id inv}. Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - - Lemma cancel_left : forall z x y, op z x = op z y <-> x = y. - Proof. eauto using cancel_left, left_inverse. Qed. - Lemma cancel_right : forall z x y, op x z = op y z <-> x = y. - Proof. eauto using cancel_right, right_inverse. Qed. + Local Infix "*" := op. + + Lemma cancel_left : forall z x y, z*x = z*y <-> x = y. + Proof. eauto using Monoid.cancel_left, left_inverse. Qed. + Lemma cancel_right : forall z x y, x*z = y*z <-> x = y. + Proof. eauto using Monoid.cancel_right, right_inverse. Qed. + Lemma inv_inv x : inv(inv(x)) = x. + Proof. eauto using Monoid.inv_inv, left_inverse. Qed. + Lemma inv_op x y : (inv y*inv x)*(x*y) =id. + Proof. eauto using Monoid.inv_op, left_inverse. Qed. End BasicProperties. Section Homomorphism. @@ -240,12 +259,12 @@ Module Ring. Local Notation "0" := zero. Local Notation "1" := one. Local Infix "+" := add. Local Infix "-" := sub. Local Infix "*" := mul. - Lemma mul_0_r : forall x, x * 0 = 0. + Lemma mul_0_r : forall x, 0 * x = 0. Proof. intros. - assert (x*0 = x*0) as Hx by reflexivity. - rewrite <-(left_identity 0), left_distributive in Hx at 1. - assert (x*0 + x*0 - x*0 = x*0 - x*0) as Hxx by (f_equiv; exact Hx). + assert (0*x = 0*x) as Hx by reflexivity. + rewrite <-(right_identity 0), right_distributive in Hx at 1. + assert (0*x + 0*x - 0*x = 0*x - 0*x) as Hxx by (f_equiv; exact Hx). rewrite !ring_sub_definition, <-associative, right_inverse, right_identity in Hxx; exact Hxx. Qed. @@ -258,6 +277,37 @@ Module Ring. rewrite associative, left_inverse, left_identity in Hxx; exact Hxx. Qed. + Lemma sub_0_l x : 0 - x = opp x. + Proof. rewrite ring_sub_definition. rewrite left_identity. reflexivity. Qed. + + Lemma mul_opp_r x y : x * opp y = opp (x * y). + Proof. + assert (Ho:x*(opp y) + x*y = 0) + by (rewrite <-left_distributive, left_inverse, mul_0_l; reflexivity). + rewrite <-(left_identity (opp (x*y))), <-Ho; clear Ho. + rewrite <-!associative, right_inverse, right_identity; reflexivity. + Qed. + + Lemma mul_opp_l x y : opp x * y = opp (x * y). + Proof. + assert (Ho:opp x*y + x*y = 0) + by (rewrite <-right_distributive, left_inverse, mul_0_r; reflexivity). + rewrite <-(left_identity (opp (x*y))), <-Ho; clear Ho. + rewrite <-!associative, right_inverse, right_identity; reflexivity. + Qed. + + Global Instance is_left_distributive_sub : is_left_distributive (eq:=eq)(add:=sub)(mul:=mul). + Proof. + split; intros. rewrite !ring_sub_definition, left_distributive. + eapply Group.cancel_left, mul_opp_r. + Qed. + + Global Instance is_right_distributive_sub : is_right_distributive (eq:=eq)(add:=sub)(mul:=mul). + Proof. + split; intros. rewrite !ring_sub_definition, right_distributive. + eapply Group.cancel_left, mul_opp_l. + Qed. + Global Instance Ncring_Ring_ops : @Ncring.Ring_ops T zero one add mul sub opp eq. Global Instance Ncring_Ring : @Ncring.Ring T zero one add mul sub opp eq Ncring_Ring_ops. Proof. @@ -266,6 +316,8 @@ Module Ring. eapply @left_identity; eauto with typeclass_instances. - eapply @right_identity; eauto with typeclass_instances. - eapply associative. + - intros; eapply right_distributive. + - intros; eapply left_distributive. Qed. Lemma opp_nonzero_nonzero : forall x, x <> 0 -> opp x <> 0. @@ -361,7 +413,7 @@ Module Field. Global Instance is_mul_nonzero_nonzero : @is_mul_nonzero_nonzero T eq 0 mul. Proof. constructor. intros x y Hx Hy Hxy. - assert (0 = (inv y * (inv x * x)) * y) as H00 by (rewrite <-!associative, Hxy, !Ring.mul_0_r; reflexivity). + assert (0 = (inv y * (inv x * x)) * y) as H00. (rewrite <-!associative, Hxy, !Ring.mul_0_l; reflexivity). rewrite left_multiplicative_inverse in H00 by assumption. rewrite right_identity in H00. rewrite left_multiplicative_inverse in H00 by assumption. @@ -456,128 +508,6 @@ Ltac field_simplify_eq_hyps := Ltac field_simplify_eq_all := field_simplify_eq_hyps; try field_simplify_eq. -(*** Tactics for manipulating polynomial equations *) -Require Nsatz. -Require Import List. -Open Scope core_scope. - -Generalizable All Variables. -Lemma cring_sub_diag_iff {R zero eq sub} `{cring:Cring.Cring (R:=R) (ring0:=zero) (ring_eq:=eq) (sub:=sub)} - : forall x y, eq (sub x y) zero <-> eq x y. -Proof. - split;intros Hx. - { eapply Nsatz.psos_r1b. eapply Hx. } - { eapply Nsatz.psos_r1. eapply Hx. } -Qed. - -Ltac get_goal := lazymatch goal with |- ?g => g end. - -Ltac nsatz_equation_implications_to_list eq zero g := - lazymatch g with - | eq ?p zero => constr:(p::nil) - | eq ?p zero -> ?g => let l := nsatz_equation_implications_to_list eq zero g in constr:(p::l) - end. - -Ltac nsatz_reify_equations eq zero := - let g := get_goal in - let lb := nsatz_equation_implications_to_list eq zero g in - lazymatch (eval red in (Ncring_tac.list_reifyl (lterm:=lb))) with - (?variables, ?le) => - lazymatch (eval compute in (List.rev le)) with - | ?reified_goal::?reified_givens => constr:(variables, reified_givens, reified_goal) - end - end. - -Ltac nsatz_get_free_variables reified_package := - lazymatch reified_package with (?fv, _, _) => fv end. - -Ltac nsatz_get_reified_givens reified_package := - lazymatch reified_package with (_, ?givens, _) => givens end. - -Ltac nsatz_get_reified_goal reified_package := - lazymatch reified_package with (_, _, ?goal) => goal end. - -Require Import Coq.setoid_ring.Ring_polynom. -Ltac nsatz_compute_to_goal sugar nparams reified_goal power reified_givens := - nsatz_compute (PEc sugar :: PEc nparams :: PEpow reified_goal power :: reified_givens). - -Ltac nsatz_compute_get_leading_coefficient := - lazymatch goal with - |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => a - end. - -Ltac nsatz_compute_get_certificate := - lazymatch goal with - |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => constr:(c,b) - end. - -Ltac nsatz_rewrite_and_revert domain := - lazymatch type of domain with - | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => - lazymatch goal with - | |- eq _ zero => idtac - | |- eq _ _ => rewrite <-(cring_sub_diag_iff (cring:=FCring)) - end; - repeat match goal with - | [H : eq _ zero |- _ ] => revert H - | [H : eq _ _ |- _ ] => rewrite <-(cring_sub_diag_iff (cring:=FCring)) in H; revert H - end - end. - -Ltac nsatz_nonzero := - try solve [apply Integral_domain.integral_domain_one_zero - |apply Integral_domain.integral_domain_minus_one_zero - |trivial - |apply Ring.opp_nonzero_nonzero;trivial]. - -Ltac nsatz_domain_sugar_power domain sugar power := - let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) - lazymatch type of domain with - | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => - nsatz_rewrite_and_revert domain; - let reified_package := nsatz_reify_equations eq zero in - let fv := nsatz_get_free_variables reified_package in - let interp := constr:(@Nsatz.PEevalR _ _ _ _ _ _ _ _ Fops fv) in - let reified_givens := nsatz_get_reified_givens reified_package in - let reified_goal := nsatz_get_reified_goal reified_package in - nsatz_compute_to_goal sugar nparams reified_goal power reified_givens; - let a := nsatz_compute_get_leading_coefficient in - let crt := nsatz_compute_get_certificate in - intros _ (* discard [nsatz_compute] output *); intros; - apply (fun Haa refl cond => @Integral_domain.Rintegral_domain_pow _ _ _ _ _ _ _ _ _ _ _ domain (interp a) _ (BinNat.N.to_nat power) Haa (@Nsatz.check_correct _ _ _ _ _ _ _ _ _ _ FCring fv reified_givens (PEmul a (PEpow reified_goal power)) crt refl cond)); - [ nsatz_nonzero; cbv iota beta delta [Nsatz.PEevalR PEeval InitialRing.gen_phiZ InitialRing.gen_phiPOS] - | solve [vm_compute; exact (eq_refl true)] (* exact_no_check (eq_refl true) *) - | solve [repeat (split; [assumption|]); exact I] ] - end. - -Ltac nsatz_guess_domain := - match goal with - | |- ?eq _ _ => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | |- not (?eq _ _) => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | [H: ?eq _ _ |- _ ] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | [H: not (?eq _ _) |- _] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - end. - -Ltac nsatz_sugar_power sugar power := - let domain := nsatz_guess_domain in - nsatz_domain_sugar_power domain sugar power. - -Tactic Notation "nsatz" constr(n) := - let nn := (eval compute in (BinNat.N.of_nat n)) in - nsatz_sugar_power BinInt.Z0 nn. - -Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. - -Ltac nsatz_contradict := - intros; - let domain := nsatz_guess_domain in - lazymatch type of domain with - | @Integral_domain.Integral_domain _ ?zero ?one _ _ _ _ ?eq ?Fops ?FRing ?FCring => - assert (eq one zero) as Hbad; - [nsatz; nsatz_nonzero - |destruct (Integral_domain.integral_domain_one_zero (Integral_domain:=domain) Hbad)] - end. - (*** Polynomial equations over fields *) Ltac field_algebra := @@ -587,6 +517,7 @@ Ltac field_algebra := repeat (apply conj); try solve [nsatz_nonzero + |apply Ring.opp_nonzero_nonzero;trivial |unfold not; intro; nsatz_contradict]. Section Example. diff --git a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v index 88ae9578c..4ad76856e 100644 --- a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v +++ b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v @@ -1,47 +1,32 @@ Require Export Crypto.Spec.CompleteEdwardsCurve. -Require Import Crypto.ModularArithmetic.FField. -Require Import Crypto.ModularArithmetic.FNsatz. +Require Import Crypto.Algebra Crypto.Nsatz. Require Import Crypto.CompleteEdwardsCurve.Pre. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. Module E. + Import Group Ring Field CompleteEdwardsCurve.E. Section CompleteEdwardsCurveTheorems. - Context {prm:TwistedEdwardsParams}. - Local Opaque q a d prime_q two_lt_q nonzero_a square_a nonsquare_d. (* [F_field] calls [compute] *) - Existing Instance prime_q. - - Add Field Ffield_p' : (@Ffield_theory q _) - (morphism (@Fring_morph q), - preprocess [Fpreprocess], - postprocess [Fpostprocess; try exact Fq_1_neq_0; try assumption], - constants [Fconstant], - div (@Fmorph_div_theory q), - power_tac (@Fpower_theory q) [Fexp_tac]). - - Add Field Ffield_notConstant : (OpaqueFieldTheory q) - (constants [notConstant]). - - Ltac clear_prm := - generalize dependent a; intro a; intros; - generalize dependent d; intro d; intros; - generalize dependent prime_q; intro prime_q; intros; - generalize dependent q; intro q; intros; - clear prm. - - Lemma point_eq : forall xy1 xy2 pf1 pf2, - xy1 = xy2 -> exist E.onCurve xy1 pf1 = exist E.onCurve xy2 pf2. - Proof. - destruct xy1, xy2; intros; find_injection; intros; subst. apply f_equal. - apply UIP_dec, F_eq_dec. (* this is a hack. We actually don't care about the equality of the proofs. However, we *can* prove it, and knowing it lets us use the universal equality instead of a type-specific equivalence, which makes many things nicer. *) - Qed. Hint Resolve point_eq. + Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv a d} + {field:@field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} + {prm:@twisted_edwards_params F Feq Fzero Fone Fadd Fmul a d}. + Local Infix "=" := Feq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := Fzero. Local Notation "1" := Fone. + Local Infix "+" := Fadd. Local Infix "*" := Fmul. + Local Infix "-" := Fsub. Local Infix "/" := Fdiv. + Local Notation "x ^2" := (x*x) (at level 30). + Local Notation point := (@point F Feq Fone Fadd Fmul a d). + Local Notation onCurve := (@onCurve F Feq Fone Fadd Fmul a d). + + Add Field _edwards_curve_theorems_field : (field_theory_for_stdlib_tactic (H:=field)). - Definition point_eqb (p1 p2:E.point) : bool := andb - (F_eqb (fst (proj1_sig p1)) (fst (proj1_sig p2))) - (F_eqb (snd (proj1_sig p1)) (snd (proj1_sig p2))). + Definition eq (P Q:point) := + let Feq2 (ab xy:F*F) := fst ab = fst xy /\ snd ab = snd xy in + Feq2 (coordinates P) (coordinates Q). + Infix "=" := eq : E_scope. + (* TODO:port Local Ltac t := unfold point_eqb; repeat match goal with @@ -94,207 +79,94 @@ Module E. Proof. intros. destruct (point_eq_dec p1 p2); eauto using point_eqb_complete, point_eqb_neq_complete. Qed. - - Ltac Edefn := unfold E.add, E.add', E.zero; intros; - repeat match goal with - | [ p : E.point |- _ ] => - let x := fresh "x" p in - let y := fresh "y" p in - let pf := fresh "pf" p in - destruct p as [[x y] pf]; unfold E.onCurve in pf - | _ => eapply point_eq, (f_equal2 pair) - | _ => eapply point_eq - end. - Lemma add_comm : forall A B, (A+B = B+A)%E. - Proof. - Edefn; apply (f_equal2 div); ring. - Qed. - - Ltac unifiedAdd_nonzero := match goal with - | [ |- (?op 1 (d * _ * _ * _ * _ * - inv (1 - d * ?xA * ?xB * ?yA * ?yB) * inv (1 + d * ?xA * ?xB * ?yA * ?yB)))%F <> 0%F] - => let Hadd := fresh "Hadd" in - pose proof (@unifiedAdd'_onCurve _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d (xA, yA) (xB, yB)) as Hadd; - simpl in Hadd; - match goal with - | [H : (1 - d * ?xC * xB * ?yC * yB)%F <> 0%F |- (?op 1 ?other)%F <> 0%F] => - replace other with - (d * xC * ((xA * yB + yA * xB) / (1 + d * xA * xB * yA * yB)) - * yC * ((yA * yB - a * xA * xB) / (1 - d * xA * xB * yA * yB)))%F by (subst; unfold div; ring); - auto - end - end. - - Lemma add_assoc : forall A B C, (A+(B+C) = (A+B)+C)%E. - Proof. - Edefn; F_field_simplify_eq; try abstract (rewrite ?@F_pow_2_r in *; clear_prm; F_nsatz); - pose proof (@edwardsAddCompletePlus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d); - pose proof (@edwardsAddCompleteMinus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d); - cbv beta iota in *; - repeat split; field_nonzero idtac; unifiedAdd_nonzero. - Qed. - - Lemma add_0_r : forall P, (P + E.zero = P)%E. - Proof. - Edefn; repeat rewrite ?F_add_0_r, ?F_add_0_l, ?F_sub_0_l, ?F_sub_0_r, - ?F_mul_0_r, ?F_mul_0_l, ?F_mul_1_l, ?F_mul_1_r, ?F_div_1_r; exact eq_refl. - Qed. + *) - Lemma add_0_l : forall P, (E.zero + P)%E = P. - Proof. - intros; rewrite add_comm. apply add_0_r. - Qed. + (* TODO: move to util *) + Lemma decide_and : forall P Q, {P}+{not P} -> {Q}+{not Q} -> {P/\Q}+{not(P/\Q)}. + Proof. intros; repeat match goal with [H:{_}+{_}|-_] => destruct H end; intuition. Qed. - Lemma mul_0_l : forall P, (0 * P = E.zero)%E. - Proof. - auto. - Qed. + Ltac destruct_points := + repeat match goal with + | [ p : point |- _ ] => + let x := fresh "x" p in + let y := fresh "y" p in + let pf := fresh "pf" p in + destruct p as [[x y] pf] + end. - Lemma mul_S_l : forall n P, (S n * P)%E = (P + n * P)%E. - Proof. - auto. - Qed. + Ltac expand_opp := + rewrite ?mul_opp_r, ?mul_opp_l, ?ring_sub_definition, ?inv_inv, <-?ring_sub_definition. - Lemma mul_add_l : forall a b P, ((a + b)%nat * P)%E = E.add (a * P)%E (b * P)%E. - Proof. - induction a; intros; rewrite ?plus_Sn_m, ?plus_O_n, ?mul_S_l, ?mul_0_l, ?add_0_l, ?mul_S_, ?IHa, ?add_assoc; auto. - Qed. + Local Hint Resolve char_gt_2. + Local Hint Resolve nonzero_a. + Local Hint Resolve square_a. + Local Hint Resolve nonsquare_d. + Local Hint Resolve @edwardsAddCompletePlus. + Local Hint Resolve @edwardsAddCompleteMinus. + + Program Definition opp (P:point) : point := + exist _ (let '(x, y) := coordinates P in (Fopp x, y) ) _. + Solve All Obligations using intros; destruct_points; simpl; field_algebra. - Lemma mul_assoc : forall (n m : nat) P, (n * (m * P) = (n * m)%nat * P)%E. + Global Instance edwards_acurve_abelian_group : abelian_group (eq:=eq)(op:=add)(id:=zero)(inv:=opp). Proof. - induction n; intros; auto. - rewrite ?mul_S_l, ?Mult.mult_succ_l, ?mul_add_l, ?IHn, add_comm. reflexivity. + repeat match goal with + | |- _ => progress intros + | [H: _ /\ _ |- _ ] => destruct H + | |- _ => progress destruct_points + | |- _ => progress cbv [fst snd coordinates proj1_sig eq add zero opp] in * + | |- _ => split + | |- Feq _ _ => common_denominator_all; try nsatz + | |- _ <> 0 => expand_opp; solve [nsatz_nonzero|eauto] + | |- {_}+{_} => eauto 15 using decide_and, @eq_dec with typeclass_instances + end. + (* TODO: port denominator-nonzero proofs for associativity *) + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. Qed. - Lemma mul_zero_r : forall m, (m * E.zero = E.zero)%E. - Proof. - induction m; rewrite ?mul_S_l, ?add_0_l; auto. - Qed. - - (* solve for x ^ 2 *) - Definition solve_for_x2 (y : F q) := ((y ^ 2 - 1) / (d * (y ^ 2) - a))%F. - - Lemma d_y2_a_nonzero : (forall y, 0 <> d * y ^ 2 - a)%F. - intros ? eq_zero. - pose proof prime_q. - destruct square_a as [sqrt_a sqrt_a_id]. - rewrite <- sqrt_a_id in eq_zero. - destruct (Fq_square_mul_sub _ _ _ eq_zero) as [ [sqrt_d sqrt_d_id] | a_zero]. - + pose proof (nonsquare_d sqrt_d); auto. - + subst. - rewrite Fq_pow_zero in sqrt_a_id by congruence. - auto using nonzero_a. - Qed. - - Lemma a_d_y2_nonzero : (forall y, a - d * y ^ 2 <> 0)%F. - Proof. - intros y eq_zero. - pose proof prime_q. - eapply F_minus_swap in eq_zero. - eauto using (d_y2_a_nonzero y). - Qed. - - Lemma solve_correct : forall x y, E.onCurve (x, y) <-> - (x ^ 2 = solve_for_x2 y)%F. + (* TODO: move to [Group] and [AbelianGroup] as appropriate *) + Lemma mul_0_l : forall P, (0 * P = zero)%E. + Proof. intros; reflexivity. Qed. + Lemma mul_S_l : forall n P, (S n * P = P + n * P)%E. + Proof. intros; reflexivity. Qed. + Lemma mul_add_l : forall (n m:nat) (P:point), ((n + m)%nat * P = n * P + m * P)%E. Proof. - split. - + intro onCurve_x_y. - pose proof prime_q. - unfold E.onCurve in onCurve_x_y. - eapply F_div_mul; auto using (d_y2_a_nonzero y). - replace (x ^ 2 * (d * y ^ 2 - a))%F with ((d * x ^ 2 * y ^ 2) - (a * x ^ 2))%F by ring. - rewrite F_sub_add_swap. - replace (y ^ 2 + a * x ^ 2)%F with (a * x ^ 2 + y ^ 2)%F by ring. - rewrite onCurve_x_y. - ring. - + intro x2_eq. - unfold E.onCurve, solve_for_x2 in *. - rewrite x2_eq. - field. - auto using d_y2_a_nonzero. + induction n; intros; + rewrite ?plus_Sn_m, ?plus_O_n, ?mul_S_l, ?left_identity, <-?associative, <-?IHn; reflexivity. Qed. - - - Definition opp' (xy:(F q*F q)) : (F q * F q) := let '(x, y) := xy in (opp x, y). - Definition opp (P:E.point) : E.point. exists (opp' (proj1_sig P)). - Proof. - destruct P as [[]]; simpl; rewrite F_square_opp; trivial. - Defined. - - Definition sub P Q := (P + opp Q)%E. - - Lemma opp_zero : opp E.zero = E.zero. - Proof. - pose proof @F_opp_0. - unfold opp, opp', E.zero; simpl; eapply point_eq; congruence. - Qed. - - Lemma add_opp_r : forall P, (P + opp P = E.zero)%E. - Proof. - unfold opp, opp'; Edefn; rewrite ?@F_pow_2_r in *; (F_field_simplify_eq; [clear_prm; F_nsatz|..]); - rewrite <-?@F_pow_2_r in *; - pose proof (@edwardsAddCompletePlus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d _ _ _ _ pfP pfP); - pose proof (@edwardsAddCompleteMinus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d _ _ _ _ pfP pfP); - field_nonzero idtac. - Qed. - - Lemma add_opp_l : forall P, (opp P + P = E.zero)%E. + Lemma mul_assoc : forall (n m : nat) P, (n * (m * P) = (n * m)%nat * P)%E. Proof. - intros. rewrite add_comm. eapply add_opp_r. + induction n; intros; [reflexivity|]. + rewrite ?mul_S_l, ?Mult.mult_succ_l, ?mul_add_l, ?IHn, commutative; reflexivity. Qed. - - Lemma add_cancel_r : forall A B C, (B+A = C+A -> B = C)%E. + Lemma mul_zero_r : forall m, (m * E.zero = E.zero)%E. + Proof. induction m; rewrite ?mul_S_l, ?left_identity, ?IHm; try reflexivity. Qed. + (* + Lemma opp_mul : forall n P, (opp (n * P) = n * (opp P))%E. Proof. - intros. - assert ((B + A) + opp A = (C + A) + opp A)%E as Hc by congruence. - rewrite <-!add_assoc, !add_opp_r, !add_0_r in Hc; exact Hc. + induction n. intros. simpl. admit. Qed. + *) - Lemma add_cancel_l : forall A B C, (A+B = A+C -> B = C)%E. - Proof. - intros. - rewrite (add_comm A C) in H. - rewrite (add_comm A B) in H. - eauto using add_cancel_r. - Qed. - - Lemma shuffle_eq_add_opp : forall P Q R, (P + Q = R <-> Q = opp P + R)%E. - Proof. - split; intros. - { assert (opp P + (P + Q) = opp P + R)%E as Hc by congruence. - rewrite add_assoc, add_opp_l, add_comm, add_0_r in Hc; exact Hc. } - { subst. rewrite add_assoc, add_opp_r, add_comm, add_0_r; reflexivity. } - Qed. - - Lemma opp_opp : forall P, opp (opp P) = P. - Proof. - intros. - pose proof (add_opp_r P%E) as H. - rewrite add_comm in H. - rewrite shuffle_eq_add_opp in H. - rewrite add_0_r in H. - congruence. - Qed. - - Lemma opp_add : forall P Q, opp (P + Q)%E = (opp P + opp Q)%E. - Proof. - intros. - pose proof (add_opp_r (P+Q)%E) as H. - rewrite <-!add_assoc in H. - rewrite add_comm in H. - rewrite <-!add_assoc in H. - rewrite shuffle_eq_add_opp in H. - rewrite add_comm in H. - rewrite shuffle_eq_add_opp in H. - rewrite add_0_r in H. - assumption. - Qed. + + Section PointCompression. + Local Notation "x ^2" := (x*x). + Definition solve_for_x2 (y : F) := ((y^2 - 1) / (d * (y^2) - a)). - Lemma opp_mul : forall n P, opp (E.mul n P) = E.mul n (opp P). - Proof. - pose proof opp_add; pose proof opp_zero. - induction n; trivial; intros; rewrite !mul_S_l, opp_add; congruence. - Qed. + Lemma a_d_y2_nonzero : forall y, d * y^2 - a <> 0. + Proof. + intros ? eq_zero. + destruct square_a as [sqrt_a sqrt_a_id]; rewrite <- sqrt_a_id in eq_zero. + destruct (eq_dec y 0); [apply nonzero_a|apply nonsquare_d with (sqrt_a/y)]; field_algebra. + Qed. + + Lemma solve_correct : forall x y, onCurve (x, y) <-> (x^2 = solve_for_x2 y). + Proof. + unfold solve_for_x2; simpl; split; intros; field_algebra; auto using a_d_y2_nonzero. + Qed. + End PointCompression. End CompleteEdwardsCurveTheorems. -End E. -Infix "-" := E.sub : E_scope. \ No newline at end of file +End E. \ No newline at end of file diff --git a/src/ModularArithmetic/ModularArithmeticTheorems.v b/src/ModularArithmetic/ModularArithmeticTheorems.v index fe7600784..4e0ba461e 100644 --- a/src/ModularArithmetic/ModularArithmeticTheorems.v +++ b/src/ModularArithmetic/ModularArithmeticTheorems.v @@ -154,9 +154,10 @@ Section FandZ. Proof. repeat split; Fdefn. { rewrite Z.add_0_r. auto. } - { rewrite <-Z.add_sub_swap, <-Z.add_sub_assoc, Z.sub_diag, Z.add_0_r. apply Z_mod_same_full. } { apply F_eq_dec. } + { rewrite <-Z.add_sub_swap, <-Z.add_sub_assoc, Z.sub_diag, Z.add_0_r. apply Z_mod_same_full. } { rewrite Z.mul_1_r. auto. } + { apply F_eq_dec. } Qed. Lemma ZToField_0 : @ZToField m 0 = 0. diff --git a/src/Nsatz.v b/src/Nsatz.v new file mode 100644 index 000000000..c8a648626 --- /dev/null +++ b/src/Nsatz.v @@ -0,0 +1,119 @@ +(*** Tactics for manipulating polynomial equations *) +Require Nsatz. +Require Import List. + +Generalizable All Variables. +Lemma cring_sub_diag_iff {R zero eq sub} `{cring:Cring.Cring (R:=R) (ring0:=zero) (ring_eq:=eq) (sub:=sub)} + : forall x y, eq (sub x y) zero <-> eq x y. +Proof. + split;intros Hx. + { eapply Nsatz.psos_r1b. eapply Hx. } + { eapply Nsatz.psos_r1. eapply Hx. } +Qed. + +Ltac get_goal := lazymatch goal with |- ?g => g end. + +Ltac nsatz_equation_implications_to_list eq zero g := + lazymatch g with + | eq ?p zero => constr:(p::nil) + | eq ?p zero -> ?g => let l := nsatz_equation_implications_to_list eq zero g in constr:(p::l) + end. + +Ltac nsatz_reify_equations eq zero := + let g := get_goal in + let lb := nsatz_equation_implications_to_list eq zero g in + lazymatch (eval red in (Ncring_tac.list_reifyl (lterm:=lb))) with + (?variables, ?le) => + lazymatch (eval compute in (List.rev le)) with + | ?reified_goal::?reified_givens => constr:(variables, reified_givens, reified_goal) + end + end. + +Ltac nsatz_get_free_variables reified_package := + lazymatch reified_package with (?fv, _, _) => fv end. + +Ltac nsatz_get_reified_givens reified_package := + lazymatch reified_package with (_, ?givens, _) => givens end. + +Ltac nsatz_get_reified_goal reified_package := + lazymatch reified_package with (_, _, ?goal) => goal end. + +Require Import Coq.setoid_ring.Ring_polynom. +Ltac nsatz_compute_to_goal sugar nparams reified_goal power reified_givens := + nsatz_compute (PEc sugar :: PEc nparams :: PEpow reified_goal power :: reified_givens). + +Ltac nsatz_compute_get_leading_coefficient := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => a + end. + +Ltac nsatz_compute_get_certificate := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => constr:(c,b) + end. + +Ltac nsatz_rewrite_and_revert domain := + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + lazymatch goal with + | |- eq _ zero => idtac + | |- eq _ _ => rewrite <-(cring_sub_diag_iff (cring:=FCring)) + end; + repeat match goal with + | [H : eq _ zero |- _ ] => revert H + | [H : eq _ _ |- _ ] => rewrite <-(cring_sub_diag_iff (cring:=FCring)) in H; revert H + end + end. + +Ltac nsatz_nonzero := + try solve [apply Integral_domain.integral_domain_one_zero + |apply Integral_domain.integral_domain_minus_one_zero + |trivial]. + +Ltac nsatz_domain_sugar_power domain sugar power := + let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + nsatz_rewrite_and_revert domain; + let reified_package := nsatz_reify_equations eq zero in + let fv := nsatz_get_free_variables reified_package in + let interp := constr:(@Nsatz.PEevalR _ _ _ _ _ _ _ _ Fops fv) in + let reified_givens := nsatz_get_reified_givens reified_package in + let reified_goal := nsatz_get_reified_goal reified_package in + nsatz_compute_to_goal sugar nparams reified_goal power reified_givens; + let a := nsatz_compute_get_leading_coefficient in + let crt := nsatz_compute_get_certificate in + intros _ (* discard [nsatz_compute] output *); intros; + apply (fun Haa refl cond => @Integral_domain.Rintegral_domain_pow _ _ _ _ _ _ _ _ _ _ _ domain (interp a) _ (BinNat.N.to_nat power) Haa (@Nsatz.check_correct _ _ _ _ _ _ _ _ _ _ FCring fv reified_givens (PEmul a (PEpow reified_goal power)) crt refl cond)); + [ nsatz_nonzero; cbv iota beta delta [Nsatz.PEevalR PEeval InitialRing.gen_phiZ InitialRing.gen_phiPOS] + | solve [vm_compute; exact (eq_refl true)] (* exact_no_check (eq_refl true) *) + | solve [repeat (split; [assumption|]); exact I] ] + end. + +Ltac nsatz_guess_domain := + match goal with + | |- ?eq _ _ => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | |- not (?eq _ _) => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: ?eq _ _ |- _ ] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: not (?eq _ _) |- _] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + end. + +Ltac nsatz_sugar_power sugar power := + let domain := nsatz_guess_domain in + nsatz_domain_sugar_power domain sugar power. + +Tactic Notation "nsatz" constr(n) := + let nn := (eval compute in (BinNat.N.of_nat n)) in + nsatz_sugar_power BinInt.Z0 nn. + +Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. + +Ltac nsatz_contradict := + intros; + let domain := nsatz_guess_domain in + lazymatch type of domain with + | @Integral_domain.Integral_domain _ ?zero ?one _ _ _ _ ?eq ?Fops ?FRing ?FCring => + assert (eq one zero) as Hbad; + [nsatz; nsatz_nonzero + |destruct (Integral_domain.integral_domain_one_zero (Integral_domain:=domain) Hbad)] + end. \ No newline at end of file diff --git a/src/Spec/CompleteEdwardsCurve.v b/src/Spec/CompleteEdwardsCurve.v index 518d3d551..5df36e295 100644 --- a/src/Spec/CompleteEdwardsCurve.v +++ b/src/Spec/CompleteEdwardsCurve.v @@ -8,11 +8,11 @@ Module E. * *) - Context {F eq Fzero one opp Fadd sub Fmul inv div} `{Algebra.field F eq Fzero one opp Fadd sub Fmul inv div}. - Local Infix "=" := eq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. - Local Notation "0" := Fzero. Local Notation "1" := one. + Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} `{Algebra.field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv}. + Local Infix "=" := Feq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := Fzero. Local Notation "1" := Fone. Local Infix "+" := Fadd. Local Infix "*" := Fmul. - Local Infix "-" := sub. Local Infix "/" := div. + Local Infix "-" := Fsub. Local Infix "/" := Fdiv. Local Notation "x ^2" := (x*x) (at level 30). Context {a d: F}. -- cgit v1.2.3 From e72cc12f4fa668f82fe5fd20fa5a20b30f9ecd00 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Sat, 18 Jun 2016 20:00:32 -0400 Subject: port CompleteEdwardsCurve.ExtendedCoordinates, make [field_algebra] try fewer nonzero ports. remove FField and FNsatz --- _CoqProject | 3 +- src/Algebra.v | 68 +++- .../CompleteEdwardsCurveTheorems.v | 106 +++-- src/CompleteEdwardsCurve/ExtendedCoordinates.v | 431 +++++++++++---------- src/CompleteEdwardsCurve/Pre.v | 4 +- src/ModularArithmetic/FField.v | 63 --- src/ModularArithmetic/FNsatz.v | 40 -- src/Nsatz.v | 3 +- src/Util/Fieldwise.v | 42 ++ 9 files changed, 397 insertions(+), 363 deletions(-) delete mode 100644 src/ModularArithmetic/FField.v delete mode 100644 src/ModularArithmetic/FNsatz.v create mode 100644 src/Util/Fieldwise.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index a0fbc5401..21aca1390 100644 --- a/_CoqProject +++ b/_CoqProject @@ -17,8 +17,6 @@ src/Encoding/ModularWordEncodingTheorems.v src/Encoding/PointEncodingPre.v src/Encoding/PointEncodingTheorems.v src/ModularArithmetic/ExtendedBaseVector.v -src/ModularArithmetic/FField.v -src/ModularArithmetic/FNsatz.v src/ModularArithmetic/ModularArithmeticTheorems.v src/ModularArithmetic/ModularBaseSystem.v src/ModularArithmetic/ModularBaseSystemOpt.v @@ -41,6 +39,7 @@ src/Specific/GF1305.v src/Specific/GF25519.v src/Tactics/VerdiTactics.v src/Util/CaseUtil.v +src/Util/Fieldwise.v src/Util/IterAssocOp.v src/Util/ListUtil.v src/Util/NatUtil.v diff --git a/src/Algebra.v b/src/Algebra.v index f6b2fa330..27c0d2e59 100644 --- a/src/Algebra.v +++ b/src/Algebra.v @@ -181,6 +181,15 @@ Module Monoid. End Monoid. End Monoid. +Section ZeroNeqOne. + Context {T eq zero one} `{@is_zero_neq_one T eq zero one} `{Equivalence T eq}. + + Lemma one_neq_zero : not (eq one zero). + Proof. + intro HH; symmetry in HH. auto using zero_neq_one. + Qed. +End ZeroNeqOne. + Module Group. Section BasicProperties. Context {T eq op id inv} `{@group T eq op id inv}. @@ -195,11 +204,37 @@ Module Group. Proof. eauto using Monoid.inv_inv, left_inverse. Qed. Lemma inv_op x y : (inv y*inv x)*(x*y) =id. Proof. eauto using Monoid.inv_op, left_inverse. Qed. + + Lemma inv_unique x ix : ix * x = id -> ix = inv x. + Proof. + intro Hix. + cut (ix*x*inv x = inv x). + - rewrite <-associative, right_inverse, right_identity; trivial. + - rewrite Hix, left_identity; reflexivity. + Qed. + + Lemma inv_id : inv id = id. + Proof. symmetry. eapply inv_unique, left_identity. Qed. + + Lemma inv_nonzero_nonzero : forall x, x <> id -> inv x <> id. + Proof. + intros ? Hx Ho. + assert (Hxo: x * inv x = id) by (rewrite right_inverse; reflexivity). + rewrite Ho, right_identity in Hxo. intuition. + Qed. + + Section ZeroNeqOne. + Context {one} `{is_zero_neq_one T eq id one}. + Lemma opp_one_neq_zero : inv one <> id. + Proof. apply inv_nonzero_nonzero, one_neq_zero. Qed. + Lemma zero_neq_opp_one : id <> inv one. + Proof. intro Hx. symmetry in Hx. eauto using opp_one_neq_zero. Qed. + End ZeroNeqOne. End BasicProperties. Section Homomorphism. - Context {H eq op id inv} `{@group H eq op id inv}. - Context {G EQ OP ID INV} `{@group G EQ OP ID INV}. + Context {G EQ OP ID INV} {groupG:@group G EQ OP ID INV}. + Context {H eq op id inv} {groupH:@group H eq op id inv}. Context {phi:G->H}. Local Infix "=" := eq. Local Infix "=" := eq : type_scope. @@ -296,6 +331,8 @@ Module Ring. rewrite <-!associative, right_inverse, right_identity; reflexivity. Qed. + Definition opp_nonzero_nonzero : forall x, x <> 0 -> opp x <> 0 := Group.inv_nonzero_nonzero. + Global Instance is_left_distributive_sub : is_left_distributive (eq:=eq)(add:=sub)(mul:=mul). Proof. split; intros. rewrite !ring_sub_definition, left_distributive. @@ -319,13 +356,6 @@ Module Ring. - intros; eapply right_distributive. - intros; eapply left_distributive. Qed. - - Lemma opp_nonzero_nonzero : forall x, x <> 0 -> opp x <> 0. - Proof. - intros ? Hx Ho. - assert (Hxo: x + opp x = 0) by (rewrite right_inverse; reflexivity). - rewrite Ho, right_identity in Hxo. intuition. - Qed. End Ring. Section Homomorphism. @@ -382,7 +412,7 @@ Module Ring. End Ring. Module IntegralDomain. - Section CommutativeRing. + Section IntegralDomain. Context {T eq zero one opp add sub mul} `{@integral_domain T eq zero one opp add sub mul}. Lemma mul_nonzero_nonzero_cases (x y : T) @@ -400,7 +430,7 @@ Module IntegralDomain. - auto using mul_nonzero_nonzero_cases. - intro bad; symmetry in bad; auto using zero_neq_one. Qed. - End CommutativeRing. + End IntegralDomain. End IntegralDomain. Module Field. @@ -454,7 +484,6 @@ Module Field. End Homomorphism. End Field. - (*** Tactics for manipulating field equations *) Require Import Coq.setoid_ring.Field_tac. @@ -488,7 +517,7 @@ Ltac common_denominator_in H := Ltac common_denominator_all := common_denominator; - repeat match goal with [H: _ |- _ _ _ ] => common_denominator_in H end. + repeat match goal with [H: _ |- _ _ _ ] => progress common_denominator_in H end. Inductive field_simplify_done {T} : T -> Type := Field_simplify_done : forall H, field_simplify_done H. @@ -510,15 +539,22 @@ Ltac field_simplify_eq_all := field_simplify_eq_hyps; try field_simplify_eq. (*** Polynomial equations over fields *) +Ltac neq01 := + try solve + [apply zero_neq_one + |apply Group.zero_neq_opp_one + |apply one_neq_zero + |apply Group.opp_one_neq_zero]. + Ltac field_algebra := intros; common_denominator_all; try (nsatz; dropRingSyntax); repeat (apply conj); try solve - [nsatz_nonzero - |apply Ring.opp_nonzero_nonzero;trivial - |unfold not; intro; nsatz_contradict]. + [neq01 + |trivial + |apply Ring.opp_nonzero_nonzero;trivial]. Section Example. Context {F zero one opp add sub mul inv div} `{F_field:field F eq zero one opp add sub mul inv div}. diff --git a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v index 4ad76856e..e6ec7ab86 100644 --- a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v +++ b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v @@ -4,6 +4,9 @@ Require Import Crypto.Algebra Crypto.Nsatz. Require Import Crypto.CompleteEdwardsCurve.Pre. Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. +Require Import Coq.Classes.Morphisms. +Require Import Relation_Definitions. +Require Import Crypto.Util.Fieldwise. Module E. Import Group Ring Field CompleteEdwardsCurve.E. @@ -21,12 +24,10 @@ Module E. Add Field _edwards_curve_theorems_field : (field_theory_for_stdlib_tactic (H:=field)). - Definition eq (P Q:point) := - let Feq2 (ab xy:F*F) := fst ab = fst xy /\ snd ab = snd xy in - Feq2 (coordinates P) (coordinates Q). + Definition eq (P Q:point) := fieldwise (n:=2) Feq (coordinates P) (coordinates Q). Infix "=" := eq : E_scope. - (* TODO:port + (* TODO: decide whether we still want something like this, then port Local Ltac t := unfold point_eqb; repeat match goal with @@ -108,23 +109,30 @@ Module E. exist _ (let '(x, y) := coordinates P in (Fopp x, y) ) _. Solve All Obligations using intros; destruct_points; simpl; field_algebra. + Ltac bash := + repeat match goal with + | |- _ => progress intros + | [H: _ /\ _ |- _ ] => destruct H + | |- _ => progress destruct_points + | |- _ => progress cbv [fst snd coordinates proj1_sig eq fieldwise fieldwise' add zero opp] in * + | |- _ => split + | |- Feq _ _ => field_algebra + | |- _ <> 0 => expand_opp; solve [nsatz_nonzero|eauto] + | |- {_}+{_} => eauto 15 using decide_and, @eq_dec with typeclass_instances + end. + + Global Instance Proper_add : Proper (eq==>eq==>eq) add. Proof. bash. Qed. + Global Instance Proper_opp : Proper (eq==>eq) opp. Proof. bash. Qed. + Global Instance Proper_coordinates : Proper (eq==>fieldwise (n:=2) Feq) coordinates. Proof. bash. Qed. + Global Instance edwards_acurve_abelian_group : abelian_group (eq:=eq)(op:=add)(id:=zero)(inv:=opp). Proof. - repeat match goal with - | |- _ => progress intros - | [H: _ /\ _ |- _ ] => destruct H - | |- _ => progress destruct_points - | |- _ => progress cbv [fst snd coordinates proj1_sig eq add zero opp] in * - | |- _ => split - | |- Feq _ _ => common_denominator_all; try nsatz - | |- _ <> 0 => expand_opp; solve [nsatz_nonzero|eauto] - | |- {_}+{_} => eauto 15 using decide_and, @eq_dec with typeclass_instances - end. - (* TODO: port denominator-nonzero proofs for associativity *) - match goal with | |- _ <> 0 => admit end. - match goal with | |- _ <> 0 => admit end. - match goal with | |- _ <> 0 => admit end. - match goal with | |- _ <> 0 => admit end. + bash. + (* TODO: port denominator-nonzero proofs for associativity *) + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. + match goal with | |- _ <> 0 => admit end. Qed. (* TODO: move to [Group] and [AbelianGroup] as appropriate *) @@ -144,13 +152,8 @@ Module E. Qed. Lemma mul_zero_r : forall m, (m * E.zero = E.zero)%E. Proof. induction m; rewrite ?mul_S_l, ?left_identity, ?IHm; try reflexivity. Qed. - (* Lemma opp_mul : forall n P, (opp (n * P) = n * (opp P))%E. - Proof. - induction n. intros. simpl. admit. - Qed. - *) - + Admitted. Section PointCompression. Local Notation "x ^2" := (x*x). @@ -169,4 +172,57 @@ Module E. Qed. End PointCompression. End CompleteEdwardsCurveTheorems. + + Section Homomorphism. + Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv Fa Fd} + {fieldF:@field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} + {Fprm:@twisted_edwards_params F Feq Fzero Fone Fadd Fmul Fa Fd}. + Context {K Keq Kzero Kone Kopp Kadd Ksub Kmul Kinv Kdiv Ka Kd} + {fieldK:@field K Keq Kzero Kone Kopp Kadd Ksub Kmul Kinv Kdiv} + {Kprm:@twisted_edwards_params K Keq Kzero Kone Kadd Kmul Ka Kd}. + Context {phi:F->K} {Hphi:@Ring.is_homomorphism F Feq Fone Fadd Fmul + K Keq Kone Kadd Kmul phi}. + Context {Ha:Keq (phi Fa) Ka} {Hd:Keq (phi Fd) Kd}. + Local Notation Fpoint := (@point F Feq Fone Fadd Fmul Fa Fd). + Local Notation Kpoint := (@point K Keq Kone Kadd Kmul Ka Kd). + + Create HintDb field_homomorphism discriminated. + Hint Rewrite <- + homomorphism_one + homomorphism_add + homomorphism_sub + homomorphism_mul + homomorphism_div + Ha + Hd + : field_homomorphism. + + Program Definition ref_phi (P:Fpoint) : Kpoint := exist _ ( + let (x, y) := coordinates P in (phi x, phi y)) _. + Next Obligation. + destruct P as [[? ?] ?]; simpl. + rewrite_strat bottomup hints field_homomorphism. + eauto using is_homomorphism_phi_proper; assumption. + Qed. + + Context {point_phi:Fpoint->Kpoint} + {point_phi_Proper:Proper (eq==>eq) point_phi} + {point_phi_correct: forall (P:Fpoint), eq (point_phi P) (ref_phi P)}. + + Lemma lift_homomorphism : @Group.is_homomorphism Fpoint eq add Kpoint eq add point_phi. + Proof. + repeat match goal with + | |- Group.is_homomorphism => split + | |- _ => intro + | |- _ /\ _ => split + | [H: _ /\ _ |- _ ] => destruct H + | [p: point |- _ ] => destruct p as [[??]?] + | |- context[point_phi] => setoid_rewrite point_phi_correct + | |- _ => progress cbv [fst snd coordinates proj1_sig eq fieldwise fieldwise' add zero opp ref_phi] in * + | |- Keq ?x ?x => reflexivity + | |- Keq ?x ?y => rewrite_strat bottomup hints field_homomorphism + | [ H : Feq _ _ |- Keq (phi _) (phi _)] => solve [f_equiv; intuition] + end. + Qed. + End Homomorphism. End E. \ No newline at end of file diff --git a/src/CompleteEdwardsCurve/ExtendedCoordinates.v b/src/CompleteEdwardsCurve/ExtendedCoordinates.v index 44033097d..4a352c738 100644 --- a/src/CompleteEdwardsCurve/ExtendedCoordinates.v +++ b/src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -1,202 +1,154 @@ -Require Import Crypto.CompleteEdwardsCurve.Pre. -Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. -Require Import Crypto.ModularArithmetic.FField. -Require Import Crypto.Tactics.VerdiTactics. -Require Import Util.IterAssocOp BinNat NArith. -Require Import Coq.Setoids.Setoid Coq.Classes.Morphisms Coq.Classes.Equivalence. -Local Open Scope equiv_scope. -Local Open Scope F_scope. - -Section ExtendedCoordinates. - Context {prm:TwistedEdwardsParams}. - Local Opaque q a d prime_q two_lt_q nonzero_a square_a nonsquare_d. (* [F_field] calls [compute] *) - Existing Instance prime_q. - - Add Field Ffield_p' : (@Ffield_theory q _) - (morphism (@Fring_morph q), - preprocess [Fpreprocess], - postprocess [Fpostprocess; try exact Fq_1_neq_0; try assumption], - constants [Fconstant], - div (@Fmorph_div_theory q), - power_tac (@Fpower_theory q) [Fexp_tac]). - - Add Field Ffield_notConstant : (OpaqueFieldTheory q) - (constants [notConstant]). - - (** [extended] represents a point on an elliptic curve using extended projective - * Edwards coordinates with twist a=-1 (see ). *) - Record extended := mkExtended {extendedX : F q; - extendedY : F q; - extendedZ : F q; - extendedT : F q}. - Local Notation "'(' X ',' Y ',' Z ',' T ')'" := (mkExtended X Y Z T). - - Definition twistedToExtended (P : (F q*F q)) : extended := - let '(x, y) := P in (x, y, 1, x*y). - Definition extendedToTwisted (P : extended) : F q * F q := - let '(X, Y, Z, T) := P in ((X/Z), (Y/Z)). - Definition rep (P:extended) (rP:(F q*F q)) : Prop := - let '(X, Y, Z, T) := P in - extendedToTwisted P = rP /\ - Z <> 0 /\ - T = X*Y/Z. - Local Hint Unfold twistedToExtended extendedToTwisted rep. - Local Notation "P '~=' rP" := (rep P rP) (at level 70). - - Ltac unfoldExtended := - repeat progress (autounfold; unfold E.onCurve, E.add, E.add', rep in *; intros); - repeat match goal with - | [ p : (F q*F q)%type |- _ ] => - let x := fresh "x" p in - let y := fresh "y" p in - destruct p as [x y] - | [ p : extended |- _ ] => - let X := fresh "X" p in - let Y := fresh "Y" p in - let Z := fresh "Z" p in - let T := fresh "T" p in - destruct p as [X Y Z T] - | [ H: _ /\ _ |- _ ] => destruct H - | [ H: @eq (F q * F q)%type _ _ |- _ ] => invcs H - | [ H: @eq F q ?x _ |- _ ] => isVar x; rewrite H; clear H - end. - - Ltac solveExtended := unfoldExtended; - repeat match goal with - | [ |- _ /\ _ ] => split - | [ |- @eq (F q * F q)%type _ _] => apply f_equal2 - | _ => progress rewrite ?@F_add_0_r, ?@F_add_0_l, ?@F_sub_0_l, ?@F_sub_0_r, - ?@F_mul_0_r, ?@F_mul_0_l, ?@F_mul_1_l, ?@F_mul_1_r, ?@F_div_1_r - | _ => solve [eapply @Fq_1_neq_0; eauto with typeclass_instances] - | _ => solve [eauto with typeclass_instances] - | [ H: a = _ |- _ ] => rewrite H - end. - - Lemma twistedToExtended_rep : forall P, twistedToExtended P ~= P. - Proof. - solveExtended. - Qed. - - Lemma extendedToTwisted_rep : forall P rP, P ~= rP -> extendedToTwisted P = rP. - Proof. - solveExtended. - Qed. - - Definition extendedPoint := { P:extended | rep P (extendedToTwisted P) /\ E.onCurve (extendedToTwisted P) }. - - Program Definition mkExtendedPoint : E.point -> extendedPoint := twistedToExtended. - Next Obligation. - destruct x; erewrite extendedToTwisted_rep; eauto using twistedToExtended_rep. - Qed. - - Program Definition unExtendedPoint : extendedPoint -> E.point := extendedToTwisted. - Next Obligation. - destruct x; simpl; intuition. - Qed. - - Definition extendedPoint_eq P Q := unExtendedPoint P = unExtendedPoint Q. - Global Instance Equivalence_extendedPoint_eq : Equivalence extendedPoint_eq. - Proof. - repeat (econstructor || intro); unfold extendedPoint_eq in *; congruence. - Qed. - - Lemma unExtendedPoint_mkExtendedPoint : forall P, unExtendedPoint (mkExtendedPoint P) = P. - Proof. - destruct P; eapply E.point_eq; simpl; erewrite extendedToTwisted_rep; eauto using twistedToExtended_rep. - Qed. - - Global Instance Proper_mkExtendedPoint : Proper (eq==>equiv) mkExtendedPoint. - Proof. - repeat (econstructor || intro); unfold extendedPoint_eq in *; congruence. - Qed. - - Global Instance Proper_unExtendedPoint : Proper (equiv==>eq) unExtendedPoint. - Proof. - repeat (econstructor || intro); unfold extendedPoint_eq in *; congruence. - Qed. - - Definition twice_d := d + d. - - Section TwistMinus1. - Context (a_eq_minus1 : a = opp 1). - (** Second equation from section 3.1, also and *) - Definition unifiedAddM1' (P1 P2 : extended) : extended := - let '(X1, Y1, Z1, T1) := P1 in - let '(X2, Y2, Z2, T2) := P2 in - let A := (Y1-X1)*(Y2-X2) in - let B := (Y1+X1)*(Y2+X2) in - let C := T1*twice_d*T2 in - let D := Z1*(Z2+Z2) in - let E := B-A in - let F := D-C in - let G := D+C in - let H := B+A in - let X3 := E*F in - let Y3 := G*H in - let T3 := E*H in - let Z3 := F*G in - (X3, Y3, Z3, T3). - Local Hint Unfold E.add. - - Local Ltac tnz := repeat apply Fq_mul_nonzero_nonzero; auto using (@char_gt_2 q two_lt_q). - - Lemma F_mul_2_l : forall x : F q, ZToField 2 * x = x + x. - intros. ring. - Qed. - - Lemma unifiedAddM1'_rep: forall P Q rP rQ, E.onCurve rP -> E.onCurve rQ -> - P ~= rP -> Q ~= rQ -> (unifiedAddM1' P Q) ~= (E.add' rP rQ). - Proof. - intros P Q rP rQ HoP HoQ HrP HrQ. - pose proof (@edwardsAddCompletePlus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d). - pose proof (@edwardsAddCompleteMinus _ _ _ _ two_lt_q nonzero_a square_a nonsquare_d). - unfoldExtended; unfold twice_d; rewrite a_eq_minus1 in *; simpl in *. repeat rewrite <-F_mul_2_l. - repeat split; repeat apply (f_equal2 pair); try F_field; repeat split; auto; - repeat rewrite ?F_add_0_r, ?F_add_0_l, ?F_sub_0_l, ?F_sub_0_r, - ?F_mul_0_r, ?F_mul_0_l, ?F_mul_1_l, ?F_mul_1_r, ?F_div_1_r; - field_nonzero tnz. - Qed. - - Lemma unifiedAdd'_onCurve : forall P Q, E.onCurve P -> E.onCurve Q -> E.onCurve (E.add' P Q). - Proof. - intros; pose proof (proj2_sig (E.add (exist _ _ H) (exist _ _ H0))); eauto. - Qed. - - Program Definition unifiedAddM1 : extendedPoint -> extendedPoint -> extendedPoint := unifiedAddM1'. - Next Obligation. - destruct x, x0; simpl; intuition. - - erewrite extendedToTwisted_rep; eauto using unifiedAddM1'_rep. - - erewrite extendedToTwisted_rep. - (* It would be nice if I could use eauto here, but it gets evars wrong :( *) - 2: eapply unifiedAddM1'_rep. 5:apply H1. 4:apply H. 3:auto. 2:auto. - eauto using unifiedAdd'_onCurve. - Qed. - - Lemma unifiedAddM1_rep : forall P Q, E.add (unExtendedPoint P) (unExtendedPoint Q) = unExtendedPoint (unifiedAddM1 P Q). - Proof. - destruct P, Q; unfold unExtendedPoint, E.add, unifiedAddM1; eapply E.point_eq; simpl in *; intuition. - pose proof (unifiedAddM1'_rep x x0 (extendedToTwisted x) (extendedToTwisted x0)); - destruct (unifiedAddM1' x x0); - unfold rep in *; intuition. - Qed. - - Lemma unifiedAddM1_correct : forall P Q, mkExtendedPoint (E.add P Q) === unifiedAddM1 (mkExtendedPoint P) (mkExtendedPoint Q). - Proof. - unfold equiv, extendedPoint_eq; intros; - pose proof unifiedAddM1_rep (mkExtendedPoint P) (mkExtendedPoint Q); - pose proof unExtendedPoint_mkExtendedPoint; - congruence. - Qed. - - Global Instance Proper_unifiedAddM1 : Proper (equiv==>equiv==>equiv) unifiedAddM1. - Proof. - repeat (econstructor || intro). - repeat match goal with [H: _ === _ |- _ ] => inversion H; clear H end; unfold equiv, extendedPoint_eq. - rewrite <-!unifiedAddM1_rep. - destruct x, y, x0, y0; simpl in *; eapply E.point_eq; congruence. - Qed. +Require Export Crypto.Spec.CompleteEdwardsCurve. +Require Import Crypto.Algebra Crypto.Nsatz. +Require Import Crypto.CompleteEdwardsCurve.Pre Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. +Require Import Coq.Logic.Eqdep_dec. +Require Import Crypto.Tactics.VerdiTactics. +Require Import Coq.Classes.Morphisms. +Require Import Relation_Definitions. +Require Import Crypto.Util.Fieldwise. + +Module Extended. + Section ExtendedCoordinates. + Import Group Ring Field. + Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv a d} + {field:@field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} + {prm:@E.twisted_edwards_params F Feq Fzero Fone Fadd Fmul a d}. + Local Infix "=" := Feq : type_scope. Local Notation "a <> b" := (not (a = b)) : type_scope. + Local Notation "0" := Fzero. Local Notation "1" := Fone. + Local Infix "+" := Fadd. Local Infix "*" := Fmul. + Local Infix "-" := Fsub. Local Infix "/" := Fdiv. + Local Notation "x ^2" := (x*x) (at level 30). + Local Notation Epoint := (@E.point F Feq Fone Fadd Fmul a d). + Local Notation onCurve := (@Pre.onCurve F Feq Fone Fadd Fmul a d). + + Add Field _edwards_curve_extended_field : (field_theory_for_stdlib_tactic (H:=field)). + + (** [Extended.point] represents a point on an elliptic curve using extended projective + * Edwards coordinates with twist a=-1 (see ). *) + Definition point := { P | let '(X,Y,Z,T) := P in onCurve((X/Z), (Y/Z)) /\ Z<>0 /\ Z*T=X*Y }. + Definition coordinates (P:point) : F*F*F*F := proj1_sig P. + + Create HintDb bash discriminated. + Local Hint Unfold E.eq fst snd fieldwise fieldwise' coordinates E.coordinates proj1_sig Pre.onCurve : bash. + Ltac bash := + repeat match goal with + | |- Proper _ _ => intro + | _ => progress intros + | [ H: _ /\ _ |- _ ] => destruct H + | [ p:E.point |- _ ] => destruct p as [[??]?] + | [ p:point |- _ ] => destruct p as [[[[??]?]?]?] + | _ => progress autounfold with bash in * + | |- _ /\ _ => split + | _ => solve [neq01] + | _ => solve [eauto] + | _ => solve [intuition] + | _ => solve [etransitivity; eauto] + | |- Feq _ _ => field_algebra + | |- _ <> 0 => apply mul_nonzero_nonzero + | [ H : _ <> 0 |- _ <> 0 ] => + intro; apply H; + field_algebra; + solve [ apply Ring.opp_nonzero_nonzero, E.char_gt_2 + | apply E.char_gt_2] + end. + + Obligation Tactic := bash. + + Program Definition from_twisted (P:Epoint) : point := exist _ + (let (x,y) := E.coordinates P in (x, y, 1, x*y)) _. + + Program Definition to_twisted (P:point) : Epoint := exist _ + (let '(X,Y,Z,T) := coordinates P in ((X/Z), (Y/Z))) _. + + Definition eq (P Q:point) := E.eq (to_twisted P) (to_twisted Q). + + Local Hint Unfold from_twisted to_twisted eq : bash. + + Global Instance Equivalence_eq : Equivalence eq. Proof. split; split; bash. Qed. + Global Instance Proper_from_twisted : Proper (E.eq==>eq) from_twisted. Proof. bash. Qed. + Global Instance Proper_to_twisted : Proper (eq==>E.eq) to_twisted. Proof. bash. Qed. + Lemma to_twisted_from_twisted P : E.eq (to_twisted (from_twisted P)) P. Proof. bash. Qed. + + Section TwistMinus1. + Context {a_eq_minus1 : a = Fopp 1}. + Context {twice_d:F} {Htwice_d:twice_d = d + d}. + (** Second equation from section 3.1, also and *) + Definition add_coordinates P1 P2 : F*F*F*F := + let '(X1, Y1, Z1, T1) := P1 in + let '(X2, Y2, Z2, T2) := P2 in + let A := (Y1-X1)*(Y2-X2) in + let B := (Y1+X1)*(Y2+X2) in + let C := T1*twice_d*T2 in + let D := Z1*(Z2+Z2) in + let E := B-A in + let F := D-C in + let G := D+C in + let H := B+A in + let X3 := E*F in + let Y3 := G*H in + let T3 := E*H in + let Z3 := F*G in + (X3, Y3, Z3, T3). + + Local Hint Unfold E.add E.coordinates add_coordinates : bash. + + Lemma add_coordinates_correct (P Q:point) : + let '(X,Y,Z,T) := add_coordinates (coordinates P) (coordinates Q) in + let (x, y) := E.coordinates (E.add (to_twisted P) (to_twisted Q)) in + (fieldwise (n:=2) Feq) (x, y) (X/Z, Y/Z). + Proof. + destruct P as [[[[]?]?][HP []]]; destruct Q as [[[[]?]?][HQ []]]. + pose proof edwardsAddCompletePlus (a_nonzero:=E.nonzero_a)(a_square:=E.square_a)(d_nonsquare:=E.nonsquare_d)(char_gt_2:=E.char_gt_2) _ _ _ _ HP HQ. + pose proof edwardsAddCompleteMinus (a_nonzero:=E.nonzero_a)(a_square:=E.square_a)(d_nonsquare:=E.nonsquare_d)(char_gt_2:=E.char_gt_2) _ _ _ _ HP HQ. + bash. + Qed. + + Obligation Tactic := idtac. + Program Definition add (P Q:point) : point := add_coordinates (coordinates P) (coordinates Q). + Next Obligation. + intros. + pose proof (add_coordinates_correct P Q) as Hrep. + pose proof Pre.unifiedAdd'_onCurve(a_nonzero:=E.nonzero_a)(a_square:=E.square_a)(d_nonsquare:=E.nonsquare_d)(char_gt_2:=E.char_gt_2) (E.coordinates (to_twisted P)) (E.coordinates (to_twisted Q)) as Hon. + destruct P as [[[[]?]?][HP []]]; destruct Q as [[[[]?]?][HQ []]]. + pose proof edwardsAddCompletePlus (a_nonzero:=E.nonzero_a)(a_square:=E.square_a)(d_nonsquare:=E.nonsquare_d)(char_gt_2:=E.char_gt_2) _ _ _ _ HP HQ as Hnz1. + pose proof edwardsAddCompleteMinus (a_nonzero:=E.nonzero_a)(a_square:=E.square_a)(d_nonsquare:=E.nonsquare_d)(char_gt_2:=E.char_gt_2) _ _ _ _ HP HQ as Hnz2. + autounfold with bash in *; simpl in *. + destruct Hrep as [HA HB]. rewrite <-!HA, <-!HB; clear HA HB. + bash. + Qed. + Local Hint Unfold add : bash. + + Lemma to_twisted_add P Q : E.eq (to_twisted (add P Q)) (E.add (to_twisted P) (to_twisted Q)). + Proof. + pose proof (add_coordinates_correct P Q) as Hrep. + destruct P as [[[[]?]?][HP []]]; destruct Q as [[[[]?]?][HQ []]]. + autounfold with bash in *; simpl in *. + destruct Hrep as [HA HB]. rewrite <-!HA, <-!HB; clear HA HB. + split; reflexivity. + Qed. + + Global Instance Proper_add : Proper (eq==>eq==>eq) add. + Proof. + unfold eq. intros x y H x0 y0 H0. + transitivity (to_twisted x + to_twisted x0)%E; rewrite to_twisted_add, ?H, ?H0; reflexivity. + Qed. + + Lemma homomorphism_to_twisted : @Group.is_homomorphism point eq add Epoint E.eq E.add to_twisted. + Proof. split; trivial using Proper_to_twisted, to_twisted_add. Qed. + + Lemma add_from_twisted P Q : eq (from_twisted (P + Q)%E) (add (from_twisted P) (from_twisted Q)). + Proof. + pose proof (to_twisted_add (from_twisted P) (from_twisted Q)). + unfold eq; rewrite !to_twisted_from_twisted in *. + symmetry; assumption. + Qed. + + Lemma homomorphism_from_twisted : @Group.is_homomorphism Epoint E.eq E.add point eq add from_twisted. + Proof. split; trivial using Proper_from_twisted, add_from_twisted. Qed. + + (* TODO: decide whether we still need those, then port *) + (* Lemma unifiedAddM1_0_r : forall P, unifiedAddM1 P (mkExtendedPoint E.zero) === P. unfold equiv, extendedPoint_eq; intros. rewrite <-!unifiedAddM1_rep, unExtendedPoint_mkExtendedPoint, E.add_0_r; auto. @@ -223,19 +175,70 @@ Section ExtendedCoordinates. unfold E.mul; fold E.mul. rewrite <-IHn, unifiedAddM1_rep; auto. Qed. - End TwistMinus1. - - Definition negateExtended' P := let '(X, Y, Z, T) := P in (opp X, Y, Z, opp T). - Program Definition negateExtended (P:extendedPoint) : extendedPoint := negateExtended' (proj1_sig P). - Next Obligation. - Proof. - unfold negateExtended', rep; destruct P as [[X Y Z T] H]; simpl. destruct H as [[[] []] ?]; subst. - repeat rewrite ?F_div_opp_1, ?F_mul_opp_l, ?F_square_opp; repeat split; trivial. - Qed. - - Lemma negateExtended_correct : forall P, E.opp (unExtendedPoint P) = unExtendedPoint (negateExtended P). - Proof. - unfold E.opp, unExtendedPoint, negateExtended; destruct P as [[]]; simpl; intros. - eapply E.point_eq; repeat rewrite ?F_div_opp_1, ?F_mul_opp_l, ?F_square_opp; trivial. - Qed. -End ExtendedCoordinates. + *) + End TwistMinus1. + End ExtendedCoordinates. + + Section Homomorphism. + Import Group Ring Field. + Context {F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv Fa Fd} + {fieldF:@field F Feq Fzero Fone Fopp Fadd Fsub Fmul Finv Fdiv} + {Fprm:@E.twisted_edwards_params F Feq Fzero Fone Fadd Fmul Fa Fd}. + Context {K Keq Kzero Kone Kopp Kadd Ksub Kmul Kinv Kdiv Ka Kd} + {fieldK:@field K Keq Kzero Kone Kopp Kadd Ksub Kmul Kinv Kdiv} + {Kprm:@E.twisted_edwards_params K Keq Kzero Kone Kadd Kmul Ka Kd}. + Context {phi:F->K} {Hphi:@Ring.is_homomorphism F Feq Fone Fadd Fmul + K Keq Kone Kadd Kmul phi}. + Context {phi_nonzero : forall x, ~ Feq x Fzero -> ~ Keq (phi x) Kzero}. + Context {HFa: Feq Fa (Fopp Fone)} {HKa:Keq Ka (Kopp Kone)}. + Context {Hd:Keq (phi Fd) Kd} {Kdd Fdd} {HKdd:Keq Kdd (Kadd Kd Kd)} {HFdd:Feq Fdd (Fadd Fd Fd)}. + Local Notation Fpoint := (@point F Feq Fzero Fone Fadd Fmul Fdiv Fa Fd). + Local Notation Kpoint := (@point K Keq Kzero Kone Kadd Kmul Kdiv Ka Kd). + + Lemma Ha : Keq (phi Fa) Ka. + Proof. rewrite HFa, HKa, <-homomorphism_one. eapply homomorphism_opp. Qed. + + Lemma Hdd : Keq (phi Fdd) Kdd. + Proof. rewrite HFdd, HKdd. rewrite homomorphism_add. repeat f_equiv; auto. Qed. + + Create HintDb field_homomorphism discriminated. + Hint Rewrite <- + homomorphism_one + homomorphism_add + homomorphism_sub + homomorphism_mul + homomorphism_div + Ha + Hd + Hdd + : field_homomorphism. + + Program Definition ref_phi (P:Fpoint) : Kpoint := exist _ ( + let '(X, Y, Z, T) := coordinates P in (phi X, phi Y, phi Z, phi T)) _. + Next Obligation. + destruct P as [[[[] ?] ?] [? [? ?]]]; unfold onCurve in *; simpl. + rewrite_strat bottomup hints field_homomorphism. + eauto 10 using is_homomorphism_phi_proper, phi_nonzero. + Qed. + + Context {point_phi:Fpoint->Kpoint} + {point_phi_Proper:Proper (eq==>eq) point_phi} + {point_phi_correct: forall (P:Fpoint), eq (point_phi P) (ref_phi P)}. + + Lemma lift_homomorphism : @Group.is_homomorphism Fpoint eq (add(a_eq_minus1:=HFa)(Htwice_d:=HFdd)) Kpoint eq (add(a_eq_minus1:=HKa)(Htwice_d:=HKdd)) point_phi. + Proof. + repeat match goal with + | |- Group.is_homomorphism => split + | |- _ => intro + | |- _ /\ _ => split + | [H: _ /\ _ |- _ ] => destruct H + | [p: point |- _ ] => destruct p as [[[[] ?] ?] [? [? ?]]] + | |- context[point_phi] => setoid_rewrite point_phi_correct + | |- _ => progress cbv [fst snd coordinates proj1_sig eq to_twisted E.eq E.coordinates fieldwise fieldwise' add add_coordinates ref_phi] in * + | |- Keq ?x ?x => reflexivity + | |- Keq ?x ?y => rewrite_strat bottomup hints field_homomorphism + | [ H : Feq _ _ |- Keq (phi _) (phi _)] => solve [f_equiv; intuition] + end. + Qed. + End Homomorphism. +End Extended. \ No newline at end of file diff --git a/src/CompleteEdwardsCurve/Pre.v b/src/CompleteEdwardsCurve/Pre.v index 19f2fd9db..4744afe6b 100644 --- a/src/CompleteEdwardsCurve/Pre.v +++ b/src/CompleteEdwardsCurve/Pre.v @@ -1,5 +1,5 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Require Import Crypto.Algebra. +Require Import Crypto.Algebra Crypto.Nsatz. Generalizable All Variables. Section Pre. @@ -38,7 +38,7 @@ Section Pre. => apply d_nonsquare with (sqrt_d:= (f (sqrt_a * x1) (d * x1 * x2 * y1 * y2 * y1)) /(f (sqrt_a * x2) y2 * x1 * y1 )) | _ => apply a_nonzero - end; field_algebra; auto using Ring.opp_nonzero_nonzero. + end; field_algebra; auto using Ring.opp_nonzero_nonzero; intro; nsatz_contradict. Qed. Lemma edwardsAddCompletePlus x1 y1 x2 y2 : diff --git a/src/ModularArithmetic/FField.v b/src/ModularArithmetic/FField.v deleted file mode 100644 index 4f2b623e0..000000000 --- a/src/ModularArithmetic/FField.v +++ /dev/null @@ -1,63 +0,0 @@ -Require Export Crypto.Spec.ModularArithmetic. -Require Export Coq.setoid_ring.Field. - -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. - -Local Open Scope F_scope. - -Definition OpaqueF := F. -Definition OpaqueZmodulo := BinInt.Z.modulo. -Definition Opaqueadd {p} : OpaqueF p -> OpaqueF p -> OpaqueF p := @add p. -Definition Opaquemul {p} : OpaqueF p -> OpaqueF p -> OpaqueF p := @mul p. -Definition Opaquesub {p} : OpaqueF p -> OpaqueF p -> OpaqueF p := @sub p. -Definition Opaquediv {p} : OpaqueF p -> OpaqueF p -> OpaqueF p := @div p. -Definition Opaqueopp {p} : OpaqueF p -> OpaqueF p := @opp p. -Definition Opaqueinv {p} : OpaqueF p -> OpaqueF p := @inv p. -Definition OpaqueZToField {p} : BinInt.Z -> OpaqueF p := @ZToField p. -Definition Opaqueadd_correct {p} : @Opaqueadd p = @add p := eq_refl. -Definition Opaquesub_correct {p} : @Opaquesub p = @sub p := eq_refl. -Definition Opaquemul_correct {p} : @Opaquemul p = @mul p := eq_refl. -Definition Opaquediv_correct {p} : @Opaquediv p = @div p := eq_refl. -Global Opaque F OpaqueZmodulo Opaqueadd Opaquemul Opaquesub Opaquediv Opaqueopp Opaqueinv OpaqueZToField. - -Definition OpaqueFieldTheory p {prime_p} : @field_theory (OpaqueF p) (OpaqueZToField 0%Z) (OpaqueZToField 1%Z) Opaqueadd Opaquemul Opaquesub Opaqueopp Opaquediv Opaqueinv eq := Eval hnf in @Ffield_theory p prime_p. - -Ltac FIELD_SIMPL_idtac FLD lH rl := - let Simpl := idtac (* (protect_fv "field") *) in - let lemma := get_SimplifyEqLemma FLD in - get_FldPre FLD (); - Field_Scheme Simpl Ring_tac.ring_subst_niter lemma FLD lH; - get_FldPost FLD (). -Ltac field_simplify_eq_idtac := let G := Get_goal in field_lookup (PackField FIELD_SIMPL_idtac) [] G. - -Ltac F_to_Opaque := - change F with OpaqueF in *; - change BinInt.Z.modulo with OpaqueZmodulo in *; - change @add with @Opaqueadd in *; - change @mul with @Opaquemul in *; - change @sub with @Opaquesub in *; - change @div with @Opaquediv in *; - change @opp with @Opaqueopp in *; - change @inv with @Opaqueinv in *; - change @ZToField with @OpaqueZToField in *. - -Ltac F_from_Opaque p := - change OpaqueF with F in *; - change (@sig BinNums.Z (fun z : BinNums.Z => @eq BinNums.Z z (BinInt.Z.modulo z p))) with (F p) in *; - change OpaqueZmodulo with BinInt.Z.modulo in *; - change @Opaqueopp with @opp in *; - change @Opaqueinv with @inv in *; - change @OpaqueZToField with @ZToField in *; - rewrite ?@Opaqueadd_correct, ?@Opaquesub_correct, ?@Opaquemul_correct, ?@Opaquediv_correct in *. - -Ltac F_field_simplify_eq := - lazymatch goal with |- @eq (F ?p) _ _ => - F_to_Opaque; - field_simplify_eq_idtac; - compute; - F_from_Opaque p - end. - -Ltac F_field := F_field_simplify_eq; [ring|..]. - -Ltac notConstant t := constr:NotConstant. diff --git a/src/ModularArithmetic/FNsatz.v b/src/ModularArithmetic/FNsatz.v deleted file mode 100644 index 221b8d799..000000000 --- a/src/ModularArithmetic/FNsatz.v +++ /dev/null @@ -1,40 +0,0 @@ -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. -Require Export Crypto.ModularArithmetic.FField. -Require Import Coq.nsatz.Nsatz. - -Ltac FqAsIntegralDomain := - lazymatch goal with [H:Znumtheory.prime ?q |- _ ] => - pose proof (_:@Integral_domain.Integral_domain (F q) _ _ _ _ _ _ _ _ _ _) as FqIntegralDomain; - lazymatch type of FqIntegralDomain with @Integral_domain.Integral_domain _ _ _ _ _ _ _ _ ?ringOps ?ringOk ?ringComm => - generalize dependent ringComm; intro Cring; - generalize dependent ringOk; intro Ring; - generalize dependent ringOps; intro RingOps; - lazymatch type of RingOps with @Ncring.Ring_ops ?t ?z ?o ?a ?m ?s ?p ?e => - generalize dependent e; intro equiv; - generalize dependent p; intro opp; - generalize dependent s; intro sub; - generalize dependent m; intro mul; - generalize dependent a; intro add; - generalize dependent o; intro one; - generalize dependent z; intro zero; - generalize dependent t; intro R - end - end; intros; - clear q H - end. - -Ltac fixed_equality_to_goal H x y := generalize (psos_r1 x y H); clear H. -Ltac fixed_equalities_to_goal := - match goal with - | H:?x == ?y |- _ => fixed_equality_to_goal H x y - | H:_ ?x ?y |- _ => fixed_equality_to_goal H x y - | H:_ _ ?x ?y |- _ => fixed_equality_to_goal H x y - | H:_ _ _ ?x ?y |- _ => fixed_equality_to_goal H x y - | H:_ _ _ _ ?x ?y |- _ => fixed_equality_to_goal H x y - end. -Ltac fixed_nsatz := - intros; try apply psos_r1b; - lazymatch goal with - | |- @equality ?T _ _ _ => repeat fixed_equalities_to_goal; nsatz_generic 6%N 1%Z (@nil T) (@nil T) - end. -Ltac F_nsatz := abstract (FqAsIntegralDomain; fixed_nsatz). diff --git a/src/Nsatz.v b/src/Nsatz.v index c8a648626..469ba4c29 100644 --- a/src/Nsatz.v +++ b/src/Nsatz.v @@ -1,5 +1,5 @@ (*** Tactics for manipulating polynomial equations *) -Require Nsatz. +Require Coq.nsatz.Nsatz. Require Import List. Generalizable All Variables. @@ -109,6 +109,7 @@ Tactic Notation "nsatz" constr(n) := Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. Ltac nsatz_contradict := + unfold not; intros; let domain := nsatz_guess_domain in lazymatch type of domain with diff --git a/src/Util/Fieldwise.v b/src/Util/Fieldwise.v new file mode 100644 index 000000000..f2f0b5acb --- /dev/null +++ b/src/Util/Fieldwise.v @@ -0,0 +1,42 @@ +Require Import Coq.Classes.Morphisms. +Require Import Relation_Definitions. + +Fixpoint tuple' n T : Type := + match n with + | O => T + | S n' => (tuple' n' T * T)%type + end. + +Definition tuple n T : Type := + match n with + | O => unit + | S n' => tuple' n' T + end. + +Fixpoint fieldwise' {A B} (n:nat) (R:A->B->Prop) (a:tuple' n A) (b:tuple' n B) {struct n} : Prop. + destruct n; simpl @tuple' in *. + { exact (R a b). } + { exact (R (snd a) (snd b) /\ fieldwise' _ _ n R (fst a) (fst b)). } +Defined. + +Definition fieldwise {A B} (n:nat) (R:A->B->Prop) (a:tuple n A) (b:tuple n B) : Prop. + destruct n; simpl @tuple in *. + { exact True. } + { exact (fieldwise' _ R a b). } +Defined. + +Global Instance Equivalence_fieldwise' {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: + Equivalence (fieldwise' n R). +Proof. + induction n; [solve [auto]|]. + simpl; constructor; repeat intro; intuition eauto. +Qed. + +Global Instance Equivalence_fieldwise {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: + Equivalence (fieldwise n R). +Proof. + destruct n; (repeat constructor || apply Equivalence_fieldwise'). +Qed. + +Arguments fieldwise' {A B n} _ _ _. +Arguments fieldwise {A B n} _ _ _. \ No newline at end of file -- cgit v1.2.3 From ce51a8e4b5c03178a08b7cd0e5bd34bae2fdf4a0 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 20 Jun 2016 02:00:55 -0400 Subject: tuple tooling --- _CoqProject | 2 +- .../CompleteEdwardsCurveTheorems.v | 2 +- src/CompleteEdwardsCurve/ExtendedCoordinates.v | 2 +- src/Util/Fieldwise.v | 42 ------------ src/Util/Tuple.v | 80 ++++++++++++++++++++++ 5 files changed, 83 insertions(+), 45 deletions(-) delete mode 100644 src/Util/Fieldwise.v create mode 100644 src/Util/Tuple.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index 21aca1390..1fefae2d4 100644 --- a/_CoqProject +++ b/_CoqProject @@ -39,11 +39,11 @@ src/Specific/GF1305.v src/Specific/GF25519.v src/Tactics/VerdiTactics.v src/Util/CaseUtil.v -src/Util/Fieldwise.v src/Util/IterAssocOp.v src/Util/ListUtil.v src/Util/NatUtil.v src/Util/NumTheoryUtil.v src/Util/Tactics.v +src/Util/Tuple.v src/Util/WordUtil.v src/Util/ZUtil.v diff --git a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v index e6ec7ab86..f9a866acb 100644 --- a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v +++ b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v @@ -6,7 +6,7 @@ Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. Require Import Coq.Classes.Morphisms. Require Import Relation_Definitions. -Require Import Crypto.Util.Fieldwise. +Require Import Crypto.Util.Tuple. Module E. Import Group Ring Field CompleteEdwardsCurve.E. diff --git a/src/CompleteEdwardsCurve/ExtendedCoordinates.v b/src/CompleteEdwardsCurve/ExtendedCoordinates.v index 4a352c738..fe0e732a8 100644 --- a/src/CompleteEdwardsCurve/ExtendedCoordinates.v +++ b/src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -6,7 +6,7 @@ Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. Require Import Coq.Classes.Morphisms. Require Import Relation_Definitions. -Require Import Crypto.Util.Fieldwise. +Require Import Crypto.Util.Tuple. Module Extended. Section ExtendedCoordinates. diff --git a/src/Util/Fieldwise.v b/src/Util/Fieldwise.v deleted file mode 100644 index f2f0b5acb..000000000 --- a/src/Util/Fieldwise.v +++ /dev/null @@ -1,42 +0,0 @@ -Require Import Coq.Classes.Morphisms. -Require Import Relation_Definitions. - -Fixpoint tuple' n T : Type := - match n with - | O => T - | S n' => (tuple' n' T * T)%type - end. - -Definition tuple n T : Type := - match n with - | O => unit - | S n' => tuple' n' T - end. - -Fixpoint fieldwise' {A B} (n:nat) (R:A->B->Prop) (a:tuple' n A) (b:tuple' n B) {struct n} : Prop. - destruct n; simpl @tuple' in *. - { exact (R a b). } - { exact (R (snd a) (snd b) /\ fieldwise' _ _ n R (fst a) (fst b)). } -Defined. - -Definition fieldwise {A B} (n:nat) (R:A->B->Prop) (a:tuple n A) (b:tuple n B) : Prop. - destruct n; simpl @tuple in *. - { exact True. } - { exact (fieldwise' _ R a b). } -Defined. - -Global Instance Equivalence_fieldwise' {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: - Equivalence (fieldwise' n R). -Proof. - induction n; [solve [auto]|]. - simpl; constructor; repeat intro; intuition eauto. -Qed. - -Global Instance Equivalence_fieldwise {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: - Equivalence (fieldwise n R). -Proof. - destruct n; (repeat constructor || apply Equivalence_fieldwise'). -Qed. - -Arguments fieldwise' {A B n} _ _ _. -Arguments fieldwise {A B n} _ _ _. \ No newline at end of file diff --git a/src/Util/Tuple.v b/src/Util/Tuple.v new file mode 100644 index 000000000..de1af2a95 --- /dev/null +++ b/src/Util/Tuple.v @@ -0,0 +1,80 @@ +Require Import Coq.Classes.Morphisms. +Require Import Relation_Definitions. + +Fixpoint tuple' T n : Type := + match n with + | O => T + | S n' => (tuple' T n' * T)%type + end. + +Definition tuple T n : Type := + match n with + | O => unit + | S n' => tuple' T n' + end. + +Fixpoint to_list' {T} (n:nat) {struct n} : tuple' T n -> list T := + match n with + | 0 => fun x => (x::nil)%list + | S n' => fun xs : tuple' T (S n') => let (xs', x) := xs in (x :: to_list' n' xs')%list + end. + +Definition to_list {T} (n:nat) : tuple T n -> list T := + match n with + | 0 => fun _ => nil + | S n' => fun xs : tuple T (S n') => to_list' n' xs + end. + +Fixpoint from_list' {T} (x:T) (xs:list T) : tuple' T (length xs) := + match xs with + | nil => x + | (y :: xs')%list => (from_list' y xs', x) + end. + +Definition from_list {T} (xs:list T) : tuple T (length xs) := + match xs as l return (tuple T (length l)) with + | nil => tt + | (t :: xs')%list => from_list' t xs' + end. + +Lemma to_list_from_list : forall {T} (xs:list T), to_list (length xs) (from_list xs) = xs. +Proof. + destruct xs; auto; simpl. + generalize dependent t. + induction xs; auto; simpl; intros; f_equal; auto. +Qed. + +Lemma length_to_list : forall {T} {n} (xs:tuple T n), length (to_list n xs) = n. +Proof. + destruct n; auto; intros; simpl in *. + induction n; auto; intros; simpl in *. + destruct xs; simpl in *; eauto. +Qed. + +Fixpoint fieldwise' {A B} (n:nat) (R:A->B->Prop) (a:tuple' A n) (b:tuple' B n) {struct n} : Prop. + destruct n; simpl @tuple' in *. + { exact (R a b). } + { exact (R (snd a) (snd b) /\ fieldwise' _ _ n R (fst a) (fst b)). } +Defined. + +Definition fieldwise {A B} (n:nat) (R:A->B->Prop) (a:tuple A n) (b:tuple B n) : Prop. + destruct n; simpl @tuple in *. + { exact True. } + { exact (fieldwise' _ R a b). } +Defined. + +Global Instance Equivalence_fieldwise' {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: + Equivalence (fieldwise' n R). +Proof. + induction n; [solve [auto]|]. + simpl; constructor; repeat intro; intuition eauto. +Qed. + +Global Instance Equivalence_fieldwise {A} {R:relation A} {R_equiv:Equivalence R} {n:nat}: + Equivalence (fieldwise n R). +Proof. + destruct n; (repeat constructor || apply Equivalence_fieldwise'). +Qed. + +Arguments fieldwise' {A B n} _ _ _. +Arguments fieldwise {A B n} _ _ _. \ No newline at end of file -- cgit v1.2.3 From 3febea4ed8fdb255c634acbeb3705c88baa89303 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 20 Jun 2016 03:50:08 -0400 Subject: Remove anything incompatible with new algebraic hierarcy - PointEncoding (these will hopefully come back soon) - EdDSAProofs (not a priority to bring back, but not hard either) - Ed25519 spec bits and pieces which were not finished anyway --- _CoqProject | 11 +- src/CompleteEdwardsCurve/DoubleAndAdd.v | 30 ---- src/EdDSAProofs.v | 108 ------------- src/Encoding/PointEncodingPre.v | 275 -------------------------------- src/Encoding/PointEncodingTheorems.v | 207 ------------------------ src/Experiments/SpecEd25519.v | 165 +++++++++++++++++++ src/Spec/Ed25519.v | 179 --------------------- src/Spec/PointEncoding.v | 39 ----- 8 files changed, 168 insertions(+), 846 deletions(-) delete mode 100644 src/CompleteEdwardsCurve/DoubleAndAdd.v delete mode 100644 src/EdDSAProofs.v delete mode 100644 src/Encoding/PointEncodingPre.v delete mode 100644 src/Encoding/PointEncodingTheorems.v create mode 100644 src/Experiments/SpecEd25519.v delete mode 100644 src/Spec/Ed25519.v delete mode 100644 src/Spec/PointEncoding.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index ffb532390..a3458ed1e 100644 --- a/_CoqProject +++ b/_CoqProject @@ -5,21 +5,18 @@ Bedrock/Word.v src/Algebra.v src/BaseSystem.v src/BaseSystemProofs.v -src/EdDSAProofs.v -src/Field.v src/Nsatz.v src/Rep.v src/Testbit.v -src/UnfinishedDerivations.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v -src/CompleteEdwardsCurve/DoubleAndAdd.v src/CompleteEdwardsCurve/ExtendedCoordinates.v src/CompleteEdwardsCurve/Pre.v src/Encoding/EncodingTheorems.v src/Encoding/ModularWordEncodingPre.v src/Encoding/ModularWordEncodingTheorems.v -src/Encoding/PointEncodingPre.v -src/Encoding/PointEncodingTheorems.v +src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v +src/Experiments/GenericFieldPow.v +src/Experiments/SpecEd25519.v src/ModularArithmetic/ExtendedBaseVector.v src/ModularArithmetic/ModularArithmeticTheorems.v src/ModularArithmetic/ModularBaseSystem.v @@ -32,12 +29,10 @@ src/ModularArithmetic/PseudoMersenneBaseParams.v src/ModularArithmetic/PseudoMersenneBaseRep.v src/ModularArithmetic/Tutorial.v src/Spec/CompleteEdwardsCurve.v -src/Spec/Ed25519.v src/Spec/EdDSA.v src/Spec/Encoding.v src/Spec/ModularArithmetic.v src/Spec/ModularWordEncoding.v -src/Spec/PointEncoding.v src/Specific/GF1305.v src/Specific/GF25519.v src/Tactics/VerdiTactics.v diff --git a/src/CompleteEdwardsCurve/DoubleAndAdd.v b/src/CompleteEdwardsCurve/DoubleAndAdd.v deleted file mode 100644 index 50027349d..000000000 --- a/src/CompleteEdwardsCurve/DoubleAndAdd.v +++ /dev/null @@ -1,30 +0,0 @@ -Require Import Crypto.Tactics.VerdiTactics. -Require Import Crypto.Spec.CompleteEdwardsCurve Crypto.Util.IterAssocOp. -Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Coq.Numbers.BinNums Coq.NArith.NArith Coq.NArith.Nnat Coq.ZArith.ZArith. - -Section EdwardsDoubleAndAdd. - Context {prm:TwistedEdwardsParams}. - Definition doubleAndAdd (bound n : nat) (P : E.point) : E.point := - iter_op E.add E.zero N.testbit_nat (N.of_nat n) P bound. - - Lemma scalarMult_double : forall n P, E.mul (n + n) P = E.mul n (P + P)%E. - Proof. - intros. - replace (n + n)%nat with (n * 2)%nat by omega. - induction n; simpl; auto. - rewrite E.add_assoc. - f_equal; auto. - Qed. - - Lemma doubleAndAdd_spec : forall bound n P, N.size_nat (N.of_nat n) <= bound -> - E.mul n P = doubleAndAdd bound n P. - Proof. - induction n; auto; intros; unfold doubleAndAdd; - rewrite iter_op_spec with (scToN := fun x => x); ( - unfold Morphisms.Proper, Morphisms.respectful, Equivalence.equiv; - intros; subst; try rewrite Nat2N.id; - reflexivity || assumption || apply E.add_assoc - || rewrite E.add_comm; apply E.add_0_r). - Qed. -End EdwardsDoubleAndAdd. \ No newline at end of file diff --git a/src/EdDSAProofs.v b/src/EdDSAProofs.v deleted file mode 100644 index 2e45bcad5..000000000 --- a/src/EdDSAProofs.v +++ /dev/null @@ -1,108 +0,0 @@ -Require Import Crypto.Spec.EdDSA Crypto.Spec.Encoding. -Require Import Coq.Numbers.Natural.Peano.NPeano. -Require Import Bedrock.Word. -Require Import Coq.ZArith.Znumtheory Coq.ZArith.BinInt Coq.ZArith.ZArith. -Require Import Crypto.Spec.CompleteEdwardsCurve Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems Crypto.ModularArithmetic.ModularArithmeticTheorems. -Require Import Crypto.Util.ListUtil Crypto.Util.CaseUtil Crypto.Util.ZUtil. -Require Import Crypto.Tactics.VerdiTactics. -Local Open Scope nat_scope. - -Section EdDSAProofs. - Context {prm:EdDSAParams}. - Existing Instance E. - Existing Instance PointEncoding. - Existing Instance FqEncoding. - Existing Instance FlEncoding. - Existing Instance n_le_b. - Hint Rewrite sign_spec split1_combine split2_combine. - Hint Rewrite Nat.mod_mod using omega. - - Ltac arith' := intros; autorewrite with core; try (omega || congruence). - - Ltac arith := arith'; - repeat match goal with - | [ H : _ |- _ ] => rewrite H; arith' - end. - - (* for signature (R_, S_), R_ = encode_point (r * B) *) - Lemma decode_sign_split1 : forall A_ sk {n} (M : word n), - split1 b b (sign A_ sk M) = enc (wordToNat (H (prngKey sk ++ M)) * B)%E. - Proof. - unfold sign; arith. - Qed. - Hint Rewrite decode_sign_split1. - - (* for signature (R_, S_), S_ = encode_scalar (r + H(R_, A_, M)s) *) - Lemma decode_sign_split2 : forall sk {n} (M : word n), - split2 b b (sign (public sk) sk M) = - let r : nat := H (prngKey sk ++ M) in (* secret nonce *) - let R : E.point := (r * B)%E in (* commitment to nonce *) - let s : nat := curveKey sk in (* secret scalar *) - let S : F (Z.of_nat l) := ZToField (Z.of_nat (r + H (enc R ++ public sk ++ M) * s)) in - enc S. - Proof. - unfold sign; arith. - Qed. - Hint Rewrite decode_sign_split2. - - Hint Rewrite E.add_0_r E.add_0_l E.add_assoc. - Hint Rewrite E.mul_assoc E.mul_add_l E.mul_0_l E.mul_zero_r. - Hint Rewrite plus_O_n plus_Sn_m mult_0_l mult_succ_l. - Hint Rewrite l_order_B. - Lemma l_order_B' : forall x, (l * x * B = E.zero)%E. - Proof. - intros; rewrite Mult.mult_comm. rewrite <- E.mul_assoc. arith. - Qed. Hint Rewrite l_order_B'. - - Lemma scalarMult_mod_l : forall n0, (n0 mod l * B = n0 * B)%E. - Proof. - intros. - rewrite (div_mod n0 l) at 2 by (generalize l_odd; omega). - arith. - Qed. Hint Rewrite scalarMult_mod_l. - - Hint Rewrite @encoding_valid. - Hint Rewrite @FieldToZ_ZToField. - Hint Rewrite <-mod_Zmod. - Hint Rewrite Nat2Z.id. - - Lemma l_nonzero : l <> O. pose l_odd; omega. Qed. - Hint Resolve l_nonzero. - - Lemma verify_valid_passes : forall sk {n} (M : word n), - verify (public sk) M (sign (public sk) sk M) = true. - Proof. - unfold verify, sign, public; arith; try break_if; intuition. - Qed. - - (* This is just an experiment, talk to andreser if you think this is a good idea *) - Inductive valid {n:nat} : word b -> Word.word n -> word (b+b) -> Prop := - Valid : forall (A:E.point) (M:Word.word n) (S:nat) (R:E.point), - (S * B = R + (H (enc R ++ enc A ++ M)) * A)%E - -> valid (enc A) M (enc R ++ enc (ZToField (BinInt.Z.of_nat S))). - Goal forall A_ {n} (M:Word.word n) sig, verify A_ M sig = true <-> valid A_ M sig. - split; unfold verify. - Focus 2. { - intros. - inversion H. subst. - rewrite !Word.split2_combine, !Word.split1_combine, !encoding_valid. - rewrite FieldToZ_ZToField. - rewrite <-Zdiv.mod_Zmod by admit. - rewrite Znat.Nat2Z.id. - rewrite <-H0. - assert ((S mod l) * B = S * B)%E as Hl by admit; rewrite Hl. - destruct (E.point_eq_dec (S * B)%E); congruence. - } Unfocus. { - repeat match goal with |- context [match ?x with _ => _ end] => case_eq x; intro end; try congruence. - intros. clear H. - repeat match goal with [H: _ |- _ ] => apply encoding_canonical in H end; subst. - rewrite <-(Word.combine_split b b sig). - rewrite <-H0 in *; clear H0. rewrite <-H2 in *; clear H2. - assert (f = (ZToField (BinInt.Z.of_nat (BinInt.Z.to_nat (FieldToZ f))))) as H1. { - rewrite Znat.Z2Nat.id by admit. rewrite ZToField_FieldToZ; reflexivity. } - rewrite H1; clear H1. - econstructor; trivial. - } - Qed. -End EdDSAProofs. diff --git a/src/Encoding/PointEncodingPre.v b/src/Encoding/PointEncodingPre.v deleted file mode 100644 index 73ced869b..000000000 --- a/src/Encoding/PointEncodingPre.v +++ /dev/null @@ -1,275 +0,0 @@ -Require Import Coq.ZArith.ZArith Coq.ZArith.Znumtheory. -Require Import Coq.Numbers.Natural.Peano.NPeano. -Require Import Coq.Program.Equality. -Require Import Crypto.Encoding.EncodingTheorems. -Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. -Require Import Bedrock.Word. -Require Import Crypto.Encoding.ModularWordEncodingTheorems. -Require Import Crypto.Tactics.VerdiTactics. -Require Import Crypto.Util.ZUtil. - -Require Import Crypto.Spec.Encoding Crypto.Spec.ModularWordEncoding Crypto.Spec.ModularArithmetic. - -Local Open Scope F_scope. - -Section PointEncoding. - Context {prm: TwistedEdwardsParams} {sz : nat} {sz_nonzero : (0 < sz)%nat} - {bound_check : (Z.to_nat q < 2 ^ sz)%nat} {q_5mod8 : (q mod 8 = 5)%Z} - {sqrt_minus1_valid : (@ZToField q 2 ^ Z.to_N (q / 4)) ^ 2 = opp 1} - {FqEncoding : canonical encoding of (F q) as (word sz)} - {sign_bit : F q -> bool} {sign_bit_zero : sign_bit 0 = false} - {sign_bit_opp : forall x, x <> 0 -> negb (sign_bit x) = sign_bit (opp x)}. - Existing Instance prime_q. - - Add Field Ffield : (@Ffield_theory q _) - (morphism (@Fring_morph q), - preprocess [Fpreprocess], - postprocess [Fpostprocess; try exact Fq_1_neq_0; try assumption], - constants [Fconstant], - div (@Fmorph_div_theory q), - power_tac (@Fpower_theory q) [Fexp_tac]). - - Definition sqrt_valid (a : F q) := ((sqrt_mod_q a) ^ 2 = a)%F. - - Lemma solve_sqrt_valid : forall p, E.onCurve p -> - sqrt_valid (E.solve_for_x2 (snd p)). - Proof. - intros ? onCurve_xy. - destruct p as [x y]; simpl. - rewrite (E.solve_correct x y) in onCurve_xy. - rewrite <- onCurve_xy. - unfold sqrt_valid. - eapply sqrt_mod_q_valid; eauto. - unfold isSquare; eauto. - Grab Existential Variables. eauto. - Qed. - - Lemma solve_onCurve: forall (y : F q), sqrt_valid (E.solve_for_x2 y) -> - E.onCurve (sqrt_mod_q (E.solve_for_x2 y), y). - Proof. - intros. - unfold sqrt_valid in *. - apply E.solve_correct; auto. - Qed. - - Lemma solve_opp_onCurve: forall (y : F q), sqrt_valid (E.solve_for_x2 y) -> - E.onCurve (opp (sqrt_mod_q (E.solve_for_x2 y)), y). - Proof. - intros y sqrt_valid_x2. - unfold sqrt_valid in *. - apply E.solve_correct. - rewrite <- sqrt_valid_x2 at 2. - ring. - Qed. - - Definition point_enc_coordinates (p : (F q * F q)) : Word.word (S sz) := let '(x,y) := p in - Word.WS (sign_bit x) (enc y). - - Let point_enc (p : E.point) : Word.word (S sz) := let '(x,y) := proj1_sig p in - Word.WS (sign_bit x) (enc y). - - Definition point_dec_coordinates (sign_bit : F q -> bool) (w : Word.word (S sz)) : option (F q * F q) := - match dec (Word.wtl w) with - | None => None - | Some y => let x2 := E.solve_for_x2 y in - let x := sqrt_mod_q x2 in - if F_eq_dec (x ^ 2) x2 - then - let p := (if Bool.eqb (whd w) (sign_bit x) then x else opp x, y) in - if (andb (F_eqb x 0) (whd w)) - then None (* special case for 0, since its opposite has the same sign; if the sign bit of 0 is 1, produce None.*) - else Some p - else None - end. - - Ltac inversion_Some_eq := match goal with [H: Some ?x = Some ?y |- _] => inversion H; subst end. - - Lemma point_dec_coordinates_onCurve : forall w p, point_dec_coordinates sign_bit w = Some p -> E.onCurve p. - Proof. - unfold point_dec_coordinates; intros. - edestruct dec; [ | congruence]. - break_if; [ | congruence]. - break_if; [ congruence | ]. - break_if; inversion_Some_eq; auto using solve_onCurve, solve_opp_onCurve. - Qed. - - Lemma prod_eq_dec : forall {A} (A_eq_dec : forall a a' : A, {a = a'} + {a <> a'}) - (x y : (A * A)), {x = y} + {x <> y}. - Proof. - decide equality. - Qed. - - Lemma option_eq_dec : forall {A} (A_eq_dec : forall a a' : A, {a = a'} + {a <> a'}) - (x y : option A), {x = y} + {x <> y}. - Proof. - decide equality. - Qed. - - Definition point_dec' w p : option E.point := - match (option_eq_dec (prod_eq_dec F_eq_dec) (point_dec_coordinates sign_bit w) (Some p)) with - | left EQ => Some (exist _ p (point_dec_coordinates_onCurve w p EQ)) - | right _ => None (* this case is never reached *) - end. - - Definition point_dec (w : word (S sz)) : option E.point := - match (point_dec_coordinates sign_bit w) with - | Some p => point_dec' w p - | None => None - end. - - Lemma point_coordinates_encoding_canonical : forall w p, - point_dec_coordinates sign_bit w = Some p -> point_enc_coordinates p = w. - Proof. - unfold point_dec_coordinates, point_enc_coordinates; intros ? ? coord_dec_Some. - case_eq (dec (wtl w)); [ intros ? dec_Some | intros dec_None; rewrite dec_None in *; congruence ]. - destruct p. - rewrite (shatter_word w). - f_equal; rewrite dec_Some in *; - do 2 (break_if; try congruence); inversion coord_dec_Some; subst. - + destruct (F_eq_dec (sqrt_mod_q (E.solve_for_x2 f1)) 0%F) as [sqrt_0 | ?]. - - rewrite sqrt_0 in *. - apply sqrt_mod_q_root_0 in sqrt_0; try assumption. - rewrite sqrt_0 in *. - break_if; [symmetry; auto using Bool.eqb_prop | ]. - rewrite sign_bit_zero in *. - simpl in Heqb; rewrite Heqb in *. - discriminate. - - break_if. - symmetry; auto using Bool.eqb_prop. - rewrite <- sign_bit_opp by assumption. - destruct (whd w); inversion Heqb0; break_if; auto. - + inversion coord_dec_Some; subst. - auto using encoding_canonical. -Qed. - - Lemma point_encoding_canonical : forall w x, point_dec w = Some x -> point_enc x = w. - Proof. - (* - unfold point_enc; intros. - unfold point_dec in *. - assert (point_dec_coordinates w = Some (proj1_sig x)). { - set (y := point_dec_coordinates w) in *. - revert H. - dependent destruction y. intros. - rewrite H0 in H. - *) - Admitted. - -Lemma point_dec_coordinates_correct w - : option_map (@proj1_sig _ _) (point_dec w) = point_dec_coordinates sign_bit w. -Proof. - unfold point_dec, option_map. - do 2 break_match; try congruence; unfold point_dec' in *; - break_match; try congruence. - inversion_Some_eq. - reflexivity. -Qed. - -Lemma y_decode : forall p, dec (wtl (point_enc_coordinates p)) = Some (snd p). -Proof. - intros. - destruct p as [x y]; simpl. - exact (encoding_valid y). -Qed. - -Lemma sign_bit_opp_eq_iff : forall x y, y <> 0 -> - (sign_bit x <> sign_bit y <-> sign_bit x = sign_bit (opp y)). -Proof. - split; intro sign_mismatch; case_eq (sign_bit x); case_eq (sign_bit y); - try congruence; intros y_sign x_sign; rewrite <- sign_bit_opp in * by auto; - rewrite y_sign, x_sign in *; reflexivity || discriminate. -Qed. - -Lemma sign_bit_squares : forall x y, y <> 0 -> x ^ 2 = y ^ 2 -> - sign_bit x = sign_bit y -> x = y. -Proof. - intros ? ? y_nonzero squares_eq sign_match. - destruct (sqrt_solutions _ _ squares_eq) as [? | eq_opp]; auto. - assert (sign_bit x = sign_bit (opp y)) as sign_mismatch by (f_equal; auto). - apply sign_bit_opp_eq_iff in sign_mismatch; auto. - congruence. -Qed. - -Lemma sign_bit_match : forall x x' y : F q, E.onCurve (x, y) -> E.onCurve (x', y) -> - sign_bit x = sign_bit x' -> x = x'. -Proof. - intros ? ? ? onCurve_x onCurve_x' sign_match. - apply E.solve_correct in onCurve_x. - apply E.solve_correct in onCurve_x'. - destruct (F_eq_dec x' 0). - + subst. - rewrite Fq_pow_zero in onCurve_x' by congruence. - rewrite <- onCurve_x' in *. - eapply Fq_root_zero; eauto. - + apply sign_bit_squares; auto. - rewrite onCurve_x, onCurve_x'. - reflexivity. -Qed. - -Lemma point_encoding_coordinates_valid : forall p, E.onCurve p -> - point_dec_coordinates sign_bit (point_enc_coordinates p) = Some p. -Proof. - intros p onCurve_p. - unfold point_dec_coordinates. - rewrite y_decode. - pose proof (solve_sqrt_valid p onCurve_p) as solve_sqrt_valid_p. - destruct p as [x y]. - unfold sqrt_valid in *. - simpl. - replace (E.solve_for_x2 y) with (x ^ 2 : F q) in * by (apply E.solve_correct; assumption). - case_eq (F_eqb x 0); intro eqb_x_0. - + apply F_eqb_eq in eqb_x_0; rewrite eqb_x_0 in *. - rewrite !Fq_pow_zero, sqrt_mod_q_of_0, Fq_pow_zero by congruence. - rewrite if_F_eq_dec_if_F_eqb, sign_bit_zero. - reflexivity. - + assert (sqrt_mod_q (x ^ 2) <> 0) by (intro false_eq; apply sqrt_mod_q_root_0 in false_eq; try assumption; - apply Fq_root_zero in false_eq; rewrite false_eq, F_eqb_refl in eqb_x_0; congruence). - replace (F_eqb (sqrt_mod_q (x ^ 2)) 0) with false by (symmetry; - apply F_eqb_neq_complete; assumption). - break_if. - - simpl. - f_equal. - break_if. - * rewrite Bool.eqb_true_iff in Heqb. - pose proof (solve_onCurve y solve_sqrt_valid_p). - f_equal. - apply (sign_bit_match _ _ y); auto. - apply E.solve_correct in onCurve_p; rewrite onCurve_p in *. - assumption. - * rewrite Bool.eqb_false_iff in Heqb. - pose proof (solve_opp_onCurve y solve_sqrt_valid_p). - f_equal. - apply sign_bit_opp_eq_iff in Heqb; try assumption. - apply (sign_bit_match _ _ y); auto. - apply E.solve_correct in onCurve_p. - rewrite onCurve_p; auto. - - simpl in solve_sqrt_valid_p. - replace (E.solve_for_x2 y) with (x ^ 2 : F q) in * by (apply E.solve_correct; assumption). - congruence. -Qed. - -Lemma point_dec'_valid : forall p, - point_dec' (point_enc_coordinates (proj1_sig p)) (proj1_sig p) = Some p. -Proof. - unfold point_dec'; intros. - break_match. - + f_equal. - destruct p. - apply E.point_eq. - reflexivity. - + rewrite point_encoding_coordinates_valid in n by apply (proj2_sig p). - congruence. -Qed. - -Lemma point_encoding_valid : forall p, point_dec (point_enc p) = Some p. -Proof. - intros. - unfold point_dec. - replace (point_enc p) with (point_enc_coordinates (proj1_sig p)) by reflexivity. - break_match; rewrite point_encoding_coordinates_valid in * by apply (proj2_sig p); try congruence. - inversion_Some_eq. - eapply point_dec'_valid. -Qed. - -End PointEncoding. diff --git a/src/Encoding/PointEncodingTheorems.v b/src/Encoding/PointEncodingTheorems.v deleted file mode 100644 index ccea1d81b..000000000 --- a/src/Encoding/PointEncodingTheorems.v +++ /dev/null @@ -1,207 +0,0 @@ -Require Import Coq.ZArith.ZArith Coq.ZArith.Znumtheory. -Require Import Coq.Numbers.Natural.Peano.NPeano. -Require Import Coq.Program.Equality. -Require Import Crypto.Encoding.EncodingTheorems. -Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. -Require Import Bedrock.Word. -Require Import Crypto.Tactics.VerdiTactics. - -Require Import Crypto.Spec.Encoding Crypto.Spec.ModularArithmetic Crypto.Spec.CompleteEdwardsCurve. - -Local Open Scope F_scope. - -Section PointEncoding. - Context {prm: CompleteEdwardsCurve.TwistedEdwardsParams} {sz : nat} - {FqEncoding : canonical encoding of ModularArithmetic.F (CompleteEdwardsCurve.q) as Word.word sz} - {q_5mod8 : (CompleteEdwardsCurve.q mod 8 = 5)%Z} - {sqrt_minus1_valid : (@ZToField CompleteEdwardsCurve.q 2 ^ BinInt.Z.to_N (CompleteEdwardsCurve.q / 4)) ^ 2 = opp 1}. - Existing Instance CompleteEdwardsCurve.prime_q. - - Add Field Ffield : (@PrimeFieldTheorems.Ffield_theory CompleteEdwardsCurve.q _) - (morphism (@ModularArithmeticTheorems.Fring_morph CompleteEdwardsCurve.q), - preprocess [ModularArithmeticTheorems.Fpreprocess], - postprocess [ModularArithmeticTheorems.Fpostprocess; try exact PrimeFieldTheorems.Fq_1_neq_0; try assumption], - constants [ModularArithmeticTheorems.Fconstant], - div (@ModularArithmeticTheorems.Fmorph_div_theory CompleteEdwardsCurve.q), - power_tac (@ModularArithmeticTheorems.Fpower_theory CompleteEdwardsCurve.q) [ModularArithmeticTheorems.Fexp_tac]). - - Definition sqrt_valid (a : F q) := ((sqrt_mod_q a) ^ 2 = a)%F. - - Lemma solve_sqrt_valid : forall (p : E.point), - sqrt_valid (E.solve_for_x2 (snd (proj1_sig p))). - Proof. - intros. - destruct p as [[x y] onCurve_xy]; simpl. - rewrite (E.solve_correct x y) in onCurve_xy. - rewrite <- onCurve_xy. - unfold sqrt_valid. - eapply sqrt_mod_q_valid; eauto. - unfold isSquare; eauto. - Grab Existential Variables. eauto. - Qed. - - Lemma solve_onCurve: forall (y : F q), sqrt_valid (E.solve_for_x2 y) -> - E.onCurve (sqrt_mod_q (E.solve_for_x2 y), y). - Proof. - intros. - unfold sqrt_valid in *. - apply E.solve_correct; auto. - Qed. - - Lemma solve_opp_onCurve: forall (y : F q), sqrt_valid (E.solve_for_x2 y) -> - E.onCurve (opp (sqrt_mod_q (E.solve_for_x2 y)), y). - Proof. - intros y sqrt_valid_x2. - unfold sqrt_valid in *. - apply E.solve_correct. - rewrite <- sqrt_valid_x2 at 2. - ring. - Qed. - -Definition sign_bit (x : F q) := (wordToN (enc (opp x)) None - | Some y => let x2 := E.solve_for_x2 y in - let x := sqrt_mod_q x2 in - if F_eq_dec (x ^ 2) x2 - then - let p := (if Bool.eqb (whd w) (sign_bit x) then x else opp x, y) in - Some p - else None - end. - -Definition point_dec (w : word (S sz)) : option E.point := - match dec (wtl w) with - | None => None - | Some y => let x2 := E.solve_for_x2 y in - let x := sqrt_mod_q x2 in - match (F_eq_dec (x ^ 2) x2) with - | right _ => None - | left EQ => if Bool.eqb (whd w) (sign_bit x) - then Some (exist _ (x, y) (solve_onCurve y EQ)) - else Some (exist _ (opp x, y) (solve_opp_onCurve y EQ)) - end - end. - -Lemma point_dec_coordinates_correct w - : option_map (@proj1_sig _ _) (point_dec w) = point_dec_coordinates w. -Proof. - unfold point_dec, point_dec_coordinates. - edestruct dec; [ | reflexivity ]. - edestruct @F_eq_dec; [ | reflexivity ]. - edestruct @Bool.eqb; reflexivity. -Qed. - -Lemma y_decode : forall p, dec (wtl (point_enc p)) = Some (snd (proj1_sig p)). -Proof. - intros. - destruct p as [[x y] onCurve_p]; simpl. - exact (encoding_valid y). -Qed. - - -Lemma wordToN_enc_neq_opp : forall x, x <> 0 -> (wordToN (enc (opp x)) <> wordToN (enc x))%N. -Proof. - intros x x_nonzero. - intro false_eq. - apply x_nonzero. - apply F_eq_opp_zero; try apply two_lt_q. - apply wordToN_inj in false_eq. - apply encoding_inj in false_eq. - auto. -Qed. - -Lemma sign_bit_opp_negb : forall x, x <> 0 -> negb (sign_bit x) = sign_bit (opp x). -Proof. - intros x x_nonzero. - unfold sign_bit. - rewrite <- N.leb_antisym. - rewrite N.ltb_compare, N.leb_compare. - rewrite F_opp_involutive. - case_eq (wordToN (enc x) ?= wordToN (enc (opp x)))%N; auto. - intro wordToN_enc_eq. - pose proof (wordToN_enc_neq_opp x x_nonzero). - apply N.compare_eq_iff in wordToN_enc_eq. - congruence. -Qed. - -Lemma sign_bit_opp : forall x y, y <> 0 -> - (sign_bit x <> sign_bit y <-> sign_bit x = sign_bit (opp y)). -Proof. - split; intro sign_mismatch; case_eq (sign_bit x); case_eq (sign_bit y); - try congruence; intros y_sign x_sign; rewrite <- sign_bit_opp_negb in * by auto; - rewrite y_sign, x_sign in *; reflexivity || discriminate. -Qed. - -Lemma sign_bit_squares : forall x y, y <> 0 -> x ^ 2 = y ^ 2 -> - sign_bit x = sign_bit y -> x = y. -Proof. - intros ? ? y_nonzero squares_eq sign_match. - destruct (sqrt_solutions _ _ squares_eq) as [? | eq_opp]; auto. - assert (sign_bit x = sign_bit (opp y)) as sign_mismatch by (f_equal; auto). - apply sign_bit_opp in sign_mismatch; auto. - congruence. -Qed. - -Lemma sign_bit_match : forall x x' y : F q, E.onCurve (x, y) -> E.onCurve (x', y) -> - sign_bit x = sign_bit x' -> x = x'. -Proof. - intros ? ? ? onCurve_x onCurve_x' sign_match. - apply E.solve_correct in onCurve_x. - apply E.solve_correct in onCurve_x'. - destruct (F_eq_dec x' 0). - + subst. - rewrite Fq_pow_zero in onCurve_x' by congruence. - rewrite <- onCurve_x' in *. - eapply Fq_root_zero; eauto. - + apply sign_bit_squares; auto. - rewrite onCurve_x, onCurve_x'. - reflexivity. -Qed. - -Lemma point_encoding_valid : forall p, point_dec (point_enc p) = Some p. -Proof. - intros. - unfold point_dec. - rewrite y_decode. - pose proof solve_sqrt_valid p as solve_sqrt_valid_p. - unfold sqrt_valid in *. - destruct p as [[x y] onCurve_p]. - simpl in *. - destruct (F_eq_dec ((sqrt_mod_q (E.solve_for_x2 y)) ^ 2) (E.solve_for_x2 y)); intuition. - break_if; f_equal; apply E.point_eq. - + rewrite Bool.eqb_true_iff in Heqb. - pose proof (solve_onCurve y solve_sqrt_valid_p). - f_equal. - apply (sign_bit_match _ _ y); auto. - + rewrite Bool.eqb_false_iff in Heqb. - pose proof (solve_opp_onCurve y solve_sqrt_valid_p). - f_equal. - apply sign_bit_opp in Heqb. - apply (sign_bit_match _ _ y); auto. - intro eq_zero. - apply E.solve_correct in onCurve_p. - rewrite eq_zero in *. - rewrite Fq_pow_zero in solve_sqrt_valid_p by congruence. - rewrite <- solve_sqrt_valid_p in onCurve_p. - apply Fq_root_zero in onCurve_p. - rewrite onCurve_p in Heqb; auto. -Qed. - -(* Waiting on canonicalization *) -Lemma point_encoding_canonical : forall (x_enc : word (S sz)) (x : E.point), -point_dec x_enc = Some x -> point_enc x = x_enc. -Admitted. - -Instance point_encoding : canonical encoding of E.point as (word (S sz)) := { - enc := point_enc; - dec := point_dec; - encoding_valid := point_encoding_valid; - encoding_canonical := point_encoding_canonical -}. - -End PointEncoding. diff --git a/src/Experiments/SpecEd25519.v b/src/Experiments/SpecEd25519.v new file mode 100644 index 000000000..4e30313d9 --- /dev/null +++ b/src/Experiments/SpecEd25519.v @@ -0,0 +1,165 @@ +Require Import Coq.ZArith.ZArith Coq.ZArith.Zpower Coq.ZArith.ZArith Coq.ZArith.Znumtheory. +Require Import Coq.Numbers.Natural.Peano.NPeano Coq.NArith.NArith. +Require Import Crypto.Spec.ModularWordEncoding. +Require Import Crypto.Encoding.ModularWordEncodingTheorems. +Require Import Crypto.Spec.EdDSA. +Require Import Crypto.Spec.CompleteEdwardsCurve Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. +Require Import Crypto.ModularArithmetic.PrimeFieldTheorems Crypto.ModularArithmetic.ModularArithmeticTheorems. +Require Import Crypto.Util.NatUtil Crypto.Util.ZUtil Crypto.Util.WordUtil Crypto.Util.NumTheoryUtil. +Require Import Bedrock.Word. +Require Import Crypto.Tactics.VerdiTactics. +Require Import Coq.Logic.Decidable. +Require Import Coq.omega.Omega. + +Local Open Scope nat_scope. +Definition q : Z := (2 ^ 255 - 19)%Z. +Global Instance prime_q : prime q. Admitted. +Lemma two_lt_q : (2 < q)%Z. reflexivity. Qed. + +Definition a : F q := opp 1%F. + +(* TODO (jadep) : make the proofs about a and d more general *) +Lemma nonzero_a : a <> 0%F. +Proof. + unfold a. + intro eq_opp1_0. + apply (@Fq_1_neq_0 q prime_q). + rewrite <- (F_opp_spec 1%F). + rewrite eq_opp1_0. + symmetry; apply F_add_0_r. +Qed. + +Ltac q_bound := pose proof two_lt_q; omega. +Lemma square_a : isSquare a. +Proof. + Lemma q_1mod4 : (q mod 4 = 1)%Z. reflexivity. Qed. + intros. + pose proof (minus1_square_1mod4 q prime_q q_1mod4) as minus1_square. + destruct minus1_square as [b b_id]. + apply square_Zmod_F. + exists b; rewrite b_id. + unfold a. + rewrite opp_ZToField. + rewrite FieldToZ_ZToField. + rewrite Z.mod_small; q_bound. +Qed. + +Hint Rewrite + @FieldToZ_add + @FieldToZ_mul + @FieldToZ_opp + @FieldToZ_inv_efficient + @FieldToZ_pow_efficient + @FieldToZ_ZToField + @Zmod_mod + : ZToField. + +Definition d : F q := (opp (ZToField 121665) / (ZToField 121666))%F. +Lemma nonsquare_d : forall x, (x^2 <> d)%F. + pose proof @euler_criterion_if q prime_q d two_lt_q. + match goal with + [H: if ?b then ?x else ?y |- ?y ] => replace b with false in H; [exact H|clear H] + end. + unfold d, div. autorewrite with ZToField; [|eauto using prime_q, two_lt_q..]. + vm_compute. (* 10s *) + exact eq_refl. +Qed. (* 10s *) + +Instance curve25519params : @E.twisted_edwards_params (F q) eq (ZToField 0) (ZToField 1) add mul a d := + { + nonzero_a := nonzero_a + (* TODO:port + char_gt_2 : ~ Feq (Fadd Fone Fone) Fzero; + nonzero_a : ~ Feq a Fzero; + nonsquare_d : forall x : F, ~ Feq (Fmul x x) d } + *) + }. +Admitted. + +Lemma two_power_nat_Z2Nat : forall n, Z.to_nat (two_power_nat n) = 2 ^ n. +Admitted. + +Definition b := 256. +Lemma b_valid : (2 ^ (b - 1) > Z.to_nat q)%nat. +Proof. + unfold q, gt. + replace (2 ^ (b - 1)) with (Z.to_nat (2 ^ (Z.of_nat (b - 1)))) + by (rewrite <- two_power_nat_equiv; apply two_power_nat_Z2Nat). + rewrite <- Z2Nat.inj_lt; compute; congruence. +Qed. + +Definition c := 3. +Lemma c_valid : c = 2 \/ c = 3. +Proof. + right; auto. +Qed. + +Definition n := b - 2. +Lemma n_ge_c : n >= c. +Proof. + unfold n, c, b; omega. +Qed. +Lemma n_le_b : n <= b. +Proof. + unfold n, b; omega. +Qed. + +Definition l : nat := Z.to_nat (252 + 27742317777372353535851937790883648493)%Z. +Lemma prime_l : prime (Z.of_nat l). Admitted. +Lemma l_odd : l > 2. +Proof. + unfold l, proj1_sig. + rewrite Z2Nat.inj_add; try omega. + apply lt_plus_trans. + compute; omega. +Qed. + +Require Import Crypto.Spec.Encoding. + +Lemma q_pos : (0 < q)%Z. q_bound. Qed. +Definition FqEncoding : canonical encoding of (F q) as word (b-1) := + @modular_word_encoding q (b - 1) q_pos b_valid. + +Lemma l_pos : (0 < Z.of_nat l)%Z. pose proof prime_l; prime_bound. Qed. +Lemma l_bound : Z.to_nat (Z.of_nat l) < 2 ^ b. +Proof. + rewrite Nat2Z.id. + rewrite <- pow2_id. + rewrite Zpow_pow2. + unfold l. + apply Z2Nat.inj_lt; compute; congruence. +Qed. +Definition FlEncoding : canonical encoding of F (Z.of_nat l) as word b := + @modular_word_encoding (Z.of_nat l) b l_pos l_bound. + +Lemma q_5mod8 : (q mod 8 = 5)%Z. cbv; reflexivity. Qed. + +Lemma sqrt_minus1_valid : ((@ZToField q 2 ^ Z.to_N (q / 4)) ^ 2 = opp 1)%F. +Proof. + apply F_eq. + autorewrite with ZToField. + vm_compute. + reflexivity. +Qed. + +Local Notation point := (@E.point (F q) eq (ZToField 1) add mul a d). +Local Notation zero := (E.zero(H:=field_modulo)). +Local Notation add := (E.add(H0:=curve25519params)). +Local Infix "*" := (E.mul(H0:=curve25519params)). +Axiom H : forall n : nat, word n -> word (b + b). +Axiom B : point. (* TODO: B = decodePoint (y=4/5, x="positive") *) +Axiom B_nonzero : B <> zero. +Axiom l_order_B : l * B = zero. +Axiom point_encoding : canonical encoding of point as word b. +Axiom scalar_encoding : canonical encoding of {n : nat | n < l} as word b. + +Global Instance Ed25519 : @EdDSA point E.eq add zero E.opp E.mul b H c n l B point_encoding scalar_encoding := + { + EdDSA_c_valid := c_valid; + EdDSA_n_ge_c := n_ge_c; + EdDSA_n_le_b := n_le_b; + EdDSA_B_not_identity := B_nonzero; + EdDSA_l_prime := prime_l; + EdDSA_l_odd := l_odd; + EdDSA_l_order_B := l_order_B + }. \ No newline at end of file diff --git a/src/Spec/Ed25519.v b/src/Spec/Ed25519.v deleted file mode 100644 index 4876bb8d1..000000000 --- a/src/Spec/Ed25519.v +++ /dev/null @@ -1,179 +0,0 @@ -Require Import Coq.ZArith.ZArith Coq.ZArith.Zpower Coq.ZArith.ZArith Coq.ZArith.Znumtheory. -Require Import Coq.Numbers.Natural.Peano.NPeano Coq.NArith.NArith. -Require Import Crypto.Spec.PointEncoding Crypto.Spec.ModularWordEncoding. -Require Import Crypto.Encoding.ModularWordEncodingTheorems. -Require Import Crypto.Spec.EdDSA. -Require Import Crypto.Spec.CompleteEdwardsCurve Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.ModularArithmetic.PrimeFieldTheorems Crypto.ModularArithmetic.ModularArithmeticTheorems. -Require Import Crypto.Util.NatUtil Crypto.Util.ZUtil Crypto.Util.WordUtil Crypto.Util.NumTheoryUtil. -Require Import Bedrock.Word. -Require Import Crypto.Tactics.VerdiTactics. -Require Import Coq.Logic.Decidable. -Require Import Coq.omega.Omega. - -Local Open Scope nat_scope. -Definition q : Z := (2 ^ 255 - 19)%Z. -Lemma prime_q : prime q. Admitted. -Lemma two_lt_q : (2 < q)%Z. reflexivity. Qed. - -Definition a : F q := opp 1%F. - -(* TODO (jadep) : make the proofs about a and d more general *) -Lemma nonzero_a : a <> 0%F. -Proof. - unfold a. - intro eq_opp1_0. - apply (@Fq_1_neq_0 q prime_q). - rewrite <- (F_opp_spec 1%F). - rewrite eq_opp1_0. - symmetry; apply F_add_0_r. -Qed. - -Ltac q_bound := pose proof two_lt_q; omega. -Lemma square_a : isSquare a. -Proof. - Lemma q_1mod4 : (q mod 4 = 1)%Z. reflexivity. Qed. - intros. - pose proof (minus1_square_1mod4 q prime_q q_1mod4) as minus1_square. - destruct minus1_square as [b b_id]. - apply square_Zmod_F. - exists b; rewrite b_id. - unfold a. - rewrite opp_ZToField. - rewrite FieldToZ_ZToField. - rewrite Z.mod_small; q_bound. -Qed. - -Hint Rewrite - @FieldToZ_add - @FieldToZ_mul - @FieldToZ_opp - @FieldToZ_inv_efficient - @FieldToZ_pow_efficient - @FieldToZ_ZToField - @Zmod_mod - : ZToField. - -Definition d : F q := (opp (ZToField 121665) / (ZToField 121666))%F. -Lemma nonsquare_d : forall x, (x^2 <> d)%F. - pose proof @euler_criterion_if q prime_q d two_lt_q. - match goal with - [H: if ?b then ?x else ?y |- ?y ] => replace b with false in H; [exact H|clear H] - end. - unfold d, div. autorewrite with ZToField; [|eauto using prime_q, two_lt_q..]. - vm_compute. (* 10s *) - exact eq_refl. -Qed. (* 10s *) - -Instance curve25519params : TwistedEdwardsParams := { - q := q; - prime_q := prime_q; - two_lt_q := two_lt_q; - a := a; - nonzero_a := nonzero_a; - square_a := square_a; - d := d; - nonsquare_d := nonsquare_d -}. - -Lemma two_power_nat_Z2Nat : forall n, Z.to_nat (two_power_nat n) = 2 ^ n. -Admitted. - -Definition b := 256. -Lemma b_valid : (2 ^ (b - 1) > Z.to_nat CompleteEdwardsCurve.q)%nat. -Proof. - replace (CompleteEdwardsCurve.q) with q by reflexivity. - unfold q, gt. - replace (2 ^ (b - 1)) with (Z.to_nat (2 ^ (Z.of_nat (b - 1)))) - by (rewrite <- two_power_nat_equiv; apply two_power_nat_Z2Nat). - rewrite <- Z2Nat.inj_lt; compute; congruence. -Qed. - -Definition c := 3. -Lemma c_valid : c = 2 \/ c = 3. -Proof. - right; auto. -Qed. - -Definition n := b - 2. -Lemma n_ge_c : n >= c. -Proof. - unfold n, c, b; omega. -Qed. -Lemma n_le_b : n <= b. -Proof. - unfold n, b; omega. -Qed. - -Definition l : nat := Z.to_nat (252 + 27742317777372353535851937790883648493)%Z. -Lemma prime_l : prime (Z.of_nat l). Admitted. -Lemma l_odd : l > 2. -Proof. - unfold l, proj1_sig. - rewrite Z2Nat.inj_add; try omega. - apply lt_plus_trans. - compute; omega. -Qed. - -Require Import Crypto.Spec.Encoding. - -Lemma q_pos : (0 < q)%Z. q_bound. Qed. -Definition FqEncoding : canonical encoding of (F q) as word (b-1) := - @modular_word_encoding q (b - 1) q_pos b_valid. - -Lemma l_pos : (0 < Z.of_nat l)%Z. pose proof prime_l; prime_bound. Qed. -Lemma l_bound : Z.to_nat (Z.of_nat l) < 2 ^ b. -Proof. - rewrite Nat2Z.id. - rewrite <- pow2_id. - rewrite Zpow_pow2. - unfold l. - apply Z2Nat.inj_lt; compute; congruence. -Qed. -Definition FlEncoding : canonical encoding of F (Z.of_nat l) as word b := - @modular_word_encoding (Z.of_nat l) b l_pos l_bound. - -Lemma q_5mod8 : (q mod 8 = 5)%Z. cbv; reflexivity. Qed. - -Lemma sqrt_minus1_valid : ((@ZToField q 2 ^ Z.to_N (q / 4)) ^ 2 = opp 1)%F. -Proof. - apply F_eq. - autorewrite with ZToField. - vm_compute. - reflexivity. -Qed. - -Definition PointEncoding : canonical encoding of E.point as (word b) := - (@point_encoding curve25519params (b - 1) q_5mod8 sqrt_minus1_valid FqEncoding sign_bit - (@sign_bit_zero _ prime_q two_lt_q _ b_valid) (@sign_bit_opp _ prime_q two_lt_q _ b_valid)). - -Definition H : forall n : nat, word n -> word (b + b). Admitted. -Definition B : E.point. Admitted. (* TODO: B = decodePoint (y=4/5, x="positive") *) -Definition B_nonzero : B <> E.zero. Admitted. -Definition l_order_B : (l * B)%E = E.zero. Admitted. - -Local Instance ed25519params : EdDSAParams := { - E := curve25519params; - b := b; - H := H; - c := c; - n := n; - B := B; - l := l; - FqEncoding := FqEncoding; - FlEncoding := FlEncoding; - PointEncoding := PointEncoding; - - b_valid := b_valid; - c_valid := c_valid; - n_ge_c := n_ge_c; - n_le_b := n_le_b; - B_not_identity := B_nonzero; - l_prime := prime_l; - l_odd := l_odd; - l_order_B := l_order_B -}. - -Definition ed25519_verify - : forall (pubkey:word b) (len:nat) (msg:word len) (sig:word (b+b)), bool - := @verify ed25519params. \ No newline at end of file diff --git a/src/Spec/PointEncoding.v b/src/Spec/PointEncoding.v deleted file mode 100644 index 29e359baa..000000000 --- a/src/Spec/PointEncoding.v +++ /dev/null @@ -1,39 +0,0 @@ -Require Coq.ZArith.ZArith Coq.ZArith.Znumtheory. -Require Coq.Numbers.Natural.Peano.NPeano. -Require Crypto.Encoding.EncodingTheorems. -Require Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Crypto.ModularArithmetic.PrimeFieldTheorems. -Require Bedrock.Word. -Require Crypto.Tactics.VerdiTactics. -Require Crypto.Encoding.PointEncodingPre. -Obligation Tactic := eauto; exact PointEncodingPre.point_encoding_canonical. - -Require Import Crypto.Spec.Encoding Crypto.Spec.ModularWordEncoding. -Require Import Crypto.Spec.CompleteEdwardsCurve Crypto.Spec.ModularArithmetic. - -Local Open Scope F_scope. - -Section PointEncoding. - Context {prm: TwistedEdwardsParams} {sz : nat} {sz_nonzero : (0 < sz)%nat} - {bound_check : (BinInt.Z.to_nat q < NPeano.Nat.pow 2 sz)%nat} {q_5mod8 : (q mod 8 = 5)%Z} - {sqrt_minus1_valid : (@ZToField q 2 ^ BinInt.Z.to_N (q / 4)) ^ 2 = opp 1} - {FqEncoding : canonical encoding of (F q) as (Word.word sz)} - {sign_bit : F q -> bool} {sign_bit_zero : sign_bit 0 = false} - {sign_bit_opp : forall x, x <> 0 -> negb (sign_bit x) = sign_bit (opp x)}. - - Definition point_enc (p : E.point) : Word.word (S sz) := let '(x,y) := proj1_sig p in - Word.WS (sign_bit x) (enc y). - - Program Definition point_dec_with_spec : - {point_dec : Word.word (S sz) -> option E.point - | forall w x, point_dec w = Some x -> (point_enc x = w) - } := @PointEncodingPre.point_dec _ _ _ sign_bit. - Definition point_dec := Eval hnf in (proj1_sig point_dec_with_spec). - - Global Instance point_encoding : canonical encoding of E.point as (Word.word (S sz)) := { - enc := point_enc; - dec := point_dec; - encoding_valid := @PointEncodingPre.point_encoding_valid _ _ q_5mod8 sqrt_minus1_valid _ _ sign_bit_zero sign_bit_opp; - encoding_canonical := PointEncodingPre.point_encoding_canonical - }. -End PointEncoding. \ No newline at end of file -- cgit v1.2.3 From 449dbf816caed0e7b72ce74838d8a379fcae7dd4 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 20 Jun 2016 04:06:14 -0400 Subject: remove obsolete rep mechanism --- _CoqProject | 3 +- .../DerivationsOptionRectLetInEncoding.v | 342 +++++++++++++++++++ .../DerivationsOptionRectLetInFqPowEncoding.v | 376 --------------------- src/Rep.v | 13 - src/Specific/GF25519.v | 98 +----- 5 files changed, 344 insertions(+), 488 deletions(-) create mode 100644 src/Experiments/DerivationsOptionRectLetInEncoding.v delete mode 100644 src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v delete mode 100644 src/Rep.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index a3458ed1e..14179cb3d 100644 --- a/_CoqProject +++ b/_CoqProject @@ -6,7 +6,6 @@ src/Algebra.v src/BaseSystem.v src/BaseSystemProofs.v src/Nsatz.v -src/Rep.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -14,7 +13,7 @@ src/CompleteEdwardsCurve/Pre.v src/Encoding/EncodingTheorems.v src/Encoding/ModularWordEncodingPre.v src/Encoding/ModularWordEncodingTheorems.v -src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v +src/Experiments/DerivationsOptionRectLetInEncoding.v src/Experiments/GenericFieldPow.v src/Experiments/SpecEd25519.v src/ModularArithmetic/ExtendedBaseVector.v diff --git a/src/Experiments/DerivationsOptionRectLetInEncoding.v b/src/Experiments/DerivationsOptionRectLetInEncoding.v new file mode 100644 index 000000000..9a6873bba --- /dev/null +++ b/src/Experiments/DerivationsOptionRectLetInEncoding.v @@ -0,0 +1,342 @@ +Require Import Bedrock.Word. +Require Import Crypto.Spec.EdDSA. +Require Import Crypto.Tactics.VerdiTactics. +Require Import BinNat BinInt NArith Crypto.Spec.ModularArithmetic. +Require Import ModularArithmetic.ModularArithmeticTheorems. +Require Import ModularArithmetic.PrimeFieldTheorems. +Require Import Crypto.Spec.CompleteEdwardsCurve. +Require Import Crypto.Spec.Encoding Crypto.Spec.ModularWordEncoding. +Require Import Crypto.CompleteEdwardsCurve.ExtendedCoordinates. +Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. +Require Import Crypto.Util.IterAssocOp Crypto.Util.WordUtil. +Require Import Coq.Setoids.Setoid Coq.Classes.Morphisms Coq.Classes.Equivalence. +Require Import Zdiv. +Require Import Crypto.Util.Tuple. +Local Open Scope equiv_scope. + +Generalizable All Variables. + + +Local Ltac set_evars := + repeat match goal with + | [ |- appcontext[?E] ] => is_evar E; let e := fresh "e" in set (e := E) + end. + +Local Ltac subst_evars := + repeat match goal with + | [ e := ?E |- _ ] => is_evar E; subst e + end. + +Definition path_sig {A P} {RA:relation A} {Rsig:relation (@sig A P)} + {HP:Proper (RA==>Basics.impl) P} + (H:forall (x y:A) (px:P x) (py:P y), RA x y -> Rsig (exist _ x px) (exist _ y py)) + (x : @sig A P) (y0:A) (pf : RA (proj1_sig x) y0) +: Rsig x (exist _ y0 (HP _ _ pf (proj2_sig x))). +Proof. destruct x. eapply H. assumption. Defined. + +Definition Let_In {A P} (x : A) (f : forall a : A, P a) : P x := let y := x in f y. +Global Instance Let_In_Proper_changebody {A P R} {Reflexive_R:@Reflexive P R} + : Proper (eq ==> pointwise_relation _ R ==> R) (@Let_In A (fun _ => P)). +Proof. + lazy; intros; try congruence. + subst; auto. +Qed. + +Lemma Let_In_Proper_changevalue {A B} RA {RB} (f:A->B) {Proper_f:Proper (RA==>RB) f} + : Proper (RA ==> RB) (fun x => Let_In x f). +Proof. intuition. Qed. + +Ltac fold_identity_lambdas := + repeat match goal with + | [ H: appcontext [fun x => ?f x] |- _ ] => change (fun x => f x) with f in * + | |- appcontext [fun x => ?f x] => change (fun x => f x) with f in * + end. + +Local Ltac replace_let_in_with_Let_In := + match goal with + | [ |- context G[let x := ?y in @?z x] ] + => let G' := context G[Let_In y z] in change G' + end. + +Local Ltac Let_In_app fn := + match goal with + | [ |- appcontext G[Let_In (fn ?x) ?f] ] + => change (Let_In (fn x) f) with (Let_In x (fun y => f (fn y))); cbv beta + end. + +Lemma if_map : forall {T U} (f:T->U) (b:bool) (x y:T), (if b then f x else f y) = f (if b then x else y). +Proof. + destruct b; trivial. +Qed. + +Lemma pull_Let_In {B C} (f : B -> C) A (v : A) (b : A -> B) + : Let_In v (fun v' => f (b v')) = f (Let_In v b). +Proof. + reflexivity. +Qed. + +Lemma Let_app_In {A B T} (g:A->B) (f:B->T) (x:A) : + @Let_In _ (fun _ => T) (g x) f = + @Let_In _ (fun _ => T) x (fun p => f (g x)). +Proof. reflexivity. Qed. + +Lemma Let_app_In' : forall {A B T} {R} {R_equiv:@Equivalence T R} + (g : A -> B) (f : B -> T) (x : A) + f' (f'_ok: forall z, f' z === f (g z)), + Let_In (g x) f === Let_In x f'. +Proof. intros; cbv [Let_In]; rewrite f'_ok; reflexivity. Qed. +Definition unfold_Let_In {A B} x (f:A->B) : Let_In x f = let y := x in f y := eq_refl. + +Lemma Let_app2_In {A B C D T} (g1:A->C) (g2:B->D) (f:C*D->T) (x:A) (y:B) : + @Let_In _ (fun _ => T) (g1 x, g2 y) f = + @Let_In _ (fun _ => T) (x, y) (fun p => f ((g1 (fst p), g2 (snd p)))). +Proof. reflexivity. Qed. + +Lemma funexp_proj {T T'} `{@Equivalence T' RT'} + (proj : T -> T') + (f : T -> T) + (f' : T' -> T') {Proper_f':Proper (RT'==>RT') f'} + (f_proj : forall a, proj (f a) === f' (proj a)) + x n + : proj (funexp f x n) === funexp f' (proj x) n. +Proof. + revert x; induction n as [|n IHn]; simpl; intros. + - reflexivity. + - rewrite f_proj. rewrite IHn. reflexivity. +Qed. + +Global Instance pair_Equivalence {A B} `{@Equivalence A RA} `{@Equivalence B RB} : @Equivalence (A*B) (fun x y => fst x = fst y /\ snd x === snd y). +Proof. + constructor; repeat intro; intuition; try congruence. + match goal with [H : _ |- _ ] => solve [rewrite H; auto] end. +Qed. + +Global Instance Proper_test_and_op {T scalar} `{Requiv:@Equivalence T RT} + {op:T->T->T} {Proper_op:Proper (RT==>RT==>RT) op} + {testbit:scalar->nat->bool} {s:scalar} {zero:T} : + let R := fun x y => fst x = fst y /\ snd x === snd y in + Proper (R==>R) (test_and_op op testbit s zero). +Proof. + unfold test_and_op; simpl; repeat intro; intuition; + repeat match goal with + | [ |- context[match ?n with _ => _ end] ] => destruct n eqn:?; simpl in *; subst; try discriminate; auto + | [ H: _ |- _ ] => setoid_rewrite H; reflexivity + end. +Qed. + +Lemma iter_op_proj {T T' S} `{T'Equiv:@Equivalence T' RT'} + (proj : T -> T') (op : T -> T -> T) (op' : T' -> T' -> T') {Proper_op':Proper (RT' ==> RT' ==> RT') op'} x y z + (testbit : S -> nat -> bool) (bound : nat) + (op_proj : forall a b, proj (op a b) === op' (proj a) (proj b)) + : proj (iter_op op x testbit y z bound) === iter_op op' (proj x) testbit y (proj z) bound. +Proof. + unfold iter_op. + lazymatch goal with + | [ |- ?proj (snd (funexp ?f ?x ?n)) === snd (funexp ?f' _ ?n) ] + => pose proof (fun pf x0 x1 => @funexp_proj _ _ _ _ (fun x => (fst x, proj (snd x))) f f' (Proper_test_and_op (Requiv:=T'Equiv)) pf (x0, x1)) as H'; + lazymatch type of H' with + | ?H'' -> _ => assert (H'') as pf; [clear H'|edestruct (H' pf); simpl in *; solve [eauto]] + end + end. + + intros [??]; simpl. + repeat match goal with + | [ |- context[match ?n with _ => _ end] ] => destruct n eqn:? + | _ => progress (unfold equiv; simpl) + | _ => progress (subst; intuition) + | _ => reflexivity + | _ => rewrite op_proj + end. +Qed. + +Global Instance option_rect_Proper_nd {A T} + : Proper ((pointwise_relation _ eq) ==> eq ==> eq ==> eq) (@option_rect A (fun _ => T)). +Proof. + intros ?? H ??? [|]??; subst; simpl; congruence. +Qed. + +Global Instance option_rect_Proper_nd' {A T} + : Proper ((pointwise_relation _ eq) ==> eq ==> forall_relation (fun _ => eq)) (@option_rect A (fun _ => T)). +Proof. + intros ?? H ??? [|]; subst; simpl; congruence. +Qed. + +Hint Extern 1 (Proper _ (@option_rect ?A (fun _ => ?T))) => exact (@option_rect_Proper_nd' A T) : typeclass_instances. + +Lemma option_rect_option_map : forall {A B C} (f:A->B) some none v, + option_rect (fun _ => C) (fun x => some (f x)) none v = option_rect (fun _ => C) some none (option_map f v). +Proof. + destruct v; reflexivity. +Qed. + +Lemma option_rect_function {A B C S' N' v} f + : f (option_rect (fun _ : option A => option B) S' N' v) + = option_rect (fun _ : option A => C) (fun x => f (S' x)) (f N') v. +Proof. destruct v; reflexivity. Qed. +Local Ltac commute_option_rect_Let_In := (* pull let binders out side of option_rect pattern matching *) + idtac; + lazymatch goal with + | [ |- ?LHS = option_rect ?P ?S ?N (Let_In ?x ?f) ] + => (* we want to just do a [change] here, but unification is stupid, so we have to tell it what to unfold in what order *) + cut (LHS = Let_In x (fun y => option_rect P S N (f y))); cbv beta; + [ set_evars; + let H := fresh in + intro H; + rewrite H; + clear; + abstract (cbv [Let_In]; reflexivity) + | ] + end. + +(** TODO: possibly move me, remove local *) +Local Ltac replace_option_match_with_option_rect := + idtac; + lazymatch goal with + | [ |- _ = ?RHS :> ?T ] + => lazymatch RHS with + | match ?a with None => ?N | Some x => @?S x end + => replace RHS with (option_rect (fun _ => T) S N a) by (destruct a; reflexivity) + end + end. +Local Ltac simpl_option_rect := (* deal with [option_rect _ _ _ None] and [option_rect _ _ _ (Some _)] *) + repeat match goal with + | [ |- context[option_rect ?P ?S ?N None] ] + => change (option_rect P S N None) with N + | [ |- context[option_rect ?P ?S ?N (Some ?x) ] ] + => change (option_rect P S N (Some x)) with (S x); cbv beta + end. + +Definition COMPILETIME {T} (x:T) : T := x. + +Lemma N_to_nat_le_mono : forall a b, (a <= b)%N -> (N.to_nat a <= N.to_nat b)%nat. +Proof. + intros. + pose proof (Nomega.Nlt_out a (N.succ b)). + rewrite N2Nat.inj_succ, N.lt_succ_r, <-NPeano.Nat.lt_succ_r in *; auto. +Qed. +Lemma N_size_nat_le_mono : forall a b, (a <= b)%N -> (N.size_nat a <= N.size_nat b)%nat. +Proof. + intros. + destruct (N.eq_dec a 0), (N.eq_dec b 0); try abstract (subst;rewrite ?N.le_0_r in *;subst;simpl;omega). + rewrite !Nsize_nat_equiv, !N.size_log2 by assumption. + edestruct N.succ_le_mono; eauto using N_to_nat_le_mono, N.log2_le_mono. +Qed. + +Lemma Z_to_N_Z_of_nat : forall n, Z.to_N (Z.of_nat n) = N.of_nat n. +Proof. induction n; auto. Qed. + +Lemma Z_of_nat_nonzero : forall m, m <> 0 -> (0 < Z.of_nat m)%Z. +Proof. intros. destruct m; [congruence|reflexivity]. Qed. + +Local Infix "mod" := NPeano.modulo : nat_scope. +Lemma N_of_nat_modulo : forall n m, m <> 0 -> N.of_nat (n mod m)%nat = (N.of_nat n mod N.of_nat m)%N. +Proof. + intros. + apply Znat.N2Z.inj_iff. + rewrite !Znat.nat_N_Z. + rewrite Zdiv.mod_Zmod by auto. + apply Znat.Z2N.inj_iff. + { apply Z.mod_pos_bound. apply Z_of_nat_nonzero. assumption. } + { apply Znat.N2Z.is_nonneg. } + rewrite Znat.Z2N.inj_mod by (auto using Znat.Nat2Z.is_nonneg, Z_of_nat_nonzero). + rewrite !Z_to_N_Z_of_nat, !Znat.N2Z.id; reflexivity. +Qed. + +Lemma encoding_canonical' {T} {B} {encoding:canonical encoding of T as B} : + forall a b, enc a = enc b -> a = b. +Proof. + intros. + pose proof (f_equal dec H). + pose proof encoding_valid. + pose proof encoding_canonical. + congruence. +Qed. + +Lemma compare_encodings {T} {B} {encoding:canonical encoding of T as B} + (B_eqb:B->B->bool) (B_eqb_iff : forall a b:B, (B_eqb a b = true) <-> a = b) + : forall a b : T, (a = b) <-> (B_eqb (enc a) (enc b) = true). +Proof. + intros. + split; intro H. + { rewrite B_eqb_iff; congruence. } + { apply B_eqb_iff in H; eauto using encoding_canonical'. } +Qed. + +Lemma eqb_eq_dec' {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : + forall a b, if eqb a b then a = b else a <> b. +Proof. + intros. + case_eq (eqb a b); intros. + { eapply eqb_iff; trivial. } + { specialize (eqb_iff a b). rewrite H in eqb_iff. intuition. } +Qed. + +Definition eqb_eq_dec {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : + forall a b : T, {a=b}+{a<>b}. +Proof. + intros. + pose proof (eqb_eq_dec' eqb eqb_iff a b). + destruct (eqb a b); eauto. +Qed. + +Definition eqb_eq_dec_and_output {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : + forall a b : T, {a = b /\ eqb a b = true}+{a<>b /\ eqb a b = false}. +Proof. + intros. + pose proof (eqb_eq_dec' eqb eqb_iff a b). + destruct (eqb a b); eauto. +Qed. + +Lemma eqb_compare_encodings {T} {B} {encoding:canonical encoding of T as B} + (T_eqb:T->T->bool) (T_eqb_iff : forall a b:T, (T_eqb a b = true) <-> a = b) + (B_eqb:B->B->bool) (B_eqb_iff : forall a b:B, (B_eqb a b = true) <-> a = b) + : forall a b : T, T_eqb a b = B_eqb (enc a) (enc b). +Proof. + intros; + destruct (eqb_eq_dec_and_output T_eqb T_eqb_iff a b); + destruct (eqb_eq_dec_and_output B_eqb B_eqb_iff (enc a) (enc b)); + intuition; + try find_copy_apply_lem_hyp B_eqb_iff; + try find_copy_apply_lem_hyp T_eqb_iff; + try congruence. + apply (compare_encodings B_eqb B_eqb_iff) in H2; congruence. +Qed. + +Lemma decode_failed_neq_encoding {T B} (encoding_T_B:canonical encoding of T as B) (X:B) + (dec_failed:dec X = None) (a:T) : X <> enc a. +Proof. pose proof encoding_valid. congruence. Qed. +Lemma compare_without_decoding {T B} (encoding_T_B:canonical encoding of T as B) + (T_eqb:T->T->bool) (T_eqb_iff:forall a b, T_eqb a b = true <-> a = b) + (B_eqb:B->B->bool) (B_eqb_iff:forall a b, B_eqb a b = true <-> a = b) + (P_:B) (Q:T) : + option_rect (fun _ : option T => bool) + (fun P : T => T_eqb P Q) + false + (dec P_) + = B_eqb P_ (enc Q). +Proof. + destruct (dec P_) eqn:Hdec; simpl option_rect. + { apply encoding_canonical in Hdec; subst; auto using eqb_compare_encodings. } + { pose proof encoding_canonical. + pose proof encoding_valid. + pose proof eqb_compare_encodings. + eapply decode_failed_neq_encoding in Hdec. + destruct (B_eqb P_ (enc Q)) eqn:Heq; [rewrite B_eqb_iff in Heq; eauto | trivial]. } +Qed. + +Lemma unfoldDiv : forall {m} (x y:F m), (x/y = x * inv y)%F. Proof. unfold div. congruence. Qed. + +Definition FieldToN {m} (x:F m) := Z.to_N (FieldToZ x). +Lemma FieldToN_correct {m} (x:F m) : FieldToN (m:=m) x = Z.to_N (FieldToZ x). reflexivity. Qed. + +Definition natToField {m} x : F m := ZToField (Z.of_nat x). +Definition FieldToNat {m} (x:F m) : nat := Z.to_nat (FieldToZ x). +Lemma FieldToNat_natToField {m} : m <> 0 -> forall x, x mod m = FieldToNat (natToField (m:=Z.of_nat m) x). + unfold natToField, FieldToNat; intros. + rewrite (FieldToZ_ZToField), <-mod_Zmod, Nat2Z.id; trivial. +Qed. + +Lemma F_eqb_iff {q} : forall x y : F q, F_eqb x y = true <-> x = y. +Proof. + split; eauto using F_eqb_eq, F_eqb_complete. +Qed. \ No newline at end of file diff --git a/src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v b/src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v deleted file mode 100644 index 146059ca4..000000000 --- a/src/Experiments/DerivationsOptionRectLetInFqPowEncoding.v +++ /dev/null @@ -1,376 +0,0 @@ -Require Import Bedrock.Word. -Require Import Crypto.Spec.EdDSA. -Require Import Crypto.Tactics.VerdiTactics. -Require Import BinNat BinInt NArith Crypto.Spec.ModularArithmetic. -Require Import ModularArithmetic.ModularArithmeticTheorems. -Require Import ModularArithmetic.PrimeFieldTheorems. -Require Import Crypto.Spec.CompleteEdwardsCurve. -Require Import Crypto.Spec.Encoding Crypto.Spec.ModularWordEncoding. -Require Import Crypto.CompleteEdwardsCurve.ExtendedCoordinates. -Require Import Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. -Require Import Crypto.Util.IterAssocOp Crypto.Util.WordUtil Crypto.Rep. -Require Import Coq.Setoids.Setoid Coq.Classes.Morphisms Coq.Classes.Equivalence. -Require Import Zdiv. -Require Import Crypto.Util.Tuple. -Local Open Scope equiv_scope. - -Generalizable All Variables. - - -Local Ltac set_evars := - repeat match goal with - | [ |- appcontext[?E] ] => is_evar E; let e := fresh "e" in set (e := E) - end. - -Local Ltac subst_evars := - repeat match goal with - | [ e := ?E |- _ ] => is_evar E; subst e - end. - -Definition path_sig {A P} {RA:relation A} {Rsig:relation (@sig A P)} - {HP:Proper (RA==>Basics.impl) P} - (H:forall (x y:A) (px:P x) (py:P y), RA x y -> Rsig (exist _ x px) (exist _ y py)) - (x : @sig A P) (y0:A) (pf : RA (proj1_sig x) y0) -: Rsig x (exist _ y0 (HP _ _ pf (proj2_sig x))). -Proof. destruct x. eapply H. assumption. Defined. - -Definition Let_In {A P} (x : A) (f : forall a : A, P a) : P x := let y := x in f y. -Global Instance Let_In_Proper_changebody {A P R} {Reflexive_R:@Reflexive P R} - : Proper (eq ==> pointwise_relation _ R ==> R) (@Let_In A (fun _ => P)). -Proof. - lazy; intros; try congruence. - subst; auto. -Qed. - -Lemma Let_In_Proper_changevalue {A B} RA {RB} (f:A->B) {Proper_f:Proper (RA==>RB) f} - : Proper (RA ==> RB) (fun x => Let_In x f). -Proof. intuition. Qed. - -Ltac fold_identity_lambdas := - repeat match goal with - | [ H: appcontext [fun x => ?f x] |- _ ] => change (fun x => f x) with f in * - | |- appcontext [fun x => ?f x] => change (fun x => f x) with f in * - end. - -Local Ltac replace_let_in_with_Let_In := - match goal with - | [ |- context G[let x := ?y in @?z x] ] - => let G' := context G[Let_In y z] in change G' - end. - -Local Ltac Let_In_app fn := - match goal with - | [ |- appcontext G[Let_In (fn ?x) ?f] ] - => change (Let_In (fn x) f) with (Let_In x (fun y => f (fn y))); cbv beta - end. - -Lemma if_map : forall {T U} (f:T->U) (b:bool) (x y:T), (if b then f x else f y) = f (if b then x else y). -Proof. - destruct b; trivial. -Qed. - -Lemma pull_Let_In {B C} (f : B -> C) A (v : A) (b : A -> B) - : Let_In v (fun v' => f (b v')) = f (Let_In v b). -Proof. - reflexivity. -Qed. - -Lemma Let_app_In {A B T} (g:A->B) (f:B->T) (x:A) : - @Let_In _ (fun _ => T) (g x) f = - @Let_In _ (fun _ => T) x (fun p => f (g x)). -Proof. reflexivity. Qed. - -Lemma Let_app_In' : forall {A B T} {R} {R_equiv:@Equivalence T R} - (g : A -> B) (f : B -> T) (x : A) - f' (f'_ok: forall z, f' z === f (g z)), - Let_In (g x) f === Let_In x f'. -Proof. intros; cbv [Let_In]; rewrite f'_ok; reflexivity. Qed. -Definition unfold_Let_In {A B} x (f:A->B) : Let_In x f = let y := x in f y := eq_refl. - -Lemma Let_app2_In {A B C D T} (g1:A->C) (g2:B->D) (f:C*D->T) (x:A) (y:B) : - @Let_In _ (fun _ => T) (g1 x, g2 y) f = - @Let_In _ (fun _ => T) (x, y) (fun p => f ((g1 (fst p), g2 (snd p)))). -Proof. reflexivity. Qed. - -Lemma funexp_proj {T T'} `{@Equivalence T' RT'} - (proj : T -> T') - (f : T -> T) - (f' : T' -> T') {Proper_f':Proper (RT'==>RT') f'} - (f_proj : forall a, proj (f a) === f' (proj a)) - x n - : proj (funexp f x n) === funexp f' (proj x) n. -Proof. - revert x; induction n as [|n IHn]; simpl; intros. - - reflexivity. - - rewrite f_proj. rewrite IHn. reflexivity. -Qed. - -Global Instance pair_Equivalence {A B} `{@Equivalence A RA} `{@Equivalence B RB} : @Equivalence (A*B) (fun x y => fst x = fst y /\ snd x === snd y). -Proof. - constructor; repeat intro; intuition; try congruence. - match goal with [H : _ |- _ ] => solve [rewrite H; auto] end. -Qed. - -Global Instance Proper_test_and_op {T scalar} `{Requiv:@Equivalence T RT} - {op:T->T->T} {Proper_op:Proper (RT==>RT==>RT) op} - {testbit:scalar->nat->bool} {s:scalar} {zero:T} : - let R := fun x y => fst x = fst y /\ snd x === snd y in - Proper (R==>R) (test_and_op op testbit s zero). -Proof. - unfold test_and_op; simpl; repeat intro; intuition; - repeat match goal with - | [ |- context[match ?n with _ => _ end] ] => destruct n eqn:?; simpl in *; subst; try discriminate; auto - | [ H: _ |- _ ] => setoid_rewrite H; reflexivity - end. -Qed. - -Lemma iter_op_proj {T T' S} `{T'Equiv:@Equivalence T' RT'} - (proj : T -> T') (op : T -> T -> T) (op' : T' -> T' -> T') {Proper_op':Proper (RT' ==> RT' ==> RT') op'} x y z - (testbit : S -> nat -> bool) (bound : nat) - (op_proj : forall a b, proj (op a b) === op' (proj a) (proj b)) - : proj (iter_op op x testbit y z bound) === iter_op op' (proj x) testbit y (proj z) bound. -Proof. - unfold iter_op. - lazymatch goal with - | [ |- ?proj (snd (funexp ?f ?x ?n)) === snd (funexp ?f' _ ?n) ] - => pose proof (fun pf x0 x1 => @funexp_proj _ _ _ _ (fun x => (fst x, proj (snd x))) f f' (Proper_test_and_op (Requiv:=T'Equiv)) pf (x0, x1)) as H'; - lazymatch type of H' with - | ?H'' -> _ => assert (H'') as pf; [clear H'|edestruct (H' pf); simpl in *; solve [eauto]] - end - end. - - intros [??]; simpl. - repeat match goal with - | [ |- context[match ?n with _ => _ end] ] => destruct n eqn:? - | _ => progress (unfold equiv; simpl) - | _ => progress (subst; intuition) - | _ => reflexivity - | _ => rewrite op_proj - end. -Qed. - -Global Instance option_rect_Proper_nd {A T} - : Proper ((pointwise_relation _ eq) ==> eq ==> eq ==> eq) (@option_rect A (fun _ => T)). -Proof. - intros ?? H ??? [|]??; subst; simpl; congruence. -Qed. - -Global Instance option_rect_Proper_nd' {A T} - : Proper ((pointwise_relation _ eq) ==> eq ==> forall_relation (fun _ => eq)) (@option_rect A (fun _ => T)). -Proof. - intros ?? H ??? [|]; subst; simpl; congruence. -Qed. - -Hint Extern 1 (Proper _ (@option_rect ?A (fun _ => ?T))) => exact (@option_rect_Proper_nd' A T) : typeclass_instances. - -Lemma option_rect_option_map : forall {A B C} (f:A->B) some none v, - option_rect (fun _ => C) (fun x => some (f x)) none v = option_rect (fun _ => C) some none (option_map f v). -Proof. - destruct v; reflexivity. -Qed. - -Lemma option_rect_function {A B C S' N' v} f - : f (option_rect (fun _ : option A => option B) S' N' v) - = option_rect (fun _ : option A => C) (fun x => f (S' x)) (f N') v. -Proof. destruct v; reflexivity. Qed. -Local Ltac commute_option_rect_Let_In := (* pull let binders out side of option_rect pattern matching *) - idtac; - lazymatch goal with - | [ |- ?LHS = option_rect ?P ?S ?N (Let_In ?x ?f) ] - => (* we want to just do a [change] here, but unification is stupid, so we have to tell it what to unfold in what order *) - cut (LHS = Let_In x (fun y => option_rect P S N (f y))); cbv beta; - [ set_evars; - let H := fresh in - intro H; - rewrite H; - clear; - abstract (cbv [Let_In]; reflexivity) - | ] - end. - -(** TODO: possibly move me, remove local *) -Local Ltac replace_option_match_with_option_rect := - idtac; - lazymatch goal with - | [ |- _ = ?RHS :> ?T ] - => lazymatch RHS with - | match ?a with None => ?N | Some x => @?S x end - => replace RHS with (option_rect (fun _ => T) S N a) by (destruct a; reflexivity) - end - end. -Local Ltac simpl_option_rect := (* deal with [option_rect _ _ _ None] and [option_rect _ _ _ (Some _)] *) - repeat match goal with - | [ |- context[option_rect ?P ?S ?N None] ] - => change (option_rect P S N None) with N - | [ |- context[option_rect ?P ?S ?N (Some ?x) ] ] - => change (option_rect P S N (Some x)) with (S x); cbv beta - end. - -Definition COMPILETIME {T} (x:T) : T := x. - -Lemma N_to_nat_le_mono : forall a b, (a <= b)%N -> (N.to_nat a <= N.to_nat b)%nat. -Proof. - intros. - pose proof (Nomega.Nlt_out a (N.succ b)). - rewrite N2Nat.inj_succ, N.lt_succ_r, <-NPeano.Nat.lt_succ_r in *; auto. -Qed. -Lemma N_size_nat_le_mono : forall a b, (a <= b)%N -> (N.size_nat a <= N.size_nat b)%nat. -Proof. - intros. - destruct (N.eq_dec a 0), (N.eq_dec b 0); try abstract (subst;rewrite ?N.le_0_r in *;subst;simpl;omega). - rewrite !Nsize_nat_equiv, !N.size_log2 by assumption. - edestruct N.succ_le_mono; eauto using N_to_nat_le_mono, N.log2_le_mono. -Qed. - -Lemma Z_to_N_Z_of_nat : forall n, Z.to_N (Z.of_nat n) = N.of_nat n. -Proof. induction n; auto. Qed. - -Lemma Z_of_nat_nonzero : forall m, m <> 0 -> (0 < Z.of_nat m)%Z. -Proof. intros. destruct m; [congruence|reflexivity]. Qed. - -Local Infix "mod" := NPeano.modulo : nat_scope. -Lemma N_of_nat_modulo : forall n m, m <> 0 -> N.of_nat (n mod m)%nat = (N.of_nat n mod N.of_nat m)%N. -Proof. - intros. - apply Znat.N2Z.inj_iff. - rewrite !Znat.nat_N_Z. - rewrite Zdiv.mod_Zmod by auto. - apply Znat.Z2N.inj_iff. - { apply Z.mod_pos_bound. apply Z_of_nat_nonzero. assumption. } - { apply Znat.N2Z.is_nonneg. } - rewrite Znat.Z2N.inj_mod by (auto using Znat.Nat2Z.is_nonneg, Z_of_nat_nonzero). - rewrite !Z_to_N_Z_of_nat, !Znat.N2Z.id; reflexivity. -Qed. - -Lemma encoding_canonical' {T} {B} {encoding:canonical encoding of T as B} : - forall a b, enc a = enc b -> a = b. -Proof. - intros. - pose proof (f_equal dec H). - pose proof encoding_valid. - pose proof encoding_canonical. - congruence. -Qed. - -Lemma compare_encodings {T} {B} {encoding:canonical encoding of T as B} - (B_eqb:B->B->bool) (B_eqb_iff : forall a b:B, (B_eqb a b = true) <-> a = b) - : forall a b : T, (a = b) <-> (B_eqb (enc a) (enc b) = true). -Proof. - intros. - split; intro H. - { rewrite B_eqb_iff; congruence. } - { apply B_eqb_iff in H; eauto using encoding_canonical'. } -Qed. - -Lemma eqb_eq_dec' {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : - forall a b, if eqb a b then a = b else a <> b. -Proof. - intros. - case_eq (eqb a b); intros. - { eapply eqb_iff; trivial. } - { specialize (eqb_iff a b). rewrite H in eqb_iff. intuition. } -Qed. - -Definition eqb_eq_dec {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : - forall a b : T, {a=b}+{a<>b}. -Proof. - intros. - pose proof (eqb_eq_dec' eqb eqb_iff a b). - destruct (eqb a b); eauto. -Qed. - -Definition eqb_eq_dec_and_output {T} (eqb:T->T->bool) (eqb_iff:forall a b, eqb a b = true <-> a = b) : - forall a b : T, {a = b /\ eqb a b = true}+{a<>b /\ eqb a b = false}. -Proof. - intros. - pose proof (eqb_eq_dec' eqb eqb_iff a b). - destruct (eqb a b); eauto. -Qed. - -Lemma eqb_compare_encodings {T} {B} {encoding:canonical encoding of T as B} - (T_eqb:T->T->bool) (T_eqb_iff : forall a b:T, (T_eqb a b = true) <-> a = b) - (B_eqb:B->B->bool) (B_eqb_iff : forall a b:B, (B_eqb a b = true) <-> a = b) - : forall a b : T, T_eqb a b = B_eqb (enc a) (enc b). -Proof. - intros; - destruct (eqb_eq_dec_and_output T_eqb T_eqb_iff a b); - destruct (eqb_eq_dec_and_output B_eqb B_eqb_iff (enc a) (enc b)); - intuition; - try find_copy_apply_lem_hyp B_eqb_iff; - try find_copy_apply_lem_hyp T_eqb_iff; - try congruence. - apply (compare_encodings B_eqb B_eqb_iff) in H2; congruence. -Qed. - -Lemma decode_failed_neq_encoding {T B} (encoding_T_B:canonical encoding of T as B) (X:B) - (dec_failed:dec X = None) (a:T) : X <> enc a. -Proof. pose proof encoding_valid. congruence. Qed. -Lemma compare_without_decoding {T B} (encoding_T_B:canonical encoding of T as B) - (T_eqb:T->T->bool) (T_eqb_iff:forall a b, T_eqb a b = true <-> a = b) - (B_eqb:B->B->bool) (B_eqb_iff:forall a b, B_eqb a b = true <-> a = b) - (P_:B) (Q:T) : - option_rect (fun _ : option T => bool) - (fun P : T => T_eqb P Q) - false - (dec P_) - = B_eqb P_ (enc Q). -Proof. - destruct (dec P_) eqn:Hdec; simpl option_rect. - { apply encoding_canonical in Hdec; subst; auto using eqb_compare_encodings. } - { pose proof encoding_canonical. - pose proof encoding_valid. - pose proof eqb_compare_encodings. - eapply decode_failed_neq_encoding in Hdec. - destruct (B_eqb P_ (enc Q)) eqn:Heq; [rewrite B_eqb_iff in Heq; eauto | trivial]. } -Qed. - -Lemma unfoldDiv : forall {m} (x y:F m), (x/y = x * inv y)%F. Proof. unfold div. congruence. Qed. - -Definition FieldToN {m} (x:F m) := Z.to_N (FieldToZ x). -Lemma FieldToN_correct {m} (x:F m) : FieldToN (m:=m) x = Z.to_N (FieldToZ x). reflexivity. Qed. - -Definition natToField {m} x : F m := ZToField (Z.of_nat x). -Definition FieldToNat {m} (x:F m) : nat := Z.to_nat (FieldToZ x). -Lemma FieldToNat_natToField {m} : m <> 0 -> forall x, x mod m = FieldToNat (natToField (m:=Z.of_nat m) x). - unfold natToField, FieldToNat; intros. - rewrite (FieldToZ_ZToField), <-mod_Zmod, Nat2Z.id; trivial. -Qed. - -Lemma F_eqb_iff {q} : forall x y : F q, F_eqb x y = true <-> x = y. -Proof. - split; eauto using F_eqb_eq, F_eqb_complete. -Qed. - -Section FSRepOperations. - Context {q:Z} {prime_q:Znumtheory.prime q} {two_lt_q:(2 < q)%Z}. - Context {l:Z} {two_lt_l:(2 < l)%Z}. - Context `{rcS:RepConversions (F l) SRep} {rcSOK:RepConversionsOK rcS}. - Context `(rcF:RepConversions (F q) FRep) (rcFOK:RepConversionsOK rcF). - Context (FRepAdd FRepSub FRepMul:FRep->FRep->FRep) (FRepAdd_correct:RepBinOpOK rcF add FRepMul). - Context (FRepSub_correct:RepBinOpOK rcF sub FRepSub) (FRepMul_correct:RepBinOpOK rcF mul FRepMul). - Axiom SRep_testbit : SRep -> nat -> bool. - Axiom SRep_testbit_correct : forall (x0 : SRep) (i : nat), SRep_testbit x0 i = N.testbit_nat (FieldToN (unRep x0)) i. - - Definition FSRepPow width x n := iter_op FRepMul (toRep 1%F) SRep_testbit n x width. - Lemma FSRepPow_correct : forall width x n, (N.size_nat (FieldToN (unRep n)) <= width)%nat -> (unRep x ^ FieldToN (unRep n))%F = unRep (FSRepPow width x n). - Proof. (* this proof derives the required formula, which I copy-pasted above to be able to reference it without the length precondition *) - unfold FSRepPow; intros. - erewrite <-pow_nat_iter_op_correct by auto. - erewrite <-(fun x => iter_op_spec (scalar := SRep) mul F_mul_assoc _ F_mul_1_l _ _ SRep_testbit_correct n x width) by auto. - rewrite <-(rcFOK 1%F) at 1. - erewrite <-iter_op_proj; - [apply eq_refl - |eauto with typeclass_instances - |symmetry; eapply FRepMul_correct]. - Qed. - - Context (q_minus_2_lt_l:(q - 2 < l)%Z). - Definition FRepInv x : FRep := FSRepPow (COMPILETIME (N.size_nat (Z.to_N (q - 2)))) x (COMPILETIME (toRep (ZToField (q - 2)))). - Lemma FRepInv_correct : forall x, inv (unRep x)%F = unRep (FRepInv x). - unfold FRepInv, COMPILETIME; intros. - rewrite <-FSRepPow_correct; rewrite FieldToN_correct, rcSOK, FieldToZ_ZToField, Zmod_small by omega; trivial. - pose proof @Fq_inv_fermat_correct as Hf; unfold inv_fermat in Hf; rewrite Hf by - auto using prime_q, two_lt_q. - reflexivity. - Qed. -End FSRepOperations. \ No newline at end of file diff --git a/src/Rep.v b/src/Rep.v deleted file mode 100644 index b7e7f10c5..000000000 --- a/src/Rep.v +++ /dev/null @@ -1,13 +0,0 @@ -Class RepConversions (T:Type) (RT:Type) : Type := - { - toRep : T -> RT; - unRep : RT -> T - }. - -Definition RepConversionsOK {T RT} (RC:RepConversions T RT) := forall x, unRep (toRep x) = x. - -Definition RepFunOK {T RT} `(RC:RepConversions T RT) (f:T->T) (rf : RT -> RT) := - forall x, f (unRep x) = unRep (rf x). - -Definition RepBinOpOK {T RT} `(RC:RepConversions T RT) (op:T->T->T) (rop : RT -> RT -> RT) := - forall x y, op (unRep x) (unRep y) = unRep (rop x y). diff --git a/src/Specific/GF25519.v b/src/Specific/GF25519.v index ff7bff8e1..471c1d548 100644 --- a/src/Specific/GF25519.v +++ b/src/Specific/GF25519.v @@ -7,7 +7,6 @@ Require Import Coq.Lists.List Crypto.Util.ListUtil. Require Import Crypto.ModularArithmetic.PrimeFieldTheorems. Require Import Crypto.Tactics.VerdiTactics. Require Import Crypto.BaseSystem. -Require Import Crypto.Rep. Import ListNotations. Require Import Coq.ZArith.ZArith Coq.ZArith.Zpower Coq.ZArith.ZArith Coq.ZArith.Znumtheory. Local Open Scope Z. @@ -128,99 +127,4 @@ Infix "&" := Z.land (at level 50). Eval cbv beta iota delta [proj1_sig GF25519Base25Point5_freeze_formula Let_In] in fun f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 => proj1_sig ( GF25519Base25Point5_freeze_formula f0 f1 f2 f3 f4 f5 f6 f7 f8 f9). -*) - -Definition F25519Rep := (Z * Z * Z * Z * Z * Z * Z * Z * Z * Z)%type. - -Definition F25519toRep (x:F (2^255 - 19)) : F25519Rep := (0, 0, 0, 0, 0, 0, 0, 0, 0, FieldToZ x)%Z. -Definition F25519unRep (rx:F25519Rep) := - let '(x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) := rx in - ModularBaseSystem.decode [x0;x1;x2;x3;x4;x5;x6;x7;x8;x9]. - -Global Instance F25519RepConversions : RepConversions (F (2^255 - 19)) F25519Rep := - { - toRep := F25519toRep; - unRep := F25519unRep - }. - -Lemma F25519RepConversionsOK : RepConversionsOK F25519RepConversions. -Proof. - unfold F25519RepConversions, RepConversionsOK, unRep, toRep, F25519toRep, F25519unRep; intros. - change (ModularBaseSystem.decode (ModularBaseSystem.encode x) = x). - eauto using ModularBaseSystemProofs.rep_decode, ModularBaseSystemProofs.encode_rep. -Qed. - -Definition F25519Rep_mul (f g:F25519Rep) : F25519Rep. - refine ( - let '(f9, f8, f7, f6, f5, f4, f3, f2, f1, f0) := f in - let '(g9, g8, g7, g6, g5, g4, g3, g2, g1, g0) := g in _). - (* FIXME: the r should not be present in generated code *) - pose (r := proj1_sig (GF25519Base25Point5_mul_reduce_formula f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 - g0 g1 g2 g3 g4 g5 g6 g7 g8 g9)). - simpl in r. - unfold F25519Rep. - repeat let t' := (eval cbv beta delta [r] in r) in - lazymatch t' with Let_In ?arg ?f => - let x := fresh "x" in - refine (let x := arg in _); - let t'' := (eval cbv beta in (f x)) in - change (Let_In arg f) with t'' in r - end. - let t' := (eval cbv beta delta [r] in r) in - lazymatch t' with [?r0;?r1;?r2;?r3;?r4;?r5;?r6;?r7;?r8;?r9] => - clear r; - exact (r9, r8, r7, r6, r5, r4, r3, r2, r1, r0) - end. -(*Time*) Defined. - -Lemma F25519_mul_OK : RepBinOpOK F25519RepConversions ModularArithmetic.mul F25519Rep_mul. - cbv iota beta delta [RepBinOpOK F25519RepConversions F25519Rep_mul toRep unRep F25519toRep F25519unRep]. - destruct x as [[[[[[[[[x9 x8] x7] x6] x5] x4] x3] x2] x1] x0]. - destruct y as [[[[[[[[[y9 y8] y7] y6] y5] y4] y3] y2] y1] y0]. - let E := constr:(GF25519Base25Point5_mul_reduce_formula x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 y0 y1 y2 y3 y4 y5 y6 y7 y8 y9) in - transitivity (ModularBaseSystem.decode (proj1_sig E)); [|solve[simpl; apply f_equal; reflexivity]]; - destruct E as [? r]; cbv [proj1_sig]. - cbv [rep ModularBaseSystem.rep PseudoMersenneBase modulus] in r; edestruct r; eauto. -Qed. - -Definition F25519Rep_add (f g:F25519Rep) : F25519Rep. - refine ( - let '(f9, f8, f7, f6, f5, f4, f3, f2, f1, f0) := f in - let '(g9, g8, g7, g6, g5, g4, g3, g2, g1, g0) := g in _). - let t' := (eval simpl in (proj1_sig (GF25519Base25Point5_add_formula f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 - g0 g1 g2 g3 g4 g5 g6 g7 g8 g9))) in - lazymatch t' with [?r0;?r1;?r2;?r3;?r4;?r5;?r6;?r7;?r8;?r9] => - exact (r9, r8, r7, r6, r5, r4, r3, r2, r1, r0) - end. -Defined. - -Definition F25519Rep_sub (f g:F25519Rep) : F25519Rep. - refine ( - let '(f9, f8, f7, f6, f5, f4, f3, f2, f1, f0) := f in - let '(g9, g8, g7, g6, g5, g4, g3, g2, g1, g0) := g in _). - let t' := (eval simpl in (proj1_sig (GF25519Base25Point5_sub_formula f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 - g0 g1 g2 g3 g4 g5 g6 g7 g8 g9))) in - lazymatch t' with [?r0;?r1;?r2;?r3;?r4;?r5;?r6;?r7;?r8;?r9] => - exact (r9, r8, r7, r6, r5, r4, r3, r2, r1, r0) - end. -Defined. - -Lemma F25519_add_OK : RepBinOpOK F25519RepConversions ModularArithmetic.add F25519Rep_add. - cbv iota beta delta [RepBinOpOK F25519RepConversions F25519Rep_add toRep unRep F25519toRep F25519unRep]. - destruct x as [[[[[[[[[x9 x8] x7] x6] x5] x4] x3] x2] x1] x0]. - destruct y as [[[[[[[[[y9 y8] y7] y6] y5] y4] y3] y2] y1] y0]. - let E := constr:(GF25519Base25Point5_add_formula x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 y0 y1 y2 y3 y4 y5 y6 y7 y8 y9) in - transitivity (ModularBaseSystem.decode (proj1_sig E)); [|solve[simpl; apply f_equal; reflexivity]]; - destruct E as [? r]; cbv [proj1_sig]. - cbv [rep ModularBaseSystem.rep PseudoMersenneBase modulus] in r; edestruct r; eauto. -Qed. - -Lemma F25519_sub_OK : RepBinOpOK F25519RepConversions ModularArithmetic.sub F25519Rep_sub. - cbv iota beta delta [RepBinOpOK F25519RepConversions F25519Rep_sub toRep unRep F25519toRep F25519unRep]. - destruct x as [[[[[[[[[x9 x8] x7] x6] x5] x4] x3] x2] x1] x0]. - destruct y as [[[[[[[[[y9 y8] y7] y6] y5] y4] y3] y2] y1] y0]. - let E := constr:(GF25519Base25Point5_sub_formula x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 y0 y1 y2 y3 y4 y5 y6 y7 y8 y9) in - transitivity (ModularBaseSystem.decode (proj1_sig E)); [|solve[simpl; apply f_equal; reflexivity]]; - destruct E as [? r]; cbv [proj1_sig]. - cbv [rep ModularBaseSystem.rep PseudoMersenneBase modulus] in r; edestruct r; eauto. -Qed. +*) \ No newline at end of file -- cgit v1.2.3 From 8d498c587aaa23dcb50c31fa5a426873b3dd9dea Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 20 Jun 2016 04:16:04 -0400 Subject: move nsatz into tactics directory --- _CoqProject | 2 +- src/Algebra.v | 4 +- .../CompleteEdwardsCurveTheorems.v | 2 +- src/CompleteEdwardsCurve/ExtendedCoordinates.v | 4 +- src/CompleteEdwardsCurve/Pre.v | 2 +- src/Nsatz.v | 120 --------------------- src/Tactics/Nsatz.v | 120 +++++++++++++++++++++ 7 files changed, 127 insertions(+), 127 deletions(-) delete mode 100644 src/Nsatz.v create mode 100644 src/Tactics/Nsatz.v (limited to '_CoqProject') diff --git a/_CoqProject b/_CoqProject index 14179cb3d..9c4cdd3cf 100644 --- a/_CoqProject +++ b/_CoqProject @@ -5,7 +5,6 @@ Bedrock/Word.v src/Algebra.v src/BaseSystem.v src/BaseSystemProofs.v -src/Nsatz.v src/Testbit.v src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -34,6 +33,7 @@ src/Spec/ModularArithmetic.v src/Spec/ModularWordEncoding.v src/Specific/GF1305.v src/Specific/GF25519.v +src/Tactics/Nsatz.v src/Tactics/VerdiTactics.v src/Util/CaseUtil.v src/Util/IterAssocOp.v diff --git a/src/Algebra.v b/src/Algebra.v index 27c0d2e59..a319d0e80 100644 --- a/src/Algebra.v +++ b/src/Algebra.v @@ -1,5 +1,5 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Require Import Crypto.Util.Tactics Crypto.Nsatz. +Require Import Crypto.Util.Tactics Crypto.Tactics.Nsatz. Local Close Scope nat_scope. Local Close Scope type_scope. Local Close Scope core_scope. Section Algebra. @@ -591,4 +591,4 @@ Section Z. Example _example_nonzero_nsatz_contradict_Z x y : Z.mul x y = (Zpos xH) -> not (x = Z0). Proof. intros. intro. nsatz_contradict. Qed. -End Z. \ No newline at end of file +End Z. diff --git a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v index f9a866acb..89984027f 100644 --- a/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v +++ b/src/CompleteEdwardsCurve/CompleteEdwardsCurveTheorems.v @@ -1,6 +1,6 @@ Require Export Crypto.Spec.CompleteEdwardsCurve. -Require Import Crypto.Algebra Crypto.Nsatz. +Require Import Crypto.Algebra Crypto.Tactics.Nsatz. Require Import Crypto.CompleteEdwardsCurve.Pre. Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. diff --git a/src/CompleteEdwardsCurve/ExtendedCoordinates.v b/src/CompleteEdwardsCurve/ExtendedCoordinates.v index fe0e732a8..49c5d5041 100644 --- a/src/CompleteEdwardsCurve/ExtendedCoordinates.v +++ b/src/CompleteEdwardsCurve/ExtendedCoordinates.v @@ -1,6 +1,6 @@ Require Export Crypto.Spec.CompleteEdwardsCurve. -Require Import Crypto.Algebra Crypto.Nsatz. +Require Import Crypto.Algebra Crypto.Tactics.Nsatz. Require Import Crypto.CompleteEdwardsCurve.Pre Crypto.CompleteEdwardsCurve.CompleteEdwardsCurveTheorems. Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Tactics.VerdiTactics. @@ -241,4 +241,4 @@ Module Extended. end. Qed. End Homomorphism. -End Extended. \ No newline at end of file +End Extended. diff --git a/src/CompleteEdwardsCurve/Pre.v b/src/CompleteEdwardsCurve/Pre.v index 4744afe6b..397a6259c 100644 --- a/src/CompleteEdwardsCurve/Pre.v +++ b/src/CompleteEdwardsCurve/Pre.v @@ -1,5 +1,5 @@ Require Import Coq.Classes.Morphisms. Require Coq.Setoids.Setoid. -Require Import Crypto.Algebra Crypto.Nsatz. +Require Import Crypto.Algebra Crypto.Tactics.Nsatz. Generalizable All Variables. Section Pre. diff --git a/src/Nsatz.v b/src/Nsatz.v deleted file mode 100644 index 469ba4c29..000000000 --- a/src/Nsatz.v +++ /dev/null @@ -1,120 +0,0 @@ -(*** Tactics for manipulating polynomial equations *) -Require Coq.nsatz.Nsatz. -Require Import List. - -Generalizable All Variables. -Lemma cring_sub_diag_iff {R zero eq sub} `{cring:Cring.Cring (R:=R) (ring0:=zero) (ring_eq:=eq) (sub:=sub)} - : forall x y, eq (sub x y) zero <-> eq x y. -Proof. - split;intros Hx. - { eapply Nsatz.psos_r1b. eapply Hx. } - { eapply Nsatz.psos_r1. eapply Hx. } -Qed. - -Ltac get_goal := lazymatch goal with |- ?g => g end. - -Ltac nsatz_equation_implications_to_list eq zero g := - lazymatch g with - | eq ?p zero => constr:(p::nil) - | eq ?p zero -> ?g => let l := nsatz_equation_implications_to_list eq zero g in constr:(p::l) - end. - -Ltac nsatz_reify_equations eq zero := - let g := get_goal in - let lb := nsatz_equation_implications_to_list eq zero g in - lazymatch (eval red in (Ncring_tac.list_reifyl (lterm:=lb))) with - (?variables, ?le) => - lazymatch (eval compute in (List.rev le)) with - | ?reified_goal::?reified_givens => constr:(variables, reified_givens, reified_goal) - end - end. - -Ltac nsatz_get_free_variables reified_package := - lazymatch reified_package with (?fv, _, _) => fv end. - -Ltac nsatz_get_reified_givens reified_package := - lazymatch reified_package with (_, ?givens, _) => givens end. - -Ltac nsatz_get_reified_goal reified_package := - lazymatch reified_package with (_, _, ?goal) => goal end. - -Require Import Coq.setoid_ring.Ring_polynom. -Ltac nsatz_compute_to_goal sugar nparams reified_goal power reified_givens := - nsatz_compute (PEc sugar :: PEc nparams :: PEpow reified_goal power :: reified_givens). - -Ltac nsatz_compute_get_leading_coefficient := - lazymatch goal with - |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => a - end. - -Ltac nsatz_compute_get_certificate := - lazymatch goal with - |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => constr:(c,b) - end. - -Ltac nsatz_rewrite_and_revert domain := - lazymatch type of domain with - | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => - lazymatch goal with - | |- eq _ zero => idtac - | |- eq _ _ => rewrite <-(cring_sub_diag_iff (cring:=FCring)) - end; - repeat match goal with - | [H : eq _ zero |- _ ] => revert H - | [H : eq _ _ |- _ ] => rewrite <-(cring_sub_diag_iff (cring:=FCring)) in H; revert H - end - end. - -Ltac nsatz_nonzero := - try solve [apply Integral_domain.integral_domain_one_zero - |apply Integral_domain.integral_domain_minus_one_zero - |trivial]. - -Ltac nsatz_domain_sugar_power domain sugar power := - let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) - lazymatch type of domain with - | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => - nsatz_rewrite_and_revert domain; - let reified_package := nsatz_reify_equations eq zero in - let fv := nsatz_get_free_variables reified_package in - let interp := constr:(@Nsatz.PEevalR _ _ _ _ _ _ _ _ Fops fv) in - let reified_givens := nsatz_get_reified_givens reified_package in - let reified_goal := nsatz_get_reified_goal reified_package in - nsatz_compute_to_goal sugar nparams reified_goal power reified_givens; - let a := nsatz_compute_get_leading_coefficient in - let crt := nsatz_compute_get_certificate in - intros _ (* discard [nsatz_compute] output *); intros; - apply (fun Haa refl cond => @Integral_domain.Rintegral_domain_pow _ _ _ _ _ _ _ _ _ _ _ domain (interp a) _ (BinNat.N.to_nat power) Haa (@Nsatz.check_correct _ _ _ _ _ _ _ _ _ _ FCring fv reified_givens (PEmul a (PEpow reified_goal power)) crt refl cond)); - [ nsatz_nonzero; cbv iota beta delta [Nsatz.PEevalR PEeval InitialRing.gen_phiZ InitialRing.gen_phiPOS] - | solve [vm_compute; exact (eq_refl true)] (* exact_no_check (eq_refl true) *) - | solve [repeat (split; [assumption|]); exact I] ] - end. - -Ltac nsatz_guess_domain := - match goal with - | |- ?eq _ _ => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | |- not (?eq _ _) => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | [H: ?eq _ _ |- _ ] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - | [H: not (?eq _ _) |- _] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) - end. - -Ltac nsatz_sugar_power sugar power := - let domain := nsatz_guess_domain in - nsatz_domain_sugar_power domain sugar power. - -Tactic Notation "nsatz" constr(n) := - let nn := (eval compute in (BinNat.N.of_nat n)) in - nsatz_sugar_power BinInt.Z0 nn. - -Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. - -Ltac nsatz_contradict := - unfold not; - intros; - let domain := nsatz_guess_domain in - lazymatch type of domain with - | @Integral_domain.Integral_domain _ ?zero ?one _ _ _ _ ?eq ?Fops ?FRing ?FCring => - assert (eq one zero) as Hbad; - [nsatz; nsatz_nonzero - |destruct (Integral_domain.integral_domain_one_zero (Integral_domain:=domain) Hbad)] - end. \ No newline at end of file diff --git a/src/Tactics/Nsatz.v b/src/Tactics/Nsatz.v new file mode 100644 index 000000000..469ba4c29 --- /dev/null +++ b/src/Tactics/Nsatz.v @@ -0,0 +1,120 @@ +(*** Tactics for manipulating polynomial equations *) +Require Coq.nsatz.Nsatz. +Require Import List. + +Generalizable All Variables. +Lemma cring_sub_diag_iff {R zero eq sub} `{cring:Cring.Cring (R:=R) (ring0:=zero) (ring_eq:=eq) (sub:=sub)} + : forall x y, eq (sub x y) zero <-> eq x y. +Proof. + split;intros Hx. + { eapply Nsatz.psos_r1b. eapply Hx. } + { eapply Nsatz.psos_r1. eapply Hx. } +Qed. + +Ltac get_goal := lazymatch goal with |- ?g => g end. + +Ltac nsatz_equation_implications_to_list eq zero g := + lazymatch g with + | eq ?p zero => constr:(p::nil) + | eq ?p zero -> ?g => let l := nsatz_equation_implications_to_list eq zero g in constr:(p::l) + end. + +Ltac nsatz_reify_equations eq zero := + let g := get_goal in + let lb := nsatz_equation_implications_to_list eq zero g in + lazymatch (eval red in (Ncring_tac.list_reifyl (lterm:=lb))) with + (?variables, ?le) => + lazymatch (eval compute in (List.rev le)) with + | ?reified_goal::?reified_givens => constr:(variables, reified_givens, reified_goal) + end + end. + +Ltac nsatz_get_free_variables reified_package := + lazymatch reified_package with (?fv, _, _) => fv end. + +Ltac nsatz_get_reified_givens reified_package := + lazymatch reified_package with (_, ?givens, _) => givens end. + +Ltac nsatz_get_reified_goal reified_package := + lazymatch reified_package with (_, _, ?goal) => goal end. + +Require Import Coq.setoid_ring.Ring_polynom. +Ltac nsatz_compute_to_goal sugar nparams reified_goal power reified_givens := + nsatz_compute (PEc sugar :: PEc nparams :: PEpow reified_goal power :: reified_givens). + +Ltac nsatz_compute_get_leading_coefficient := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => a + end. + +Ltac nsatz_compute_get_certificate := + lazymatch goal with + |- Logic.eq ((?a :: _ :: ?b) :: ?c) _ -> _ => constr:(c,b) + end. + +Ltac nsatz_rewrite_and_revert domain := + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + lazymatch goal with + | |- eq _ zero => idtac + | |- eq _ _ => rewrite <-(cring_sub_diag_iff (cring:=FCring)) + end; + repeat match goal with + | [H : eq _ zero |- _ ] => revert H + | [H : eq _ _ |- _ ] => rewrite <-(cring_sub_diag_iff (cring:=FCring)) in H; revert H + end + end. + +Ltac nsatz_nonzero := + try solve [apply Integral_domain.integral_domain_one_zero + |apply Integral_domain.integral_domain_minus_one_zero + |trivial]. + +Ltac nsatz_domain_sugar_power domain sugar power := + let nparams := constr:(BinInt.Zneg BinPos.xH) in (* some symbols can be "parameters", treated as coefficients *) + lazymatch type of domain with + | @Integral_domain.Integral_domain ?F ?zero _ _ _ _ _ ?eq ?Fops ?FRing ?FCring => + nsatz_rewrite_and_revert domain; + let reified_package := nsatz_reify_equations eq zero in + let fv := nsatz_get_free_variables reified_package in + let interp := constr:(@Nsatz.PEevalR _ _ _ _ _ _ _ _ Fops fv) in + let reified_givens := nsatz_get_reified_givens reified_package in + let reified_goal := nsatz_get_reified_goal reified_package in + nsatz_compute_to_goal sugar nparams reified_goal power reified_givens; + let a := nsatz_compute_get_leading_coefficient in + let crt := nsatz_compute_get_certificate in + intros _ (* discard [nsatz_compute] output *); intros; + apply (fun Haa refl cond => @Integral_domain.Rintegral_domain_pow _ _ _ _ _ _ _ _ _ _ _ domain (interp a) _ (BinNat.N.to_nat power) Haa (@Nsatz.check_correct _ _ _ _ _ _ _ _ _ _ FCring fv reified_givens (PEmul a (PEpow reified_goal power)) crt refl cond)); + [ nsatz_nonzero; cbv iota beta delta [Nsatz.PEevalR PEeval InitialRing.gen_phiZ InitialRing.gen_phiPOS] + | solve [vm_compute; exact (eq_refl true)] (* exact_no_check (eq_refl true) *) + | solve [repeat (split; [assumption|]); exact I] ] + end. + +Ltac nsatz_guess_domain := + match goal with + | |- ?eq _ _ => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | |- not (?eq _ _) => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: ?eq _ _ |- _ ] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + | [H: not (?eq _ _) |- _] => constr:(_:Integral_domain.Integral_domain (ring_eq:=eq)) + end. + +Ltac nsatz_sugar_power sugar power := + let domain := nsatz_guess_domain in + nsatz_domain_sugar_power domain sugar power. + +Tactic Notation "nsatz" constr(n) := + let nn := (eval compute in (BinNat.N.of_nat n)) in + nsatz_sugar_power BinInt.Z0 nn. + +Tactic Notation "nsatz" := nsatz 1%nat || nsatz 2%nat || nsatz 3%nat || nsatz 4%nat || nsatz 5%nat. + +Ltac nsatz_contradict := + unfold not; + intros; + let domain := nsatz_guess_domain in + lazymatch type of domain with + | @Integral_domain.Integral_domain _ ?zero ?one _ _ _ _ ?eq ?Fops ?FRing ?FCring => + assert (eq one zero) as Hbad; + [nsatz; nsatz_nonzero + |destruct (Integral_domain.integral_domain_one_zero (Integral_domain:=domain) Hbad)] + end. \ No newline at end of file -- cgit v1.2.3