diff options
Diffstat (limited to 'src/ModularArithmetic/PrimeFieldTheorems.v')
-rw-r--r-- | src/ModularArithmetic/PrimeFieldTheorems.v | 705 |
1 files changed, 154 insertions, 551 deletions
diff --git a/src/ModularArithmetic/PrimeFieldTheorems.v b/src/ModularArithmetic/PrimeFieldTheorems.v index 8d47e36ed..c97bde495 100644 --- a/src/ModularArithmetic/PrimeFieldTheorems.v +++ b/src/ModularArithmetic/PrimeFieldTheorems.v @@ -10,568 +10,171 @@ Require Import Coq.ZArith.BinInt Coq.NArith.BinNat Coq.ZArith.ZArith Coq.ZArith. Require Import Coq.Logic.Eqdep_dec. Require Import Crypto.Util.NumTheoryUtil Crypto.Util.ZUtil. Require Import Crypto.Util.Tactics. +Require Import Crypto.Util.Decidable. Require Export Crypto.Util.FixCoqMistakes. Require Crypto.Algebra. +Import Crypto.ModularArithmetic.ModularArithmeticTheorems.Zmod. Existing Class prime. -Lemma F_inv_spec : forall {m}, inv 0%F = (0%F : F m) - /\ (prime m -> forall a0 : F m, a0 <> 0%F -> (a0 * inv a0)%F = 1%F). -Proof. - intros m. - pose (@inv_with_spec m) as H. - change (@inv m) with (proj1_sig H). - destruct H; eauto. -Qed. - -Section FieldModuloPre. - Context {q:Z} {prime_q:prime q}. - Local Open Scope F_scope. - - Lemma Fq_1_neq_0 : (1:F q) <> (0:F q). - Proof. - pose proof prime_ge_2 q _. - rewrite F_eq, !FieldToZ_ZToField, !Zmod_small by omega; congruence. - Qed. - - Lemma F_mul_inv_r : forall x : F q, x <> 0 -> x * inv x = 1. - Proof. - intros. - edestruct @F_inv_spec; eauto. - Qed. - - Lemma F_mul_inv_l : forall x : F q, x <> 0 -> inv x * x = 1. - Proof. - intros. - edestruct @F_inv_spec as [Ha Hb]; eauto. - erewrite <-Hb; eauto. - Fdefn. - Qed. - - (* Add an abstract field (without modifiers) *) - Definition Ffield_theory : field_theory 0%F 1%F (@add q) (@mul q) (@sub q) (@opp q) (@div q) (@inv q) eq. - Proof. - constructor; auto using Fring_theory, Fq_1_neq_0, F_mul_inv_l. - Qed. - - Global Instance field_modulo : @Algebra.field (F q) Logic.eq (ZToField 0) (ZToField 1) opp add sub mul inv div. - Proof. - constructor; try solve_proper. - - apply commutative_ring_modulo. - - split. auto using F_mul_inv_l. - - split. auto using Fq_1_neq_0. - Qed. -End FieldModuloPre. - -Module Type PrimeModulus. - Parameter modulus : Z. - Parameter prime_modulus : prime modulus. -End PrimeModulus. - -Module FieldModulo (Import M : PrimeModulus). - (* Add our field with all the fixin's *) - Module Import RingM := RingModulo M. - Definition field_theory_modulo := @Ffield_theory modulus prime_modulus. - Add Field Ffield_Z : field_theory_modulo - (morphism ring_morph_modulo, - preprocess [Fpreprocess], - postprocess [Fpostprocess], - constants [Fconstant], - div morph_div_theory_modulo, - power_tac power_theory_modulo [Fexp_tac]). -End FieldModulo. - -Section VariousModPrime. - Context {q:Z} {prime_q:prime q}. - Local Open Scope F_scope. - Add Field Ffield_Z : (@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]). - - Lemma Fq_mul_eq : forall x y z : F q, z <> 0 -> x * z = y * z -> x = y. - Proof. - intros ? ? ? z_nonzero mul_z_eq. - assert (x * z * inv z = y * z * inv z) as H by (rewrite mul_z_eq; reflexivity). - replace (x * z * inv z) with (x * (z * inv z)) in H by (field; trivial). - replace (y * z * inv z) with (y * (z * inv z)) in H by (field; trivial). - rewrite F_mul_inv_r in H by assumption. - replace (x * 1) with x in H by field. - replace (y * 1) with y in H by field. - trivial. - Qed. - - Lemma Fq_mul_eq_l : forall x y z : F q, z <> 0 -> z * x = z * y -> x = y. - Proof. - intros ? ? ? Hz Heq. - apply (Fq_mul_eq _ _ z); auto. - apply (Fq_sub_eq _ _ _ _ Heq); ring. - Qed. - - Lemma Fq_inv_unique' : forall - inv1 (inv1ok: inv1 0 = 0 /\ forall x : F q, x <> 0 -> x * inv1 x = 1) - inv2 (inv2ok: inv2 0 = 0 /\ forall x : F q, x <> 0 -> x * inv2 x = 1), - forall x, inv1 x = inv2 x. - Proof. - intros inv1 [inv1_0 inv1_x] inv2 [inv2_0 inv2_x] x. - destruct (F_eq_dec x 0) as [H|H]; [congruence|]. - apply (Fq_mul_eq_l _ _ x H). rewrite inv1_x, inv2_x; trivial. - Qed. - - Lemma Fq_inv_unique : forall - inv' (inv'ok: inv' 0 = 0 /\ forall x : F q, x <> 0 -> x * inv' x = 1), - forall x, inv x = inv' x. - Proof. - intros ? [? ?] ?. - pose proof (@F_inv_spec q) as [? ?]. - eauto using Fq_inv_unique'. - Qed. - - Lemma Fq_mul_zero_why : forall a b : F q, a*b = 0 -> a = 0 \/ b = 0. - intros. - assert (Z := F_eq_dec a 0); destruct Z. - - - left; intuition. - - - assert (a * b / a = 0) by - ( rewrite H; field; intuition ). - - replace (a*b/a) with (b) in H0 by (field; trivial). - right; intuition. - Qed. - - Lemma Fq_mul_nonzero_nonzero : forall a b : F q, a <> 0 -> b <> 0 -> a*b <> 0. - intros; intuition; subst. - apply Fq_mul_zero_why in H1. - destruct H1; subst; intuition. - Qed. - Hint Resolve Fq_mul_nonzero_nonzero. - - Lemma Fq_pow_zero : forall (p: N), p <> 0%N -> (0^p = @ZToField q 0)%F. - induction p using N.peano_ind; - rewrite <-?N.add_1_l, ?(proj2 (@F_pow_spec q _) _), ?(proj1 (@F_pow_spec q _)). - - intuition. - - intro H. apply F_mul_0_l. - Qed. - - Lemma Fq_root_zero : forall (x: F q) (p: N), x^p = 0 -> x = 0. - induction p using N.peano_ind; - rewrite <-?N.add_1_l, ?(proj2 (@F_pow_spec q _) _), ?(proj1 (@F_pow_spec q _)). - - intros; destruct Fq_1_neq_0; auto. - - intro H; destruct (Fq_mul_zero_why x (x^p) H); auto. - Qed. - - Lemma Fq_root_nonzero : forall (x:F q) p, x^p <> 0 -> (p <> 0)%N -> x <> 0. - induction p using N.peano_ind; - rewrite <-?N.add_1_l, ?(proj2 (@F_pow_spec q _) _), ?(proj1 (@F_pow_spec q _)). - - intuition. - - destruct (N.eq_dec p 0); intro H; intros; subst. - + rewrite (proj1 (@F_pow_spec q _)) in H; replace (x*1) with (x) in H by ring; trivial. - + apply IHp; auto. intro Hz; rewrite Hz in *. apply H, F_mul_0_r. - Qed. - - Lemma Fq_pow_nonzero : forall (x : F q) p, x <> 0 -> x^p <> 0. - Proof. - induction p using N.peano_ind; - rewrite <-?N.add_1_l, ?(proj2 (@F_pow_spec q _) _), ?(proj1 (@F_pow_spec q _)). - - intuition. auto using Fq_1_neq_0. - - intros H Hc. destruct (Fq_mul_zero_why _ _ Hc). - + intuition. - + apply IHp; auto. - Qed. - - Lemma F_inv_0 : inv 0 = (0 : F q). - Proof. - destruct (@F_inv_spec q); auto. - Qed. - - Definition inv_fermat (x:F q) : F q := x ^ Z.to_N (q - 2)%Z. - Lemma Fq_inv_fermat: 2 < q -> forall x : F q, inv x = x ^ Z.to_N (q - 2)%Z. - Proof. - intros. - erewrite (Fq_inv_unique inv_fermat); trivial; split; intros; unfold inv_fermat. - { replace 2%N with (Z.to_N (Z.of_N 2))%N by auto. - rewrite Fq_pow_zero. reflexivity. intro. - assert (Z.of_N (Z.to_N (q-2)) = 0%Z) by (rewrite H0; eauto); rewrite Z2N.id in *; omega. } - { clear x. rename x0 into x. pose proof (fermat_inv _ _ x) as Hf; forward Hf. - { pose proof @ZToField_FieldToZ; pose proof @ZToField_mod; congruence. } - specialize (Hf H1); clear H1. - rewrite <-(ZToField_FieldToZ x). - rewrite ZToField_pow. - replace (Z.of_N (Z.to_N (q - 2))) with (q-2)%Z by (rewrite Z2N.id ; omega). - rewrite <-ZToField_mul. - apply ZToField_eqmod. - rewrite Hf, Zmod_small by omega; reflexivity. - } - Qed. - Lemma Fq_inv_fermat_correct : 2 < q -> forall x : F q, inv_fermat x = inv x. - Proof. - unfold inv_fermat; intros. rewrite Fq_inv_fermat; auto. - Qed. - - Let inv_fermat_powmod (x:Z) : Z := powmod q x (Z.to_N (q-2)). - Lemma FieldToZ_inv_efficient : 2 < q -> - forall x : F q, FieldToZ (inv x) = inv_fermat_powmod x. - Proof. - unfold inv_fermat_powmod; intros. - rewrite Fq_inv_fermat, powmod_Zpow_mod, <-FieldToZ_pow_Zpow_mod; auto. - Qed. +Module Zmod. + Section Field. + Context (q:Z) {prime_q:prime q}. + Lemma inv_spec : inv 0%F = (0%F : F q) + /\ (prime q -> forall x : F q, x <> 0%F -> (inv x * x)%F = 1%F). + Proof. change (@inv q) with (proj1_sig (@inv_with_spec q)); destruct (@inv_with_spec q); eauto. Qed. + + Lemma inv_0 : inv 0 = ZToField q 0. Proof. destruct inv_spec; auto. Qed. + Lemma inv_nonzero (x:F q) : (x <> 0 -> inv x * x%F = 1)%F. Proof. destruct inv_spec; auto. Qed. + + Global Instance field_modulo : @Algebra.field (F q) Logic.eq 0%F 1%F opp add sub mul inv div. + Proof. + repeat match goal with + | _ => solve [ solve_proper + | apply commutative_ring_modulo + | apply inv_nonzero + | cbv [not]; pose proof prime_ge_2 q prime_q; + rewrite Zmod.eq_FieldToZ_iff, !Zmod.FieldToZ_ZToField, !Zmod_small; omega ] + | _ => split + end. + Qed. - Lemma F_minus_swap : forall x y : F q, x - y = 0 -> y - x = 0. - Proof. - intros ? ? eq_zero. - replace x with (x - y + y); try ring. - rewrite eq_zero. - ring. - Qed. + Definition field_theory : field_theory 0%F 1%F add mul sub opp div inv eq + := Algebra.Field.field_theory_for_stdlib_tactic. + End Field. + + (** A field tactic hook that can be imported *) + Module Type PrimeModulus. + Parameter modulus : Z. + Parameter prime_modulus : prime modulus. + End PrimeModulus. + Module FieldModulo (Export M : PrimeModulus). + Module Import RingM := RingModulo M. + Add Field _field : (field_theory modulus) + (morphism (ring_morph modulus), + constants [is_constant], + div (morph_div_theory modulus), + power_tac (power_theory modulus) [is_pow_constant]). + End FieldModulo. + + Section NumberThoery. + Context {q:Z} {prime_q:prime q} {two_lt_q: 2 < q}. + Local Open Scope F_scope. + Add Field _field : (field_theory q) + (morphism (ring_morph q), + constants [is_constant], + div (morph_div_theory q), + power_tac (power_theory q) [is_pow_constant]). + + Lemma FieldToZ_1 : @FieldToZ q 1 = 1%Z. + Proof. simpl. rewrite Zmod_small; omega. Qed. + + Lemma Fq_inv_fermat (x:F q) : inv x = x ^ Z.to_N (q - 2)%Z. + Proof. + destruct (dec (x = 0%F)) as [?|Hnz]; [subst x; rewrite inv_0|]. + { admit. } + erewrite <-Algebra.Field.inv_unique; try reflexivity. + rewrite eq_FieldToZ_iff, FieldToZ_mul, FieldToZ_pow, Z2N.id, FieldToZ_1 by omega. + apply (fermat_inv q _ (FieldToZ x)); rewrite mod_FieldToZ; eapply FieldToZ_nonzero; trivial. + Qed. - Lemma Fq_square_mul : forall x y z : F q, (y <> 0) -> - x ^ 2 = z * y ^ 2 -> exists sqrt_z, sqrt_z ^ 2 = z. - Proof. - intros ? ? ? y_nonzero A. - exists (x / y). - assert ((x / y) ^ 2 = x ^ 2 / y ^ 2) as square_distr_div by (field; trivial). - assert (y ^ 2 <> 0) as y2_nonzero by ( - change (2%N) with (1+(1+0))%N; - rewrite !(proj2 (@F_pow_spec q _) _), !(proj1 (@F_pow_spec q _)); - auto 10 using Fq_mul_nonzero_nonzero, Fq_1_neq_0). - rewrite (Fq_mul_eq _ z (y ^ 2)); auto. - rewrite <- A. - field; trivial. - Qed. + (* TODO: move to number thoery util *) + Lemma odd_as_div a : Z.odd a = true -> a = (2*(a/2) + 1)%Z. + Proof. + rewrite Zodd_mod, <-Zeq_is_eq_bool; intro H_1; rewrite <-H_1. + apply Z_div_mod_eq; reflexivity. + Qed. + + Lemma euler_criterion (a : F q) (a_nonzero : a <> 0) : + (a ^ (Z.to_N (q / 2)) = 1) <-> (exists b, b*b = a). + Proof. + pose proof FieldToZ_nonzero_range a; pose proof (odd_as_div q). + specialize_by ltac:(destruct (Z.prime_odd_or_2 _ prime_q); try omega; trivial). + rewrite eq_FieldToZ_iff, !FieldToZ_pow, !FieldToZ_1, !Z2N.id by omega. + rewrite square_iff, <-(euler_criterion (q/2)) by (trivial || omega); reflexivity. + Qed. - Lemma Fq_square_mul_sub : forall x y z : F q, - 0 = z * y ^ 2 - x ^ 2 -> (exists sqrt_z, sqrt_z ^ 2 = z) \/ x = 0. - Proof. - intros ? ? ? eq_zero_sub. - destruct (F_eq_dec y 0). { + Global Instance Decidable_square (x:F q) : Decidable (exists y, y*y = x). + Proof. + destruct (dec (x = 0)). + { left. abstract (exists 0; subst; ring). } + { eapply Decidable_iff_to_impl; [eapply euler_criterion; assumption | exact _]. } + Defined. + End NumberThoery. + + Section SquareRootsPrime5Mod8. + Context {q:Z} {prime_q: prime q} {q_5mod8 : q mod 8 = 5}. + + (* This is always true, but easier to check by computation than to prove *) + Context (sqrt_minus1_valid : ((ZToField q 2 ^ Z.to_N (q / 4)) ^ 2 = opp 1)%F). + Local Open Scope F_scope. + Add Field _field2 : (field_theory q) + (morphism (ring_morph q), + constants [is_constant], + div (morph_div_theory q), + power_tac (power_theory q) [is_pow_constant]). + + Let sqrt_minus1 : F q := ZToField _ 2 ^ Z.to_N (q / 4). + + Lemma two_lt_q_5mod8 : 2 < q. + Proof. + pose proof (prime_ge_2 q _) as two_le_q. + apply Zle_lt_or_eq in two_le_q. + destruct two_le_q; auto. subst_max. - rewrite Fq_pow_zero in eq_zero_sub by congruence. - rewrite F_mul_0_r in eq_zero_sub. - assert (x ^ 2 = 0 - x ^ 2 + x ^ 2) as minus_plus_x2 by (rewrite <- eq_zero_sub; ring). - assert (x ^ 2 = 0) as x2_zero by (rewrite minus_plus_x2; ring). - apply Fq_root_zero in x2_zero. - right; auto. - } { - left. - eapply Fq_square_mul; eauto. - instantiate (1 := x). - assert (x ^ 2 = z * y ^ 2 - x ^ 2 + x ^ 2) as plus_minus_x2 by - (rewrite <- eq_zero_sub; ring). - rewrite plus_minus_x2; ring. - } - Qed. - - Lemma F_div_mul : forall x y z : F q, y <> 0 -> (z = (x / y) <-> z * y = x). - Proof. - split; intros; subst; field. - Qed. - - Lemma F_div_1_r : forall x : F q, (x/1)%F = x. - Proof. - intros; field. (* TODO: Warning: Collision between bound variables ... *) - Qed. - - Lemma F_div_opp_1 : forall x y : F q, (opp x / y = opp (x / y))%F. - Proof. - intros; destruct (F_eq_dec y 0); [subst;unfold div;rewrite !F_inv_0|]; field. - Qed. - - Lemma F_eq_opp_zero : forall x : F q, 2 < q -> (x = opp x <-> x = 0). - Proof. - split; intro A. - + pose proof (F_opp_spec x) as opp_spec. - rewrite <- A in opp_spec. - replace (x + x) with (ZToField 2 * x) in opp_spec by ring. - apply Fq_mul_zero_why in opp_spec. - destruct opp_spec as [eq_2_0 | ?]; auto. - apply F_eq in eq_2_0. - rewrite FieldToZ_ZToField in eq_2_0. - replace (FieldToZ 0) with 0%Z in eq_2_0 by auto. - replace (2 mod q) with 2 in eq_2_0; try discriminate. - symmetry; apply Z.mod_small; omega. - + subst. - rewrite <- (F_opp_spec 0) at 1. - ring. - Qed. - - Lemma euler_criterion_F : forall (a : F q) (q_odd : 2 < q) (a_nonzero : a <> 0), - (a ^ (Z.to_N (q / 2)) = 1) <-> isSquare a. - Proof. - (*pose proof q_odd.*) - split; intros A. { - apply square_Zmod_F; auto. - eapply euler_criterion; omega || auto. - + apply div2_p_1mod4; auto; omega. - + pose proof (FieldToZ_nonzero_range a a_nonzero); omega. - + replace (q / 2)%Z with (Z.of_N (Z.to_N (q / 2))) - by (apply Z2N.id; apply Z.div_pos; prime_bound). - rewrite FieldToZ_pow_Zpow_mod by omega. - rewrite A. - replace (FieldToZ 1) with (1 mod q) by auto. - apply Z.mod_1_l; omega. - } { - apply F_eq. - rewrite <- FieldToZ_pow_Zpow_mod by omega. - rewrite Z2N.id by (apply Z.div_pos; omega). - replace (FieldToZ 1) with 1%Z - by (rewrite FieldToZ_ZToField at 1; symmetry; apply Zmod_1_l; omega). - apply euler_criterion; try prime_bound; auto. - + apply div2_p_1mod4; auto; omega. - + pose proof (FieldToZ_nonzero_range a a_nonzero); omega. - + apply square_Zmod_F; auto. - } - Qed. - - Lemma euler_criterion_if' : forall (a : F q) (q_odd : 2 < q), - if (orb (F_eqb a 0) (F_eqb (a ^ (Z.to_N (q / 2))) 1)) - then (isSquare a) else (forall b, b ^ 2 <> a). - Proof. - unfold orb; intros. - rewrite <- if_F_eq_dec_if_F_eqb. - do 2 break_if; try congruence. - + subst; exists 0; apply Fq_pow_zero; congruence. - + unfold isSquare; apply F_eqb_eq in Heqb; apply euler_criterion_F; eauto. - + intros b b_id. - apply F_eqb_neq in Heqb. - assert (isSquare a) as a_square by (eexists; eauto). - apply euler_criterion_F in a_square; auto. - Qed. - - Lemma euler_criterion_if : forall (a : F q) (q_odd : 2 < q), - if (a =? 0) || (powmod q a (Z.to_N (q / 2)) =? 1) - then (isSquare a) else (forall b, b ^ 2 <> a). - Proof. - intros. - pose proof (euler_criterion_if' a q_odd) as H. - unfold F_eqb in H. - rewrite !FieldToZ_ZToField, !@FieldToZ_pow_efficient, !Zmod_small in H by omega; assumption. - Qed. - - Lemma sqrt_solutions : forall x y : F q, y ^ 2 = x ^ 2 -> y = x \/ y = opp x. - Proof. - intros ? ? squares_eq. - remember (y - x) as z. - replace y with (x + z) in * by (rewrite Heqz; ring). - replace (x ^ 2) with (0 + x ^ 2) in squares_eq by ring. - replace ((x + z) ^ 2) with (z * (x + (x + z)) + x ^ 2) in squares_eq by ring. - apply F_add_reg_r in squares_eq. - apply Fq_mul_zero_why in squares_eq. - destruct squares_eq as [? | z_2x_0]; [ left; subst; ring | right ]. - pose proof (F_opp_spec x) as opp_spec. - rewrite <- z_2x_0 in opp_spec. - apply F_add_reg_l in opp_spec; auto. - Qed. - - Global Instance Fq_Ring_ops : @Ring_ops (F q) 0 1 add mul sub opp eq. - Global Instance Fq_Ring: @Ring (F q) 0 1 add mul sub opp eq Fq_Ring_ops. - Proof. - econstructor; eauto with typeclass_instances; - unfold R2, equality, eq_notation, addition, add_notation, one, one_notation, - multiplication, mul_notation, zero, zero_notation, subtraction, - sub_notation, opposite, opp_notation; intros; ring. + discriminate. Qed. - Global Instance Fq_Cring: @Cring (F q) 0 1 add mul sub opp eq Fq_Ring_ops Fq_Ring. - Proof. - repeat intro. apply F_mul_comm. - Qed. - - Global Instance Fq_Integral_domain : @Integral_domain (F q) 0 1 add mul sub opp eq Fq_Ring_ops Fq_Ring Fq_Cring. - Proof. - econstructor; eauto using Fq_mul_zero_why, Fq_1_neq_0. - Qed. - - Lemma add_cancel_mul_r_nonzero {y : F q} (H : y <> 0) (x z : F q) - : x * y + z = (x + (z * (inv y))) * y. - Proof. field. Qed. - - Lemma sub_cancel_mul_r_nonzero {y : F q} (H : y <> 0) (x z : F q) - : x * y - z = (x - (z * (inv y))) * y. - Proof. field. Qed. - - Lemma add_cancel_l_nonzero {y : F q} (H : y <> 0) (z : F q) - : y + z = (1 + (z * (inv y))) * y. - Proof. field. Qed. - - Lemma sub_cancel_l_nonzero {y : F q} (H : y <> 0) (z : F q) - : y - z = (1 - (z * (inv y))) * y. - Proof. field. Qed. -End VariousModPrime. - -Section SquareRootsPrime5Mod8. - Context {q:Z} {prime_q: prime q} {q_5mod8 : q mod 8 = 5}. - - (* This is always true, but easier to check by computation than to prove *) - Context (sqrt_minus1_valid : ((ZToField 2 ^ Z.to_N (q / 4)) ^ 2 = @opp q 1)%F). - - Local Open Scope F_scope. - Add Field Ffield_8mod5 : (@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]). - - (* This is only the square root of -1 if q mod 8 is 3 or 5 *) - Definition sqrt_minus1 : F q := ZToField 2 ^ Z.to_N (q / 4). - - Lemma two_lt_q_5mod8 : 2 < q. - Proof. - pose proof (prime_ge_2 q _) as two_le_q. - apply Zle_lt_or_eq in two_le_q. - destruct two_le_q; auto. - subst_max. - discriminate. - Qed. - - (* square root mod q relies on the fact that q is 5 mod 8 *) - Definition sqrt_mod_q (a : F q) := - let b := a ^ Z.to_N (q / 8 + 1) in - (match (F_eq_dec (b ^ 2) a) with - | left A => b - | right A => (sqrt_minus1 * b)%F - end). - - Lemma eq_b4_a2 : forall x : F q, isSquare x -> - ((x ^ Z.to_N (q / 8 + 1)) ^ 2) ^ 2 = x ^ 2. - Proof. - intros. - destruct (F_eq_dec x 0). { - subst. - repeat rewrite Fq_pow_zero; try (intuition; discriminate). - intro false_eq. - assert (0 <= q / 8)%Z by zero_bounds. - assert (0 < q / 8 + 1) by omega. - replace 0%N with (Z.to_N 0) in * by auto. - apply Z2N.inj in false_eq; omega. - } { - rewrite F_pow_compose. - replace (2 * 2)%N with 4%N by auto. - rewrite F_pow_compose. - replace (4 * Z.to_N (q / 8 + 1))%N with (Z.to_N (q / 2 + 2))%N. + Definition sqrt_5mod8 (a : F q) : F q := + let b := a ^ Z.to_N (q / 8 + 1) in + if dec (b ^ 2 = a) + then b + else sqrt_minus1 * b. + + Lemma eq_b4_a2 (x : F q) (Hex:exists y, y*y = x) : + ((x ^ Z.to_N (q / 8 + 1)) ^ 2) ^ 2 = x ^ 2. + Proof. + pose proof two_lt_q_5mod8. + assert (0 <= q/8)%Z by (apply Z.div_le_lower_bound; rewrite ?Z.mul_0_r; omega). + assert (Z.to_N (q / 8 + 1) <> 0%N) by + (intro Hbad; change (0%N) with (Z.to_N 0%Z) in Hbad; rewrite Z2N.inj_iff in Hbad; omega). + destruct (dec (x = 0)); [subst; rewrite !pow_0_l by (trivial || lazy_decide); reflexivity|]. + rewrite !pow_pow_l. + + replace (Z.to_N (q / 8 + 1) * (2*2))%N with (Z.to_N (q / 2 + 2))%N. + Focus 2. { (* this is a boring but gnarly proof :/ *) + change (2*2)%N with (Z.to_N 4). + rewrite <- Z2N.inj_mul by zero_bounds. + apply Z2N.inj_iff; try zero_bounds. + rewrite <- Z.mul_cancel_l with (p := 2) by omega. + ring_simplify. + rewrite Z.mul_div_eq by omega. + rewrite Z.mul_div_eq by omega. + rewrite (Zmod_div_mod 2 8 q) by + (try omega; apply Zmod_divide; omega || auto). + rewrite q_5mod8. + replace (5 mod 2)%Z with 1%Z by auto. + ring. + } Unfocus. + + rewrite Z2N.inj_add, pow_add_r by zero_bounds. + replace (x ^ Z.to_N (q / 2)) with (@ZToField q 1) by + (symmetry; apply @euler_criterion; eauto). + change (Z.to_N 2) with 2%N; ring. + Qed. - Focus 2. - replace 4%N with (Z.to_N 4) by auto. - rewrite <- Z2N.inj_mul by zero_bounds. - apply Z2N.inj_iff; try zero_bounds. - rewrite <- Z.mul_cancel_l with (p := 2) by omega. + Lemma sqrt_5mod8_valid : forall x, (exists y, y*y = x) -> + (sqrt_5mod8 x)*(sqrt_5mod8 x) = x. + Proof. + intros x x_square. + pose proof (eq_b4_a2 x x_square) as Hyy; rewrite !pow_2_r in Hyy. + destruct (Algebra.only_two_square_roots_choice _ x (x*x) Hyy eq_refl) as [Hb|Hb]; clear Hyy; + unfold sqrt_5mod8; break_if; rewrite !@pow_2_r in *; intuition. ring_simplify. - rewrite Z.mul_div_eq by omega. - rewrite Z.mul_div_eq by omega. - rewrite (Zmod_div_mod 2 8 q) by - (try omega; apply Zmod_divide; omega || auto). - rewrite q_5mod8. - replace (5 mod 2)%Z with 1%Z by auto. - ring. - (* End Focus *) - - rewrite Z2N.inj_add by zero_bounds. - rewrite <- F_pow_add by zero_bounds. - replace (x ^ Z.to_N (q / 2)) with (@ZToField q 1). - replace (Z.to_N 2) with 2%N by auto. - ring. - - symmetry; apply euler_criterion_F; auto using two_lt_q_5mod8. - } - Qed. - - Lemma sqrt_mod_q_valid : forall x, isSquare x -> - (sqrt_mod_q x) ^ 2 = x. - Proof. - intros x x_square. - destruct (sqrt_solutions x _ (eq_b4_a2 x x_square)) as [? | eq_b2_oppx]; - unfold sqrt_mod_q; break_if; intuition. - ring_simplify. - unfold sqrt_minus1. - rewrite sqrt_minus1_valid. - rewrite eq_b2_oppx. - field. - Qed. - - Lemma sqrt_mod_q_of_0 : sqrt_mod_q 0 = 0. - Proof. - unfold sqrt_mod_q. - rewrite !Fq_pow_zero. - break_if; ring. - - congruence. - intro false_eq. - rewrite <-(N2Z.id 0) in false_eq. - rewrite N2Z.inj_0 in false_eq. - pose proof (prime_ge_2 q prime_q). - apply Z2N.inj in false_eq; zero_bounds. - assert (0 < q / 8 + 1)%Z. - apply Z.add_nonneg_pos; zero_bounds. - omega. - Qed. - - Lemma sqrt_mod_q_root_0 : forall x : F q, sqrt_mod_q x = 0 -> x = 0. - Proof. - unfold sqrt_mod_q; intros. - break_if. - - match goal with [ H : ?sqrt_x ^ 2 = x, H' : ?sqrt_x = 0 |- _ ] => rewrite <-H, H' end. + unfold sqrt_minus1; rewrite @pow_2_r. + rewrite sqrt_minus1_valid; rewrite @pow_2_r. + rewrite Hb. ring. - - match goal with - | [H : sqrt_minus1 * _ = 0 |- _ ]=> - apply Fq_mul_zero_why in H; destruct H as [sqrt_minus1_zero | ? ]; - [ | eapply Fq_root_zero; eauto ] - end. - unfold sqrt_minus1 in sqrt_minus1_zero. - rewrite sqrt_minus1_zero in sqrt_minus1_valid. - exfalso. - pose proof (@F_opp_spec q 1) as opp_spec_1. - rewrite <-sqrt_minus1_valid in opp_spec_1. - assert (((1 + 0 ^ 2) : F q) = (1 : F q)) as ring_subst by ring. - rewrite ring_subst in *. - apply Fq_1_neq_0; assumption. - Qed. - -End SquareRootsPrime5Mod8. - -Local Open Scope F_scope. -(** Tactics for solving inequalities. *) -Ltac solve_cancel_by_field y tnz := - solve [ generalize dependent y; intros; - field; tnz ]. - -Ltac cancel_nonzero_factors' tnz := - idtac; - match goal with - | [ |- ?x = 0 -> False ] - => change (x <> 0) - | [ |- ?x * ?y <> 0 ] - => apply Fq_mul_nonzero_nonzero - | [ H : ?y <> 0 |- _ ] - => progress rewrite ?(add_cancel_mul_r_nonzero H), ?(sub_cancel_mul_r_nonzero H), ?(add_cancel_l_nonzero H), ?(sub_cancel_l_nonzero H); - apply Fq_mul_nonzero_nonzero; [ | assumption ] - | [ |- ?op (?y * (ZToField (m := ?q) ?n)) ?z <> 0 ] - => unique assert (ZToField (m := q) n <> 0) by tnz; - generalize dependent (ZToField (m := q) n); intros - | [ |- ?op (?x * (?y * ?z)) _ <> 0 ] - => rewrite F_mul_assoc - end. -Ltac cancel_nonzero_factors tnz := repeat cancel_nonzero_factors' tnz. -Ltac specialize_quantified_equalities := - repeat match goal with - | [ H : forall _ _ _ _, _ = _ -> _, H' : _ = _ |- _ ] - => unique pose proof (fun x2 y2 => H _ _ x2 y2 H') - | [ H : forall _ _, _ = _ -> _, H' : _ = _ |- _ ] - => unique pose proof (H _ _ H') - end. -Ltac finish_inequality tnz := - idtac; - match goal with - | [ H : ?x <> 0 |- ?y <> 0 ] - => replace y with x by (field; tnz); exact H - end. -Ltac field_nonzero tnz := - cancel_nonzero_factors tnz; - try (specialize_quantified_equalities; - progress cancel_nonzero_factors tnz); - try solve [ specialize_quantified_equalities; - finish_inequality tnz ]. + Qed. + End SquareRootsPrime5Mod8. +End Zmod.
\ No newline at end of file |