Skip to content

Commit

Permalink
Trac #34614: add missing EllipticCurveHom methods to Îlu isogenies
Browse files Browse the repository at this point in the history
The `EllipticCurveHom_velusqrt` class introduced in #34303 inherits from
`EllipticCurveHom` (#32388, #32502), but it doesn't yet implement all of
the required methods. In this patch, we add them.

Diff without the dependency: https://git.sagemath.org/sage.git/diff?id2=
7326051&id=8cb0f29aa2cd5be18506e1d65eac
954481d1ec8a

URL: https://trac.sagemath.org/34614
Reported by: lorenz
Ticket author(s): Lorenz Panny
Reviewer(s): Travis Scrimshaw, Kwankyu Lee
  • Loading branch information
Release Manager committed Oct 11, 2022
2 parents a7dac85 + 8cb0f29 commit 685a07c
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 94 deletions.
53 changes: 7 additions & 46 deletions src/sage/schemes/elliptic_curves/ell_curve_isogeny.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@
sage: Q = E(6,5)
sage: phi = E.isogeny(Q)
sage: phi
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 to Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x + 1 over
Finite Field of size 11 to Elliptic Curve defined by y^2 = x^3 + 7*x + 8
over Finite Field of size 11
sage: P = E(4,5)
sage: phi(P)
(10 : 0 : 1)
sage: phi.codomain()
Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11
sage: phi.rational_maps()
((x^7 + 4*x^6 - 3*x^5 - 2*x^4 - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4 - 5*x^3 + 5*x^2), (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y - 5*x^3*y - 5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3))
((x^7 + 4*x^6 - 3*x^5 - 2*x^4 - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4
- 5*x^3 + 5*x^2), (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y - 5*x^3*y -
5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3))
The methods directly accessible from an elliptic curve ``E`` over a
field are
Expand Down Expand Up @@ -337,7 +341,6 @@ def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3):
w = 3*(s1**3 - 3*s1*s2 + 3*s3) + (b2*temp1 + b4*s1)/2
return v, w


def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n):
r"""
Compute Vélu's `(v,w)` using Kohel's formulas for isogenies of odd
Expand Down Expand Up @@ -374,7 +377,6 @@ def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n):
w = 10*(s1**3 - 3*s1*s2 + 3*s3) + 2*b2*(s1**2 - 2*s2) + 3*b4*s1 + n*b6
return v, w


def compute_codomain_kohel(E, kernel):
r"""
Compute the codomain from the kernel polynomial using Kohel's
Expand Down Expand Up @@ -481,7 +483,6 @@ def compute_codomain_kohel(E, kernel):

return compute_codomain_formula(E, v, w)


def two_torsion_part(E, psi):
r"""
Return the greatest common divisor of ``psi`` and the 2-torsion
Expand Down Expand Up @@ -516,6 +517,7 @@ def two_torsion_part(E, psi):
psi_2 = E.two_division_polynomial(x)
return psi.gcd(psi_2)


class EllipticCurveIsogeny(EllipticCurveHom):
r"""
This class implements separable isogenies of elliptic curves.
Expand Down Expand Up @@ -1739,7 +1741,6 @@ def __setup_post_isomorphism(self, codomain, model):
post_isom = oldE2.isomorphism_to(codomain)
self.__set_post_isomorphism(codomain, post_isom)


###########################
# Velu's Formula Functions
###########################
Expand Down Expand Up @@ -1873,7 +1874,6 @@ def __compute_codomain_via_velu(self):
"""
return compute_codomain_formula(self._domain, self.__v, self.__w)


@staticmethod
def __velu_sum_helper(xQ, Qvalues, a1, a3, x, y):
r"""
Expand Down Expand Up @@ -1922,7 +1922,6 @@ def __velu_sum_helper(xQ, Qvalues, a1, a3, x, y):

return tX, tY


