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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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))
>>> 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)[source]#
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: 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
>>> 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()[source]#
Compute the dual of this Frobenius isogeny.
This method returns an
EllipticCurveHom
object.EXAMPLES:
An ordinary example:
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
>>> 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: 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
>>> 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()[source]#
Return the inseparable degree of this Frobenius isogeny.
Since this class implements only purely inseparable isogenies, the inseparable degree equals the degree.
EXAMPLES:
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
>>> 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()[source]#
Return the kernel polynomial of this Frobenius isogeny as a polynomial in \(x\). This method always returns \(1\).
EXAMPLES:
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
>>> 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()[source]#
Return the explicit rational maps defining this Frobenius isogeny as (sparse) bivariate rational maps in \(x\) and \(y\).
EXAMPLES:
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)
>>> 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()[source]#
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: 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
>>> 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: pi.scaling_factor().parent() Finite Field of size 11
>>> 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()[source]#
Return the \(x\)-coordinate rational map of this Frobenius isogeny as a (sparse) univariate rational map in \(x\).
EXAMPLES:
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
>>> 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