Frobenius isogenies of elliptic curves - Elliptic curves

Skip to content
Back to top
View this page
Edit this page

# Frobenius isogenies of elliptic curves

Frobenius isogenies only exist in positive characteristic \(p\). They are given by \(\pi_n:(x,y)\mapsto (x^{p^n},y^{p^n})\).

This class implements \(\pi_n\) for \(n \geq 0\). Together with existing tools for composing isogenies (see `EllipticCurveHom_composite`), we can therefore represent arbitrary inseparable isogenies in Sage.

EXAMPLES:

Constructing a Frobenius isogeny is straightforward:

Sage

    sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
    sage: z5, = GF(17^5).gens()
    sage: E = EllipticCurve([z5,1])
    sage: pi = EllipticCurveHom_frobenius(E); pi
    Frobenius isogeny of degree 17:
      From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 17^5
      To:   Elliptic Curve defined by y^2 = x^3 + (9*z5^4+7*z5^3+10*z5^2+z5+14)*x + 1
            over Finite Field in z5 of size 17^5

Python

    >>> from sage.all import *
    >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
    >>> z5, = GF(Integer(17)**Integer(5)).gens()
    >>> E = EllipticCurve([z5,Integer(1)])
    >>> pi = EllipticCurveHom_frobenius(E); pi
    Frobenius isogeny of degree 17:
      From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 17^5
      To:   Elliptic Curve defined by y^2 = x^3 + (9*z5^4+7*z5^3+10*z5^2+z5+14)*x + 1
            over Finite Field in z5 of size 17^5

By passing \(n\), we can also construct higher-power Frobenius maps, such as the Frobenius endomorphism:

Sage

    sage: z5, = GF(7^5).gens()
    sage: E = EllipticCurve([z5,1])
    sage: pi = EllipticCurveHom_frobenius(E, 5); pi
    Frobenius endomorphism of degree 16807 = 7^5:
      From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 7^5
      To:   Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 7^5

[Python]

    >>> from sage.all import *
    >>> z5, = GF(Integer(7)**Integer(5)).gens()
    >>> E = EllipticCurve([z5,Integer(1)])
    >>> pi = EllipticCurveHom_frobenius(E, Integer(5)); pi
    Frobenius endomorphism of degree 16807 = 7^5:
      From: Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 7^5
      To:   Elliptic Curve defined by y^2 = x^3 + z5*x + 1
            over Finite Field in z5 of size 7^5

The usual `EllipticCurveHom` methods are supported:

Sage

    sage: z5, = GF(7^5).gens()
    sage: E = EllipticCurve([z5,1])
    sage: pi = EllipticCurveHom_frobenius(E,5)
    sage: pi.degree()
    16807
    sage: pi.rational_maps()
    (x^16807, y^16807)
    sage: pi.formal()                   # known bug
    ...
    sage: pi.is_normalized()            # known bug
    ...
    sage: pi.is_separable()
    False
    sage: pi.is_injective()
    True
    sage: pi.is_surjective()
    True

Python

    >>> from sage.all import *
    >>> z5, = GF(Integer(7)**Integer(5)).gens()
    >>> E = EllipticCurve([z5,Integer(1)])
    >>> pi = EllipticCurveHom_frobenius(E,Integer(5))
    >>> pi.degree()
    16807
    >>> pi.rational_maps()
    (x^16807, y^16807)
    >>> pi.formal()                   # known bug
    ...
    >>> pi.is_normalized()            # known bug
    ...
    >>> pi.is_separable()
    False
    >>> pi.is_injective()
    True
    >>> pi.is_surjective()
    True

Computing the dual of Frobenius is supported as well:

