import Mathlib import Definitions.Def_WeierstrassCurve_VeluPointMap open Polynomial namespace WeierstrassCurve section Field variable {F : Type*} [Field F] (W : WeierstrassCurve F) private lemma veluY_summand_negY (x y : F) (Q : F × F) : W.veluU Q.1 Q.2 * (2 * W.toAffine.negY x y + W.a₁ * x + W.a₃) / (x - Q.1) ^ 3 + W.veluT Q.1 Q.2 * (W.a₁ * (x - Q.1) + W.toAffine.negY x y - Q.2) / (x - Q.1) ^ 2 + (W.a₁ * W.veluU Q.1 Q.2 - W.veluGx Q.1 Q.2 * W.veluGy Q.1 Q.2) / (x - Q.1) ^ 2 = W.a₁ * (W.veluT Q.1 Q.2 / (x - Q.1) + W.veluU Q.1 Q.2 / (x - Q.1) ^ 2) - (W.veluU Q.1 Q.2 * (2 * y + W.a₁ * x + W.a₃) / (x - Q.1) ^ 3 + W.veluT Q.1 Q.2 * (W.a₁ * (x - Q.1) + y - Q.2) / (x - Q.1) ^ 2 + (W.a₁ * W.veluU Q.1 Q.2 - W.veluGx Q.1 Q.2 * W.veluGy Q.1 Q.2) / (x - Q.1) ^ 2) := by rcases eq_or_ne x Q.1 with h | h · simp [h, sub_self] · have hd : x - Q.1 ≠ 0 := sub_ne_zero.mpr h simp only [veluT, veluU, veluGx, veluGy, Affine.negY] field_simp ring lemma veluY_negY (S : Finset (F × F)) (x y : F) : W.veluY S x (W.toAffine.negY x y) = (W.veluQuotient S).toAffine.negY (W.veluX S x) (W.veluY S x y) := by simp only [veluY, veluX] rw [Finset.sum_congr rfl fun Q _ => W.veluY_summand_negY x y Q, Finset.sum_sub_distrib, ← Finset.mul_sum] simp only [Affine.negY, veluQuotient_a₁, veluQuotient_a₃] ring variable {W} in theorem velu_singleton_map_nonsingular {x₀ y₀ x y : F} (hP : W.toAffine.Equation x y) (hQ : W.toAffine.Equation x₀ y₀) (hΨ : (W.Ψ₃).eval x₀ = 0) (hx : x ≠ x₀) (hΔ : (W.veluQuotient {(x₀, y₀)}).Δ ≠ 0) : (W.veluQuotient {(x₀, y₀)}).toAffine.Nonsingular (W.veluX {(x₀, y₀)} x) (W.veluY {(x₀, y₀)} x y) := ((W.veluQuotient {(x₀, y₀)}).toAffine.equation_iff_nonsingular_of_Δ_ne_zero hΔ).mp (W.velu_singleton_map_equation hP hQ hΨ hx) private lemma some_congr {W' : Affine F} {x y₁ y₂ : F} {h₁ : W'.Nonsingular x y₁} {h₂ : W'.Nonsingular x y₂} (hy : y₁ = y₂) : Affine.Point.some x y₁ h₁ = Affine.Point.some x y₂ h₂ := by subst hy; rfl variable {W} in open scoped Classical in noncomputable def veluPointMap3 {x₀ y₀ : F} (hQ : W.toAffine.Equation x₀ y₀) (hΨ : (W.Ψ₃).eval x₀ = 0) (hΔ : (W.veluQuotient {(x₀, y₀)}).Δ ≠ 0) : W.toAffine.Point → (W.veluQuotient {(x₀, y₀)}).toAffine.Point | .zero => .zero | .some x y h => if hx : x = x₀ then .zero else .some _ _ (velu_singleton_map_nonsingular h.1 hQ hΨ hx hΔ) variable {W} variable {x₀ y₀ : F} (hQ : W.toAffine.Equation x₀ y₀) (hΨ : (W.Ψ₃).eval x₀ = 0) (hΔ : (W.veluQuotient {(x₀, y₀)}).Δ ≠ 0) @[simp] lemma veluPointMap3_zero : veluPointMap3 hQ hΨ hΔ .zero = .zero := rfl lemma veluPointMap3_some_of_eq {x y : F} (h : W.toAffine.Nonsingular x y) (hx : x = x₀) : veluPointMap3 hQ hΨ hΔ (.some x y h) = .zero := by simp only [veluPointMap3] exact dif_pos hx lemma veluPointMap3_some_of_ne {x y : F} (h : W.toAffine.Nonsingular x y) (hx : x ≠ x₀) : veluPointMap3 hQ hΨ hΔ (.some x y h) = .some _ _ (velu_singleton_map_nonsingular h.1 hQ hΨ hx hΔ) := by simp only [veluPointMap3] exact dif_neg hx lemma veluPointMap3_neg (P : W.toAffine.Point) : veluPointMap3 hQ hΨ hΔ (-P) = -(veluPointMap3 hQ hΨ hΔ P) := by cases P with | zero => rfl | some x y h => rw [Affine.Point.neg_some] by_cases hx : x = x₀ · rw [veluPointMap3_some_of_eq hQ hΨ hΔ _ hx, veluPointMap3_some_of_eq hQ hΨ hΔ h hx] rfl · rw [veluPointMap3_some_of_ne hQ hΨ hΔ _ hx, veluPointMap3_some_of_ne hQ hΨ hΔ h hx, Affine.Point.neg_some] exact some_congr (W.veluY_negY {(x₀, y₀)} x y) end Field end WeierstrassCurve