diff options
Diffstat (limited to 'src/ModularArithmetic/ModularArithmeticTheorems.v')
-rw-r--r-- | src/ModularArithmetic/ModularArithmeticTheorems.v | 1037 |
1 files changed, 324 insertions, 713 deletions
diff --git a/src/ModularArithmetic/ModularArithmeticTheorems.v b/src/ModularArithmetic/ModularArithmeticTheorems.v index be9307b50..e36d15c8b 100644 --- a/src/ModularArithmetic/ModularArithmeticTheorems.v +++ b/src/ModularArithmetic/ModularArithmeticTheorems.v @@ -2,54 +2,20 @@ Require Import Coq.omega.Omega. Require Import Crypto.Spec.ModularArithmetic. Require Import Crypto.ModularArithmetic.Pre. -Require Import Coq.Logic.Eqdep_dec. -Require Import Crypto.Tactics.VerdiTactics. Require Import Coq.ZArith.BinInt Coq.ZArith.Zdiv Coq.ZArith.Znumtheory Coq.NArith.NArith. (* import Zdiv before Znumtheory *) Require Import Coq.Classes.Morphisms Coq.Setoids.Setoid. -Require Export Coq.setoid_ring.Ring_theory Coq.setoid_ring.Field_theory Coq.setoid_ring.Field_tac. -Require Export Crypto.Util.IterAssocOp. +Require Export Coq.setoid_ring.Ring_theory Coq.setoid_ring.Ring_tac. +Require Import Crypto.Algebra Crypto.Util.Decidable. Require Export Crypto.Util.FixCoqMistakes. -Section ModularArithmeticPreliminaries. - Context {m:Z}. - Let ZToFm := ZToField : BinNums.Z -> F m. Hint Unfold ZToFm. Local Coercion ZToFm : Z >-> F. - - Theorem F_eq: forall (x y : F m), x = y <-> FieldToZ x = FieldToZ y. - Proof. - destruct x, y; intuition; simpl in *; try congruence. - subst_max. - f_equal. - eapply UIP_dec, Z.eq_dec. - Qed. - - Lemma F_pow_spec : forall (a:F m), - pow a 0%N = 1%F /\ forall x, pow a (1 + x)%N = mul a (pow a x). - Proof. - intros a. - pose (@pow_with_spec m) as H. - change (@pow m) with (proj1_sig H). - destruct H; eauto. - Qed. -End ModularArithmeticPreliminaries. - (* Fails iff the input term does some arithmetic with mod'd values. *) Ltac notFancy E := -match E with -| - (_ mod _) => idtac -| context[_ mod _] => fail 1 -| _ => idtac -end. - -Lemma Zplus_neg : forall n m, n + -m = n - m. -Proof. - auto. -Qed. - -Lemma Zmod_eq : forall a b n, a = b -> a mod n = b mod n. -Proof. - intros; rewrite H; trivial. -Qed. + match E with + | - (_ mod _) => idtac + | context[_ mod _] => fail 1 + | _ => idtac + end. (* Remove redundant [mod] operations from the conclusion. *) Ltac demod := @@ -68,680 +34,325 @@ Ltac demod := notFancy y; rewrite (Zmult_mod_idemp_r y) | [ |- context[(?x mod _) mod _] ] => notFancy x; rewrite (Zmod_mod x) - | _ => rewrite Zplus_neg in * || rewrite Z.sub_diag in * end. -(* Remove exists under equals: we do this a lot *) -Ltac eq_remove_proofs := lazymatch goal with -| [ |- @eq (F _) ?a ?b ] => - assert (Q := F_eq a b); - simpl in *; apply Q; clear Q -end. - -(** TODO FIXME(from jgross): This tactic is way too powerful for - arcane reasons. It should not be using so many databases with - [intuition]. *) -Ltac Fdefn := +Ltac unwrap_F := intros; repeat match goal with [ x : F _ |- _ ] => destruct x end; - try eq_remove_proofs; - demod; - rewrite ?Z.mul_1_l; - intuition auto with zarith lia relations typeclass_instances; demod; try solve [ f_equal; intuition auto with zarith lia relations typeclass_instances ]. - -Local Open Scope F_scope. - -Section FEquality. - Context {m:Z}. - - (** Equality **) - Definition F_eqb (x y : F m) : bool := Z.eqb x y. - - Lemma F_eqb_eq x y : F_eqb x y = true -> x = y. - Proof. - unfold F_eqb; Fdefn; apply Z.eqb_eq; trivial. - Qed. - - Lemma F_eqb_complete : forall x y: F m, x = y -> F_eqb x y = true. - Proof. - intros; subst; apply Z.eqb_refl. - Qed. - - Lemma F_eqb_refl : forall x, F_eqb x x = true. - Proof. - intros; apply F_eqb_complete; trivial. - Qed. - - Lemma F_eqb_neq x y : F_eqb x y = false -> x <> y. - Proof. - intuition; subst y. - pose proof (F_eqb_refl x). - congruence. - Qed. - - Lemma F_eqb_neq_complete x y : x <> y -> F_eqb x y = false. - Proof. - intros. - case_eq (F_eqb x y); intros; trivial. - pose proof (F_eqb_eq x y); intuition. - Qed. - - Lemma F_eq_dec : forall x y : F m, {x = y} + {x <> y}. - Proof. - intros; case_eq (F_eqb x y); [left|right]; auto using F_eqb_eq, F_eqb_neq. - Qed. - - Lemma if_F_eq_dec_if_F_eqb : forall {T} x y (a b:T), (if F_eq_dec x y then a else b) = (if F_eqb x y then a else b). - Proof. - intros; intuition; break_if. - - rewrite F_eqb_complete; trivial. - - rewrite F_eqb_neq_complete; trivial. - Defined. -End FEquality. - -Section FandZ. - Context {m:Z}. - - Lemma ZToField_small_nonzero : forall z, (0 < z < m)%Z -> ZToField z <> (0:F m). - Proof. - intuition; find_inversion; rewrite ?Z.mod_0_l, ?Z.mod_small in *; intuition auto with zarith. - Qed. - - Require Crypto.Algebra. - Global Instance commutative_ring_modulo : @Algebra.commutative_ring (F m) Logic.eq (ZToField 0) (ZToField 1) opp add sub mul. - Proof. - repeat split; Fdefn; try apply F_eq_dec. - { rewrite Z.add_0_r. auto. } - { rewrite Z.mul_1_r. auto. } - Qed. - - Lemma F_opp_spec : forall (a:F m), add a (opp a) = 0. - Fdefn. - Qed. - - Lemma ZToField_0 : @ZToField m 0 = 0. - Proof. - Fdefn. - Qed. - - Lemma FieldToZ_ZToField : forall z, FieldToZ (@ZToField m z) = z mod m. - Proof. - Fdefn. - Qed. - - Lemma mod_FieldToZ : forall x, (@FieldToZ m x) mod m = FieldToZ x. - Proof. - Fdefn. - Qed. - - (** ZToField distributes over operations **) - Lemma ZToField_add : forall (x y : Z), - @ZToField m (x + y) = ZToField x + ZToField y. - Proof. - Fdefn. - Qed. - - Lemma FieldToZ_add : forall x y : F m, - FieldToZ (x + y) = ((FieldToZ x + FieldToZ y) mod m)%Z. - Proof. - Fdefn. - Qed. - - Lemma FieldToZ_mul : forall x y : F m, - FieldToZ (x * y) = ((FieldToZ x * FieldToZ y) mod m)%Z. - Proof. - Fdefn. - Qed. - - Lemma FieldToZ_pow_Zpow_mod : forall (x : F m) n, - (FieldToZ x ^ Z.of_N n mod m = FieldToZ (x ^ n)%F)%Z. - Proof. - intros. - induction n using N.peano_ind; - destruct (F_pow_spec x) as [pow_0 pow_succ] . { - rewrite pow_0. - rewrite Z.pow_0_r; auto. - } { - rewrite N2Z.inj_succ. - rewrite Z.pow_succ_r by apply N2Z.is_nonneg. - rewrite <- N.add_1_l. - rewrite pow_succ. - rewrite <- Zmult_mod_idemp_r. - rewrite IHn. - apply FieldToZ_mul. - } - Qed. - - Lemma FieldToZ_pow_efficient : forall (x : F m) n, FieldToZ (x^n) = powmod m (FieldToZ x) n. - Proof. - intros. - rewrite powmod_Zpow_mod. - rewrite <-FieldToZ_pow_Zpow_mod. - reflexivity. - Qed. - - Lemma pow_nat_iter_op_correct: forall (x:F m) n, (@nat_iter_op _ mul 1) (N.to_nat n) x = x^n. - Proof. - induction n using N.peano_ind; - destruct (F_pow_spec x) as [pow_0 pow_succ]; - rewrite ?N2Nat.inj_succ, ?pow_0, <-?N.add_1_l, ?pow_succ; - simpl; congruence. - Qed. - - Lemma mod_plus_zero_subproof a b : 0 mod m = (a + b) mod m -> - b mod m = (- a) mod m. - Proof. - rewrite <-Z.sub_0_l; intros. - replace (0-a)%Z with (b-(a + b))%Z by omega. - rewrite Zminus_mod. - rewrite <- H. - rewrite Zmod_0_l. - replace (b mod m - 0)%Z with (b mod m) by omega. - rewrite Zmod_mod. - reflexivity. - Qed. - - Lemma FieldToZ_opp' : forall x, FieldToZ (@opp m x) mod m = -x mod m. - Proof. - intros. - pose proof (FieldToZ_add x (opp x)) as H. - rewrite F_opp_spec, FieldToZ_ZToField in H. - auto using mod_plus_zero_subproof. - Qed. - - Lemma FieldToZ_opp : forall x, FieldToZ (@opp m x) = -x mod m. - Proof. - intros. - pose proof (FieldToZ_opp' x) as H; rewrite mod_FieldToZ in H; trivial. - Qed. - - Lemma sub_intersperse_modulus : forall x y, ((x - y) mod m = (x + (m - y)) mod m)%Z. - Proof. - intros. - replace (x + (m - y))%Z with (m+(x-y))%Z by omega. - rewrite Zplus_mod. - rewrite Z_mod_same_full; simpl Z.add. - rewrite Zmod_mod. - reflexivity. - Qed. - - (* Compatibility between inject and subtraction *) - Lemma ZToField_sub : forall (x y : Z), - @ZToField m (x - y) = ZToField x - ZToField y. - Proof. - Fdefn. - Qed. - - (* Compatibility between inject and multiplication *) - Lemma ZToField_mul : forall (x y : Z), - @ZToField m (x * y) = ZToField x * ZToField y. - Proof. - Fdefn. - Qed. - - (* Compatibility between inject and GFtoZ *) - Lemma ZToField_idempotent : forall (x : F m), ZToField x = x. - Proof. - Fdefn. - Qed. - Definition ZToField_FieldToZ := ZToField_idempotent. (* alias *) - - (* Compatibility between inject and mod *) - Lemma ZToField_mod : forall x, @ZToField m x = ZToField (x mod m). - Proof. - Fdefn. - Qed. - - (* Compatibility between inject and pow *) - Lemma ZToField_pow : forall x n, - @ZToField m x ^ n = ZToField (x ^ (Z.of_N n) mod m). - Proof. - intros. - induction n using N.peano_ind; - destruct (F_pow_spec (@ZToField m x)) as [pow_0 pow_succ] . { - rewrite pow_0. - Fdefn. - } { - rewrite N2Z.inj_succ. - rewrite Z.pow_succ_r by apply N2Z.is_nonneg. - rewrite <- N.add_1_l. - rewrite pow_succ. - rewrite IHn. - Fdefn. - } - Qed. - - Lemma ZToField_eqmod : forall x y : Z, x mod m = y mod m -> ZToField x = @ZToField m y. - Fdefn. - Qed. - - Lemma FieldToZ_nonzero: - forall x0 : F m, x0 <> 0 -> FieldToZ x0 <> 0%Z. - Proof. - intros x0 Hnz Hz. - rewrite <- Hz, ZToField_FieldToZ in Hnz; auto. - Qed. - -End FandZ. - -Section RingModuloPre. - Context {m:Z}. - Let ZToFm := ZToField : Z -> F m. Hint Unfold ZToFm. Local Coercion ZToFm : Z >-> F. - (* Substitution to prove all Compats *) - Ltac compat := repeat intro; subst; trivial. - - Instance Fplus_compat : Proper (eq==>eq==>eq) (@add m). - Proof. - compat. - Qed. - - Instance Fminus_compat : Proper (eq==>eq==>eq) (@sub m). - Proof. - compat. - Qed. - - Instance Fmult_compat : Proper (eq==>eq==>eq) (@mul m). - Proof. - compat. - Qed. - - Instance Fopp_compat : Proper (eq==>eq) (@opp m). - Proof. - compat. - Qed. - - Instance Finv_compat : Proper (eq==>eq) (@inv m). - Proof. - compat. - Qed. - - Instance Fdiv_compat : Proper (eq==>eq==>eq) (@div m). - Proof. - compat. - Qed. - - (***** Ring Theory *****) - Definition Fring_theory : ring_theory 0%F 1%F (@add m) (@mul m) (@sub m) (@opp m) eq. - Proof. - constructor; Fdefn. - Qed. - - Lemma F_mul_1_r: - forall x : F m, x * 1 = x. - Proof. - Fdefn; rewrite Z.mul_1_r; auto. - Qed. - - Lemma F_mul_assoc: - forall x y z : F m, x * (y * z) = x * y * z. - Proof. - Fdefn. - Qed. - - Lemma F_pow_pow_N (x : F m) : forall (n : N), (x ^ id n)%F = pow_N 1%F mul x n. - Proof. - destruct (F_pow_spec x) as [HO HS]; intros. - destruct n; auto; unfold id. - rewrite Pre.N_pos_1plus at 1. - rewrite HS. - simpl. - induction p using Pos.peano_ind. - - simpl. rewrite HO; apply F_mul_1_r. - - rewrite (@pow_pos_succ (F m) (@mul m) eq _ _ F_mul_assoc x). - rewrite <-IHp, Pos.pred_N_succ, Pre.N_pos_1plus, HS. - f_equal. - Qed. - - (***** Power theory *****) - Lemma Fpower_theory : power_theory 1%F (@mul m) eq id (@pow m). - Proof. - constructor; apply F_pow_pow_N. - Qed. - - (***** Division Theory *****) - Definition Fquotrem(a b: F m): F m * F m := - let '(q, r) := (Z.quotrem a b) in (q : F m, r : F m). - Lemma Fdiv_theory : div_theory eq (@add m) (@mul m) (@id _) Fquotrem. - Proof. - constructor; intros; unfold Fquotrem, id. - - replace (Z.quotrem a b) with (Z.quot a b, Z.rem a b) by - try (unfold Z.quot, Z.rem; rewrite <- surjective_pairing; trivial). - - Fdefn; rewrite <-Z.quot_rem'; trivial. - Qed. - - Lemma Z_mul_mod_modulus_r : forall x m, ((x*m) mod m = 0)%Z. - intros. - rewrite Zmult_mod, Z_mod_same_full. - rewrite Z.mul_0_r, Zmod_0_l. - reflexivity. - Qed. - - Lemma Z_mod_opp_equiv : forall x y m, x mod m = (-y) mod m -> - (-x) mod m = y mod m. - Proof. - intros. - rewrite <-Z.sub_0_l. - rewrite Zminus_mod. rewrite H. - rewrite ?Zminus_mod_idemp_l, ?Zminus_mod_idemp_r; f_equal. - destruct y; auto. - Qed. - - Lemma Z_opp_opp : forall x : Z, (-(-x)) = x. - destruct x; auto. - Qed. - - Lemma Z_mod_opp : forall x m, (- x) mod m = (- (x mod m)) mod m. - intros. - apply Z_mod_opp_equiv. - rewrite Z_opp_opp. - demod; auto. - Qed. - - (* Define a "ring morphism" between GF and Z, i.e. an equivalence - * between 'inject (ZFunction (X))' and 'GFFunction (inject (X))'. - * - * Doing this allows us to do our coefficient manipulations in Z - * rather than GF, because we know it's equivalent to inject the - * result afterward. - *) - Lemma Fring_morph: - ring_morph 0%F 1%F (@add m) (@mul m) (@sub m) (@opp m) eq - 0%Z 1%Z Z.add Z.mul Z.sub Z.opp Z.eqb - (@ZToField m). - Proof. - constructor; intros; try Fdefn; unfold id; - try (apply gf_eq; simpl; intuition). - - apply Z_mod_opp_equiv; rewrite Z_opp_opp, Zmod_mod; reflexivity. - - rewrite (proj1 (Z.eqb_eq x y)); trivial. - Qed. - - (* Redefine our division theory under the ring morphism *) - Lemma Fmorph_div_theory: + lazy iota beta delta [add sub mul opp FieldToZ ZToField proj1_sig] in *; + try apply eqsig_eq; + demod. + +Global Instance eq_dec {m} : DecidableRel (@eq (F m)). exact _. Defined. + +Global Instance commutative_ring_modulo m + : @Algebra.commutative_ring (F m) Logic.eq 0%F 1%F opp add sub mul. +Proof. + repeat (split || intro); unwrap_F; + autorewrite with zsimplify; solve [ exact _ | auto with zarith | congruence]. +Qed. + + +Module Zmod. + Lemma pow_spec {m} a : pow a 0%N = 1%F :> F m /\ forall x, pow a (1 + x)%N = mul a (pow a x). + Proof. change (@pow m) with (proj1_sig (@pow_with_spec m)); destruct (@pow_with_spec m); eauto. Qed. + + Section FandZ. + Context {m:Z}. + Local Open Scope F_scope. + + Theorem eq_FieldToZ_iff (x y : F m) : x = y <-> FieldToZ x = FieldToZ y. + Proof. destruct x, y; intuition; simpl in *; try apply (eqsig_eq _ _); congruence. Qed. + + Lemma eq_ZToField_iff : forall x y : Z, x mod m = y mod m <-> ZToField m x = ZToField m y. + Proof. split; unwrap_F; congruence. Qed. + + + Lemma FieldToZ_ZToField : forall z, FieldToZ (@ZToField m z) = z mod m. + Proof. unwrap_F; trivial. Qed. + + Lemma ZToField_FieldToZ x : ZToField m (FieldToZ x) = x :> F m. + Proof. unwrap_F; congruence. Qed. + + + Lemma ZToField_mod : forall x, ZToField m x = ZToField m (x mod m). + Proof. unwrap_F; trivial. Qed. + + Lemma mod_FieldToZ : forall (x:F m), FieldToZ x mod m = FieldToZ x. + Proof. unwrap_F. congruence. Qed. + + Lemma FieldToZ_0 : FieldToZ (0:F m) = 0%Z. + Proof. unwrap_F. apply Zmod_0_l. Qed. + + Lemma ZToField_small_nonzero z : (0 < z < m)%Z -> ZToField m z <> 0. + Proof. intros Hrange Hnz. inversion Hnz. rewrite Zmod_small, Zmod_0_l in *; omega. Qed. + + Lemma FieldToZ_nonzero (x:F m) : x <> 0 -> FieldToZ x <> 0%Z. + Proof. intros Hnz Hz. rewrite <- Hz, ZToField_FieldToZ in Hnz; auto. Qed. + + Lemma FieldToZ_range (x : F m) : 0 < m -> 0 <= x < m. + Proof. intros. rewrite <- mod_FieldToZ. apply Z.mod_pos_bound. trivial. Qed. + + Lemma FieldToZ_nonzero_range (x : F m) : (x <> 0) -> 0 < m -> (1 <= x < m)%Z. + Proof. + unfold not; intros Hnz Hlt. + rewrite eq_FieldToZ_iff, FieldToZ_0 in Hnz; pose proof (FieldToZ_range x Hlt). + omega. + Qed. + + Lemma ZToField_add : forall (x y : Z), + ZToField m (x + y) = ZToField m x + ZToField m y. + Proof. unwrap_F; trivial. Qed. + + Lemma FieldToZ_add : forall x y : F m, + FieldToZ (x + y) = ((FieldToZ x + FieldToZ y) mod m)%Z. + Proof. unwrap_F; trivial. Qed. + + Lemma ZToField_mul x y : ZToField m (x * y) = ZToField _ x * ZToField _ y :> F m. + Proof. unwrap_F. trivial. Qed. + + Lemma FieldToZ_mul : forall x y : F m, + FieldToZ (x * y) = ((FieldToZ x * FieldToZ y) mod m)%Z. + Proof. unwrap_F; trivial. Qed. + + Lemma ZToField_sub x y : ZToField _ (x - y) = ZToField _ x - ZToField _ y :> F m. + Proof. unwrap_F. trivial. Qed. + + Lemma FieldToZ_opp : forall x, FieldToZ (@opp m x) = -x mod m. + Proof. unwrap_F; trivial. Qed. + + Lemma ZToField_pow x n : ZToField _ x ^ n = ZToField _ (x ^ (Z.of_N n) mod m) :> F m. + Proof. + intros. + induction n using N.peano_ind; + destruct (pow_spec (@ZToField m x)) as [pow_0 pow_succ] . { + rewrite pow_0. + unwrap_F; trivial. + } { + rewrite N2Z.inj_succ. + rewrite Z.pow_succ_r by apply N2Z.is_nonneg. + rewrite <- N.add_1_l. + rewrite pow_succ. + rewrite IHn. + unwrap_F; trivial. + } + Qed. + + Lemma FieldToZ_pow : forall (x : F m) n, + FieldToZ (x ^ n)%F = (FieldToZ x ^ Z.of_N n mod m)%Z. + Proof. + intros. + symmetry. + induction n using N.peano_ind; + destruct (pow_spec x) as [pow_0 pow_succ] . { + rewrite pow_0, Z.pow_0_r; auto. + } { + rewrite N2Z.inj_succ. + rewrite Z.pow_succ_r by apply N2Z.is_nonneg. + rewrite <- N.add_1_l. + rewrite pow_succ. + rewrite <- Zmult_mod_idemp_r. + rewrite IHn. + apply FieldToZ_mul. + } + Qed. + + Lemma square_iff (x:F m) : + (exists y : F m, y * y = x) <-> (exists y : Z, y * y mod m = x)%Z. + Proof. + setoid_rewrite eq_FieldToZ_iff; setoid_rewrite FieldToZ_mul; split; intro H; destruct H as [x' H]. + - eauto. + - exists (ZToField _ x'); rewrite !FieldToZ_ZToField; demod; auto. + Qed. + + (* TODO: move to ZUtil *) + Lemma sub_intersperse_modulus : forall x y, ((x - y) mod m = (x + (m - y)) mod m)%Z. + Proof. + intros. + replace (x + (m - y))%Z with (m+(x-y))%Z by omega. + rewrite Zplus_mod. + rewrite Z_mod_same_full; simpl Z.add. + rewrite Zmod_mod. + reflexivity. + Qed. + End FandZ. + + Section RingTacticGadgets. + Context (m:Z). + + Definition ring_theory : ring_theory 0%F 1%F (@add m) (@mul m) (@sub m) (@opp m) eq + := Algebra.Ring.ring_theory_for_stdlib_tactic. + + Lemma pow_pow_N (x : F m) : forall (n : N), (x ^ id n)%F = pow_N 1%F mul x n. + Proof. + destruct (pow_spec x) as [HO HS]; intros. + destruct n; auto; unfold id. + rewrite Pre.N_pos_1plus at 1. + rewrite HS. + simpl. + induction p using Pos.peano_ind. + - simpl. rewrite HO. apply Algebra.right_identity. + - rewrite (@pow_pos_succ (F m) (@mul m) eq _ _ associative x). + rewrite <-IHp, Pos.pred_N_succ, Pre.N_pos_1plus, HS. + trivial. + Qed. + + Lemma power_theory : power_theory 1%F (@mul m) eq id (@pow m). + Proof. split; apply pow_pow_N. Qed. + + (***** Division Theory *****) + Definition quotrem(a b: F m): F m * F m := + let '(q, r) := (Z.quotrem a b) in (ZToField _ q , ZToField _ r). + Lemma Fdiv_theory : div_theory eq (@add m) (@mul m) (@id _) quotrem. + Proof. + constructor; intros; unfold quotrem, id. + + replace (Z.quotrem a b) with (Z.quot a b, Z.rem a b) by + try (unfold Z.quot, Z.rem; rewrite <- surjective_pairing; trivial). + + unwrap_F; rewrite <-Z.quot_rem'; trivial. + Qed. + + Lemma Z_mod_opp_equiv : forall x y m, x mod m = (-y) mod m -> + (-x) mod m = y mod m. + Proof. + intros. + rewrite <-Z.sub_0_l. + rewrite Zminus_mod. rewrite H. + rewrite ?Zminus_mod_idemp_l, ?Zminus_mod_idemp_r; f_equal. + destruct y; auto. + Qed. + + Lemma Z_opp_opp : forall x : Z, (-(-x)) = x. + destruct x; auto. + Qed. + + Lemma Z_mod_opp : forall x m, (- x) mod m = (- (x mod m)) mod m. + intros. + apply Z_mod_opp_equiv. + rewrite Z_opp_opp. + demod; auto. + Qed. + + (* Define a "ring morphism" between GF and Z, i.e. an equivalence + * between 'inject (ZFunction (X))' and 'GFFunction (inject (X))'. + * + * Doing this allows the [ring] tactic to do coefficient + * manipulations in Z rather than F, because we know it's equivalent + * to inject the result afterward. *) + Lemma ring_morph: ring_morph 0%F 1%F (@add m) (@mul m) (@sub m) (@opp m) eq + 0%Z 1%Z Z.add Z.mul Z.sub Z.opp Z.eqb (@ZToField m). + Proof. split; intros; unwrap_F; solve [ auto | rewrite (proj1 (Z.eqb_eq x y)); trivial]. Qed. + + (* Redefine our division theory under the ring morphism *) + Lemma morph_div_theory: div_theory eq Zplus Zmult (@ZToField m) Z.quotrem. - Proof. - constructor; intros; intuition. - replace (Z.quotrem a b) with (Z.quot a b, Z.rem a b); - try (unfold Z.quot, Z.rem; rewrite <- surjective_pairing; trivial). - - eq_remove_proofs; demod; - rewrite <- (Z.quot_rem' a b); - destruct a; simpl; trivial. - Qed. - - Lemma ZToField_1 : @ZToField m 1 = 1. - Proof. - Fdefn. - Qed. -End RingModuloPre. - -Ltac Fconstant t := match t with @ZToField _ ?x => x | _ => NotConstant end. -Ltac Fexp_tac t := Ncst t. -Ltac Fpreprocess := rewrite <-?ZToField_0, ?ZToField_1. -Ltac Fpostprocess := repeat split; - repeat match goal with [ |- context[exist ?a ?b (Pre.Z_mod_mod ?x ?q)] ] => - change (exist a b (Pre.Z_mod_mod x q)) with (@ZToField q x%Z) end; - rewrite ?ZToField_0, ?ZToField_1. - -Module Type Modulus. - Parameter modulus : Z. -End Modulus. - -(* Example of how to instantiate the ring tactic *) -Module RingModulo (Export M : Modulus). - Definition ring_theory_modulo := @Fring_theory modulus. - Definition ring_morph_modulo := @Fring_morph modulus. - Definition morph_div_theory_modulo := @Fmorph_div_theory modulus. - Definition power_theory_modulo := @Fpower_theory modulus. - - Add Ring GFring_Z : ring_theory_modulo - (morphism ring_morph_modulo, - constants [Fconstant], - div morph_div_theory_modulo, - power_tac power_theory_modulo [Fexp_tac]). -End RingModulo. - -Section VariousModulo. - Context {m:Z}. - - Add Ring GFring_Z : (@Fring_theory m) - (morphism (@Fring_morph m), - constants [Fconstant], - div (@Fmorph_div_theory m), - power_tac (@Fpower_theory m) [Fexp_tac]). - - Lemma F_mul_0_l : forall x : F m, 0 * x = 0. - Proof. - intros; ring. - Qed. - - Lemma F_mul_0_r : forall x : F m, x * 0 = 0. - Proof. - intros; ring. - Qed. - - Lemma F_mul_nonzero_l : forall a b : F m, a*b <> 0 -> a <> 0. - intros; intuition; subst. - assert (0 * b = 0) by ring; intuition. - Qed. - - Lemma F_mul_nonzero_r : forall a b : F m, a*b <> 0 -> b <> 0. - intros; intuition; subst. - assert (a * 0 = 0) by ring; intuition. - Qed. - - Lemma F_pow_distr_mul : forall (x y:F m) z, (0 <= z)%N -> - (x ^ z) * (y ^ z) = (x * y) ^ z. - Proof. - intros. - replace z with (Z.to_N (Z.of_N z)) by apply N2Z.id. - apply natlike_ind with (x := Z.of_N z); simpl; [ ring | | - replace 0%Z with (Z.of_N 0%N) by auto; apply N2Z.inj_le; auto]. - intros z' z'_nonneg IHz'. - rewrite Z2N.inj_succ by auto. - rewrite <-N.add_1_l. - rewrite !(proj2 (@F_pow_spec m _) _). - rewrite <- IHz'. - ring. - Qed. - - Lemma F_opp_0 : opp (0 : F m) = 0%F. - Proof. - intros; ring. - Qed. - - Lemma F_opp_swap : forall x y : F m, opp x = y <-> x = opp y. - Proof. - split; intro; subst; ring. - Qed. - - Lemma F_opp_involutive : forall x : F m, opp (opp x) = x. - Proof. - intros; ring. - Qed. - - Lemma F_square_opp : forall x : F m, (opp x ^ 2 = x ^ 2)%F. - Proof. - intros; ring. - Qed. - - Lemma F_mul_opp_r : forall x y : F m, (x * opp y = opp (x * y))%F. - intros; ring. - Qed. - - Lemma F_mul_opp_l : forall x y : F m, (opp x * y = opp (x * y))%F. - intros; ring. - Qed. - - Lemma F_mul_opp_both : forall x y : F m, (opp x * opp y = x * y)%F. - intros; ring. - Qed. - - Lemma F_add_0_r : forall x : F m, (x + 0)%F = x. - Proof. - intros; ring. - Qed. - - Lemma F_add_0_l : forall x : F m, (0 + x)%F = x. - Proof. - intros; ring. - Qed. - - Lemma F_add_reg_r : forall x y z : F m, y + x = z + x -> y = z. - Proof. - intros ? ? ? A. - replace y with (y + x - x) by ring. - rewrite A; ring. - Qed. - - Lemma F_add_reg_l : forall x y z : F m, x + y = x + z -> y = z. - Proof. - intros ? ? ? A. - replace y with (x + y - x) by ring. - rewrite A; ring. - Qed. - - Lemma F_sub_0_r : forall x : F m, (x - 0)%F = x. - Proof. - intros; ring. - Qed. - - Lemma F_sub_0_l : forall x : F m, (0 - x)%F = opp x. - Proof. - intros; ring. - Qed. - - Lemma F_mul_1_l : forall x : F m, (1 * x)%F = x. - Proof. - intros; ring. - Qed. - - Lemma F_ZToField_m : ZToField m = @ZToField m 0. - Proof. - Fdefn. - rewrite Zmod_0_l. - apply Z_mod_same_full. - Qed. - - Lemma F_sub_m_l : forall x : F m, opp x = ZToField m - x. - Proof. - rewrite F_ZToField_m. - symmetry. - apply F_sub_0_l. - Qed. - - Lemma opp_ZToField : forall x : Z, opp (ZToField x) = @ZToField m (m - x). - Proof. - Fdefn. - rewrite Zminus_mod, Z_mod_same_full, (Z.sub_0_l (x mod m)); reflexivity. - Qed. - - Lemma F_pow_2_r : forall x : F m, x^2 = x*x. - Proof. - intros. ring. - Qed. - - Lemma F_pow_3_r : forall x : F m, x^3 = x*x*x. - Proof. - intros. ring. - Qed. - - Lemma F_pow_add : forall (x : F m) k j, x ^ j * x ^ k = x ^ (j + k). - Proof. - intros. - destruct (F_pow_spec x) as [exp_zero exp_succ]. - induction j using N.peano_ind. - + rewrite exp_zero. - ring_simplify; eauto. - + - rewrite N.add_succ_l. - do 2 rewrite <- N.add_1_l. - do 2 rewrite exp_succ by apply N.neq_succ_0. - rewrite <- IHj. - ring. - Qed. - - Lemma F_pow_compose : forall (x : F m) k j, (x ^ j) ^ k = x ^ (k * j). - Proof. - intros. - induction k using N.peano_ind; [rewrite Nmult_0_l; ring | ]. - rewrite Nmult_Sn_m. - rewrite <- F_pow_add. - rewrite <- IHk. - rewrite <- N.add_1_l. - rewrite (proj2 (F_pow_spec _)). - ring. - Qed. - - Lemma F_sub_add_swap : forall w x y z : F m, w - x = y - z <-> w + z = y + x. - Proof. - split; intro A; - [ replace w with (w - x + x) by ring - | replace w with (w + z - z) by ring ]; rewrite A; ring. - Qed. - - Definition isSquare (x : F m) := exists sqrt_x, sqrt_x ^ 2 = x. - - Lemma square_Zmod_F : forall (a : F m), isSquare a <-> - (exists b : Z, ((b * b) mod m)%Z = a). - Proof. - split; intro A; destruct A as [sqrt_a sqrt_a_id]. { - exists sqrt_a. - rewrite <- FieldToZ_mul. - apply F_eq. - ring_simplify; auto. - } { - exists (ZToField sqrt_a). - rewrite ZToField_pow. - replace (Z.of_N 2) with 2%Z by auto. - rewrite Z.pow_2_r. - rewrite sqrt_a_id. - apply ZToField_FieldToZ. - } - Qed. - - Lemma FieldToZ_range : forall x : F m, 0 < m -> 0 <= x < m. - Proof. - intros. - rewrite <- mod_FieldToZ. - apply Z.mod_pos_bound. - omega. - Qed. - - Lemma FieldToZ_nonzero_range : forall x : F m, (x <> 0) -> 0 < m -> - (1 <= x < m)%Z. - Proof. - intros. - pose proof (FieldToZ_range x). - unfold not in *. - rewrite F_eq in H. - replace (FieldToZ 0) with 0%Z in H by auto. - omega. - Qed. - - Lemma F_mul_comm : forall x y : F m, x*y = y*x. - intros; ring. - Qed. - - Lemma Fq_sub_eq : forall x y a b : F m, a = b -> x-a = y-b -> x = y. - Proof. - intros x y a b Hab Hxayb; subst. - replace x with ((x - b) + b) by ring. - replace y with ((y - b) + b) by ring. - rewrite Hxayb; ring. - Qed. - - Lemma F_FieldToZ_add_opp : forall x : F m, x <> 0 -> (FieldToZ x + FieldToZ (opp x) = m)%Z. - Proof. - intros. - rewrite FieldToZ_opp. - rewrite Z_mod_nz_opp_full, mod_FieldToZ; try omega. - rewrite mod_FieldToZ. - replace 0%Z with (@FieldToZ m 0) by auto. - intro false_eq. - rewrite <-F_eq in false_eq. - congruence. - Qed. - -End VariousModulo. + Proof. + split; intros. + replace (Z.quotrem a b) with (Z.quot a b, Z.rem a b); + try (unfold Z.quot, Z.rem; rewrite <- surjective_pairing; trivial). + unwrap_F; rewrite <- (Z.quot_rem' a b); trivial. + Qed. + + End RingTacticGadgets. + + Ltac is_constant t := match t with @ZToField _ ?x => x | _ => NotConstant end. + Ltac is_pow_constant t := Ncst t. + + Module Type Modulus. Parameter modulus : Z. End Modulus. + + (* Example of how to instantiate the ring tactic *) + Module RingModulo (Export M : Modulus). + Add Ring _theory : (ring_theory modulus) + (morphism (ring_morph modulus), + constants [is_constant], + div (morph_div_theory modulus), + power_tac (power_theory modulus) [is_pow_constant]). + + Example ring_modulo_example : forall x y z, x*z + z*y = z*(x+y). + Proof. intros. ring. Qed. + End RingModulo. + + Section VariousModulo. + Context {m:Z}. + Local Open Scope F_scope. + + Add Ring _theory : (ring_theory m) + (morphism (ring_morph m), + constants [is_constant], + div (morph_div_theory m), + power_tac (power_theory m) [is_pow_constant]). + + Lemma mul_nonzero_l : forall a b : F m, a*b <> 0 -> a <> 0. + Proof. intros a b Hnz Hz. rewrite Hz in Hnz; apply Hnz; ring. Qed. + + Lemma mul_nonzero_r : forall a b : F m, a*b <> 0 -> b <> 0. + Proof. intros a b Hnz Hz. rewrite Hz in Hnz; apply Hnz; ring. Qed. + End VariousModulo. + + Section Pow. + Context {m:Z}. + Add Ring _theory' : (ring_theory m) + (morphism (ring_morph m), + constants [is_constant], + div (morph_div_theory m), + power_tac (power_theory m) [is_pow_constant]). + Local Open Scope F_scope. + + Import Algebra.ScalarMult. + Global Instance pow_is_scalarmult + : is_scalarmult (G:=F m) (eq:=eq) (add:=mul) (zero:=1%F) (mul := fun n x => x ^ (N.of_nat n)). + Proof. + split; intros; rewrite ?Nat2N.inj_succ, <-?N.add_1_l; + match goal with + | [x:F m |- _ ] => solve [destruct (@pow_spec m P); auto] + | |- Proper _ _ => solve_proper + end. + Qed. + + (* TODO: move this somewhere? *) + Create HintDb nat2N discriminated. + Hint Rewrite Nat2N.inj_iff + (eq_refl _ : (0%N = N.of_nat 0)) + (eq_refl _ : (1%N = N.of_nat 1)) + (eq_refl _ : (2%N = N.of_nat 2)) + (eq_refl _ : (3%N = N.of_nat 3)) + : nat2N. + Hint Rewrite <- Nat2N.inj_double Nat2N.inj_succ_double Nat2N.inj_succ + Nat2N.inj_add Nat2N.inj_mul Nat2N.inj_sub Nat2N.inj_pred + Nat2N.inj_div2 Nat2N.inj_max Nat2N.inj_min Nat2N.id + : nat2N. + + Ltac pow_to_scalarmult_ref := + repeat (autorewrite with nat2N; + match goal with + | |- context [ (_^?n)%F ] => + rewrite <-(N2Nat.id n); generalize (N.to_nat n); clear n; + let m := fresh n in intro m + | |- context [ (_^N.of_nat ?n)%F ] => + let rw := constr:(scalarmult_ext(zero:=ZToField m 1) n) in + setoid_rewrite rw (* rewriting moduloa reduction *) + end). + + Lemma pow_0_r (x:F m) : x^0 = 1. + Proof. pow_to_scalarmult_ref. apply scalarmult_0_l. Qed. + + Lemma pow_add_r (x:F m) (a b:N) : x^(a+b) = x^a * x^b. + Proof. pow_to_scalarmult_ref; apply scalarmult_add_l. Qed. + + Lemma pow_0_l (n:N) : n <> 0%N -> 0^n = 0 :> F m. + Proof. pow_to_scalarmult_ref; destruct n; simpl; intros; [congruence|ring]. Qed. + + Lemma pow_pow_l (x:F m) (a b:N) : (x^a)^b = x^(a*b). + Proof. pow_to_scalarmult_ref. apply scalarmult_assoc. Qed. + + Lemma pow_1_r (x:F m) : x^1 = x. + Proof. pow_to_scalarmult_ref; simpl; ring. Qed. + + Lemma pow_2_r (x:F m) : x^2 = x*x. + Proof. pow_to_scalarmult_ref; simpl; ring. Qed. + + Lemma pow_3_r (x:F m) : x^3 = x*x*x. + Proof. pow_to_scalarmult_ref; simpl; ring. Qed. + End Pow. +End Zmod. |