Documentation

TauCeti.AlgebraicGeometry.EllipticCurve.Universal

The universal elliptic curve #

This file defines the universal Weierstrass curve (Universal.curve) over the polynomial ring ℤ[A₁,A₂,A₃,A₄,A₆], and the universal pointed elliptic curve (Universal.pointedCurve) over the field of fractions (Universal.Field) of Universal.Ring = Universal.Poly/⟨P⟩ = ℤ[A₁,A₂,A₃,A₄,A₆,X,Y]/⟨P⟩ (where P is the Weierstrass polynomial) with distinguished point (X,Y).

It also defines the universal elliptic Weierstrass curve (Universal.ellipticCurve) over Universal.EllipticRing = ℤ[A₁,A₂,A₃,A₄,A₆][Δ⁻¹], the polynomial ring localised away from the discriminant Δ of the universal curve, and the classifying homomorphism (WeierstrassCurve.specializeElliptic) along which an elliptic Weierstrass curve over any commutative ring is the base change of that curve.

Main definitions #

Main results #

Implementation notes #

The cusp curve Y² = X³ carries the rational point (1,1), with the nice property that ψₙ(1,1) = n. Specializing along it is therefore the cheap route to nonvanishing of the universal ψₙ for n ≠ 0, which shows that (X,Y) is a point of infinite order on the universal pointed elliptic curve. The CharZero Universal.Ring instance is the first use of that argument.

Roadmap #