def __compute_via_velu_numeric(self, xP, yP):
r"""
Private function that sorts the list of points in the kernel
Expand Down Expand Up @@ -1952,7 +1951,6 @@ def __compute_via_velu_numeric(self, xP, yP):

return self.__compute_via_velu(xP,yP)


def __compute_via_velu(self, xP, yP):
r"""
Private function for Vélu's formulas, to perform the summation.
Expand Down Expand Up @@ -2018,7 +2016,6 @@ def __compute_via_velu(self, xP, yP):

return X, Y


def __initialize_rational_maps_via_velu(self):
r"""
Private function for Vélu's formulas, helper function to
Expand All @@ -2040,7 +2037,6 @@ def __initialize_rational_maps_via_velu(self):
y = self.__mpoly_ring.gen(1)
return self.__compute_via_velu(x,y)


def __init_kernel_polynomial_velu(self):
r"""
Private function for Vélu's formulas, helper function to
Expand Down Expand Up @@ -2070,7 +2066,6 @@ def __init_kernel_polynomial_velu(self):

self.__kernel_polynomial = psi


###################################
# Kohel's Variant of Velu's Formula
###################################
Expand Down Expand Up @@ -2262,7 +2257,6 @@ def __init_even_kernel_polynomial(self, E, psi_G):

return phi, omega, v, w, n, d


def __init_odd_kernel_polynomial(self, E, psi):
r"""
Return the isogeny parameters for a cyclic isogeny of odd degree.
Expand Down Expand Up @@ -2363,7 +2357,6 @@ def __init_odd_kernel_polynomial(self, E, psi):

return phi, omega, v, w, n, d


#
# This is the fast omega computation that works when characteristic is not 2
#
Expand Down Expand Up @@ -2692,36 +2685,6 @@ def scaling_factor(self):
sc *= self.__post_isomorphism.scaling_factor()
return sc

def as_morphism(self):
r"""
Return this isogeny as a morphism of projective schemes.
EXAMPLES::
sage: k = GF(11)
sage: E = EllipticCurve(k, [1,1])
sage: Q = E(6,5)
sage: phi = E.isogeny(Q)
sage: mor = phi.as_morphism()
sage: mor.domain() == E
True
sage: mor.codomain() == phi.codomain()
True
sage: mor(Q) == phi(Q)
True
TESTS::
sage: mor(0*Q)
(0 : 1 : 0)
sage: mor(1*Q)
(0 : 1 : 0)
"""
from sage.schemes.curves.constructor import Curve
X_affine = Curve(self.domain()).affine_patch(2)
Y_affine = Curve(self.codomain()).affine_patch(2)
return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2)

def kernel_polynomial(self):
r"""
Return the kernel polynomial of this isogeny.
Expand Down Expand Up @@ -3246,7 +3209,6 @@ def split_kernel_polynomial(poly):
from sage.misc.misc_c import prod
return prod([p for p,e in poly.squarefree_decomposition()])


def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="starks"):
r"""
Return the kernel polynomial of an isogeny of degree ``ell``
Expand Down Expand Up @@ -3487,7 +3449,6 @@ def compute_sequence_of_maps(E1, E2, ell):

return pre_isom, post_isom, E1pr, E2pr, ker_poly


# Utility functions for manipulating isogeny degree matrices

def fill_isogeny_matrix(M):
Expand Down
43 changes: 33 additions & 10 deletions src/sage/schemes/elliptic_curves/hom.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
- Lorenz Panny (2021): Refactor isogenies and isomorphisms into
the common :class:`EllipticCurveHom` interface.
"""

from sage.misc.cachefunc import cached_method
from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE

Expand Down Expand Up @@ -93,7 +92,6 @@ def _composition_(self, other, homset):
from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
return EllipticCurveHom_composite.from_factors([other, self])


@staticmethod
def _comparison_impl(left, right, op):
"""
Expand Down Expand Up @@ -194,7 +192,6 @@ def _richcmp_(self, other, op):

return richcmp(self.rational_maps(), other.rational_maps(), op)


def degree(self):
r"""
Return the degree of this elliptic-curve morphism.
Expand Down Expand Up @@ -327,11 +324,10 @@ def x_rational_map(self):
...
NotImplementedError: ...
"""
#TODO: could have a default implementation that simply
# returns the first component of rational_maps()
# TODO: could have a default implementation that simply
# returns the first component of rational_maps()
raise NotImplementedError('children must implement')


def scaling_factor(self):
r"""
Return the Weierstrass scaling factor associated to this
Expand Down Expand Up @@ -409,7 +405,6 @@ def formal(self, prec=20):
assert th.valuation() == +1, f"th has valuation {th.valuation()} (should be +1)"
return th


