import Mathlib.RingTheory.Polynomial.Basic import Goppadecoding.prod import Goppadecoding.char2 import Goppadecoding.vanishing import Goppadecoding.finite_perfect open Polynomial BigOperators namespace Goppadecoding section goppa_squaring variable {U: Type _} [DecidableEq U] variable {k: Type _} [Field k] [CharP k 2] [DecidableEq k] theorem goppa_squaring [PerfectRing k 2] {α c: U → k} {S: Finset U} {A P g: k[X]} (Adef: A = monic_vanishing_at α S) (gsqfree: Squarefree g) (gA: IsCoprime g A) (cinF2: (∀ s, s ∈ S → c s = 0 ∨ c s = 1)) (Pdef: P = (∑ s in S, C (c s) * monic_vanishing_at_except α S s)) : (g ∣ P ↔ g^2 ∣ P) := by let Y := ∏ s in S.filter (fun s ↦ c s ≠ 0), (X - C (α s)) let Z := ∏ s in S.filter (fun s ↦ c s = 0), (X - C (α s)) have YZ: Y*Z = A := by calc _ = (∏ s in S.filter (fun s ↦ ¬ c s = 0), (X - C (α s))) * (∏ s in S.filter (fun s ↦ c s = 0), (X - C (α s))) := by rfl _ = ∏ s in S, (X - C (α s)) := by apply prod_filter_not_mul_prod_filter _ = monic_vanishing_at α S := by rfl _ = A := by rw[Adef] have gYZ: IsCoprime g (Y*Z) := by rw[YZ]; exact gA have gZ: IsCoprime g Z := IsCoprime.of_mul_right_right gYZ have Yprime: Y.diff = ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α (S.filter (fun s ↦ c s ≠ 0)) s := by calc _ = (monic_vanishing_at α (S.filter (fun s ↦ c s ≠ 0))).diff := by rfl _ = ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α (S.filter (fun s ↦ c s ≠ 0)) s := by apply derivative_monic_vanishing_at have ZYprime: Z * Y.diff = ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α S s := by calc _ = Z * ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α (S.filter (fun t ↦ c t ≠ 0)) s := by rw[Yprime] _ = ∑ s in S.filter (fun s ↦ c s ≠ 0), Z * monic_vanishing_at_except α (S.filter (fun t ↦ c t ≠ 0)) s := by rw[Finset.mul_sum] _ = ∑ s in S.filter (fun s ↦ c s ≠ 0), (∏ t in S.filter (fun t ↦ c t = 0), (X - C (α t))) * ∏ t in ((S.filter (fun t ↦ c t ≠ 0)).erase s), (X - C (α t)) := by rfl _ = ∑ s in S.filter (fun s ↦ c s ≠ 0), ∏ t in S.erase s, (X - C (α t)) := by apply Finset.sum_congr simp only [ne_eq] intro s sY have union: S.erase s = (S.filter (fun t ↦ c t = 0)) ∪ ((S.filter (fun t ↦ c t ≠ 0)).erase s) := by rw[erase_eq_filter_not_union_filter_erase sY] simp only [ne_eq, not_not, Finset.mem_filter, not_and] have disjoint: Disjoint (S.filter (fun t ↦ c t = 0)) ((S.filter (fun t ↦ c t ≠ 0)).erase s) := by apply disjoint_filter_not_filter_erase rw[prod_eq_disjoint_union union disjoint (fun t ↦ X - C (α t))] _ = _ := by rfl have ZYprime2: Z * Y.diff = ∑ s in S, C (c s) * monic_vanishing_at_except α S s := by calc _ = ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α S s := ZYprime _ = 0 + ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α S s := by group _ = (∑ s in S.filter (fun s ↦ c s = 0), 0) + ∑ s in S.filter (fun s ↦ c s ≠ 0), monic_vanishing_at_except α S s := by rw[Finset.sum_const_zero] _ = ∑ s in S, if c s = 0 then 0 else monic_vanishing_at_except α S s := by rw[Finset.sum_ite] _ = _ := by apply Finset.sum_congr simp only intro s sinS by_cases cs0: c s = 0 . simp only [cs0, ite_true, map_zero, zero_mul] . simp only [cs0, ite_false, ne_eq] have cs0or1: c s = 0 ∨ c s = 1 := cinF2 s sinS rw[or_iff_not_imp_left] at cs0or1 have cs1: c s = 1 := cs0or1 cs0 simp only [cs1, map_one, one_mul] have ZYprimeP: Z * Y.diff = P := by rw[ZYprime2,Pdef] constructor . intro gdivP have gYprime: g ∣ Y.diff := by have gZYprime: g ∣ Z * Y.diff := by rw[ZYprimeP]; exact gdivP exact dvd_if_dvd_mul_left gZ gZYprime have ggYprime: g^2 ∣ Y.diff := squarefree_dvd_derivative gsqfree gYprime rw[← ZYprimeP] exact Dvd.dvd.mul_left ggYprime Z . intro g2P rw[sq] at g2P exact dvd_of_mul_right_dvd g2P theorem goppa_squaring_finite [Fintype k] {α c: U → k} {S: Finset U} {A P g: k[X]} (Adef: A = monic_vanishing_at α S) (sqfree: Squarefree g) (gA: IsCoprime g A) (cinF2: (∀ s, s ∈ S → c s = 0 ∨ c s = 1)) (Pdef: P = (∑ s in S, C (c s) * monic_vanishing_at_except α S s)) : (g ∣ P ↔ g^2 ∣ P) := goppa_squaring Adef sqfree gA cinF2 Pdef end goppa_squaring