aboutsummaryrefslogtreecommitdiff
path: root/src/Galois/GaloisField.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/Galois/GaloisField.v')
-rw-r--r--src/Galois/GaloisField.v259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/Galois/GaloisField.v b/src/Galois/GaloisField.v
new file mode 100644
index 000000000..73eb17549
--- /dev/null
+++ b/src/Galois/GaloisField.v
@@ -0,0 +1,259 @@
+Require Import BinInt BinNat ZArith Znumtheory.
+Require Import BoolEq Field_theory.
+Require Export Crypto.Galois.Galois Crypto.Galois.GaloisTheory.
+Require Import Crypto.Tactics.VerdiTactics.
+
+(* This file is for the actual field tactics and some specialized
+ * morphisms that help field operate.
+ *
+ * When you want a Galois Field, this is the /only module/ you
+ * should import, because it automatically pulls in everything
+ * from Galois and the Modulus.
+ *)
+Module GaloisField (M: Modulus).
+ Module G := Galois M.
+ Module T := GaloisTheory M.
+ Export M G T.
+
+ (* 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 GFring_morph:
+ ring_morph GFzero GFone GFplus GFmult GFminus GFopp eq
+ 0%Z 1%Z Zplus Zmult Zminus Zopp Zeq_bool
+ inject.
+ Proof.
+ constructor; intros; try galois;
+ try (apply gf_eq; simpl; intuition).
+
+ apply Zmod_small; destruct modulus; simpl;
+ apply prime_ge_2 in p; intuition.
+
+ replace (- (x mod modulus)) with (0 - (x mod modulus));
+ try rewrite Zminus_mod_idemp_r; trivial.
+
+ replace x with y; intuition.
+ symmetry; apply Zeq_bool_eq; trivial.
+ Qed.
+
+ (* Redefine our division theory under the ring morphism *)
+ Lemma GFmorph_div_theory:
+ div_theory eq Zplus Zmult inject 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.
+
+ (* Some simple utility lemmas *)
+ Lemma injectZeroIsGFZero :
+ GFzero = inject 0.
+ Proof.
+ apply gf_eq; simpl; trivial.
+ Qed.
+
+ Lemma injectOneIsGFOne :
+ GFone = inject 1.
+ Proof.
+ apply gf_eq; simpl; intuition.
+ symmetry; apply Zmod_small; destruct modulus; simpl;
+ apply prime_ge_2 in p; intuition.
+ Qed.
+
+ Lemma divOneIsX :
+ forall (x: GF), (x / 1)%GF = x.
+ Proof.
+ intros; unfold GFdiv.
+
+ replace (GFinv 1)%GF with 1%GF by (
+ replace (GFinv 1)%GF with (GFinv 1 * 1)%GF by ring;
+ rewrite GF_multiplicative_inverse; intuition).
+
+ ring.
+ Qed.
+
+ Lemma exist_neq: forall A (P: A -> Prop) x y Px Py, x <> y -> exist P x Px <> exist P y Py.
+ Proof.
+ intuition; solve_by_inversion.
+ Qed.
+
+ (* Change all GFones to (inject 1) and GFzeros to (inject 0) so that
+ * we can use our ring morphism to simplify them
+ *)
+ Ltac GFpreprocess :=
+ repeat rewrite injectZeroIsGFZero;
+ repeat rewrite injectOneIsGFOne.
+
+ (* Split up the equation (because field likes /\, then
+ * change back all of our GFones and GFzeros.
+ *
+ * TODO (adamc): what causes it to generate these subproofs?
+ *)
+ Ltac GFpostprocess :=
+ repeat split;
+
+ repeat match goal with
+ | [ |- context[exist ?a ?b (inject_subproof ?x)] ] =>
+ replace (exist a b (inject_subproof x)) with (inject x%Z) by reflexivity
+ end;
+
+ repeat rewrite <- injectZeroIsGFZero;
+ repeat rewrite <- injectOneIsGFOne;
+ repeat rewrite divOneIsX.
+
+ (* Tactic to passively convert from GF to Z in special circumstances *)
+ Ltac GFconstant t :=
+ match t with
+ | inject ?x => x
+ | _ => NotConstant
+ end.
+
+ (* Add our ring with all the fixin's *)
+ Add Ring GFring_Z : GFring_theory
+ (morphism GFring_morph,
+ constants [GFconstant],
+ div GFmorph_div_theory,
+ power_tac GFpower_theory [GFexp_tac]).
+
+ (* Add our field with all the fixin's *)
+ Add Field GFfield_Z : GFfield_theory
+ (morphism GFring_morph,
+ preprocess [GFpreprocess],
+ postprocess [GFpostprocess],
+ constants [GFconstant],
+ div GFmorph_div_theory,
+ power_tac GFpower_theory [GFexp_tac]).
+
+ Local Open Scope GF_scope.
+
+ Lemma GF_mul_eq : forall x y z, z <> 0 -> x * z = y * z -> x = y.
+ Proof.
+ intros ? ? ? z_nonzero mul_z_eq.
+ replace x with (x * 1) by field.
+ rewrite <- (GF_multiplicative_inverse z_nonzero).
+ replace (x * (GFinv z * z)) with ((x * z) * GFinv z) by ring.
+ rewrite mul_z_eq.
+ replace (y * z * GFinv z) with (y * (GFinv z * z)) by ring.
+ rewrite GF_multiplicative_inverse; auto; field.
+ Qed.
+
+ Lemma GF_mul_0_l : forall x, 0 * x = 0.
+ Proof.
+ intros; field.
+ Qed.
+
+ Lemma GF_mul_0_r : forall x, x * 0 = 0.
+ Proof.
+ intros; field.
+ Qed.
+
+ Definition GF_eq_dec : forall x y : GF, {x = y} + {x <> y}.
+ intros.
+ assert (H := Z.eq_dec (inject x) (inject y)).
+
+ destruct H.
+
+ - left; galois; intuition.
+
+ - right; intuition.
+ rewrite H in n.
+ assert (y = y); intuition.
+ Qed.
+
+ Lemma mul_nonzero_l : forall a b, a*b <> 0 -> a <> 0.
+ intros; intuition; subst.
+ assert (0 * b = 0) by field; intuition.
+ Qed.
+
+ Lemma mul_nonzero_r : forall a b, a*b <> 0 -> b <> 0.
+ intros; intuition; subst.
+ assert (a * 0 = 0) by field; intuition.
+ Qed.
+
+ Lemma mul_zero_why : forall a b, a*b = 0 -> a = 0 \/ b = 0.
+ intros.
+ assert (Z := GF_eq_dec a 0); destruct Z.
+
+ - left; intuition.
+
+ - assert (a * b / a = 0) by
+ ( rewrite H; field; intuition ).
+
+ field_simplify in H0.
+ replace (b/1) with b in H0 by (field; intuition).
+ right; intuition.
+ apply n in H0; intuition.
+ Qed.
+
+ Lemma mul_nonzero_nonzero : forall a b, a <> 0 -> b <> 0 -> a*b <> 0.
+ intros; intuition; subst.
+ apply mul_zero_why in H1.
+ destruct H1; subst; intuition.
+ Qed.
+ Hint Resolve mul_nonzero_nonzero.
+
+ Lemma GFexp_distr_mul : forall x y 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; [ field | |
+ 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 (GFexp_pred x) by apply N.neq_succ_0.
+ rewrite (GFexp_pred y) by apply N.neq_succ_0.
+ rewrite (GFexp_pred (x * y)) by apply N.neq_succ_0.
+ rewrite N.pred_succ.
+ rewrite <- IHz'.
+ field.
+ Qed.
+
+ Lemma GF_square_mul : forall x y z, (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. {
+ unfold GFdiv, GFexp, GFexp'.
+ replace (GFinv (y * y)) with (GFinv y * GFinv y); try ring.
+ unfold GFinv.
+ destruct (N.eq_dec (N.pred (totientToN totient)) 0) as [ eq_zero | neq_zero ];
+ [ rewrite eq_zero | rewrite GFexp_distr_mul ]; try field.
+ simpl.
+ do 2 rewrite <- Z2N.inj_pred.
+ replace 0%N with (Z.to_N 0%Z) by auto.
+ apply Z2N.inj_le; modulus_bound.
+ }
+ assert (y ^ 2 <> 0) as y2_nonzero by (apply mul_nonzero_nonzero; auto).
+ rewrite (GF_mul_eq _ z (y ^ 2)); auto.
+ unfold GFdiv.
+ rewrite <- A.
+ field; auto.
+ Qed.
+
+ Lemma sqrt_solutions : forall x y, y ^ 2 = x ^ 2 -> y = x \/ y = GFopp x.
+ Proof.
+ intros.
+ (* TODO(jadep) *)
+ Admitted.
+
+ Lemma GFopp_swap : forall x y, GFopp x = y <-> x = GFopp y.
+ Proof.
+ split; intro; subst; field.
+ Qed.
+
+ Lemma GFopp_involutive : forall x, GFopp (GFopp x) = x.
+ Proof.
+ intros; field.
+ Qed.
+
+End GaloisField.