passagemath-schemes 10.6.38__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.

Potentially problematic release.


This version of passagemath-schemes might be problematic. Click here for more details.

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