The [n]-is-division-polynomials bullet of TauCetiRoadmap/EllipticCurves/README.md's opening narrative on isogenies asks for multiplication by n ≠ 0 as an isogeny of degree n² whose pullback is "pinned by the division-polynomial multiplication formula, already proved at the point level in the Lutz–Nagell provenance through J. Xu's work (mathlib #13782 / ZSMul.lean) — the mathlib-track anchor Layer 1 consumes". This file is the Universal.Ring prerequisite of that ZSMul.lean: ringEval is what turns a single identity over curveRing into the same identity for every Weierstrass curve and every point on it, so the point-level [n]-compatibility is proved once, universally, rather than curve by curve. It maps out of Universal.Ring; identities over pointedCurve, which is over Universal.Field, transport only after their denominators are cleared into Universal.Ring. Mathlib PR #13782 is still open, so the whole Universal namespace below is absent from Mathlib.

Provenance #

Ported from J. Xu's LutzNagell/Universal.lean in AINTLIB (github.com/CBirkbeck/AINTLIB, Apache 2.0, main at 1c1c7466, projects/NagellLutz/LutzNagell/Universal.lean), the source the roadmap pins for the Nagell–Lutz strand. Most declarations here come from that file: the Coeff index type and the bulk of the Universal namespace (curve, Poly, Ring, Field, polyToField, pointedCurve, Affine.point, Jacobian.point, curvePoly and curveRing with their lemmas), and the specialization API (specialize, polyEval, ringEval with their compatibility lemmas).

Three groups are not simple ports, and are listed among the adaptations below: ringHom_ext is new, and so is map_polyToField — upstream that identity is definitional and is taken as rfl inside the ZSMul.lean proofs that need it, which this repository's unexposed polyToField makes impossible; the CharZero Universal.Ring instance replaces the source's Poly.two_ne_zero and Field.two_ne_zero rather than porting them, and carries the field case with it — Mathlib derives CharZero Universal.Field from it through IsFractionRing.charZero, so no second instance is declared. That derivation is why Mathlib.Algebra.CharP.Algebra is imported: without it (2 : Universal.Field) ≠ 0, which the division-polynomial addition formulas need, does not synthesize. And the equation lemmas for the opaque definitions (polyToField_apply, Affine.point_def, Jacobian.point_def, pointedCurve_Δ) exist because this repository's module system leaves definition bodies unexposed. That file's header reads Authors: Junyan Xu; following this repository's convention for adapted material, the upstream authorship is credited here rather than in the copyright header.

Four adaptations were made. The file was converted to this repository's module system (module, public import, public section). The source's three opening lemmas — CoordinateRing.algebraMap_poly_injective, CoordinateRing.algebraMap_injective' and Affine.Point.some_eq_some_iff — are not ported: the first two are FaithfulSMul.algebraMap_injective applied to Mathlib's own FaithfulSMul instances on the coordinate ring, and the third is the Iff reading of the auto-generated some.injEq, which simp proves alone. This repository declines such wrappers, and had already declined the analogous instances in Affine/FunctionField/Finrank.lean; the one internal use, in algebraMap_field_injective, calls FaithfulSMul.algebraMap_injective directly. Dropping them also removes the source's set_option backward.isDefEq.respectTransparency false in, which existed only for the first of them and which TauCeti/ forbids in any case. No definition in this file is exposed. polyToField_apply, algebraMap_field_eq_comp, the five pointedCurve_aᵢ lemmas and the two point_def lemmas are proved := (rfl): the parentheses satisfy the module system's export check without publishing any body, which is what an @[expose] would do. The section is a plain public section for the reason spelled out in TauCeti/AlgebraicGeometry/EllipticCurve/Affine/Point/VariableChange.lean — exposing the whole file would publish every proof body to make a handful of rfls go through. And equation_point opens with change where the source has show, that step rewriting the goal rather than only naming it (linter.style.show).

polyToField_polynomial is the source's declaration of that name (its :120), and the last of this file's declarations to arrive; equation_point, which the source also routes through it, does so here too. One difference: upstream it is @[simp], and here it must not be. simp can already prove the statement, because this file's polyToField_apply is @[simp] where the source's is not, and the tag therefore fails scripts/lint-env.sh with a fresh simpNF violation ("simp can prove this: by simp only [*, polyToField_apply, AdjoinRoot.mk_self, map_zero]"). Untagged, that run reports no new violations. Being redundant for simp does not make the name redundant: three proofs cite it by name, equation_point here and the two doubling formulas in DivisionPolynomial/ZSMul.lean.

The section on the universal elliptic Weierstrass curve has a second source: the ModularCurves project of AINTLIB (github.com/CBirkbeck/AINTLIB, Apache 2.0, commit c3415f32a313e19ace43e05479aeaa0d56ca287a, under projects/ModularCurves/ModularCurves/). Adapted from it are WeierstrassAtlasRing with its IsDomain and IsNoetherianRing instances and universalWeierstrassLoc with its IsElliptic instance (Moduli/WeierstrassAtlas.lean), classifyRingHom and universalWeierstrassLoc_map_classifyRingHom (EllipticCurve/WeierstrassAtlasBundle.lean), classifyRingHom_map and classifyRingHom_universalWeierstrassLoc (EllipticCurve/AdditionBaseChange.lean), and ringHomOfEllipticW_ellipticWOfRingHom (Moduli/MellWeierstrass.lean). Those headers read Authors: Chris Birkbeck, except that of WeierstrassAtlasBundle.lean, which reads Authors: The AINTLIB Authors.

The source builds these on a second universal curve, universalWeierstrass over MvPolynomial (Fin 5) ℤ, with its own coefficient maps classifyCoeffHom and specializeAt. Here they are built on this file's Universal.curve and specialize, so there is one universal curve and specializeElliptic extends specialize. EllipticRing.ringHom_ext is new: the source repeats IsLocalization.ringHom_ext and MvPolynomial.ringHom_ext inside each proof. specializeElliptic_map and specializeElliptic_ellipticCurve are corollaries of specializeElliptic_map_ellipticCurve rather than separate computations, and specializeElliptic_map takes the ellipticity of W.map f from Mathlib's instance instead of a second hypothesis. The Noetherian instance is not declared: instance search derives it from Mathlib's instances once Coeff is a Fintype. The source's ULift copies in higher universes (WeierstrassAtlasRingU, universalWeierstrassLocU, classifyRingHomU) are not ported.

The universal elliptic curve #

A type whose elements represent the five coefficients a₁, a₂, a₃, a₄ and a₆ of the Weierstrass polynomial. It indexes the variables of MvPolynomial Coeff ℤ = ℤ[A₁,⋯,A₆], the ring the universal curve is defined over. There is no A₅ — the subscripts are weights, not positions — and the constructors are uppercase as names of indeterminates: specialize sends A₁ to W.a₁.

Instances For
    @[instance_reducible]

    The five coefficient indices form a finite type, so ℤ[A₁,⋯,A₆] and its localisations are Noetherian rings.

    Equations

    The universal Weierstrass curve: the curve over ℤ[A₁,⋯,A₆] = MvPolynomial Coeff ℤ (the universal polynomial ring for Weierstrass curves) whose five coefficients are the five indeterminates. Every Weierstrass curve is one of its specializations (map_specialize); its base changes are curvePoly, curveRing and pointedCurve.

    Equations
    • One or more equations did not get rendered due to their size.
    Instances For
      @[simp]

      The a₁ coefficient of the universal curve is the indeterminate A₁, and likewise for A₂ through A₆. The definition body is unexposed, so these are how a consumer normalises a coefficient of curve inside a polynomial identity.

      @[simp]

      The a₂ coefficient of the universal curve is the indeterminate A₂.

      @[simp]

      The a₃ coefficient of the universal curve is the indeterminate A₃.

      @[simp]

      The a₄ coefficient of the universal curve is the indeterminate A₄.

      @[simp]

      The a₆ coefficient of the universal curve is the indeterminate A₆.

      The discriminant of the universal Weierstrass curve is a nonzero polynomial in ℤ[A₁,⋯,A₆], i.e. a Weierstrass equation is not singular identically in its coefficients. Transported along algebraMap_field_injective, this is what makes pointedCurve elliptic over Universal.Field.

      @[reducible, inline]

      The polynomial ring ℤ[A₁,A₂,A₃,A₄,A₆,X,Y]: two variables adjoined to the universal polynomial ring ℤ[A₁,⋯,A₆], in Mathlib's iterated form R[X][Y], so Y is the outer variable. The Weierstrass polynomial curve.polynomial lives here; Universal.Ring is the quotient by it.

      Equations
      Instances For
        @[reducible, inline]

        The universal ring for pointed Weierstrass curves: ℤ[A₁,⋯,A₆,X,Y]/⟨P⟩, for P the Weierstrass polynomial. A Weierstrass curve over R together with an affine point on it determines a ring homomorphism out of it — ringEval — and determines it uniquely, since the coefficients and the two coordinates generate (ringHom_ext). Being an abbrev for curve.CoordinateRing, it inherits Mathlib's Affine.CoordinateRing API.

        Equations
        Instances For
          @[reducible, inline]

          The universal field for pointed Weierstrass curves is the field of fractions of the universal ring.

          Equations
          Instances For

            The ring homomorphism ℤ[A₁,⋯,A₆,X,Y] → Universal.Field: reduce modulo the Weierstrass polynomial, then include the universal ring into its fraction field. Every statement about the universal pointed curve is ultimately about the images of X and Y under this map.

            Equations
            Instances For
              @[simp]

              polyToField is reduction modulo the Weierstrass polynomial followed by the inclusion into the fraction field.

              The Weierstrass polynomial vanishes in the universal field. It is exactly the element Universal.Ring quotients out, so polyToField kills it — which is how an identity over pointedCurve discards the multiples of curve.polynomial that clearing denominators throws up.

              The structure map of Universal.Field over the coefficient ring factors through Poly: the coefficients A₁,⋯,A₆ reach the universal field by the same route as X and Y do. Rewriting with this turns a statement about algebraMap into one about polyToField.

              The Universal.Ring counterpart of algebraMap_field_eq_comp: the structure map from the coefficient ring is the inclusion ℤ[A₁,⋯,A₆] → Poly followed by the quotient map.

              The coefficient ring ℤ[A₁,⋯,A₆] embeds in the universal field: the five indeterminates stay algebraically independent after adjoining a point and passing to fractions. This is what carries curve_Δ_ne_zero over to pointedCurve, giving the IsElliptic instance below.

              @[reducible, inline]

              The universal pointed Weierstrass curve: the universal curve base-changed to the universal field, over which it is an elliptic curve (instance below) carrying the distinguished point (X, Y) (equation_point, packaged as Affine.point). It is the base change to Universal.Field, and so is the third of curvePoly, curveRing, pointedCurve.

              Equations
              Instances For

                The discriminant of pointedCurve is the image of curve.Δ. pointedCurve is by definition curve.baseChange Universal.Field, so this is map_Δ at that base change — named here rather than reached through a definitional show, so the ellipticity proof rewrites with an ordinary equation and the reliance on that definitional unfolding sits in one place.

                The universal pointed Weierstrass curve is an elliptic curve: its discriminant is a unit, because Δ of the universal curve is a nonzero polynomial and the coefficient ring embeds in the universal field.

                The pair (X, Y) — the images of the two adjoined variables in the universal field — satisfies the affine Weierstrass equation of pointedCurve. This is what makes the universal curve pointed; Affine.point packages it as an element of the point group.

                @[simp]

                The affine distinguished point is equation_point packaged as a point of the group. The definition body is not exposed, so this equation lemma is how a consumer recovers it.

                @[simp]

                The Jacobian distinguished point is the affine one, moved along fromAffine.

                The a₁ coefficient of pointedCurve is the image of the indeterminate A₁ in the universal field, and likewise for pointedCurve_a₂ through pointedCurve_a₆.

                None of the five is @[simp]: pointedCurve is curve.baseChange Universal.Field, which unfolds to curve.map (algebraMap _ _), so simp already rewrites pointedCurve.a₁ with Mathlib's WeierstrassCurve.map_a₁, to algebraMap _ _ curve.a₁; tagging these would put a non-normal-form left-hand side in the simp set. They are the polyToField reading of the same coefficients, for use by name.

                The a₂ coefficient of pointedCurve is the image of the indeterminate A₂.

                The a₃ coefficient of pointedCurve is the image of the indeterminate A₃.

                The a₄ coefficient of pointedCurve is the image of the indeterminate A₄.

                The a₆ coefficient of pointedCurve is the image of the indeterminate A₆.

                @[reducible, inline]

                The base change of the universal curve from ℤ[A₁,⋯,A₆] to ℤ[A₁,⋯,A₆,X,Y].

                Equations
                Instances For
                  @[reducible, inline]

                  The base change of the universal curve from ℤ[A₁,⋯,A₆] to ℤ[A₁,⋯,A₆,X,Y]/⟨P⟩ (the universal ring), where P is the Weierstrass polynomial.

                  Equations
                  Instances For
                    @[simp]

                    Pushing curvePoly along polyToField gives pointedCurve: the base change of the universal curve to ℤ[A₁,⋯,A₆,X,Y] and its base change to the universal field agree along polyToField.

                    The curve-dependent Jacobian transports state their left-hand side over W.map f, so pushing one from Poly to Universal.Field produces curvePoly.map polyToField and needs this lemma to land on pointedCurve: map_dblZ, map_dblXYZ, map_addX, map_addY, map_addXYZ. map_addZ is not among them — addZ takes no curve argument, so its transport is curve-free.

                    The specialization homomorphism from ℤ[A₁, ⋯, A₆] to the ring of definition of the Weierstrass curve.

                    Equations
                    Instances For
                      @[simp]

                      specialize sends each indeterminate to the corresponding coefficient of W. With curve_a₁‥curve_a₆ this normalises coefficient evaluation inside a polynomial identity, without unfolding either definition.

                      @[simp]

                      Every Weierstrass curve is a specialization of the universal Weierstrass curve.

                      @[simp]

                      specialize sends the discriminant of the universal curve to the discriminant of W.

                      noncomputable def WeierstrassCurve.Universal.polyEval {R : Type u_1} [CommRing R] (W : WeierstrassCurve R) (x y : R) :

                      A point in the affine plane over R induces an evaluation homomorphism from ℤ[A₁, ⋯, A₆, X, Y] to R.

                      Equations
                      Instances For
                        @[simp]

                        polyEval computes in the expected order: substitute W's coefficients for the indeterminates A₁,⋯,A₆, then evaluate the resulting bivariate polynomial at (x, y).

                        noncomputable def WeierstrassCurve.Universal.ringEval {R : Type u_1} [CommRing R] {W : WeierstrassCurve R} {x y : R} (eqn : Affine.Equation W x y) :

                        A point on a Weierstrass curve over R induces a specialization homomorphism from the universal ring to R.

                        Equations
                        Instances For
                          @[simp]
                          theorem WeierstrassCurve.Universal.ringEval_mk {R : Type u_1} [CommRing R] {W : WeierstrassCurve R} {x y : R} (eqn : Affine.Equation W x y) (p : Poly) :

                          ringEval is polyEval read on the quotient: evaluating a representative p gives the same answer as evaluating p in Poly. The pointwise form of ringEval_comp_mk.

                          @[simp]

                          The homomorphism-level form of ringEval_mk: ringEval eqn is the factorisation of polyEval W x y through the quotient by the Weierstrass polynomial. Use this shape when composing ring maps and ringEval_mk when rewriting underneath an application.

                          @[simp]

                          ringEval sends the distinguished X to the abscissa of the point. Together with ringEval_root this is the coordinate-level content of the universal property: the pair (X, Y) of Universal.Ring goes to the chosen point (x, y) of W.

                          @[simp]

                          ringEval sends the distinguished Y to the ordinate of the point.

                          @[simp]

                          Restricted to the coefficient ring, polyEval W x y is just W.specialize: evaluating at a point does not disturb the substitution of W's coefficients.

                          Extensionality for homomorphisms out of the universal ring. Two ring homomorphisms out of Universal.Ring are equal as soon as they agree on the coefficient ring ℤ[A₁,⋯,A₆] and on the two distinguished coordinates X and Y — that is, on generators.

                          Together with ringEval_comp_eq_specialize, ringEval_of_X and ringEval_root this is the uniqueness half of the universal property: ringEval is not merely a homomorphism carrying the universal curve and its point to W and (x, y), it is the only one. That is what licenses proving an identity once over curveRing and reading it off for every curve and every point.

                          Agreement after composing with AdjoinRoot.mk would not do: mk is surjective, so that hypothesis is merely a restatement of the conclusion and proves nothing about generators.

                          @[simp]

                          The Universal.Ring counterpart of polyEval_comp_eq_specialize: ringEval eqn also restricts to W.specialize on the coefficient ring. This is the compatibility that makes map_ringEval, and with it every specialization argument, go through.

                          The universal ring has characteristic zero: specializing to the cusp curve at (1, 1) retracts it onto ℤ. This is the first use of that specialization argument, and it is what gives (2 : Universal.Ring) ≠ 0 — needed by the halving steps of the group law and of the division-polynomial recursion.

                          @[simp]
                          theorem WeierstrassCurve.Universal.map_ringEval {R : Type u_1} [CommRing R] {W : WeierstrassCurve R} {x y : R} (eqn : Affine.Equation W x y) :

                          Specialization is compatible with base change: pushing the universal curve over Universal.Ring along ringEval eqn returns W itself. This is the mechanism the whole file exists for — an identity proved once for curveRing and its distinguished point becomes the same identity for every Weierstrass curve W and every point (x, y) on it.

                          The universal elliptic Weierstrass curve over ℤ[A₁,⋯,A₆][Δ⁻¹] #

                          @[reducible, inline]

                          The universal ring for elliptic Weierstrass curves: ℤ[A₁,⋯,A₆][Δ⁻¹], the universal polynomial ring ℤ[A₁,⋯,A₆] localised away from the discriminant of the universal curve. Being an abbrev for Localization.Away curve.Δ, it inherits Mathlib's localisation API, and with it the Noetherian instance.

                          Equations
                          Instances For

                            ℤ[A₁,⋯,A₆][Δ⁻¹] is an integral domain, since the universal discriminant is nonzero (curve_Δ_ne_zero).

                            @[reducible, inline]

                            The universal elliptic Weierstrass curve: the universal curve base-changed to ℤ[A₁,⋯,A₆][Δ⁻¹], over which its discriminant (ellipticCurve_Δ) is a unit. Every elliptic Weierstrass curve is its base change along exactly one ring homomorphism (map_specializeElliptic, specializeElliptic_map_ellipticCurve).

                            Equations
                            Instances For
                              @[simp]

                              The discriminant of ellipticCurve is the image of curve.Δ in ℤ[A₁,⋯,A₆][Δ⁻¹]. Rewrite with this in place of Mathlib's map_Δ, which simp and rw do not apply to ellipticCurve.Δ on their own, since neither unfolds baseChange.

                              The universal elliptic Weierstrass curve is an elliptic curve: its discriminant is the image of curve.Δ in the localisation away from curve.Δ, hence a unit.

                              Extensionality for homomorphisms out of ℤ[A₁,⋯,A₆][Δ⁻¹]. Two ring homomorphisms out of Universal.EllipticRing are equal as soon as they agree on the images of the five indeterminates A₁,⋯,A₆ — the coefficients of ellipticCurve. So a homomorphism out of Universal.EllipticRing is determined by the Weierstrass curve it produces from ellipticCurve.

                              The classifying homomorphism of an elliptic Weierstrass curve W over R: the ring homomorphism ℤ[A₁,⋯,A₆][Δ⁻¹] →+* R extending W.specialize, which substitutes the coefficients of W for the indeterminates (specializeElliptic_comp_algebraMap). The universal elliptic Weierstrass curve maps to W along it (map_specializeElliptic), and it is the only homomorphism with that property (specializeElliptic_map_ellipticCurve).

                              Equations
                              Instances For
                                @[simp]

                                Restricted to the coefficient ring ℤ[A₁,⋯,A₆], the classifying homomorphism of W is W.specialize. Use this shape when composing ring maps and specializeElliptic_algebraMap when rewriting underneath an application.

                                @[simp]

                                The classifying homomorphism of W sends the image of a polynomial p in the coefficients to W.specialize p; with specialize_X, it sends the image of each indeterminate to the corresponding coefficient of W. The pointwise form of specializeElliptic_comp_algebraMap.

                                @[simp]

                                Every elliptic Weierstrass curve is the base change of the universal elliptic Weierstrass curve along its classifying homomorphism. An identity that is compatible with base change, proved once for Universal.ellipticCurve over the integral domain Universal.EllipticRing, thereby holds for every elliptic Weierstrass curve over every commutative ring. See map_specialize for Weierstrass curves that need not be elliptic.

                                @[simp]

                                A ring homomorphism f out of ℤ[A₁,⋯,A₆][Δ⁻¹] is the classifying homomorphism of the Weierstrass curve ellipticCurve.map f it produces. With map_specializeElliptic, this makes f ↦ ellipticCurve.map f and W ↦ W.specializeElliptic mutually inverse: ring homomorphisms ℤ[A₁,⋯,A₆][Δ⁻¹] →+* R correspond exactly to elliptic Weierstrass curves over R.

                                The classifying homomorphism is natural in the base ring: the classifying homomorphism of the base change W.map f is that of W followed by f.

                                @[simp]

                                The universal elliptic Weierstrass curve is classified by the identity homomorphism of ℤ[A₁,⋯,A₆][Δ⁻¹].