Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compute the matrix of an isogeny on a given n-torsion subgroup #35164

Merged
merged 4 commits into from
Mar 26, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions src/sage/schemes/elliptic_curves/hom.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

- Lorenz Panny (2021): Refactor isogenies and isomorphisms into
the common :class:`EllipticCurveHom` interface.

- Lorenz Panny (2022): :meth:`~EllipticCurveHom.matrix_on_subgroup`
"""
from sage.misc.cachefunc import cached_method
from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE
Expand Down Expand Up @@ -722,6 +724,108 @@ def as_morphism(self):
Y_affine = Curve(self.codomain()).affine_patch(2)
return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2)

def matrix_on_subgroup(self, domain_gens, codomain_gens=None):
r"""
Return the matrix as which this isogeny acts on the
yyyyx4 marked this conversation as resolved.
Show resolved Hide resolved
`n`-torsion subgroup with respect to the given bases.

(This is useful for tasks such as computing a set of
yyyyx4 marked this conversation as resolved.
Show resolved Hide resolved
generators for the kernel subgroup.)

INPUT:

- ``domain_gens`` -- basis `(P,Q)` of some `n`-torsion
subgroup on the domain of this elliptic-curve morphism

- ``codomain_gens`` -- basis `(R,S)` of the `n`-torsion
on the codomain of this morphism, or (default) ``None``
if ``self`` is an endomorphism

OUTPUT:

A `2\times 2` matrix `M` over `\ZZ/n`, such that the
image of any point `[a]P + [b]Q` under this morphism
equals `[c]R + [d]S` where `(c\ d)^T = (a\ b) M`.

EXAMPLES::

sage: F.<i> = GF(419^2, modulus=[1,0,1])
sage: E = EllipticCurve(F, [1,0])
sage: P = E(3, 176*i)
sage: Q = E(i+7, 67*i+48)
sage: P.weil_pairing(Q, 420).multiplicative_order()
420
sage: iota = E.automorphisms()[2]; iota
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in i of size 419^2
Via: (u,r,s,t) = (i, 0, 0, 0)
sage: iota^2 == E.scalar_multiplication(-1)
True
sage: mat = iota.matrix_on_subgroup((P,Q)); mat
[301 386]
[ 83 119]
sage: mat.parent()
Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 420
sage: iota(P) == 301*P + 386*Q
True
sage: iota(Q) == 83*P + 119*Q
True
sage: a,b = 123, 456
sage: c,d = vector((a,b)) * mat; (c,d)
(111, 102)
sage: iota(a*P + b*Q) == c*P + d*Q
True

We can compute the matrix of a Frobenius endomorphism
(:class:`~sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius`)
on a large enough subgroup to verify point-counting results::

sage: F.<a> = GF((101, 36))
sage: E = EllipticCurve(GF(101), [1,1])
sage: EE = E.change_ring(F)
sage: P,Q = EE.torsion_basis(37)
sage: pi = EE.frobenius_isogeny()
sage: M = pi.matrix_on_subgroup((P,Q))
sage: M.trace()
34
sage: E.trace_of_frobenius()
-3

.. SEEALSO::

To compute a basis of the `n`-torsion, you may use
:meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.torsion_basis`.
"""
if codomain_gens is None:
if not self.is_endomorphism():
raise ValueError('basis of codomain subgroup is required for non-endomorphisms')
codomain_gens = domain_gens

P,Q = domain_gens
R,S = codomain_gens

ords = {P.order() for P in (P,Q,R,S)}
if len(ords) != 1:
#TODO: Is there some meaningful way to lift this restriction?
raise ValueError('generator points must all have the same order')
n, = ords

if P.weil_pairing(Q, n).multiplicative_order() != n:
raise ValueError('generator points on domain are not independent')
if R.weil_pairing(S, n).multiplicative_order() != n:
raise ValueError('generator points on codomain are not independent')

imP = self(P)
imQ = self(Q)

from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper
H = AdditiveAbelianGroupWrapper(self.codomain().point_homset(), [R,S], [n,n])
vecP = H.discrete_log(imP)
vecQ = H.discrete_log(imQ)

from sage.matrix.constructor import matrix
from sage.rings.finite_rings.integer_mod_ring import Zmod
return matrix(Zmod(n), [vecP, vecQ])


def compare_via_evaluation(left, right):
r"""
Expand Down