From b4fd94ccfd460f6951d38382bb7b6690e97f4e68 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 21 Dec 2022 12:24:26 +0800 Subject: [PATCH 1/3] compute the matrix of an isogeny on a given n-torsion subgroup --- src/sage/schemes/elliptic_curves/hom.py | 89 +++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index e4de0f2cf42..e0f6e223e3b 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -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 @@ -722,6 +724,93 @@ 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 + `n`-torsion subgroup with respect to the given bases. + + (This is useful for tasks such as computing a set of + 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. = 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 + + .. 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""" From 10aff667b8cfb0177eedf5ef692b27122aceeacd Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 20 Feb 2023 16:25:08 +0800 Subject: [PATCH 2/3] add another example --- src/sage/schemes/elliptic_curves/hom.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index e0f6e223e3b..eeb2bdd530d 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -775,6 +775,21 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): 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. = 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 From b04edc8b613c5fe276d25b377b602c96be01af42 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 21 Feb 2023 10:50:25 +0800 Subject: [PATCH 3/3] tweak documentation following reviewer feedback --- src/sage/schemes/elliptic_curves/hom.py | 30 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index eeb2bdd530d..e1c5ed25c84 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -726,12 +726,9 @@ def as_morphism(self): def matrix_on_subgroup(self, domain_gens, codomain_gens=None): r""" - Return the matrix as which this isogeny acts on the + Return the matrix by which this isogeny acts on the `n`-torsion subgroup with respect to the given bases. - (This is useful for tasks such as computing a set of - generators for the kernel subgroup.) - INPUT: - ``domain_gens`` -- basis `(P,Q)` of some `n`-torsion @@ -775,7 +772,28 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): sage: iota(a*P + b*Q) == c*P + d*Q True - We can compute the matrix of a Frobenius endomorphism + One important application of this is to compute generators of + the kernel subgroup of an isogeny, when the `n`-torsion subgroup + containing the kernel is accessible:: + + sage: K = E(83*i-16, 9*i-147) + sage: K.order() + 7 + sage: phi = E.isogeny(K) + sage: R,S = phi.codomain().gens() + sage: mat = phi.matrix_on_subgroup((P,Q), (R,S)) + sage: mat # random -- depends on R,S + [124 263] + [115 141] + sage: kermat = mat.left_kernel_matrix(); kermat + [300 60] + sage: ker = [ZZ(v[0])*P + ZZ(v[1])*Q for v in kermat] + sage: {phi(T) for T in ker} + {(0 : 1 : 0)} + sage: phi == E.isogeny(ker) + True + + We can also 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:: @@ -785,6 +803,8 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): sage: P,Q = EE.torsion_basis(37) sage: pi = EE.frobenius_isogeny() sage: M = pi.matrix_on_subgroup((P,Q)) + sage: M.parent() + Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 37 sage: M.trace() 34 sage: E.trace_of_frobenius()