def is_normalized(self):
r"""
Determine whether this morphism is a normalized isogeny.
Expand Down Expand Up @@ -489,7 +484,6 @@ def is_normalized(self):
"""
return self.scaling_factor() == 1


def is_separable(self):
r"""
Determine whether or not this morphism is separable.
Expand Down Expand Up @@ -657,6 +651,36 @@ def __hash__(self):
"""
return hash((self.domain(), self.codomain(), self.kernel_polynomial()))

def as_morphism(self):
r"""
Return ``self`` as a morphism of projective schemes.
EXAMPLES::
sage: k = GF(11)
sage: E = EllipticCurve(k, [1,1])
sage: Q = E(6,5)
sage: phi = E.isogeny(Q)
sage: mor = phi.as_morphism()
sage: mor.domain() == E
True
sage: mor.codomain() == phi.codomain()
True
sage: mor(Q) == phi(Q)
True
TESTS::
sage: mor(0*Q)
(0 : 1 : 0)
sage: mor(1*Q)
(0 : 1 : 0)
"""
from sage.schemes.curves.constructor import Curve
X_affine = Curve(self.domain()).affine_patch(2)
Y_affine = Curve(self.codomain()).affine_patch(2)
return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2)


def compare_via_evaluation(left, right):
r"""
Expand Down Expand Up @@ -713,14 +737,13 @@ def compare_via_evaluation(left, right):
EE = E.base_extend(F.extension(e))
Ps = EE.gens()
return all(left._eval(P) == right._eval(P) for P in Ps)

elif isinstance(F, number_field_base.NumberField):
for _ in range(100):
P = E.lift_x(F.random_element(), extend=True)
if not P.has_finite_order():
return left._eval(P) == right._eval(P)
else:
assert False, "couldn't find a point of infinite order"

else:
raise NotImplementedError('not implemented for this base field')

19 changes: 12 additions & 7 deletions src/sage/schemes/elliptic_curves/hom_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
sage: EllipticCurveHom_composite(E, P)
Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143:
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722) over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x
+ (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722)
over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
Yet, the interface provided by :class:`EllipticCurveHom_composite`
is identical to :class:`EllipticCurveIsogeny` and other instantiations
Expand All @@ -40,10 +42,15 @@
sage: psi(E.lift_x(11))
(352 : 73 : 1)
sage: psi.rational_maps()
((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x - 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + 21),
(x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + 129*x^2*y + 163*x*y + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - 77*x^3 + 185*x^2 + 169*x - 128))
((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x -
72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x
+ 21), (x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y +
129*x^2*y + 163*x*y + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... -
77*x^3 + 185*x^2 + 169*x - 128))
sage: psi.kernel_polynomial()
x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10 + 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + 43*x^2 + 149*x + 373
x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10
+ 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 +
43*x^2 + 149*x + 373
sage: psi.dual()
Composite morphism of degree 35 = 7*5:
From: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419
Expand Down Expand Up @@ -82,7 +89,7 @@
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism

#TODO: implement sparse strategies? (cf. the SIKE cryptosystem)
# TODO: Implement sparse strategies? (cf. the SIKE cryptosystem)

def _eval_factored_isogeny(phis, P):
"""
Expand Down Expand Up @@ -468,7 +475,6 @@ def factors(self):
"""
return self._phis


# EllipticCurveHom methods

@staticmethod
Expand Down Expand Up @@ -765,7 +771,6 @@ def is_injective(self):
"""
return all(phi.is_injective() for phi in self._phis)


@staticmethod
def make_default():
r"""
Expand Down

0 comments on commit 685a07c

Please sign in to comment.