Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
add more EllipticCurveHom methods to EllipticCurveHom_velusqrt
Browse files Browse the repository at this point in the history
  • Loading branch information
yyyyx4 committed Sep 29, 2022
1 parent 3ef8390 commit 0a38cc5
Showing 1 changed file with 180 additions and 12 deletions.
192 changes: 180 additions & 12 deletions src/sage/schemes/elliptic_curves/hom_velusqrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,6 @@
...
NotImplementedError: only implemented for elliptic curves over finite fields
.. NOTE::
Currently :class:`EllipticCurveHom_velusqrt` does not implement
all methods of :class:`EllipticCurveHom`. This will hopefully
change in the future.
AUTHORS:
- Lorenz Panny (2022)
Expand All @@ -128,6 +122,8 @@
from sage.structure.sequence import Sequence
from sage.structure.all import coercion_model as cm

from sage.misc.cachefunc import cached_method

from sage.misc.misc_c import prod

from sage.structure.richcmp import op_EQ
Expand Down Expand Up @@ -524,7 +520,7 @@ def __init__(self, E, n, P, Q=None):
IJK = _choose_IJK(2*n+1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1]

self.base = E.base_ring()
R, Z = self.base['x'].objgen()
R, Z = self.base['Z'].objgen()

# Cassels, Lectures on Elliptic Curves, p.132
A,B = E.a_invariants()[-2:]
Expand Down Expand Up @@ -592,6 +588,7 @@ def __call__(self, alpha, *, derivative=False):
R = self._hI_resultant(EJ, EJrems)
hK = self.hK(alpha)
res = hK * R / self.DeltaIJ
res = base(res)

if not derivative:
return res
Expand All @@ -606,6 +603,7 @@ def __call__(self, alpha, *, derivative=False):
dR = 0
dhK = self.dhK(alpha)
dres = (dhK * R + hK * dR) / self.DeltaIJ
dres = base(dres)

return res, dres

Expand All @@ -626,7 +624,7 @@ def _hI_resultant(self, poly, rems=None):
sage: E = EllipticCurve(GF(71), [5,5])
sage: P = E(4, 35)
sage: hP = FastEllipticPolynomial(E, P.order(), P)
sage: f = GF(71)['x']([5,4,3,2,1])
sage: f = GF(71)['Z']([5,4,3,2,1])
sage: hP._hI_resultant(f)
66
sage: prod(f(r) for fi in hP.hItree.layers[0]
Expand All @@ -637,7 +635,7 @@ def _hI_resultant(self, poly, rems=None):
sage: Q = E(0, 17)
sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q)
sage: f = GF(71)['x']([9,8,7,6,5,4,3,2,1])
sage: f = GF(71)['Z']([9,8,7,6,5,4,3,2,1])
sage: hPQ._hI_resultant(f)
36
sage: prod(f(r) for fi in hPQ.hItree.layers[0]
Expand Down Expand Up @@ -895,7 +893,7 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None):
EE = self._Q.curve()
self._P = EE(self._P)

self._base_ring = EE.base_ring()
self._internal_base_ring = EE.base_ring()

self._h0 = FastEllipticPolynomial(EE, self._degree, self._P)
self._h1 = FastEllipticPolynomial(EE, self._degree, self._P, self._Q)
Expand Down Expand Up @@ -949,6 +947,13 @@ def _raw_eval(self, x, y=None):
50907
sage: phi._raw_eval(123, 456)
(3805, 29941)
TESTS::
sage: {t.parent() for t in phi._raw_eval(*Q.xy())}
{Finite Field of size 65537}
sage: {t.parent() for t in phi._raw_eval(123, 456)}
{Finite Field of size 65537}
"""
if y is None:
h0 = self._h0(x)
Expand Down Expand Up @@ -1018,15 +1023,15 @@ def _compute_codomain(self, model=None):
From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2
To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2
"""
R, Z = self._base_ring['Z'].objgen()
R, Z = self._internal_base_ring['Z'].objgen()
poly = self._raw_domain.two_division_polynomial().monic()(Z)

f = 1
for g,_ in poly.factor():
if g.degree() == 1:
f *= Z - self._raw_eval(-g[0])
else:
K, X0 = self._base_ring.extension(g,'T').objgen()
K, X0 = self._internal_base_ring.extension(g,'T').objgen()
imX0 = self._raw_eval(X0)
try:
imX0 = imX0.polynomial() # K is a FiniteField
Expand Down Expand Up @@ -1170,6 +1175,169 @@ def _comparison_impl(left, right, op):
return NotImplemented
return compare_via_evaluation(left, right)

@cached_method
def kernel_polynomial(self):
r"""
Return the kernel polynomial of this Îlu isogeny.
.. NOTE::
The data returned by this method has size linear in the degree.
EXAMPLES::
sage: E = EllipticCurve(GF(65537^2,'a'), [5,5])
sage: K = E.cardinality()//31 * E.gens()[0]
sage: phi = E.isogeny(K, algorithm='velusqrt')
sage: h = phi.kernel_polynomial(); h
x^15 + 21562*x^14 + 8571*x^13 + 20029*x^12 + 1775*x^11 + 60402*x^10 + 17481*x^9 + 46543*x^8 + 46519*x^7 + 18590*x^6 + 36554*x^5 + 36499*x^4 + 48857*x^3 + 3066*x^2 + 23264*x + 53937
sage: h == E.isogeny(K).kernel_polynomial()
True
sage: h(K.xy()[0])
0
TESTS::
sage: phi.kernel_polynomial().parent()
Univariate Polynomial Ring in x over Finite Field in a of size 65537^2
"""
R,x = self._domain.base_ring()['x'].objgen()
h = self._h0(x)
h = h(self._pre_iso.x_rational_map())
return R(h).monic()