Sage

    sage: E = EllipticCurve([GF(17^6).gen(), 0])
    sage: pi = EllipticCurveHom_frobenius(E)
    sage: pihat = pi.dual(); pihat
    Isogeny of degree 17
     from Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)*x
          over Finite Field in z6 of size 17^6
       to Elliptic Curve defined by y^2 = x^3 + z6*x
          over Finite Field in z6 of size 17^6
    sage: pihat.is_separable()
    True
    sage: pihat * pi == EllipticCurveHom_scalar(E,17)   # known bug -- #6413
    True

[Python]

    >>> from sage.all import *
    >>> E = EllipticCurve([GF(Integer(17)**Integer(6)).gen(), Integer(0)])
    >>> pi = EllipticCurveHom_frobenius(E)
    >>> pihat = pi.dual(); pihat
    Isogeny of degree 17
     from Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)*x
          over Finite Field in z6 of size 17^6
       to Elliptic Curve defined by y^2 = x^3 + z6*x
          over Finite Field in z6 of size 17^6
    >>> pihat.is_separable()
    True
    >>> pihat * pi == EllipticCurveHom_scalar(E,Integer(17))   # known bug -- #6413
    True

A supersingular example (with purely inseparable dual):

Sage

    sage: E = EllipticCurve([0, GF(17^6).gen()])
    sage: E.is_supersingular()
    True
    sage: pi1 = EllipticCurveHom_frobenius(E)
    sage: pi1hat = pi1.dual(); pi1hat
    Composite morphism of degree 17 = 17*1:
      From: Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)
            over Finite Field in z6 of size 17^6
      To:   Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
    sage: pi6 = EllipticCurveHom_frobenius(E,6)
    sage: pi6hat = pi6.dual(); pi6hat
    Composite morphism of degree 24137569 = 24137569*1:
      From: Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
      To:   Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
    sage: pi6hat.factors()
    (Frobenius endomorphism of degree 24137569 = 17^6:
       From: Elliptic Curve defined by y^2 = x^3 + z6
             over Finite Field in z6 of size 17^6
       To:   Elliptic Curve defined by y^2 = x^3 + z6
             over Finite Field in z6 of size 17^6,
     Elliptic-curve endomorphism of
      Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6
       Via:  (u,r,s,t) = (2*z6^5 + 10*z6^3 + z6^2 + 8, 0, 0, 0))

Python

    >>> from sage.all import *
    >>> E = EllipticCurve([Integer(0), GF(Integer(17)**Integer(6)).gen()])
    >>> E.is_supersingular()
    True
    >>> pi1 = EllipticCurveHom_frobenius(E)
    >>> pi1hat = pi1.dual(); pi1hat
    Composite morphism of degree 17 = 17*1:
      From: Elliptic Curve defined by y^2 = x^3 + (15*z6^5+5*z6^4+8*z6^3+12*z6^2+11*z6+7)
            over Finite Field in z6 of size 17^6
      To:   Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
    >>> pi6 = EllipticCurveHom_frobenius(E,Integer(6))
    >>> pi6hat = pi6.dual(); pi6hat
    Composite morphism of degree 24137569 = 24137569*1:
      From: Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
      To:   Elliptic Curve defined by y^2 = x^3 + z6
            over Finite Field in z6 of size 17^6
    >>> pi6hat.factors()
    (Frobenius endomorphism of degree 24137569 = 17^6:
       From: Elliptic Curve defined by y^2 = x^3 + z6
             over Finite Field in z6 of size 17^6
       To:   Elliptic Curve defined by y^2 = x^3 + z6
             over Finite Field in z6 of size 17^6,
     Elliptic-curve endomorphism of
      Elliptic Curve defined by y^2 = x^3 + z6 over Finite Field in z6 of size 17^6
       Via:  (u,r,s,t) = (2*z6^5 + 10*z6^3 + z6^2 + 8, 0, 0, 0))

AUTHORS:

- Lorenz Panny (2021): implement `EllipticCurveHom_frobenius`

- Mickaël Montessinos (2021): computing the dual of a Frobenius isogeny

class sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius(E, power=1)

  Bases: `EllipticCurveHom`

  Construct a Frobenius isogeny on a given curve with a given power of the base-ring characteristic.

  Writing \(n\) for the parameter `power` (default: \(1\)), the isogeny is defined by \((x,y) \to (x^{p^n}, y^{p^n})\) where \(p\) is the characteristic of the base ring.

  EXAMPLES:

  Sage

      sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
      sage: E = EllipticCurve(j=GF(11^2).gen())
      sage: EllipticCurveHom_frobenius(E)
      Frobenius isogeny of degree 11:
        From: Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2
        To:   Elliptic Curve defined by y^2 = x^3 + (9*z2+3)*x + (3*z2+7) over Finite Field in z2 of size 11^2
      sage: EllipticCurveHom_frobenius(E, 2)
      Frobenius endomorphism of degree 121 = 11^2:
        From: Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2
        To:   Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2

  Python

      >>> from sage.all import *
      >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
      >>> E = EllipticCurve(j=GF(Integer(11)**Integer(2)).gen())
      >>> EllipticCurveHom_frobenius(E)
      Frobenius isogeny of degree 11:
        From: Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2
        To:   Elliptic Curve defined by y^2 = x^3 + (9*z2+3)*x + (3*z2+7) over Finite Field in z2 of size 11^2
      >>> EllipticCurveHom_frobenius(E, Integer(2))
      Frobenius endomorphism of degree 121 = 11^2:
        From: Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2
        To:   Elliptic Curve defined by y^2 = x^3 + (2*z2+6)*x + (8*z2+8) over Finite Field in z2 of size 11^2

  dual()

    Compute the dual of this Frobenius isogeny.

    This method returns an `EllipticCurveHom` object.

    EXAMPLES:

    An ordinary example:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar
        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(31), [0,1])
        sage: f = EllipticCurveHom_frobenius(E)
        sage: f.dual() * f == EllipticCurveHom_scalar(f.domain(), 31)
        True
        sage: f * f.dual() == EllipticCurveHom_scalar(f.codomain(), 31)
        True

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(31)), [Integer(0),Integer(1)])
        >>> f = EllipticCurveHom_frobenius(E)
        >>> f.dual() * f == EllipticCurveHom_scalar(f.domain(), Integer(31))
        True
        >>> f * f.dual() == EllipticCurveHom_scalar(f.codomain(), Integer(31))
        True

    A supersingular example:

    Sage

        sage: E = EllipticCurve(GF(31), [1,0])
        sage: f = EllipticCurveHom_frobenius(E)
        sage: f.dual() * f == EllipticCurveHom_scalar(f.domain(), 31)
        True
        sage: f * f.dual() == EllipticCurveHom_scalar(f.codomain(), 31)
        True

    [Python]

        >>> from sage.all import *
        >>> E = EllipticCurve(GF(Integer(31)), [Integer(1),Integer(0)])
        >>> f = EllipticCurveHom_frobenius(E)
        >>> f.dual() * f == EllipticCurveHom_scalar(f.domain(), Integer(31))
        True
        >>> f * f.dual() == EllipticCurveHom_scalar(f.codomain(), Integer(31))
        True

    ALGORITHM:

    - For supersingular curves, the dual of Frobenius is again purely inseparable, so we start out with a Frobenius isogeny of equal degree in the opposite direction.

    - For ordinary curves, we immediately reduce to the case of prime degree. The kernel of the dual is the unique subgroup of size \(p\), which we compute from the \(p\)-division polynomial.

    In both cases, we then search for the correct post-isomorphism using `find_post_isomorphism()`.

  inseparable_degree()

    Return the inseparable degree of this Frobenius isogeny.

    Since this class implements only purely inseparable isogenies, the inseparable degree equals the degree.

    EXAMPLES:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(11), [1,1])
        sage: pi = EllipticCurveHom_frobenius(E, 4)
        sage: pi.inseparable_degree()
        14641
        sage: pi.inseparable_degree() == pi.degree()
        True

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(11)), [Integer(1),Integer(1)])
        >>> pi = EllipticCurveHom_frobenius(E, Integer(4))
        >>> pi.inseparable_degree()
        14641
        >>> pi.inseparable_degree() == pi.degree()
        True

  kernel_polynomial()

    Return the kernel polynomial of this Frobenius isogeny as a polynomial in \(x\). This method always returns \(1\).

    EXAMPLES:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(11), [1,1])
        sage: pi = EllipticCurveHom_frobenius(E, 5)
        sage: pi.kernel_polynomial()
        1

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(11)), [Integer(1),Integer(1)])
        >>> pi = EllipticCurveHom_frobenius(E, Integer(5))
        >>> pi.kernel_polynomial()
        1

  rational_maps()

    Return the explicit rational maps defining this Frobenius isogeny as (sparse) bivariate rational maps in \(x\) and \(y\).

    EXAMPLES:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(11), [1,1])
        sage: pi = EllipticCurveHom_frobenius(E, 4)
        sage: pi.rational_maps()
        (x^14641, y^14641)

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(11)), [Integer(1),Integer(1)])
        >>> pi = EllipticCurveHom_frobenius(E, Integer(4))
        >>> pi.rational_maps()
        (x^14641, y^14641)

  scaling_factor()

    Return the Weierstrass scaling factor associated to this Frobenius morphism.

    The scaling factor is the constant \(u\) (in the base field) such that \(\varphi^* \omega_2 = u \omega_1\), where \(\varphi: E_1\to E_2\) is this morphism and \(\omega_i\) are the standard Weierstrass differentials on \(E_i\) defined by \(\mathrm dx/(2y+a_1x+a_3)\).

    EXAMPLES:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(11), [1,1])
        sage: pi = EllipticCurveHom_frobenius(E)
        sage: pi.formal()
        t^11 + O(t^33)
        sage: pi.scaling_factor()
        0
        sage: pi = EllipticCurveHom_frobenius(E, 3)
        sage: pi.formal()
        t^1331 + O(t^1353)
        sage: pi.scaling_factor()
        0
        sage: pi = EllipticCurveHom_frobenius(E, 0)
        sage: pi == E.scalar_multiplication(1)
        True
        sage: pi.scaling_factor()
        1

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(11)), [Integer(1),Integer(1)])
        >>> pi = EllipticCurveHom_frobenius(E)
        >>> pi.formal()
        t^11 + O(t^33)
        >>> pi.scaling_factor()
        0
        >>> pi = EllipticCurveHom_frobenius(E, Integer(3))
        >>> pi.formal()
        t^1331 + O(t^1353)
        >>> pi.scaling_factor()
        0
        >>> pi = EllipticCurveHom_frobenius(E, Integer(0))
        >>> pi == E.scalar_multiplication(Integer(1))
        True
        >>> pi.scaling_factor()
        1

    The scaling factor lives in the base ring:

    Sage

        sage: pi.scaling_factor().parent()
        Finite Field of size 11

    [Python]

        >>> from sage.all import *
        >>> pi.scaling_factor().parent()
        Finite Field of size 11

    ALGORITHM: Inseparable isogenies of degree \(>1\) have scaling factor \(0\).

  x_rational_map()

    Return the \(x\)-coordinate rational map of this Frobenius isogeny as a (sparse) univariate rational map in \(x\).

    EXAMPLES:

    Sage

        sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        sage: E = EllipticCurve(GF(11), [1,1])
        sage: pi = EllipticCurveHom_frobenius(E, 4)
        sage: pi.x_rational_map()
        x^14641

    Python

        >>> from sage.all import *
        >>> from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
        >>> E = EllipticCurve(GF(Integer(11)), [Integer(1),Integer(1)])
        >>> pi = EllipticCurveHom_frobenius(E, Integer(4))
        >>> pi.x_rational_map()
        x^14641