import Mathlib import Definitions.Def_TateCurve_XMultDistinctRouteB import Definitions.Def_TateCurve_TateFiltrationPrep import Definitions.Def_TateCurve_KeystoneVocab import Theorems.Thm_TateCurve_symAddHyps_unconditional import Theorems.Thm_TateCurve_diffHyp_unconditional import Theorems.Thm_TateCurve_eq_zero_or_eq_tateParam_unconditional set_option linter.unusedSectionVars false set_option autoImplicit false universe u namespace WeierstrassCurve variable {F : Type u} [Field F] [DecidableEq F] (W : WeierstrassCurve F) abbrev n_torsionGen (n : ℕ) : Type u := Submodule.torsionBy ℤ W.toAffine.Point n end WeierstrassCurve namespace WeierstrassCurve.Affine variable {F : Type*} [Field F] [DecidableEq F] {W : WeierstrassCurve F} lemma addX_sub_addX_negY_mul_sq {x₁ x₂ : F} (y₁ y₂ : F) (hx : x₁ ≠ x₂) : (W.toAffine.addX x₁ x₂ (W.toAffine.slope x₁ x₂ y₁ y₂) - W.toAffine.addX x₁ x₂ (W.toAffine.slope x₁ x₂ y₁ (W.toAffine.negY x₂ y₂))) * (x₁ - x₂) ^ 2 = -((y₁ - W.toAffine.negY x₁ y₁) * (y₂ - W.toAffine.negY x₂ y₂)) := by have e₁ := addX_mul_sq_of_X_ne (W := W.toAffine) y₁ y₂ hx have e₂ := addX_mul_sq_of_X_ne (W := W.toAffine) y₁ (W.toAffine.negY x₂ y₂) hx rw [sub_mul, e₁, e₂] simp only [negY] ring end WeierstrassCurve.Affine open WeierstrassCurve.Affine namespace TateCurve variable {K : Type*} [NontriviallyNormedField K] [IsUltrametricDist K] [CompleteSpace K] [CharZero K] [DecidableEq K] variable {q u v w ζ t : K} {p : ℕ} lemma sub_negY_curve (q x y : K) : y - (curve q).toAffine.negY x y = 2 * y + x := by rw [negY] show y - (-y - (curve q).a₁ * x - (curve q).a₃) = 2 * y + x rw [curve_a₁, curve_a₃] ring private lemma point_some_congr {W : WeierstrassCurve K} {x x' y y' : K} (hx : x = x') (hy : y = y') (h : W.toAffine.Nonsingular x y) (h' : W.toAffine.Nonsingular x' y') : (Point.some x y h : W.toAffine.Point) = Point.some x' y' h' := by subst hx; subst hy; rfl section LatticeHelpers private lemma zpow_ne_one_of_norm_lt_one (hq : ‖q‖₊ < 1) {m : ℤ} (hm : m ≠ 0) : q ^ m ≠ 1 := by have hpos : ∀ n : ℕ, n ≠ 0 → q ^ n ≠ 1 := by intro n hn hcontra have h1 : ‖q ^ n‖₊ = 1 := by rw [hcontra, nnnorm_one] have h2 : ‖q ^ n‖₊ < 1 := by rw [nnnorm_pow] exact pow_lt_one₀ zero_le hq hn exact absurd h1 (ne_of_lt h2) intro hcontra rcases lt_trichotomy m 0 with hneg | hzero | hpos' · have h1 : q ^ (-m) = 1 := by have h2 : (q ^ m)⁻¹ = (1 : K)⁻¹ := by rw [hcontra] rwa [← zpow_neg, inv_one] at h2 have h2 : q ^ ((-m).toNat) = 1 := by rw [← zpow_natCast, Int.toNat_of_nonneg (by omega)] exact h1 exact hpos (-m).toNat (by omega) h2 · exact hm hzero · have h2 : q ^ (m.toNat) = 1 := by rw [← zpow_natCast, Int.toNat_of_nonneg (by omega)] exact hcontra exact hpos m.toNat (by omega) h2 private lemma zpow_left_injective_of_norm_lt_one (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) {m n : ℤ} (h : q ^ m = q ^ n) : m = n := by by_contra hmn apply zpow_ne_one_of_norm_lt_one hq (sub_ne_zero.mpr hmn) rw [sub_eq_add_neg, zpow_add₀ hq0, h, ← zpow_add₀ hq0, add_neg_cancel, zpow_zero] end LatticeHelpers section TateParameters variable {p : ℕ} lemma tateParam_ne_zero (hζ0 : ζ ≠ 0) (ht0 : t ≠ 0) {i j : ℕ} : ζ ^ i * t ^ j ≠ 0 := mul_ne_zero (pow_ne_zero i hζ0) (pow_ne_zero j ht0) lemma tateParam_pow (hζp : ζ ^ p = 1) (ht : t ^ p = q) (i j : ℕ) : (ζ ^ i * t ^ j) ^ p = q ^ (j : ℤ) := by have h1 : (ζ ^ i) ^ p = 1 := by rw [← pow_mul, mul_comm, pow_mul, hζp, one_pow] have h2 : (t ^ j) ^ p = q ^ j := by rw [← pow_mul, mul_comm, pow_mul, ht] rw [mul_pow, h1, h2, one_mul, zpow_natCast] lemma tateParam_offLattice (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) {i j : ℕ} (hi : i < p) (hj : j < p) (hij : ¬(i = 0 ∧ j = 0)) : OffLattice q (ζ ^ i * t ^ j) := by have hζp : ζ ^ p = 1 := hζ.pow_eq_one intro n hn have h1 : q ^ (n * (p : ℤ) + (j : ℤ)) = 1 := by have h2 : (q ^ n * (ζ ^ i * t ^ j)) ^ p = 1 := by rw [hn, one_pow] rwa [mul_pow, tateParam_pow hζp ht, ← zpow_natCast (q ^ n) p, ← zpow_mul, ← zpow_add₀ hq0] at h2 have h3 : n * (p : ℤ) + (j : ℤ) = 0 := by by_contra h exact zpow_ne_one_of_norm_lt_one hq h h1 have hn0 : n = 0 := by rcases lt_trichotomy n 0 with hneg | h0 | hpos · exfalso have hle : n * (p : ℤ) ≤ (-1) * (p : ℤ) := mul_le_mul_of_nonneg_right (by omega) (by positivity) omega · exact h0 · exfalso have hle : 1 * (p : ℤ) ≤ n * (p : ℤ) := mul_le_mul_of_nonneg_right (by omega) (by positivity) omega have hj0 : j = 0 := by have h4 : (j : ℤ) = 0 := by rw [hn0] at h3 simpa using h3 exact_mod_cast h4 have hi0 : i ≠ 0 := fun h => hij ⟨h, hj0⟩ have h5 : ζ ^ i = 1 := by have h6 := hn rw [hn0, zpow_zero, one_mul, hj0, pow_zero, mul_one] at h6 exact h6 exact hi0 (hζ.pow_inj hi (by omega) (by rw [h5, pow_zero])) lemma tateParam_class_eq (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (ht0 : t ≠ 0) {i j i' j' : ℕ} (hi : i < p) (hj : j < p) (hi' : i' < p) (hj' : j' < p) {k : ℤ} (hk : ζ ^ i' * t ^ j' = q ^ k * (ζ ^ i * t ^ j)) : i = i' ∧ j = j' := by have hζp : ζ ^ p = 1 := hζ.pow_eq_one have hpow : (q : K) ^ (j' : ℤ) = q ^ (k * (p : ℤ) + (j : ℤ)) := by have h1 : (ζ ^ i' * t ^ j') ^ p = (q ^ k * (ζ ^ i * t ^ j)) ^ p := by rw [hk] rwa [tateParam_pow hζp ht, mul_pow, tateParam_pow hζp ht, ← zpow_natCast (q ^ k) p, ← zpow_mul, ← zpow_add₀ hq0] at h1 have hjj : (j' : ℤ) = k * (p : ℤ) + (j : ℤ) := zpow_left_injective_of_norm_lt_one hq0 hq hpow have hk0 : k = 0 := by rcases lt_trichotomy k 0 with hneg | h0 | hpos · exfalso have hle : k * (p : ℤ) ≤ (-1) * (p : ℤ) := mul_le_mul_of_nonneg_right (by omega) (by positivity) omega · exact h0 · exfalso have hle : 1 * (p : ℤ) ≤ k * (p : ℤ) := mul_le_mul_of_nonneg_right (by omega) (by positivity) omega have hjeq : j = j' := by have h4 : (j' : ℤ) = (j : ℤ) := by rw [hjj, hk0]; ring exact_mod_cast h4.symm have hieq : i = i' := by have h2 : ζ ^ i' * t ^ j = ζ ^ i * t ^ j := by have h3 := hk rw [hk0, zpow_zero, one_mul, ← hjeq] at h3 exact h3 have h4 : ζ ^ i' = ζ ^ i := mul_right_cancel₀ (pow_ne_zero j ht0) h2 exact hζ.pow_inj hi hi' h4.symm exact ⟨hieq, hjeq⟩ end TateParameters lemma point_inv_eq_neg (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hu0 : u ≠ 0) (hu : OffLattice q u) (h₁ : (curve q).toAffine.Nonsingular (pointX q u⁻¹) (pointY q u⁻¹)) (h₂ : (curve q).toAffine.Nonsingular (pointX q u) (pointY q u)) : (Point.some (pointX q u⁻¹) (pointY q u⁻¹) h₁ : (curve q).toAffine.Point) = -Point.some (pointX q u) (pointY q u) h₂ := by rw [Point.neg_some] refine point_some_congr (pointX_inv hq0 hu0 hu) ?_ h₁ _ rw [pointY_inv hq0 hq hu0 hu, negY] show -pointY q u - pointX q u = -pointY q u - (curve q).a₁ * pointX q u - (curve q).a₃ rw [curve_a₁, curve_a₃] ring theorem point_mul_eq_add_or_sub_of_symAddHyps (hyps : SymAddHyps q) (hp : AddParams q v w) (hxne : pointX q v ≠ pointX q w) (h₁ : (curve q).toAffine.Nonsingular (pointX q (v * w)) (pointY q (v * w))) (h₂ : (curve q).toAffine.Nonsingular (pointX q v) (pointY q v)) (h₃ : (curve q).toAffine.Nonsingular (pointX q w) (pointY q w)) : (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q v) (pointY q v) h₂ + Point.some (pointX q w) (pointY q w) h₃ ∨ (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = -(Point.some (pointX q v) (pointY q v) h₂ + Point.some (pointX q w) (pointY q w) h₃) ∨ (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q v) (pointY q v) h₂ - Point.some (pointX q w) (pointY q w) h₃ ∨ (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = -(Point.some (pointX q v) (pointY q v) h₂ - Point.some (pointX q w) (pointY q w) h₃) := by have hd2 : (pointX q v - pointX q w) ^ 2 ≠ 0 := pow_ne_zero 2 (sub_ne_zero.mpr hxne) have hS1 := hyps.sum v w hp have hS2 := hyps.prod v w hp rw [symSumNum_eq_b] at hS1 rw [symProdNum_eq_b] at hS2 have hsum := WeierstrassCurve.Affine.addX_add_addX_negY_mul_sq' (W := curve q) h₂.left h₃.left hxne have hprod := WeierstrassCurve.Affine.addX_mul_addX_negY_mul_sq (W := (curve q).toAffine) h₂.left h₃.left hxne have hsumEq : pointX q (v * w) + pointX q (v * w⁻¹) = (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w)) + (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w))) := mul_right_cancel₀ hd2 (hS1.trans hsum.symm) have hprodEq : pointX q (v * w) * pointX q (v * w⁻¹) = (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w)) * (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w))) := mul_right_cancel₀ hd2 (hS2.trans hprod.symm) have hroot : (pointX q (v * w) - (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w))) * (pointX q (v * w) - (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w)))) = 0 := by linear_combination pointX q (v * w) * hsumEq - hprodEq have hcond : ¬(pointX q v = pointX q w ∧ pointY q v = (curve q).toAffine.negY (pointX q w) (pointY q w)) := fun hxy => hxne hxy.left have hcond' : ¬(pointX q v = pointX q w ∧ pointY q v = (curve q).toAffine.negY (pointX q w) ((curve q).toAffine.negY (pointX q w) (pointY q w))) := fun hxy => hxne hxy.left rcases mul_eq_zero.mp hroot with hcase | hcase · have hxeq := sub_eq_zero.mp hcase have hns : (curve q).toAffine.Nonsingular ((curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w))) ((curve q).toAffine.addY (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w))) := WeierstrassCurve.Affine.nonsingular_add h₂ h₃ hcond rcases WeierstrassCurve.Affine.Y_eq_of_X_eq h₁.left hns.left hxeq with hyeq | hyeq · left rw [Point.add_of_X_ne hxne] exact point_some_congr hxeq hyeq h₁ _ · right; left rw [Point.add_of_X_ne hxne, Point.neg_some] exact point_some_congr hxeq hyeq h₁ _ · have hxeq := sub_eq_zero.mp hcase have hns : (curve q).toAffine.Nonsingular ((curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w)))) ((curve q).toAffine.addY (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w)))) := WeierstrassCurve.Affine.nonsingular_add h₂ ((nonsingular_neg _ _).mpr h₃) hcond' rcases WeierstrassCurve.Affine.Y_eq_of_X_eq h₁.left hns.left hxeq with hyeq | hyeq · right; right; left rw [sub_eq_add_neg, Point.neg_some, Point.add_of_X_ne hxne] exact point_some_congr hxeq hyeq h₁ _ · right; right; right rw [sub_eq_add_neg, Point.neg_some, Point.add_of_X_ne hxne, Point.neg_some] exact point_some_congr hxeq hyeq h₁ _ private lemma muT_norm_eq_one_of_isPrimitiveRoot (hζ : IsPrimitiveRoot ζ p) (hp0 : p ≠ 0) : ‖ζ‖ = 1 := by have h1 : ‖ζ‖ ^ p = 1 := by rw [← norm_pow, hζ.pow_eq_one, norm_one] rcases (pow_eq_one_iff_of_ne_zero hp0).mp h1 with h | ⟨h, _⟩ · exact h · exfalso have h2 := norm_nonneg ζ rw [h] at h2 linarith private lemma offLattice_zeta_pow' (hq0 : q ≠ 0) (hq1 : ‖q‖ < 1) (hζ : IsPrimitiveRoot ζ p) (hp0 : p ≠ 0) {k : ℕ} (hk : ¬ p ∣ k) : OffLattice q (ζ ^ k) := offLattice_of_norm_eq_one hq0 hq1 (by rw [norm_pow, muT_norm_eq_one_of_isPrimitiveRoot hζ hp0, one_pow]) (fun h1 => hk ((hζ.pow_eq_one_iff_dvd k).mp h1)) theorem point_mul_eq_add_or_neg_of_symAddHyps_of_diff (hyps : SymAddHyps q) (hd1 : (pointX q (v * w) - pointX q (v * w⁻¹)) * (pointX q v - pointX q w) ^ 2 = -((2 * pointY q v + pointX q v) * (2 * pointY q w + pointX q w))) (hp : AddParams q v w) (hxne : pointX q v ≠ pointX q w) (h₁ : (curve q).toAffine.Nonsingular (pointX q (v * w)) (pointY q (v * w))) (h₂ : (curve q).toAffine.Nonsingular (pointX q v) (pointY q v)) (h₃ : (curve q).toAffine.Nonsingular (pointX q w) (pointY q w)) : (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q v) (pointY q v) h₂ + Point.some (pointX q w) (pointY q w) h₃ ∨ (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = -(Point.some (pointX q v) (pointY q v) h₂ + Point.some (pointX q w) (pointY q w) h₃) := by have hd2 : (pointX q v - pointX q w) ^ 2 ≠ 0 := pow_ne_zero 2 (sub_ne_zero.mpr hxne) have hS1 := hyps.sum v w hp rw [symSumNum_eq_b] at hS1 have hsum := WeierstrassCurve.Affine.addX_add_addX_negY_mul_sq' (W := curve q) h₂.left h₃.left hxne have hsumEq : pointX q (v * w) + pointX q (v * w⁻¹) = (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w)) + (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w))) := mul_right_cancel₀ hd2 (hS1.trans hsum.symm) have hdiffC := WeierstrassCurve.Affine.addX_sub_addX_negY_mul_sq (W := curve q) (pointY q v) (pointY q w) hxne rw [sub_negY_curve, sub_negY_curve] at hdiffC have hdiffEq : pointX q (v * w) - pointX q (v * w⁻¹) = (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w)) - (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.negY (pointX q w) (pointY q w))) := mul_right_cancel₀ hd2 (hd1.trans hdiffC.symm) have hxeq : pointX q (v * w) = (curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w)) := by have h2 : (2 : K) ≠ 0 := by norm_num apply mul_left_cancel₀ h2 linear_combination hsumEq + hdiffEq have hcond : ¬(pointX q v = pointX q w ∧ pointY q v = (curve q).toAffine.negY (pointX q w) (pointY q w)) := fun hxy => hxne hxy.left have hns : (curve q).toAffine.Nonsingular ((curve q).toAffine.addX (pointX q v) (pointX q w) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w))) ((curve q).toAffine.addY (pointX q v) (pointX q w) (pointY q v) ((curve q).toAffine.slope (pointX q v) (pointX q w) (pointY q v) (pointY q w))) := WeierstrassCurve.Affine.nonsingular_add h₂ h₃ hcond rcases WeierstrassCurve.Affine.Y_eq_of_X_eq h₁.left hns.left hxeq with hyeq | hyeq · left rw [Point.add_of_X_ne hxne] exact point_some_congr hxeq hyeq h₁ _ · right rw [Point.add_of_X_ne hxne, Point.neg_some] exact point_some_congr hxeq hyeq h₁ _ theorem point_mul_eq_add_of_symAddHyps_of_diffHyp (hyps : SymAddHyps q) (hdiff : DiffHyp q) (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : AddParams q v w) (hxne : pointX q v ≠ pointX q w) (hp' : AddParams q (v * w) v⁻¹) (hxne' : pointX q (v * w) ≠ pointX q v) (h₁ : (curve q).toAffine.Nonsingular (pointX q (v * w)) (pointY q (v * w))) (h₂ : (curve q).toAffine.Nonsingular (pointX q v) (pointY q v)) (h₃ : (curve q).toAffine.Nonsingular (pointX q w) (pointY q w)) (hP2 : (Point.some (pointX q v) (pointY q v) h₂ : (curve q).toAffine.Point) + Point.some (pointX q v) (pointY q v) h₂ ≠ 0) : (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q v) (pointY q v) h₂ + Point.some (pointX q w) (pointY q w) h₃ := by have hvw0 : v * w ≠ 0 := mul_ne_zero hp.u_ne_zero hp.v_ne_zero have hprod0 : (v * w) * v⁻¹ ≠ 0 := mul_ne_zero hvw0 (inv_ne_zero hp.u_ne_zero) have h₄ : (curve q).toAffine.Nonsingular (pointX q ((v * w) * v⁻¹)) (pointY q ((v * w) * v⁻¹)) := nonsingular_point hq0 hq hprod0 hp'.offLattice_mul have hinv0 : v⁻¹ ≠ 0 := inv_ne_zero hp.u_ne_zero have hinvOff : OffLattice q v⁻¹ := OffLattice.inv hq0 hp.offLattice_u have h₅ : (curve q).toAffine.Nonsingular (pointX q v⁻¹) (pointY q v⁻¹) := nonsingular_point hq0 hq hinv0 hinvOff set R := (Point.some (pointX q (v * w)) (pointY q (v * w)) h₁ : (curve q).toAffine.Point) with hR_def set P := (Point.some (pointX q v) (pointY q v) h₂ : (curve q).toAffine.Point) with hP_def set Q := (Point.some (pointX q w) (pointY q w) h₃ : (curve q).toAffine.Point) with hQ_def have hxneDer : pointX q (v * w) ≠ pointX q v⁻¹ := by rw [pointX_inv hq0 hp.u_ne_zero hp.offLattice_u] exact hxne' have hder := point_mul_eq_add_or_neg_of_symAddHyps_of_diff hyps (hdiff (v * w) v⁻¹ hp') hp' hxneDer h₄ h₁ h₅ have helem : (v * w) * v⁻¹ = w := by rw [mul_comm v w, mul_assoc, mul_inv_cancel₀ hp.u_ne_zero, mul_one] have e₄ : (Point.some (pointX q ((v * w) * v⁻¹)) (pointY q ((v * w) * v⁻¹)) h₄ : (curve q).toAffine.Point) = Q := point_some_congr (congrArg (pointX q) helem) (congrArg (pointY q) helem) h₄ h₃ have e₅ : (Point.some (pointX q v⁻¹) (pointY q v⁻¹) h₅ : (curve q).toAffine.Point) = -P := point_inv_eq_neg hq0 hq hp.u_ne_zero hp.offLattice_u h₅ h₂ rw [e₄, e₅] at hder rcases hder with hder | hder · calc R = P + (R + -P) := by abel _ = P + Q := by rw [← hder] · rcases point_mul_eq_add_or_neg_of_symAddHyps_of_diff hyps (hdiff v w hp) hp hxne h₁ h₂ h₃ with hmain | hmain · exact hmain · exfalso apply hP2 have k1 : R + (P + Q) = 0 := by rw [hR_def, hmain]; abel have k2 : Q + (R + -P) = 0 := by rw [hder]; abel calc P + P = (R + (P + Q)) - (Q + (R + -P)) := by abel _ = 0 - 0 := by rw [k1, k2] _ = 0 := by abel theorem zeta_pow_mul_self_point_eq_add (hyps : SymAddHyps q) (hdiff : DiffHyp q) (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp5 : 5 ≤ p) (hpp : p.Prime) (hζ : IsPrimitiveRoot ζ p) {a : ℕ} (ha1 : 1 ≤ a) (hap : a < p) (h₁ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a))) (h₂ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a)) (pointY q (ζ ^ a))) : (Point.some (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ + Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ := by have hp0 : p ≠ 0 := by omega have hζ0 : ζ ≠ 0 := hζ.ne_zero hp0 have hζa0 : ζ ^ a ≠ 0 := pow_ne_zero _ hζ0 have hq1 : ‖q‖ < 1 := by exact_mod_cast hq have hnζ : ‖ζ‖ = 1 := muT_norm_eq_one_of_isPrimitiveRoot hζ hp0 have hnζa : ‖ζ ^ a‖ = 1 := by rw [norm_pow, hnζ, one_pow] have hndvd_a : ¬ p ∣ a := fun hdvd => absurd (Nat.le_of_dvd (by omega) hdvd) (by omega) have hndvd_2a : ¬ p ∣ a + a := by intro hdvd rw [← two_mul a] at hdvd rcases (Nat.Prime.dvd_mul hpp).mp hdvd with h2 | ha · exact absurd (Nat.le_of_dvd (by norm_num) h2) (by omega) · exact hndvd_a ha have hndvd_3a : ¬ p ∣ a + a + a := by intro hdvd have h3a : a + a + a = 3 * a := by ring rw [h3a] at hdvd rcases (Nat.Prime.dvd_mul hpp).mp hdvd with h3 | ha · exact absurd (Nat.le_of_dvd (by norm_num) h3) (by omega) · exact hndvd_a ha have hndvd_pa : ¬ p ∣ p - a := fun hdvd => absurd (Nat.le_of_dvd (by omega) hdvd) (by omega) have hζaOff : OffLattice q (ζ ^ a) := offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_a have hζ2aOff : OffLattice q (ζ ^ a * ζ ^ a) := by rw [← pow_add] exact offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_2a have hζpaOff : OffLattice q (ζ ^ (p - a)) := offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_pa have hpa_inv : ζ ^ (p - a) = (ζ ^ a)⁻¹ := by have hcancel : ζ ^ a * ζ ^ (p - a) = ζ ^ a * (ζ ^ a)⁻¹ := by rw [mul_inv_cancel₀ hζa0, ← pow_add, show a + (p - a) = p by omega, hζ.pow_eq_one] exact mul_left_cancel₀ hζa0 hcancel have helem1 : (ζ ^ a * ζ ^ a) * ζ ^ (p - a) = ζ ^ a := by rw [mul_assoc, ← pow_add, show a + (p - a) = p by omega, hζ.pow_eq_one, mul_one] have hpDouble : AddParams q (ζ ^ a * ζ ^ a) (ζ ^ (p - a)) := by refine ⟨hq0, mul_ne_zero hζa0 hζa0, pow_ne_zero _ hζ0, hζ2aOff, hζpaOff, ?_, ?_⟩ · rw [helem1]; exact hζaOff · have helem2 : (ζ ^ a * ζ ^ a) * (ζ ^ (p - a))⁻¹ = ζ ^ (a + a + a) := by rw [hpa_inv, inv_inv, ← pow_add, ← pow_add] rw [helem2] exact offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_3a have hxneDouble : pointX q (ζ ^ a * ζ ^ a) ≠ pointX q (ζ ^ (p - a)) := by intro hX rcases eq_or_mul_eq_one_of_pointX_eq hq0 hq (mul_ne_zero hζa0 hζa0) (pow_ne_zero _ hζ0) hζ2aOff hζpaOff (le_of_eq (by rw [norm_mul, hnζa, one_mul])) (le_of_eq (by rw [norm_pow, hnζ, one_pow])) (by rw [helem1, hnζa]; exact hq1) hX with heq | hone · apply hndvd_3a have h1 : ζ ^ (a + a + a) = 1 := by rw [pow_add, pow_add, heq, ← pow_add, show p - a + a = p by omega, hζ.pow_eq_one] exact (hζ.pow_eq_one_iff_dvd _).mp h1 · rw [helem1] at hone exact hndvd_a ((hζ.pow_eq_one_iff_dvd a).mp hone) have hprodNs : (curve q).toAffine.Nonsingular (pointX q ((ζ ^ a * ζ ^ a) * ζ ^ (p - a))) (pointY q ((ζ ^ a * ζ ^ a) * ζ ^ (p - a))) := nonsingular_point hq0 hq (mul_ne_zero (mul_ne_zero hζa0 hζa0) (pow_ne_zero _ hζ0)) hpDouble.offLattice_mul have hwNs : (curve q).toAffine.Nonsingular (pointX q (ζ ^ (p - a))) (pointY q (ζ ^ (p - a))) := nonsingular_point hq0 hq (pow_ne_zero _ hζ0) hζpaOff have hcase := point_mul_eq_add_or_neg_of_symAddHyps_of_diff hyps (hdiff (ζ ^ a * ζ ^ a) (ζ ^ (p - a)) hpDouble) hpDouble hxneDouble hprodNs h₁ hwNs have e1 : (Point.some (pointX q ((ζ ^ a * ζ ^ a) * ζ ^ (p - a))) (pointY q ((ζ ^ a * ζ ^ a) * ζ ^ (p - a))) hprodNs : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ := point_some_congr (congrArg (pointX q) helem1) (congrArg (pointY q) helem1) hprodNs h₂ have hwNs' : (curve q).toAffine.Nonsingular (pointX q ((ζ ^ a)⁻¹)) (pointY q ((ζ ^ a)⁻¹)) := by rw [← hpa_inv] exact hwNs have e2 : (Point.some (pointX q (ζ ^ (p - a))) (pointY q (ζ ^ (p - a))) hwNs : (curve q).toAffine.Point) = -(Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂) := by have e2' : (Point.some (pointX q (ζ ^ (p - a))) (pointY q (ζ ^ (p - a))) hwNs : (curve q).toAffine.Point) = Point.some (pointX q ((ζ ^ a)⁻¹)) (pointY q ((ζ ^ a)⁻¹)) hwNs' := point_some_congr (congrArg (pointX q) hpa_inv) (congrArg (pointY q) hpa_inv) hwNs hwNs' rw [e2'] exact point_inv_eq_neg hq0 hq hζa0 hζaOff hwNs' h₂ rw [e1, e2] at hcase set P2 := (Point.some (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a)) h₁ : (curve q).toAffine.Point) with hP2_def set P1 := (Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ : (curve q).toAffine.Point) with hP1_def rcases hcase with hc | hc · calc P2 = (P2 + -P1) + P1 := by abel _ = P1 + P1 := by rw [← hc] · exfalso have k : P1 + (P2 + -P1) = 0 := by nth_rewrite 1 [hc] abel have h0 : P2 = 0 := by calc P2 = P1 + (P2 + -P1) := by abel _ = 0 := k exact Point.some_ne_zero h₁ h0 private lemma muTranslation_aux (hyps : SymAddHyps q) (hdiff : DiffHyp q) (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp5 : 5 ≤ p) (hpp : p.Prime) (hζ : IsPrimitiveRoot ζ p) {a : ℕ} (ha1 : 1 ≤ a) (hap : a < p) {u : K} (hu0 : u ≠ 0) (hu : OffLattice q u) (hau : OffLattice q (ζ ^ a * u)) (hule : ‖u‖ ≤ 1) (hqlt : ‖q‖ < ‖u‖) (h₁ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u))) (h₂ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a)) (pointY q (ζ ^ a))) (h₃ : (curve q).toAffine.Nonsingular (pointX q u) (pointY q u)) : (Point.some (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ + Point.some (pointX q u) (pointY q u) h₃ := by have hp0 : p ≠ 0 := by omega have hζ0 : ζ ≠ 0 := hζ.ne_zero hp0 have hζa0 : ζ ^ a ≠ 0 := pow_ne_zero _ hζ0 have hq1 : ‖q‖ < 1 := by exact_mod_cast hq have hnζ : ‖ζ‖ = 1 := muT_norm_eq_one_of_isPrimitiveRoot hζ hp0 have hnζa : ‖ζ ^ a‖ = 1 := by rw [norm_pow, hnζ, one_pow] have hndvd_a : ¬ p ∣ a := fun hdvd => absurd (Nat.le_of_dvd (by omega) hdvd) (by omega) have hndvd_2a : ¬ p ∣ a + a := by intro hdvd rw [← two_mul a] at hdvd rcases (Nat.Prime.dvd_mul hpp).mp hdvd with h2 | ha · exact absurd (Nat.le_of_dvd (by norm_num) h2) (by omega) · exact hndvd_a ha have hζaOff : OffLattice q (ζ ^ a) := offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_a have hζ2aOff : OffLattice q (ζ ^ a * ζ ^ a) := by rw [← pow_add] exact offLattice_zeta_pow' hq0 hq1 hζ hp0 hndvd_2a have hDns : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a)) := nonsingular_point hq0 hq (mul_ne_zero hζa0 hζa0) hζ2aOff by_cases hC2 : OffLattice q (ζ ^ a * u⁻¹) · by_cases hC4 : OffLattice q (ζ ^ a * ζ ^ a * u) · have hpMain : AddParams q (ζ ^ a) u := ⟨hq0, hζa0, hu0, hζaOff, hu, hau, hC2⟩ have hxneMain : pointX q (ζ ^ a) ≠ pointX q u := by intro hX rcases eq_or_mul_eq_one_of_pointX_eq hq0 hq hζa0 hu0 hζaOff hu (le_of_eq hnζa) hule (by rw [norm_mul, hnζa, one_mul]; exact hqlt) hX with heq | hone · apply hC2 0 rw [zpow_zero, one_mul, heq, mul_inv_cancel₀ hu0] · exact hau 0 (by rw [zpow_zero, one_mul]; exact hone) have hpDer : AddParams q (ζ ^ a * u) (ζ ^ a)⁻¹ := by refine ⟨hq0, mul_ne_zero hζa0 hu0, inv_ne_zero hζa0, hau, OffLattice.inv hq0 hζaOff, ?_, ?_⟩ · have helem : (ζ ^ a * u) * (ζ ^ a)⁻¹ = u := by rw [mul_comm (ζ ^ a) u, mul_assoc, mul_inv_cancel₀ hζa0, mul_one] rw [helem]; exact hu · have helem : (ζ ^ a * u) * ((ζ ^ a)⁻¹)⁻¹ = ζ ^ a * ζ ^ a * u := by rw [inv_inv]; ring rw [helem]; exact hC4 have hxneDer : pointX q (ζ ^ a * u) ≠ pointX q (ζ ^ a) := by intro hX rcases eq_or_mul_eq_one_of_pointX_eq hq0 hq (mul_ne_zero hζa0 hu0) hζa0 hau hζaOff (by rw [norm_mul, hnζa, one_mul]; exact hule) (le_of_eq hnζa) (by rw [norm_mul, norm_mul, hnζa, one_mul, mul_one]; exact hqlt) hX with heq | hone · have hu1 : u = 1 := by have h := heq.trans (mul_one (ζ ^ a)).symm exact mul_left_cancel₀ hζa0 h exact hu 0 (by rw [zpow_zero, one_mul, hu1]) · apply hC4 0 rw [zpow_zero, one_mul] calc ζ ^ a * ζ ^ a * u = (ζ ^ a * u) * ζ ^ a := by ring _ = 1 := hone have hP2 : (Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ : (curve q).toAffine.Point) + Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ ≠ 0 := by intro h2tor have hodd : Odd p := hpp.odd_of_ne_two (by omega) have hpow : (ζ ^ a) ^ p = q ^ (0 : ℤ) := by rw [← pow_mul, mul_comm a p, pow_mul, hζ.pow_eq_one, one_pow, zpow_zero] have hptor : p • (Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ : (curve q).toAffine.Point) = 0 := nsmul_prime_eq_zero hyps hq0 hq hζa0 hζaOff hpow hpp hodd h₂ set PT := (Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ : (curve q).toAffine.Point) with hPT_def obtain ⟨k, hk⟩ := hodd have hk' : p = k + k + 1 := by omega have hpP : p • PT = PT := by calc p • PT = (k + k + 1) • PT := by rw [← hk'] _ = k • PT + k • PT + PT := by rw [add_nsmul, add_nsmul, one_nsmul] _ = k • (PT + PT) + PT := by rw [← nsmul_add] _ = PT := by rw [h2tor, smul_zero, zero_add] have h0 : PT = 0 := by rw [← hpP, hptor] exact Point.some_ne_zero h₂ h0 exact point_mul_eq_add_of_symAddHyps_of_diffHyp hyps hdiff hq0 hq hpMain hxneMain hpDer hxneDer h₁ h₂ h₃ hP2 · have hdouble := zeta_pow_mul_self_point_eq_add hyps hdiff hq0 hq hp5 hpp hζ ha1 hap hDns h₂ have hC4' : ∃ n : ℤ, q ^ n * (ζ ^ a * ζ ^ a * u) = 1 := by by_contra hcon exact hC4 (fun n hn => hcon ⟨n, hn⟩) obtain ⟨n, hn⟩ := hC4' have hqn0 : (q : K) ^ n ≠ 0 := zpow_ne_zero _ hq0 have hzu_eq : ζ ^ a * u = q ^ (-n) * (ζ ^ a)⁻¹ := by have hcancel : (q ^ n * ζ ^ a) * (ζ ^ a * u) = (q ^ n * ζ ^ a) * (q ^ (-n) * (ζ ^ a)⁻¹) := by rw [show (q ^ n * ζ ^ a) * (ζ ^ a * u) = q ^ n * (ζ ^ a * ζ ^ a * u) by ring, hn, show (q ^ n * ζ ^ a) * (q ^ (-n) * (ζ ^ a)⁻¹) = (q ^ n * q ^ (-n)) * (ζ ^ a * (ζ ^ a)⁻¹) by ring, ← zpow_add₀ hq0, show n + -n = 0 by omega, zpow_zero, mul_inv_cancel₀ hζa0, mul_one] exact mul_left_cancel₀ (mul_ne_zero hqn0 hζa0) hcancel have hu_eq : u = q ^ (-n) * (ζ ^ a * ζ ^ a)⁻¹ := by have hcancel : (q ^ n * (ζ ^ a * ζ ^ a)) * u = (q ^ n * (ζ ^ a * ζ ^ a)) * (q ^ (-n) * (ζ ^ a * ζ ^ a)⁻¹) := by rw [show (q ^ n * (ζ ^ a * ζ ^ a)) * u = q ^ n * (ζ ^ a * ζ ^ a * u) by ring, hn, show (q ^ n * (ζ ^ a * ζ ^ a)) * (q ^ (-n) * (ζ ^ a * ζ ^ a)⁻¹) = (q ^ n * q ^ (-n)) * ((ζ ^ a * ζ ^ a) * (ζ ^ a * ζ ^ a)⁻¹) by ring, ← zpow_add₀ hq0, show n + -n = 0 by omega, zpow_zero, mul_inv_cancel₀ (mul_ne_zero hζa0 hζa0), mul_one] exact mul_left_cancel₀ (mul_ne_zero hqn0 (mul_ne_zero hζa0 hζa0)) hcancel have hXzu : pointX q (ζ ^ a * u) = pointX q (ζ ^ a) := by rw [hzu_eq, pointX_zpow_mul hq0, pointX_inv hq0 hζa0 hζaOff] have hYzu : pointY q (ζ ^ a * u) = -pointY q (ζ ^ a) - pointX q (ζ ^ a) := by rw [hzu_eq, pointY_zpow_mul hq0, pointY_inv hq0 hq hζa0 hζaOff] have hXu : pointX q u = pointX q (ζ ^ a * ζ ^ a) := by rw [hu_eq, pointX_zpow_mul hq0, pointX_inv hq0 (mul_ne_zero hζa0 hζa0) hζ2aOff] have hYu : pointY q u = -pointY q (ζ ^ a * ζ ^ a) - pointX q (ζ ^ a * ζ ^ a) := by rw [hu_eq, pointY_zpow_mul hq0, pointY_inv hq0 hq (mul_ne_zero hζa0 hζa0) hζ2aOff] have hL : (Point.some (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u)) h₁ : (curve q).toAffine.Point) = -(Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂) := by rw [Point.neg_some] refine point_some_congr hXzu ?_ h₁ _ rw [hYzu, negY] show -pointY q (ζ ^ a) - pointX q (ζ ^ a) = -pointY q (ζ ^ a) - (curve q).a₁ * pointX q (ζ ^ a) - (curve q).a₃ rw [curve_a₁, curve_a₃] ring have hU : (Point.some (pointX q u) (pointY q u) h₃ : (curve q).toAffine.Point) = -(Point.some (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a)) hDns) := by rw [Point.neg_some] refine point_some_congr hXu ?_ h₃ _ rw [hYu, negY] show -pointY q (ζ ^ a * ζ ^ a) - pointX q (ζ ^ a * ζ ^ a) = -pointY q (ζ ^ a * ζ ^ a) - (curve q).a₁ * pointX q (ζ ^ a * ζ ^ a) - (curve q).a₃ rw [curve_a₁, curve_a₃] ring rw [hL, hU, hdouble] abel · have hdouble := zeta_pow_mul_self_point_eq_add hyps hdiff hq0 hq hp5 hpp hζ ha1 hap hDns h₂ have hC2' : ∃ n : ℤ, q ^ n * (ζ ^ a * u⁻¹) = 1 := by by_contra hcon exact hC2 (fun n hn => hcon ⟨n, hn⟩) obtain ⟨n, hn⟩ := hC2' have hu_eq : u = q ^ n * ζ ^ a := by have h1 : (q ^ n * (ζ ^ a * u⁻¹)) * u = u := by rw [hn, one_mul] have h2 : (q ^ n * ζ ^ a) * (u⁻¹ * u) = u := by calc (q ^ n * ζ ^ a) * (u⁻¹ * u) = (q ^ n * (ζ ^ a * u⁻¹)) * u := by ring _ = u := h1 rw [inv_mul_cancel₀ hu0, mul_one] at h2 exact h2.symm have hXu : pointX q u = pointX q (ζ ^ a) := by rw [hu_eq, pointX_zpow_mul hq0] have hYu : pointY q u = pointY q (ζ ^ a) := by rw [hu_eq, pointY_zpow_mul hq0] have hzu_eq : ζ ^ a * u = q ^ n * (ζ ^ a * ζ ^ a) := by rw [hu_eq]; ring have hXzu : pointX q (ζ ^ a * u) = pointX q (ζ ^ a * ζ ^ a) := by rw [hzu_eq, pointX_zpow_mul hq0] have hYzu : pointY q (ζ ^ a * u) = pointY q (ζ ^ a * ζ ^ a) := by rw [hzu_eq, pointY_zpow_mul hq0] have hL : (Point.some (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a * ζ ^ a)) (pointY q (ζ ^ a * ζ ^ a)) hDns := point_some_congr hXzu hYzu h₁ hDns have hU : (Point.some (pointX q u) (pointY q u) h₃ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ := point_some_congr hXu hYu h₃ h₂ rw [hL, hU] exact hdouble theorem muTranslation_of_symAddHyps_of_diffHyp (hyps : SymAddHyps q) (hdiff : DiffHyp q) (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp5 : 5 ≤ p) (hpp : p.Prime) (hζ : IsPrimitiveRoot ζ p) : MuTranslation q ζ p := by intro a ha1 hap u hu0 hu hau h₁ h₂ h₃ have hq1 : ‖q‖ < 1 := by exact_mod_cast hq have hqpos : (0 : ℝ) < ‖q‖ := norm_pos_iff.mpr hq0 have hupos : (0 : ℝ) < ‖u‖ := norm_pos_iff.mpr hu0 obtain ⟨m, hm⟩ := exists_mem_Ioc_zpow (x := ‖u‖) (y := ‖q‖⁻¹) hupos ((one_lt_inv₀ hqpos).mpr hq1) have hinv_zpow : ∀ k : ℤ, (‖q‖⁻¹) ^ k = ‖q‖ ^ (-k) := by intro k rw [inv_zpow, ← zpow_neg] set u' := q ^ (m + 1) * u with hu'_def have hu'0 : u' ≠ 0 := mul_ne_zero (zpow_ne_zero _ hq0) hu0 have hu' : OffLattice q u' := OffLattice.zpow_mul hq0 (m + 1) hu have hau' : OffLattice q (ζ ^ a * u') := by have helem : ζ ^ a * u' = q ^ (m + 1) * (ζ ^ a * u) := by rw [hu'_def]; ring rw [helem] exact OffLattice.zpow_mul hq0 (m + 1) hau have hnorm_u' : ‖u'‖ = ‖q‖ ^ (m + 1) * ‖u‖ := by rw [hu'_def, norm_mul, norm_zpow] have hu'le : ‖u'‖ ≤ 1 := by rw [hnorm_u'] have h1 : ‖u‖ ≤ ‖q‖ ^ (-(m + 1)) := by have h2 := hm.2 rwa [hinv_zpow (m + 1)] at h2 calc ‖q‖ ^ (m + 1) * ‖u‖ ≤ ‖q‖ ^ (m + 1) * ‖q‖ ^ (-(m + 1)) := mul_le_mul_of_nonneg_left h1 (le_of_lt (zpow_pos hqpos _)) _ = 1 := by rw [← zpow_add₀ (ne_of_gt hqpos), show m + 1 + -(m + 1) = 0 by omega, zpow_zero] have hu'gt : ‖q‖ < ‖u'‖ := by rw [hnorm_u'] have h1 : ‖q‖ ^ (-m) < ‖u‖ := by have h2 := hm.1 rwa [hinv_zpow m] at h2 calc ‖q‖ = ‖q‖ ^ (m + 1) * ‖q‖ ^ (-m) := by rw [← zpow_add₀ (ne_of_gt hqpos), show m + 1 + -m = 1 by omega, zpow_one] _ < ‖q‖ ^ (m + 1) * ‖u‖ := mul_lt_mul_of_pos_left h1 (zpow_pos hqpos _) have hXu' : pointX q u' = pointX q u := by rw [hu'_def, pointX_zpow_mul hq0] have hYu' : pointY q u' = pointY q u := by rw [hu'_def, pointY_zpow_mul hq0] have hzuelem : ζ ^ a * u' = q ^ (m + 1) * (ζ ^ a * u) := by rw [hu'_def]; ring have hXzu' : pointX q (ζ ^ a * u') = pointX q (ζ ^ a * u) := by rw [hzuelem, pointX_zpow_mul hq0] have hYzu' : pointY q (ζ ^ a * u') = pointY q (ζ ^ a * u) := by rw [hzuelem, pointY_zpow_mul hq0] have h₁' : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a * u')) (pointY q (ζ ^ a * u')) := by rw [hXzu', hYzu']; exact h₁ have h₃' : (curve q).toAffine.Nonsingular (pointX q u') (pointY q u') := by rw [hXu', hYu']; exact h₃ have haux := muTranslation_aux hyps hdiff hq0 hq hp5 hpp hζ ha1 hap hu'0 hu' hau' hu'le hu'gt h₁' h₂ h₃' have e₁ : (Point.some (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a * u')) (pointY q (ζ ^ a * u')) h₁' := point_some_congr hXzu'.symm hYzu'.symm h₁ h₁' have e₃ : (Point.some (pointX q u) (pointY q u) h₃ : (curve q).toAffine.Point) = Point.some (pointX q u') (pointY q u') h₃' := point_some_congr hXu'.symm hYu'.symm h₃ h₃' rw [e₁, e₃] exact haux lemma zeta_pow_mod (hζp : ζ ^ p = 1) (n : ℕ) : ζ ^ n = ζ ^ (n % p) := by conv_lhs => rw [← Nat.mod_add_div n p] rw [pow_add, pow_mul, hζp, one_pow, mul_one] lemma offLattice_zeta_pow (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) {a : ℕ} (ha1 : 1 ≤ a) (hap : a < p) : OffLattice q (ζ ^ a) := by have hp0 : 0 < p := lt_of_le_of_lt (Nat.zero_le a) hap have h := tateParam_offLattice (t := t) hq0 hq hζ ht hap hp0 (fun h => by omega) rwa [pow_zero, mul_one] at h lemma zeta_pow_point_eq_nsmul (hμ : MuTranslation q ζ p) (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (hζpt : (curve q).toAffine.Nonsingular (pointX q ζ) (pointY q ζ)) : ∀ a : ℕ, 1 ≤ a → a < p → ∀ h₁ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a)) (pointY q (ζ ^ a)), (Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₁ : (curve q).toAffine.Point) = a • Point.some (pointX q ζ) (pointY q ζ) hζpt := by have hζ0 : ζ ≠ 0 := fun h0 => by have hζp := hζ.pow_eq_one rw [h0, zero_pow hp.ne_zero] at hζp exact zero_ne_one hζp intro a induction a with | zero => intro h; omega | succ n ih => intro _ hlt h₁ rcases Nat.lt_or_ge n 1 with h2 | h2 · have hn0 : n = 0 := by omega subst hn0 have hx : ζ ^ 1 = ζ := pow_one ζ rw [one_nsmul] exact point_some_congr (congrArg (pointX q) hx) (congrArg (pointY q) hx) h₁ hζpt · have hnp : n < p := by omega have hparam : ζ ^ 1 * ζ ^ n = ζ ^ (n + 1) := by rw [pow_one, mul_comm, ← pow_succ] have hu0 : (ζ : K) ^ n ≠ 0 := pow_ne_zero _ hζ0 have huoff : OffLattice q (ζ ^ n) := offLattice_zeta_pow hq0 hq hζ ht h2 hnp have hprodoff : OffLattice q (ζ ^ 1 * ζ ^ n) := by have h := offLattice_zeta_pow hq0 hq hζ ht (a := n + 1) (by omega) hlt rwa [← hparam] at h have h₁' : (curve q).toAffine.Nonsingular (pointX q (ζ ^ 1 * ζ ^ n)) (pointY q (ζ ^ 1 * ζ ^ n)) := by rw [hparam]; exact h₁ have h₂ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ 1)) (pointY q (ζ ^ 1)) := by rw [pow_one]; exact hζpt have hns_n : (curve q).toAffine.Nonsingular (pointX q (ζ ^ n)) (pointY q (ζ ^ n)) := nonsingular_point hq0 hq hu0 huoff have htrans := hμ 1 le_rfl (by omega) (ζ ^ n) hu0 huoff hprodoff h₁' h₂ hns_n calc (Point.some (pointX q (ζ ^ (n + 1))) (pointY q (ζ ^ (n + 1))) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ 1 * ζ ^ n)) (pointY q (ζ ^ 1 * ζ ^ n)) h₁' := point_some_congr (congrArg (pointX q) hparam.symm) (congrArg (pointY q) hparam.symm) h₁ h₁' _ = Point.some (pointX q (ζ ^ 1)) (pointY q (ζ ^ 1)) h₂ + Point.some (pointX q (ζ ^ n)) (pointY q (ζ ^ n)) hns_n := htrans _ = Point.some (pointX q ζ) (pointY q ζ) hζpt + Point.some (pointX q (ζ ^ n)) (pointY q (ζ ^ n)) hns_n := by congr 1 exact point_some_congr (congrArg (pointX q) (pow_one ζ)) (congrArg (pointY q) (pow_one ζ)) h₂ hζpt _ = Point.some (pointX q ζ) (pointY q ζ) hζpt + n • Point.some (pointX q ζ) (pointY q ζ) hζpt := by rw [ih h2 hnp hns_n] _ = (n + 1) • Point.some (pointX q ζ) (pointY q ζ) hζpt := by rw [add_comm, ← succ_nsmul] end TateCurve namespace TateCurve variable {K : Type*} [NontriviallyNormedField K] [IsUltrametricDist K] [CompleteSpace K] [CharZero K] [DecidableEq K] [IsAlgClosed K] variable {q ζ t : K} {p : ℕ} section UnconditionalCascade theorem muTranslation_unconditional (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp5 : 5 ≤ p) (hpp : p.Prime) (hζ : IsPrimitiveRoot ζ p) : MuTranslation q ζ p := muTranslation_of_symAddHyps_of_diffHyp (symAddHyps_unconditional hq0 hq) (diffHyp_unconditional hq0 (by exact_mod_cast hq)) hq0 hq hp5 hpp hζ theorem nsmul_prime_eq_zero_unconditional (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) {u : K} (hu0 : u ≠ 0) (hu : OffLattice q u) {s : ℤ} (hpow : u ^ p = q ^ s) (hp : p.Prime) (hodd : Odd p) (hns : (curve q).toAffine.Nonsingular (pointX q u) (pointY q u)) : p • (Point.some (pointX q u) (pointY q u) hns : (curve q).toAffine.Point) = 0 := nsmul_prime_eq_zero (symAddHyps_unconditional hq0 hq) hq0 hq hu0 hu hpow hp hodd hns theorem eq_zpow_mul_of_pointXY_eq_unconditional (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) {u v : K} (hu0 : u ≠ 0) (hv0 : v ≠ 0) (hu : OffLattice q u) (hv : OffLattice q v) {su sv : ℤ} (hpu : u ^ p = q ^ su) (hpv : v ^ p = q ^ sv) (hp : p.Prime) (hodd : Odd p) (hX : pointX q u = pointX q v) (hY : pointY q u = pointY q v) : ∃ k : ℤ, v = q ^ k * u := eq_zpow_mul_of_pointXY_eq (symAddHyps_unconditional hq0 hq) hq0 hq hu0 hv0 hu hv hpu hpv hp hodd hX hY end UnconditionalCascade section Parametrization private lemma zeta_ne_zero (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) : ζ ≠ 0 := by intro h0 have hζp : ζ ^ p = 1 := hζ.pow_eq_one rw [h0, zero_pow hp.ne_zero] at hζp exact zero_ne_one hζp private lemma troot_ne_zero (hq0 : q ≠ 0) (hp : p.Prime) (ht : t ^ p = q) : t ≠ 0 := by intro h0 exact hq0 (by rw [← ht, h0, zero_pow hp.ne_zero]) variable (q ζ t) in noncomputable def tateTorsionPoint (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (i j : ℕ) : (curve q).toAffine.Point := if hij : i < p ∧ j < p ∧ ¬(i = 0 ∧ j = 0) then Point.some (pointX q (ζ ^ i * t ^ j)) (pointY q (ζ ^ i * t ^ j)) (nonsingular_point hq0 hq (tateParam_ne_zero (zeta_ne_zero hp hζ) (troot_ne_zero hq0 hp ht)) (tateParam_offLattice hq0 hq hζ ht hij.1 hij.2.1 hij.2.2)) else 0 lemma tateTorsionPoint_spec (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) {i j : ℕ} (hi : i < p) (hj : j < p) (hij : ¬(i = 0 ∧ j = 0)) : tateTorsionPoint q ζ t hq0 hq hp hζ ht i j = Point.some (pointX q (ζ ^ i * t ^ j)) (pointY q (ζ ^ i * t ^ j)) (nonsingular_point hq0 hq (tateParam_ne_zero (zeta_ne_zero hp hζ) (troot_ne_zero hq0 hp ht)) (tateParam_offLattice hq0 hq hζ ht hi hj hij)) := by rw [tateTorsionPoint, dif_pos ⟨hi, hj, hij⟩] @[simp] lemma tateTorsionPoint_zero_zero (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) : tateTorsionPoint q ζ t hq0 hq hp hζ ht 0 0 = 0 := by rw [tateTorsionPoint, dif_neg (fun h => h.2.2 ⟨rfl, rfl⟩)] lemma tateTorsionPoint_ne_zero (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) {i j : ℕ} (hi : i < p) (hj : j < p) (hij : ¬(i = 0 ∧ j = 0)) : tateTorsionPoint q ζ t hq0 hq hp hζ ht i j ≠ 0 := by rw [tateTorsionPoint_spec hq0 hq hp hζ ht hi hj hij] exact Point.some_ne_zero _ lemma nsmul_tateTorsionPoint (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (i j : ℕ) : p • tateTorsionPoint q ζ t hq0 hq hp hζ ht i j = 0 := by by_cases hij : i < p ∧ j < p ∧ ¬(i = 0 ∧ j = 0) · rw [tateTorsionPoint_spec hq0 hq hp hζ ht hij.1 hij.2.1 hij.2.2] exact nsmul_prime_eq_zero_unconditional hq0 hq (tateParam_ne_zero (zeta_ne_zero hp hζ) (troot_ne_zero hq0 hp ht)) (tateParam_offLattice hq0 hq hζ ht hij.1 hij.2.1 hij.2.2) (tateParam_pow hζ.pow_eq_one ht i j) hp (hp.odd_of_ne_two (by omega)) _ · rw [tateTorsionPoint, dif_neg hij, smul_zero] lemma tateTorsionPoint_mem (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (i j : ℕ) : tateTorsionPoint q ζ t hq0 hq hp hζ ht i j ∈ Submodule.torsionBy ℤ (curve q).toAffine.Point p := by rw [Submodule.mem_torsionBy_iff, natCast_zsmul] exact nsmul_tateTorsionPoint hq0 hq hp hp5 hζ ht i j lemma tateTorsionPoint_injOn (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) {i j i' j' : ℕ} (hi : i < p) (hj : j < p) (hi' : i' < p) (hj' : j' < p) (hpp : tateTorsionPoint q ζ t hq0 hq hp hζ ht i j = tateTorsionPoint q ζ t hq0 hq hp hζ ht i' j') : i = i' ∧ j = j' := by have hζ0 : ζ ≠ 0 := zeta_ne_zero hp hζ have ht0 : t ≠ 0 := troot_ne_zero hq0 hp ht by_cases hij : i = 0 ∧ j = 0 · by_cases hij' : i' = 0 ∧ j' = 0 · exact ⟨hij.1.trans hij'.1.symm, hij.2.trans hij'.2.symm⟩ · exfalso rw [hij.1, hij.2, tateTorsionPoint_zero_zero] at hpp exact tateTorsionPoint_ne_zero hq0 hq hp hζ ht hi' hj' hij' hpp.symm · by_cases hij' : i' = 0 ∧ j' = 0 · exfalso rw [hij'.1, hij'.2, tateTorsionPoint_zero_zero] at hpp exact tateTorsionPoint_ne_zero hq0 hq hp hζ ht hi hj hij hpp · rw [tateTorsionPoint_spec hq0 hq hp hζ ht hi hj hij, tateTorsionPoint_spec hq0 hq hp hζ ht hi' hj' hij', Point.some.injEq] at hpp obtain ⟨k, hk⟩ := eq_zpow_mul_of_pointXY_eq_unconditional hq0 hq (tateParam_ne_zero hζ0 ht0) (tateParam_ne_zero hζ0 ht0) (tateParam_offLattice hq0 hq hζ ht hi hj hij) (tateParam_offLattice hq0 hq hζ ht hi' hj' hij') (tateParam_pow hζ.pow_eq_one ht i j) (tateParam_pow hζ.pow_eq_one ht i' j') hp (hp.odd_of_ne_two (by omega)) hpp.1 hpp.2 exact tateParam_class_eq hq0 hq hζ ht ht0 hi hj hi' hj' hk variable (q ζ t) in noncomputable def tateTorsionEquiv (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) : (Fin p × Fin p) ≃ ((curve q).n_torsionGen p) := by refine Equiv.ofBijective (fun ij => ⟨tateTorsionPoint q ζ t hq0 hq hp hζ ht (ij.1 : ℕ) (ij.2 : ℕ), tateTorsionPoint_mem hq0 hq hp hp5 hζ ht (ij.1 : ℕ) (ij.2 : ℕ)⟩) ⟨?_, ?_⟩ · rintro ⟨i, j⟩ ⟨i', j'⟩ hff obtain ⟨h1, h2⟩ := tateTorsionPoint_injOn hq0 hq hp hp5 hζ ht i.isLt j.isLt i'.isLt j'.isLt (congrArg Subtype.val hff) rw [Prod.mk.injEq] exact ⟨Fin.ext h1, Fin.ext h2⟩ · rintro ⟨R, hR⟩ have hRkill : p • R = 0 := by have h := (Submodule.mem_torsionBy_iff _ _).mp hR rwa [natCast_zsmul] at h rcases eq_zero_or_eq_tateParam_unconditional hq0 hq hp hp5 hζ ht R hRkill with h0 | ⟨i, j, hi, hj, hij, hns, hRe⟩ · refine ⟨(⟨0, hp.pos⟩, ⟨0, hp.pos⟩), ?_⟩ apply Subtype.ext show tateTorsionPoint q ζ t hq0 hq hp hζ ht 0 0 = R rw [tateTorsionPoint_zero_zero, h0] · refine ⟨(⟨i, hi⟩, ⟨j, hj⟩), ?_⟩ apply Subtype.ext show tateTorsionPoint q ζ t hq0 hq hp hζ ht i j = R rw [tateTorsionPoint_spec hq0 hq hp hζ ht hi hj hij, hRe] theorem natCard_n_torsionGen_curve (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) : Nat.card ((curve q).n_torsionGen p) = p ^ 2 := by rw [← Nat.card_congr (tateTorsionEquiv q ζ t hq0 hq hp hp5 hζ ht), Nat.card_eq_fintype_card, Fintype.card_prod, Fintype.card_fin, sq] end Parametrization section GroupStructure theorem tateTorsionPoint_zeta_mul (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) {a : ℕ} (ha1 : 1 ≤ a) (hap : a < p) {u : K} (hu0 : u ≠ 0) (hu : OffLattice q u) (hau : OffLattice q (ζ ^ a * u)) (h₁ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u))) (h₂ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ a)) (pointY q (ζ ^ a))) (h₃ : (curve q).toAffine.Nonsingular (pointX q u) (pointY q u)) : (Point.some (pointX q (ζ ^ a * u)) (pointY q (ζ ^ a * u)) h₁ : (curve q).toAffine.Point) = Point.some (pointX q (ζ ^ a)) (pointY q (ζ ^ a)) h₂ + Point.some (pointX q u) (pointY q u) h₃ := muTranslation_unconditional hq0 hq hp5 hp hζ a ha1 hap u hu0 hu hau h₁ h₂ h₃ theorem tateTorsionPoint_fst_eq_nsmul (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hp5 : 5 ≤ p) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (hζns : (curve q).toAffine.Nonsingular (pointX q ζ) (pointY q ζ)) {i : ℕ} (hi1 : 1 ≤ i) (hip : i < p) (h₁ : (curve q).toAffine.Nonsingular (pointX q (ζ ^ i)) (pointY q (ζ ^ i))) : (Point.some (pointX q (ζ ^ i)) (pointY q (ζ ^ i)) h₁ : (curve q).toAffine.Point) = i • Point.some (pointX q ζ) (pointY q ζ) hζns := zeta_pow_point_eq_nsmul (muTranslation_unconditional hq0 hq hp5 hp hζ) hq0 hq hp hζ ht hζns i hi1 hip h₁ theorem tateTorsionPoint_inv (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) {u : K} (hu0 : u ≠ 0) (hu : OffLattice q u) (h₁ : (curve q).toAffine.Nonsingular (pointX q u⁻¹) (pointY q u⁻¹)) (h₂ : (curve q).toAffine.Nonsingular (pointX q u) (pointY q u)) : (Point.some (pointX q u⁻¹) (pointY q u⁻¹) h₁ : (curve q).toAffine.Point) = -Point.some (pointX q u) (pointY q u) h₂ := point_inv_eq_neg hq0 hq hu0 hu h₁ h₂ end GroupStructure section GaloisAction private lemma map_tateParam (σ : K →+* K) {e c : ℕ} (hσζ : σ ζ = ζ ^ e) (hσt : σ t = ζ ^ c * t) (i j : ℕ) : σ (ζ ^ i * t ^ j) = ζ ^ (e * i + c * j) * t ^ j := by rw [map_mul, map_pow, map_pow, hσζ, hσt, mul_pow, ← pow_mul, ← pow_mul, pow_add] ring theorem map_pointX_tateParam (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (σ : K →+* K) (hσ : Isometry ⇑σ) (hσq : σ q = q) {e c : ℕ} (hσζ : σ ζ = ζ ^ e) (hσt : σ t = ζ ^ c * t) (i j : ℕ) : σ (pointX q (ζ ^ i * t ^ j)) = pointX q (ζ ^ (e * i + c * j) * t ^ j) := by rw [map_pointX σ hσ hσq hq0 hq (tateParam_ne_zero (zeta_ne_zero hp hζ) (troot_ne_zero hq0 hp ht)), map_tateParam σ hσζ hσt] theorem map_pointY_tateParam (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (σ : K →+* K) (hσ : Isometry ⇑σ) (hσq : σ q = q) {e c : ℕ} (hσζ : σ ζ = ζ ^ e) (hσt : σ t = ζ ^ c * t) (i j : ℕ) : σ (pointY q (ζ ^ i * t ^ j)) = pointY q (ζ ^ (e * i + c * j) * t ^ j) := by rw [map_pointY σ hσ hσq hq0 hq (tateParam_ne_zero (zeta_ne_zero hp hζ) (troot_ne_zero hq0 hp ht)), map_tateParam σ hσζ hσt] theorem map_pointX_tateParam_toric (hq0 : q ≠ 0) (hq : ‖q‖₊ < 1) (hp : p.Prime) (hζ : IsPrimitiveRoot ζ p) (ht : t ^ p = q) (σ : K →+* K) (hσ : Isometry ⇑σ) (hσq : σ q = q) {e c : ℕ} (hσζ : σ ζ = ζ ^ e) (hσt : σ t = ζ ^ c * t) (i : ℕ) : σ (pointX q (ζ ^ i * t ^ 0)) = pointX q (ζ ^ (e * i) * t ^ 0) := by have h := map_pointX_tateParam hq0 hq hp hζ ht σ hσ hσq hσζ hσt i 0 simpa using h end GaloisAction end TateCurve