@cached_method
def dual(self):
r"""
Return the dual of this Îlu isogeny as an :class:`EllipticCurveHom`.
.. NOTE::
The dual is computed by :class:`EllipticCurveIsogeny`,
hence it does not benefit from the Îlu speedup.
EXAMPLES::
sage: E = EllipticCurve(GF(101^2), [1,1,1,1,1])
sage: K = E.cardinality()//11 * E.gens()[0]
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
Elliptic-curve isogeny (using Îlu) of degree 11:
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2
sage: phi.dual()
Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
sage: phi.dual() * phi == phi.domain().multiplication_by_m_isogeny(11)
True
sage: phi * phi.dual() == phi.codomain().multiplication_by_m_isogeny(11)
True
"""
#FIXME This code fails if the degree is divisible by the characteristic.
F = self._raw_domain.base_ring()
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
isom = ~WeierstrassIsomorphism(self._raw_domain, (~F(self._degree), 0, 0, 0))
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
phi = EllipticCurveIsogeny(self._raw_codomain, None, isom.domain(), self._degree)
return ~self._pre_iso * isom * phi * ~self._post_iso

@cached_method
def rational_maps(self):
r"""
Return the pair of explicit rational maps of this Îlu isogeny
as fractions of bivariate polynomials in `x` and `y`.
.. NOTE::
The data returned by this method has size linear in the degree.
EXAMPLES::
sage: E = EllipticCurve(GF(101^2), [1,1,1,1,1])
sage: K = E.cardinality()//11 * E.gens()[0]
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
Elliptic-curve isogeny (using Îlu) of degree 11:
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2
sage: phi.rational_maps()
((-17*x^11 - 34*x^10 - 36*x^9 + ... - 29*x^2 - 25*x - 25)/(x^10 + 10*x^9 + 19*x^8 - ... + x^2 + 47*x + 24),
(-3*x^16 - 6*x^15*y - 48*x^15 + ... - 49*x - 9*y + 46)/(x^15 + 15*x^14 - 35*x^13 - ... + 3*x^2 - 45*x + 47))
TESTS::
sage: phi.rational_maps()[0].parent()
Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2
sage: phi.rational_maps()[1].parent()
Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2
"""
S = self._internal_base_ring['x,y']
fx, fy = map(S, self._pre_iso.rational_maps())
fx, fy = self._raw_eval(fx, fy)
gx, gy = self._post_iso.rational_maps()
fx, fy = gx(fx, fy), gy(fx, fy)
R = self._domain.base_ring()['x,y'].fraction_field()
return R(fx), R(fy)

@cached_method
def x_rational_map(self):
r"""
Return the `x`-coordinate rational map of this Îlu isogeny
as a univariate rational expression in `x`.
.. NOTE::
The data returned by this method has size linear in the degree.
EXAMPLES::
sage: E = EllipticCurve(GF(101^2), [1,1,1,1,1])
sage: K = E.cardinality()//11 * E.gens()[0]
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
Elliptic-curve isogeny (using Îlu) of degree 11:
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2
sage: phi.x_rational_map()
(84*x^11 + 67*x^10 + 65*x^9 + ... + 72*x^2 + 76*x + 76)/(x^10 + 10*x^9 + 19*x^8 + ... + x^2 + 47*x + 24)
sage: phi.x_rational_map() == phi.rational_maps()[0]
True
TESTS::
sage: phi.x_rational_map().parent()
Fraction Field of Univariate Polynomial Ring in x over Finite Field in z2 of size 101^2
"""
S = self._internal_base_ring['x']
fx = S(self._pre_iso.x_rational_map())
fx = self._raw_eval(fx)
gx = self._post_iso.x_rational_map()
fx = gx(fx)
R = self._domain.base_ring()['x'].fraction_field()
return R(fx)

def scaling_factor(self):
r"""
Return the Weierstrass scaling factor associated to this
Îlu isogeny.
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 isogeny and `\omega_i` are
the standard Weierstrass differentials on `E_i` defined by
`\mathrm dx/(2y+a_1x+a_3)`.
EXAMPLES::
sage: E = EllipticCurve(GF(101^2), [1,1,1,1,1])
sage: K = E.cardinality()//11 * E.gens()[0]
sage: phi = E.isogeny(K, algorithm='velusqrt', model='montgomery'); phi
Elliptic-curve isogeny (using Îlu) of degree 11:
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
To: Elliptic Curve defined by y^2 = x^3 + 61*x^2 + x over Finite Field in z2 of size 101^2
sage: phi.scaling_factor()
55
sage: phi.scaling_factor() == phi.formal()[1]
True
"""
return self._pre_iso.scaling_factor() * self._post_iso.scaling_factor()


def _random_example_for_testing():
r"""
Expand Down

0 comments on commit 0a38cc5

Please sign in to comment.