passagemath-schemes 10.8.1a4__cp314-cp314t-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.8.1a4.dist-info/METADATA +203 -0
- passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
- passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
- passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
- passagemath_schemes-10.8.1a4.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9556 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2578 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +727 -0
- sage/lfunctions/pari.py +971 -0
- sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5132 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
- sage/modular/abvar/abvar_newform.py +246 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +187 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +721 -0
- sage/modular/abvar/homspace.py +989 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +741 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1406 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +361 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +659 -0
- sage/modular/arithgroup/congroup_gammaH.py +1491 -0
- sage/modular/arithgroup/congroup_generic.py +630 -0
- sage/modular/arithgroup/congroup_sl2z.py +266 -0
- sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1067 -0
- sage/modular/arithgroup/tests.py +425 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3736 -0
- sage/modular/btquotients/pautomorphicform.py +2564 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1107 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +571 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1076 -0
- sage/modular/hecke/algebra.py +725 -0
- sage/modular/hecke/all.py +19 -0
- sage/modular/hecke/ambient_module.py +994 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +302 -0
- sage/modular/hecke/hecke_operator.py +736 -0
- sage/modular/hecke/homspace.py +185 -0
- sage/modular/hecke/module.py +1744 -0
- sage/modular/hecke/morphism.py +139 -0
- sage/modular/hecke/submodule.py +970 -0
- sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2020 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1070 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +817 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +120 -0
- sage/modular/modform/ambient_g1.py +199 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +487 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4105 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +127 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1859 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +380 -0
- sage/modular/modform/weight1.py +221 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2527 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3349 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3844 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1291 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +376 -0
- sage/modular/multiple_zeta.py +2635 -0
- sage/modular/multiple_zeta_F_algebra.py +789 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1879 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +776 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +856 -0
- sage/modular/pollack_stevens/modsym.py +1590 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1078 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +846 -0
- sage/modular/quasimodform/ring.py +826 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +700 -0
- sage/schemes/curves/affine_curve.py +2924 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +397 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3203 -0
- sage/schemes/curves/weighted_projective_curve.py +106 -0
- sage/schemes/curves/zariski_vankampen.py +1931 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +991 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1103 -0
- sage/schemes/elliptic_curves/constructor.py +1530 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
- sage/schemes/elliptic_curves/ell_egros.py +457 -0
- sage/schemes/elliptic_curves/ell_field.py +2837 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3249 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4944 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7184 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1663 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7328 -0
- sage/schemes/elliptic_curves/height.py +2108 -0
- sage/schemes/elliptic_curves/hom.py +1788 -0
- sage/schemes/elliptic_curves/hom_composite.py +1084 -0
- sage/schemes/elliptic_curves/hom_fractional.py +544 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +681 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1523 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +247 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +915 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +716 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +369 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +312 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3863 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +581 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +53 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4177 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,3249 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
"""
|
|
3
|
+
Elliptic curves over finite fields
|
|
4
|
+
|
|
5
|
+
AUTHORS:
|
|
6
|
+
|
|
7
|
+
- William Stein (2005): Initial version
|
|
8
|
+
|
|
9
|
+
- Robert Bradshaw et al....
|
|
10
|
+
|
|
11
|
+
- John Cremona (2008-02): Point counting and group structure for
|
|
12
|
+
non-prime fields, Frobenius endomorphism and order, elliptic logs
|
|
13
|
+
|
|
14
|
+
- Mariah Lenox (2011-03): Added ``set_order`` method
|
|
15
|
+
|
|
16
|
+
- Lorenz Panny, John Cremona (2023-02): ``.twists()``
|
|
17
|
+
|
|
18
|
+
- Lorenz Panny (2023): ``special_supersingular_curve()``
|
|
19
|
+
|
|
20
|
+
- Martin Grenouilloux, Gareth Ma (2024-09): ``EllipticCurve_with_prime_order()``
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
25
|
+
#
|
|
26
|
+
# This program is free software: you can redistribute it and/or modify
|
|
27
|
+
# it under the terms of the GNU General Public License as published by
|
|
28
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
29
|
+
# (at your option) any later version.
|
|
30
|
+
# https://www.gnu.org/licenses/
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
|
|
33
|
+
import sage.groups.generic as generic
|
|
34
|
+
|
|
35
|
+
from sage.arith.functions import lcm
|
|
36
|
+
from sage.arith.misc import binomial, GCD as gcd
|
|
37
|
+
from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper
|
|
38
|
+
from sage.misc.cachefunc import cached_method
|
|
39
|
+
from sage.rings.finite_rings.finite_field_base import FiniteField
|
|
40
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
41
|
+
from sage.rings.integer import Integer
|
|
42
|
+
from sage.rings.integer_ring import ZZ
|
|
43
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
|
44
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
45
|
+
from sage.schemes.curves.projective_curve import Hasse_bounds, ProjectivePlaneCurve_finite_field
|
|
46
|
+
from sage.structure.element import Element
|
|
47
|
+
|
|
48
|
+
from . import ell_point
|
|
49
|
+
from .constructor import EllipticCurve
|
|
50
|
+
from .ell_field import EllipticCurve_field
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class EllipticCurve_finite_field(EllipticCurve_field, ProjectivePlaneCurve_finite_field):
|
|
54
|
+
r"""
|
|
55
|
+
Elliptic curve over a finite field.
|
|
56
|
+
|
|
57
|
+
EXAMPLES::
|
|
58
|
+
|
|
59
|
+
sage: EllipticCurve(GF(101),[2,3])
|
|
60
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field of size 101
|
|
61
|
+
|
|
62
|
+
sage: # needs sage.rings.finite_rings
|
|
63
|
+
sage: F = GF(101^2, 'a')
|
|
64
|
+
sage: EllipticCurve([F(2),F(3)])
|
|
65
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field in a of size 101^2
|
|
66
|
+
|
|
67
|
+
Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type
|
|
68
|
+
"elliptic curve over a finite field"::
|
|
69
|
+
|
|
70
|
+
sage: F = Zmod(101)
|
|
71
|
+
sage: EllipticCurve(F, [2, 3])
|
|
72
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101
|
|
73
|
+
sage: E = EllipticCurve([F(2), F(3)])
|
|
74
|
+
sage: type(E)
|
|
75
|
+
<class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
|
|
76
|
+
sage: E.category()
|
|
77
|
+
Category of abelian varieties over Ring of integers modulo 101
|
|
78
|
+
|
|
79
|
+
Elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type
|
|
80
|
+
"generic elliptic curve"::
|
|
81
|
+
|
|
82
|
+
sage: F = Zmod(95)
|
|
83
|
+
sage: EllipticCurve(F, [2, 3])
|
|
84
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95
|
|
85
|
+
sage: E = EllipticCurve([F(2), F(3)])
|
|
86
|
+
sage: type(E)
|
|
87
|
+
<class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'>
|
|
88
|
+
sage: E.category()
|
|
89
|
+
Category of schemes over Ring of integers modulo 95
|
|
90
|
+
sage: TestSuite(E).run(skip=["_test_elements"])
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
_point = ell_point.EllipticCurvePoint_finite_field
|
|
94
|
+
|
|
95
|
+
def plot(self, *args, **kwds):
|
|
96
|
+
"""
|
|
97
|
+
Draw a graph of this elliptic curve over a prime finite field.
|
|
98
|
+
|
|
99
|
+
INPUT:
|
|
100
|
+
|
|
101
|
+
- ``*args``, ``**kwds`` -- all other options are passed
|
|
102
|
+
to the circle graphing primitive
|
|
103
|
+
|
|
104
|
+
EXAMPLES::
|
|
105
|
+
|
|
106
|
+
sage: E = EllipticCurve(FiniteField(17), [0,1])
|
|
107
|
+
sage: P = plot(E, rgbcolor=(0,0,1)) # needs sage.plot
|
|
108
|
+
"""
|
|
109
|
+
R = self.base_ring()
|
|
110
|
+
if not R.is_prime_field():
|
|
111
|
+
raise NotImplementedError
|
|
112
|
+
|
|
113
|
+
from sage.plot.point import points
|
|
114
|
+
|
|
115
|
+
return points([P[0:2] for P in self.points() if not P.is_zero()], *args, **kwds)
|
|
116
|
+
|
|
117
|
+
def _points_via_group_structure(self):
|
|
118
|
+
r"""
|
|
119
|
+
Return a list of all the points on the curve using the group structure.
|
|
120
|
+
|
|
121
|
+
For cyclic groups with generator `G` of order `n`, the set of points
|
|
122
|
+
is computed from `[x]G` for `x \in [0, n - 1]` requiring `n - 2`
|
|
123
|
+
additions on the curve.
|
|
124
|
+
|
|
125
|
+
For non-cyclic groups, first two cyclic subgroups `H_i` are computed as
|
|
126
|
+
above from `[x]G_i` for `x \in [0, n_i]` requiring `n_1 + n_2 - 4`
|
|
127
|
+
additions. The set of all points is returned as the cartesian product
|
|
128
|
+
of these two cyclic groups.
|
|
129
|
+
|
|
130
|
+
When the group is trivial, only the point at infinity is returned.
|
|
131
|
+
|
|
132
|
+
EXAMPLES::
|
|
133
|
+
|
|
134
|
+
sage: S = EllipticCurve(GF(97),[2,3])._points_via_group_structure()
|
|
135
|
+
sage: len(S)
|
|
136
|
+
100
|
|
137
|
+
|
|
138
|
+
See :issue:`4687`, where the following example did not work::
|
|
139
|
+
|
|
140
|
+
sage: E = EllipticCurve(GF(2),[0, 0, 1, 1, 1])
|
|
141
|
+
sage: E.points()
|
|
142
|
+
[(0 : 1 : 0)]
|
|
143
|
+
|
|
144
|
+
::
|
|
145
|
+
|
|
146
|
+
sage: E = EllipticCurve(GF(2),[0, 0, 1, 0, 1])
|
|
147
|
+
sage: E.points()
|
|
148
|
+
[(0 : 1 : 0), (1 : 0 : 1), (1 : 1 : 1)]
|
|
149
|
+
|
|
150
|
+
::
|
|
151
|
+
|
|
152
|
+
sage: # needs sage.rings.finite_rings
|
|
153
|
+
sage: E = EllipticCurve(GF(4,'a'),[0, 0, 1, 0, 1])
|
|
154
|
+
sage: E.points()
|
|
155
|
+
[(0 : 1 : 0), (0 : a : 1), (0 : a + 1 : 1), (1 : 0 : 1), (1 : 1 : 1), (a : 0 : 1), (a : 1 : 1), (a + 1 : 0 : 1), (a + 1 : 1 : 1)]
|
|
156
|
+
"""
|
|
157
|
+
# TODO, eliminate when polynomial calling is fast
|
|
158
|
+
# 11-03-2024 - G. Pope : it is not clear to me what the above TODO references
|
|
159
|
+
|
|
160
|
+
# Compute the generators of the abelian group of the curve
|
|
161
|
+
G = self.abelian_group()
|
|
162
|
+
gens = [x.element() for x in G.gens()]
|
|
163
|
+
|
|
164
|
+
# Zero element of the group
|
|
165
|
+
zero = self(0)
|
|
166
|
+
|
|
167
|
+
# Trivial group, return the identity element only
|
|
168
|
+
if len(gens) == 0:
|
|
169
|
+
return [zero]
|
|
170
|
+
|
|
171
|
+
def __multiples(G):
|
|
172
|
+
"""
|
|
173
|
+
Compute the list of points [i]G for i in [0, G.order())
|
|
174
|
+
"""
|
|
175
|
+
H = [zero, G]
|
|
176
|
+
P = G
|
|
177
|
+
for _ in range(2, G.order()):
|
|
178
|
+
P += G
|
|
179
|
+
H.append(P)
|
|
180
|
+
return H
|
|
181
|
+
|
|
182
|
+
# Collect all multiples of the generator
|
|
183
|
+
H1 = __multiples(gens[0])
|
|
184
|
+
|
|
185
|
+
# Cyclic case, we now have all points
|
|
186
|
+
if len(gens) == 1:
|
|
187
|
+
return H1
|
|
188
|
+
|
|
189
|
+
# Non-cyclic case we generate the second set of points and compute
|
|
190
|
+
# the entire set of points from the Cartesian product
|
|
191
|
+
H2 = __multiples(gens[1])
|
|
192
|
+
return [P + Q for P in H1 for Q in H2]
|
|
193
|
+
|
|
194
|
+
def points(self):
|
|
195
|
+
r"""
|
|
196
|
+
Return all rational points on this elliptic curve. The list of points is cached
|
|
197
|
+
so subsequent calls are free.
|
|
198
|
+
|
|
199
|
+
EXAMPLES::
|
|
200
|
+
|
|
201
|
+
sage: p = 5
|
|
202
|
+
sage: F = GF(p)
|
|
203
|
+
sage: E = EllipticCurve(F, [1, 3])
|
|
204
|
+
sage: len(E.points())
|
|
205
|
+
4
|
|
206
|
+
sage: E.order()
|
|
207
|
+
4
|
|
208
|
+
sage: E.points()
|
|
209
|
+
[(0 : 1 : 0), (1 : 0 : 1), (4 : 1 : 1), (4 : 4 : 1)]
|
|
210
|
+
|
|
211
|
+
::
|
|
212
|
+
|
|
213
|
+
sage: K = GF((p, 2), 'a')
|
|
214
|
+
sage: E = E.change_ring(K)
|
|
215
|
+
sage: len(E.points())
|
|
216
|
+
32
|
|
217
|
+
sage: E.order()
|
|
218
|
+
32
|
|
219
|
+
sage: w = E.points(); w
|
|
220
|
+
[(0 : 1 : 0), (0 : 2*a + 4 : 1), (0 : 3*a + 1 : 1), (1 : 0 : 1), (2 : 2*a + 4 : 1), (2 : 3*a + 1 : 1), (3 : 2*a + 4 : 1), (3 : 3*a + 1 : 1), (4 : 1 : 1), (4 : 4 : 1), (a : 1 : 1), (a : 4 : 1), (a + 2 : a + 1 : 1), (a + 2 : 4*a + 4 : 1), (a + 3 : a : 1), (a + 3 : 4*a : 1), (a + 4 : 0 : 1), (2*a : 2*a : 1), (2*a : 3*a : 1), (2*a + 4 : a + 1 : 1), (2*a + 4 : 4*a + 4 : 1), (3*a + 1 : a + 3 : 1), (3*a + 1 : 4*a + 2 : 1), (3*a + 2 : 2*a + 3 : 1), (3*a + 2 : 3*a + 2 : 1), (4*a : 0 : 1), (4*a + 1 : 1 : 1), (4*a + 1 : 4 : 1), (4*a + 3 : a + 3 : 1), (4*a + 3 : 4*a + 2 : 1), (4*a + 4 : a + 4 : 1), (4*a + 4 : 4*a + 1 : 1)]
|
|
221
|
+
|
|
222
|
+
Note that the returned list is an immutable sorted Sequence::
|
|
223
|
+
|
|
224
|
+
sage: w[0] = 9
|
|
225
|
+
Traceback (most recent call last):
|
|
226
|
+
...
|
|
227
|
+
ValueError: object is immutable; please change a copy instead.
|
|
228
|
+
"""
|
|
229
|
+
if hasattr(self, "__points"):
|
|
230
|
+
return self.__points
|
|
231
|
+
|
|
232
|
+
from sage.structure.sequence import Sequence
|
|
233
|
+
v = self._points_via_group_structure()
|
|
234
|
+
v.sort()
|
|
235
|
+
self.__points = Sequence(v, immutable=True)
|
|
236
|
+
return self.__points
|
|
237
|
+
|
|
238
|
+
rational_points = points
|
|
239
|
+
|
|
240
|
+
def count_points(self, n=1):
|
|
241
|
+
"""
|
|
242
|
+
Return the cardinality of this elliptic curve over the base field or extensions.
|
|
243
|
+
|
|
244
|
+
INPUT:
|
|
245
|
+
|
|
246
|
+
- ``n`` -- positive integer
|
|
247
|
+
|
|
248
|
+
OUTPUT: if `n=1`, returns the cardinality of the curve over its base field
|
|
249
|
+
|
|
250
|
+
If `n>1`, returns a list `[c_1, c_2, ..., c_n]` where `c_d` is
|
|
251
|
+
the cardinality of the curve over the extension of degree `d`
|
|
252
|
+
of its base field.
|
|
253
|
+
|
|
254
|
+
EXAMPLES::
|
|
255
|
+
|
|
256
|
+
sage: p = 101
|
|
257
|
+
sage: F = GF(p)
|
|
258
|
+
sage: E = EllipticCurve(F, [2,3])
|
|
259
|
+
sage: E.count_points(1)
|
|
260
|
+
96
|
|
261
|
+
sage: E.count_points(5)
|
|
262
|
+
[96, 10368, 1031904, 104053248, 10509895776]
|
|
263
|
+
|
|
264
|
+
::
|
|
265
|
+
|
|
266
|
+
sage: # needs sage.rings.finite_rings
|
|
267
|
+
sage: F.<a> = GF(p^2)
|
|
268
|
+
sage: E = EllipticCurve(F, [a,a])
|
|
269
|
+
sage: E.cardinality()
|
|
270
|
+
10295
|
|
271
|
+
sage: E.count_points()
|
|
272
|
+
10295
|
|
273
|
+
sage: E.count_points(1)
|
|
274
|
+
10295
|
|
275
|
+
sage: E.count_points(5)
|
|
276
|
+
[10295, 104072155, 1061518108880, 10828567126268595, 110462212555439192375]
|
|
277
|
+
"""
|
|
278
|
+
try:
|
|
279
|
+
n = Integer(n)
|
|
280
|
+
except TypeError:
|
|
281
|
+
raise TypeError("n must be a positive integer")
|
|
282
|
+
|
|
283
|
+
if n < 1:
|
|
284
|
+
raise ValueError("n must be a positive integer")
|
|
285
|
+
|
|
286
|
+
if n == 1:
|
|
287
|
+
return self.cardinality()
|
|
288
|
+
|
|
289
|
+
return [self.cardinality(extension_degree=i) for i in range(1, n + 1)]
|
|
290
|
+
|
|
291
|
+
def trace_of_frobenius(self):
|
|
292
|
+
r"""
|
|
293
|
+
Return the trace of Frobenius acting on this elliptic curve.
|
|
294
|
+
|
|
295
|
+
.. NOTE::
|
|
296
|
+
|
|
297
|
+
This computes the curve cardinality, which may be
|
|
298
|
+
time-consuming.
|
|
299
|
+
|
|
300
|
+
EXAMPLES::
|
|
301
|
+
|
|
302
|
+
sage: E = EllipticCurve(GF(101),[2,3])
|
|
303
|
+
sage: E.trace_of_frobenius()
|
|
304
|
+
6
|
|
305
|
+
sage: E = EllipticCurve(GF(11^5,'a'),[2,5]) # needs sage.rings.finite_rings
|
|
306
|
+
sage: E.trace_of_frobenius() # needs sage.rings.finite_rings
|
|
307
|
+
802
|
|
308
|
+
|
|
309
|
+
The following shows that the issue from :issue:`2849` is fixed::
|
|
310
|
+
|
|
311
|
+
sage: E = EllipticCurve(GF(3^5,'a'),[-1,-1]) # needs sage.rings.finite_rings
|
|
312
|
+
sage: E.trace_of_frobenius() # needs sage.rings.finite_rings
|
|
313
|
+
-27
|
|
314
|
+
"""
|
|
315
|
+
return 1 + self.base_field().order() - self.cardinality()
|
|
316
|
+
|
|
317
|
+
def cardinality(self, algorithm=None, extension_degree=1):
|
|
318
|
+
r"""
|
|
319
|
+
Return the number of points on this elliptic curve.
|
|
320
|
+
|
|
321
|
+
INPUT:
|
|
322
|
+
|
|
323
|
+
- ``algorithm`` -- (optional) string:
|
|
324
|
+
|
|
325
|
+
- ``'pari'`` -- use the PARI C-library function ``ellcard``
|
|
326
|
+
|
|
327
|
+
- ``'bsgs'`` -- use the baby-step giant-step method as
|
|
328
|
+
implemented in Sage, with the Cremona-Sutherland version
|
|
329
|
+
of Mestre's trick
|
|
330
|
+
|
|
331
|
+
- ``'exhaustive'`` -- naive point counting
|
|
332
|
+
|
|
333
|
+
- ``'subfield'`` -- reduce to a smaller field, provided that
|
|
334
|
+
the j-invariant lies in a subfield
|
|
335
|
+
|
|
336
|
+
- ``'all'`` -- compute cardinality with both ``'pari'`` and
|
|
337
|
+
``'bsgs'``; return result if they agree or raise a
|
|
338
|
+
:exc:`AssertionError` if they do not
|
|
339
|
+
|
|
340
|
+
- ``extension_degree`` -- integer `d` (default: 1); if the
|
|
341
|
+
base field is `\GF{q}`, return the cardinality of ``self``
|
|
342
|
+
over the extension `\GF{q^d}` of degree `d`
|
|
343
|
+
|
|
344
|
+
OUTPUT:
|
|
345
|
+
|
|
346
|
+
The order of the group of rational points of ``self`` over its
|
|
347
|
+
base field, or over an extension field of degree `d` as above.
|
|
348
|
+
The result is cached.
|
|
349
|
+
|
|
350
|
+
EXAMPLES::
|
|
351
|
+
|
|
352
|
+
sage: # needs sage.rings.finite_rings
|
|
353
|
+
sage: EllipticCurve(GF(4, 'a'), [1,2,3,4,5]).cardinality()
|
|
354
|
+
8
|
|
355
|
+
sage: k.<a> = GF(3^3)
|
|
356
|
+
sage: l = [a^2 + 1, 2*a^2 + 2*a + 1, a^2 + a + 1, 2, 2*a]
|
|
357
|
+
sage: EllipticCurve(k,l).cardinality()
|
|
358
|
+
29
|
|
359
|
+
|
|
360
|
+
::
|
|
361
|
+
|
|
362
|
+
sage: # needs sage.rings.finite_rings
|
|
363
|
+
sage: l = [1, 1, 0, 2, 0]
|
|
364
|
+
sage: EllipticCurve(k, l).cardinality()
|
|
365
|
+
38
|
|
366
|
+
|
|
367
|
+
An even bigger extension (which we check against Magma)::
|
|
368
|
+
|
|
369
|
+
sage: # needs sage.rings.finite_rings
|
|
370
|
+
sage: EllipticCurve(GF(3^100, 'a'), [1,2,3,4,5]).cardinality()
|
|
371
|
+
515377520732011331036459693969645888996929981504
|
|
372
|
+
sage: magma.eval("Order(EllipticCurve([GF(3^100)|1,2,3,4,5]))") # optional - magma
|
|
373
|
+
'515377520732011331036459693969645888996929981504'
|
|
374
|
+
|
|
375
|
+
::
|
|
376
|
+
|
|
377
|
+
sage: EllipticCurve(GF(10007), [1,2,3,4,5]).cardinality()
|
|
378
|
+
10076
|
|
379
|
+
sage: EllipticCurve(GF(10007), [1,2,3,4,5]).cardinality(algorithm='pari')
|
|
380
|
+
10076
|
|
381
|
+
sage: EllipticCurve(GF(next_prime(10**20)), [1,2,3,4,5]).cardinality()
|
|
382
|
+
100000000011093199520
|
|
383
|
+
|
|
384
|
+
The cardinality is cached::
|
|
385
|
+
|
|
386
|
+
sage: # needs sage.rings.finite_rings
|
|
387
|
+
sage: E = EllipticCurve(GF(3^100, 'a'), [1,2,3,4,5])
|
|
388
|
+
sage: E.cardinality() is E.cardinality()
|
|
389
|
+
True
|
|
390
|
+
|
|
391
|
+
The following is very fast since the curve is actually defined
|
|
392
|
+
over the prime field::
|
|
393
|
+
|
|
394
|
+
sage: # needs sage.rings.finite_rings
|
|
395
|
+
sage: k.<a> = GF(11^100)
|
|
396
|
+
sage: E1 = EllipticCurve(k, [3,3])
|
|
397
|
+
sage: N1 = E1.cardinality(algorithm='subfield'); N1
|
|
398
|
+
137806123398222701841183371720896367762643312000384671846835266941791510341065565176497846502742959856128
|
|
399
|
+
sage: E1.cardinality_pari() == N1
|
|
400
|
+
True
|
|
401
|
+
sage: E2 = E1.quadratic_twist()
|
|
402
|
+
sage: N2 = E2.cardinality(algorithm='subfield'); N2
|
|
403
|
+
137806123398222701841183371720896367762643312000384656816094284101308193849980588362304472492174093035876
|
|
404
|
+
sage: E2.cardinality_pari() == N2
|
|
405
|
+
True
|
|
406
|
+
sage: N1 + N2 == 2*(k.cardinality() + 1)
|
|
407
|
+
True
|
|
408
|
+
|
|
409
|
+
We can count points over curves defined as a reduction::
|
|
410
|
+
|
|
411
|
+
sage: # needs sage.rings.number_field
|
|
412
|
+
sage: x = polygen(QQ)
|
|
413
|
+
sage: K.<w> = NumberField(x^2 + x + 1)
|
|
414
|
+
sage: EK = EllipticCurve(K, [0, 0, w, 2, 1])
|
|
415
|
+
sage: E = EK.base_extend(K.residue_field(2))
|
|
416
|
+
sage: E
|
|
417
|
+
Elliptic Curve defined by y^2 + wbar*y = x^3 + 1
|
|
418
|
+
over Residue field in wbar of Fractional ideal (2)
|
|
419
|
+
sage: E.cardinality()
|
|
420
|
+
7
|
|
421
|
+
sage: E = EK.base_extend(K.residue_field(w - 1))
|
|
422
|
+
sage: E.abelian_group()
|
|
423
|
+
Trivial group embedded in Abelian group of points on Elliptic Curve defined
|
|
424
|
+
by y^2 + y = x^3 + 2*x + 1 over Residue field of Fractional ideal (w - 1)
|
|
425
|
+
|
|
426
|
+
::
|
|
427
|
+
|
|
428
|
+
sage: R.<x> = GF(17)[]
|
|
429
|
+
sage: pol = R.irreducible_element(5)
|
|
430
|
+
sage: k.<a> = R.residue_field(pol)
|
|
431
|
+
sage: E = EllipticCurve(R, [1, x]).base_extend(k)
|
|
432
|
+
sage: E
|
|
433
|
+
Elliptic Curve defined by y^2 = x^3 + x + a
|
|
434
|
+
over Residue field in a of Principal ideal (x^5 + x + 14)
|
|
435
|
+
of Univariate Polynomial Ring in x over Finite Field of size 17
|
|
436
|
+
sage: E.cardinality()
|
|
437
|
+
1421004
|
|
438
|
+
|
|
439
|
+
TESTS::
|
|
440
|
+
|
|
441
|
+
sage: EllipticCurve(GF(10009), [1,2,3,4,5]).cardinality(algorithm='foobar')
|
|
442
|
+
Traceback (most recent call last):
|
|
443
|
+
...
|
|
444
|
+
ValueError: algorithm 'foobar' is not known
|
|
445
|
+
|
|
446
|
+
If the cardinality has already been computed, then the ``algorithm``
|
|
447
|
+
keyword is ignored::
|
|
448
|
+
|
|
449
|
+
sage: E = EllipticCurve(GF(10007), [1,2,3,4,5])
|
|
450
|
+
sage: E.cardinality(algorithm='pari')
|
|
451
|
+
10076
|
|
452
|
+
sage: E.cardinality(algorithm='foobar')
|
|
453
|
+
10076
|
|
454
|
+
|
|
455
|
+
Check that a bug noted at :issue:`15667` is fixed::
|
|
456
|
+
|
|
457
|
+
sage: # needs sage.rings.finite_rings
|
|
458
|
+
sage: F.<a> = GF(3^6)
|
|
459
|
+
sage: EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]).cardinality()
|
|
460
|
+
784
|
|
461
|
+
"""
|
|
462
|
+
if extension_degree > 1:
|
|
463
|
+
# A recursive call to cardinality() with
|
|
464
|
+
# extension_degree=1, which will cache the cardinality, is
|
|
465
|
+
# made by the call to frobenius_order() here:
|
|
466
|
+
frob = self.frobenius() ** extension_degree - 1
|
|
467
|
+
R = self.frobenius_order()
|
|
468
|
+
if R.degree() == 1:
|
|
469
|
+
return frob * frob
|
|
470
|
+
else:
|
|
471
|
+
return frob.norm()
|
|
472
|
+
|
|
473
|
+
# We need manual caching (not @cached_method) since various
|
|
474
|
+
# other methods refer to this _order attribute, in particular
|
|
475
|
+
# self.set_order().
|
|
476
|
+
try:
|
|
477
|
+
return self._order
|
|
478
|
+
except AttributeError:
|
|
479
|
+
pass
|
|
480
|
+
|
|
481
|
+
jpol = None
|
|
482
|
+
if algorithm is None:
|
|
483
|
+
# Check for j in subfield
|
|
484
|
+
jpol = self.j_invariant().minimal_polynomial()
|
|
485
|
+
if jpol.degree() < self.base_field().degree():
|
|
486
|
+
algorithm = "subfield"
|
|
487
|
+
else:
|
|
488
|
+
algorithm = "pari"
|
|
489
|
+
|
|
490
|
+
if algorithm == "pari":
|
|
491
|
+
N = self.cardinality_pari()
|
|
492
|
+
elif algorithm == "subfield":
|
|
493
|
+
if jpol is None:
|
|
494
|
+
jpol = self.j_invariant().minimal_polynomial()
|
|
495
|
+
N = self._cardinality_subfield(jpol)
|
|
496
|
+
elif algorithm == "bsgs":
|
|
497
|
+
N = self.cardinality_bsgs()
|
|
498
|
+
elif algorithm == "exhaustive":
|
|
499
|
+
N = self.cardinality_exhaustive()
|
|
500
|
+
elif algorithm == "all":
|
|
501
|
+
N = self.cardinality_pari()
|
|
502
|
+
N2 = self.cardinality_bsgs()
|
|
503
|
+
if N != N2:
|
|
504
|
+
raise AssertionError("cardinality with pari=%s but with bsgs=%s" % (N, N2))
|
|
505
|
+
else:
|
|
506
|
+
raise ValueError("algorithm {!r} is not known".format(algorithm))
|
|
507
|
+
|
|
508
|
+
self._order = N
|
|
509
|
+
return N
|
|
510
|
+
|
|
511
|
+
from .cardinality import (cardinality_bsgs,
|
|
512
|
+
cardinality_exhaustive, _cardinality_subfield)
|
|
513
|
+
|
|
514
|
+
order = cardinality # alias
|
|
515
|
+
|
|
516
|
+
@cached_method
|
|
517
|
+
def multiplication_by_p_isogeny(self):
|
|
518
|
+
r"""
|
|
519
|
+
Return the multiplication-by-`p` isogeny.
|
|
520
|
+
|
|
521
|
+
EXAMPLES::
|
|
522
|
+
|
|
523
|
+
sage: p = 23
|
|
524
|
+
sage: K.<a> = GF(p^3)
|
|
525
|
+
sage: E = EllipticCurve(j=K.random_element())
|
|
526
|
+
sage: phi = E.multiplication_by_p_isogeny()
|
|
527
|
+
sage: assert phi.degree() == p**2
|
|
528
|
+
sage: P = E.random_element()
|
|
529
|
+
sage: assert phi(P) == P * p
|
|
530
|
+
"""
|
|
531
|
+
frob = self.frobenius_isogeny()
|
|
532
|
+
return frob.dual() * frob
|
|
533
|
+
|
|
534
|
+
def frobenius_polynomial(self):
|
|
535
|
+
r"""
|
|
536
|
+
Return the characteristic polynomial of Frobenius.
|
|
537
|
+
|
|
538
|
+
The Frobenius endomorphism of the elliptic curve has quadratic
|
|
539
|
+
characteristic polynomial. In most cases this is irreducible and
|
|
540
|
+
defines an imaginary quadratic order; for some supersingular
|
|
541
|
+
curves, Frobenius is an integer a and the polynomial is
|
|
542
|
+
`(x-a)^2`.
|
|
543
|
+
|
|
544
|
+
.. NOTE::
|
|
545
|
+
|
|
546
|
+
This computes the curve cardinality, which may be
|
|
547
|
+
time-consuming.
|
|
548
|
+
|
|
549
|
+
EXAMPLES::
|
|
550
|
+
|
|
551
|
+
sage: E = EllipticCurve(GF(11),[3,3])
|
|
552
|
+
sage: E.frobenius_polynomial()
|
|
553
|
+
x^2 - 4*x + 11
|
|
554
|
+
|
|
555
|
+
For some supersingular curves, Frobenius is in Z and the polynomial
|
|
556
|
+
is a square::
|
|
557
|
+
|
|
558
|
+
sage: # needs sage.rings.finite_rings
|
|
559
|
+
sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1])
|
|
560
|
+
sage: E.frobenius_polynomial().factor()
|
|
561
|
+
(x + 5)^2
|
|
562
|
+
"""
|
|
563
|
+
x = polygen(ZZ)
|
|
564
|
+
return x**2-self.trace_of_frobenius()*x+self.base_field().cardinality()
|
|
565
|
+
|
|
566
|
+
def frobenius_order(self):
|
|
567
|
+
r"""
|
|
568
|
+
Return the quadratic order Z[phi] where phi is the Frobenius
|
|
569
|
+
endomorphism of the elliptic curve.
|
|
570
|
+
|
|
571
|
+
.. NOTE::
|
|
572
|
+
|
|
573
|
+
This computes the curve cardinality, which may be
|
|
574
|
+
time-consuming.
|
|
575
|
+
|
|
576
|
+
.. SEEALSO::
|
|
577
|
+
|
|
578
|
+
:meth:`endomorphism_order`
|
|
579
|
+
|
|
580
|
+
EXAMPLES::
|
|
581
|
+
|
|
582
|
+
sage: E = EllipticCurve(GF(11),[3,3])
|
|
583
|
+
sage: E.frobenius_order()
|
|
584
|
+
Order of conductor 2 generated by pi
|
|
585
|
+
in Number Field in pi with defining polynomial x^2 - 4*x + 11
|
|
586
|
+
|
|
587
|
+
For some supersingular curves, Frobenius is in `\ZZ` and the Frobenius
|
|
588
|
+
order is `\ZZ`::
|
|
589
|
+
|
|
590
|
+
sage: # needs sage.rings.finite_rings
|
|
591
|
+
sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1])
|
|
592
|
+
sage: R = E.frobenius_order()
|
|
593
|
+
sage: R
|
|
594
|
+
Order generated by []
|
|
595
|
+
in Number Field in pi with defining polynomial x + 5
|
|
596
|
+
sage: R.degree()
|
|
597
|
+
1
|
|
598
|
+
"""
|
|
599
|
+
f = self.frobenius_polynomial().factor()[0][0]
|
|
600
|
+
return ZZ.extension(f, names='pi')
|
|
601
|
+
|
|
602
|
+
def frobenius(self):
|
|
603
|
+
r"""
|
|
604
|
+
Return the frobenius of ``self`` as an element of a quadratic order.
|
|
605
|
+
|
|
606
|
+
.. NOTE::
|
|
607
|
+
|
|
608
|
+
This computes the curve cardinality, which may be
|
|
609
|
+
time-consuming.
|
|
610
|
+
|
|
611
|
+
Frobenius is only determined up to conjugacy.
|
|
612
|
+
|
|
613
|
+
EXAMPLES::
|
|
614
|
+
|
|
615
|
+
sage: E = EllipticCurve(GF(11),[3,3])
|
|
616
|
+
sage: E.frobenius()
|
|
617
|
+
pi
|
|
618
|
+
sage: E.frobenius().minpoly()
|
|
619
|
+
x^2 - 4*x + 11
|
|
620
|
+
|
|
621
|
+
For some supersingular curves, Frobenius is in Z::
|
|
622
|
+
|
|
623
|
+
sage: # needs sage.rings.finite_rings
|
|
624
|
+
sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1])
|
|
625
|
+
sage: E.frobenius()
|
|
626
|
+
-5
|
|
627
|
+
"""
|
|
628
|
+
R = self.frobenius_order()
|
|
629
|
+
if R.degree() == 1:
|
|
630
|
+
return self.frobenius_polynomial().roots(multiplicities=False)[0]
|
|
631
|
+
else:
|
|
632
|
+
return R.gen(1)
|
|
633
|
+
|
|
634
|
+
def frobenius_endomorphism(self):
|
|
635
|
+
r"""
|
|
636
|
+
Return the `q`-power Frobenius endomorphism of this elliptic
|
|
637
|
+
curve, where `q` is the cardinality of the (finite) base field.
|
|
638
|
+
|
|
639
|
+
EXAMPLES::
|
|
640
|
+
|
|
641
|
+
sage: # needs sage.rings.finite_rings
|
|
642
|
+
sage: F.<t> = GF(11^4)
|
|
643
|
+
sage: E = EllipticCurve([t,t])
|
|
644
|
+
sage: E.frobenius_endomorphism()
|
|
645
|
+
Frobenius endomorphism of degree 14641 = 11^4:
|
|
646
|
+
From: Elliptic Curve defined by y^2 = x^3 + t*x + t over Finite Field in t of size 11^4
|
|
647
|
+
To: Elliptic Curve defined by y^2 = x^3 + t*x + t over Finite Field in t of size 11^4
|
|
648
|
+
sage: E.frobenius_endomorphism() == E.frobenius_isogeny(4)
|
|
649
|
+
True
|
|
650
|
+
|
|
651
|
+
.. SEEALSO::
|
|
652
|
+
|
|
653
|
+
:meth:`~sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic.frobenius_isogeny`
|
|
654
|
+
"""
|
|
655
|
+
return self.frobenius_isogeny(self.base_field().degree())
|
|
656
|
+
|
|
657
|
+
def frobenius_discriminant(self):
|
|
658
|
+
r"""
|
|
659
|
+
Return the discriminant of the ring `\ZZ[\pi_E]` where `\pi_E` is the Frobenius endomorphism.
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: # needs sage.rings.finite_rings
|
|
664
|
+
sage: F.<t> = GF(11^4)
|
|
665
|
+
sage: E = EllipticCurve([t,t])
|
|
666
|
+
sage: E.frobenius_discriminant()
|
|
667
|
+
-57339
|
|
668
|
+
"""
|
|
669
|
+
return self.frobenius_polynomial().discriminant()
|
|
670
|
+
|
|
671
|
+
def cardinality_pari(self):
|
|
672
|
+
r"""
|
|
673
|
+
Return the cardinality of ``self`` using PARI.
|
|
674
|
+
|
|
675
|
+
This uses :pari:`ellcard`.
|
|
676
|
+
|
|
677
|
+
EXAMPLES::
|
|
678
|
+
|
|
679
|
+
sage: p = next_prime(10^3)
|
|
680
|
+
sage: E = EllipticCurve(GF(p),[3,4])
|
|
681
|
+
sage: E.cardinality_pari()
|
|
682
|
+
1020
|
|
683
|
+
sage: K = GF(next_prime(10^6))
|
|
684
|
+
sage: E = EllipticCurve(K,[1,0,0,1,1])
|
|
685
|
+
sage: E.cardinality_pari()
|
|
686
|
+
999945
|
|
687
|
+
|
|
688
|
+
Since :issue:`16931`, this now works over finite fields which
|
|
689
|
+
are not prime fields::
|
|
690
|
+
|
|
691
|
+
sage: # needs sage.rings.finite_rings
|
|
692
|
+
sage: k.<a> = GF(7^3)
|
|
693
|
+
sage: E = EllipticCurve_from_j(a)
|
|
694
|
+
sage: E.cardinality_pari()
|
|
695
|
+
318
|
|
696
|
+
sage: K.<a> = GF(3^20)
|
|
697
|
+
sage: E = EllipticCurve(K,[1,0,0,1,a])
|
|
698
|
+
sage: E.cardinality_pari()
|
|
699
|
+
3486794310
|
|
700
|
+
|
|
701
|
+
TESTS::
|
|
702
|
+
|
|
703
|
+
sage: E.cardinality_pari().parent() # needs sage.rings.finite_rings
|
|
704
|
+
Integer Ring
|
|
705
|
+
"""
|
|
706
|
+
return Integer(self.__pari__().ellcard())
|
|
707
|
+
|
|
708
|
+
@cached_method
|
|
709
|
+
def gens(self) -> tuple:
|
|
710
|
+
r"""
|
|
711
|
+
Return points which generate the abelian group of points on
|
|
712
|
+
this elliptic curve.
|
|
713
|
+
|
|
714
|
+
The algorithm involves factoring the group order of ``self``,
|
|
715
|
+
but is otherwise (randomized) polynomial-time.
|
|
716
|
+
|
|
717
|
+
(The points returned by this function are not guaranteed to be
|
|
718
|
+
the same each time, although they should remain fixed within a
|
|
719
|
+
single run of Sage unless :meth:`abelian_group` is called.)
|
|
720
|
+
|
|
721
|
+
OUTPUT: a tuple of points on the curve
|
|
722
|
+
|
|
723
|
+
- if the group is trivial: an empty tuple.
|
|
724
|
+
|
|
725
|
+
- if the group is cyclic: a tuple with 1 point, a generator.
|
|
726
|
+
|
|
727
|
+
- if the group is not cyclic: a tuple with 2 points, where the
|
|
728
|
+
order of the first point equals the exponent of the group.
|
|
729
|
+
|
|
730
|
+
.. WARNING::
|
|
731
|
+
|
|
732
|
+
In the case of 2 generators `P` and `Q`, it is not
|
|
733
|
+
guaranteed that the group is the cartesian product of the 2
|
|
734
|
+
cyclic groups `\langle P \rangle` and `\langle Q \rangle`.
|
|
735
|
+
In other words, the order of `Q` is not as small as possible.
|
|
736
|
+
If you really need a basis (rather than just a generating set)
|
|
737
|
+
of the group, use :meth:`abelian_group`.
|
|
738
|
+
|
|
739
|
+
EXAMPLES::
|
|
740
|
+
|
|
741
|
+
sage: E = EllipticCurve(GF(11),[2,5])
|
|
742
|
+
sage: P = E.gens()[0]; P # random
|
|
743
|
+
(0 : 7 : 1)
|
|
744
|
+
sage: E.cardinality(), P.order()
|
|
745
|
+
(10, 10)
|
|
746
|
+
sage: E = EllipticCurve(GF(41),[2,5])
|
|
747
|
+
sage: E.gens() # random
|
|
748
|
+
((20 : 38 : 1), (25 : 31 : 1))
|
|
749
|
+
sage: E.cardinality()
|
|
750
|
+
44
|
|
751
|
+
|
|
752
|
+
If the abelian group has been computed, return those generators
|
|
753
|
+
instead::
|
|
754
|
+
|
|
755
|
+
sage: E.abelian_group()
|
|
756
|
+
Additive abelian group isomorphic to Z/22 + Z/2
|
|
757
|
+
embedded in Abelian group of points on Elliptic Curve
|
|
758
|
+
defined by y^2 = x^3 + 2*x + 5 over Finite Field of size 41
|
|
759
|
+
sage: ab_gens = E.abelian_group().gens()
|
|
760
|
+
sage: ab_gens == E.gens()
|
|
761
|
+
True
|
|
762
|
+
sage: E.gens()[0].order()
|
|
763
|
+
22
|
|
764
|
+
sage: E.gens()[1].order()
|
|
765
|
+
2
|
|
766
|
+
|
|
767
|
+
Examples with 1 and 0 generators::
|
|
768
|
+
|
|
769
|
+
sage: # needs sage.rings.finite_rings
|
|
770
|
+
sage: F.<a> = GF(3^6)
|
|
771
|
+
sage: E = EllipticCurve([a, a+1])
|
|
772
|
+
sage: pts = E.gens()
|
|
773
|
+
sage: len(pts)
|
|
774
|
+
1
|
|
775
|
+
sage: pts[0].order() == E.cardinality()
|
|
776
|
+
True
|
|
777
|
+
|
|
778
|
+
sage: E = EllipticCurve(GF(2), [0,0,1,1,1])
|
|
779
|
+
sage: E.gens()
|
|
780
|
+
()
|
|
781
|
+
|
|
782
|
+
This works over larger finite fields where :meth:`abelian_group`
|
|
783
|
+
may be too expensive::
|
|
784
|
+
|
|
785
|
+
sage: # needs sage.rings.finite_rings
|
|
786
|
+
sage: k.<a> = GF(5^60)
|
|
787
|
+
sage: E = EllipticCurve([a, a])
|
|
788
|
+
sage: len(E.gens())
|
|
789
|
+
2
|
|
790
|
+
sage: E.cardinality()
|
|
791
|
+
867361737988403547206134229616487867594472
|
|
792
|
+
sage: a = E.gens()[0].order(); a # random
|
|
793
|
+
433680868994201773603067114808243933797236
|
|
794
|
+
sage: b = E.gens()[1].order(); b # random
|
|
795
|
+
30977204928157269543076222486303138128374
|
|
796
|
+
sage: lcm(a,b)
|
|
797
|
+
433680868994201773603067114808243933797236
|
|
798
|
+
"""
|
|
799
|
+
card, ords, pts = self.__pari__().ellgroup(flag=1)
|
|
800
|
+
if not hasattr(self, '_order'):
|
|
801
|
+
self._order = ZZ(card)
|
|
802
|
+
pts = tuple(self.point(list(P)) for P in pts)
|
|
803
|
+
if len(pts) >= 1:
|
|
804
|
+
pts[0]._order = ZZ(ords[0]) # PARI documentation: "P is of order d_1"
|
|
805
|
+
return pts
|
|
806
|
+
|
|
807
|
+
def __iter__(self):
|
|
808
|
+
"""
|
|
809
|
+
Return an iterator through the points of this elliptic curve.
|
|
810
|
+
|
|
811
|
+
EXAMPLES::
|
|
812
|
+
|
|
813
|
+
sage: E = EllipticCurve(GF(11), [1,2])
|
|
814
|
+
sage: for P in E: print("{} {}".format(P, P.order()))
|
|
815
|
+
(0 : 1 : 0) 1
|
|
816
|
+
(1 : 2 : 1) 4
|
|
817
|
+
(1 : 9 : 1) 4
|
|
818
|
+
(2 : 1 : 1) 8
|
|
819
|
+
...
|
|
820
|
+
(10 : 0 : 1) 2
|
|
821
|
+
"""
|
|
822
|
+
yield from self.points()
|
|
823
|
+
|
|
824
|
+
def __getitem__(self, n):
|
|
825
|
+
"""
|
|
826
|
+
Return the n-th point in ``self``'s ``__points`` list.
|
|
827
|
+
|
|
828
|
+
This enables users to iterate over the curve's point set.
|
|
829
|
+
|
|
830
|
+
EXAMPLES::
|
|
831
|
+
|
|
832
|
+
sage: E = EllipticCurve(GF(97),[2,3])
|
|
833
|
+
sage: S = E.points()
|
|
834
|
+
sage: E[10]
|
|
835
|
+
(10 : 76 : 1)
|
|
836
|
+
sage: E[15]
|
|
837
|
+
(17 : 10 : 1)
|
|
838
|
+
sage: for P in E: print(P.order())
|
|
839
|
+
1
|
|
840
|
+
50
|
|
841
|
+
50
|
|
842
|
+
50
|
|
843
|
+
50
|
|
844
|
+
5
|
|
845
|
+
5
|
|
846
|
+
50
|
|
847
|
+
...
|
|
848
|
+
"""
|
|
849
|
+
return self.points()[n]
|
|
850
|
+
|
|
851
|
+
@cached_method
|
|
852
|
+
def abelian_group(self):
|
|
853
|
+
r"""
|
|
854
|
+
Return the abelian group structure of the group of points on this
|
|
855
|
+
elliptic curve.
|
|
856
|
+
|
|
857
|
+
.. SEEALSO::
|
|
858
|
+
|
|
859
|
+
If you do not need the complete abelian group structure but
|
|
860
|
+
only generators of the group, use :meth:`gens` which can
|
|
861
|
+
be much faster in some cases.
|
|
862
|
+
|
|
863
|
+
This method relies on :meth:`gens`, which uses random points on the
|
|
864
|
+
curve and hence the generators are likely to differ from one run to
|
|
865
|
+
another. However, the group is cached, so the generators will not
|
|
866
|
+
change in any one run of Sage.
|
|
867
|
+
|
|
868
|
+
OUTPUT:
|
|
869
|
+
|
|
870
|
+
- an :class:`AdditiveAbelianGroupWrapper` object encapsulating the
|
|
871
|
+
abelian group of rational points on this elliptic curve
|
|
872
|
+
|
|
873
|
+
ALGORITHM:
|
|
874
|
+
|
|
875
|
+
We first call :meth:`gens` to obtain a generating set `(P,Q)`.
|
|
876
|
+
Letting `P` denote the point of larger order `n_1`, we extend `P`
|
|
877
|
+
to a basis `(P,Q')` by computing a scalar `x` such that `Q'=Q-[x]P`
|
|
878
|
+
has order `n_2=\#E/n_1`. Finding `x` involves a (typically easy)
|
|
879
|
+
discrete-logarithm computation.
|
|
880
|
+
|
|
881
|
+
The complexity of the algorithm is the cost of factoring the group
|
|
882
|
+
order, plus `\Theta(\sqrt{\ell})` for each prime `\ell` such that
|
|
883
|
+
the rational `\ell^\infty`-torsion of ``self`` is isomorphic to
|
|
884
|
+
`\ZZ/\ell^r\times\ZZ/\ell^s` with `r>s>0`, times a polynomial in
|
|
885
|
+
the logarithm of the base-field size.
|
|
886
|
+
|
|
887
|
+
AUTHORS:
|
|
888
|
+
|
|
889
|
+
- John Cremona: original implementation
|
|
890
|
+
- Lorenz Panny (2021): current implementation
|
|
891
|
+
|
|
892
|
+
.. SEEALSO::
|
|
893
|
+
|
|
894
|
+
:meth:`AdditiveAbelianGroupWrapper.from_generators()<sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper.from_generators>`
|
|
895
|
+
|
|
896
|
+
EXAMPLES::
|
|
897
|
+
|
|
898
|
+
sage: E = EllipticCurve(GF(11),[2,5])
|
|
899
|
+
sage: E.abelian_group()
|
|
900
|
+
Additive abelian group isomorphic to Z/10 embedded in
|
|
901
|
+
Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 5
|
|
902
|
+
over Finite Field of size 11
|
|
903
|
+
|
|
904
|
+
::
|
|
905
|
+
|
|
906
|
+
sage: E = EllipticCurve(GF(41),[2,5])
|
|
907
|
+
sage: E.abelian_group()
|
|
908
|
+
Additive abelian group isomorphic to Z/22 + Z/2 ...
|
|
909
|
+
|
|
910
|
+
::
|
|
911
|
+
|
|
912
|
+
sage: # needs sage.rings.finite_rings
|
|
913
|
+
sage: F.<a> = GF(3^6,'a')
|
|
914
|
+
sage: E = EllipticCurve([a^4 + a^3 + 2*a^2 + 2*a, 2*a^5 + 2*a^3 + 2*a^2 + 1])
|
|
915
|
+
sage: E.abelian_group()
|
|
916
|
+
Additive abelian group isomorphic to Z/26 + Z/26 ...
|
|
917
|
+
|
|
918
|
+
::
|
|
919
|
+
|
|
920
|
+
sage: # needs sage.rings.finite_rings
|
|
921
|
+
sage: F.<a> = GF(101^3,'a')
|
|
922
|
+
sage: E = EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24])
|
|
923
|
+
sage: E.abelian_group()
|
|
924
|
+
Additive abelian group isomorphic to Z/1031352 ...
|
|
925
|
+
|
|
926
|
+
The group can be trivial::
|
|
927
|
+
|
|
928
|
+
sage: E = EllipticCurve(GF(2), [0,0,1,1,1])
|
|
929
|
+
sage: E.abelian_group()
|
|
930
|
+
Trivial group embedded in Abelian group of points on
|
|
931
|
+
Elliptic Curve defined by y^2 + y = x^3 + x + 1 over Finite Field of size 2
|
|
932
|
+
|
|
933
|
+
Of course, there are plenty of points if we extend the field::
|
|
934
|
+
|
|
935
|
+
sage: E.cardinality(extension_degree=100)
|
|
936
|
+
1267650600228231653296516890625
|
|
937
|
+
|
|
938
|
+
This tests the patch for :issue:`3111`, using 10 primes randomly
|
|
939
|
+
selected::
|
|
940
|
+
|
|
941
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
942
|
+
sage: E = EllipticCurve('389a')
|
|
943
|
+
sage: for p in [5927, 2297, 1571, 1709, 3851, 127, 3253, 5783, 3499, 4817]:
|
|
944
|
+
....: G = E.change_ring(GF(p)).abelian_group()
|
|
945
|
+
sage: for p in prime_range(10000): # long time (19s on sage.math, 2011)
|
|
946
|
+
....: if p != 389:
|
|
947
|
+
....: G = E.change_ring(GF(p)).abelian_group()
|
|
948
|
+
|
|
949
|
+
This tests that the bug reported in :issue:`3926` has been fixed::
|
|
950
|
+
|
|
951
|
+
sage: # needs sage.rings.number_field
|
|
952
|
+
sage: K.<i> = QuadraticField(-1)
|
|
953
|
+
sage: OK = K.ring_of_integers()
|
|
954
|
+
sage: P = K.factor(10007)[0][0]
|
|
955
|
+
sage: OKmodP = OK.residue_field(P)
|
|
956
|
+
sage: E = EllipticCurve([0, 0, 0, i, i + 3])
|
|
957
|
+
sage: Emod = E.change_ring(OKmodP); Emod
|
|
958
|
+
Elliptic Curve defined by y^2 = x^3 + ibar*x + (ibar+3)
|
|
959
|
+
over Residue field in ibar of Fractional ideal (10007)
|
|
960
|
+
sage: Emod.abelian_group() #random generators
|
|
961
|
+
(Multiplicative Abelian group isomorphic to C50067594 x C2,
|
|
962
|
+
((3152*ibar + 7679 : 7330*ibar + 7913 : 1), (8466*ibar + 1770 : 0 : 1)))
|
|
963
|
+
"""
|
|
964
|
+
|
|
965
|
+
gens = self.gens()
|
|
966
|
+
assert len(gens) <= 2
|
|
967
|
+
|
|
968
|
+
if len(gens) == 2:
|
|
969
|
+
|
|
970
|
+
P, Q = gens
|
|
971
|
+
n = self.cardinality() # cached
|
|
972
|
+
n1 = P.order() # cached
|
|
973
|
+
n2 = n//n1
|
|
974
|
+
assert not n1 * Q # PARI should guarantee this
|
|
975
|
+
|
|
976
|
+
k = n1.prime_to_m_part(n2)
|
|
977
|
+
Q *= k # don't need; kill that part
|
|
978
|
+
nQ = n2 * generic.order_from_multiple(n2*Q, n1//k//n2)
|
|
979
|
+
|
|
980
|
+
S = n//nQ * P
|
|
981
|
+
T = n2 * Q
|
|
982
|
+
S.set_order(nQ//n2, check=False) # for .log()
|
|
983
|
+
x = T.log(S)
|
|
984
|
+
Q -= x * n1//nQ * P
|
|
985
|
+
|
|
986
|
+
assert not n2 * Q # by construction
|
|
987
|
+
Q.set_order(n2, check=False)
|
|
988
|
+
|
|
989
|
+
gens = P, Q
|
|
990
|
+
|
|
991
|
+
orders = [T.order() for T in gens] # cached
|
|
992
|
+
|
|
993
|
+
self.gens.set_cache(gens)
|
|
994
|
+
return AdditiveAbelianGroupWrapper(self.point_homset(), gens, orders)
|
|
995
|
+
|
|
996
|
+
def torsion_basis(self, n):
|
|
997
|
+
r"""
|
|
998
|
+
Return a basis of the `n`-torsion subgroup of this elliptic curve,
|
|
999
|
+
assuming it is fully rational.
|
|
1000
|
+
|
|
1001
|
+
EXAMPLES::
|
|
1002
|
+
|
|
1003
|
+
sage: # needs sage.rings.finite_rings
|
|
1004
|
+
sage: E = EllipticCurve(GF(62207^2), [1,0])
|
|
1005
|
+
sage: E.abelian_group()
|
|
1006
|
+
Additive abelian group isomorphic to Z/62208 + Z/62208 embedded in
|
|
1007
|
+
Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x
|
|
1008
|
+
over Finite Field in z2 of size 62207^2
|
|
1009
|
+
sage: PA,QA = E.torsion_basis(2^8)
|
|
1010
|
+
sage: PA.weil_pairing(QA, 2^8).multiplicative_order()
|
|
1011
|
+
256
|
|
1012
|
+
sage: PB,QB = E.torsion_basis(3^5)
|
|
1013
|
+
sage: PB.weil_pairing(QB, 3^5).multiplicative_order()
|
|
1014
|
+
243
|
|
1015
|
+
|
|
1016
|
+
::
|
|
1017
|
+
|
|
1018
|
+
sage: E = EllipticCurve(GF(101), [4,4])
|
|
1019
|
+
sage: E.torsion_basis(23)
|
|
1020
|
+
Traceback (most recent call last):
|
|
1021
|
+
...
|
|
1022
|
+
ValueError: curve does not have full rational 23-torsion
|
|
1023
|
+
sage: F = E.division_field(23); F
|
|
1024
|
+
Finite Field in t of size 101^11
|
|
1025
|
+
sage: EE = E.change_ring(F)
|
|
1026
|
+
sage: P, Q = EE.torsion_basis(23)
|
|
1027
|
+
sage: P # random
|
|
1028
|
+
(89*z11^10 + 51*z11^9 + 96*z11^8 + 8*z11^7 + 67*z11^6
|
|
1029
|
+
+ 31*z11^5 + 55*z11^4 + 59*z11^3 + 28*z11^2 + 8*z11 + 88
|
|
1030
|
+
: 40*z11^10 + 33*z11^9 + 80*z11^8 + 87*z11^7 + 97*z11^6
|
|
1031
|
+
+ 69*z11^5 + 56*z11^4 + 17*z11^3 + 26*z11^2 + 69*z11 + 11
|
|
1032
|
+
: 1)
|
|
1033
|
+
sage: Q # random
|
|
1034
|
+
(25*z11^10 + 61*z11^9 + 49*z11^8 + 17*z11^7 + 80*z11^6
|
|
1035
|
+
+ 20*z11^5 + 49*z11^4 + 52*z11^3 + 61*z11^2 + 27*z11 + 61
|
|
1036
|
+
: 60*z11^10 + 91*z11^9 + 89*z11^8 + 7*z11^7 + 63*z11^6
|
|
1037
|
+
+ 55*z11^5 + 23*z11^4 + 17*z11^3 + 90*z11^2 + 91*z11 + 68
|
|
1038
|
+
: 1)
|
|
1039
|
+
|
|
1040
|
+
.. SEEALSO::
|
|
1041
|
+
|
|
1042
|
+
Use :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.division_field`
|
|
1043
|
+
to determine a field extension containing the full `\ell`-torsion subgroup.
|
|
1044
|
+
|
|
1045
|
+
ALGORITHM:
|
|
1046
|
+
|
|
1047
|
+
This method currently uses :meth:`abelian_group` and
|
|
1048
|
+
:meth:`AdditiveAbelianGroupWrapper.torsion_subgroup`.
|
|
1049
|
+
"""
|
|
1050
|
+
# TODO: In many cases this is not the fastest algorithm.
|
|
1051
|
+
# Alternatives include factoring division polynomials and
|
|
1052
|
+
# random sampling (like PARI's ellgroup, but with a milder
|
|
1053
|
+
# termination condition). We should implement these too
|
|
1054
|
+
# and figure out when to use which.
|
|
1055
|
+
T = self.abelian_group().torsion_subgroup(n)
|
|
1056
|
+
if T.invariants() != (n, n):
|
|
1057
|
+
raise ValueError(f'curve does not have full rational {n}-torsion')
|
|
1058
|
+
return tuple(P.element() for P in T.gens())
|
|
1059
|
+
|
|
1060
|
+
def is_isogenous(self, other, field=None, proof=True):
|
|
1061
|
+
"""
|
|
1062
|
+
Return whether or not ``self`` is isogenous to ``other``.
|
|
1063
|
+
|
|
1064
|
+
INPUT:
|
|
1065
|
+
|
|
1066
|
+
- ``other`` -- another elliptic curve
|
|
1067
|
+
|
|
1068
|
+
- ``field`` -- (default: ``None``) a field containing the base
|
|
1069
|
+
fields of the two elliptic curves into which the two curves
|
|
1070
|
+
may be extended to test if they are isogenous over this
|
|
1071
|
+
field. By default is_isogenous will not try to find this
|
|
1072
|
+
field unless one of the curves can be extended into the base
|
|
1073
|
+
field of the ``other``, in which case it will test over the
|
|
1074
|
+
larger base field.
|
|
1075
|
+
|
|
1076
|
+
- ``proof`` -- boolean (default: ``True``); this parameter is here only
|
|
1077
|
+
to be consistent with versions for other types of elliptic curves
|
|
1078
|
+
|
|
1079
|
+
OUTPUT:
|
|
1080
|
+
|
|
1081
|
+
boolean; ``True`` if there is an isogeny from curve ``self`` to
|
|
1082
|
+
curve ``other`` defined over ``field``
|
|
1083
|
+
|
|
1084
|
+
EXAMPLES::
|
|
1085
|
+
|
|
1086
|
+
sage: # needs sage.rings.finite_rings
|
|
1087
|
+
sage: E1 = EllipticCurve(GF(11^2,'a'),[2,7]); E1
|
|
1088
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 7 over Finite Field in a of size 11^2
|
|
1089
|
+
sage: E1.is_isogenous(5)
|
|
1090
|
+
Traceback (most recent call last):
|
|
1091
|
+
...
|
|
1092
|
+
ValueError: Second argument is not an Elliptic Curve.
|
|
1093
|
+
sage: E1.is_isogenous(E1)
|
|
1094
|
+
True
|
|
1095
|
+
|
|
1096
|
+
sage: # needs sage.rings.finite_rings
|
|
1097
|
+
sage: E2 = EllipticCurve(GF(7^3,'b'),[3,1]); E2
|
|
1098
|
+
Elliptic Curve defined by y^2 = x^3 + 3*x + 1 over Finite Field in b of size 7^3
|
|
1099
|
+
sage: E1.is_isogenous(E2)
|
|
1100
|
+
Traceback (most recent call last):
|
|
1101
|
+
...
|
|
1102
|
+
ValueError: The base fields must have the same characteristic.
|
|
1103
|
+
|
|
1104
|
+
sage: # needs sage.rings.finite_rings
|
|
1105
|
+
sage: E3 = EllipticCurve(GF(11^2,'c'),[4,3]); E3
|
|
1106
|
+
Elliptic Curve defined by y^2 = x^3 + 4*x + 3 over Finite Field in c of size 11^2
|
|
1107
|
+
sage: E1.is_isogenous(E3)
|
|
1108
|
+
False
|
|
1109
|
+
|
|
1110
|
+
sage: # needs sage.rings.finite_rings
|
|
1111
|
+
sage: E4 = EllipticCurve(GF(11^6,'d'),[6,5]); E4
|
|
1112
|
+
Elliptic Curve defined by y^2 = x^3 + 6*x + 5 over Finite Field in d of size 11^6
|
|
1113
|
+
sage: E1.is_isogenous(E4)
|
|
1114
|
+
True
|
|
1115
|
+
|
|
1116
|
+
sage: # needs sage.rings.finite_rings
|
|
1117
|
+
sage: E5 = EllipticCurve(GF(11^7,'e'),[4,2]); E5
|
|
1118
|
+
Elliptic Curve defined by y^2 = x^3 + 4*x + 2 over Finite Field in e of size 11^7
|
|
1119
|
+
sage: E1.is_isogenous(E5)
|
|
1120
|
+
Traceback (most recent call last):
|
|
1121
|
+
...
|
|
1122
|
+
ValueError: Curves have different base fields: use the field parameter.
|
|
1123
|
+
|
|
1124
|
+
When the field is given::
|
|
1125
|
+
|
|
1126
|
+
sage: # needs sage.rings.finite_rings
|
|
1127
|
+
sage: E1 = EllipticCurve(GF(13^2,'a'),[2,7]); E1
|
|
1128
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 7 over Finite Field in a of size 13^2
|
|
1129
|
+
sage: E1.is_isogenous(5,GF(13^6,'f'))
|
|
1130
|
+
Traceback (most recent call last):
|
|
1131
|
+
...
|
|
1132
|
+
ValueError: Second argument is not an Elliptic Curve.
|
|
1133
|
+
sage: E6 = EllipticCurve(GF(11^3,'g'),[9,3]); E6
|
|
1134
|
+
Elliptic Curve defined by y^2 = x^3 + 9*x + 3 over Finite Field in g of size 11^3
|
|
1135
|
+
sage: E1.is_isogenous(E6,QQ)
|
|
1136
|
+
Traceback (most recent call last):
|
|
1137
|
+
...
|
|
1138
|
+
ValueError: The base fields must have the same characteristic.
|
|
1139
|
+
sage: E7 = EllipticCurve(GF(13^5,'h'),[2,9]); E7
|
|
1140
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 9 over Finite Field in h of size 13^5
|
|
1141
|
+
sage: E1.is_isogenous(E7,GF(13^4,'i'))
|
|
1142
|
+
Traceback (most recent call last):
|
|
1143
|
+
...
|
|
1144
|
+
ValueError: Field must be an extension of the base fields of both curves
|
|
1145
|
+
sage: E1.is_isogenous(E7,GF(13^10,'j'))
|
|
1146
|
+
False
|
|
1147
|
+
sage: E1.is_isogenous(E7,GF(13^30,'j'))
|
|
1148
|
+
False
|
|
1149
|
+
"""
|
|
1150
|
+
from .ell_generic import EllipticCurve_generic
|
|
1151
|
+
if not isinstance(other, EllipticCurve_generic):
|
|
1152
|
+
raise ValueError("Second argument is not an Elliptic Curve.")
|
|
1153
|
+
if self.is_isomorphic(other):
|
|
1154
|
+
return True
|
|
1155
|
+
if self.base_field().characteristic() != other.base_field().characteristic():
|
|
1156
|
+
raise ValueError("The base fields must have the same characteristic.")
|
|
1157
|
+
if field is None:
|
|
1158
|
+
if self.base_field().degree() == other.base_field().degree():
|
|
1159
|
+
return self.cardinality() == other.cardinality()
|
|
1160
|
+
|
|
1161
|
+
elif self.base_field().degree() == gcd(self.base_field().degree(),
|
|
1162
|
+
other.base_field().degree()):
|
|
1163
|
+
return self.cardinality(extension_degree=other.base_field().degree()//self.base_field().degree()) == other.cardinality()
|
|
1164
|
+
|
|
1165
|
+
elif other.base_field().degree() == gcd(self.base_field().degree(),
|
|
1166
|
+
other.base_field().degree()):
|
|
1167
|
+
return other.cardinality(extension_degree=self.base_field().degree()//other.base_field().degree()) == self.cardinality()
|
|
1168
|
+
|
|
1169
|
+
else:
|
|
1170
|
+
raise ValueError("Curves have different base fields: use the field parameter.")
|
|
1171
|
+
else:
|
|
1172
|
+
f_deg = field.degree()
|
|
1173
|
+
s_deg = self.base_field().degree()
|
|
1174
|
+
o_deg = other.base_field().degree()
|
|
1175
|
+
if not lcm(s_deg, o_deg).divides(f_deg):
|
|
1176
|
+
raise ValueError("Field must be an extension of the base fields of both curves")
|
|
1177
|
+
else:
|
|
1178
|
+
sc = self.cardinality(extension_degree=f_deg // s_deg)
|
|
1179
|
+
oc = other.cardinality(extension_degree=f_deg // o_deg)
|
|
1180
|
+
return sc == oc
|
|
1181
|
+
|
|
1182
|
+
def is_supersingular(self, proof=True):
|
|
1183
|
+
r"""
|
|
1184
|
+
Return ``True`` if this elliptic curve is supersingular, else ``False``.
|
|
1185
|
+
|
|
1186
|
+
INPUT:
|
|
1187
|
+
|
|
1188
|
+
- ``proof``-- boolean (default: ``True``); if ``True``, returns a
|
|
1189
|
+
proved result. If ``False``, then a return value of ``False`` is
|
|
1190
|
+
certain but a return value of ``True`` may be based on a
|
|
1191
|
+
probabilistic test. See the documentation of the function
|
|
1192
|
+
:meth:`is_j_supersingular` for more details.
|
|
1193
|
+
|
|
1194
|
+
EXAMPLES::
|
|
1195
|
+
|
|
1196
|
+
sage: F = GF(101)
|
|
1197
|
+
sage: EllipticCurve(j=F(0)).is_supersingular()
|
|
1198
|
+
True
|
|
1199
|
+
sage: EllipticCurve(j=F(1728)).is_supersingular()
|
|
1200
|
+
False
|
|
1201
|
+
sage: EllipticCurve(j=F(66)).is_supersingular()
|
|
1202
|
+
True
|
|
1203
|
+
sage: EllipticCurve(j=F(99)).is_supersingular()
|
|
1204
|
+
False
|
|
1205
|
+
|
|
1206
|
+
TESTS::
|
|
1207
|
+
|
|
1208
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import supersingular_j_polynomial, is_j_supersingular
|
|
1209
|
+
sage: F = GF(103)
|
|
1210
|
+
sage: ssjlist = [F(1728)] + supersingular_j_polynomial(103).roots(multiplicities=False)
|
|
1211
|
+
sage: Set([j for j in F if is_j_supersingular(j)]) == Set(ssjlist)
|
|
1212
|
+
True
|
|
1213
|
+
"""
|
|
1214
|
+
return is_j_supersingular(self.j_invariant(), proof=proof)
|
|
1215
|
+
|
|
1216
|
+
def is_ordinary(self, proof=True):
|
|
1217
|
+
r"""
|
|
1218
|
+
Return ``True`` if this elliptic curve is ordinary, else ``False``.
|
|
1219
|
+
|
|
1220
|
+
INPUT:
|
|
1221
|
+
|
|
1222
|
+
- ``proof``-- boolean (default: ``True``); if ``True``, returns a
|
|
1223
|
+
proved result. If ``False``, then a return value of ``True`` is
|
|
1224
|
+
certain but a return value of ``False`` may be based on a
|
|
1225
|
+
probabilistic test. See the documentation of the function
|
|
1226
|
+
:meth:`is_j_supersingular` for more details.
|
|
1227
|
+
|
|
1228
|
+
EXAMPLES::
|
|
1229
|
+
|
|
1230
|
+
sage: F = GF(101)
|
|
1231
|
+
sage: EllipticCurve(j=F(0)).is_ordinary()
|
|
1232
|
+
False
|
|
1233
|
+
sage: EllipticCurve(j=F(1728)).is_ordinary()
|
|
1234
|
+
True
|
|
1235
|
+
sage: EllipticCurve(j=F(66)).is_ordinary()
|
|
1236
|
+
False
|
|
1237
|
+
sage: EllipticCurve(j=F(99)).is_ordinary()
|
|
1238
|
+
True
|
|
1239
|
+
"""
|
|
1240
|
+
return not is_j_supersingular(self.j_invariant(), proof=proof)
|
|
1241
|
+
|
|
1242
|
+
def has_order(self, value, num_checks=8) -> bool:
|
|
1243
|
+
r"""
|
|
1244
|
+
Return ``True`` if the curve has order ``value``.
|
|
1245
|
+
|
|
1246
|
+
INPUT:
|
|
1247
|
+
|
|
1248
|
+
- ``value`` -- integer in the Hasse-Weil range for this curve
|
|
1249
|
+
|
|
1250
|
+
- ``num_checks``-- integer (default: `8`); the number of times to check
|
|
1251
|
+
whether ``value`` times a random point on this curve equals the
|
|
1252
|
+
identity. If ``value`` is a prime and the curve is over a field of
|
|
1253
|
+
order at least `5`, it is sufficient to pass in ``num_checks=1`` -
|
|
1254
|
+
see the examples below.
|
|
1255
|
+
|
|
1256
|
+
.. NOTE::
|
|
1257
|
+
|
|
1258
|
+
Since the method is probabilistic, there is a possibility for the
|
|
1259
|
+
method to yield false positives (i.e. returning ``True`` even when
|
|
1260
|
+
the result is ``False``). Even worse, it is possible for this to
|
|
1261
|
+
happen even when ``num_checks`` is increased arbitrarily. See below
|
|
1262
|
+
for an example and :issue:`38617` for an open discussion.
|
|
1263
|
+
|
|
1264
|
+
EXAMPLES:
|
|
1265
|
+
|
|
1266
|
+
For curves over small finite fields, the order is computed and compared
|
|
1267
|
+
directly::
|
|
1268
|
+
|
|
1269
|
+
sage: E = EllipticCurve(GF(7), [0, 1])
|
|
1270
|
+
sage: E.order()
|
|
1271
|
+
12
|
|
1272
|
+
sage: E.has_order(12, num_checks=0)
|
|
1273
|
+
True
|
|
1274
|
+
sage: E.has_order(11, num_checks=0)
|
|
1275
|
+
False
|
|
1276
|
+
sage: E.has_order(13, num_checks=0)
|
|
1277
|
+
False
|
|
1278
|
+
|
|
1279
|
+
This tests the method on a random curve::
|
|
1280
|
+
|
|
1281
|
+
sage: # long time (10s)
|
|
1282
|
+
sage: p = random_prime(2**128, lbound=2**127)
|
|
1283
|
+
sage: K = GF((p, 2), name="a")
|
|
1284
|
+
sage: E = EllipticCurve(K, [K.random_element() for _ in range(2)])
|
|
1285
|
+
sage: N = E.order()
|
|
1286
|
+
sage: E.has_order(N, num_checks=20)
|
|
1287
|
+
True
|
|
1288
|
+
sage: E.has_order(N + 1)
|
|
1289
|
+
False
|
|
1290
|
+
|
|
1291
|
+
This demonstrates the bug mentioned in the NOTE above. The last return
|
|
1292
|
+
value should be ``False`` after :issue:`38617` is fixed::
|
|
1293
|
+
|
|
1294
|
+
sage: E = EllipticCurve(GF(5443568676570036275321323), [0, 13])
|
|
1295
|
+
sage: N = 2333145661241
|
|
1296
|
+
sage: E.order() == N^2
|
|
1297
|
+
True
|
|
1298
|
+
sage: E.has_order(N^2)
|
|
1299
|
+
True
|
|
1300
|
+
sage: del E._order
|
|
1301
|
+
sage: E.has_order(N^2 + N)
|
|
1302
|
+
True
|
|
1303
|
+
|
|
1304
|
+
Due to the nature of the algorithm (testing multiple of points) and the Hasse-Weil bound, we see that for testing prime orders, ``num_checks=1`` is sufficient::
|
|
1305
|
+
|
|
1306
|
+
sage: p = random_prime(1000)
|
|
1307
|
+
sage: E = EllipticCurve(GF(p), j=randrange(p))
|
|
1308
|
+
sage: q = random_prime(p + 20, lbound=p - 20)
|
|
1309
|
+
sage: E.has_order(q, num_checks=20) == E.has_order(q, num_checks=1)
|
|
1310
|
+
True
|
|
1311
|
+
|
|
1312
|
+
AUTHORS:
|
|
1313
|
+
|
|
1314
|
+
- Mariah Lenox (2011-02-16): Initial implementation
|
|
1315
|
+
|
|
1316
|
+
- Gareth Ma (2024-01-21): Fix bug for small curves
|
|
1317
|
+
"""
|
|
1318
|
+
q = self.base_field().order()
|
|
1319
|
+
a, b = Hasse_bounds(q, 1)
|
|
1320
|
+
if not a <= value <= b:
|
|
1321
|
+
return False
|
|
1322
|
+
|
|
1323
|
+
# For really small values, the random tests are too weak to detect wrong
|
|
1324
|
+
# orders So we go with computing directly instead.
|
|
1325
|
+
# In #38341, the bound has been increased to a large value (2^64), but
|
|
1326
|
+
# it should be decreased (to ~100) after bug #38617 is fixed.
|
|
1327
|
+
if q <= 2**64 or hasattr(self, "_order"):
|
|
1328
|
+
return self.order() == value
|
|
1329
|
+
|
|
1330
|
+
# This might be slow
|
|
1331
|
+
# if value.is_prime():
|
|
1332
|
+
# num_checks = 1
|
|
1333
|
+
|
|
1334
|
+
# Is value * random == identity?
|
|
1335
|
+
for _ in range(num_checks):
|
|
1336
|
+
while True:
|
|
1337
|
+
G = self.random_point()
|
|
1338
|
+
if not G.is_zero():
|
|
1339
|
+
break
|
|
1340
|
+
|
|
1341
|
+
if not (value * G).is_zero():
|
|
1342
|
+
return False
|
|
1343
|
+
|
|
1344
|
+
# TODO: uncomment this and remove the line in `set_order` after 38617 is fixed.
|
|
1345
|
+
# self._order = value
|
|
1346
|
+
|
|
1347
|
+
return True
|
|
1348
|
+
|
|
1349
|
+
def set_order(self, value, *, check=True, num_checks=8):
|
|
1350
|
+
r"""
|
|
1351
|
+
Set the value of ``self._order`` to ``value``.
|
|
1352
|
+
|
|
1353
|
+
Use this when you know a priori the order of the curve to
|
|
1354
|
+
avoid a potentially expensive order calculation.
|
|
1355
|
+
|
|
1356
|
+
INPUT:
|
|
1357
|
+
|
|
1358
|
+
- ``value`` -- integer in the Hasse-Weil range for this curve
|
|
1359
|
+
|
|
1360
|
+
- ``check``-- boolean (default: ``True``); whether or
|
|
1361
|
+
not to run sanity checks on the input
|
|
1362
|
+
|
|
1363
|
+
- ``num_checks``-- integer (default: `8`); if ``check`` is
|
|
1364
|
+
``True``, the number of times to check whether ``value``
|
|
1365
|
+
times a random point on this curve equals the identity
|
|
1366
|
+
|
|
1367
|
+
OUTPUT: none
|
|
1368
|
+
|
|
1369
|
+
EXAMPLES:
|
|
1370
|
+
|
|
1371
|
+
This example illustrates basic usage::
|
|
1372
|
+
|
|
1373
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1374
|
+
sage: E.set_order(12)
|
|
1375
|
+
sage: E.order()
|
|
1376
|
+
12
|
|
1377
|
+
sage: E.order() * E.random_point()
|
|
1378
|
+
(0 : 1 : 0)
|
|
1379
|
+
|
|
1380
|
+
We now give a more interesting case, the NIST-P521 curve. Its
|
|
1381
|
+
order is too big to calculate with Sage, and takes a long time
|
|
1382
|
+
using other packages, so it is very useful here::
|
|
1383
|
+
|
|
1384
|
+
sage: p = 2^521 - 1
|
|
1385
|
+
sage: prev_proof_state = proof.arithmetic()
|
|
1386
|
+
sage: proof.arithmetic(False) # turn off primality checking
|
|
1387
|
+
sage: F = GF(p)
|
|
1388
|
+
sage: A = p - 3
|
|
1389
|
+
sage: B = 1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
|
|
1390
|
+
sage: q = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449
|
|
1391
|
+
sage: E = EllipticCurve([F(A), F(B)])
|
|
1392
|
+
sage: E.set_order(q)
|
|
1393
|
+
sage: G = E.random_point()
|
|
1394
|
+
sage: G.order() * G # This takes practically no time.
|
|
1395
|
+
(0 : 1 : 0)
|
|
1396
|
+
sage: proof.arithmetic(prev_proof_state) # restore state
|
|
1397
|
+
|
|
1398
|
+
It is an error to pass a value which is not an integer in the
|
|
1399
|
+
Hasse-Weil range::
|
|
1400
|
+
|
|
1401
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1402
|
+
sage: E.set_order("hi")
|
|
1403
|
+
Traceback (most recent call last):
|
|
1404
|
+
...
|
|
1405
|
+
TypeError: unable to convert 'hi' to an integer
|
|
1406
|
+
sage: E.set_order(0)
|
|
1407
|
+
Traceback (most recent call last):
|
|
1408
|
+
...
|
|
1409
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 does not have order 0
|
|
1410
|
+
sage: E.set_order(1000)
|
|
1411
|
+
Traceback (most recent call last):
|
|
1412
|
+
...
|
|
1413
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 does not have order 1000
|
|
1414
|
+
|
|
1415
|
+
It is also very likely an error to pass a value which is not the actual
|
|
1416
|
+
order of this curve. How unlikely is determined by ``num_checks``, the
|
|
1417
|
+
factorization of the actual order, and the actual group structure::
|
|
1418
|
+
|
|
1419
|
+
sage: E = EllipticCurve(GF(1009), [0, 1]) # This curve has order 948
|
|
1420
|
+
sage: E.set_order(947)
|
|
1421
|
+
Traceback (most recent call last):
|
|
1422
|
+
...
|
|
1423
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 1009 does not have order 947
|
|
1424
|
+
|
|
1425
|
+
For curves over small finite fields, the order is cheap to compute, so
|
|
1426
|
+
it is computed directly and compared::
|
|
1427
|
+
|
|
1428
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1429
|
+
sage: E.set_order(11)
|
|
1430
|
+
Traceback (most recent call last):
|
|
1431
|
+
...
|
|
1432
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 does not have order 11
|
|
1433
|
+
|
|
1434
|
+
TESTS:
|
|
1435
|
+
|
|
1436
|
+
The previous version's random tests are not strong enough. In particular,
|
|
1437
|
+
the following used to work::
|
|
1438
|
+
|
|
1439
|
+
sage: E = EllipticCurve(GF(2), [0, 0, 1, 1, 1]) # This curve has order 1
|
|
1440
|
+
sage: E.set_order(3)
|
|
1441
|
+
Traceback (most recent call last):
|
|
1442
|
+
...
|
|
1443
|
+
ValueError: Elliptic Curve defined by y^2 + y = x^3 + x + 1 over Finite Field of size 2 does not have order 3
|
|
1444
|
+
|
|
1445
|
+
::
|
|
1446
|
+
|
|
1447
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1448
|
+
sage: E.set_order(4, num_checks=0)
|
|
1449
|
+
Traceback (most recent call last):
|
|
1450
|
+
...
|
|
1451
|
+
ValueError: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 does not have order 4
|
|
1452
|
+
sage: E.order()
|
|
1453
|
+
12
|
|
1454
|
+
|
|
1455
|
+
.. TODO:: Add provable correctness check by computing the abelian group
|
|
1456
|
+
structure and comparing.
|
|
1457
|
+
|
|
1458
|
+
AUTHORS:
|
|
1459
|
+
|
|
1460
|
+
- Mariah Lenox (2011-02-16): Initial implementation
|
|
1461
|
+
|
|
1462
|
+
- Gareth Ma (2024-01-21): Fix bug for small curves
|
|
1463
|
+
"""
|
|
1464
|
+
value = Integer(value)
|
|
1465
|
+
|
|
1466
|
+
if check and not self.has_order(value, num_checks=num_checks):
|
|
1467
|
+
raise ValueError(f"{self} does not have order {value}")
|
|
1468
|
+
|
|
1469
|
+
# TODO: It might help some of PARI's algorithms if we
|
|
1470
|
+
# could copy this over to the .pari_curve() as well.
|
|
1471
|
+
# At the time of writing, this appears to be tricky to
|
|
1472
|
+
# do in a non-hacky way because cypari2 doesn't expose
|
|
1473
|
+
# "member functions" of PARI objects.
|
|
1474
|
+
|
|
1475
|
+
self._order = value
|
|
1476
|
+
|
|
1477
|
+
def _fetch_cached_order(self, other):
|
|
1478
|
+
r"""
|
|
1479
|
+
This method copies the ``_order`` member from ``other`` to
|
|
1480
|
+
``self``. Both curves must have the same finite base field.
|
|
1481
|
+
|
|
1482
|
+
This is used in
|
|
1483
|
+
:class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`
|
|
1484
|
+
to keep track of an already computed curve order: According
|
|
1485
|
+
to Tate's theorem [Tate1966b]_, isogenous elliptic curves
|
|
1486
|
+
over a finite field have the same number of rational points.
|
|
1487
|
+
|
|
1488
|
+
EXAMPLES::
|
|
1489
|
+
|
|
1490
|
+
sage: E1 = EllipticCurve(GF(2^127-1), [1,2,3,4,5])
|
|
1491
|
+
sage: E1.set_order(170141183460469231746191640949390434666)
|
|
1492
|
+
sage: E2 = EllipticCurve(GF(2^127-1), [115649500210559831225094148253060920818, 36348294106991415644658737184600079491])
|
|
1493
|
+
sage: E2._fetch_cached_order(E1)
|
|
1494
|
+
sage: E2._order
|
|
1495
|
+
170141183460469231746191640949390434666
|
|
1496
|
+
|
|
1497
|
+
TESTS::
|
|
1498
|
+
|
|
1499
|
+
sage: E3 = EllipticCurve(GF(17), [1,2,3,4,5])
|
|
1500
|
+
sage: hasattr(E3, '_order')
|
|
1501
|
+
False
|
|
1502
|
+
sage: E3._fetch_cached_order(E1)
|
|
1503
|
+
Traceback (most recent call last):
|
|
1504
|
+
...
|
|
1505
|
+
ValueError: curves have distinct base fields
|
|
1506
|
+
"""
|
|
1507
|
+
if hasattr(self, '_order') or not hasattr(other, '_order'):
|
|
1508
|
+
return
|
|
1509
|
+
F = self.base_field()
|
|
1510
|
+
if F != other.base_field():
|
|
1511
|
+
raise ValueError('curves have distinct base fields')
|
|
1512
|
+
n = getattr(other, '_order', None)
|
|
1513
|
+
if n is not None:
|
|
1514
|
+
self._order = n
|
|
1515
|
+
|
|
1516
|
+
def height_above_floor(self, ell, e):
|
|
1517
|
+
r"""
|
|
1518
|
+
Return the height of the `j`-invariant of this elliptic curve on its `\ell`-volcano.
|
|
1519
|
+
|
|
1520
|
+
The curve must have a rational endomorphism ring of rank 2: This includes all
|
|
1521
|
+
ordinary elliptic curves over finite fields as well as those supersingular
|
|
1522
|
+
elliptic curves with Frobenius not in `\ZZ`.
|
|
1523
|
+
|
|
1524
|
+
INPUT:
|
|
1525
|
+
|
|
1526
|
+
- ``ell`` -- a prime number
|
|
1527
|
+
- ``e`` -- nonnegative integer, the `\ell`-adic valuation of
|
|
1528
|
+
the conductor the Frobenius order
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
.. NOTE::
|
|
1532
|
+
|
|
1533
|
+
For a suitable `E/\GF{q}`, and a prime `\ell`, the height
|
|
1534
|
+
`e` of the `\ell`-volcano containing `E` is the `\ell`-adic
|
|
1535
|
+
valuation of the conductor of the order generated by the
|
|
1536
|
+
`\GF{q}`-Frobenius `\pi_E`; the height of `E` on its
|
|
1537
|
+
ell-volcano is the `\ell`-adic valuation of the conductor
|
|
1538
|
+
of the order `\text{End}_{\GF{q}}(E)`.
|
|
1539
|
+
|
|
1540
|
+
ALGORITHM:
|
|
1541
|
+
|
|
1542
|
+
See [RouSuthZur2022]_.
|
|
1543
|
+
|
|
1544
|
+
EXAMPLES::
|
|
1545
|
+
|
|
1546
|
+
sage: F = GF(312401)
|
|
1547
|
+
sage: E = EllipticCurve(F,(0, 0, 0, 309381, 93465))
|
|
1548
|
+
sage: D = E.frobenius_discriminant(); D
|
|
1549
|
+
-687104
|
|
1550
|
+
sage: D.factor()
|
|
1551
|
+
-1 * 2^10 * 11 * 61
|
|
1552
|
+
sage: E.height_above_floor(2,8)
|
|
1553
|
+
5
|
|
1554
|
+
"""
|
|
1555
|
+
pi = self.frobenius()
|
|
1556
|
+
if pi in ZZ:
|
|
1557
|
+
raise ValueError("{} has a (rational) endomorphism ring of rank 4".format(self))
|
|
1558
|
+
|
|
1559
|
+
e = ZZ(e)
|
|
1560
|
+
if not e:
|
|
1561
|
+
return ZZ.zero()
|
|
1562
|
+
|
|
1563
|
+
if self.is_supersingular():
|
|
1564
|
+
if ell == self.base_field().characteristic():
|
|
1565
|
+
# In this (exceptional) case, the Frobenius can always be divided
|
|
1566
|
+
# by the maximal possible power of the characteristic. The reason
|
|
1567
|
+
# is that Frobenius must be of the form phi o [p^k] where phi is
|
|
1568
|
+
# a purely inseparable isogeny of degree 1 or p, hence this [p^k]
|
|
1569
|
+
# can always be divided out while retaining an endomorphism.
|
|
1570
|
+
assert self.base_field().cardinality().valuation(ell) >= 2*e
|
|
1571
|
+
return e
|
|
1572
|
+
|
|
1573
|
+
# In the supersingular case, the j-invariant alone does not determine
|
|
1574
|
+
# the level in the volcano. (The underlying reason is that there can
|
|
1575
|
+
# be multiple non-F_q-isomorphic curves with a given j-invariant in
|
|
1576
|
+
# the isogeny graph.)
|
|
1577
|
+
# Example: y^2 = x^3 ± x over F_p with p congruent to 3 modulo 4 have
|
|
1578
|
+
# distinct (rational) endomorphism rings.
|
|
1579
|
+
# Thus we run the "probing the depths" algorithm with F_q-isomorphism
|
|
1580
|
+
# classes of curves instead.
|
|
1581
|
+
E0 = [self] * 3
|
|
1582
|
+
E1 = [phi.codomain() for phi in self.isogenies_prime_degree(ell)]
|
|
1583
|
+
assert E1
|
|
1584
|
+
if len(E1) == 1:
|
|
1585
|
+
return ZZ.zero()
|
|
1586
|
+
assert len(E1) == ell + 1
|
|
1587
|
+
h = ZZ.one()
|
|
1588
|
+
while True:
|
|
1589
|
+
for i in range(3):
|
|
1590
|
+
isogs = E1[i].isogenies_prime_degree(ell)
|
|
1591
|
+
try:
|
|
1592
|
+
step = next(phi for phi in isogs if not phi.codomain().is_isomorphic(E0[i]))
|
|
1593
|
+
except StopIteration:
|
|
1594
|
+
return h
|
|
1595
|
+
E0[i], E1[i] = step.domain(), step.codomain()
|
|
1596
|
+
h += 1
|
|
1597
|
+
assert h <= e
|
|
1598
|
+
raise AssertionError('unreachable code -- this is a bug')
|
|
1599
|
+
|
|
1600
|
+
j = self.j_invariant()
|
|
1601
|
+
if j in [0, 1728]:
|
|
1602
|
+
return e
|
|
1603
|
+
F = j.parent()
|
|
1604
|
+
x = polygen(F)
|
|
1605
|
+
from sage.rings.polynomial.polynomial_ring import polygens
|
|
1606
|
+
from sage.schemes.elliptic_curves.mod_poly import classical_modular_polynomial
|
|
1607
|
+
X, Y = polygens(F, 'X,Y')
|
|
1608
|
+
phi = classical_modular_polynomial(ell)(X, Y)
|
|
1609
|
+
j1 = phi([x,j]).roots(multiplicities=False)
|
|
1610
|
+
nj1 = len(j1)
|
|
1611
|
+
on_floor = self.two_torsion_rank() < 2 if ell == 2 else nj1 <= ell
|
|
1612
|
+
if on_floor:
|
|
1613
|
+
return ZZ.zero()
|
|
1614
|
+
if e == 1 or nj1 != ell+1: # double roots can only happen at the surface
|
|
1615
|
+
return e
|
|
1616
|
+
if nj1 < 3:
|
|
1617
|
+
return ZZ.zero()
|
|
1618
|
+
j0 = [j,j,j]
|
|
1619
|
+
h = ZZ.one()
|
|
1620
|
+
while True:
|
|
1621
|
+
for i in range(3):
|
|
1622
|
+
r = (phi([x,j1[i]])//(x-j0[i])).roots(multiplicities=False)
|
|
1623
|
+
if not r:
|
|
1624
|
+
return h
|
|
1625
|
+
j0[i] = j1[i]
|
|
1626
|
+
j1[i] = r[0]
|
|
1627
|
+
h += 1
|
|
1628
|
+
|
|
1629
|
+
def endomorphism_discriminant_from_class_number(self, h):
|
|
1630
|
+
r"""
|
|
1631
|
+
Return the endomorphism order discriminant of this ordinary elliptic curve, given its class number ``h``.
|
|
1632
|
+
|
|
1633
|
+
INPUT:
|
|
1634
|
+
|
|
1635
|
+
- ``h`` -- positive integer
|
|
1636
|
+
|
|
1637
|
+
OUTPUT:
|
|
1638
|
+
|
|
1639
|
+
integer; the discriminant of the endomorphism ring `\text{End}(E)`, if
|
|
1640
|
+
this has class number ``h``. If `\text{End}(E)` does not have class
|
|
1641
|
+
number ``h``, a :exc:`ValueError` is raised.
|
|
1642
|
+
|
|
1643
|
+
ALGORITHM:
|
|
1644
|
+
|
|
1645
|
+
Compute the trace of Frobenius and hence the discriminant
|
|
1646
|
+
`D_0` and class number `h_0` of the maximal order containing
|
|
1647
|
+
the endomorphism order. From the given value of `h`, which
|
|
1648
|
+
must be a multiple of `h_0`, compute the possible conductors,
|
|
1649
|
+
using :meth:`height_above_floor` for each prime `\ell`
|
|
1650
|
+
dividing the quotient `h/h_0`. If exactly one conductor `f`
|
|
1651
|
+
remains, return `f^2D_0`, otherwise raise a :exc:`ValueError`;
|
|
1652
|
+
this can onlyhappen when the input value of `h` was incorrect.
|
|
1653
|
+
|
|
1654
|
+
.. NOTE::
|
|
1655
|
+
|
|
1656
|
+
Adapted from [RouSuthZur2022]_. The application for which
|
|
1657
|
+
one knows the class number in advance is in the
|
|
1658
|
+
recognition of Hilbert Class Polynomials: see
|
|
1659
|
+
:func:`sage.schemes.elliptic_curves.cm.is_HCP`.
|
|
1660
|
+
|
|
1661
|
+
EXAMPLES::
|
|
1662
|
+
|
|
1663
|
+
sage: F = GF(312401)
|
|
1664
|
+
sage: E = EllipticCurve(F,(0, 0, 0, 309381, 93465))
|
|
1665
|
+
sage: E.endomorphism_discriminant_from_class_number(30)
|
|
1666
|
+
-671
|
|
1667
|
+
|
|
1668
|
+
We check that this is the correct discriminant, and the input value of `h` was correct::
|
|
1669
|
+
|
|
1670
|
+
sage: H = hilbert_class_polynomial(-671)
|
|
1671
|
+
sage: H(E.j_invariant()) == 0 and H.degree()==30
|
|
1672
|
+
True
|
|
1673
|
+
"""
|
|
1674
|
+
F = self.base_field()
|
|
1675
|
+
if not F.is_finite():
|
|
1676
|
+
raise ValueError("Base field {} must be finite".format(F))
|
|
1677
|
+
if self.is_supersingular():
|
|
1678
|
+
raise ValueError("Elliptic curve ({}) must be ordinary".format(self))
|
|
1679
|
+
D1 = self.frobenius_discriminant()
|
|
1680
|
+
D0 = D1.squarefree_part()
|
|
1681
|
+
if D0 % 4 != 1:
|
|
1682
|
+
D0 *= 4
|
|
1683
|
+
v = ZZ(D1//D0).isqrt()
|
|
1684
|
+
h0 = D0.class_number()
|
|
1685
|
+
if h % h0:
|
|
1686
|
+
raise ValueError("Incorrect class number {}".format(h))
|
|
1687
|
+
from sage.schemes.elliptic_curves.cm import OrderClassNumber
|
|
1688
|
+
cs = [v//f for f in v.divisors() if OrderClassNumber(D0,h0,f) == h] # cofactors c=v/f compatible with h(f**2D0)=h
|
|
1689
|
+
if not cs:
|
|
1690
|
+
raise ValueError("Incorrect class number {}".format(h))
|
|
1691
|
+
if len(cs) == 1:
|
|
1692
|
+
return (v//cs[0])**2 * D0
|
|
1693
|
+
|
|
1694
|
+
L = sorted(set(sum([c.prime_factors() for c in cs], [])))
|
|
1695
|
+
for ell in L:
|
|
1696
|
+
e = self.height_above_floor(ell,v.valuation(ell))
|
|
1697
|
+
cs = [c for c in cs if c.valuation(ell) == e]
|
|
1698
|
+
if not cs:
|
|
1699
|
+
raise ValueError("Incorrect class number {}".format(h))
|
|
1700
|
+
if len(cs) == 1:
|
|
1701
|
+
return (v//cs[0])**2 * D0
|
|
1702
|
+
raise ValueError("Incorrect class number {}".format(h))
|
|
1703
|
+
|
|
1704
|
+
def endomorphism_order(self):
|
|
1705
|
+
r"""
|
|
1706
|
+
Return a quadratic order isomorphic to the endomorphism ring
|
|
1707
|
+
of this elliptic curve, assuming the order has rank two.
|
|
1708
|
+
|
|
1709
|
+
.. NOTE::
|
|
1710
|
+
|
|
1711
|
+
In the future, this method will hopefully be extended to return a
|
|
1712
|
+
:class:`~sage.algebras.quatalg.quaternion_algebra.QuaternionOrder`
|
|
1713
|
+
object in the rank-4 case, but this has not been implemented yet.
|
|
1714
|
+
|
|
1715
|
+
.. SEEALSO::
|
|
1716
|
+
|
|
1717
|
+
:meth:`frobenius_order`
|
|
1718
|
+
|
|
1719
|
+
EXAMPLES::
|
|
1720
|
+
|
|
1721
|
+
sage: E = EllipticCurve(GF(11), [3,3])
|
|
1722
|
+
sage: E.endomorphism_order()
|
|
1723
|
+
Maximal Order generated by 1/2*pi + 1/2 in Number Field in pi with defining polynomial x^2 - 4*x + 11
|
|
1724
|
+
|
|
1725
|
+
It also works for supersingular elliptic curves provided that Frobenius
|
|
1726
|
+
is not in `\ZZ`::
|
|
1727
|
+
|
|
1728
|
+
sage: E = EllipticCurve(GF(11), [1,0])
|
|
1729
|
+
sage: E.is_supersingular()
|
|
1730
|
+
True
|
|
1731
|
+
sage: E.endomorphism_order()
|
|
1732
|
+
Order of conductor 2 generated by pi in Number Field in pi with defining polynomial x^2 + 11
|
|
1733
|
+
|
|
1734
|
+
::
|
|
1735
|
+
|
|
1736
|
+
sage: E = EllipticCurve(GF(11), [-1,0])
|
|
1737
|
+
sage: E.is_supersingular()
|
|
1738
|
+
True
|
|
1739
|
+
sage: E.endomorphism_order()
|
|
1740
|
+
Maximal Order generated by 1/2*pi + 1/2 in Number Field in pi with defining polynomial x^2 + 11
|
|
1741
|
+
|
|
1742
|
+
There are some exceptional cases where Frobenius itself is divisible
|
|
1743
|
+
by the characteristic::
|
|
1744
|
+
|
|
1745
|
+
sage: EllipticCurve([GF(7^2).gen(), 0]).endomorphism_order()
|
|
1746
|
+
Gaussian Integers generated by 1/7*pi in Number Field in pi with defining polynomial x^2 + 49
|
|
1747
|
+
sage: EllipticCurve(GF(3^5), [1, 0]).endomorphism_order()
|
|
1748
|
+
Order of conductor 2 generated by 1/9*pi in Number Field in pi with defining polynomial x^2 + 243
|
|
1749
|
+
sage: EllipticCurve(GF(7^3), [-1, 0]).endomorphism_order()
|
|
1750
|
+
Maximal Order generated by 1/14*pi + 1/2 in Number Field in pi with defining polynomial x^2 + 343
|
|
1751
|
+
"""
|
|
1752
|
+
pi = self.frobenius()
|
|
1753
|
+
if pi in ZZ:
|
|
1754
|
+
raise NotImplementedError('the rank-4 case is not supported yet')
|
|
1755
|
+
|
|
1756
|
+
O = self.frobenius_order()
|
|
1757
|
+
f0 = O.conductor()
|
|
1758
|
+
|
|
1759
|
+
f = 1
|
|
1760
|
+
for l,e in f0.factor():
|
|
1761
|
+
h = self.height_above_floor(l, e)
|
|
1762
|
+
f *= l**(e-h)
|
|
1763
|
+
|
|
1764
|
+
K = O.number_field()
|
|
1765
|
+
return K.order_of_conductor(f)
|
|
1766
|
+
|
|
1767
|
+
def twists(self):
|
|
1768
|
+
r"""
|
|
1769
|
+
Return a list of `k`-isomorphism representatives of all
|
|
1770
|
+
twists of this elliptic curve, where `k` is the base field.
|
|
1771
|
+
|
|
1772
|
+
The input curve appears as the first entry of the result.
|
|
1773
|
+
|
|
1774
|
+
.. NOTE::
|
|
1775
|
+
|
|
1776
|
+
A *twist* of `E/k` is an elliptic curve `E'` defined over
|
|
1777
|
+
`k` that is isomorphic to `E` over the algebraic closure
|
|
1778
|
+
`\bar k`.
|
|
1779
|
+
|
|
1780
|
+
Most elliptic curves over a finite field only admit a
|
|
1781
|
+
single nontrivial twist (the quadratic twist); the only
|
|
1782
|
+
exceptions are curves with `j`-invariant `0` or `1728`.
|
|
1783
|
+
|
|
1784
|
+
In all cases the sum over all the twists `E'` of `1/|Aut(E')|` is 1.
|
|
1785
|
+
|
|
1786
|
+
.. SEEALSO::
|
|
1787
|
+
|
|
1788
|
+
- :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.quadratic_twist`
|
|
1789
|
+
- :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.quartic_twist`
|
|
1790
|
+
- :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.sextic_twist`
|
|
1791
|
+
|
|
1792
|
+
EXAMPLES::
|
|
1793
|
+
|
|
1794
|
+
sage: E = EllipticCurve(GF(97), [1,1])
|
|
1795
|
+
sage: E.j_invariant()
|
|
1796
|
+
54
|
|
1797
|
+
sage: E.twists()
|
|
1798
|
+
[Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 97,
|
|
1799
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97]
|
|
1800
|
+
|
|
1801
|
+
::
|
|
1802
|
+
|
|
1803
|
+
sage: E = EllipticCurve(GF(97), [1,0])
|
|
1804
|
+
sage: E.j_invariant()
|
|
1805
|
+
79
|
|
1806
|
+
sage: E.twists()
|
|
1807
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 97,
|
|
1808
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1809
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1810
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97]
|
|
1811
|
+
|
|
1812
|
+
::
|
|
1813
|
+
|
|
1814
|
+
sage: E = EllipticCurve(GF(97), [0,1])
|
|
1815
|
+
sage: E.j_invariant()
|
|
1816
|
+
0
|
|
1817
|
+
sage: E.twists()
|
|
1818
|
+
[Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 97,
|
|
1819
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1820
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1821
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1822
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97,
|
|
1823
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 97]
|
|
1824
|
+
|
|
1825
|
+
This can be useful to quickly compute a list of all elliptic curves
|
|
1826
|
+
over a finite field `k` up to `k`-isomorphism::
|
|
1827
|
+
|
|
1828
|
+
sage: Es = [E for j in GF(13) for E in EllipticCurve(j=j).twists()]
|
|
1829
|
+
sage: len(Es)
|
|
1830
|
+
32
|
|
1831
|
+
sage: Es
|
|
1832
|
+
[Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 13,
|
|
1833
|
+
...
|
|
1834
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 13]
|
|
1835
|
+
|
|
1836
|
+
In characteristic 3, the number of twists is 2 except for
|
|
1837
|
+
`j=0=1728`, when there are either 4 or 6 depending on whether the
|
|
1838
|
+
field has odd or even degree over `\GF{3}`::
|
|
1839
|
+
|
|
1840
|
+
sage: # needs sage.rings.finite_rings
|
|
1841
|
+
sage: K = GF(3**5)
|
|
1842
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()]
|
|
1843
|
+
[(0, 1, 0, 0, 2), (0, z5, 0, 0, 2*z5^3)]
|
|
1844
|
+
|
|
1845
|
+
sage: # needs sage.rings.finite_rings
|
|
1846
|
+
sage: K = GF(3**5)
|
|
1847
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random
|
|
1848
|
+
[(0, 0, 0, 1, 0),
|
|
1849
|
+
(0, 0, 0, 2, 0),
|
|
1850
|
+
(0, 0, 0, 2, z5^4 + z5^3 + z5^2),
|
|
1851
|
+
(0, 0, 0, 2, 2*z5^4 + 2*z5^3 + 2*z5^2)]
|
|
1852
|
+
|
|
1853
|
+
sage: # needs sage.rings.finite_rings
|
|
1854
|
+
sage: K = GF(3**4)
|
|
1855
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()]
|
|
1856
|
+
[(0, 1, 0, 0, 2), (0, z4, 0, 0, 2*z4^3)]
|
|
1857
|
+
|
|
1858
|
+
sage: # needs sage.rings.finite_rings
|
|
1859
|
+
sage: K = GF(3**4)
|
|
1860
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random
|
|
1861
|
+
[(0, 0, 0, 1, 0),
|
|
1862
|
+
(0, 0, 0, 2, 2*z4^3 + 2*z4^2 + 2*z4 + 2),
|
|
1863
|
+
(0, 0, 0, 1, 0),
|
|
1864
|
+
(0, 0, 0, 1, 2*z4^3 + 2*z4^2 + 2*z4 + 2),
|
|
1865
|
+
(0, 0, 0, z4, 0),
|
|
1866
|
+
(0, 0, 0, z4^3, 0)]
|
|
1867
|
+
|
|
1868
|
+
In characteristic 2, the number of twists is 2 except for
|
|
1869
|
+
`j=0=1728`, when there are either 3 or 7 depending on whether the
|
|
1870
|
+
field has odd or even degree over `\GF{2}`::
|
|
1871
|
+
|
|
1872
|
+
sage: # needs sage.rings.finite_rings
|
|
1873
|
+
sage: K = GF(2**7)
|
|
1874
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()]
|
|
1875
|
+
[(1, 0, 0, 0, 1), (1, 1, 0, 0, 1)]
|
|
1876
|
+
|
|
1877
|
+
sage: # needs sage.rings.finite_rings
|
|
1878
|
+
sage: K = GF(2**7)
|
|
1879
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()]
|
|
1880
|
+
[(0, 0, 1, 0, 0), (0, 0, 1, 1, 0), (0, 0, 1, 1, 1)]
|
|
1881
|
+
|
|
1882
|
+
sage: # needs sage.rings.finite_rings
|
|
1883
|
+
sage: K = GF(2**8)
|
|
1884
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(1)).twists()] # random
|
|
1885
|
+
[(1, 0, 0, 0, 1), (1, z8^7 + z8^6 + z8^5 + z8^4 + z8^2 + z8, 0, 0, 1)]
|
|
1886
|
+
|
|
1887
|
+
sage: # needs sage.rings.finite_rings
|
|
1888
|
+
sage: K = GF(2**8)
|
|
1889
|
+
sage: [E.ainvs() for E in EllipticCurve(j=K(0)).twists()] # random
|
|
1890
|
+
[(0, 0, 1, 0, 0),
|
|
1891
|
+
(0, 0, 1, 0, z8^5 + z8^4 + z8^3),
|
|
1892
|
+
(0, 0, 1, z8^6 + z8^5 + z8^2 + 1, 0),
|
|
1893
|
+
(0, 0, z8^4 + z8^3 + z8^2 + 1, 0, 0),
|
|
1894
|
+
(0, 0, z8^4 + z8^3 + z8^2 + 1, 0, z8^3 + z8^2 + 1),
|
|
1895
|
+
(0, 0, z8^6 + z8^3 + z8^2, 0, 0),
|
|
1896
|
+
(0, 0, z8^6 + z8^3 + z8^2, 0, z8^3 + z8^2)]
|
|
1897
|
+
|
|
1898
|
+
TESTS:
|
|
1899
|
+
|
|
1900
|
+
Randomized check that we find all twists and there are no duplicates::
|
|
1901
|
+
|
|
1902
|
+
sage: # needs sage.rings.finite_rings
|
|
1903
|
+
sage: p = next_prime(randrange(2,100))
|
|
1904
|
+
sage: e = randrange(1,10)
|
|
1905
|
+
sage: F.<t> = GF((p,e))
|
|
1906
|
+
sage: E = EllipticCurve(j=F.random_element())
|
|
1907
|
+
sage: twists1 = E.twists()
|
|
1908
|
+
sage: {sum(E1.is_isomorphic(E2) for E2 in twists1) == 1 for E1 in twists1}
|
|
1909
|
+
{True}
|
|
1910
|
+
sage: j = E.j_invariant()
|
|
1911
|
+
sage: A,B = polygens(F, 'A,B')
|
|
1912
|
+
sage: eq = 1728*4*A**3 - j * (4*A**3 + 27*B**2)
|
|
1913
|
+
sage: twists2 = []
|
|
1914
|
+
sage: for _ in range(10):
|
|
1915
|
+
....: I = Ideal([eq, A + B - F.random_element()])
|
|
1916
|
+
....: try:
|
|
1917
|
+
....: V = I.variety()
|
|
1918
|
+
....: except ValueError:
|
|
1919
|
+
....: if I.dimension() == 0:
|
|
1920
|
+
....: raise
|
|
1921
|
+
....: if not V:
|
|
1922
|
+
....: continue
|
|
1923
|
+
....: sol = choice(V)
|
|
1924
|
+
....: a, b = sol[A], sol[B]
|
|
1925
|
+
....: try:
|
|
1926
|
+
....: twists2.append(EllipticCurve([a, b]))
|
|
1927
|
+
....: except ArithmeticError:
|
|
1928
|
+
....: pass
|
|
1929
|
+
sage: all(any(E2.is_isomorphic(E1) for E1 in twists1) for E2 in twists2)
|
|
1930
|
+
True
|
|
1931
|
+
"""
|
|
1932
|
+
K = self.base_field()
|
|
1933
|
+
j = self.j_invariant()
|
|
1934
|
+
twists = None
|
|
1935
|
+
if not j:
|
|
1936
|
+
twists = curves_with_j_0(K)
|
|
1937
|
+
elif j == 1728:
|
|
1938
|
+
twists = curves_with_j_1728(K)
|
|
1939
|
+
|
|
1940
|
+
if twists: # i.e. if j=0 or 1728
|
|
1941
|
+
# replace the one isomorphic to self with self and move to front
|
|
1942
|
+
for i, t in enumerate(twists):
|
|
1943
|
+
if self.is_isomorphic(t):
|
|
1944
|
+
twists[i] = twists[0]
|
|
1945
|
+
twists[0] = self
|
|
1946
|
+
break
|
|
1947
|
+
return twists
|
|
1948
|
+
|
|
1949
|
+
# Now j is not 0 or 1728, and we only have a quadratic twist
|
|
1950
|
+
|
|
1951
|
+
if K.characteristic() == 2:
|
|
1952
|
+
# find D with trace 1 for the additive twist
|
|
1953
|
+
D = K.one()
|
|
1954
|
+
while not D or D.trace() == 0:
|
|
1955
|
+
D = K.random_element()
|
|
1956
|
+
else:
|
|
1957
|
+
# find a nonsquare D.
|
|
1958
|
+
D = K.gen()
|
|
1959
|
+
q2 = (K.cardinality() - 1) // 2
|
|
1960
|
+
while not D or D**q2 == 1:
|
|
1961
|
+
D = K.random_element()
|
|
1962
|
+
# assert D and D**q2 != 1
|
|
1963
|
+
# assert not D.is_square()
|
|
1964
|
+
|
|
1965
|
+
return [self, self.quadratic_twist(D)]
|
|
1966
|
+
|
|
1967
|
+
|
|
1968
|
+
def curves_with_j_0(K):
|
|
1969
|
+
r"""
|
|
1970
|
+
Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K`.
|
|
1971
|
+
|
|
1972
|
+
.. NOTE::
|
|
1973
|
+
|
|
1974
|
+
In characteristics 2 and 3 this function simply calls ``curves_with_j_0_char2`` or
|
|
1975
|
+
``curves_with_j_0_char3``. Otherwise there are either 2 or 6 curves, parametrised by
|
|
1976
|
+
`K^*/(K^*)^6`.
|
|
1977
|
+
|
|
1978
|
+
Examples:
|
|
1979
|
+
|
|
1980
|
+
For `K=\GF{q}` where `q\equiv1\mod{6}` there are six curves, the sextic twists of `y^2=x^3+1`::
|
|
1981
|
+
|
|
1982
|
+
sage: # needs sage.rings.finite_rings
|
|
1983
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0
|
|
1984
|
+
sage: sorted(curves_with_j_0(GF(7)), key = lambda E: E.a_invariants())
|
|
1985
|
+
[Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7,
|
|
1986
|
+
Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 7,
|
|
1987
|
+
Elliptic Curve defined by y^2 = x^3 + 3 over Finite Field of size 7,
|
|
1988
|
+
Elliptic Curve defined by y^2 = x^3 + 4 over Finite Field of size 7,
|
|
1989
|
+
Elliptic Curve defined by y^2 = x^3 + 5 over Finite Field of size 7,
|
|
1990
|
+
Elliptic Curve defined by y^2 = x^3 + 6 over Finite Field of size 7]
|
|
1991
|
+
sage: curves = curves_with_j_0(GF(25)); len(curves)
|
|
1992
|
+
6
|
|
1993
|
+
sage: all(not curves[i].is_isomorphic(curves[j]) for i in range(6) for j in range(i + 1, 6))
|
|
1994
|
+
True
|
|
1995
|
+
sage: set(E.j_invariant() for E in curves)
|
|
1996
|
+
{0}
|
|
1997
|
+
|
|
1998
|
+
For `K=\GF{q}` where `q\equiv5\mod{6}` there are two curves,
|
|
1999
|
+
quadratic twists of each other by `-3`: `y^2=x^3+1` and
|
|
2000
|
+
`y^2=x^3-27`::
|
|
2001
|
+
|
|
2002
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0
|
|
2003
|
+
sage: curves_with_j_0(GF(5))
|
|
2004
|
+
[Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 5,
|
|
2005
|
+
Elliptic Curve defined by y^2 = x^3 + 3 over Finite Field of size 5]
|
|
2006
|
+
sage: curves_with_j_0(GF(11))
|
|
2007
|
+
[Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 11,
|
|
2008
|
+
Elliptic Curve defined by y^2 = x^3 + 6 over Finite Field of size 11]
|
|
2009
|
+
"""
|
|
2010
|
+
if not K.is_finite():
|
|
2011
|
+
raise ValueError("field must be finite")
|
|
2012
|
+
p = K.characteristic()
|
|
2013
|
+
if p == 2:
|
|
2014
|
+
return curves_with_j_0_char2(K)
|
|
2015
|
+
if p == 3:
|
|
2016
|
+
return curves_with_j_0_char3(K)
|
|
2017
|
+
q = K.cardinality()
|
|
2018
|
+
if q % 3 == 2:
|
|
2019
|
+
# Then we only have two quadratic twists (and -3 is non-square)
|
|
2020
|
+
return [EllipticCurve(K, [0, a]) for a in [1, -27]]
|
|
2021
|
+
# Now we have genuine sextic twists, find D generating K* mod 6th powers
|
|
2022
|
+
q2 = (q - 1) // 2
|
|
2023
|
+
q3 = (q - 1) // 3
|
|
2024
|
+
D = K.gen()
|
|
2025
|
+
while not D or D**q2 == 1 or D**q3 == 1:
|
|
2026
|
+
D = K.random_element()
|
|
2027
|
+
|
|
2028
|
+
curves = [EllipticCurve(K, [0, D**i]) for i in range(6)]
|
|
2029
|
+
# TODO: issue 37110, Precompute orders of sextic twists + docs
|
|
2030
|
+
# The idea should be to evaluate the character (D / q) or something
|
|
2031
|
+
# Probably reference [RS2010]_ and [Connell1999]_
|
|
2032
|
+
# Also a necessary change is `curves_with_j_0` should take in an optional "starting curve"
|
|
2033
|
+
# (passed from the original .twists call), because if you start twisting from that curve,
|
|
2034
|
+
# then you can also compute the orders!
|
|
2035
|
+
return curves
|
|
2036
|
+
|
|
2037
|
+
|
|
2038
|
+
def curves_with_j_1728(K):
|
|
2039
|
+
r"""
|
|
2040
|
+
Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 1728 over the finite field `K`.
|
|
2041
|
+
|
|
2042
|
+
.. NOTE::
|
|
2043
|
+
|
|
2044
|
+
In characteristics 2 and 3 (so 0=1728) this function simply calls ``curves_with_j_0_char2`` or
|
|
2045
|
+
``curves_with_j_0_char3``. Otherwise there are either 2 or 4 curves, parametrised by
|
|
2046
|
+
`K^*/(K^*)^4`.
|
|
2047
|
+
|
|
2048
|
+
EXAMPLES:
|
|
2049
|
+
|
|
2050
|
+
For `K=\GF{q}` where `q\equiv1\mod{4}`, there are four curves, the quartic twists of `y^2=x^3+x`::
|
|
2051
|
+
|
|
2052
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_1728
|
|
2053
|
+
sage: sorted(curves_with_j_1728(GF(5)), key = lambda E: E.a_invariants())
|
|
2054
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 5,
|
|
2055
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 5,
|
|
2056
|
+
Elliptic Curve defined by y^2 = x^3 + 3*x over Finite Field of size 5,
|
|
2057
|
+
Elliptic Curve defined by y^2 = x^3 + 4*x over Finite Field of size 5]
|
|
2058
|
+
sage: curves_with_j_1728(GF(49)) # random # needs sage.rings.finite_rings
|
|
2059
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 7^2,
|
|
2060
|
+
Elliptic Curve defined by y^2 = x^3 + z2*x over Finite Field in z2 of size 7^2,
|
|
2061
|
+
Elliptic Curve defined by y^2 = x^3 + (z2+4)*x over Finite Field in z2 of size 7^2,
|
|
2062
|
+
Elliptic Curve defined by y^2 = x^3 + (5*z2+4)*x over Finite Field in z2 of size 7^2]
|
|
2063
|
+
|
|
2064
|
+
For `K=\GF{q}` where `q\equiv3\mod{4}`, there are two curves,
|
|
2065
|
+
quadratic twists of each other by `-1`: `y^2=x^3+x` and
|
|
2066
|
+
`y^2=x^3-x`::
|
|
2067
|
+
|
|
2068
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_1728
|
|
2069
|
+
sage: curves_with_j_1728(GF(7))
|
|
2070
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7,
|
|
2071
|
+
Elliptic Curve defined by y^2 = x^3 + 6*x over Finite Field of size 7]
|
|
2072
|
+
sage: curves_with_j_1728(GF(11))
|
|
2073
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 11,
|
|
2074
|
+
Elliptic Curve defined by y^2 = x^3 + 10*x over Finite Field of size 11]
|
|
2075
|
+
"""
|
|
2076
|
+
if not K.is_finite():
|
|
2077
|
+
raise ValueError("field must be finite")
|
|
2078
|
+
p = K.characteristic()
|
|
2079
|
+
if p == 2:
|
|
2080
|
+
return curves_with_j_0_char2(K)
|
|
2081
|
+
if p == 3:
|
|
2082
|
+
return curves_with_j_0_char3(K)
|
|
2083
|
+
q = K.cardinality()
|
|
2084
|
+
if q % 4 == 3:
|
|
2085
|
+
return [EllipticCurve(K, [a,0]) for a in [1,-1]]
|
|
2086
|
+
# Now we have genuine quartic twists, find D generating K* mod 4th powers
|
|
2087
|
+
q2 = (q - 1) // 2
|
|
2088
|
+
D = K.gen()
|
|
2089
|
+
while not D or D**q2 == 1:
|
|
2090
|
+
D = K.random_element()
|
|
2091
|
+
curves = [EllipticCurve(K, [D**i, 0]) for i in range(4)]
|
|
2092
|
+
return curves
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
def curves_with_j_0_char2(K):
|
|
2096
|
+
r"""
|
|
2097
|
+
Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 2.
|
|
2098
|
+
|
|
2099
|
+
.. NOTE::
|
|
2100
|
+
|
|
2101
|
+
The number of twists is either 3 or 7 depending on whether
|
|
2102
|
+
the field has odd or even degree over `\GF{2}`. See
|
|
2103
|
+
[Connell1999]_, pages 429-431.
|
|
2104
|
+
|
|
2105
|
+
Examples:
|
|
2106
|
+
|
|
2107
|
+
In odd degree, there are three isomorphism classes all with representatives defined over `\GF{2}`::
|
|
2108
|
+
|
|
2109
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char2
|
|
2110
|
+
sage: # needs sage.rings.finite_rings
|
|
2111
|
+
sage: K = GF(2**7)
|
|
2112
|
+
sage: curves = curves_with_j_0_char2(K)
|
|
2113
|
+
sage: len(curves)
|
|
2114
|
+
3
|
|
2115
|
+
sage: [E.ainvs() for E in curves]
|
|
2116
|
+
[(0, 0, 1, 0, 0), (0, 0, 1, 1, 0), (0, 0, 1, 1, 1)]
|
|
2117
|
+
|
|
2118
|
+
Check that the curves are mutually non-isomorphic::
|
|
2119
|
+
|
|
2120
|
+
sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings
|
|
2121
|
+
....: for e1 in curves for e2 in curves)
|
|
2122
|
+
True
|
|
2123
|
+
|
|
2124
|
+
Check that the weight formula holds::
|
|
2125
|
+
|
|
2126
|
+
sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings
|
|
2127
|
+
True
|
|
2128
|
+
|
|
2129
|
+
In even degree there are seven isomorphism classes::
|
|
2130
|
+
|
|
2131
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char2
|
|
2132
|
+
sage: # needs sage.rings.finite_rings
|
|
2133
|
+
sage: K = GF(2**8)
|
|
2134
|
+
sage: curves = EllipticCurve(j=K(0)).twists()
|
|
2135
|
+
sage: len(curves)
|
|
2136
|
+
7
|
|
2137
|
+
sage: [E.ainvs() for E in curves] # random
|
|
2138
|
+
[(0, 0, 1, 0, 0),
|
|
2139
|
+
(0, 0, 1, 0, z8^5 + z8^4 + z8^3),
|
|
2140
|
+
(0, 0, 1, z8^6 + z8^5 + z8^2 + 1, 0),
|
|
2141
|
+
(0, 0, z8^4 + z8^3 + z8^2 + 1, 0, 0),
|
|
2142
|
+
(0, 0, z8^4 + z8^3 + z8^2 + 1, 0, z8^3 + z8^2 + 1),
|
|
2143
|
+
(0, 0, z8^6 + z8^3 + z8^2, 0, 0),
|
|
2144
|
+
(0, 0, z8^6 + z8^3 + z8^2, 0, z8^3 + z8^2)]
|
|
2145
|
+
|
|
2146
|
+
Check that the twists are mutually non-isomorphic::
|
|
2147
|
+
|
|
2148
|
+
sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings
|
|
2149
|
+
....: for e1 in curves for e2 in curves)
|
|
2150
|
+
True
|
|
2151
|
+
|
|
2152
|
+
Check that the weight formula holds::
|
|
2153
|
+
|
|
2154
|
+
sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings
|
|
2155
|
+
True
|
|
2156
|
+
"""
|
|
2157
|
+
if not K.is_finite() or K.characteristic() != 2:
|
|
2158
|
+
raise ValueError("field must be finite of characteristic 2")
|
|
2159
|
+
if K.degree() % 2:
|
|
2160
|
+
return [EllipticCurve(K, [0, 0, 1, 0, 0]),
|
|
2161
|
+
EllipticCurve(K, [0, 0, 1, 1, 0]),
|
|
2162
|
+
EllipticCurve(K, [0, 0, 1, 1, 1])]
|
|
2163
|
+
# find a,b,c,d,e such that
|
|
2164
|
+
# a is not a cube, i.e. a**((q-1)//3)!=1
|
|
2165
|
+
# Tr(b)=1
|
|
2166
|
+
# X^4+X+c irreducible
|
|
2167
|
+
# X^2+a*X+d irreducible
|
|
2168
|
+
# X^2+a^2*X+e irreducible
|
|
2169
|
+
a = b = c = d = e = None
|
|
2170
|
+
x = polygen(K)
|
|
2171
|
+
q3 = (K.cardinality()-1)//3
|
|
2172
|
+
while not a or a**q3 == 1:
|
|
2173
|
+
a = K.random_element()
|
|
2174
|
+
asq = a*a
|
|
2175
|
+
while not b or not b.trace():
|
|
2176
|
+
b = K.random_element()
|
|
2177
|
+
c = K.one() # OK if degree is 2 mod 4
|
|
2178
|
+
if K.degree() % 4 == 0:
|
|
2179
|
+
while (x**4+x+c).roots():
|
|
2180
|
+
c = K.random_element()
|
|
2181
|
+
while not d or (x**2+a*x+d).roots():
|
|
2182
|
+
d = K.random_element()
|
|
2183
|
+
while not e or (x**2+asq*x+e).roots():
|
|
2184
|
+
e = K.random_element()
|
|
2185
|
+
return [EllipticCurve(K, ai) for ai in
|
|
2186
|
+
[[0,0,1,0,0], [0,0,1,0,b], [0,0,1,c,0], [0,0,a,0,0], [0,0,a,0,d], [0,0,asq,0,0], [0,0,asq,0,e]]]
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
def curves_with_j_0_char3(K):
|
|
2190
|
+
r"""
|
|
2191
|
+
Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 3.
|
|
2192
|
+
|
|
2193
|
+
.. NOTE::
|
|
2194
|
+
|
|
2195
|
+
The number of twists is either 4 or 6 depending on whether
|
|
2196
|
+
the field has odd or even degree over `\GF{3}`. See
|
|
2197
|
+
[Connell1999]_, pages 429-431.
|
|
2198
|
+
|
|
2199
|
+
Examples:
|
|
2200
|
+
|
|
2201
|
+
In odd degree, there are four isomorphism classes::
|
|
2202
|
+
|
|
2203
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char3
|
|
2204
|
+
sage: # needs sage.rings.finite_rings
|
|
2205
|
+
sage: K = GF(3**5)
|
|
2206
|
+
sage: curves = curves_with_j_0_char3(K)
|
|
2207
|
+
sage: len(curves)
|
|
2208
|
+
4
|
|
2209
|
+
sage: [E.ainvs() for E in curves] # random
|
|
2210
|
+
[(0, 0, 0, 1, 0),
|
|
2211
|
+
(0, 0, 0, 2, 0),
|
|
2212
|
+
(0, 0, 0, 2, z5^4 + z5^3 + z5^2),
|
|
2213
|
+
(0, 0, 0, 2, 2*z5^4 + 2*z5^3 + 2*z5^2)]
|
|
2214
|
+
|
|
2215
|
+
Check that the twists are mutually non-isomorphic::
|
|
2216
|
+
|
|
2217
|
+
sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings
|
|
2218
|
+
....: for e1 in curves for e2 in curves)
|
|
2219
|
+
True
|
|
2220
|
+
|
|
2221
|
+
Check that the weight formula holds::
|
|
2222
|
+
|
|
2223
|
+
sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings
|
|
2224
|
+
True
|
|
2225
|
+
|
|
2226
|
+
In even degree, there are six isomorphism classes::
|
|
2227
|
+
|
|
2228
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import curves_with_j_0_char3
|
|
2229
|
+
sage: # needs sage.rings.finite_rings
|
|
2230
|
+
sage: K = GF(3**4)
|
|
2231
|
+
sage: curves = EllipticCurve(j=K(0)).twists()
|
|
2232
|
+
sage: len(curves)
|
|
2233
|
+
6
|
|
2234
|
+
sage: [E.ainvs() for E in curves] # random
|
|
2235
|
+
[(0, 0, 0, 1, 0),
|
|
2236
|
+
(0, 0, 0, 2, 2*z4^3 + 2*z4^2 + 2*z4 + 2),
|
|
2237
|
+
(0, 0, 0, 1, 0),
|
|
2238
|
+
(0, 0, 0, 1, 2*z4^3 + 2*z4^2 + 2*z4 + 2),
|
|
2239
|
+
(0, 0, 0, z4, 0),
|
|
2240
|
+
(0, 0, 0, z4^3, 0)]
|
|
2241
|
+
|
|
2242
|
+
Check that the twists are mutually non-isomorphic::
|
|
2243
|
+
|
|
2244
|
+
sage: all((e1 == e2 or not e1.is_isomorphic(e2)) # needs sage.rings.finite_rings
|
|
2245
|
+
....: for e1 in curves for e2 in curves)
|
|
2246
|
+
True
|
|
2247
|
+
|
|
2248
|
+
Check that the weight formula holds::
|
|
2249
|
+
|
|
2250
|
+
sage: sum(1/len(E.automorphisms()) for E in curves) == 1 # needs sage.rings.finite_rings
|
|
2251
|
+
True
|
|
2252
|
+
"""
|
|
2253
|
+
if not K.is_finite() or K.characteristic() != 3:
|
|
2254
|
+
raise ValueError("field must be finite of characteristic 3")
|
|
2255
|
+
# find b with nonzero trace
|
|
2256
|
+
b = None
|
|
2257
|
+
while not b or not b.trace():
|
|
2258
|
+
b = K.random_element()
|
|
2259
|
+
|
|
2260
|
+
if K.degree() % 2:
|
|
2261
|
+
return [EllipticCurve(K, a4a6) for a4a6 in
|
|
2262
|
+
[[1,0], [-1,0], [-1,b], [-1,-b]]]
|
|
2263
|
+
|
|
2264
|
+
# find a, i, c where:
|
|
2265
|
+
# a generates K* mod 4th powers, i.e. non-square,
|
|
2266
|
+
# i^2=-1
|
|
2267
|
+
# c with x^3+a^2*x+c irreducible
|
|
2268
|
+
a = K.gen()
|
|
2269
|
+
q2 = (K.cardinality()-1)//2
|
|
2270
|
+
while not a or a**q2 == 1:
|
|
2271
|
+
a = K.random_element()
|
|
2272
|
+
x = polygen(K)
|
|
2273
|
+
i = (x**2+1).roots()[0][0]
|
|
2274
|
+
c = None
|
|
2275
|
+
while not c or (x**3 + a**2*x + c).roots():
|
|
2276
|
+
c = K.random_element()
|
|
2277
|
+
return [EllipticCurve(K, a4a6) for a4a6 in
|
|
2278
|
+
[[1,0], [1,i*b], [a,0], [a**2,0], [a**2,c], [a**3,0]]]
|
|
2279
|
+
|
|
2280
|
+
# dict to hold precomputed coefficient vectors of supersingular j values (excluding 0, 1728):
|
|
2281
|
+
|
|
2282
|
+
|
|
2283
|
+
supersingular_j_polynomials = {}
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
def fill_ss_j_dict():
|
|
2287
|
+
r"""
|
|
2288
|
+
Fill the global cache of supersingular j-_polynomials.
|
|
2289
|
+
|
|
2290
|
+
This function does nothing except the first time it is called,
|
|
2291
|
+
when it fills ``supersingular_j_polynomials`` with precomputed
|
|
2292
|
+
values for `p<300`. Setting the values this way avoids start-up
|
|
2293
|
+
costs.
|
|
2294
|
+
"""
|
|
2295
|
+
global supersingular_j_polynomials
|
|
2296
|
+
if not supersingular_j_polynomials:
|
|
2297
|
+
supersingular_j_polynomials[13] = [8, 1]
|
|
2298
|
+
supersingular_j_polynomials[17] = [9, 1]
|
|
2299
|
+
supersingular_j_polynomials[19] = [12, 1]
|
|
2300
|
+
supersingular_j_polynomials[23] = [4, 1]
|
|
2301
|
+
supersingular_j_polynomials[29] = [21, 2, 1]
|
|
2302
|
+
supersingular_j_polynomials[31] = [8, 25, 1]
|
|
2303
|
+
supersingular_j_polynomials[37] = [11, 5, 23, 1]
|
|
2304
|
+
supersingular_j_polynomials[41] = [18, 10, 19, 1]
|
|
2305
|
+
supersingular_j_polynomials[43] = [32, 11, 21, 1]
|
|
2306
|
+
supersingular_j_polynomials[47] = [35, 33, 31, 1]
|
|
2307
|
+
supersingular_j_polynomials[53] = [24, 9, 30, 7, 1]
|
|
2308
|
+
supersingular_j_polynomials[59] = [39, 31, 35, 39, 1]
|
|
2309
|
+
supersingular_j_polynomials[61] = [60, 21, 27, 8, 60, 1]
|
|
2310
|
+
supersingular_j_polynomials[67] = [8, 36, 47, 4, 53, 1]
|
|
2311
|
+
supersingular_j_polynomials[71] = [18, 54, 28, 33, 1, 1]
|
|
2312
|
+
supersingular_j_polynomials[73] = [7, 39, 38, 9, 68, 60, 1]
|
|
2313
|
+
supersingular_j_polynomials[79] = [10, 25, 1, 63, 57, 55, 1]
|
|
2314
|
+
supersingular_j_polynomials[83] = [43, 72, 81, 81, 62, 11, 1]
|
|
2315
|
+
supersingular_j_polynomials[89] = [42, 79, 23, 22, 37, 86, 60, 1]
|
|
2316
|
+
supersingular_j_polynomials[97] = [19, 28, 3, 72, 2, 96, 10, 60, 1]
|
|
2317
|
+
supersingular_j_polynomials[101] = [9, 76, 45, 79, 1, 68, 87, 60, 1]
|
|
2318
|
+
supersingular_j_polynomials[103] = [64, 15, 24, 58, 70, 83, 84, 100, 1]
|
|
2319
|
+
supersingular_j_polynomials[107] = [6, 18, 72, 59, 43, 19, 17, 68, 1]
|
|
2320
|
+
supersingular_j_polynomials[109] = [107, 22, 39, 83, 30, 34, 108, 104, 60, 1]
|
|
2321
|
+
supersingular_j_polynomials[113] = [86, 71, 75, 6, 47, 97, 100, 4, 60, 1]
|
|
2322
|
+
supersingular_j_polynomials[127] = [32, 31, 5, 50, 115, 122, 114, 67, 38, 35, 1]
|
|
2323
|
+
supersingular_j_polynomials[131] = [65, 64, 10, 34, 129, 35, 94, 127, 7, 7, 1]
|
|
2324
|
+
supersingular_j_polynomials[137] = [104, 83, 3, 82, 112, 23, 77, 135, 18, 50, 60, 1]
|
|
2325
|
+
supersingular_j_polynomials[139] = [87, 79, 109, 21, 138, 9, 104, 130, 61, 118, 90, 1]
|
|
2326
|
+
supersingular_j_polynomials[149] = [135, 55, 80, 86, 87, 74, 32, 60, 130, 80, 146, 60, 1]
|
|
2327
|
+
supersingular_j_polynomials[151] = [94, 125, 8, 6, 93, 21, 114, 80, 107, 58, 42, 18, 1]
|
|
2328
|
+
supersingular_j_polynomials[157] = [14, 95, 22, 58, 110, 23, 71, 51, 47, 5, 147, 59, 60, 1]
|
|
2329
|
+
supersingular_j_polynomials[163] = [102, 26, 74, 95, 112, 151, 98, 107, 27, 37, 25, 111, 109, 1]
|
|
2330
|
+
supersingular_j_polynomials[167] = [14, 9, 27, 109, 97, 55, 51, 74, 145, 125, 36, 113, 89, 1]
|
|
2331
|
+
supersingular_j_polynomials[173] = [152, 73, 56, 12, 18, 96, 98, 49, 30, 43, 52, 79, 163, 60, 1]
|
|
2332
|
+
supersingular_j_polynomials[179] = [110, 51, 3, 94, 123, 90, 156, 90, 88, 119, 158, 27, 71, 29, 1]
|
|
2333
|
+
supersingular_j_polynomials[181] = [7, 65, 77, 29, 139, 34, 65, 84, 164, 73, 51, 136, 7, 141, 60, 1]
|
|
2334
|
+
supersingular_j_polynomials[191] = [173, 140, 144, 3, 135, 80, 182, 84, 93, 75, 83, 17, 22, 42, 160, 1]
|
|
2335
|
+
supersingular_j_polynomials[193] = [23, 48, 26, 15, 108, 141, 124, 44, 132, 49, 72, 173, 126, 101, 22, 60, 1]
|
|
2336
|
+
supersingular_j_polynomials[197] = [14, 111, 64, 170, 193, 32, 124, 91, 112, 163, 14, 112, 167, 191, 183, 60, 1]
|
|
2337
|
+
supersingular_j_polynomials[199] = [125, 72, 65, 30, 63, 45, 10, 177, 91, 102, 28, 27, 5, 150, 51, 128, 1]
|
|
2338
|
+
supersingular_j_polynomials[211] = [27, 137, 128, 90, 102, 141, 5, 77, 131, 144, 83, 108, 23, 105, 98, 13, 80, 1]
|
|
2339
|
+
supersingular_j_polynomials[223] = [56, 183, 46, 133, 191, 94, 20, 8, 92, 100, 57, 200, 166, 67, 59, 218, 28, 32, 1]
|
|
2340
|
+
supersingular_j_polynomials[227] = [79, 192, 142, 66, 11, 114, 100, 208, 57, 147, 32, 5, 144, 93, 185, 147, 92, 16, 1]
|
|
2341
|
+
supersingular_j_polynomials[229] = [22, 55, 182, 130, 228, 172, 63, 25, 108, 99, 100, 101, 220, 111, 205, 199, 91, 163, 60, 1]
|
|
2342
|
+
supersingular_j_polynomials[233] = [101, 148, 85, 113, 226, 68, 71, 103, 61, 44, 173, 175, 5, 225, 227, 99, 146, 170, 60, 1]
|
|
2343
|
+
supersingular_j_polynomials[239] = [225, 81, 47, 26, 133, 182, 238, 2, 144, 154, 234, 178, 165, 130, 35, 61, 144, 112, 207, 1]
|
|
2344
|
+
supersingular_j_polynomials[241] = [224, 51, 227, 139, 134, 186, 187, 152, 161, 175, 213, 59, 105, 88, 87, 124, 202, 40, 15, 60, 1]
|
|
2345
|
+
supersingular_j_polynomials[251] = [30, 183, 80, 127, 40, 56, 230, 168, 192, 48, 226, 61, 214, 54, 165, 147, 105, 88, 38, 171, 1]
|
|
2346
|
+
supersingular_j_polynomials[257] = [148, 201, 140, 146, 169, 147, 220, 4, 205, 224, 35, 42, 198, 97, 127, 7, 110, 229, 118, 202, 60, 1]
|
|
2347
|
+
supersingular_j_polynomials[263] = [245, 126, 72, 213, 14, 64, 152, 83, 169, 114, 9, 128, 138, 231, 103, 85, 114, 211, 173, 249, 135, 1]
|
|
2348
|
+
supersingular_j_polynomials[269] = [159, 32, 69, 95, 201, 266, 190, 176, 76, 151, 212, 21, 106, 49, 263, 105, 136, 194, 215, 181, 237, 60, 1]
|
|
2349
|
+
supersingular_j_polynomials[271] = [169, 87, 179, 109, 133, 101, 31, 167, 208, 99, 127, 120, 83, 62, 36, 23, 61, 50, 69, 263, 265, 111, 1]
|
|
2350
|
+
supersingular_j_polynomials[277] = [251, 254, 171, 72, 190, 237, 12, 231, 123, 217, 263, 151, 270, 183, 29, 228, 85, 4, 67, 101, 29, 169, 60, 1]
|
|
2351
|
+
supersingular_j_polynomials[281] = [230, 15, 146, 69, 41, 23, 142, 232, 18, 80, 58, 134, 270, 62, 272, 70, 247, 189, 118, 255, 274, 159, 60, 1]
|
|
2352
|
+
supersingular_j_polynomials[283] = [212, 4, 42, 155, 38, 1, 270, 175, 172, 256, 264, 232, 50, 82, 244, 127, 148, 46, 249, 72, 59, 124, 75, 1]
|
|
2353
|
+
supersingular_j_polynomials[293] = [264, 66, 165, 144, 243, 25, 163, 210, 18, 107, 160, 153, 70, 255, 91, 211, 22, 7, 256, 50, 150, 94, 225, 60, 1]
|
|
2354
|
+
|
|
2355
|
+
|
|
2356
|
+
def supersingular_j_polynomial(p, use_cache=True):
|
|
2357
|
+
r"""
|
|
2358
|
+
Return a polynomial whose roots are the supersingular
|
|
2359
|
+
`j`-invariants in characteristic `p`, other than 0, 1728.
|
|
2360
|
+
|
|
2361
|
+
INPUT:
|
|
2362
|
+
|
|
2363
|
+
- ``p`` -- integer; a prime number
|
|
2364
|
+
|
|
2365
|
+
- ``use_cache`` -- boolean (default: ``True``); use cached coefficients if they exist
|
|
2366
|
+
|
|
2367
|
+
ALGORITHM:
|
|
2368
|
+
|
|
2369
|
+
First compute H(X) whose roots are the Legendre
|
|
2370
|
+
`\lambda`-invariants of supersingular curves (Silverman V.4.1(b))
|
|
2371
|
+
in characteristic `p`. Then, using a resultant computation with
|
|
2372
|
+
the polynomial relating `\lambda` and `j` (Silverman III.1.7(b)),
|
|
2373
|
+
we recover the polynomial (in variable ``j``) whose roots are the
|
|
2374
|
+
`j`-invariants. Factors of `j` and `j-1728` are removed if
|
|
2375
|
+
present.
|
|
2376
|
+
|
|
2377
|
+
.. NOTE::
|
|
2378
|
+
|
|
2379
|
+
The only point of the use_cache parameter is to allow checking
|
|
2380
|
+
the precomputed coefficients.
|
|
2381
|
+
|
|
2382
|
+
EXAMPLES::
|
|
2383
|
+
|
|
2384
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import supersingular_j_polynomial
|
|
2385
|
+
sage: f = supersingular_j_polynomial(67); f
|
|
2386
|
+
j^5 + 53*j^4 + 4*j^3 + 47*j^2 + 36*j + 8
|
|
2387
|
+
sage: f.factor()
|
|
2388
|
+
(j + 1) * (j^2 + 8*j + 45) * (j^2 + 44*j + 24)
|
|
2389
|
+
|
|
2390
|
+
::
|
|
2391
|
+
|
|
2392
|
+
sage: [supersingular_j_polynomial(p) for p in prime_range(30)]
|
|
2393
|
+
[1, 1, 1, 1, 1, j + 8, j + 9, j + 12, j + 4, j^2 + 2*j + 21]
|
|
2394
|
+
|
|
2395
|
+
TESTS::
|
|
2396
|
+
|
|
2397
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import supersingular_j_polynomial
|
|
2398
|
+
sage: supersingular_j_polynomial(6)
|
|
2399
|
+
Traceback (most recent call last):
|
|
2400
|
+
...
|
|
2401
|
+
ValueError: p (=6) should be a prime number
|
|
2402
|
+
|
|
2403
|
+
Check the cached values are correct::
|
|
2404
|
+
|
|
2405
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import supersingular_j_polynomial as ssjpol
|
|
2406
|
+
sage: assert all(ssjpol(p,True) == ssjpol(p,False) for p in primes(300))
|
|
2407
|
+
"""
|
|
2408
|
+
try:
|
|
2409
|
+
p = ZZ(p)
|
|
2410
|
+
except TypeError:
|
|
2411
|
+
raise ValueError("p (=%s) should be a prime number" % p)
|
|
2412
|
+
if not p.is_prime():
|
|
2413
|
+
raise ValueError("p (=%s) should be a prime number" % p)
|
|
2414
|
+
|
|
2415
|
+
J = polygen(GF(p),'j')
|
|
2416
|
+
if p < 13:
|
|
2417
|
+
return J.parent().one()
|
|
2418
|
+
if use_cache:
|
|
2419
|
+
fill_ss_j_dict()
|
|
2420
|
+
if p in supersingular_j_polynomials:
|
|
2421
|
+
return J.parent()(supersingular_j_polynomials[p])
|
|
2422
|
+
|
|
2423
|
+
from sage.misc.misc_c import prod
|
|
2424
|
+
m = (p-1)//2
|
|
2425
|
+
X,T = PolynomialRing(GF(p),2,names=['X','T']).gens()
|
|
2426
|
+
H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1))
|
|
2427
|
+
F = T**2 * (T-1)**2 * X - 256*(T**2-T+1)**3
|
|
2428
|
+
R = F.resultant(H, T)
|
|
2429
|
+
R = prod([fi for fi, e in R([J, 0]).factor()])
|
|
2430
|
+
if R(0) == 0:
|
|
2431
|
+
R = R // J
|
|
2432
|
+
if R(1728) == 0:
|
|
2433
|
+
R = R // (J - 1728)
|
|
2434
|
+
supersingular_j_polynomials[p] = R.coefficients(sparse=False)
|
|
2435
|
+
return R
|
|
2436
|
+
|
|
2437
|
+
|
|
2438
|
+
def is_j_supersingular(j, proof=True):
|
|
2439
|
+
r"""
|
|
2440
|
+
Return ``True`` if `j` is a supersingular `j`-invariant.
|
|
2441
|
+
|
|
2442
|
+
INPUT:
|
|
2443
|
+
|
|
2444
|
+
- ``j`` -- finite field element
|
|
2445
|
+
|
|
2446
|
+
- ``proof``-- boolean (default: ``True``); if ``True``, returns a proved
|
|
2447
|
+
result. If ``False``, then a return value of ``False`` is certain but a
|
|
2448
|
+
return value of ``True`` may be based on a probabilistic test. See
|
|
2449
|
+
the ALGORITHM section below for more details.
|
|
2450
|
+
|
|
2451
|
+
OUTPUT: boolean; ``True`` if `j` is supersingular, else ``False``
|
|
2452
|
+
|
|
2453
|
+
ALGORITHM:
|
|
2454
|
+
|
|
2455
|
+
For small characteristics `p` we check whether the `j`-invariant
|
|
2456
|
+
is in a precomputed list of supersingular values. Otherwise we
|
|
2457
|
+
next check the `j`-invariant. If `j=0`, the curve is
|
|
2458
|
+
supersingular if and only if `p=2` or `p\equiv3\pmod{4}`; if
|
|
2459
|
+
`j=1728`, the curve is supersingular if and only if `p=3` or
|
|
2460
|
+
`p\equiv2\pmod{3}`. Next, if the base field is the prime field
|
|
2461
|
+
`{\rm GF}(p)`, we check that `(p+1)P=0` for several random points
|
|
2462
|
+
`P`, returning ``False`` if any fail: supersingular curves over `{\rm
|
|
2463
|
+
GF}(p)` have cardinality `p+1`. If Proof is false we now return
|
|
2464
|
+
``True``. Otherwise we compute the cardinality and return ``True`` if and
|
|
2465
|
+
only if it is divisible by `p`.
|
|
2466
|
+
|
|
2467
|
+
EXAMPLES::
|
|
2468
|
+
|
|
2469
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import is_j_supersingular, supersingular_j_polynomials
|
|
2470
|
+
sage: [(p,[j for j in GF(p) if is_j_supersingular(j)]) for p in prime_range(30)]
|
|
2471
|
+
[(2, [0]), (3, [0]), (5, [0]), (7, [6]), (11, [0, 1]), (13, [5]),
|
|
2472
|
+
(17, [0, 8]), (19, [7, 18]), (23, [0, 3, 19]), (29, [0, 2, 25])]
|
|
2473
|
+
|
|
2474
|
+
sage: [j for j in GF(109) if is_j_supersingular(j)]
|
|
2475
|
+
[17, 41, 43]
|
|
2476
|
+
sage: PolynomialRing(GF(109),'j')(supersingular_j_polynomials[109]).roots()
|
|
2477
|
+
[(43, 1), (41, 1), (17, 1)]
|
|
2478
|
+
|
|
2479
|
+
sage: [p for p in prime_range(100) if is_j_supersingular(GF(p)(0))]
|
|
2480
|
+
[2, 3, 5, 11, 17, 23, 29, 41, 47, 53, 59, 71, 83, 89]
|
|
2481
|
+
sage: [p for p in prime_range(100) if is_j_supersingular(GF(p)(1728))]
|
|
2482
|
+
[2, 3, 7, 11, 19, 23, 31, 43, 47, 59, 67, 71, 79, 83]
|
|
2483
|
+
sage: [p for p in prime_range(100) if is_j_supersingular(GF(p)(123456))]
|
|
2484
|
+
[2, 3, 59, 89]
|
|
2485
|
+
"""
|
|
2486
|
+
if not (isinstance(j, Element) and isinstance(j.parent(), FiniteField)):
|
|
2487
|
+
raise ValueError("%s must be an element of a finite field" % j)
|
|
2488
|
+
|
|
2489
|
+
F = j.parent()
|
|
2490
|
+
p = F.characteristic()
|
|
2491
|
+
d = F.degree()
|
|
2492
|
+
|
|
2493
|
+
if j.is_zero():
|
|
2494
|
+
return p == 3 or p % 3 == 2
|
|
2495
|
+
|
|
2496
|
+
if (j - 1728).is_zero():
|
|
2497
|
+
return p == 2 or p % 4 == 3
|
|
2498
|
+
|
|
2499
|
+
# From now on we know that j != 0, 1728
|
|
2500
|
+
|
|
2501
|
+
if p in (2, 3, 5, 7, 11):
|
|
2502
|
+
return False # since j=0, 1728 are the only s.s. invariants
|
|
2503
|
+
|
|
2504
|
+
# supersingular j-invariants have degree at most 2:
|
|
2505
|
+
|
|
2506
|
+
jpol = j.minimal_polynomial()
|
|
2507
|
+
degj = jpol.degree()
|
|
2508
|
+
if degj > 2:
|
|
2509
|
+
return False
|
|
2510
|
+
|
|
2511
|
+
# if p occurs in the precomputed list, use that:
|
|
2512
|
+
|
|
2513
|
+
fill_ss_j_dict()
|
|
2514
|
+
if p in supersingular_j_polynomials:
|
|
2515
|
+
return supersingular_j_polynomial(p)(j).is_zero()
|
|
2516
|
+
|
|
2517
|
+
# Over GF(p), supersingular elliptic curves have cardinality
|
|
2518
|
+
# exactly p+1, so we check some random points in order to detect
|
|
2519
|
+
# non-supersingularity. Over GF(p^2) (for p at least 5) the
|
|
2520
|
+
# cardinality is either (p-1)^2 or (p+1)^2, and the group has
|
|
2521
|
+
# exponent p+1 or p-1, so we can do a similar random check: unless
|
|
2522
|
+
# (p+1)*P=0 for all the random points, or (p-1)*P=0 for all of
|
|
2523
|
+
# them, we can certainly return False.
|
|
2524
|
+
|
|
2525
|
+
# First we replace j by an element of GF(p) or GF(p^2) (since F
|
|
2526
|
+
# might be a proper extension of these):
|
|
2527
|
+
|
|
2528
|
+
if degj == 1:
|
|
2529
|
+
j = -jpol(0) # = j, but in GF(p)
|
|
2530
|
+
elif d > 2:
|
|
2531
|
+
F = GF((p, 2), 'a')
|
|
2532
|
+
j = jpol.roots(F, multiplicities=False)[0] # j, but in GF(p^2)
|
|
2533
|
+
|
|
2534
|
+
E = EllipticCurve(j=j)
|
|
2535
|
+
if degj == 1:
|
|
2536
|
+
for i in range(10):
|
|
2537
|
+
P = E.random_element()
|
|
2538
|
+
if not ((p + 1) * P).is_zero():
|
|
2539
|
+
return False
|
|
2540
|
+
else:
|
|
2541
|
+
n = None # will hold either p+1 or p-1 later
|
|
2542
|
+
for i in range(10):
|
|
2543
|
+
P = E.random_element()
|
|
2544
|
+
# avoid 2-torsion; we know that a1=a3=0 and #E>4!
|
|
2545
|
+
while P[2].is_zero() or P[1].is_zero():
|
|
2546
|
+
P = E.random_element()
|
|
2547
|
+
|
|
2548
|
+
if n is None: # not yet decided between p+1 and p-1
|
|
2549
|
+
pP = p*P
|
|
2550
|
+
if pP[0] != P[0]: # i.e. pP is neither P nor -P
|
|
2551
|
+
return False
|
|
2552
|
+
if pP[1] == P[1]: # then p*P == P != -P
|
|
2553
|
+
n = p - 1
|
|
2554
|
+
else: # then p*P == -P != P
|
|
2555
|
+
n = p + 1
|
|
2556
|
+
else:
|
|
2557
|
+
if not (n*P).is_zero():
|
|
2558
|
+
return False
|
|
2559
|
+
|
|
2560
|
+
# when proof is False we return True for any curve which passes
|
|
2561
|
+
# the probabilistic test:
|
|
2562
|
+
|
|
2563
|
+
if not proof:
|
|
2564
|
+
return True
|
|
2565
|
+
|
|
2566
|
+
# otherwise we check the trace of Frobenius (which could be
|
|
2567
|
+
# expensive since it involves counting the number of points on E):
|
|
2568
|
+
|
|
2569
|
+
return E.trace_of_frobenius() % p == 0
|
|
2570
|
+
|
|
2571
|
+
|
|
2572
|
+
def special_supersingular_curve(F, q=None, *, endomorphism=False):
|
|
2573
|
+
r"""
|
|
2574
|
+
Given a finite field ``F`` of characteristic `p`, and optionally
|
|
2575
|
+
a positive integer `q` such that the Hilbert conductor of `-q`
|
|
2576
|
+
and `-p` equals `p`, construct a "special" supersingular elliptic
|
|
2577
|
+
curve `E` defined over ``F``.
|
|
2578
|
+
|
|
2579
|
+
Such a curve
|
|
2580
|
+
|
|
2581
|
+
- has coefficients in `\mathbb F_p`;
|
|
2582
|
+
|
|
2583
|
+
- has group structure `E(\mathbb F_p) \cong \ZZ/(p+1)` and
|
|
2584
|
+
`E(\mathbb F_{p^2}) \cong \ZZ/(p+1) \times \ZZ/(p+1)`;
|
|
2585
|
+
|
|
2586
|
+
- has an endomorphism `\vartheta` of degree `q` that
|
|
2587
|
+
anticommutes with the `\mathbb F_p`-Frobenius on `E`.
|
|
2588
|
+
|
|
2589
|
+
(The significance of `\vartheta` is that any such endomorphism,
|
|
2590
|
+
together with the `\mathbb F_p`-Frobenius, generates the endomorphism
|
|
2591
|
+
algebra `\mathrm{End}(E) \otimes \QQ`.)
|
|
2592
|
+
|
|
2593
|
+
The complexity grows exponentially in `\log(q)`. Automatically
|
|
2594
|
+
chosen values of `q` lie in `O((\log p)^2)` assuming GRH.
|
|
2595
|
+
|
|
2596
|
+
INPUT:
|
|
2597
|
+
|
|
2598
|
+
- ``F`` -- finite field `\mathbb F_{p^r}`
|
|
2599
|
+
|
|
2600
|
+
- ``q`` -- positive integer (optional, default ``None``)
|
|
2601
|
+
|
|
2602
|
+
- ``endomorphism`` -- boolean (default: ``False``); when set to ``True``,
|
|
2603
|
+
it is required that `2 \mid r`, and the function then additionally
|
|
2604
|
+
returns `\vartheta`
|
|
2605
|
+
|
|
2606
|
+
.. WARNING::
|
|
2607
|
+
|
|
2608
|
+
Due to :issue:`38481`, calling this function with a value of `q`
|
|
2609
|
+
larger than approximately `p/4` may currently fail. This failure
|
|
2610
|
+
will not occur for automatically chosen values of `q`.
|
|
2611
|
+
|
|
2612
|
+
EXAMPLES::
|
|
2613
|
+
|
|
2614
|
+
sage: special_supersingular_curve(GF(1013^2), endomorphism=True)
|
|
2615
|
+
(Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1013^2,
|
|
2616
|
+
Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1013^2 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1013^2)
|
|
2617
|
+
|
|
2618
|
+
sage: special_supersingular_curve(GF(1019^2), endomorphism=True)
|
|
2619
|
+
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1019^2,
|
|
2620
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1019^2
|
|
2621
|
+
Via: (u,r,s,t) = (389*z2 + 241, 0, 0, 0))
|
|
2622
|
+
|
|
2623
|
+
sage: special_supersingular_curve(GF(1021^2), endomorphism=True)
|
|
2624
|
+
(Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2,
|
|
2625
|
+
Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2 to Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2)
|
|
2626
|
+
|
|
2627
|
+
sage: special_supersingular_curve(GF(1031^2), endomorphism=True)
|
|
2628
|
+
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2,
|
|
2629
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2
|
|
2630
|
+
Via: (u,r,s,t) = (747*z2 + 284, 0, 0, 0))
|
|
2631
|
+
|
|
2632
|
+
sage: special_supersingular_curve(GF(1033^2), endomorphism=True)
|
|
2633
|
+
(Elliptic Curve defined by y^2 = x^3 + 53*x + 980 over Finite Field in z2 of size 1033^2,
|
|
2634
|
+
Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + 53*x + 980 over Finite Field in z2 of size 1033^2 to Elliptic Curve defined by y^2 = x^3 + 53*x + 980 over Finite Field in z2 of size 1033^2)
|
|
2635
|
+
|
|
2636
|
+
sage: special_supersingular_curve(GF(1039^2), endomorphism=True)
|
|
2637
|
+
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1039^2,
|
|
2638
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1039^2
|
|
2639
|
+
Via: (u,r,s,t) = (626*z2 + 200, 0, 0, 0))
|
|
2640
|
+
|
|
2641
|
+
sage: special_supersingular_curve(GF(1049^2), endomorphism=True)
|
|
2642
|
+
(Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1049^2,
|
|
2643
|
+
Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1049^2 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 1049^2)
|
|
2644
|
+
|
|
2645
|
+
sage: special_supersingular_curve(GF(1051^2), endomorphism=True)
|
|
2646
|
+
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2,
|
|
2647
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2
|
|
2648
|
+
Via: (u,r,s,t) = (922*z2 + 129, 0, 0, 0))
|
|
2649
|
+
|
|
2650
|
+
We can also supply a suitable value of `q` ourselves::
|
|
2651
|
+
|
|
2652
|
+
sage: special_supersingular_curve(GF(1019), q=99)
|
|
2653
|
+
Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field of size 1019
|
|
2654
|
+
|
|
2655
|
+
sage: special_supersingular_curve(GF(1019^2), q=99, endomorphism=True)
|
|
2656
|
+
(Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2,
|
|
2657
|
+
Isogeny of degree 99 from Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2 to Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2)
|
|
2658
|
+
|
|
2659
|
+
sage: special_supersingular_curve(GF(1013), q=99)
|
|
2660
|
+
Traceback (most recent call last):
|
|
2661
|
+
...
|
|
2662
|
+
ValueError: invalid choice of q
|
|
2663
|
+
|
|
2664
|
+
TESTS::
|
|
2665
|
+
|
|
2666
|
+
sage: p = random_prime(1000)
|
|
2667
|
+
sage: E = special_supersingular_curve(GF(p))
|
|
2668
|
+
sage: E.is_supersingular()
|
|
2669
|
+
True
|
|
2670
|
+
sage: E.order() == p + 1
|
|
2671
|
+
True
|
|
2672
|
+
sage: F.<t> = GF((p,2))
|
|
2673
|
+
sage: E, endo = special_supersingular_curve(F, endomorphism=True)
|
|
2674
|
+
sage: E.is_supersingular()
|
|
2675
|
+
True
|
|
2676
|
+
sage: E.j_invariant() in GF(p)
|
|
2677
|
+
True
|
|
2678
|
+
sage: E.abelian_group().invariants() == (p+1, p+1)
|
|
2679
|
+
True
|
|
2680
|
+
sage: endo.domain() is endo.codomain() is E
|
|
2681
|
+
True
|
|
2682
|
+
sage: endo.trace()
|
|
2683
|
+
0
|
|
2684
|
+
sage: pi = E.frobenius_isogeny()
|
|
2685
|
+
sage: pi.codomain() is pi.domain() is E
|
|
2686
|
+
True
|
|
2687
|
+
sage: pi * endo == -endo * pi # needs sage.symbolic
|
|
2688
|
+
True
|
|
2689
|
+
|
|
2690
|
+
Also try it for larger-degree fields::
|
|
2691
|
+
|
|
2692
|
+
sage: k = ZZ(randrange(3, 10, 2))
|
|
2693
|
+
sage: E = special_supersingular_curve(GF((p, k)))
|
|
2694
|
+
sage: E.is_supersingular()
|
|
2695
|
+
True
|
|
2696
|
+
sage: F.<t> = GF((p, 2*k))
|
|
2697
|
+
sage: E, endo = special_supersingular_curve(F, endomorphism=True)
|
|
2698
|
+
sage: E.is_supersingular()
|
|
2699
|
+
True
|
|
2700
|
+
sage: E.j_invariant() in GF(p)
|
|
2701
|
+
True
|
|
2702
|
+
sage: endo.domain() is endo.codomain() is E
|
|
2703
|
+
True
|
|
2704
|
+
sage: endo.trace()
|
|
2705
|
+
0
|
|
2706
|
+
sage: pi = E.frobenius_isogeny()
|
|
2707
|
+
sage: pi.codomain() is pi.domain() is E
|
|
2708
|
+
True
|
|
2709
|
+
sage: pi * endo == -endo * pi # needs sage.symbolic
|
|
2710
|
+
True
|
|
2711
|
+
|
|
2712
|
+
Also try it when `q` is given:
|
|
2713
|
+
|
|
2714
|
+
sage: p = random_prime(300, lbound=10)
|
|
2715
|
+
sage: k = ZZ(randrange(1, 5))
|
|
2716
|
+
sage: while True:
|
|
2717
|
+
....: q = randrange(1, p//4) # upper bound p//4 is a workaround for #38481
|
|
2718
|
+
....: if QuaternionAlgebra(-q, -p).discriminant() == p:
|
|
2719
|
+
....: break
|
|
2720
|
+
sage: E = special_supersingular_curve(GF((p, k)), q)
|
|
2721
|
+
sage: E.is_supersingular()
|
|
2722
|
+
True
|
|
2723
|
+
sage: F.<t> = GF((p, 2*k))
|
|
2724
|
+
sage: E, endo = special_supersingular_curve(F, q, endomorphism=True)
|
|
2725
|
+
sage: E.is_supersingular()
|
|
2726
|
+
True
|
|
2727
|
+
sage: E.j_invariant() in GF(p)
|
|
2728
|
+
True
|
|
2729
|
+
sage: endo.domain() is endo.codomain() is E
|
|
2730
|
+
True
|
|
2731
|
+
sage: endo.degree() == q
|
|
2732
|
+
True
|
|
2733
|
+
sage: endo.trace()
|
|
2734
|
+
0
|
|
2735
|
+
sage: pi = E.frobenius_isogeny()
|
|
2736
|
+
sage: pi.codomain() is pi.domain() is E
|
|
2737
|
+
True
|
|
2738
|
+
sage: pi * endo == -endo * pi # needs sage.symbolic
|
|
2739
|
+
True
|
|
2740
|
+
|
|
2741
|
+
.. NOTE::
|
|
2742
|
+
|
|
2743
|
+
This function makes no guarantees about the distribution of
|
|
2744
|
+
the output. The current implementation is deterministic in
|
|
2745
|
+
many cases.
|
|
2746
|
+
|
|
2747
|
+
ALGORITHM: [Bro2009]_, Algorithm 2.4
|
|
2748
|
+
"""
|
|
2749
|
+
if not isinstance(F, FiniteField):
|
|
2750
|
+
raise TypeError('input must be a finite field')
|
|
2751
|
+
p = F.characteristic()
|
|
2752
|
+
deg = F.degree()
|
|
2753
|
+
|
|
2754
|
+
if endomorphism and deg % 2:
|
|
2755
|
+
raise ValueError('endomorphism was requested but is not defined over given field')
|
|
2756
|
+
|
|
2757
|
+
if q is not None:
|
|
2758
|
+
from sage.arith.misc import hilbert_conductor
|
|
2759
|
+
if p.divides(q) or hilbert_conductor(-q, -p) != p:
|
|
2760
|
+
raise ValueError('invalid choice of q')
|
|
2761
|
+
|
|
2762
|
+
# first find the degree q of our special endomorphism
|
|
2763
|
+
if q is None:
|
|
2764
|
+
if p == 2:
|
|
2765
|
+
q = 3
|
|
2766
|
+
elif p % 4 == 3:
|
|
2767
|
+
q = 1
|
|
2768
|
+
elif p % 3 == 2:
|
|
2769
|
+
q = 3
|
|
2770
|
+
elif p % 8 == 5:
|
|
2771
|
+
q = 2
|
|
2772
|
+
else:
|
|
2773
|
+
from sage.arith.misc import legendre_symbol
|
|
2774
|
+
for q in map(ZZ, range(3,p,4)):
|
|
2775
|
+
if not q.is_prime():
|
|
2776
|
+
continue
|
|
2777
|
+
if legendre_symbol(-q, p) == -1:
|
|
2778
|
+
break
|
|
2779
|
+
else: # should never happen
|
|
2780
|
+
assert False, 'bug in special_supersingular_curve()'
|
|
2781
|
+
q = ZZ(q)
|
|
2782
|
+
|
|
2783
|
+
from sage.arith.misc import fundamental_discriminant
|
|
2784
|
+
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
|
|
2785
|
+
H = hilbert_class_polynomial(fundamental_discriminant(-q))
|
|
2786
|
+
j = H.change_ring(GF(p)).any_root()
|
|
2787
|
+
if j.is_zero():
|
|
2788
|
+
if p == 2:
|
|
2789
|
+
ainvs = [0,0,1,0,0]
|
|
2790
|
+
elif p == 3:
|
|
2791
|
+
ainvs = [1,0]
|
|
2792
|
+
else:
|
|
2793
|
+
ainvs = [0,1]
|
|
2794
|
+
elif j == 1728:
|
|
2795
|
+
ainvs = [1,0]
|
|
2796
|
+
else:
|
|
2797
|
+
a = 27 * j / (4 * (1728-j))
|
|
2798
|
+
ainvs = [a,-a]
|
|
2799
|
+
E = EllipticCurve(F, ainvs)
|
|
2800
|
+
|
|
2801
|
+
if ZZ(2).divides(deg):
|
|
2802
|
+
k = deg//2
|
|
2803
|
+
E.set_order((p**k - (-1)**k)**2)
|
|
2804
|
+
else:
|
|
2805
|
+
E.set_order(p**deg - (-1)**deg)
|
|
2806
|
+
|
|
2807
|
+
if not endomorphism:
|
|
2808
|
+
return E
|
|
2809
|
+
|
|
2810
|
+
if q.is_one():
|
|
2811
|
+
endo = next(auto for auto in E.automorphisms() if auto.trace().is_zero())
|
|
2812
|
+
else:
|
|
2813
|
+
iso = E.isomorphism(F(-q).sqrt(), is_codomain=True)
|
|
2814
|
+
try:
|
|
2815
|
+
endo = iso * E.isogeny(None, iso.domain(), degree=q)
|
|
2816
|
+
except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481
|
|
2817
|
+
endos = (iso*phi for phi in E.isogenies_degree(q)
|
|
2818
|
+
for iso in phi.codomain().isomorphisms(E))
|
|
2819
|
+
endo = next(endo for endo in endos if endo.trace().is_zero())
|
|
2820
|
+
|
|
2821
|
+
endo._degree = ZZ(q)
|
|
2822
|
+
endo.trace.set_cache(ZZ.zero())
|
|
2823
|
+
return E, endo
|
|
2824
|
+
|
|
2825
|
+
|
|
2826
|
+
def EllipticCurve_with_order(m, *, D=None):
|
|
2827
|
+
r"""
|
|
2828
|
+
Return an iterator for elliptic curves over finite fields with the given order. The curves are
|
|
2829
|
+
computed using the Complex Multiplication (CM) method.
|
|
2830
|
+
|
|
2831
|
+
A :class:`~sage.structure.factorization.Factorization` can be passed for ``m``, in which case
|
|
2832
|
+
the algorithm is more efficient.
|
|
2833
|
+
|
|
2834
|
+
If ``D`` is specified, it is used as the discriminant.
|
|
2835
|
+
|
|
2836
|
+
EXAMPLES::
|
|
2837
|
+
|
|
2838
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_with_order
|
|
2839
|
+
sage: E = next(EllipticCurve_with_order(1234)); E # random
|
|
2840
|
+
Elliptic Curve defined by y^2 = x^3 + 1142*x + 1209 over Finite Field of size 1237
|
|
2841
|
+
sage: E.order() == 1234
|
|
2842
|
+
True
|
|
2843
|
+
|
|
2844
|
+
When ``iter`` is set, the function returns an iterator of all elliptic curves with the given
|
|
2845
|
+
order::
|
|
2846
|
+
|
|
2847
|
+
sage: from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_with_order
|
|
2848
|
+
sage: it = EllipticCurve_with_order(21); it
|
|
2849
|
+
<generator object EllipticCurve_with_order at 0x...>
|
|
2850
|
+
sage: E = next(it); E # random
|
|
2851
|
+
Elliptic Curve defined by y^2 = x^3 + 6*x + 14 over Finite Field of size 23
|
|
2852
|
+
sage: E.order() == 21
|
|
2853
|
+
True
|
|
2854
|
+
sage: Es = [E] + list(it); Es # random
|
|
2855
|
+
[Elliptic Curve defined by y^2 = x^3 + 6*x + 14 over Finite Field of size 23,
|
|
2856
|
+
Elliptic Curve defined by y^2 = x^3 + 12*x + 4 over Finite Field of size 23,
|
|
2857
|
+
Elliptic Curve defined by y^2 = x^3 + 5*x + 2 over Finite Field of size 23,
|
|
2858
|
+
Elliptic Curve defined by y^2 = x^3 + (z2+3) over Finite Field in z2 of size 5^2,
|
|
2859
|
+
Elliptic Curve defined by y^2 = x^3 + (2*z2+2) over Finite Field in z2 of size 5^2,
|
|
2860
|
+
Elliptic Curve defined by y^2 = x^3 + 7*x + 1 over Finite Field of size 19,
|
|
2861
|
+
Elliptic Curve defined by y^2 = x^3 + 17*x + 10 over Finite Field of size 19,
|
|
2862
|
+
Elliptic Curve defined by y^2 = x^3 + 5*x + 12 over Finite Field of size 17,
|
|
2863
|
+
Elliptic Curve defined by y^2 = x^3 + 9*x + 1 over Finite Field of size 17,
|
|
2864
|
+
Elliptic Curve defined by y^2 = x^3 + 7*x + 6 over Finite Field of size 17,
|
|
2865
|
+
Elliptic Curve defined by y^2 = x^3 + z3^2*x^2 + (2*z3^2+z3) over Finite Field in z3 of size 3^3,
|
|
2866
|
+
Elliptic Curve defined by y^2 = x^3 + (z3^2+2*z3+1)*x^2 + (2*z3^2+2*z3) over Finite Field in z3 of size 3^3,
|
|
2867
|
+
Elliptic Curve defined by y^2 = x^3 + (z3^2+z3+1)*x^2 + (2*z3^2+1) over Finite Field in z3 of size 3^3,
|
|
2868
|
+
Elliptic Curve defined by y^2 + (z4^2+z4+1)*y = x^3 over Finite Field in z4 of size 2^4,
|
|
2869
|
+
Elliptic Curve defined by y^2 + (z4^2+z4)*y = x^3 over Finite Field in z4 of size 2^4,
|
|
2870
|
+
Elliptic Curve defined by y^2 = x^3 + 18*x + 26 over Finite Field of size 29,
|
|
2871
|
+
Elliptic Curve defined by y^2 = x^3 + 11*x + 19 over Finite Field of size 29,
|
|
2872
|
+
Elliptic Curve defined by y^2 = x^3 + 4 over Finite Field of size 19,
|
|
2873
|
+
Elliptic Curve defined by y^2 = x^3 + 19 over Finite Field of size 31,
|
|
2874
|
+
Elliptic Curve defined by y^2 = x^3 + 4 over Finite Field of size 13]
|
|
2875
|
+
sage: all(E.order() == 21 for E in Es)
|
|
2876
|
+
True
|
|
2877
|
+
|
|
2878
|
+
Indeed, we can verify that this is correct. Hasse's bounds tell us that
|
|
2879
|
+
`p \leq 50` (approximately), and the rest can be checked via bruteforce::
|
|
2880
|
+
|
|
2881
|
+
sage: for p in prime_range(50):
|
|
2882
|
+
....: for j in range(p):
|
|
2883
|
+
....: E0 = EllipticCurve(GF(p), j=j)
|
|
2884
|
+
....: for Et in E0.twists():
|
|
2885
|
+
....: if Et.order() == 21:
|
|
2886
|
+
....: assert any(Et.is_isomorphic(E) for E in Es)
|
|
2887
|
+
|
|
2888
|
+
.. NOTE::
|
|
2889
|
+
|
|
2890
|
+
The output curves are not deterministic, as :func:`EllipticCurve_finite_field.twists` is not
|
|
2891
|
+
deterministic. However, the order of the j-invariants and base fields is fixed.
|
|
2892
|
+
|
|
2893
|
+
AUTHORS:
|
|
2894
|
+
|
|
2895
|
+
- Gareth Ma and Giacomo Pope (Sage Days 123): initial version
|
|
2896
|
+
"""
|
|
2897
|
+
from sage.arith.misc import is_prime_power, factor
|
|
2898
|
+
from sage.quadratic_forms.binary_qf import BinaryQF
|
|
2899
|
+
from sage.structure.factorization import Factorization
|
|
2900
|
+
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
|
|
2901
|
+
|
|
2902
|
+
def find_q(m, m4_fac, D):
|
|
2903
|
+
for t, _ in BinaryQF(1, 0, -D).solve_integer(m4_fac, _flag=3):
|
|
2904
|
+
yield m + 1 - t
|
|
2905
|
+
yield m + 1 + t
|
|
2906
|
+
|
|
2907
|
+
if isinstance(m, Factorization):
|
|
2908
|
+
m4_fac = m * factor(4)
|
|
2909
|
+
m_val = m.value()
|
|
2910
|
+
else:
|
|
2911
|
+
m4_fac = factor(m * 4)
|
|
2912
|
+
m_val = m
|
|
2913
|
+
|
|
2914
|
+
if D is None:
|
|
2915
|
+
Ds = (D for D in range(-1, -4 * m_val - 1, -1) if D % 4 in [0, 1])
|
|
2916
|
+
else:
|
|
2917
|
+
assert D < 0 and D % 4 in [0, 1]
|
|
2918
|
+
Ds = [D]
|
|
2919
|
+
|
|
2920
|
+
seen = set()
|
|
2921
|
+
for D in Ds:
|
|
2922
|
+
for q in find_q(m_val, m4_fac, D):
|
|
2923
|
+
if not is_prime_power(q):
|
|
2924
|
+
continue
|
|
2925
|
+
|
|
2926
|
+
H = hilbert_class_polynomial(D)
|
|
2927
|
+
for j0 in H.roots(ring=GF(q), multiplicities=False):
|
|
2928
|
+
E = EllipticCurve(j=j0)
|
|
2929
|
+
for Et in E.twists():
|
|
2930
|
+
if any(Et.is_isomorphic(E) for E in seen):
|
|
2931
|
+
continue
|
|
2932
|
+
# This tests whether the curve has given order
|
|
2933
|
+
if Et.has_order(m_val):
|
|
2934
|
+
# TODO: remove after 38617
|
|
2935
|
+
Et.set_order(m_val, check=False)
|
|
2936
|
+
seen.add(Et)
|
|
2937
|
+
yield Et
|
|
2938
|
+
|
|
2939
|
+
|
|
2940
|
+
def EllipticCurve_with_prime_order(N):
|
|
2941
|
+
r"""
|
|
2942
|
+
Given a prime number ``N``, find another prime number `p` and construct an
|
|
2943
|
+
elliptic curve `E` defined over `\mathbb F_p` such that
|
|
2944
|
+
`\#E(\mathbb F_p) = N`.
|
|
2945
|
+
|
|
2946
|
+
INPUT:
|
|
2947
|
+
|
|
2948
|
+
- ``N`` -- integer; the order for which we seek an elliptic curve. Must be a
|
|
2949
|
+
prime number.
|
|
2950
|
+
|
|
2951
|
+
OUTPUT: an iterator of (some) elliptic curves `E/\mathbb F_p` of order ``N``
|
|
2952
|
+
|
|
2953
|
+
ALGORITHM:
|
|
2954
|
+
|
|
2955
|
+
Our algorithm is based on [BS2007]_, Algorithm 2.2, but we deviate for
|
|
2956
|
+
several key steps. Firstly, the authors in the paper perform the search for
|
|
2957
|
+
a suitable `D` *incrementally*, by enlarging the table `S` by `log(N)`-size
|
|
2958
|
+
interval of primes `p` and testing all products of distinct primes `p` (or
|
|
2959
|
+
rather `p^*`). We find this difficult to implement without testing
|
|
2960
|
+
duplicate `D`\s, so we instead enlarge the table one prime at a time
|
|
2961
|
+
(effectively replacing `[r\log(N), (r + 1)\log(N)]` in the paper by `[r,
|
|
2962
|
+
r]`). To compensate for the speed loss, we begin the algorithm by
|
|
2963
|
+
prefilling `S` with the primes below `1000` (satisfying quadratic
|
|
2964
|
+
reciprocity properties). The constant `1000` is determined experimentally
|
|
2965
|
+
to be fast for many purposes, and for most `N` we tested we are able to
|
|
2966
|
+
find a suitable small `D` without increasing the size of `S`.
|
|
2967
|
+
|
|
2968
|
+
The paper also doesn't specify how to enumerate such `D`\s, which recall
|
|
2969
|
+
should be product of distinct values in the table `S`. We implement this
|
|
2970
|
+
with a priority queue (min heap), which also allows us to search for the
|
|
2971
|
+
suitable `D`\s in increasing (absolute value) order. This is suitable for
|
|
2972
|
+
the algorithm because smaller `D` means the Hilbert class polynomial is
|
|
2973
|
+
computed quicker.
|
|
2974
|
+
|
|
2975
|
+
Finally, to avoid repeatedly testing the same `D`\s, we require the latest
|
|
2976
|
+
prime to be added to the table to be included as a factor of `D` (see code
|
|
2977
|
+
for more explanation). As we need to find integers `x, y` such that `x^2 +
|
|
2978
|
+
(-D)y^2 = 4N` with `D < 0` and `N` prime, we actually need `|D| \leq 4N`,
|
|
2979
|
+
so we terminate the algorithm when the primes in the table are larger than
|
|
2980
|
+
that bound. This makes the iterator return all curves it can find in finite
|
|
2981
|
+
time.
|
|
2982
|
+
|
|
2983
|
+
ALGORITHM: Based on [BS2007]_, Algorithm 2.2
|
|
2984
|
+
|
|
2985
|
+
EXAMPLES::
|
|
2986
|
+
|
|
2987
|
+
sage: N = 8314040072427107567
|
|
2988
|
+
sage: E = next(EllipticCurve_with_prime_order(N))
|
|
2989
|
+
sage: E
|
|
2990
|
+
Elliptic Curve defined by y^2 = x^3 + 4757897140353078952*x + 1841350074072114366
|
|
2991
|
+
over Finite Field of size 8314040074357871443
|
|
2992
|
+
sage: E.has_order(N)
|
|
2993
|
+
True
|
|
2994
|
+
|
|
2995
|
+
The returned curves are sometimes random because
|
|
2996
|
+
:meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.twists`
|
|
2997
|
+
is not deterministic. However, it's always isomorphic::
|
|
2998
|
+
|
|
2999
|
+
sage: E = next(EllipticCurve_with_prime_order(23)); E # random
|
|
3000
|
+
Elliptic Curve defined by y^2 = x^3 + 12*x + 6 over Finite Field of size 17
|
|
3001
|
+
sage: E.is_isomorphic(EllipticCurve(GF(17), [3, 5]))
|
|
3002
|
+
True
|
|
3003
|
+
|
|
3004
|
+
You can directly iterate over the iterator; here only on the first 10
|
|
3005
|
+
curves::
|
|
3006
|
+
|
|
3007
|
+
sage: N = 54675917
|
|
3008
|
+
sage: for _, E in zip(range(10), EllipticCurve_with_prime_order(N)):
|
|
3009
|
+
....: assert E.has_order(N)
|
|
3010
|
+
|
|
3011
|
+
It works for large primes::
|
|
3012
|
+
|
|
3013
|
+
sage: N = 2666207849820848272386538889527600954292544013630953455833
|
|
3014
|
+
sage: E = next(EllipticCurve_with_prime_order(N)); E
|
|
3015
|
+
Elliptic Curve defined by y^2 = x^3 + 2666207849820848272386538889427721639173508298483739490459*x
|
|
3016
|
+
+ 77986137112576 over Finite Field of size 2666207849820848272386538889427721639173508298487130585243
|
|
3017
|
+
sage: E.has_order(N)
|
|
3018
|
+
True
|
|
3019
|
+
|
|
3020
|
+
Another example for large primes::
|
|
3021
|
+
|
|
3022
|
+
sage: N = next_prime(2^256)
|
|
3023
|
+
sage: E = next(EllipticCurve_with_prime_order(N)); E # random
|
|
3024
|
+
Elliptic Curve defined by y^2 = x^3 + 6056521267553273205988520276135607487700943205131813669424576873701361709521*x
|
|
3025
|
+
+ 86942739955486781674010637133214195706465136689012129911736706024465988573567 over Finite Field of size
|
|
3026
|
+
115792089237316195423570985008687907853847329310253429036565151476471048389761
|
|
3027
|
+
sage: E.j_invariant()
|
|
3028
|
+
111836223967433630316209796253554285080540088646141285337487360944738698436350
|
|
3029
|
+
sage: E.has_order(N)
|
|
3030
|
+
True
|
|
3031
|
+
|
|
3032
|
+
Note that the iterator does *not* return all curves with the given order::
|
|
3033
|
+
|
|
3034
|
+
sage: any(E.base_ring() is GF(7) for E in EllipticCurve_with_prime_order(7))
|
|
3035
|
+
False
|
|
3036
|
+
sage: EllipticCurve(GF(7), [0, 5]).order()
|
|
3037
|
+
7
|
|
3038
|
+
|
|
3039
|
+
However, experimentally it returns many of them. Here it returns all of
|
|
3040
|
+
them::
|
|
3041
|
+
|
|
3042
|
+
sage: N = 23
|
|
3043
|
+
sage: set_random_seed(1337) # as the function returns random twists of curves
|
|
3044
|
+
sage: curves = list(EllipticCurve_with_prime_order(N)); curves # random
|
|
3045
|
+
[Elliptic Curve defined by y^2 = x^3 + 3*x + 5 over Finite Field of size 17,
|
|
3046
|
+
Elliptic Curve defined by y^2 = x^3 + 19*x + 14 over Finite Field of size 31,
|
|
3047
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 9 over Finite Field of size 19,
|
|
3048
|
+
Elliptic Curve defined by y^2 = x^3 + 7*x + 18 over Finite Field of size 29,
|
|
3049
|
+
Elliptic Curve defined by y^2 = x^3 + 20*x + 20 over Finite Field of size 23,
|
|
3050
|
+
Elliptic Curve defined by y^2 = x^3 + 10*x + 16 over Finite Field of size 23]
|
|
3051
|
+
sage: import itertools
|
|
3052
|
+
sage: # These are the only primes, by the Hasse-Weil bound
|
|
3053
|
+
sage: for q in prime_range(17, 35):
|
|
3054
|
+
....: K = GF(q)
|
|
3055
|
+
....: for u in itertools.product(range(q), repeat=2):
|
|
3056
|
+
....: try: E = EllipticCurve(GF(q), u)
|
|
3057
|
+
....: except ArithmeticError: continue
|
|
3058
|
+
....: if E.has_order(N):
|
|
3059
|
+
....: assert any(E.is_isomorphic(E_) for E_ in curves)
|
|
3060
|
+
|
|
3061
|
+
The algorithm is efficient for small ``N`` due to the low number of suitable
|
|
3062
|
+
discriminants (see the ``abs_products_under`` internal function of the code
|
|
3063
|
+
for details)::
|
|
3064
|
+
|
|
3065
|
+
sage: len(list(EllipticCurve_with_prime_order(next_prime(5000))))
|
|
3066
|
+
534
|
|
3067
|
+
sage: len(list(EllipticCurve_with_prime_order(next_prime(50000)))) # long time (6s)
|
|
3068
|
+
3841
|
|
3069
|
+
|
|
3070
|
+
There is different verbose data for level `2` to `4`, though level `3`
|
|
3071
|
+
rarely logs anything (it logs when a new prime `p` is added to the
|
|
3072
|
+
smoothness bound)::
|
|
3073
|
+
|
|
3074
|
+
sage: from sage.misc.verbose import set_verbose
|
|
3075
|
+
sage: set_random_seed(1337) # as the function returns random twists of curves
|
|
3076
|
+
sage: for _, E in zip(range(3), EllipticCurve_with_prime_order(10^9 + 7)):
|
|
3077
|
+
....: print(E)
|
|
3078
|
+
Elliptic Curve defined by y^2 = x^3 + 265977778*x + 120868502 over Finite Field of size 1000041437
|
|
3079
|
+
Elliptic Curve defined by y^2 = x^3 + 689795416*x + 188156157 over Finite Field of size 999969307
|
|
3080
|
+
Elliptic Curve defined by y^2 = x^3 + 999178436*x + 900579394 over Finite Field of size 999969307
|
|
3081
|
+
sage: set_verbose(2)
|
|
3082
|
+
sage: set_random_seed(1337)
|
|
3083
|
+
sage: for _, E in zip(range(3), EllipticCurve_with_prime_order(10^9 + 7)):
|
|
3084
|
+
....: print(E)
|
|
3085
|
+
verbose 2 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Computing the Hilbert class polynomial H_-163
|
|
3086
|
+
Elliptic Curve defined by y^2 = x^3 + 265977778*x + 120868502 over Finite Field of size 1000041437
|
|
3087
|
+
verbose 2 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Computing the Hilbert class polynomial H_-667
|
|
3088
|
+
Elliptic Curve defined by y^2 = x^3 + 689795416*x + 188156157 over Finite Field of size 999969307
|
|
3089
|
+
Elliptic Curve defined by y^2 = x^3 + 999178436*x + 900579394 over Finite Field of size 999969307
|
|
3090
|
+
sage: set_verbose(4)
|
|
3091
|
+
sage: set_random_seed(1337)
|
|
3092
|
+
sage: for _, E in zip(range(3), EllipticCurve_with_prime_order(10^9 + 7)):
|
|
3093
|
+
....: print(E)
|
|
3094
|
+
verbose 4 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Testing D=-19
|
|
3095
|
+
...
|
|
3096
|
+
verbose 4 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Testing D=-163
|
|
3097
|
+
verbose 2 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Computing the Hilbert class polynomial H_-163
|
|
3098
|
+
Elliptic Curve defined by y^2 = x^3 + 265977778*x + 120868502 over Finite Field of size 1000041437
|
|
3099
|
+
verbose 4 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Testing D=-179
|
|
3100
|
+
...
|
|
3101
|
+
verbose 4 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Testing D=-667
|
|
3102
|
+
verbose 2 (...: ell_finite_field.py, EllipticCurve_with_prime_order) Computing the Hilbert class polynomial H_-667
|
|
3103
|
+
Elliptic Curve defined by y^2 = x^3 + 689795416*x + 188156157 over Finite Field of size 999969307
|
|
3104
|
+
Elliptic Curve defined by y^2 = x^3 + 999178436*x + 900579394 over Finite Field of size 999969307
|
|
3105
|
+
|
|
3106
|
+
TESTS::
|
|
3107
|
+
|
|
3108
|
+
sage: list(EllipticCurve_with_prime_order(2))
|
|
3109
|
+
[Elliptic Curve defined by y^2 + x*y + y = x^3 + 1 over Finite Field of size 2,
|
|
3110
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x^2 + 2 over Finite Field of size 3,
|
|
3111
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 5]
|
|
3112
|
+
|
|
3113
|
+
sage: set_verbose(0)
|
|
3114
|
+
sage: for N in prime_range(3, 100):
|
|
3115
|
+
....: E = next(EllipticCurve_with_prime_order(N))
|
|
3116
|
+
....: assert E.has_order(N)
|
|
3117
|
+
|
|
3118
|
+
sage: N = 113
|
|
3119
|
+
sage: for _, E in zip(range(30), EllipticCurve_with_prime_order(N)):
|
|
3120
|
+
....: assert E.has_order(N)
|
|
3121
|
+
|
|
3122
|
+
sage: N = 15175980689839334471
|
|
3123
|
+
sage: E = next(EllipticCurve_with_prime_order(N))
|
|
3124
|
+
sage: E.has_order(N)
|
|
3125
|
+
True
|
|
3126
|
+
|
|
3127
|
+
sage: N = next_prime(123456789)
|
|
3128
|
+
sage: E = next(EllipticCurve_with_prime_order(N))
|
|
3129
|
+
sage: E.has_order(N)
|
|
3130
|
+
True
|
|
3131
|
+
|
|
3132
|
+
sage: N = 123456789
|
|
3133
|
+
sage: E = next(EllipticCurve_with_prime_order(N))
|
|
3134
|
+
Traceback (most recent call last):
|
|
3135
|
+
...
|
|
3136
|
+
ValueError: input order is not a prime
|
|
3137
|
+
|
|
3138
|
+
sage: E = next(EllipticCurve_with_prime_order(0))
|
|
3139
|
+
Traceback (most recent call last):
|
|
3140
|
+
...
|
|
3141
|
+
ValueError: input order is not a prime
|
|
3142
|
+
|
|
3143
|
+
sage: E = next(EllipticCurve_with_prime_order(-7))
|
|
3144
|
+
Traceback (most recent call last):
|
|
3145
|
+
...
|
|
3146
|
+
ValueError: input order is not a prime
|
|
3147
|
+
|
|
3148
|
+
AUTHORS:
|
|
3149
|
+
|
|
3150
|
+
- Martin Grenouilloux, Gareth Ma (2024-09): initial implementation
|
|
3151
|
+
"""
|
|
3152
|
+
import itertools
|
|
3153
|
+
from sage.arith.misc import is_prime, legendre_symbol
|
|
3154
|
+
from sage.misc.verbose import verbose
|
|
3155
|
+
from sage.quadratic_forms.binary_qf import BinaryQF
|
|
3156
|
+
from sage.rings.fast_arith import prime_range
|
|
3157
|
+
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
|
|
3158
|
+
from sage.sets.primes import Primes
|
|
3159
|
+
|
|
3160
|
+
if not is_prime(N):
|
|
3161
|
+
raise ValueError("input order is not a prime")
|
|
3162
|
+
|
|
3163
|
+
if N == 2:
|
|
3164
|
+
yield from [
|
|
3165
|
+
EllipticCurve(GF(2), [1, 0, 1, 0, 1]),
|
|
3166
|
+
EllipticCurve(GF(3), [0, 2, 0, 0, 2]),
|
|
3167
|
+
EllipticCurve(GF(5), [2, 0])
|
|
3168
|
+
]
|
|
3169
|
+
return
|
|
3170
|
+
|
|
3171
|
+
# We start with small primes directly to accelerate the search. Note that
|
|
3172
|
+
# 1000 is a magic constant, it's just fast enough to compute without
|
|
3173
|
+
# sacrificing much speed.
|
|
3174
|
+
# The if-then-else term is (-1)^((p - 1) / 2) * p in [BS2007]_ page 5.
|
|
3175
|
+
S = [(-p if p % 4 == 3 else p) for p in prime_range(3, min(1000, 4 * N))
|
|
3176
|
+
if legendre_symbol(N, p) == 1]
|
|
3177
|
+
|
|
3178
|
+
def abs_products_under(bound):
|
|
3179
|
+
"""
|
|
3180
|
+
This function returns an iterator of all numbers with absolute
|
|
3181
|
+
value not exceeding ``bound`` expressible as product of
|
|
3182
|
+
distinct elements in ``S`` in ascending order.
|
|
3183
|
+
"""
|
|
3184
|
+
import heapq
|
|
3185
|
+
hq = [(1, 1, -1)]
|
|
3186
|
+
while hq:
|
|
3187
|
+
abs_n, n, idx = heapq.heappop(hq)
|
|
3188
|
+
yield n
|
|
3189
|
+
for nxt in range(idx + 1, len(S)):
|
|
3190
|
+
if abs_n * abs(S[nxt]) <= bound:
|
|
3191
|
+
heapq.heappush(hq, (abs_n * abs(S[nxt]), n * S[nxt], nxt))
|
|
3192
|
+
else:
|
|
3193
|
+
break
|
|
3194
|
+
|
|
3195
|
+
# We add p = 1 to process the small primes.
|
|
3196
|
+
for p in itertools.chain([1], Primes()):
|
|
3197
|
+
if p != 1:
|
|
3198
|
+
if p < abs(S[-1]):
|
|
3199
|
+
continue
|
|
3200
|
+
|
|
3201
|
+
if legendre_symbol(N, p) != 1:
|
|
3202
|
+
continue
|
|
3203
|
+
|
|
3204
|
+
# Later we need x^2 + (-D)y^2 = 4N, and since y = 0 has no
|
|
3205
|
+
# solution, we need p = |p_star| <= |-D| <= 4N. This is a stopping
|
|
3206
|
+
# condition for the algorithm.
|
|
3207
|
+
if p > 4 * N:
|
|
3208
|
+
break
|
|
3209
|
+
|
|
3210
|
+
verbose(f"Considering {len(S) + 1}th valid prime {p}", level=3)
|
|
3211
|
+
|
|
3212
|
+
p_star = -p if p % 4 == 3 else p
|
|
3213
|
+
|
|
3214
|
+
for e in abs_products_under(4 * N // p):
|
|
3215
|
+
# According to the paper, the expected minimum D to work is
|
|
3216
|
+
# O(log(N)^2)
|
|
3217
|
+
D = p_star * e
|
|
3218
|
+
assert abs(D) <= 4 * N
|
|
3219
|
+
|
|
3220
|
+
if D % 8 != 5 or D >= 0:
|
|
3221
|
+
continue
|
|
3222
|
+
|
|
3223
|
+
verbose(f"Testing {D=}", level=4)
|
|
3224
|
+
|
|
3225
|
+
Q = BinaryQF([1, 0, -D])
|
|
3226
|
+
sol = Q.solve_integer(4 * N, algorithm='cornacchia')
|
|
3227
|
+
if sol is None:
|
|
3228
|
+
continue
|
|
3229
|
+
|
|
3230
|
+
x, _ = sol
|
|
3231
|
+
for p_i in [N + 1 - x, N + 1 + x]:
|
|
3232
|
+
if is_prime(p_i):
|
|
3233
|
+
verbose(f"Computing the Hilbert class polynomial H_{D}",
|
|
3234
|
+
level=2)
|
|
3235
|
+
H = hilbert_class_polynomial(D)
|
|
3236
|
+
K = GF(p_i)
|
|
3237
|
+
for j0 in H.roots(ring=K, multiplicities=False):
|
|
3238
|
+
E = EllipticCurve(K, j=j0)
|
|
3239
|
+
# `E.twists()` also contains E.
|
|
3240
|
+
for Et in E.twists():
|
|
3241
|
+
# `num_checks=1` is sufficient for prime order
|
|
3242
|
+
if Et.has_order(N, num_checks=1):
|
|
3243
|
+
# TODO: remove after 38617
|
|
3244
|
+
Et.set_order(N, check=False)
|
|
3245
|
+
yield Et
|
|
3246
|
+
|
|
3247
|
+
if p != 1:
|
|
3248
|
+
# Extending our prime list and continuing onto the next round.
|
|
3249
|
+
S.append(p_star)
|