passagemath-schemes 10.6.40__cp314-cp314-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.
- passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,4787 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Points on elliptic curves
|
|
4
|
+
|
|
5
|
+
The base class :class:`EllipticCurvePoint` provides support for
|
|
6
|
+
points on elliptic curves defined over general rings, including
|
|
7
|
+
generic addition formulas.
|
|
8
|
+
|
|
9
|
+
The derived classes :class:`EllipticCurvePoint_field` and its
|
|
10
|
+
child classes :class:`EllipticCurvePoint_number_field` and
|
|
11
|
+
:class:`EllipticCurvePoint_finite_field` provide further support
|
|
12
|
+
for points on curves defined over arbitrary fields, as well as
|
|
13
|
+
specialized functionality for points on curves over number fields
|
|
14
|
+
(including the rational field `\QQ`) and finite fields.
|
|
15
|
+
|
|
16
|
+
EXAMPLES:
|
|
17
|
+
|
|
18
|
+
An example over `\QQ`::
|
|
19
|
+
|
|
20
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
21
|
+
sage: E = EllipticCurve('389a1')
|
|
22
|
+
sage: P = E(-1,1); P
|
|
23
|
+
(-1 : 1 : 1)
|
|
24
|
+
sage: Q = E(0,-1); Q
|
|
25
|
+
(0 : -1 : 1)
|
|
26
|
+
sage: P+Q
|
|
27
|
+
(4 : 8 : 1)
|
|
28
|
+
sage: P-Q
|
|
29
|
+
(1 : 0 : 1)
|
|
30
|
+
sage: 3*P-5*Q
|
|
31
|
+
(328/361 : -2800/6859 : 1)
|
|
32
|
+
|
|
33
|
+
An example over a number field::
|
|
34
|
+
|
|
35
|
+
sage: # needs sage.rings.number_field
|
|
36
|
+
sage: K.<i> = QuadraticField(-1)
|
|
37
|
+
sage: E = EllipticCurve(K, [1,0,0,0,-1])
|
|
38
|
+
sage: P = E(0,i); P
|
|
39
|
+
(0 : i : 1)
|
|
40
|
+
sage: P.order()
|
|
41
|
+
+Infinity
|
|
42
|
+
sage: 101*P - 100*P == P
|
|
43
|
+
True
|
|
44
|
+
|
|
45
|
+
An example over a finite field::
|
|
46
|
+
|
|
47
|
+
sage: # needs sage.rings.finite_rings
|
|
48
|
+
sage: K.<a> = GF((101,3))
|
|
49
|
+
sage: E = EllipticCurve(K, [1,0,0,0,-1])
|
|
50
|
+
sage: P = E(40*a^2 + 69*a + 84 , 58*a^2 + 73*a + 45)
|
|
51
|
+
sage: P.order()
|
|
52
|
+
1032210
|
|
53
|
+
sage: E.cardinality()
|
|
54
|
+
1032210
|
|
55
|
+
|
|
56
|
+
Arithmetic with a point over an extension of a finite field::
|
|
57
|
+
|
|
58
|
+
sage: # needs sage.rings.finite_rings
|
|
59
|
+
sage: k.<a> = GF((5,2))
|
|
60
|
+
sage: E = EllipticCurve(k,[1,0]); E
|
|
61
|
+
Elliptic Curve defined by y^2 = x^3 + x over Finite Field in a of size 5^2
|
|
62
|
+
sage: P = E([a,2*a+4])
|
|
63
|
+
sage: 5*P
|
|
64
|
+
(2*a + 3 : 2*a : 1)
|
|
65
|
+
sage: P*5
|
|
66
|
+
(2*a + 3 : 2*a : 1)
|
|
67
|
+
sage: P + P + P + P + P
|
|
68
|
+
(2*a + 3 : 2*a : 1)
|
|
69
|
+
|
|
70
|
+
::
|
|
71
|
+
|
|
72
|
+
sage: F = Zmod(3)
|
|
73
|
+
sage: E = EllipticCurve(F, [1,0]);
|
|
74
|
+
sage: P = E([2,1])
|
|
75
|
+
sage: import sys
|
|
76
|
+
sage: n = sys.maxsize
|
|
77
|
+
sage: P*(n+1)-P*n == P
|
|
78
|
+
True
|
|
79
|
+
|
|
80
|
+
Arithmetic over `\Zmod{N}` with composite `N` is supported::
|
|
81
|
+
|
|
82
|
+
sage: N = 1715761513
|
|
83
|
+
sage: E = EllipticCurve(Integers(N), [3,-13])
|
|
84
|
+
sage: P = E(2,1)
|
|
85
|
+
sage: LCM([2..60])*P
|
|
86
|
+
(1643112467 : 9446995 : 26927)
|
|
87
|
+
|
|
88
|
+
However, some algorithms (e.g., toy examples of ECM) involve performing
|
|
89
|
+
elliptic-curve operations as if the base ring were a field even when it
|
|
90
|
+
is not, and exploit the failures when attempting to invert a non-unit.
|
|
91
|
+
Sage provides a *hack* to support such educational examples via the
|
|
92
|
+
:meth:`EllipticCurve_generic.assume_base_ring_is_field` method.
|
|
93
|
+
Example::
|
|
94
|
+
|
|
95
|
+
sage: E.assume_base_ring_is_field()
|
|
96
|
+
sage: P = E(2,1)
|
|
97
|
+
sage: LCM([2..60])*P
|
|
98
|
+
Traceback (most recent call last):
|
|
99
|
+
...
|
|
100
|
+
ZeroDivisionError: Inverse of 26927 does not exist
|
|
101
|
+
(characteristic = 1715761513 = 26927*63719)
|
|
102
|
+
|
|
103
|
+
AUTHORS:
|
|
104
|
+
|
|
105
|
+
- William Stein (2005) -- Initial version
|
|
106
|
+
|
|
107
|
+
- Robert Bradshaw et al....
|
|
108
|
+
|
|
109
|
+
- John Cremona (Feb 2008) -- Point counting and group structure for
|
|
110
|
+
non-prime fields, Frobenius endomorphism and order, elliptic logs
|
|
111
|
+
|
|
112
|
+
- John Cremona (Aug 2008) -- Introduced ``EllipticCurvePoint_number_field`` class
|
|
113
|
+
|
|
114
|
+
- Tobias Nagel, Michael Mardaus, John Cremona (Dec 2008) -- `p`-adic elliptic logarithm over `\QQ`
|
|
115
|
+
|
|
116
|
+
- David Hansen (Jan 2009) -- Added ``weil_pairing`` function to ``EllipticCurvePoint_finite_field`` class
|
|
117
|
+
|
|
118
|
+
- Mariah Lenox (March 2011) -- Added ``tate_pairing`` and ``ate_pairing``
|
|
119
|
+
functions to ``EllipticCurvePoint_finite_field`` class
|
|
120
|
+
|
|
121
|
+
- Lorenz Panny (2022): point addition over general rings
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
# ****************************************************************************
|
|
125
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
126
|
+
#
|
|
127
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
128
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
129
|
+
# the License, or (at your option) any later version.
|
|
130
|
+
# https://www.gnu.org/licenses/
|
|
131
|
+
# ****************************************************************************
|
|
132
|
+
|
|
133
|
+
import math
|
|
134
|
+
|
|
135
|
+
import sage.groups.generic as generic
|
|
136
|
+
import sage.rings.abc
|
|
137
|
+
|
|
138
|
+
from sage.misc.lazy_import import lazy_import
|
|
139
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
140
|
+
from sage.rings.infinity import Infinity as oo
|
|
141
|
+
from sage.rings.integer import Integer
|
|
142
|
+
from sage.rings.integer_ring import ZZ
|
|
143
|
+
from sage.rings.padics.precision_error import PrecisionError
|
|
144
|
+
from sage.rings.rational_field import QQ
|
|
145
|
+
from sage.rings.real_mpfr import RealField, RR
|
|
146
|
+
from sage.rings.quotient_ring import QuotientRing_generic
|
|
147
|
+
|
|
148
|
+
from sage.structure.element import AdditiveGroupElement
|
|
149
|
+
from sage.structure.sequence import Sequence
|
|
150
|
+
from sage.structure.richcmp import richcmp
|
|
151
|
+
|
|
152
|
+
from sage.structure.coerce_actions import IntegerMulAction
|
|
153
|
+
|
|
154
|
+
from sage.schemes.curves.projective_curve import Hasse_bounds
|
|
155
|
+
from sage.schemes.elliptic_curves.constructor import EllipticCurve
|
|
156
|
+
from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring,
|
|
157
|
+
SchemeMorphism_point_abelian_variety_field)
|
|
158
|
+
|
|
159
|
+
lazy_import('sage.rings.padics.factory', 'Qp')
|
|
160
|
+
lazy_import('sage.schemes.generic.morphism', 'SchemeMorphism')
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
from sage.libs.pari import pari
|
|
164
|
+
from cypari2.handle_error import PariError
|
|
165
|
+
except ImportError:
|
|
166
|
+
PariError = ()
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class EllipticCurvePoint(AdditiveGroupElement,
|
|
170
|
+
SchemeMorphism_point_projective_ring):
|
|
171
|
+
"""
|
|
172
|
+
A point on an elliptic curve.
|
|
173
|
+
"""
|
|
174
|
+
def __init__(self, *args, **kwds):
|
|
175
|
+
r"""
|
|
176
|
+
Initialize this elliptic-curve point.
|
|
177
|
+
|
|
178
|
+
EXAMPLES::
|
|
179
|
+
|
|
180
|
+
sage: E = EllipticCurve(Zmod(77), [1,1,1,1,1])
|
|
181
|
+
sage: E(0)
|
|
182
|
+
(0 : 1 : 0)
|
|
183
|
+
sage: E(3, 9)
|
|
184
|
+
(3 : 9 : 1)
|
|
185
|
+
sage: E(6, 18, 2)
|
|
186
|
+
(3 : 9 : 1)
|
|
187
|
+
sage: E(66, 23, 22)
|
|
188
|
+
(33 : 50 : 11)
|
|
189
|
+
"""
|
|
190
|
+
super().__init__(*args, **kwds)
|
|
191
|
+
try:
|
|
192
|
+
self.normalize_coordinates()
|
|
193
|
+
except NotImplementedError:
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
def curve(self):
|
|
197
|
+
"""
|
|
198
|
+
Return the curve that this point is on.
|
|
199
|
+
|
|
200
|
+
This is a synonym for :meth:`scheme`.
|
|
201
|
+
|
|
202
|
+
EXAMPLES::
|
|
203
|
+
|
|
204
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
205
|
+
sage: E = EllipticCurve('389a')
|
|
206
|
+
sage: P = E([-1, 1])
|
|
207
|
+
sage: P.curve()
|
|
208
|
+
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
|
|
209
|
+
|
|
210
|
+
sage: E = EllipticCurve(QQ, [1, 1])
|
|
211
|
+
sage: P = E(0, 1)
|
|
212
|
+
sage: P.scheme()
|
|
213
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field
|
|
214
|
+
sage: P.scheme() == P.curve()
|
|
215
|
+
True
|
|
216
|
+
sage: x = polygen(ZZ, 'x')
|
|
217
|
+
sage: K.<a> = NumberField(x^2 - 3,'a') # needs sage.rings.number_field
|
|
218
|
+
sage: P = E.base_extend(K)(1, a) # needs sage.rings.number_field
|
|
219
|
+
sage: P.scheme() # needs sage.rings.number_field
|
|
220
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1 over
|
|
221
|
+
Number Field in a with defining polynomial x^2 - 3
|
|
222
|
+
"""
|
|
223
|
+
return self.scheme()
|
|
224
|
+
|
|
225
|
+
def _add_(self, other):
|
|
226
|
+
r"""
|
|
227
|
+
Add this point to another point on the same elliptic curve.
|
|
228
|
+
|
|
229
|
+
This method computes point additions for fairly general rings.
|
|
230
|
+
|
|
231
|
+
ALGORITHM:
|
|
232
|
+
|
|
233
|
+
Over quotient rings of Euclidean domains modulo principal ideals:
|
|
234
|
+
The standard formulas for fields, extended to non-fields via the
|
|
235
|
+
Chinese remainder theorem.
|
|
236
|
+
|
|
237
|
+
In more general rings: Formulas due to Bosma and Lenstra [BL1995]_
|
|
238
|
+
with corrections by Best [Best2021]_ (Appendix A).
|
|
239
|
+
See :mod:`sage.schemes.elliptic_curves.addition_formulas_ring`.
|
|
240
|
+
|
|
241
|
+
EXAMPLES::
|
|
242
|
+
|
|
243
|
+
sage: N = 1113121
|
|
244
|
+
sage: E = EllipticCurve(Zmod(N), [1,0])
|
|
245
|
+
sage: R1 = E(301098, 673883, 644675)
|
|
246
|
+
sage: R2 = E(411415, 758555, 255837)
|
|
247
|
+
sage: R3 = E(983009, 342673, 207687)
|
|
248
|
+
sage: R1 + R2 == R3
|
|
249
|
+
True
|
|
250
|
+
|
|
251
|
+
TESTS:
|
|
252
|
+
|
|
253
|
+
We check on random examples that the results are compatible modulo
|
|
254
|
+
all divisors of the characteristic. (In particular, this includes
|
|
255
|
+
prime divisors, for which the result is computed using the "old",
|
|
256
|
+
much simpler formulas for fields.) ::
|
|
257
|
+
|
|
258
|
+
sage: N = ZZ(randrange(2, 10**5))
|
|
259
|
+
sage: E = None
|
|
260
|
+
sage: while True:
|
|
261
|
+
....: try:
|
|
262
|
+
....: E = EllipticCurve(list((Zmod(N)^5).random_element()))
|
|
263
|
+
....: except ArithmeticError:
|
|
264
|
+
....: pass
|
|
265
|
+
....: else:
|
|
266
|
+
....: if E.discriminant().is_unit():
|
|
267
|
+
....: break
|
|
268
|
+
sage: pts = []
|
|
269
|
+
sage: X = polygen(Zmod(N^2))
|
|
270
|
+
sage: while len(pts) < 2:
|
|
271
|
+
....: y, z = (Zmod(N)^2).random_element()
|
|
272
|
+
....: f = E.defining_polynomial()(X, y, z)
|
|
273
|
+
....: xs = f.roots(multiplicities=False)
|
|
274
|
+
....: xs = [x for x in xs if 1 in Zmod(N).ideal([x,y,z])]
|
|
275
|
+
....: if xs:
|
|
276
|
+
....: pts.append(E(choice(xs), y, z))
|
|
277
|
+
sage: P, Q = pts
|
|
278
|
+
sage: R = P + Q # not tested (:issue:`39191`)
|
|
279
|
+
sage: for d in N.divisors(): # not tested (:issue:`39191`)
|
|
280
|
+
....: if d > 1:
|
|
281
|
+
....: assert R.change_ring(Zmod(d)) == P.change_ring(Zmod(d)) + Q.change_ring(Zmod(d))
|
|
282
|
+
"""
|
|
283
|
+
if self.is_zero():
|
|
284
|
+
return other
|
|
285
|
+
if other.is_zero():
|
|
286
|
+
return self
|
|
287
|
+
|
|
288
|
+
E = self.curve()
|
|
289
|
+
R = E.base_ring()
|
|
290
|
+
|
|
291
|
+
# We handle Euclidean domains modulo principal ideals separately.
|
|
292
|
+
# Important special cases of this include quotient rings of the
|
|
293
|
+
# integers as well as of univariate polynomial rings over fields.
|
|
294
|
+
if isinstance(R, QuotientRing_generic):
|
|
295
|
+
from sage.categories.euclidean_domains import EuclideanDomains
|
|
296
|
+
if R.cover_ring() in EuclideanDomains():
|
|
297
|
+
I = R.defining_ideal()
|
|
298
|
+
if I.ngens() == 1:
|
|
299
|
+
mod, = I.gens()
|
|
300
|
+
|
|
301
|
+
a1, a2, a3, a4, a6 = E.ainvs()
|
|
302
|
+
x1, y1, z1 = map(R, self)
|
|
303
|
+
x2, y2, z2 = map(R, other)
|
|
304
|
+
|
|
305
|
+
mod_1st = mod.gcd(z2.lift())
|
|
306
|
+
mod //= mod_1st
|
|
307
|
+
mod_2nd = mod.gcd(z1.lift())
|
|
308
|
+
mod //= mod_2nd
|
|
309
|
+
|
|
310
|
+
xz, zx = x1*z2, x2*z1
|
|
311
|
+
yz, zy = y1*z2, y2*z1
|
|
312
|
+
zz = z1*z2
|
|
313
|
+
|
|
314
|
+
# addition
|
|
315
|
+
num_add = yz - zy
|
|
316
|
+
den_add = xz - zx
|
|
317
|
+
mod_dbl = mod.gcd(num_add.lift()).gcd(den_add.lift())
|
|
318
|
+
mod_add = mod // mod_dbl
|
|
319
|
+
|
|
320
|
+
# doubling
|
|
321
|
+
if not mod_dbl.is_one():
|
|
322
|
+
num_dbl = (3*x1 + 2*a2*z1) * x1 + (a4*z1 - a1*y1) * z1
|
|
323
|
+
den_dbl = (2*y1 + a1*x1 + a3*z1) * z1
|
|
324
|
+
else:
|
|
325
|
+
num_dbl = den_dbl = 0
|
|
326
|
+
|
|
327
|
+
if mod_dbl.gcd(mod_add).is_one():
|
|
328
|
+
from sage.arith.misc import CRT_vectors
|
|
329
|
+
if mod_dbl.is_one():
|
|
330
|
+
num, den = num_add, den_add
|
|
331
|
+
elif mod_add.is_one():
|
|
332
|
+
num, den = num_dbl, den_dbl
|
|
333
|
+
else:
|
|
334
|
+
num, den = CRT_vectors([(num_add, den_add), (num_dbl, den_dbl)], [mod_add, mod_dbl])
|
|
335
|
+
|
|
336
|
+
den2 = den**2
|
|
337
|
+
x3 = ((num + a1*den)*zz*num - (xz + zx + a2*zz)*den2) * den
|
|
338
|
+
y3 = ((2*xz + zx + (a2 - a1**2)*zz)*num + (a1*(xz + zx + a2*zz) - a3*zz - yz)*den) * den2 - (num + 2*a1*den)*zz*num**2
|
|
339
|
+
z3 = zz * den * den2
|
|
340
|
+
|
|
341
|
+
pt = x3.lift(), y3.lift(), z3.lift()
|
|
342
|
+
if not mod_1st.is_one():
|
|
343
|
+
pt = CRT_vectors([pt, [x1.lift(), y1.lift(), z1.lift()]], [mod, mod_1st])
|
|
344
|
+
mod = mod.lcm(mod_1st)
|
|
345
|
+
if not mod_2nd.is_one():
|
|
346
|
+
pt = CRT_vectors([pt, [x2.lift(), y2.lift(), z2.lift()]], [mod, mod_2nd])
|
|
347
|
+
|
|
348
|
+
return E.point(Sequence(pt, E.base_ring()), check=False)
|
|
349
|
+
|
|
350
|
+
from sage.schemes.elliptic_curves.addition_formulas_ring import _add
|
|
351
|
+
from sage.modules.free_module_element import vector
|
|
352
|
+
|
|
353
|
+
pts = []
|
|
354
|
+
for pt in filter(any, _add(E, self, other)):
|
|
355
|
+
if R.one() in R.ideal(pt):
|
|
356
|
+
return E.point(pt)
|
|
357
|
+
pts.append(pt)
|
|
358
|
+
assert len(pts) == 2, 'bug in elliptic-curve point addition'
|
|
359
|
+
|
|
360
|
+
#TODO: If the base ring has trivial Picard group, it is known
|
|
361
|
+
# that some linear combination of the two vectors is a valid
|
|
362
|
+
# projective point (whose coordinates generate the unit ideal).
|
|
363
|
+
# Below, we simply try random linear combinations until we
|
|
364
|
+
# find a good choice. Is there a general method that doesn't
|
|
365
|
+
# involve guessing?
|
|
366
|
+
|
|
367
|
+
pts = [vector(R, pt) for pt in pts]
|
|
368
|
+
for _ in range(1000):
|
|
369
|
+
result = tuple(sum(R.random_element() * pt for pt in pts))
|
|
370
|
+
if R.one() in R.ideal(result):
|
|
371
|
+
return E.point(result, check=False)
|
|
372
|
+
|
|
373
|
+
assert False, 'bug: failed to compute elliptic-curve point addition'
|
|
374
|
+
|
|
375
|
+
def _neg_(self):
|
|
376
|
+
"""
|
|
377
|
+
Return the negative of this elliptic-curve point, over a general ring.
|
|
378
|
+
|
|
379
|
+
EXAMPLES::
|
|
380
|
+
|
|
381
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
382
|
+
sage: E = EllipticCurve('389a')
|
|
383
|
+
sage: P = E([-1,1])
|
|
384
|
+
sage: Q = -P; Q
|
|
385
|
+
(-1 : -2 : 1)
|
|
386
|
+
sage: Q + P
|
|
387
|
+
(0 : 1 : 0)
|
|
388
|
+
|
|
389
|
+
::
|
|
390
|
+
|
|
391
|
+
sage: N = 1113121
|
|
392
|
+
sage: E = EllipticCurve(Zmod(N), [1,0])
|
|
393
|
+
sage: R = E(301098, 673883, 644675)
|
|
394
|
+
sage: -R
|
|
395
|
+
(136211 : 914033 : 107)
|
|
396
|
+
sage: ((-R) + R) == 0
|
|
397
|
+
True
|
|
398
|
+
"""
|
|
399
|
+
if self.is_zero():
|
|
400
|
+
return self
|
|
401
|
+
E = self.curve()
|
|
402
|
+
a1, _, a3, _, _ = E.a_invariants()
|
|
403
|
+
x, y, z = self
|
|
404
|
+
return E.point([x, -y - a1*x - a3*z, z], check=False)
|
|
405
|
+
|
|
406
|
+
def _sub_(self, other):
|
|
407
|
+
"""
|
|
408
|
+
Subtract ``other`` from ``self``.
|
|
409
|
+
|
|
410
|
+
ALGORITHM: :meth:`_add_` and :meth:`_neg_`.
|
|
411
|
+
|
|
412
|
+
EXAMPLES::
|
|
413
|
+
|
|
414
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
415
|
+
sage: E = EllipticCurve('389a')
|
|
416
|
+
sage: P = E([-1,1]); Q = E([0,0])
|
|
417
|
+
sage: P - Q
|
|
418
|
+
(4 : 8 : 1)
|
|
419
|
+
sage: P - Q == P._sub_(Q)
|
|
420
|
+
True
|
|
421
|
+
sage: (P - Q) + Q
|
|
422
|
+
(-1 : 1 : 1)
|
|
423
|
+
sage: P
|
|
424
|
+
(-1 : 1 : 1)
|
|
425
|
+
|
|
426
|
+
::
|
|
427
|
+
|
|
428
|
+
sage: N = 1113121
|
|
429
|
+
sage: E = EllipticCurve(Zmod(N), [1,0])
|
|
430
|
+
sage: R1 = E(301098, 673883, 644675)
|
|
431
|
+
sage: R2 = E(411415, 758555, 255837)
|
|
432
|
+
sage: R3 = E(983009, 342673, 207687)
|
|
433
|
+
sage: R1 == R3 - R2
|
|
434
|
+
True
|
|
435
|
+
"""
|
|
436
|
+
return self + (-other)
|
|
437
|
+
|
|
438
|
+
def _acted_upon_(self, other, side):
|
|
439
|
+
r"""
|
|
440
|
+
We implement ``_acted_upon_`` to provide scalar multiplications.
|
|
441
|
+
|
|
442
|
+
EXAMPLES::
|
|
443
|
+
|
|
444
|
+
sage: # needs sage.rings.finite_rings
|
|
445
|
+
sage: N = 1113121
|
|
446
|
+
sage: E = EllipticCurve(Zmod(N), [1,0])
|
|
447
|
+
sage: R = E(301098, 673883, 644675)
|
|
448
|
+
sage: 123*R
|
|
449
|
+
(703739 : 464106 : 107)
|
|
450
|
+
sage: 70200*R
|
|
451
|
+
(0 : 1 : 0)
|
|
452
|
+
"""
|
|
453
|
+
return IntegerMulAction(ZZ, self.parent())._act_(other, self)
|
|
454
|
+
|
|
455
|
+
def __bool__(self):
|
|
456
|
+
r"""
|
|
457
|
+
Test whether this elliptic-curve point equals the neutral
|
|
458
|
+
element of the group (i.e., the point at infinity).
|
|
459
|
+
|
|
460
|
+
EXAMPLES::
|
|
461
|
+
|
|
462
|
+
sage: E = EllipticCurve(GF(7), [1,1])
|
|
463
|
+
sage: bool(E(0))
|
|
464
|
+
False
|
|
465
|
+
sage: bool(E.lift_x(2))
|
|
466
|
+
True
|
|
467
|
+
|
|
468
|
+
sage:
|
|
469
|
+
|
|
470
|
+
sage: E = EllipticCurve(Zmod(77), [1,1,1,1,1])
|
|
471
|
+
sage: bool(E(0))
|
|
472
|
+
False
|
|
473
|
+
sage: P = E(66, 23, 22); P
|
|
474
|
+
(33 : 50 : 11)
|
|
475
|
+
sage: bool(P)
|
|
476
|
+
True
|
|
477
|
+
"""
|
|
478
|
+
return bool(self[2])
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
class EllipticCurvePoint_field(EllipticCurvePoint,
|
|
482
|
+
SchemeMorphism_point_abelian_variety_field):
|
|
483
|
+
"""
|
|
484
|
+
A point on an elliptic curve over a field. The point has coordinates
|
|
485
|
+
in the base field.
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
490
|
+
sage: E = EllipticCurve('37a')
|
|
491
|
+
sage: E([0,0])
|
|
492
|
+
(0 : 0 : 1)
|
|
493
|
+
sage: E(0,0) # brackets are optional
|
|
494
|
+
(0 : 0 : 1)
|
|
495
|
+
sage: E([GF(5)(0), 0]) # entries are coerced
|
|
496
|
+
(0 : 0 : 1)
|
|
497
|
+
sage: E(0.000, 0)
|
|
498
|
+
(0 : 0 : 1)
|
|
499
|
+
sage: E(1,0,0)
|
|
500
|
+
Traceback (most recent call last):
|
|
501
|
+
...
|
|
502
|
+
TypeError: Coordinates [1, 0, 0] do not define a point on
|
|
503
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
504
|
+
|
|
505
|
+
::
|
|
506
|
+
|
|
507
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
508
|
+
sage: S = E(QQ); S
|
|
509
|
+
Abelian group of points on
|
|
510
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
511
|
+
|
|
512
|
+
sage: # needs sage.rings.number_field
|
|
513
|
+
sage: x = polygen(ZZ, 'x')
|
|
514
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
515
|
+
sage: E = EllipticCurve(K, [0,1,0,-160,308])
|
|
516
|
+
sage: P = E(26, -120)
|
|
517
|
+
sage: Q = E(2+12*i, -36+48*i)
|
|
518
|
+
sage: P.order() == Q.order() == 4 # long time
|
|
519
|
+
True
|
|
520
|
+
sage: 2*P == 2*Q
|
|
521
|
+
False
|
|
522
|
+
|
|
523
|
+
::
|
|
524
|
+
|
|
525
|
+
sage: K.<t> = FractionField(PolynomialRing(QQ,'t'))
|
|
526
|
+
sage: E = EllipticCurve([0,0,0,0,t^2])
|
|
527
|
+
sage: P = E(0,t)
|
|
528
|
+
sage: P, 2*P, 3*P
|
|
529
|
+
((0 : t : 1), (0 : -t : 1), (0 : 1 : 0))
|
|
530
|
+
|
|
531
|
+
TESTS::
|
|
532
|
+
|
|
533
|
+
sage: loads(S.dumps()) == S
|
|
534
|
+
True
|
|
535
|
+
|
|
536
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
537
|
+
sage: E = EllipticCurve('37a')
|
|
538
|
+
sage: P = E(0,0); P
|
|
539
|
+
(0 : 0 : 1)
|
|
540
|
+
sage: loads(P.dumps()) == P
|
|
541
|
+
True
|
|
542
|
+
sage: T = 100*P
|
|
543
|
+
sage: loads(T.dumps()) == T
|
|
544
|
+
True
|
|
545
|
+
|
|
546
|
+
Test pickling an elliptic curve that has known points on it::
|
|
547
|
+
|
|
548
|
+
sage: e = EllipticCurve([0, 0, 1, -1, 0]); g = e.gens(); loads(dumps(e)) == e # needs eclib
|
|
549
|
+
True
|
|
550
|
+
|
|
551
|
+
Test that the refactoring from :issue:`14711` did preserve the behaviour
|
|
552
|
+
of domain and codomain::
|
|
553
|
+
|
|
554
|
+
sage: E = EllipticCurve(QQ,[1,1])
|
|
555
|
+
sage: P = E(0,1)
|
|
556
|
+
sage: P.domain()
|
|
557
|
+
Spectrum of Rational Field
|
|
558
|
+
sage: K.<a> = NumberField(x^2 - 3, 'a') # needs sage.rings.number_field
|
|
559
|
+
sage: P = E.base_extend(K)(1,a) # needs sage.rings.number_field
|
|
560
|
+
sage: P.domain() # needs sage.rings.number_field
|
|
561
|
+
Spectrum of Number Field in a with defining polynomial x^2 - 3
|
|
562
|
+
sage: P.codomain() # needs sage.rings.number_field
|
|
563
|
+
Elliptic Curve defined by y^2 = x^3 + x + 1
|
|
564
|
+
over Number Field in a with defining polynomial x^2 - 3
|
|
565
|
+
sage: P.codomain() == P.curve() # needs sage.rings.number_field
|
|
566
|
+
True
|
|
567
|
+
"""
|
|
568
|
+
def __init__(self, curve, v, check=True):
|
|
569
|
+
"""
|
|
570
|
+
Constructor for a point on an elliptic curve.
|
|
571
|
+
|
|
572
|
+
INPUT:
|
|
573
|
+
|
|
574
|
+
- ``curve`` -- an elliptic curve
|
|
575
|
+
- ``v`` -- data determining a point (another point, the integer
|
|
576
|
+
0, or a tuple of coordinates)
|
|
577
|
+
|
|
578
|
+
EXAMPLES::
|
|
579
|
+
|
|
580
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
581
|
+
sage: E = EllipticCurve('43a')
|
|
582
|
+
sage: P = E([2, -4, 2]); P
|
|
583
|
+
(1 : -2 : 1)
|
|
584
|
+
sage: P == E([1,-2])
|
|
585
|
+
True
|
|
586
|
+
sage: P = E(0); P
|
|
587
|
+
(0 : 1 : 0)
|
|
588
|
+
sage: P=E(2, -4, 2); P
|
|
589
|
+
(1 : -2 : 1)
|
|
590
|
+
"""
|
|
591
|
+
point_homset = curve.point_homset()
|
|
592
|
+
R = point_homset.value_ring()
|
|
593
|
+
if isinstance(v, SchemeMorphism):
|
|
594
|
+
v = list(v)
|
|
595
|
+
elif v == 0:
|
|
596
|
+
v = (R.zero(), R.one(), R.zero())
|
|
597
|
+
|
|
598
|
+
SchemeMorphism_point_abelian_variety_field.__init__(self, point_homset, v, check=check)
|
|
599
|
+
|
|
600
|
+
self.normalize_coordinates()
|
|
601
|
+
|
|
602
|
+
def _repr_(self):
|
|
603
|
+
"""
|
|
604
|
+
Return a string representation of this point.
|
|
605
|
+
|
|
606
|
+
EXAMPLES::
|
|
607
|
+
|
|
608
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
609
|
+
sage: E = EllipticCurve('39a')
|
|
610
|
+
sage: P = E([-2, 1, 1])
|
|
611
|
+
sage: P._repr_()
|
|
612
|
+
'(-2 : 1 : 1)'
|
|
613
|
+
"""
|
|
614
|
+
return self.codomain().ambient_space()._repr_generic_point(self._coords)
|
|
615
|
+
|
|
616
|
+
def _latex_(self):
|
|
617
|
+
"""
|
|
618
|
+
Return a LaTeX representation of this point.
|
|
619
|
+
|
|
620
|
+
EXAMPLES::
|
|
621
|
+
|
|
622
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
623
|
+
sage: E = EllipticCurve('40a')
|
|
624
|
+
sage: P = E([3, 0])
|
|
625
|
+
sage: P._latex_()
|
|
626
|
+
'\\left(3 : 0 : 1\\right)'
|
|
627
|
+
"""
|
|
628
|
+
return self.codomain().ambient_space()._latex_generic_point(self._coords)
|
|
629
|
+
|
|
630
|
+
def __getitem__(self, n):
|
|
631
|
+
"""
|
|
632
|
+
Return the n'th coordinate of this point.
|
|
633
|
+
|
|
634
|
+
EXAMPLES::
|
|
635
|
+
|
|
636
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
637
|
+
sage: E = EllipticCurve('42a')
|
|
638
|
+
sage: P = E([-17, -51, 17])
|
|
639
|
+
sage: [P[i] for i in [2,1,0]]
|
|
640
|
+
[1, -3, -1]
|
|
641
|
+
"""
|
|
642
|
+
return self._coords[n]
|
|
643
|
+
|
|
644
|
+
def __iter__(self):
|
|
645
|
+
"""
|
|
646
|
+
Return the coordinates of this point as a list.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
651
|
+
sage: E = EllipticCurve('37a')
|
|
652
|
+
sage: list(E([0,0]))
|
|
653
|
+
[0, 0, 1]
|
|
654
|
+
"""
|
|
655
|
+
return iter(self._coords)
|
|
656
|
+
|
|
657
|
+
def __tuple__(self):
|
|
658
|
+
"""
|
|
659
|
+
Return the coordinates of this point as a tuple.
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
664
|
+
sage: E = EllipticCurve('44a')
|
|
665
|
+
sage: P = E([1, -2, 1])
|
|
666
|
+
sage: P.__tuple__()
|
|
667
|
+
(1, -2, 1)
|
|
668
|
+
"""
|
|
669
|
+
return tuple(self._coords) # Warning: _coords is a list!
|
|
670
|
+
|
|
671
|
+
def _richcmp_(self, other, op):
|
|
672
|
+
"""
|
|
673
|
+
Comparison function for points to allow sorting and equality testing.
|
|
674
|
+
|
|
675
|
+
EXAMPLES::
|
|
676
|
+
|
|
677
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
678
|
+
sage: E = EllipticCurve('45a')
|
|
679
|
+
sage: P = E([2, -1, 1])
|
|
680
|
+
sage: P == E(0)
|
|
681
|
+
False
|
|
682
|
+
sage: P+P == E(0)
|
|
683
|
+
True
|
|
684
|
+
|
|
685
|
+
The additive identity is always the minimum element::
|
|
686
|
+
|
|
687
|
+
sage: E = EllipticCurve(GF(103), [3, 5])
|
|
688
|
+
sage: min(E.points()) == 0
|
|
689
|
+
True
|
|
690
|
+
"""
|
|
691
|
+
if not isinstance(other, EllipticCurvePoint_field):
|
|
692
|
+
try:
|
|
693
|
+
other = self.codomain().ambient_space()(other)
|
|
694
|
+
except TypeError:
|
|
695
|
+
return NotImplemented
|
|
696
|
+
# op_EQ
|
|
697
|
+
if op == 2:
|
|
698
|
+
return richcmp(self._coords, other._coords, op)
|
|
699
|
+
|
|
700
|
+
try:
|
|
701
|
+
return richcmp(self._zxy_coords, other._zxy_coords, op)
|
|
702
|
+
except AttributeError:
|
|
703
|
+
# Compute _zxy_coords
|
|
704
|
+
# There is a chance that we recompute this for either ``self`` or
|
|
705
|
+
# ``other`` However, in the most common use case which is sorting
|
|
706
|
+
# list of `n` variables This will cause a O(n) cost only. If there
|
|
707
|
+
# is a better way feel free to implement it!
|
|
708
|
+
self._zxy_coords = (self._coords[2], self._coords[0], self._coords[1])
|
|
709
|
+
other._zxy_coords = (other._coords[2], other._coords[0], other._coords[1])
|
|
710
|
+
return richcmp(self._zxy_coords, other._zxy_coords, op)
|
|
711
|
+
|
|
712
|
+
def __pari__(self):
|
|
713
|
+
r"""
|
|
714
|
+
Convert this point to PARI format.
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: E = EllipticCurve([0,0,0,3,0])
|
|
719
|
+
sage: O = E(0)
|
|
720
|
+
sage: P = E.point([1,2])
|
|
721
|
+
sage: O.__pari__()
|
|
722
|
+
[0]
|
|
723
|
+
sage: P.__pari__()
|
|
724
|
+
[1, 2]
|
|
725
|
+
|
|
726
|
+
The following implicitly calls O.__pari__() and P.__pari__()::
|
|
727
|
+
|
|
728
|
+
sage: pari(E).elladd(O,P)
|
|
729
|
+
[1, 2]
|
|
730
|
+
|
|
731
|
+
TESTS:
|
|
732
|
+
|
|
733
|
+
Try the same over a finite field::
|
|
734
|
+
|
|
735
|
+
sage: E = EllipticCurve(GF(11), [0,0,0,3,0])
|
|
736
|
+
sage: O = E(0)
|
|
737
|
+
sage: P = E.point([1,2])
|
|
738
|
+
sage: O.__pari__()
|
|
739
|
+
[0]
|
|
740
|
+
sage: P.__pari__()
|
|
741
|
+
[Mod(1, 11), Mod(2, 11)]
|
|
742
|
+
|
|
743
|
+
We no longer need to explicitly call ``pari(O)`` and ``pari(P)``
|
|
744
|
+
after :issue:`11868`::
|
|
745
|
+
|
|
746
|
+
sage: pari(E).elladd(O, P)
|
|
747
|
+
[Mod(1, 11), Mod(2, 11)]
|
|
748
|
+
"""
|
|
749
|
+
x,y,z = self._coords
|
|
750
|
+
if z:
|
|
751
|
+
return pari([x/z, y/z])
|
|
752
|
+
else:
|
|
753
|
+
return pari([0])
|
|
754
|
+
|
|
755
|
+
def order(self):
|
|
756
|
+
r"""
|
|
757
|
+
Return the order of this point on the elliptic curve.
|
|
758
|
+
|
|
759
|
+
If the point is zero, returns 1, otherwise raise a
|
|
760
|
+
:exc:`NotImplementedError`.
|
|
761
|
+
|
|
762
|
+
For curves over number fields and finite fields, see below.
|
|
763
|
+
|
|
764
|
+
.. NOTE::
|
|
765
|
+
|
|
766
|
+
:meth:`additive_order` is a synonym for :meth:`order`
|
|
767
|
+
|
|
768
|
+
EXAMPLES::
|
|
769
|
+
|
|
770
|
+
sage: K.<t> = FractionField(PolynomialRing(QQ,'t'))
|
|
771
|
+
sage: E = EllipticCurve([0, 0, 0, -t^2, 0])
|
|
772
|
+
sage: P = E(t,0)
|
|
773
|
+
sage: P.order()
|
|
774
|
+
Traceback (most recent call last):
|
|
775
|
+
...
|
|
776
|
+
NotImplementedError: Computation of order of a point not implemented
|
|
777
|
+
over general fields.
|
|
778
|
+
sage: E(0).additive_order()
|
|
779
|
+
1
|
|
780
|
+
sage: E(0).order() == 1
|
|
781
|
+
True
|
|
782
|
+
"""
|
|
783
|
+
if hasattr(self, "_order"):
|
|
784
|
+
return self._order
|
|
785
|
+
if self.is_zero():
|
|
786
|
+
self._order = Integer(1)
|
|
787
|
+
return self._order
|
|
788
|
+
raise NotImplementedError("Computation of order of a point "
|
|
789
|
+
"not implemented over general fields.")
|
|
790
|
+
|
|
791
|
+
additive_order = order
|
|
792
|
+
|
|
793
|
+
def __bool__(self) -> bool:
|
|
794
|
+
"""
|
|
795
|
+
Return ``True`` if this is not the zero point on the curve.
|
|
796
|
+
|
|
797
|
+
EXAMPLES::
|
|
798
|
+
|
|
799
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
800
|
+
sage: E = EllipticCurve('37a')
|
|
801
|
+
sage: P = E(0); P
|
|
802
|
+
(0 : 1 : 0)
|
|
803
|
+
sage: P.is_zero()
|
|
804
|
+
True
|
|
805
|
+
sage: P = E.gens()[0] # needs eclib
|
|
806
|
+
sage: P.is_zero() # needs eclib
|
|
807
|
+
False
|
|
808
|
+
"""
|
|
809
|
+
return bool(self._coords[2])
|
|
810
|
+
|
|
811
|
+
def has_order(self, n) -> bool:
|
|
812
|
+
r"""
|
|
813
|
+
Test if this point has order exactly `n`.
|
|
814
|
+
|
|
815
|
+
INPUT:
|
|
816
|
+
|
|
817
|
+
- ``n`` -- integer or its :class:`~sage.structure.factorization.Factorization`
|
|
818
|
+
|
|
819
|
+
ALGORITHM:
|
|
820
|
+
|
|
821
|
+
Compare a cached order if available, otherwise use :func:`sage.groups.generic.has_order`.
|
|
822
|
+
|
|
823
|
+
EXAMPLES::
|
|
824
|
+
|
|
825
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
826
|
+
sage: E = EllipticCurve('26b1')
|
|
827
|
+
sage: P = E(1, 0)
|
|
828
|
+
sage: P.has_order(7)
|
|
829
|
+
True
|
|
830
|
+
sage: P._order
|
|
831
|
+
7
|
|
832
|
+
sage: P.has_order(7)
|
|
833
|
+
True
|
|
834
|
+
|
|
835
|
+
It also works with a :class:`~sage.structure.factorization.Factorization` object::
|
|
836
|
+
|
|
837
|
+
sage: E = EllipticCurve(GF(419), [1,0])
|
|
838
|
+
sage: P = E(-33, 8)
|
|
839
|
+
sage: P.has_order(factor(21))
|
|
840
|
+
True
|
|
841
|
+
sage: P._order
|
|
842
|
+
21
|
|
843
|
+
sage: P.has_order(factor(21))
|
|
844
|
+
True
|
|
845
|
+
|
|
846
|
+
This method can be much faster than computing the order and comparing::
|
|
847
|
+
|
|
848
|
+
sage: # not tested -- timings are different each time
|
|
849
|
+
sage: p = 4 * prod(primes(3,377)) * 587 - 1
|
|
850
|
+
sage: E = EllipticCurve(GF(p), [1,0])
|
|
851
|
+
sage: %timeit P = E.random_point(); P.set_order(multiple=p+1)
|
|
852
|
+
72.4 ms ± 773 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
|
|
853
|
+
sage: %timeit P = E.random_point(); P.has_order(p+1)
|
|
854
|
+
32.8 ms ± 3.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
|
|
855
|
+
sage: fac = factor(p+1)
|
|
856
|
+
sage: %timeit P = E.random_point(); P.has_order(fac)
|
|
857
|
+
30.6 ms ± 3.48 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
|
|
858
|
+
|
|
859
|
+
The order is cached once it has been confirmed once, and the cache is
|
|
860
|
+
shared with :meth:`order`::
|
|
861
|
+
|
|
862
|
+
sage: # not tested -- timings are different each time
|
|
863
|
+
sage: P, = E.gens()
|
|
864
|
+
sage: delattr(P, '_order')
|
|
865
|
+
sage: %time P.has_order(p+1)
|
|
866
|
+
CPU times: user 83.6 ms, sys: 30 µs, total: 83.6 ms
|
|
867
|
+
Wall time: 83.8 ms
|
|
868
|
+
True
|
|
869
|
+
sage: %time P.has_order(p+1)
|
|
870
|
+
CPU times: user 31 µs, sys: 2 µs, total: 33 µs
|
|
871
|
+
Wall time: 37.9 µs
|
|
872
|
+
True
|
|
873
|
+
sage: %time P.order()
|
|
874
|
+
CPU times: user 11 µs, sys: 0 ns, total: 11 µs
|
|
875
|
+
Wall time: 16 µs
|
|
876
|
+
5326738796327623094747867617954605554069371494832722337612446642054009560026576537626892113026381253624626941643949444792662881241621373288942880288065660
|
|
877
|
+
sage: delattr(P, '_order')
|
|
878
|
+
sage: %time P.has_order(fac)
|
|
879
|
+
CPU times: user 68.6 ms, sys: 17 µs, total: 68.7 ms
|
|
880
|
+
Wall time: 68.7 ms
|
|
881
|
+
True
|
|
882
|
+
sage: %time P.has_order(fac)
|
|
883
|
+
CPU times: user 92 µs, sys: 0 ns, total: 92 µs
|
|
884
|
+
Wall time: 97.5 µs
|
|
885
|
+
True
|
|
886
|
+
sage: %time P.order()
|
|
887
|
+
CPU times: user 10 µs, sys: 1e+03 ns, total: 11 µs
|
|
888
|
+
Wall time: 14.5 µs
|
|
889
|
+
5326738796327623094747867617954605554069371494832722337612446642054009560026576537626892113026381253624626941643949444792662881241621373288942880288065660
|
|
890
|
+
|
|
891
|
+
TESTS::
|
|
892
|
+
|
|
893
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
894
|
+
sage: E(0).has_order(1)
|
|
895
|
+
True
|
|
896
|
+
sage: E(0).has_order(Factorization([]))
|
|
897
|
+
True
|
|
898
|
+
"""
|
|
899
|
+
if hasattr(self, '_order'): # already known
|
|
900
|
+
if not isinstance(n, Integer):
|
|
901
|
+
n = n.value()
|
|
902
|
+
return self._order == n
|
|
903
|
+
ret = generic.has_order(self, n, operation='+')
|
|
904
|
+
if ret and not hasattr(self, '_order'): # known now; cache
|
|
905
|
+
if not isinstance(n, Integer):
|
|
906
|
+
n = n.value()
|
|
907
|
+
self._order = n
|
|
908
|
+
return ret
|
|
909
|
+
|
|
910
|
+
def has_finite_order(self) -> bool:
|
|
911
|
+
"""
|
|
912
|
+
Return ``True`` if this point has finite additive order as an
|
|
913
|
+
element of the group of points on this curve.
|
|
914
|
+
|
|
915
|
+
For fields other than number fields and finite fields, this is
|
|
916
|
+
NotImplemented unless self.is_zero().
|
|
917
|
+
|
|
918
|
+
EXAMPLES::
|
|
919
|
+
|
|
920
|
+
sage: K.<t> = FractionField(PolynomialRing(QQ,'t'))
|
|
921
|
+
sage: E = EllipticCurve([0, 0, 0, -t^2, 0])
|
|
922
|
+
sage: P = E(0)
|
|
923
|
+
sage: P.has_finite_order()
|
|
924
|
+
True
|
|
925
|
+
sage: P = E(t,0)
|
|
926
|
+
sage: P.has_finite_order()
|
|
927
|
+
Traceback (most recent call last):
|
|
928
|
+
...
|
|
929
|
+
NotImplementedError: Computation of order of a point not implemented
|
|
930
|
+
over general fields.
|
|
931
|
+
sage: (2*P).is_zero()
|
|
932
|
+
True
|
|
933
|
+
"""
|
|
934
|
+
if self.is_zero():
|
|
935
|
+
return True
|
|
936
|
+
return self.order() != oo
|
|
937
|
+
|
|
938
|
+
is_finite_order = has_finite_order # for backward compatibility
|
|
939
|
+
|
|
940
|
+
def has_infinite_order(self) -> bool:
|
|
941
|
+
"""
|
|
942
|
+
Return ``True`` if this point has infinite additive order as an element
|
|
943
|
+
of the group of points on this curve.
|
|
944
|
+
|
|
945
|
+
For fields other than number fields and finite fields, this is
|
|
946
|
+
NotImplemented unless ``self.is_zero()``.
|
|
947
|
+
|
|
948
|
+
EXAMPLES::
|
|
949
|
+
|
|
950
|
+
sage: K.<t> = FractionField(PolynomialRing(QQ,'t'))
|
|
951
|
+
sage: E = EllipticCurve([0, 0, 0, -t^2, 0])
|
|
952
|
+
sage: P = E(0)
|
|
953
|
+
sage: P.has_infinite_order()
|
|
954
|
+
False
|
|
955
|
+
sage: P = E(t,0)
|
|
956
|
+
sage: P.has_infinite_order()
|
|
957
|
+
Traceback (most recent call last):
|
|
958
|
+
...
|
|
959
|
+
NotImplementedError: Computation of order of a point not implemented over general fields.
|
|
960
|
+
sage: (2*P).is_zero()
|
|
961
|
+
True
|
|
962
|
+
"""
|
|
963
|
+
if self.is_zero():
|
|
964
|
+
return False
|
|
965
|
+
return self.order() == oo
|
|
966
|
+
|
|
967
|
+
def plot(self, **args):
|
|
968
|
+
"""
|
|
969
|
+
Plot this point on an elliptic curve.
|
|
970
|
+
|
|
971
|
+
INPUT:
|
|
972
|
+
|
|
973
|
+
- ``**args`` -- all arguments get passed directly onto the point
|
|
974
|
+
plotting function
|
|
975
|
+
|
|
976
|
+
EXAMPLES::
|
|
977
|
+
|
|
978
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
979
|
+
sage: E = EllipticCurve('389a')
|
|
980
|
+
sage: P = E([-1,1])
|
|
981
|
+
sage: P.plot(pointsize=30, rgbcolor=(1,0,0)) # needs sage.plot
|
|
982
|
+
Graphics object consisting of 1 graphics primitive
|
|
983
|
+
"""
|
|
984
|
+
from sage.plot.point import point
|
|
985
|
+
from sage.plot.text import text
|
|
986
|
+
|
|
987
|
+
if self.is_zero():
|
|
988
|
+
return text("$\\infty$", (-3, 3), **args)
|
|
989
|
+
else:
|
|
990
|
+
return point((self[0], self[1]), **args)
|
|
991
|
+
|
|
992
|
+
def _add_(self, other):
|
|
993
|
+
r"""
|
|
994
|
+
Add this point to another point on the same elliptic curve.
|
|
995
|
+
|
|
996
|
+
This method is specialized to elliptic curves over fields.
|
|
997
|
+
|
|
998
|
+
EXAMPLES::
|
|
999
|
+
|
|
1000
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1001
|
+
sage: E = EllipticCurve('389a')
|
|
1002
|
+
sage: P = E([-1,1]); Q = E([0,0])
|
|
1003
|
+
sage: P + Q
|
|
1004
|
+
(1 : 0 : 1)
|
|
1005
|
+
sage: P._add_(Q) == P + Q
|
|
1006
|
+
True
|
|
1007
|
+
|
|
1008
|
+
TESTS:
|
|
1009
|
+
|
|
1010
|
+
Example to show that bug :issue:`4820` is fixed::
|
|
1011
|
+
|
|
1012
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1013
|
+
sage: [type(c) for c in 2*EllipticCurve('37a1').gen(0)] # needs eclib
|
|
1014
|
+
[<... 'sage.rings.rational.Rational'>,
|
|
1015
|
+
<... 'sage.rings.rational.Rational'>,
|
|
1016
|
+
<... 'sage.rings.rational.Rational'>]
|
|
1017
|
+
|
|
1018
|
+
Checks that :issue:`15964` is fixed::
|
|
1019
|
+
|
|
1020
|
+
sage: N = 1715761513
|
|
1021
|
+
sage: E = EllipticCurve(Integers(N), [3,-13])
|
|
1022
|
+
sage: E.assume_base_ring_is_field()
|
|
1023
|
+
sage: P = E(2,1)
|
|
1024
|
+
sage: LCM([2..60])*P
|
|
1025
|
+
Traceback (most recent call last):
|
|
1026
|
+
...
|
|
1027
|
+
ZeroDivisionError: Inverse of 26927 does not exist
|
|
1028
|
+
(characteristic = 1715761513 = 26927*63719)
|
|
1029
|
+
|
|
1030
|
+
sage: N = 35
|
|
1031
|
+
sage: E = EllipticCurve(Integers(N), [5,1])
|
|
1032
|
+
sage: E.assume_base_ring_is_field()
|
|
1033
|
+
sage: P = E(0,1)
|
|
1034
|
+
sage: 4*P
|
|
1035
|
+
Traceback (most recent call last):
|
|
1036
|
+
...
|
|
1037
|
+
ZeroDivisionError: Inverse of 7 does not exist
|
|
1038
|
+
(characteristic = 35 = 7*5)
|
|
1039
|
+
|
|
1040
|
+
Checks that :issue:`34681` is fixed::
|
|
1041
|
+
|
|
1042
|
+
sage: P+P
|
|
1043
|
+
(15 : 14 : 1)
|
|
1044
|
+
sage: 2*P
|
|
1045
|
+
(15 : 14 : 1)
|
|
1046
|
+
"""
|
|
1047
|
+
# Use Prop 7.1.7 of Cohen "A Course in Computational Algebraic Number Theory"
|
|
1048
|
+
|
|
1049
|
+
if self.is_zero():
|
|
1050
|
+
return other
|
|
1051
|
+
if other.is_zero():
|
|
1052
|
+
return self
|
|
1053
|
+
|
|
1054
|
+
E = self.curve()
|
|
1055
|
+
a1, a2, a3, a4, a6 = E.ainvs()
|
|
1056
|
+
x1, y1 = self.xy()
|
|
1057
|
+
x2, y2 = other.xy()
|
|
1058
|
+
|
|
1059
|
+
if x1 == x2 and y1 == -y2 - a1*x2 - a3:
|
|
1060
|
+
return E(0) # point at infinity
|
|
1061
|
+
|
|
1062
|
+
try:
|
|
1063
|
+
if x1 == x2 and y1 == y2:
|
|
1064
|
+
m = (3*x1*x1 + 2*a2*x1 + a4 - a1*y1) / (2*y1 + a1*x1 + a3)
|
|
1065
|
+
else:
|
|
1066
|
+
m = (y1 - y2) / (x1 - x2)
|
|
1067
|
+
except ZeroDivisionError as ex:
|
|
1068
|
+
try:
|
|
1069
|
+
d = next(d for d in (x1 - x2, 2*y1 + a1*x1 + a3) if d and not d.is_unit())
|
|
1070
|
+
m, = d.parent().defining_ideal().gens()
|
|
1071
|
+
f1 = d.lift().gcd(m)
|
|
1072
|
+
f2 = m // f1
|
|
1073
|
+
assert m == f1 * f2
|
|
1074
|
+
except Exception:
|
|
1075
|
+
raise ex
|
|
1076
|
+
else:
|
|
1077
|
+
raise ZeroDivisionError(f'Inverse of {d} does not exist (characteristic = {m} = {f1}*{f2})')
|
|
1078
|
+
|
|
1079
|
+
x3 = -x1 - x2 - a2 + m*(m+a1)
|
|
1080
|
+
y3 = -y1 - a3 - a1*x3 + m*(x1-x3)
|
|
1081
|
+
# See trac #4820 for why we need to coerce 1 into the base ring here:
|
|
1082
|
+
return E.point([x3, y3, E.base_ring().one()], check=False)
|
|
1083
|
+
|
|
1084
|
+
_sub_ = EllipticCurvePoint._sub_
|
|
1085
|
+
|
|
1086
|
+
def _neg_(self):
|
|
1087
|
+
"""
|
|
1088
|
+
Return the additive inverse of this point.
|
|
1089
|
+
|
|
1090
|
+
Same as :meth:`EllipticCurvePoint._neg_`, but specialized
|
|
1091
|
+
to points over fields, which are normalized to satisfy `z=1`.
|
|
1092
|
+
|
|
1093
|
+
EXAMPLES::
|
|
1094
|
+
|
|
1095
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1096
|
+
sage: E = EllipticCurve('389a')
|
|
1097
|
+
sage: P = E([-1,1])
|
|
1098
|
+
sage: Q = -P; Q
|
|
1099
|
+
(-1 : -2 : 1)
|
|
1100
|
+
sage: Q + P
|
|
1101
|
+
(0 : 1 : 0)
|
|
1102
|
+
|
|
1103
|
+
Example to show that bug :issue:`4820` is fixed::
|
|
1104
|
+
|
|
1105
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1106
|
+
sage: [type(c) for c in -EllipticCurve('37a1').gen(0)] # needs eclib
|
|
1107
|
+
[<... 'sage.rings.rational.Rational'>,
|
|
1108
|
+
<... 'sage.rings.rational.Rational'>,
|
|
1109
|
+
<... 'sage.rings.rational.Rational'>]
|
|
1110
|
+
"""
|
|
1111
|
+
if self.is_zero():
|
|
1112
|
+
return self
|
|
1113
|
+
E, x, y = self.curve(), self[0], self[1]
|
|
1114
|
+
# See trac #4820 for why we need to coerce 1 into the base ring here:
|
|
1115
|
+
return E.point([x, -y - E.a1()*x - E.a3(), E.base_ring().one()], check=False)
|
|
1116
|
+
|
|
1117
|
+
def xy(self):
|
|
1118
|
+
"""
|
|
1119
|
+
Return the `x` and `y` coordinates of this point, as a 2-tuple.
|
|
1120
|
+
If this is the point at infinity, a :exc:`ZeroDivisionError` is raised.
|
|
1121
|
+
|
|
1122
|
+
EXAMPLES::
|
|
1123
|
+
|
|
1124
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1125
|
+
sage: E = EllipticCurve('389a')
|
|
1126
|
+
sage: P = E([-1,1])
|
|
1127
|
+
sage: P.xy()
|
|
1128
|
+
(-1, 1)
|
|
1129
|
+
sage: Q = E(0); Q
|
|
1130
|
+
(0 : 1 : 0)
|
|
1131
|
+
sage: Q.xy()
|
|
1132
|
+
Traceback (most recent call last):
|
|
1133
|
+
...
|
|
1134
|
+
ZeroDivisionError: rational division by zero
|
|
1135
|
+
"""
|
|
1136
|
+
if self[2].is_one():
|
|
1137
|
+
return self[0], self[1]
|
|
1138
|
+
else:
|
|
1139
|
+
return self[0]/self[2], self[1]/self[2]
|
|
1140
|
+
|
|
1141
|
+
def x(self):
|
|
1142
|
+
"""
|
|
1143
|
+
Return the `x` coordinate of this point, as an element of the base field.
|
|
1144
|
+
If this is the point at infinity, a :exc:`ZeroDivisionError` is raised.
|
|
1145
|
+
|
|
1146
|
+
EXAMPLES::
|
|
1147
|
+
|
|
1148
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1149
|
+
sage: E = EllipticCurve('389a')
|
|
1150
|
+
sage: P = E([-1,1])
|
|
1151
|
+
sage: P.x()
|
|
1152
|
+
-1
|
|
1153
|
+
sage: Q = E(0); Q
|
|
1154
|
+
(0 : 1 : 0)
|
|
1155
|
+
sage: Q.x()
|
|
1156
|
+
Traceback (most recent call last):
|
|
1157
|
+
...
|
|
1158
|
+
ZeroDivisionError: rational division by zero
|
|
1159
|
+
"""
|
|
1160
|
+
if self[2].is_one():
|
|
1161
|
+
return self[0]
|
|
1162
|
+
else:
|
|
1163
|
+
return self[0]/self[2]
|
|
1164
|
+
|
|
1165
|
+
def y(self):
|
|
1166
|
+
"""
|
|
1167
|
+
Return the `y` coordinate of this point, as an element of the base field.
|
|
1168
|
+
If this is the point at infinity, a :exc:`ZeroDivisionError` is raised.
|
|
1169
|
+
|
|
1170
|
+
EXAMPLES::
|
|
1171
|
+
|
|
1172
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1173
|
+
sage: E = EllipticCurve('389a')
|
|
1174
|
+
sage: P = E([-1,1])
|
|
1175
|
+
sage: P.y()
|
|
1176
|
+
1
|
|
1177
|
+
sage: Q = E(0); Q
|
|
1178
|
+
(0 : 1 : 0)
|
|
1179
|
+
sage: Q.y()
|
|
1180
|
+
Traceback (most recent call last):
|
|
1181
|
+
...
|
|
1182
|
+
ZeroDivisionError: rational division by zero
|
|
1183
|
+
"""
|
|
1184
|
+
if self[2].is_one():
|
|
1185
|
+
return self[1]
|
|
1186
|
+
else:
|
|
1187
|
+
return self[1]/self[2]
|
|
1188
|
+
|
|
1189
|
+
def is_divisible_by(self, m):
|
|
1190
|
+
"""
|
|
1191
|
+
Return ``True`` if there exists a point `Q` defined over the same
|
|
1192
|
+
field as ``self`` such that `mQ` == ``self``.
|
|
1193
|
+
|
|
1194
|
+
INPUT:
|
|
1195
|
+
|
|
1196
|
+
- ``m`` -- positive integer
|
|
1197
|
+
|
|
1198
|
+
OUTPUT:
|
|
1199
|
+
|
|
1200
|
+
boolean; ``True`` if there is a solution, else False.
|
|
1201
|
+
|
|
1202
|
+
.. WARNING::
|
|
1203
|
+
|
|
1204
|
+
This function usually triggers the computation of the
|
|
1205
|
+
`m`-th division polynomial of the associated elliptic
|
|
1206
|
+
curve, which will be expensive if `m` is large, though it
|
|
1207
|
+
will be cached for subsequent calls with the same `m`.
|
|
1208
|
+
|
|
1209
|
+
EXAMPLES::
|
|
1210
|
+
|
|
1211
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1212
|
+
sage: E = EllipticCurve('389a')
|
|
1213
|
+
sage: Q = 5*E(0,0); Q
|
|
1214
|
+
(-2739/1444 : -77033/54872 : 1)
|
|
1215
|
+
sage: Q.is_divisible_by(4)
|
|
1216
|
+
False
|
|
1217
|
+
sage: Q.is_divisible_by(5)
|
|
1218
|
+
True
|
|
1219
|
+
|
|
1220
|
+
A finite field example::
|
|
1221
|
+
|
|
1222
|
+
sage: E = EllipticCurve(GF(101), [23,34])
|
|
1223
|
+
sage: E.cardinality().factor()
|
|
1224
|
+
2 * 53
|
|
1225
|
+
sage: Set([T.order() for T in E.points()])
|
|
1226
|
+
{1, 106, 2, 53}
|
|
1227
|
+
sage: len([T for T in E.points() if T.is_divisible_by(2)])
|
|
1228
|
+
53
|
|
1229
|
+
sage: len([T for T in E.points() if T.is_divisible_by(3)])
|
|
1230
|
+
106
|
|
1231
|
+
|
|
1232
|
+
TESTS:
|
|
1233
|
+
|
|
1234
|
+
This shows that the bug reported at :issue:`10076` is fixed::
|
|
1235
|
+
|
|
1236
|
+
sage: # needs sage.rings.number_field
|
|
1237
|
+
sage: K = QuadraticField(8,'a')
|
|
1238
|
+
sage: E = EllipticCurve([K(0),0,0,-1,0])
|
|
1239
|
+
sage: P = E([-1,0])
|
|
1240
|
+
sage: P.is_divisible_by(2)
|
|
1241
|
+
False
|
|
1242
|
+
sage: P.division_points(2)
|
|
1243
|
+
[]
|
|
1244
|
+
|
|
1245
|
+
Note that it is not sufficient to test that
|
|
1246
|
+
``self.division_points(m,poly_only=True)`` has roots::
|
|
1247
|
+
|
|
1248
|
+
sage: P.division_points(2, poly_only=True).roots() # needs sage.rings.number_field
|
|
1249
|
+
[(1/2*a - 1, 1), (-1/2*a - 1, 1)]
|
|
1250
|
+
|
|
1251
|
+
sage: # needs sage.rings.number_field
|
|
1252
|
+
sage: tor = E.torsion_points(); len(tor)
|
|
1253
|
+
8
|
|
1254
|
+
sage: [T.order() for T in tor]
|
|
1255
|
+
[1, 2, 4, 4, 2, 2, 4, 4]
|
|
1256
|
+
sage: all(T.is_divisible_by(3) for T in tor)
|
|
1257
|
+
True
|
|
1258
|
+
sage: sorted(T for T in tor if T.is_divisible_by(2))
|
|
1259
|
+
[(0 : 1 : 0), (1 : 0 : 1)]
|
|
1260
|
+
sage: sorted(Set([2*T for T in tor]))
|
|
1261
|
+
[(0 : 1 : 0), (1 : 0 : 1)]
|
|
1262
|
+
"""
|
|
1263
|
+
# Coerce the input m to an integer
|
|
1264
|
+
m = Integer(m)
|
|
1265
|
+
|
|
1266
|
+
# Check for trivial cases of m = 1, -1 and 0.
|
|
1267
|
+
if m == 1 or m == -1:
|
|
1268
|
+
return True
|
|
1269
|
+
if m == 0:
|
|
1270
|
+
return self == 0 # then m*self=self for all m!
|
|
1271
|
+
m = m.abs()
|
|
1272
|
+
|
|
1273
|
+
# Now the following line would of course be correct, but we
|
|
1274
|
+
# work harder to be more efficient:
|
|
1275
|
+
# return len(self.division_points(m)) > 0
|
|
1276
|
+
|
|
1277
|
+
P = self
|
|
1278
|
+
|
|
1279
|
+
# If P has finite order n and gcd(m,n)=1 then the result is
|
|
1280
|
+
# True. However, over general fields computing P.order() is
|
|
1281
|
+
# not implemented.
|
|
1282
|
+
|
|
1283
|
+
try:
|
|
1284
|
+
n = P.order()
|
|
1285
|
+
if not n == oo:
|
|
1286
|
+
if m.gcd(n) == 1:
|
|
1287
|
+
return True
|
|
1288
|
+
except NotImplementedError:
|
|
1289
|
+
pass
|
|
1290
|
+
|
|
1291
|
+
P_is_2_torsion = (P == -P)
|
|
1292
|
+
g = P.division_points(m, poly_only=True)
|
|
1293
|
+
|
|
1294
|
+
if not P_is_2_torsion:
|
|
1295
|
+
# In this case deg(g)=m^2, and each root in K lifts to two
|
|
1296
|
+
# points Q,-Q both in E(K), of which exactly one is a
|
|
1297
|
+
# solution. So we just check the existence of roots:
|
|
1298
|
+
return len(g.roots()) > 0
|
|
1299
|
+
|
|
1300
|
+
# Now 2*P==0
|
|
1301
|
+
|
|
1302
|
+
if m % 2 == 1:
|
|
1303
|
+
return True # P itself is a solution when m is odd
|
|
1304
|
+
|
|
1305
|
+
# Now m is even and 2*P=0. Roots of g in K may or may not
|
|
1306
|
+
# lift to solutions in E(K), so we fall back to the default.
|
|
1307
|
+
# Note that division polynomials are cached so this is not
|
|
1308
|
+
# inefficient:
|
|
1309
|
+
|
|
1310
|
+
return len(self.division_points(m)) > 0
|
|
1311
|
+
|
|
1312
|
+
def division_points(self, m, poly_only=False):
|
|
1313
|
+
r"""
|
|
1314
|
+
Return a list of all points `Q` such that `mQ=P` where `P` = ``self``.
|
|
1315
|
+
|
|
1316
|
+
Only points on the elliptic curve containing ``self`` and defined
|
|
1317
|
+
over the base field are included.
|
|
1318
|
+
|
|
1319
|
+
INPUT:
|
|
1320
|
+
|
|
1321
|
+
- ``m`` -- positive integer
|
|
1322
|
+
|
|
1323
|
+
- ``poly_only`` -- boolean (default: ``False``); if ``True`` return
|
|
1324
|
+
polynomial whose roots give all possible `x`-coordinates of
|
|
1325
|
+
`m`-th roots of ``self``
|
|
1326
|
+
|
|
1327
|
+
OUTPUT: a (possibly empty) list of solutions `Q` to `mQ=P`,
|
|
1328
|
+
where `P` = ``self``
|
|
1329
|
+
|
|
1330
|
+
EXAMPLES:
|
|
1331
|
+
|
|
1332
|
+
We find the five 5-torsion points on an elliptic curve::
|
|
1333
|
+
|
|
1334
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1335
|
+
sage: E = EllipticCurve('11a'); E
|
|
1336
|
+
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
|
|
1337
|
+
sage: P = E(0); P
|
|
1338
|
+
(0 : 1 : 0)
|
|
1339
|
+
sage: P.division_points(5)
|
|
1340
|
+
[(0 : 1 : 0), (5 : -6 : 1), (5 : 5 : 1), (16 : -61 : 1), (16 : 60 : 1)]
|
|
1341
|
+
|
|
1342
|
+
Note above that 0 is included since [5]*0 = 0.
|
|
1343
|
+
|
|
1344
|
+
We create a curve of rank 1 with no torsion and do a consistency check::
|
|
1345
|
+
|
|
1346
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1347
|
+
sage: E = EllipticCurve('11a').quadratic_twist(-7)
|
|
1348
|
+
sage: Q = E([44,-270])
|
|
1349
|
+
sage: (4*Q).division_points(4)
|
|
1350
|
+
[(44 : -270 : 1)]
|
|
1351
|
+
|
|
1352
|
+
We create a curve over a non-prime finite field with group of
|
|
1353
|
+
order `18`::
|
|
1354
|
+
|
|
1355
|
+
sage: # needs sage.rings.finite_rings
|
|
1356
|
+
sage: k.<a> = GF((5,2))
|
|
1357
|
+
sage: E = EllipticCurve(k, [1,2+a,3,4*a,2])
|
|
1358
|
+
sage: P = E([3, 3*a+4])
|
|
1359
|
+
sage: factor(E.order())
|
|
1360
|
+
2 * 3^2
|
|
1361
|
+
sage: P.order()
|
|
1362
|
+
9
|
|
1363
|
+
|
|
1364
|
+
We find the `1`-division points as a consistency check -- there
|
|
1365
|
+
is just one, of course::
|
|
1366
|
+
|
|
1367
|
+
sage: P.division_points(1) # needs sage.rings.finite_rings
|
|
1368
|
+
[(3 : 3*a + 4 : 1)]
|
|
1369
|
+
|
|
1370
|
+
The point `P` has order coprime to 2 but divisible by 3, so::
|
|
1371
|
+
|
|
1372
|
+
sage: P.division_points(2) # needs sage.rings.finite_rings
|
|
1373
|
+
[(2*a + 1 : 3*a + 4 : 1), (3*a + 1 : a : 1)]
|
|
1374
|
+
|
|
1375
|
+
We check that each of the 2-division points works as claimed::
|
|
1376
|
+
|
|
1377
|
+
sage: [2*Q for Q in P.division_points(2)] # needs sage.rings.finite_rings
|
|
1378
|
+
[(3 : 3*a + 4 : 1), (3 : 3*a + 4 : 1)]
|
|
1379
|
+
|
|
1380
|
+
Some other checks::
|
|
1381
|
+
|
|
1382
|
+
sage: P.division_points(3) # needs sage.rings.finite_rings
|
|
1383
|
+
[]
|
|
1384
|
+
sage: P.division_points(4) # needs sage.rings.finite_rings
|
|
1385
|
+
[(0 : 3*a + 2 : 1), (1 : 0 : 1)]
|
|
1386
|
+
sage: P.division_points(5) # needs sage.rings.finite_rings
|
|
1387
|
+
[(1 : 1 : 1)]
|
|
1388
|
+
|
|
1389
|
+
An example over a number field (see :issue:`3383`)::
|
|
1390
|
+
|
|
1391
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
1392
|
+
sage: E = EllipticCurve('19a1')
|
|
1393
|
+
sage: x = polygen(ZZ, 'x')
|
|
1394
|
+
sage: K.<t> = NumberField(x^9 - 3*x^8 - 4*x^7 + 16*x^6 - 3*x^5
|
|
1395
|
+
....: - 21*x^4 + 5*x^3 + 7*x^2 - 7*x + 1)
|
|
1396
|
+
sage: EK = E.base_extend(K)
|
|
1397
|
+
sage: E(0).division_points(3)
|
|
1398
|
+
[(0 : 1 : 0), (5 : -10 : 1), (5 : 9 : 1)]
|
|
1399
|
+
sage: EK(0).division_points(3)
|
|
1400
|
+
[(0 : 1 : 0), (5 : 9 : 1), (5 : -10 : 1)]
|
|
1401
|
+
sage: E(0).division_points(9)
|
|
1402
|
+
[(0 : 1 : 0), (5 : -10 : 1), (5 : 9 : 1)]
|
|
1403
|
+
sage: EK(0).division_points(9)
|
|
1404
|
+
[(0 : 1 : 0), (5 : 9 : 1), (5 : -10 : 1), (-150/121*t^8 + 414/121*t^7 + 1481/242*t^6 - 2382/121*t^5 - 103/242*t^4 + 629/22*t^3 - 367/242*t^2 - 1307/121*t + 625/121 : 35/484*t^8 - 133/242*t^7 + 445/242*t^6 - 799/242*t^5 + 373/484*t^4 + 113/22*t^3 - 2355/484*t^2 - 753/242*t + 1165/484 : 1), (-150/121*t^8 + 414/121*t^7 + 1481/242*t^6 - 2382/121*t^5 - 103/242*t^4 + 629/22*t^3 - 367/242*t^2 - 1307/121*t + 625/121 : -35/484*t^8 + 133/242*t^7 - 445/242*t^6 + 799/242*t^5 - 373/484*t^4 - 113/22*t^3 + 2355/484*t^2 + 753/242*t - 1649/484 : 1), (-1383/484*t^8 + 970/121*t^7 + 3159/242*t^6 - 5211/121*t^5 + 37/484*t^4 + 654/11*t^3 - 909/484*t^2 - 4831/242*t + 6791/484 : 927/121*t^8 - 5209/242*t^7 - 8187/242*t^6 + 27975/242*t^5 - 1147/242*t^4 - 1729/11*t^3 + 1566/121*t^2 + 12873/242*t - 10871/242 : 1), (-1383/484*t^8 + 970/121*t^7 + 3159/242*t^6 - 5211/121*t^5 + 37/484*t^4 + 654/11*t^3 - 909/484*t^2 - 4831/242*t + 6791/484 : -927/121*t^8 + 5209/242*t^7 + 8187/242*t^6 - 27975/242*t^5 + 1147/242*t^4 + 1729/11*t^3 - 1566/121*t^2 - 12873/242*t + 10629/242 : 1), (-4793/484*t^8 + 6791/242*t^7 + 10727/242*t^6 - 18301/121*t^5 + 2347/484*t^4 + 2293/11*t^3 - 7311/484*t^2 - 17239/242*t + 26767/484 : 30847/484*t^8 - 21789/121*t^7 - 34605/121*t^6 + 117164/121*t^5 - 10633/484*t^4 - 29437/22*t^3 + 39725/484*t^2 + 55428/121*t - 176909/484 : 1), (-4793/484*t^8 + 6791/242*t^7 + 10727/242*t^6 - 18301/121*t^5 + 2347/484*t^4 + 2293/11*t^3 - 7311/484*t^2 - 17239/242*t + 26767/484 : -30847/484*t^8 + 21789/121*t^7 + 34605/121*t^6 - 117164/121*t^5 + 10633/484*t^4 + 29437/22*t^3 - 39725/484*t^2 - 55428/121*t + 176425/484 : 1)]
|
|
1405
|
+
|
|
1406
|
+
TESTS:
|
|
1407
|
+
|
|
1408
|
+
Check that :issue:`24844` is fixed::
|
|
1409
|
+
|
|
1410
|
+
sage: # needs sage.rings.finite_rings
|
|
1411
|
+
sage: p = next_prime(1000000)
|
|
1412
|
+
sage: E = EllipticCurve(GF(p), 123, 456)
|
|
1413
|
+
sage: pts = E(0).division_points(3)
|
|
1414
|
+
sage: P = pts[1]; P
|
|
1415
|
+
(389063 : 124244 : 1)
|
|
1416
|
+
sage: P._order
|
|
1417
|
+
3
|
|
1418
|
+
|
|
1419
|
+
When we successfully divide a point known to have infinite
|
|
1420
|
+
order, the points returned know that they also have infinite
|
|
1421
|
+
order::
|
|
1422
|
+
|
|
1423
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
1424
|
+
sage: P = E(-1,0)
|
|
1425
|
+
sage: P.order()
|
|
1426
|
+
+Infinity
|
|
1427
|
+
sage: pts = P.division_points(3); len(pts)
|
|
1428
|
+
1
|
|
1429
|
+
sage: [(Q,Q._order) for Q in pts]
|
|
1430
|
+
[((0 : -1 : 1), +Infinity)]
|
|
1431
|
+
|
|
1432
|
+
When we successfully divide a point of known finite order `n`,
|
|
1433
|
+
the points returned know that they also have finite order `nk`
|
|
1434
|
+
for some divisor `k` of `m`::
|
|
1435
|
+
|
|
1436
|
+
sage: E = EllipticCurve([1, 0, 1, -19, 26])
|
|
1437
|
+
sage: [(Q,Q._order) for Q in E(0).division_points(12)]
|
|
1438
|
+
[((0 : 1 : 0), 1),
|
|
1439
|
+
((-5 : 2 : 1), 2),
|
|
1440
|
+
((-2 : -7 : 1), 6),
|
|
1441
|
+
((-2 : 8 : 1), 6),
|
|
1442
|
+
((1 : -4 : 1), 6),
|
|
1443
|
+
((1 : 2 : 1), 6),
|
|
1444
|
+
((7/4 : -11/8 : 1), 2),
|
|
1445
|
+
((3 : -2 : 1), 2),
|
|
1446
|
+
((4 : -7 : 1), 3),
|
|
1447
|
+
((4 : 2 : 1), 3),
|
|
1448
|
+
((13 : -52 : 1), 6),
|
|
1449
|
+
((13 : 38 : 1), 6)]
|
|
1450
|
+
sage: P = E(4,-7)
|
|
1451
|
+
sage: P.order()
|
|
1452
|
+
3
|
|
1453
|
+
sage: [(Q,Q._order) for Q in P.division_points(4)]
|
|
1454
|
+
[((-2 : -7 : 1), 6), ((1 : 2 : 1), 6), ((4 : -7 : 1), 3), ((13 : 38 : 1), 6)]
|
|
1455
|
+
|
|
1456
|
+
Check for :issue:`38796`::
|
|
1457
|
+
|
|
1458
|
+
sage: E = EllipticCurve(GF(127), [1,1])
|
|
1459
|
+
sage: P = E(72, 24)
|
|
1460
|
+
sage: [-1*Q for Q in P.division_points(-1)]
|
|
1461
|
+
[(72 : 24 : 1)]
|
|
1462
|
+
"""
|
|
1463
|
+
# Coerce the input m to an integer
|
|
1464
|
+
m = Integer(m)
|
|
1465
|
+
# Check for trivial cases of m = 1, -1 and 0.
|
|
1466
|
+
if m == 1 or m == -1:
|
|
1467
|
+
return [m*self]
|
|
1468
|
+
if m == 0:
|
|
1469
|
+
if self == 0: # then every point Q is a solution, but...
|
|
1470
|
+
return [self]
|
|
1471
|
+
else:
|
|
1472
|
+
return []
|
|
1473
|
+
|
|
1474
|
+
# ans will contain the list of division points.
|
|
1475
|
+
ans = []
|
|
1476
|
+
|
|
1477
|
+
# We compute a polynomial g whose roots give all possible x
|
|
1478
|
+
# coordinates of the m-division points. The number of
|
|
1479
|
+
# solutions (over the algebraic closure) is m^2, assuming that
|
|
1480
|
+
# the characteristic does not divide m.
|
|
1481
|
+
|
|
1482
|
+
E = self.curve()
|
|
1483
|
+
P = self
|
|
1484
|
+
nP = -P
|
|
1485
|
+
P_is_2_torsion = (P == nP)
|
|
1486
|
+
|
|
1487
|
+
# If self is the 0, then self is a solution, and the correct
|
|
1488
|
+
# poly is the m'th division polynomial
|
|
1489
|
+
if P == 0:
|
|
1490
|
+
ans.append(P)
|
|
1491
|
+
g = E.division_polynomial(m)
|
|
1492
|
+
else:
|
|
1493
|
+
# The poly g here is 0 at x(Q) iff x(m*Q) = x(P).
|
|
1494
|
+
g = E._multiple_x_numerator(m) - P[0]*E._multiple_x_denominator(m)
|
|
1495
|
+
|
|
1496
|
+
# When 2*P=0, then -Q is a solution iff Q is. For even m,
|
|
1497
|
+
# no 2-torsion point is a solution, so that g is the
|
|
1498
|
+
# square of a polynomial g1 of degree m^2/2, and each root
|
|
1499
|
+
# of g1 leads to a pair of solutions Q, -Q to m*Q=P. For
|
|
1500
|
+
# odd m, P itself is the only 2-torsion solution, so g has
|
|
1501
|
+
# the form (x-x(P))*g1(x)^2 where g1 has degree (m^2-1)/2
|
|
1502
|
+
# and each root of g1 leads to a pair Q, -Q.
|
|
1503
|
+
|
|
1504
|
+
if P_is_2_torsion:
|
|
1505
|
+
if m % 2 == 0:
|
|
1506
|
+
# This computes g.sqrt() which is not implemented
|
|
1507
|
+
g = g.gcd(g.derivative())*g.leading_coefficient().sqrt()
|
|
1508
|
+
|
|
1509
|
+
# When 2*P!=0, then for each solution Q to m*Q=P, -Q is
|
|
1510
|
+
# not a solution (and points of order 2 are not
|
|
1511
|
+
# solutions). Hence the roots of g are distinct and each
|
|
1512
|
+
# gives rise to precisely one solution Q.
|
|
1513
|
+
|
|
1514
|
+
else:
|
|
1515
|
+
g0 = g.variables()[0] - P[0]
|
|
1516
|
+
g = g // g0
|
|
1517
|
+
g = g.gcd(g.derivative())*g.leading_coefficient().sqrt()
|
|
1518
|
+
g = g0*g
|
|
1519
|
+
|
|
1520
|
+
if poly_only:
|
|
1521
|
+
return g
|
|
1522
|
+
|
|
1523
|
+
for x in g.roots(multiplicities=False):
|
|
1524
|
+
if E.is_x_coord(x):
|
|
1525
|
+
# Make a point on the curve with this x coordinate.
|
|
1526
|
+
Q = E.lift_x(x)
|
|
1527
|
+
nQ = -Q
|
|
1528
|
+
mQ = m*Q
|
|
1529
|
+
# if P==-P then Q works iff -Q works, so we include
|
|
1530
|
+
# both unless they are equal:
|
|
1531
|
+
if P_is_2_torsion:
|
|
1532
|
+
if mQ == P:
|
|
1533
|
+
ans.append(Q)
|
|
1534
|
+
if nQ != Q:
|
|
1535
|
+
ans.append(nQ)
|
|
1536
|
+
else:
|
|
1537
|
+
# P is not 2-torsion so at most one of Q, -Q works
|
|
1538
|
+
# and we must try both:
|
|
1539
|
+
if mQ == P:
|
|
1540
|
+
ans.append(Q)
|
|
1541
|
+
elif mQ == nP:
|
|
1542
|
+
ans.append(nQ)
|
|
1543
|
+
|
|
1544
|
+
if not ans:
|
|
1545
|
+
return ans
|
|
1546
|
+
|
|
1547
|
+
# set orders of points found when self's order is known:
|
|
1548
|
+
if self.is_zero():
|
|
1549
|
+
self._order = Integer(1)
|
|
1550
|
+
try:
|
|
1551
|
+
n = self._order # do not compute, just use if already known
|
|
1552
|
+
if n == oo:
|
|
1553
|
+
for Q in ans:
|
|
1554
|
+
Q._order = oo
|
|
1555
|
+
else:
|
|
1556
|
+
mfac = m.factor()
|
|
1557
|
+
for Q in ans:
|
|
1558
|
+
R = n * Q
|
|
1559
|
+
Q._order = n * generic.order_from_multiple(R, m, factorization=mfac, operation='+')
|
|
1560
|
+
except AttributeError: # do nothing about order if self's order unknown
|
|
1561
|
+
pass
|
|
1562
|
+
|
|
1563
|
+
# Finally, sort and return
|
|
1564
|
+
ans.sort()
|
|
1565
|
+
return ans
|
|
1566
|
+
|
|
1567
|
+
def _divide_out(self, p):
|
|
1568
|
+
r"""
|
|
1569
|
+
Return `(Q,k)` where `p^kQ` == ``self`` and `Q` cannot be divided by `p`.
|
|
1570
|
+
|
|
1571
|
+
.. WARNING::
|
|
1572
|
+
|
|
1573
|
+
It is up to the caller to make sure that this does not loop
|
|
1574
|
+
endlessly. It is used in
|
|
1575
|
+
``EllipticCurve_generic._p_primary_torsion_basis()``, when
|
|
1576
|
+
``self`` will always have (finite) order which is a power of `p`,
|
|
1577
|
+
so that the order of `Q` increases by a factor of `p` at each
|
|
1578
|
+
stage.
|
|
1579
|
+
|
|
1580
|
+
Since it will clearly be in danger of looping when
|
|
1581
|
+
``self.is_zero()``, this case is caught, but otherwise caveat user.
|
|
1582
|
+
|
|
1583
|
+
EXAMPLES::
|
|
1584
|
+
|
|
1585
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1586
|
+
sage: E = EllipticCurve('37a1')
|
|
1587
|
+
sage: P = E([0, 0])
|
|
1588
|
+
sage: R = 12*P
|
|
1589
|
+
sage: R._divide_out(2)
|
|
1590
|
+
((-1 : -1 : 1), 2)
|
|
1591
|
+
sage: R._divide_out(3)
|
|
1592
|
+
((2 : -3 : 1), 1)
|
|
1593
|
+
sage: R._divide_out(5)
|
|
1594
|
+
((1357/841 : 28888/24389 : 1), 0)
|
|
1595
|
+
sage: R._divide_out(12)
|
|
1596
|
+
Traceback (most recent call last):
|
|
1597
|
+
...
|
|
1598
|
+
ValueError: p (=12) should be prime.
|
|
1599
|
+
"""
|
|
1600
|
+
p = Integer(p)
|
|
1601
|
+
if not p.is_prime():
|
|
1602
|
+
raise ValueError("p (=%s) should be prime." % p)
|
|
1603
|
+
|
|
1604
|
+
if self.is_zero():
|
|
1605
|
+
raise ValueError("self must not be 0.")
|
|
1606
|
+
|
|
1607
|
+
k = 0
|
|
1608
|
+
Q = self
|
|
1609
|
+
pts = Q.division_points(p)
|
|
1610
|
+
while pts:
|
|
1611
|
+
Q = pts[0]
|
|
1612
|
+
k += 1
|
|
1613
|
+
pts = Q.division_points(p)
|
|
1614
|
+
return (Q, k)
|
|
1615
|
+
|
|
1616
|
+
def set_order(self, value=None, *, multiple=None, check=True):
|
|
1617
|
+
r"""
|
|
1618
|
+
Set the cached order of this point (i.e., the value of
|
|
1619
|
+
``self._order``) to the given ``value``.
|
|
1620
|
+
|
|
1621
|
+
Alternatively, when ``multiple`` is given, this method will
|
|
1622
|
+
first run :func:`~sage.groups.generic.order_from_multiple`
|
|
1623
|
+
to determine the exact order from the given multiple of the
|
|
1624
|
+
point order, then cache the result.
|
|
1625
|
+
|
|
1626
|
+
Use this when you know a priori the order of this point, or
|
|
1627
|
+
a multiple of the order, to avoid a potentially expensive
|
|
1628
|
+
order calculation.
|
|
1629
|
+
|
|
1630
|
+
INPUT:
|
|
1631
|
+
|
|
1632
|
+
- ``value`` -- positive integer
|
|
1633
|
+
- ``multiple`` -- positive integer; mutually exclusive with ``value``
|
|
1634
|
+
|
|
1635
|
+
OUTPUT: none
|
|
1636
|
+
|
|
1637
|
+
EXAMPLES:
|
|
1638
|
+
|
|
1639
|
+
This example illustrates basic usage.
|
|
1640
|
+
|
|
1641
|
+
::
|
|
1642
|
+
|
|
1643
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1644
|
+
sage: G = E(5, 0)
|
|
1645
|
+
sage: G.set_order(2)
|
|
1646
|
+
sage: 2*G
|
|
1647
|
+
(0 : 1 : 0)
|
|
1648
|
+
sage: G = E(0, 6)
|
|
1649
|
+
sage: G.set_order(multiple=12)
|
|
1650
|
+
sage: G._order
|
|
1651
|
+
3
|
|
1652
|
+
|
|
1653
|
+
We now give a more interesting case, the NIST-P521 curve. Its
|
|
1654
|
+
order is too big to calculate with Sage, and takes a long time
|
|
1655
|
+
using other packages, so it is very useful here.
|
|
1656
|
+
|
|
1657
|
+
::
|
|
1658
|
+
|
|
1659
|
+
sage: # needs sage.rings.finite_rings
|
|
1660
|
+
sage: p = 2^521 - 1
|
|
1661
|
+
sage: prev_proof_state = proof.arithmetic()
|
|
1662
|
+
sage: proof.arithmetic(False) # turn off primality checking
|
|
1663
|
+
sage: F = GF(p)
|
|
1664
|
+
sage: A = p - 3
|
|
1665
|
+
sage: B = 1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
|
|
1666
|
+
sage: q = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449
|
|
1667
|
+
sage: E = EllipticCurve([F(A), F(B)])
|
|
1668
|
+
sage: G = E.random_point()
|
|
1669
|
+
sage: G.set_order(q)
|
|
1670
|
+
sage: G.order() * G # This takes practically no time.
|
|
1671
|
+
(0 : 1 : 0)
|
|
1672
|
+
sage: proof.arithmetic(prev_proof_state) # restore state
|
|
1673
|
+
|
|
1674
|
+
Using ``.set_order()`` with a ``multiple=`` argument can
|
|
1675
|
+
be used to compute a point's order *significantly* faster
|
|
1676
|
+
than calling :meth:`order` if the point is already known
|
|
1677
|
+
to be `m`-torsion::
|
|
1678
|
+
|
|
1679
|
+
sage: F.<a> = GF((10007, 23))
|
|
1680
|
+
sage: E = EllipticCurve(F, [9,9])
|
|
1681
|
+
sage: n = E.order()
|
|
1682
|
+
sage: m = 5 * 47 * 139 * 1427 * 2027 * 4831 * 275449 * 29523031
|
|
1683
|
+
sage: assert m.divides(n)
|
|
1684
|
+
sage: P = n/m * E.lift_x(6747+a)
|
|
1685
|
+
sage: assert m * P == 0
|
|
1686
|
+
sage: P.set_order(multiple=m) # compute exact order
|
|
1687
|
+
sage: factor(m // P.order()) # order is now cached
|
|
1688
|
+
47 * 139
|
|
1689
|
+
|
|
1690
|
+
The algorithm used internally for this functionality is
|
|
1691
|
+
:meth:`~sage.groups.generic.order_from_multiple`.
|
|
1692
|
+
Indeed, simply calling :meth:`order` on ``P`` would take
|
|
1693
|
+
much longer since factoring ``n`` is fairly expensive::
|
|
1694
|
+
|
|
1695
|
+
sage: n == m * 6670822796985115651 * 441770032618665681677 * 9289973478285634606114927
|
|
1696
|
+
True
|
|
1697
|
+
|
|
1698
|
+
It is an error to pass a ``value`` equal to `0`::
|
|
1699
|
+
|
|
1700
|
+
sage: # needs sage.rings.finite_rings
|
|
1701
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1702
|
+
sage: G = E.random_point()
|
|
1703
|
+
sage: G.set_order(0)
|
|
1704
|
+
Traceback (most recent call last):
|
|
1705
|
+
...
|
|
1706
|
+
ValueError: Value 0 illegal for point order
|
|
1707
|
+
sage: G.set_order(1000)
|
|
1708
|
+
Traceback (most recent call last):
|
|
1709
|
+
...
|
|
1710
|
+
ValueError: Value 1000 illegal: outside max Hasse bound
|
|
1711
|
+
|
|
1712
|
+
It is also very likely an error to pass a value which is not the actual
|
|
1713
|
+
order of this point. How unlikely is determined by the factorization of
|
|
1714
|
+
the actual order, and the actual group structure::
|
|
1715
|
+
|
|
1716
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1717
|
+
sage: G = E(5, 0) # G has order 2
|
|
1718
|
+
sage: G.set_order(11)
|
|
1719
|
+
Traceback (most recent call last):
|
|
1720
|
+
...
|
|
1721
|
+
ValueError: Value 11 illegal: 11 * (5 : 0 : 1) is not the identity
|
|
1722
|
+
|
|
1723
|
+
However, ``set_order`` can be fooled. For instance, the order
|
|
1724
|
+
can be set to a multiple the actual order::
|
|
1725
|
+
|
|
1726
|
+
sage: E = EllipticCurve(GF(7), [0, 1]) # This curve has order 12
|
|
1727
|
+
sage: G = E(5, 0) # G has order 2
|
|
1728
|
+
sage: G.set_order(8)
|
|
1729
|
+
sage: G.order()
|
|
1730
|
+
8
|
|
1731
|
+
|
|
1732
|
+
TESTS:
|
|
1733
|
+
|
|
1734
|
+
Check that some invalid inputs are caught::
|
|
1735
|
+
|
|
1736
|
+
sage: E = EllipticCurve(GF(101), [5,5])
|
|
1737
|
+
sage: P = E.lift_x(11)
|
|
1738
|
+
sage: P.set_order(17, multiple=119)
|
|
1739
|
+
Traceback (most recent call last):
|
|
1740
|
+
...
|
|
1741
|
+
ValueError: cannot pass both value and multiple
|
|
1742
|
+
sage: P.set_order(17)
|
|
1743
|
+
sage: P.set_order(multiple=119+1)
|
|
1744
|
+
Traceback (most recent call last):
|
|
1745
|
+
...
|
|
1746
|
+
ValueError: previously cached order 17 does not divide given multiple 120
|
|
1747
|
+
sage: P.set_order(119)
|
|
1748
|
+
Traceback (most recent call last):
|
|
1749
|
+
...
|
|
1750
|
+
ValueError: value 119 contradicts previously cached order 17
|
|
1751
|
+
|
|
1752
|
+
AUTHORS:
|
|
1753
|
+
|
|
1754
|
+
- Mariah Lenox (2011-02-16)
|
|
1755
|
+
- Lorenz Panny (2022): add ``multiple=`` option
|
|
1756
|
+
"""
|
|
1757
|
+
if multiple is not None:
|
|
1758
|
+
if value is not None:
|
|
1759
|
+
raise ValueError('cannot pass both value and multiple')
|
|
1760
|
+
|
|
1761
|
+
if hasattr(self, '_order'): # already known
|
|
1762
|
+
if check and not self._order.divides(multiple):
|
|
1763
|
+
raise ValueError(f'previously cached order {self._order} does not divide given multiple {multiple}')
|
|
1764
|
+
return
|
|
1765
|
+
|
|
1766
|
+
from sage.groups.generic import order_from_multiple
|
|
1767
|
+
value = order_from_multiple(self, multiple, check=check)
|
|
1768
|
+
check = False
|
|
1769
|
+
|
|
1770
|
+
value = Integer(value)
|
|
1771
|
+
|
|
1772
|
+
if check:
|
|
1773
|
+
if value <= 0:
|
|
1774
|
+
raise ValueError('Value %s illegal for point order' % value)
|
|
1775
|
+
E = self.curve()
|
|
1776
|
+
q = E.base_ring().cardinality()
|
|
1777
|
+
if q < oo:
|
|
1778
|
+
_, hi = Hasse_bounds(q)
|
|
1779
|
+
if value > hi:
|
|
1780
|
+
raise ValueError('Value %s illegal: outside max Hasse bound' % value)
|
|
1781
|
+
if value * self != E(0):
|
|
1782
|
+
raise ValueError('Value %s illegal: %s * %s is not the identity' % (value, value, self))
|
|
1783
|
+
if hasattr(self, '_order') and self._order != value: # already known
|
|
1784
|
+
raise ValueError(f'value {value} contradicts previously cached order {self._order}')
|
|
1785
|
+
|
|
1786
|
+
self._order = value
|
|
1787
|
+
|
|
1788
|
+
# ############################# end ################################
|
|
1789
|
+
|
|
1790
|
+
def _line_(self, R, Q):
|
|
1791
|
+
r"""
|
|
1792
|
+
Compute the value at `Q` of a straight line through points
|
|
1793
|
+
``self`` and `R`.
|
|
1794
|
+
|
|
1795
|
+
INPUT:
|
|
1796
|
+
|
|
1797
|
+
- ``R``, ``Q`` -- points on ``self.curve()`` with `Q` nonzero
|
|
1798
|
+
|
|
1799
|
+
OUTPUT:
|
|
1800
|
+
|
|
1801
|
+
An element of the base field ``self.curve().base_field()``.
|
|
1802
|
+
A :exc:`ValueError` is raised if `Q` is zero.
|
|
1803
|
+
|
|
1804
|
+
EXAMPLES::
|
|
1805
|
+
|
|
1806
|
+
sage: # needs sage.rings.finite_rings
|
|
1807
|
+
sage: F.<a> = GF((2,5))
|
|
1808
|
+
sage: E = EllipticCurve(F,[0,0,1,1,1])
|
|
1809
|
+
sage: P = E(a^4 + 1, a^3)
|
|
1810
|
+
sage: Q = E(a^4, a^4 + a^3)
|
|
1811
|
+
sage: O = E(0)
|
|
1812
|
+
sage: P._line_(P,-2*P) == 0
|
|
1813
|
+
True
|
|
1814
|
+
sage: P._line_(Q,-(P+Q)) == 0
|
|
1815
|
+
True
|
|
1816
|
+
sage: O._line_(O,Q) == F(1)
|
|
1817
|
+
True
|
|
1818
|
+
sage: P._line_(O,Q) == a^4 - a^4 + 1
|
|
1819
|
+
True
|
|
1820
|
+
sage: P._line_(13*P,Q) == a^4
|
|
1821
|
+
True
|
|
1822
|
+
sage: P._line_(P,Q) == a^4 + a^3 + a^2 + 1
|
|
1823
|
+
True
|
|
1824
|
+
|
|
1825
|
+
See :issue:`7116`::
|
|
1826
|
+
|
|
1827
|
+
sage: P._line_ (Q,O) # needs sage.rings.finite_rings
|
|
1828
|
+
Traceback (most recent call last):
|
|
1829
|
+
...
|
|
1830
|
+
ValueError: Q must be nonzero.
|
|
1831
|
+
|
|
1832
|
+
.. NOTE::
|
|
1833
|
+
|
|
1834
|
+
This function is used in _miller_ algorithm.
|
|
1835
|
+
|
|
1836
|
+
AUTHORS:
|
|
1837
|
+
|
|
1838
|
+
- David Hansen (2009-01-25)
|
|
1839
|
+
"""
|
|
1840
|
+
if Q.is_zero():
|
|
1841
|
+
raise ValueError("Q must be nonzero.")
|
|
1842
|
+
|
|
1843
|
+
if self.is_zero() or R.is_zero():
|
|
1844
|
+
if self == R:
|
|
1845
|
+
return self.curve().base_field().one()
|
|
1846
|
+
if self.is_zero():
|
|
1847
|
+
return Q[0] - R[0]
|
|
1848
|
+
if R.is_zero():
|
|
1849
|
+
return Q[0] - self[0]
|
|
1850
|
+
elif self != R:
|
|
1851
|
+
if self[0] == R[0]:
|
|
1852
|
+
return Q[0] - self[0]
|
|
1853
|
+
else:
|
|
1854
|
+
l = (R[1] - self[1])/(R[0] - self[0])
|
|
1855
|
+
return Q[1] - self[1] - l * (Q[0] - self[0])
|
|
1856
|
+
else:
|
|
1857
|
+
a1, a2, a3, a4, a6 = self.curve().a_invariants()
|
|
1858
|
+
numerator = (3*self[0]**2 + 2*a2*self[0] + a4 - a1*self[1])
|
|
1859
|
+
denominator = (2*self[1] + a1*self[0] + a3)
|
|
1860
|
+
if denominator == 0:
|
|
1861
|
+
return Q[0] - self[0]
|
|
1862
|
+
else:
|
|
1863
|
+
l = numerator/denominator
|
|
1864
|
+
return Q[1] - self[1] - l * (Q[0] - self[0])
|
|
1865
|
+
|
|
1866
|
+
def _miller_(self, Q, n):
|
|
1867
|
+
r"""
|
|
1868
|
+
Return the value at `Q` of the rational function `f_{n,P}`, where the
|
|
1869
|
+
divisor of `f_{n,P}` is `n[P]-[nP]-(n-1)[O]`.
|
|
1870
|
+
|
|
1871
|
+
INPUT:
|
|
1872
|
+
|
|
1873
|
+
- ``Q`` -- a nonzero point on ``self.curve()``
|
|
1874
|
+
|
|
1875
|
+
- ``n`` -- nonzero integer; if `n<0` then return `Q`
|
|
1876
|
+
evaluated at `1/(v_{nP}*f_{n,P})` (used in the ate pairing)
|
|
1877
|
+
|
|
1878
|
+
OUTPUT:
|
|
1879
|
+
|
|
1880
|
+
An element in the base field ``self.curve().base_field()``.
|
|
1881
|
+
A :exc:`ValueError` is raised if `Q` is zero.
|
|
1882
|
+
|
|
1883
|
+
EXAMPLES::
|
|
1884
|
+
|
|
1885
|
+
sage: # needs sage.rings.finite_rings
|
|
1886
|
+
sage: F.<a> = GF((2,5))
|
|
1887
|
+
sage: E = EllipticCurve(F, [0,0,1,1,1])
|
|
1888
|
+
sage: P = E(a^4 + 1, a^3)
|
|
1889
|
+
sage: Fx.<b> = GF((2,(4*5)))
|
|
1890
|
+
sage: Ex = EllipticCurve(Fx, [0,0,1,1,1])
|
|
1891
|
+
sage: phi = Hom(F,Fx)(F.gen().minpoly().roots(Fx)[0][0])
|
|
1892
|
+
sage: Px = Ex(phi(P.x()), phi(P.y()))
|
|
1893
|
+
sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1,
|
|
1894
|
+
....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b)
|
|
1895
|
+
sage: Px._miller_(Qx,41) == b^17 + b^13 + b^12 + b^9 + b^8 + b^6 + b^4 + 1
|
|
1896
|
+
True
|
|
1897
|
+
sage: Qx._miller_(Px,41) == b^13 + b^10 + b^8 + b^7 + b^6 + b^5
|
|
1898
|
+
True
|
|
1899
|
+
sage: P._miller_(E(0),41)
|
|
1900
|
+
Traceback (most recent call last):
|
|
1901
|
+
...
|
|
1902
|
+
ValueError: Q must be nonzero.
|
|
1903
|
+
|
|
1904
|
+
An example of even order::
|
|
1905
|
+
|
|
1906
|
+
sage: # needs sage.rings.finite_rings
|
|
1907
|
+
sage: F.<a> = GF((19,4))
|
|
1908
|
+
sage: E = EllipticCurve(F, [-1,0])
|
|
1909
|
+
sage: P = E(15*a^3 + 17*a^2 + 14*a + 13,16*a^3 + 7*a^2 + a + 18)
|
|
1910
|
+
sage: Q = E(10*a^3 + 16*a^2 + 4*a + 2, 6*a^3 + 4*a^2 + 3*a + 2)
|
|
1911
|
+
sage: x = P.weil_pairing(Q, 360)
|
|
1912
|
+
sage: x^360 == F(1)
|
|
1913
|
+
True
|
|
1914
|
+
|
|
1915
|
+
You can use the _miller_ function on linearly dependent
|
|
1916
|
+
points, but with the risk of a dividing with zero::
|
|
1917
|
+
|
|
1918
|
+
sage: Px._miller_(2*Px, 41) # needs sage.rings.finite_rings
|
|
1919
|
+
Traceback (most recent call last):
|
|
1920
|
+
...
|
|
1921
|
+
ZeroDivisionError: division by zero in finite field
|
|
1922
|
+
|
|
1923
|
+
A small example of embedding degree 6::
|
|
1924
|
+
|
|
1925
|
+
sage: # needs sage.rings.finite_rings
|
|
1926
|
+
sage: q = 401; F = GF(q); a = 146; b = 400; k = 6
|
|
1927
|
+
sage: E = EllipticCurve([F(a), F(b)])
|
|
1928
|
+
sage: R.<x> = F[]
|
|
1929
|
+
sage: K.<a> = GF(q^k, modulus=x^6 + 4*x^4 + 115*x^3 + 81*x^2 + 51*x + 3)
|
|
1930
|
+
sage: EK = E.base_extend(K)
|
|
1931
|
+
sage: P = E([F(338), F(227)])
|
|
1932
|
+
sage: Q_x = 333*a^5 + 391*a^4 + 160*a^3 + 335*a^2 + 71*a + 93
|
|
1933
|
+
sage: Q_y = 343*a^5 + 273*a^4 + 26*a^3 + 342*a^2 + 340*a + 210
|
|
1934
|
+
sage: Q = EK([Q_x, Q_y])
|
|
1935
|
+
sage: P._miller_(Q, 127)
|
|
1936
|
+
371*a^5 + 39*a^4 + 355*a^3 + 233*a^2 + 20*a + 275
|
|
1937
|
+
|
|
1938
|
+
A series of small examples and small torsions. We start with
|
|
1939
|
+
`n=1`, which is trivial: the function is the constant
|
|
1940
|
+
1::
|
|
1941
|
+
|
|
1942
|
+
sage: E = EllipticCurve([GF(7)(0), 2])
|
|
1943
|
+
sage: P = E(5, 1); Q = E(0, 3); I = E(0)
|
|
1944
|
+
sage: I._miller_(P, 1)
|
|
1945
|
+
1
|
|
1946
|
+
sage: I._miller_(Q, 1)
|
|
1947
|
+
1
|
|
1948
|
+
|
|
1949
|
+
A two-torsion example. In this case `f_{n,P}(Q) = x_Q - x_P`::
|
|
1950
|
+
|
|
1951
|
+
sage: E = EllipticCurve([GF(7)(-1), 0])
|
|
1952
|
+
sage: P = E(0,0); Q = E(1, 0);
|
|
1953
|
+
sage: P._miller_(P, 2)
|
|
1954
|
+
0
|
|
1955
|
+
sage: Q._miller_(Q, 2)
|
|
1956
|
+
0
|
|
1957
|
+
sage: P._miller_(Q, 2)
|
|
1958
|
+
1
|
|
1959
|
+
sage: Q._miller_(P, 2)
|
|
1960
|
+
6
|
|
1961
|
+
|
|
1962
|
+
A three-torsion example::
|
|
1963
|
+
|
|
1964
|
+
sage: E = EllipticCurve([GF(7)(0), 2])
|
|
1965
|
+
sage: P = E(5, 1); Q = E(0, 3);
|
|
1966
|
+
sage: P._miller_(Q, 3)
|
|
1967
|
+
4
|
|
1968
|
+
|
|
1969
|
+
A 4-torsion example::
|
|
1970
|
+
|
|
1971
|
+
sage: E = EllipticCurve([GF(7)(-1), 0])
|
|
1972
|
+
sage: P = E(5, 1); Q = E(4, 2)
|
|
1973
|
+
sage: P._miller_(Q, 4)
|
|
1974
|
+
3
|
|
1975
|
+
|
|
1976
|
+
A 5-torsion example::
|
|
1977
|
+
|
|
1978
|
+
sage: E = EllipticCurve([GF(7)(-1), 4])
|
|
1979
|
+
sage: P = E(4, 1); Q = E(6, 5)
|
|
1980
|
+
sage: P._miller_(Q, 5)
|
|
1981
|
+
1
|
|
1982
|
+
|
|
1983
|
+
A 6-torsion example::
|
|
1984
|
+
|
|
1985
|
+
sage: E = EllipticCurve([GF(7)(3), 1])
|
|
1986
|
+
sage: P = E(5, 1); Q = E(3, 3)
|
|
1987
|
+
sage: P._miller_(Q, 6)
|
|
1988
|
+
5
|
|
1989
|
+
|
|
1990
|
+
An example which is part of an ate pairing calculation. The trace of
|
|
1991
|
+
the curve is negative, so it should exercise the `n<0` case in the
|
|
1992
|
+
code::
|
|
1993
|
+
|
|
1994
|
+
sage: # needs sage.rings.finite_rings
|
|
1995
|
+
sage: p = 2017; A = 1; B = 30; r = 29; t = -70; k = 7
|
|
1996
|
+
sage: F = GF(p); R.<x> = F[]
|
|
1997
|
+
sage: E = EllipticCurve([F(A), F(B)]); P = E(369, 716)
|
|
1998
|
+
sage: K.<a> = GF(p^k, modulus=x^k+2); EK = E.base_extend(K)
|
|
1999
|
+
sage: Qx = 1226*a^6 + 1778*a^5 + 660*a^4 + 1791*a^3 + 1750*a^2 + 867*a + 770
|
|
2000
|
+
sage: Qy = 1764*a^6 + 198*a^5 + 1206*a^4 + 406*a^3 + 1200*a^2 + 273*a + 1712
|
|
2001
|
+
sage: Q = EK(Qx, Qy)
|
|
2002
|
+
sage: Q._miller_(P, t - 1)
|
|
2003
|
+
1311*a^6 + 1362*a^5 + 1177*a^4 + 807*a^3 + 1331*a^2 + 1530*a + 1931
|
|
2004
|
+
|
|
2005
|
+
ALGORITHM:
|
|
2006
|
+
|
|
2007
|
+
Double-and-add. See also [Mil2004]_.
|
|
2008
|
+
|
|
2009
|
+
AUTHORS:
|
|
2010
|
+
|
|
2011
|
+
- David Hansen (2009-01-25)
|
|
2012
|
+
- Mariah Lenox (2011-03-07) -- Added more doctests and support for
|
|
2013
|
+
negative n.
|
|
2014
|
+
"""
|
|
2015
|
+
if Q.is_zero():
|
|
2016
|
+
raise ValueError("Q must be nonzero.")
|
|
2017
|
+
if n.is_zero():
|
|
2018
|
+
raise ValueError("n must be nonzero.")
|
|
2019
|
+
n_is_negative = False
|
|
2020
|
+
if n < 0:
|
|
2021
|
+
n = n.abs()
|
|
2022
|
+
n_is_negative = True
|
|
2023
|
+
|
|
2024
|
+
one = self.curve().base_field().one()
|
|
2025
|
+
t = one
|
|
2026
|
+
V = self
|
|
2027
|
+
nbin = n.bits()
|
|
2028
|
+
i = n.nbits() - 2
|
|
2029
|
+
while i > -1:
|
|
2030
|
+
S = 2*V
|
|
2031
|
+
ell = V._line_(V, Q)
|
|
2032
|
+
vee = S._line_(-S, Q)
|
|
2033
|
+
t = (t**2)*(ell/vee)
|
|
2034
|
+
V = S
|
|
2035
|
+
if nbin[i] == 1:
|
|
2036
|
+
S = V+self
|
|
2037
|
+
ell = V._line_(self, Q)
|
|
2038
|
+
vee = S._line_(-S, Q)
|
|
2039
|
+
t = t*(ell/vee)
|
|
2040
|
+
V = S
|
|
2041
|
+
i = i-1
|
|
2042
|
+
if n_is_negative:
|
|
2043
|
+
vee = V._line_(-V, Q)
|
|
2044
|
+
t = 1/(t*vee)
|
|
2045
|
+
return t
|
|
2046
|
+
|
|
2047
|
+
def weil_pairing(self, Q, n, algorithm=None):
|
|
2048
|
+
r"""
|
|
2049
|
+
Compute the Weil pairing of this point with another point `Q`
|
|
2050
|
+
on the same curve.
|
|
2051
|
+
|
|
2052
|
+
INPUT:
|
|
2053
|
+
|
|
2054
|
+
- ``Q`` -- another point on the same curve as ``self``
|
|
2055
|
+
|
|
2056
|
+
- ``n`` -- integer `n` such that `nP = nQ = (0:1:0)`, where
|
|
2057
|
+
`P` is ``self``
|
|
2058
|
+
|
|
2059
|
+
- ``algorithm`` -- (default: ``None``) choices are ``'pari'``
|
|
2060
|
+
and ``'sage'``. PARI is usually significantly faster, but it
|
|
2061
|
+
only works over finite fields. When ``None`` is given, a
|
|
2062
|
+
suitable algorithm is chosen automatically.
|
|
2063
|
+
|
|
2064
|
+
OUTPUT: an `n`-th root of unity in the base field of the curve
|
|
2065
|
+
|
|
2066
|
+
EXAMPLES::
|
|
2067
|
+
|
|
2068
|
+
sage: # needs sage.rings.finite_rings
|
|
2069
|
+
sage: F.<a> = GF((2,5))
|
|
2070
|
+
sage: E = EllipticCurve(F, [0,0,1,1,1])
|
|
2071
|
+
sage: P = E(a^4 + 1, a^3)
|
|
2072
|
+
sage: Fx.<b> = GF((2, 4*5))
|
|
2073
|
+
sage: Ex = EllipticCurve(Fx, [0,0,1,1,1])
|
|
2074
|
+
sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0])
|
|
2075
|
+
sage: Px = Ex(phi(P.x()), phi(P.y()))
|
|
2076
|
+
sage: O = Ex(0)
|
|
2077
|
+
sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1,
|
|
2078
|
+
....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b)
|
|
2079
|
+
sage: Px.weil_pairing(Qx, 41) == b^19 + b^15 + b^9 + b^8 + b^6 + b^4 + b^3 + b^2 + 1
|
|
2080
|
+
True
|
|
2081
|
+
sage: Px.weil_pairing(17*Px, 41) == Fx(1)
|
|
2082
|
+
True
|
|
2083
|
+
sage: Px.weil_pairing(O, 41) == Fx(1)
|
|
2084
|
+
True
|
|
2085
|
+
|
|
2086
|
+
An error is raised if either point is not `n`-torsion::
|
|
2087
|
+
|
|
2088
|
+
sage: Px.weil_pairing(O, 40) # needs sage.rings.finite_rings
|
|
2089
|
+
Traceback (most recent call last):
|
|
2090
|
+
...
|
|
2091
|
+
ValueError: points must both be n-torsion
|
|
2092
|
+
|
|
2093
|
+
A larger example (see :issue:`4964`)::
|
|
2094
|
+
|
|
2095
|
+
sage: # needs sage.rings.finite_rings
|
|
2096
|
+
sage: P, Q = EllipticCurve(GF((19,4),'a'), [-1,0]).gens()
|
|
2097
|
+
sage: P.order(), Q.order()
|
|
2098
|
+
(360, 360)
|
|
2099
|
+
sage: z = P.weil_pairing(Q, 360)
|
|
2100
|
+
sage: z.multiplicative_order()
|
|
2101
|
+
360
|
|
2102
|
+
|
|
2103
|
+
Another larger example::
|
|
2104
|
+
|
|
2105
|
+
sage: F = GF(65537^2, modulus=[3,-1,1], name='a')
|
|
2106
|
+
sage: F.inject_variables()
|
|
2107
|
+
Defining a
|
|
2108
|
+
sage: E = EllipticCurve(F, [0,1])
|
|
2109
|
+
sage: P = E(22, 28891)
|
|
2110
|
+
sage: Q = E(-93, 2728*a + 64173)
|
|
2111
|
+
sage: P.weil_pairing(Q, 7282, algorithm='sage')
|
|
2112
|
+
53278*a + 36700
|
|
2113
|
+
|
|
2114
|
+
An example over a number field::
|
|
2115
|
+
|
|
2116
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
2117
|
+
sage: E = EllipticCurve('11a1').change_ring(CyclotomicField(5))
|
|
2118
|
+
sage: P, Q = E.torsion_subgroup().gens()
|
|
2119
|
+
sage: P, Q = (P.element(), Q.element())
|
|
2120
|
+
sage: (P.order(), Q.order())
|
|
2121
|
+
(5, 5)
|
|
2122
|
+
sage: P.weil_pairing(Q, 5)
|
|
2123
|
+
zeta5^2
|
|
2124
|
+
sage: Q.weil_pairing(P, 5)
|
|
2125
|
+
zeta5^3
|
|
2126
|
+
|
|
2127
|
+
TESTS:
|
|
2128
|
+
|
|
2129
|
+
Check that the original Sage implementation still works and
|
|
2130
|
+
that the result coincides with the PARI implementation::
|
|
2131
|
+
|
|
2132
|
+
sage: # needs sage.rings.finite_rings
|
|
2133
|
+
sage: GF(65537^2).inject_variables()
|
|
2134
|
+
Defining z2
|
|
2135
|
+
sage: E = EllipticCurve(GF(65537^2), [0,1])
|
|
2136
|
+
sage: R, S = E.torsion_basis(7282)
|
|
2137
|
+
sage: a, b = ZZ.random_element(), ZZ.random_element()
|
|
2138
|
+
sage: P = a*R + b*S
|
|
2139
|
+
sage: c, d = ZZ.random_element(), ZZ.random_element()
|
|
2140
|
+
sage: Q = c*R + d*S
|
|
2141
|
+
sage: P.weil_pairing(Q, 7282, algorithm='sage') == P.weil_pairing(Q, 7282, algorithm='pari')
|
|
2142
|
+
True
|
|
2143
|
+
|
|
2144
|
+
Passing an unknown ``algorithm=`` argument should fail::
|
|
2145
|
+
|
|
2146
|
+
sage: P.weil_pairing(Q, 7282, algorithm='_invalid_') # needs sage.rings.finite_rings
|
|
2147
|
+
Traceback (most recent call last):
|
|
2148
|
+
...
|
|
2149
|
+
ValueError: unknown algorithm
|
|
2150
|
+
|
|
2151
|
+
ALGORITHM:
|
|
2152
|
+
|
|
2153
|
+
- For ``algorithm='pari'``: :pari:`ellweilpairing`.
|
|
2154
|
+
|
|
2155
|
+
- For ``algorithm='sage'``:
|
|
2156
|
+
Implemented using Proposition 8 in [Mil2004]_. The value 1 is
|
|
2157
|
+
returned for linearly dependent input points. This condition
|
|
2158
|
+
is caught via a :exc:`ZeroDivisionError`, since the use of a
|
|
2159
|
+
discrete logarithm test for linear dependence is much too slow
|
|
2160
|
+
for large `n`.
|
|
2161
|
+
|
|
2162
|
+
AUTHORS:
|
|
2163
|
+
|
|
2164
|
+
- David Hansen (2009-01-25)
|
|
2165
|
+
- Lorenz Panny (2022): ``algorithm='pari'``
|
|
2166
|
+
"""
|
|
2167
|
+
P = self
|
|
2168
|
+
E = P.curve()
|
|
2169
|
+
|
|
2170
|
+
if Q.curve() is not E:
|
|
2171
|
+
raise ValueError("points must both be on the same curve")
|
|
2172
|
+
|
|
2173
|
+
if algorithm is None:
|
|
2174
|
+
if E.base_field().is_finite():
|
|
2175
|
+
algorithm = 'pari'
|
|
2176
|
+
else:
|
|
2177
|
+
algorithm = 'sage'
|
|
2178
|
+
|
|
2179
|
+
if algorithm == 'pari':
|
|
2180
|
+
if pari.ellmul(E,P,n) != [0] or pari.ellmul(E,Q,n) != [0]:
|
|
2181
|
+
raise ValueError("points must both be n-torsion")
|
|
2182
|
+
return E.base_field()(pari.ellweilpairing(E, P, Q, n))
|
|
2183
|
+
|
|
2184
|
+
if algorithm != 'sage':
|
|
2185
|
+
raise ValueError('unknown algorithm')
|
|
2186
|
+
|
|
2187
|
+
# Test if P, Q are both in E[n]
|
|
2188
|
+
if n*P or n*Q:
|
|
2189
|
+
raise ValueError("points must both be n-torsion")
|
|
2190
|
+
|
|
2191
|
+
one = E.base_field().one()
|
|
2192
|
+
|
|
2193
|
+
# Case where P = Q
|
|
2194
|
+
if P == Q:
|
|
2195
|
+
return one
|
|
2196
|
+
|
|
2197
|
+
# Case where P = O or Q = O
|
|
2198
|
+
if P.is_zero() or Q.is_zero():
|
|
2199
|
+
return one
|
|
2200
|
+
|
|
2201
|
+
# The non-trivial case P != Q
|
|
2202
|
+
|
|
2203
|
+
# Note (2010-12-29): The following code block should not be
|
|
2204
|
+
# used. It attempts to reduce the pairing calculation to order
|
|
2205
|
+
# d = gcd(|P|,|Q|) instead of order n, but this approach is
|
|
2206
|
+
# counterproductive, since calculating |P| and |Q| is much
|
|
2207
|
+
# slower than calculating the pairing [BGN05].
|
|
2208
|
+
#
|
|
2209
|
+
# [BGN05] D. Boneh, E. Goh, and K. Nissim, "Evaluating 2-DNF
|
|
2210
|
+
# Formulas on Ciphertexts", TCC 2005, LNCS 3378, pp. 325-341.
|
|
2211
|
+
#
|
|
2212
|
+
# Reduction to order d = gcd(|P|,|Q|); value is a d'th root of unity
|
|
2213
|
+
# try:
|
|
2214
|
+
# nP = P.order()
|
|
2215
|
+
# except AttributeError:
|
|
2216
|
+
# nP = generic.order_from_multiple(P,n,operation='+')
|
|
2217
|
+
# try:
|
|
2218
|
+
# nQ = Q.order()
|
|
2219
|
+
# except AttributeError:
|
|
2220
|
+
# nQ = generic.order_from_multiple(Q,n,operation='+')
|
|
2221
|
+
# d = arith.gcd(nP,nQ)
|
|
2222
|
+
# if d==1:
|
|
2223
|
+
# return one
|
|
2224
|
+
#
|
|
2225
|
+
# P = (nP//d)*P # order d
|
|
2226
|
+
# Q = (nQ//d)*Q # order d
|
|
2227
|
+
# n = d
|
|
2228
|
+
|
|
2229
|
+
try:
|
|
2230
|
+
return ((-1)**n.test_bit(0))*(P._miller_(Q, n)/Q._miller_(P, n))
|
|
2231
|
+
except ZeroDivisionError:
|
|
2232
|
+
return one
|
|
2233
|
+
|
|
2234
|
+
def tate_pairing(self, Q, n, k, q=None):
|
|
2235
|
+
r"""
|
|
2236
|
+
Return Tate pairing of `n`-torsion point `P = self` and point `Q`.
|
|
2237
|
+
|
|
2238
|
+
The value returned is `f_{n,P}(Q)^e` where `f_{n,P}` is a function with
|
|
2239
|
+
divisor `n[P]-n[O].`. This is also known as the "modified Tate
|
|
2240
|
+
pairing". It is a well-defined bilinear map.
|
|
2241
|
+
|
|
2242
|
+
INPUT:
|
|
2243
|
+
|
|
2244
|
+
- ``P=self`` -- elliptic curve point having order `n`
|
|
2245
|
+
|
|
2246
|
+
- ``Q`` -- elliptic curve point on same curve as `P` (can be any order)
|
|
2247
|
+
|
|
2248
|
+
- ``n`` -- positive integer; order of `P`
|
|
2249
|
+
|
|
2250
|
+
- ``k`` -- positive integer; embedding degree
|
|
2251
|
+
|
|
2252
|
+
- ``q`` -- positive integer; size of base field (the "big"
|
|
2253
|
+
field is `GF(q^k)`. `q` needs to be set only if its value
|
|
2254
|
+
cannot be deduced.)
|
|
2255
|
+
|
|
2256
|
+
OUTPUT:
|
|
2257
|
+
|
|
2258
|
+
An `n`-th root of unity in the base field ``self.curve().base_field()``.
|
|
2259
|
+
|
|
2260
|
+
EXAMPLES:
|
|
2261
|
+
|
|
2262
|
+
A simple example, pairing a point with itself, and pairing a point with
|
|
2263
|
+
another rational point::
|
|
2264
|
+
|
|
2265
|
+
sage: p = 103; A = 1; B = 18; E = EllipticCurve(GF(p), [A, B])
|
|
2266
|
+
sage: P = E(33, 91); n = P.order(); n
|
|
2267
|
+
19
|
|
2268
|
+
sage: k = GF(n)(p).multiplicative_order(); k
|
|
2269
|
+
6
|
|
2270
|
+
sage: P.tate_pairing(P, n, k)
|
|
2271
|
+
1
|
|
2272
|
+
sage: Q = E(87, 51)
|
|
2273
|
+
sage: P.tate_pairing(Q, n, k)
|
|
2274
|
+
1
|
|
2275
|
+
sage: set_random_seed(35)
|
|
2276
|
+
sage: P.tate_pairing(P, n, k)
|
|
2277
|
+
1
|
|
2278
|
+
|
|
2279
|
+
We now let `Q` be a point on the same curve as above, but defined over
|
|
2280
|
+
the pairing extension field, and we also demonstrate the bilinearity of
|
|
2281
|
+
the pairing::
|
|
2282
|
+
|
|
2283
|
+
sage: # needs sage.rings.finite_rings
|
|
2284
|
+
sage: K.<a> = GF((p,k))
|
|
2285
|
+
sage: EK = E.base_extend(K); P = EK(P)
|
|
2286
|
+
sage: Qx = 69*a^5 + 96*a^4 + 22*a^3 + 86*a^2 + 6*a + 35
|
|
2287
|
+
sage: Qy = 34*a^5 + 24*a^4 + 16*a^3 + 41*a^2 + 4*a + 40
|
|
2288
|
+
sage: Q = EK(Qx, Qy);
|
|
2289
|
+
|
|
2290
|
+
Multiply by cofactor so Q has order n::
|
|
2291
|
+
|
|
2292
|
+
sage: # needs sage.rings.finite_rings
|
|
2293
|
+
sage: h = 551269674; Q = h*Q
|
|
2294
|
+
sage: P = EK(P); P.tate_pairing(Q, n, k)
|
|
2295
|
+
24*a^5 + 34*a^4 + 3*a^3 + 69*a^2 + 86*a + 45
|
|
2296
|
+
sage: s = Integer(randrange(1,n))
|
|
2297
|
+
sage: ans1 = (s*P).tate_pairing(Q, n, k)
|
|
2298
|
+
sage: ans2 = P.tate_pairing(s*Q, n, k)
|
|
2299
|
+
sage: ans3 = P.tate_pairing(Q, n, k)^s
|
|
2300
|
+
sage: ans1 == ans2 == ans3
|
|
2301
|
+
True
|
|
2302
|
+
sage: (ans1 != 1) and (ans1^n == 1)
|
|
2303
|
+
True
|
|
2304
|
+
|
|
2305
|
+
Here is an example of using the Tate pairing to compute the Weil
|
|
2306
|
+
pairing (using the same data as above)::
|
|
2307
|
+
|
|
2308
|
+
sage: # needs sage.rings.finite_rings
|
|
2309
|
+
sage: e = Integer((p^k-1)/n); e
|
|
2310
|
+
62844857712
|
|
2311
|
+
sage: P.weil_pairing(Q, n)^e
|
|
2312
|
+
94*a^5 + 99*a^4 + 29*a^3 + 45*a^2 + 57*a + 34
|
|
2313
|
+
sage: P.tate_pairing(Q, n, k) == P._miller_(Q, n)^e
|
|
2314
|
+
True
|
|
2315
|
+
sage: Q.tate_pairing(P, n, k) == Q._miller_(P, n)^e
|
|
2316
|
+
True
|
|
2317
|
+
sage: P.tate_pairing(Q, n, k)/Q.tate_pairing(P, n, k)
|
|
2318
|
+
94*a^5 + 99*a^4 + 29*a^3 + 45*a^2 + 57*a + 34
|
|
2319
|
+
|
|
2320
|
+
An example where we have to pass the base field size (and we again have
|
|
2321
|
+
agreement with the Weil pairing)::
|
|
2322
|
+
|
|
2323
|
+
sage: # needs sage.rings.finite_rings
|
|
2324
|
+
sage: F.<a> = GF((2,5))
|
|
2325
|
+
sage: E = EllipticCurve(F, [0,0,1,1,1])
|
|
2326
|
+
sage: P = E(a^4 + 1, a^3)
|
|
2327
|
+
sage: Fx.<b> = GF((2,4*5))
|
|
2328
|
+
sage: Ex = EllipticCurve(Fx,[0,0,1,1,1])
|
|
2329
|
+
sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0])
|
|
2330
|
+
sage: Px = Ex(phi(P.x()), phi(P.y()))
|
|
2331
|
+
sage: Qx = Ex(b^19 + b^18 + b^16 + b^12 + b^10 + b^9 + b^8 + b^5 + b^3 + 1,
|
|
2332
|
+
....: b^18 + b^13 + b^10 + b^8 + b^5 + b^4 + b^3 + b)
|
|
2333
|
+
sage: Px.tate_pairing(Qx, n=41, k=4)
|
|
2334
|
+
Traceback (most recent call last):
|
|
2335
|
+
...
|
|
2336
|
+
ValueError: Unexpected field degree: set keyword argument q equal to
|
|
2337
|
+
the size of the base field (big field is GF(q^4)).
|
|
2338
|
+
sage: num = Px.tate_pairing(Qx, n=41, k=4, q=32); num
|
|
2339
|
+
b^19 + b^14 + b^13 + b^12 + b^6 + b^4 + b^3
|
|
2340
|
+
sage: den = Qx.tate_pairing(Px, n=41, k=4, q=32); den
|
|
2341
|
+
b^19 + b^17 + b^16 + b^15 + b^14 + b^10 + b^6 + b^2 + 1
|
|
2342
|
+
sage: e = Integer((32^4-1)/41); e
|
|
2343
|
+
25575
|
|
2344
|
+
sage: Px.weil_pairing(Qx, 41)^e == num/den
|
|
2345
|
+
True
|
|
2346
|
+
|
|
2347
|
+
An example over a large base field::
|
|
2348
|
+
|
|
2349
|
+
sage: F = GF(65537^2, modulus=[3,46810,1], name='z2')
|
|
2350
|
+
sage: F.inject_variables()
|
|
2351
|
+
Defining z2
|
|
2352
|
+
sage: E = EllipticCurve(F, [0,1])
|
|
2353
|
+
sage: P = E(22, 28891)
|
|
2354
|
+
sage: Q = E(-93, 40438*z2 + 31573)
|
|
2355
|
+
sage: P.tate_pairing(Q, 7282, 2)
|
|
2356
|
+
34585*z2 + 4063
|
|
2357
|
+
|
|
2358
|
+
TESTS:
|
|
2359
|
+
|
|
2360
|
+
The point ``P (self)`` must have ``n`` torsion::
|
|
2361
|
+
|
|
2362
|
+
sage: P.tate_pairing(Q, 163, 2)
|
|
2363
|
+
Traceback (most recent call last):
|
|
2364
|
+
...
|
|
2365
|
+
ValueError: The point P must be n-torsion
|
|
2366
|
+
|
|
2367
|
+
We must have that ``n`` divides ``q^k - 1``, this is only checked when q is supplied::
|
|
2368
|
+
|
|
2369
|
+
sage: P.tate_pairing(Q, 7282, 2, q=123)
|
|
2370
|
+
Traceback (most recent call last):
|
|
2371
|
+
...
|
|
2372
|
+
ValueError: n does not divide (q^k - 1) for the supplied value of q
|
|
2373
|
+
|
|
2374
|
+
The Tate pairing is only defined for points on curves defined over finite fields::
|
|
2375
|
+
|
|
2376
|
+
sage: E = EllipticCurve([0,1])
|
|
2377
|
+
sage: P = E(2,3)
|
|
2378
|
+
sage: P.tate_pairing(P, 6, 1)
|
|
2379
|
+
Traceback (most recent call last):
|
|
2380
|
+
...
|
|
2381
|
+
NotImplementedError: Reduced Tate pairing is currently only implemented for finite fields
|
|
2382
|
+
|
|
2383
|
+
ALGORITHM:
|
|
2384
|
+
|
|
2385
|
+
- :pari:`elltatepairing` computes the
|
|
2386
|
+
non-reduced tate pairing and the exponentiation is handled by
|
|
2387
|
+
Sage using user input for `k` (and optionally `q`).
|
|
2388
|
+
|
|
2389
|
+
AUTHORS:
|
|
2390
|
+
|
|
2391
|
+
- Mariah Lenox (2011-03-07)
|
|
2392
|
+
- Giacomo Pope (2024): Use of PARI for the non-reduced Tate pairing
|
|
2393
|
+
"""
|
|
2394
|
+
P = self
|
|
2395
|
+
E = P.curve()
|
|
2396
|
+
|
|
2397
|
+
if Q.curve() is not E:
|
|
2398
|
+
raise ValueError("Points must both be on the same curve")
|
|
2399
|
+
|
|
2400
|
+
K = E.base_ring()
|
|
2401
|
+
if not K.is_finite():
|
|
2402
|
+
raise NotImplementedError("Reduced Tate pairing is currently only implemented for finite fields")
|
|
2403
|
+
|
|
2404
|
+
d = K.degree()
|
|
2405
|
+
if q is None:
|
|
2406
|
+
if d == 1:
|
|
2407
|
+
q = K.order()
|
|
2408
|
+
elif d == k:
|
|
2409
|
+
q = K.base_ring().order()
|
|
2410
|
+
else:
|
|
2411
|
+
raise ValueError("Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^%s))." % k)
|
|
2412
|
+
# The user has supplied q, so we check here that it's a sensible value
|
|
2413
|
+
elif Mod(q, n)**k != 1:
|
|
2414
|
+
raise ValueError("n does not divide (q^k - 1) for the supplied value of q")
|
|
2415
|
+
|
|
2416
|
+
if pari.ellmul(E, P, n) != [0]:
|
|
2417
|
+
raise ValueError("The point P must be n-torsion")
|
|
2418
|
+
|
|
2419
|
+
# NOTE: Pari returns the non-reduced Tate pairing, so we
|
|
2420
|
+
# must perform the exponentiation ourselves using the supplied
|
|
2421
|
+
# k value
|
|
2422
|
+
ePQ = pari.elltatepairing(E, P, Q, n)
|
|
2423
|
+
exp = Integer((q**k - 1)/n)
|
|
2424
|
+
return K(ePQ**exp) # Cast the PARI type back to the base ring
|
|
2425
|
+
|
|
2426
|
+
def ate_pairing(self, Q, n, k, t, q=None):
|
|
2427
|
+
r"""
|
|
2428
|
+
Return ate pairing of `n`-torsion points `P` (``=self``) and `Q`.
|
|
2429
|
+
|
|
2430
|
+
Also known as the `n`-th modified ate pairing. `P` is `GF(q)`-rational,
|
|
2431
|
+
and `Q` must be an element of `Ker(\pi-p)`, where `\pi` is the
|
|
2432
|
+
`q`-frobenius map (and hence `Q` is `GF(q^k)`-rational).
|
|
2433
|
+
|
|
2434
|
+
INPUT:
|
|
2435
|
+
|
|
2436
|
+
- ``P`` (``=self``) -- a point of order `n`, in `ker(\pi-1)`, where
|
|
2437
|
+
`\pi` is the `q`-Frobenius map (e.g., `P` is `q`-rational)
|
|
2438
|
+
|
|
2439
|
+
- ``Q`` -- a point of order `n` in `ker(\pi-q)`
|
|
2440
|
+
|
|
2441
|
+
- ``n`` -- the order of `P` and `Q`
|
|
2442
|
+
|
|
2443
|
+
- ``k`` -- the embedding degree
|
|
2444
|
+
|
|
2445
|
+
- ``t`` -- the trace of Frobenius of the curve over `GF(q)`
|
|
2446
|
+
|
|
2447
|
+
- ``q`` -- (default: ``None``) the size of base field (the "big"
|
|
2448
|
+
field is `GF(q^k)`). `q` needs to be set only if its value
|
|
2449
|
+
cannot be deduced.
|
|
2450
|
+
|
|
2451
|
+
OUTPUT:
|
|
2452
|
+
|
|
2453
|
+
FiniteFieldElement in `GF(q^k)` -- the ate pairing of `P` and `Q`.
|
|
2454
|
+
|
|
2455
|
+
EXAMPLES:
|
|
2456
|
+
|
|
2457
|
+
An example with embedding degree 6::
|
|
2458
|
+
|
|
2459
|
+
sage: # needs sage.rings.finite_rings
|
|
2460
|
+
sage: p = 7549; A = 0; B = 1; n = 157; k = 6; t = 14
|
|
2461
|
+
sage: F = GF(p); E = EllipticCurve(F, [A, B])
|
|
2462
|
+
sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2)
|
|
2463
|
+
sage: EK = E.base_extend(K)
|
|
2464
|
+
sage: P = EK(3050, 5371); Q = EK(6908*a^4, 3231*a^3)
|
|
2465
|
+
sage: P.ate_pairing(Q, n, k, t)
|
|
2466
|
+
6708*a^5 + 4230*a^4 + 4350*a^3 + 2064*a^2 + 4022*a + 6733
|
|
2467
|
+
sage: s = Integer(randrange(1, n))
|
|
2468
|
+
sage: (s*P).ate_pairing(Q, n, k, t) == P.ate_pairing(s*Q, n, k, t)
|
|
2469
|
+
True
|
|
2470
|
+
sage: P.ate_pairing(s*Q, n, k, t) == P.ate_pairing(Q, n, k, t)^s
|
|
2471
|
+
True
|
|
2472
|
+
|
|
2473
|
+
Another example with embedding degree 7 and positive trace::
|
|
2474
|
+
|
|
2475
|
+
sage: # needs sage.rings.finite_rings
|
|
2476
|
+
sage: p = 2213; A = 1; B = 49; n = 1093; k = 7; t = 28
|
|
2477
|
+
sage: F = GF(p); E = EllipticCurve(F, [A, B])
|
|
2478
|
+
sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2)
|
|
2479
|
+
sage: EK = E.base_extend(K)
|
|
2480
|
+
sage: P = EK(1583, 1734)
|
|
2481
|
+
sage: Qx = 1729*a^6+1767*a^5+245*a^4+980*a^3+1592*a^2+1883*a+722
|
|
2482
|
+
sage: Qy = 1299*a^6+1877*a^5+1030*a^4+1513*a^3+1457*a^2+309*a+1636
|
|
2483
|
+
sage: Q = EK(Qx, Qy)
|
|
2484
|
+
sage: P.ate_pairing(Q, n, k, t)
|
|
2485
|
+
1665*a^6 + 1538*a^5 + 1979*a^4 + 239*a^3 + 2134*a^2 + 2151*a + 654
|
|
2486
|
+
sage: s = Integer(randrange(1, n))
|
|
2487
|
+
sage: (s*P).ate_pairing(Q, n, k, t) == P.ate_pairing(s*Q, n, k, t)
|
|
2488
|
+
True
|
|
2489
|
+
sage: P.ate_pairing(s*Q, n, k, t) == P.ate_pairing(Q, n, k, t)^s
|
|
2490
|
+
True
|
|
2491
|
+
|
|
2492
|
+
Another example with embedding degree 7 and negative trace::
|
|
2493
|
+
|
|
2494
|
+
sage: # needs sage.rings.finite_rings
|
|
2495
|
+
sage: p = 2017; A = 1; B = 30; n = 29; k = 7; t = -70
|
|
2496
|
+
sage: F = GF(p); E = EllipticCurve(F, [A, B])
|
|
2497
|
+
sage: R.<x> = F[]; K.<a> = GF((p,k), modulus=x^k+2)
|
|
2498
|
+
sage: EK = E.base_extend(K)
|
|
2499
|
+
sage: P = EK(369, 716)
|
|
2500
|
+
sage: Qx = 1226*a^6+1778*a^5+660*a^4+1791*a^3+1750*a^2+867*a+770
|
|
2501
|
+
sage: Qy = 1764*a^6+198*a^5+1206*a^4+406*a^3+1200*a^2+273*a+1712
|
|
2502
|
+
sage: Q = EK(Qx, Qy)
|
|
2503
|
+
sage: P.ate_pairing(Q, n, k, t)
|
|
2504
|
+
1794*a^6 + 1161*a^5 + 576*a^4 + 488*a^3 + 1950*a^2 + 1905*a + 1315
|
|
2505
|
+
sage: s = Integer(randrange(1, n))
|
|
2506
|
+
sage: (s*P).ate_pairing(Q, n, k, t) == P.ate_pairing(s*Q, n, k, t)
|
|
2507
|
+
True
|
|
2508
|
+
sage: P.ate_pairing(s*Q, n, k, t) == P.ate_pairing(Q, n, k, t)^s
|
|
2509
|
+
True
|
|
2510
|
+
|
|
2511
|
+
Using the same data, we show that the ate pairing is a power of the
|
|
2512
|
+
Tate pairing (see [HSV2006]_ end of section 3.1)::
|
|
2513
|
+
|
|
2514
|
+
sage: # needs sage.rings.finite_rings
|
|
2515
|
+
sage: c = (k*p^(k-1)).mod(n); T = t - 1
|
|
2516
|
+
sage: N = gcd(T^k - 1, p^k - 1)
|
|
2517
|
+
sage: s = Integer(N/n)
|
|
2518
|
+
sage: L = Integer((T^k - 1)/N)
|
|
2519
|
+
sage: M = (L*s*c.inverse_mod(n)).mod(n)
|
|
2520
|
+
sage: P.ate_pairing(Q, n, k, t) == Q.tate_pairing(P, n, k)^M
|
|
2521
|
+
True
|
|
2522
|
+
|
|
2523
|
+
An example where we have to pass the base field size (and we again have
|
|
2524
|
+
agreement with the Tate pairing). Note that though `Px` is not
|
|
2525
|
+
`F`-rational, (it is the homomorphic image of an `F`-rational point) it
|
|
2526
|
+
is nonetheless in `ker(\pi-1)`, and so is a legitimate input::
|
|
2527
|
+
|
|
2528
|
+
sage: # needs sage.rings.finite_rings
|
|
2529
|
+
sage: q = 2^5; F.<a> = GF(q)
|
|
2530
|
+
sage: n = 41; k = 4; t = -8
|
|
2531
|
+
sage: E = EllipticCurve(F,[0,0,1,1,1])
|
|
2532
|
+
sage: P = E(a^4 + 1, a^3)
|
|
2533
|
+
sage: Fx.<b> = GF(q^k)
|
|
2534
|
+
sage: Ex = EllipticCurve(Fx, [0,0,1,1,1])
|
|
2535
|
+
sage: phi = Hom(F, Fx)(F.gen().minpoly().roots(Fx)[0][0])
|
|
2536
|
+
sage: Px = Ex(phi(P.x()), phi(P.y()))
|
|
2537
|
+
sage: Qx = Ex(b^19+b^18+b^16+b^12+b^10+b^9+b^8+b^5+b^3+1,
|
|
2538
|
+
....: b^18+b^13+b^10+b^8+b^5+b^4+b^3+b)
|
|
2539
|
+
sage: Qx = Ex(Qx[0]^q, Qx[1]^q) - Qx # ensure Qx is in ker(pi - q)
|
|
2540
|
+
sage: Px.ate_pairing(Qx, n, k, t)
|
|
2541
|
+
Traceback (most recent call last):
|
|
2542
|
+
...
|
|
2543
|
+
ValueError: Unexpected field degree: set keyword argument q equal to
|
|
2544
|
+
the size of the base field (big field is GF(q^4)).
|
|
2545
|
+
sage: Px.ate_pairing(Qx, n, k, t, q)
|
|
2546
|
+
b^19 + b^18 + b^17 + b^16 + b^15 + b^14 + b^13 + b^12
|
|
2547
|
+
+ b^11 + b^9 + b^8 + b^5 + b^4 + b^2 + b + 1
|
|
2548
|
+
sage: s = Integer(randrange(1, n))
|
|
2549
|
+
sage: (s*Px).ate_pairing(Qx, n, k, t, q) == Px.ate_pairing(s*Qx, n, k, t, q)
|
|
2550
|
+
True
|
|
2551
|
+
sage: Px.ate_pairing(s*Qx, n, k, t, q) == Px.ate_pairing(Qx, n, k, t, q)^s
|
|
2552
|
+
True
|
|
2553
|
+
sage: c = (k*q^(k-1)).mod(n); T = t - 1
|
|
2554
|
+
sage: N = gcd(T^k - 1, q^k - 1)
|
|
2555
|
+
sage: s = Integer(N/n)
|
|
2556
|
+
sage: L = Integer((T^k - 1)/N)
|
|
2557
|
+
sage: M = (L*s*c.inverse_mod(n)).mod(n)
|
|
2558
|
+
sage: Px.ate_pairing(Qx, n, k, t, q) == Qx.tate_pairing(Px, n, k, q)^M
|
|
2559
|
+
True
|
|
2560
|
+
|
|
2561
|
+
It is an error if `Q` is not in the kernel of `\pi - p`, where `\pi` is
|
|
2562
|
+
the Frobenius automorphism::
|
|
2563
|
+
|
|
2564
|
+
sage: # needs sage.rings.finite_rings
|
|
2565
|
+
sage: p = 29; A = 1; B = 0; n = 5; k = 2; t = 10
|
|
2566
|
+
sage: F = GF(p); R.<x> = F[]
|
|
2567
|
+
sage: E = EllipticCurve(F, [A, B]);
|
|
2568
|
+
sage: K.<a> = GF((p,k), modulus=x^k+2); EK = E.base_extend(K)
|
|
2569
|
+
sage: P = EK(13, 8); Q = EK(13, 21)
|
|
2570
|
+
sage: P.ate_pairing(Q, n, k, t)
|
|
2571
|
+
Traceback (most recent call last):
|
|
2572
|
+
...
|
|
2573
|
+
ValueError: Point (13 : 21 : 1) not in Ker(pi - q)
|
|
2574
|
+
|
|
2575
|
+
It is also an error if `P` is not in the kernel os `\pi - 1`::
|
|
2576
|
+
|
|
2577
|
+
sage: # needs sage.rings.finite_rings
|
|
2578
|
+
sage: p = 29; A = 1; B = 0; n = 5; k = 2; t = 10
|
|
2579
|
+
sage: F = GF(p); R.<x> = F[]
|
|
2580
|
+
sage: E = EllipticCurve(F, [A, B]);
|
|
2581
|
+
sage: K.<a> = GF((p,k), modulus=x^k+2); EK = E.base_extend(K)
|
|
2582
|
+
sage: P = EK(14, 10*a); Q = EK(13, 21)
|
|
2583
|
+
sage: P.ate_pairing(Q, n, k, t)
|
|
2584
|
+
Traceback (most recent call last):
|
|
2585
|
+
...
|
|
2586
|
+
ValueError: This point (14 : 10*a : 1) is not in Ker(pi - 1)
|
|
2587
|
+
|
|
2588
|
+
.. NOTE::
|
|
2589
|
+
|
|
2590
|
+
First defined in the paper of [HSV2006]_, the ate pairing
|
|
2591
|
+
can be computationally effective in those cases when the
|
|
2592
|
+
trace of the curve over the base field is significantly
|
|
2593
|
+
smaller than the expected value. This implementation is
|
|
2594
|
+
simply Miller's algorithm followed by a naive
|
|
2595
|
+
exponentiation, and makes no claims towards efficiency.
|
|
2596
|
+
|
|
2597
|
+
AUTHORS:
|
|
2598
|
+
|
|
2599
|
+
- Mariah Lenox (2011-03-08)
|
|
2600
|
+
"""
|
|
2601
|
+
P = self
|
|
2602
|
+
# check for same curve
|
|
2603
|
+
E = P.curve()
|
|
2604
|
+
O = E(0)
|
|
2605
|
+
if Q.curve() is not E:
|
|
2606
|
+
raise ValueError("Points must both be on the same curve")
|
|
2607
|
+
|
|
2608
|
+
# set q to be the order of the base field
|
|
2609
|
+
K = E.base_ring()
|
|
2610
|
+
if q is None:
|
|
2611
|
+
d = K.degree()
|
|
2612
|
+
if d == k:
|
|
2613
|
+
q = K.base_ring().order()
|
|
2614
|
+
else:
|
|
2615
|
+
raise ValueError("Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^%s))." % k)
|
|
2616
|
+
|
|
2617
|
+
# check order of P
|
|
2618
|
+
if n*P != O:
|
|
2619
|
+
raise ValueError('This point %s is not of order n=%s' % (P, n))
|
|
2620
|
+
|
|
2621
|
+
# check for P in kernel pi - 1:
|
|
2622
|
+
piP = E(P[0]**q, P[1]**q)
|
|
2623
|
+
if piP - P != O:
|
|
2624
|
+
raise ValueError('This point %s is not in Ker(pi - 1)' % P)
|
|
2625
|
+
|
|
2626
|
+
# check for Q in kernel pi - q:
|
|
2627
|
+
piQ = E(Q[0]**q, Q[1]**q)
|
|
2628
|
+
if piQ - q*Q != O:
|
|
2629
|
+
raise ValueError('Point %s not in Ker(pi - q)' % Q)
|
|
2630
|
+
|
|
2631
|
+
T = t-1
|
|
2632
|
+
ret = Q._miller_(P, T)
|
|
2633
|
+
e = Integer((q**k - 1)/n)
|
|
2634
|
+
ret = ret**e
|
|
2635
|
+
return ret
|
|
2636
|
+
|
|
2637
|
+
def point_of_jacobian_of_curve(self):
|
|
2638
|
+
r"""
|
|
2639
|
+
Return the point in the Jacobian of the curve.
|
|
2640
|
+
|
|
2641
|
+
The Jacobian is the one attached to the projective curve associated
|
|
2642
|
+
with this elliptic curve.
|
|
2643
|
+
|
|
2644
|
+
EXAMPLES::
|
|
2645
|
+
|
|
2646
|
+
sage: # needs sage.rings.finite_rings
|
|
2647
|
+
sage: k.<a> = GF((5,2))
|
|
2648
|
+
sage: E = EllipticCurve(k,[1,0]); E
|
|
2649
|
+
Elliptic Curve defined by y^2 = x^3 + x over Finite Field in a of size 5^2
|
|
2650
|
+
sage: E.order()
|
|
2651
|
+
32
|
|
2652
|
+
sage: P = E([a, 2*a + 4])
|
|
2653
|
+
sage: P
|
|
2654
|
+
(a : 2*a + 4 : 1)
|
|
2655
|
+
sage: P.order()
|
|
2656
|
+
8
|
|
2657
|
+
sage: p = P.point_of_jacobian_of_curve()
|
|
2658
|
+
sage: p
|
|
2659
|
+
[Place (x + 4*a, y + 3*a + 1)]
|
|
2660
|
+
sage: p.order()
|
|
2661
|
+
8
|
|
2662
|
+
sage: Q = 3*P
|
|
2663
|
+
sage: q = Q.point_of_jacobian_of_curve()
|
|
2664
|
+
sage: q == 3*p
|
|
2665
|
+
True
|
|
2666
|
+
sage: G = p.parent()
|
|
2667
|
+
sage: G.order()
|
|
2668
|
+
32
|
|
2669
|
+
sage: G
|
|
2670
|
+
Group of rational points of Jacobian over Finite Field in a of size 5^2 (Hess model)
|
|
2671
|
+
sage: J = G.parent(); J
|
|
2672
|
+
Jacobian of Projective Plane Curve over Finite Field in a of size 5^2
|
|
2673
|
+
defined by x^2*y + y^3 - x*z^2 (Hess model)
|
|
2674
|
+
sage: J.curve() == E.affine_patch(2).projective_closure()
|
|
2675
|
+
True
|
|
2676
|
+
"""
|
|
2677
|
+
from sage.schemes.curves.constructor import Curve
|
|
2678
|
+
C = self.curve()
|
|
2679
|
+
A = C.ambient_space() # projective plane
|
|
2680
|
+
x, y, z = self
|
|
2681
|
+
|
|
2682
|
+
X = Curve(C.defining_ideal().gens(), A)
|
|
2683
|
+
X = X.affine_patch(2).projective_closure()
|
|
2684
|
+
F = X.function_field()
|
|
2685
|
+
P = X(z,x,y).place()
|
|
2686
|
+
|
|
2687
|
+
Pinf = F.places_infinite()[0]
|
|
2688
|
+
assert Pinf.degree() == 1, "no rational point at infinity"
|
|
2689
|
+
|
|
2690
|
+
J = X.jacobian(model='hess', base_div=F.genus()*Pinf)
|
|
2691
|
+
G = J.group(self.base_ring())
|
|
2692
|
+
return G(P - P.degree()*Pinf)
|
|
2693
|
+
|
|
2694
|
+
|
|
2695
|
+
class EllipticCurvePoint_number_field(EllipticCurvePoint_field):
|
|
2696
|
+
"""
|
|
2697
|
+
A point on an elliptic curve over a number field.
|
|
2698
|
+
|
|
2699
|
+
Most of the functionality is derived from the parent class
|
|
2700
|
+
:class:`EllipticCurvePoint_field`. In addition we have support for
|
|
2701
|
+
orders, heights, reduction modulo primes, and elliptic logarithms.
|
|
2702
|
+
|
|
2703
|
+
EXAMPLES::
|
|
2704
|
+
|
|
2705
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
2706
|
+
sage: E = EllipticCurve('37a')
|
|
2707
|
+
sage: E([0,0])
|
|
2708
|
+
(0 : 0 : 1)
|
|
2709
|
+
sage: E(0,0) # brackets are optional
|
|
2710
|
+
(0 : 0 : 1)
|
|
2711
|
+
sage: E([GF(5)(0), 0]) # entries are coerced
|
|
2712
|
+
(0 : 0 : 1)
|
|
2713
|
+
sage: E(0.000, 0)
|
|
2714
|
+
(0 : 0 : 1)
|
|
2715
|
+
sage: E(1,0,0)
|
|
2716
|
+
Traceback (most recent call last):
|
|
2717
|
+
...
|
|
2718
|
+
TypeError: Coordinates [1, 0, 0] do not define a point on
|
|
2719
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
2720
|
+
|
|
2721
|
+
::
|
|
2722
|
+
|
|
2723
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
2724
|
+
sage: S = E(QQ); S
|
|
2725
|
+
Abelian group of points on
|
|
2726
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
2727
|
+
|
|
2728
|
+
TESTS::
|
|
2729
|
+
|
|
2730
|
+
sage: loads(S.dumps()) == S
|
|
2731
|
+
True
|
|
2732
|
+
sage: P = E(0,0); P
|
|
2733
|
+
(0 : 0 : 1)
|
|
2734
|
+
sage: loads(P.dumps()) == P
|
|
2735
|
+
True
|
|
2736
|
+
sage: T = 100*P
|
|
2737
|
+
sage: loads(T.dumps()) == T
|
|
2738
|
+
True
|
|
2739
|
+
|
|
2740
|
+
Test pickling an elliptic curve that has known points on it::
|
|
2741
|
+
|
|
2742
|
+
sage: e = EllipticCurve([0, 0, 1, -1, 0]); g = e.gens(); loads(dumps(e)) == e # needs ecl
|
|
2743
|
+
True
|
|
2744
|
+
"""
|
|
2745
|
+
|
|
2746
|
+
def order(self):
|
|
2747
|
+
r"""
|
|
2748
|
+
Return the order of this point on the elliptic curve.
|
|
2749
|
+
|
|
2750
|
+
If the point has infinite order, returns +Infinity. For
|
|
2751
|
+
curves defined over `\QQ`, we call PARI; over other
|
|
2752
|
+
number fields we implement the function here.
|
|
2753
|
+
|
|
2754
|
+
.. NOTE::
|
|
2755
|
+
|
|
2756
|
+
:meth:`additive_order` is a synonym for :meth:`order`
|
|
2757
|
+
|
|
2758
|
+
EXAMPLES::
|
|
2759
|
+
|
|
2760
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
2761
|
+
sage: P = E([0,0]); P
|
|
2762
|
+
(0 : 0 : 1)
|
|
2763
|
+
sage: P.order()
|
|
2764
|
+
+Infinity
|
|
2765
|
+
|
|
2766
|
+
::
|
|
2767
|
+
|
|
2768
|
+
sage: E = EllipticCurve([0,1])
|
|
2769
|
+
sage: P = E([-1,0])
|
|
2770
|
+
sage: P.order()
|
|
2771
|
+
2
|
|
2772
|
+
sage: P.additive_order()
|
|
2773
|
+
2
|
|
2774
|
+
"""
|
|
2775
|
+
try:
|
|
2776
|
+
return self._order
|
|
2777
|
+
except AttributeError:
|
|
2778
|
+
pass
|
|
2779
|
+
|
|
2780
|
+
if self.is_zero():
|
|
2781
|
+
self._order = Integer(1)
|
|
2782
|
+
return self._order
|
|
2783
|
+
|
|
2784
|
+
E = self.curve()
|
|
2785
|
+
|
|
2786
|
+
# First try PARI
|
|
2787
|
+
try:
|
|
2788
|
+
n = E.pari_curve().ellorder(self)
|
|
2789
|
+
if n:
|
|
2790
|
+
n = Integer(n)
|
|
2791
|
+
else:
|
|
2792
|
+
n = oo
|
|
2793
|
+
self._order = n
|
|
2794
|
+
return n
|
|
2795
|
+
except PariError:
|
|
2796
|
+
pass
|
|
2797
|
+
|
|
2798
|
+
# Get the torsion order if known, else a bound on (multiple
|
|
2799
|
+
# of) the order. We do not compute the torsion if it is not
|
|
2800
|
+
# already known, since computing the bound is faster (and is
|
|
2801
|
+
# also cached).
|
|
2802
|
+
|
|
2803
|
+
try:
|
|
2804
|
+
N = E._torsion_order
|
|
2805
|
+
except AttributeError:
|
|
2806
|
+
N = E._torsion_bound()
|
|
2807
|
+
|
|
2808
|
+
# Now self is a torsion point iff it is killed by N:
|
|
2809
|
+
if not (N*self).is_zero():
|
|
2810
|
+
self._order = oo
|
|
2811
|
+
return self._order
|
|
2812
|
+
|
|
2813
|
+
# Finally we find the exact order using the generic code:
|
|
2814
|
+
self._order = generic.order_from_multiple(self, N, operation='+')
|
|
2815
|
+
return self._order
|
|
2816
|
+
|
|
2817
|
+
additive_order = order
|
|
2818
|
+
|
|
2819
|
+
def has_finite_order(self) -> bool:
|
|
2820
|
+
"""
|
|
2821
|
+
Return ``True`` iff this point has finite order on the elliptic curve.
|
|
2822
|
+
|
|
2823
|
+
EXAMPLES::
|
|
2824
|
+
|
|
2825
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
2826
|
+
sage: P = E([0,0]); P
|
|
2827
|
+
(0 : 0 : 1)
|
|
2828
|
+
sage: P.has_finite_order()
|
|
2829
|
+
False
|
|
2830
|
+
|
|
2831
|
+
::
|
|
2832
|
+
|
|
2833
|
+
sage: E = EllipticCurve([0,1])
|
|
2834
|
+
sage: P = E([-1,0])
|
|
2835
|
+
sage: P.has_finite_order()
|
|
2836
|
+
True
|
|
2837
|
+
"""
|
|
2838
|
+
if self.is_zero():
|
|
2839
|
+
return True
|
|
2840
|
+
return self.order() != oo
|
|
2841
|
+
|
|
2842
|
+
def has_infinite_order(self) -> bool:
|
|
2843
|
+
r"""
|
|
2844
|
+
Return ``True`` iff this point has infinite order on the elliptic curve.
|
|
2845
|
+
|
|
2846
|
+
EXAMPLES::
|
|
2847
|
+
|
|
2848
|
+
sage: E = EllipticCurve([0,0,1,-1,0])
|
|
2849
|
+
sage: P = E([0,0]); P
|
|
2850
|
+
(0 : 0 : 1)
|
|
2851
|
+
sage: P.has_infinite_order()
|
|
2852
|
+
True
|
|
2853
|
+
|
|
2854
|
+
::
|
|
2855
|
+
|
|
2856
|
+
sage: E = EllipticCurve([0,1])
|
|
2857
|
+
sage: P = E([-1,0])
|
|
2858
|
+
sage: P.has_infinite_order()
|
|
2859
|
+
False
|
|
2860
|
+
"""
|
|
2861
|
+
if self.is_zero():
|
|
2862
|
+
return False
|
|
2863
|
+
return self.order() == oo
|
|
2864
|
+
|
|
2865
|
+
def _has_order_at_least(self, bound, *, attempts=999):
|
|
2866
|
+
r"""
|
|
2867
|
+
Return ``True`` if this point definitely has order at least ``bound``
|
|
2868
|
+
on the elliptic curve, ``False`` if the point has smaller order, and
|
|
2869
|
+
``None`` if the result of this test is inconclusive.
|
|
2870
|
+
|
|
2871
|
+
This method can be much faster than calling :meth:`has_infinite_order`
|
|
2872
|
+
if all that is needed is a lower bound on the order.
|
|
2873
|
+
|
|
2874
|
+
ALGORITHM: Compute the order of the point modulo various small primes
|
|
2875
|
+
and combine that information using CRT.
|
|
2876
|
+
|
|
2877
|
+
EXAMPLES::
|
|
2878
|
+
|
|
2879
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
2880
|
+
sage: E = EllipticCurve('11a3')
|
|
2881
|
+
sage: P = next(filter(bool, E.torsion_points()))
|
|
2882
|
+
sage: P._has_order_at_least(5)
|
|
2883
|
+
True
|
|
2884
|
+
sage: P._has_order_at_least(6) # long time -- 5s
|
|
2885
|
+
sage: P.order()
|
|
2886
|
+
5
|
|
2887
|
+
sage: Q = E.lift_x(10^42, extend=True)
|
|
2888
|
+
sage: Q._has_order_at_least(10^100)
|
|
2889
|
+
True
|
|
2890
|
+
|
|
2891
|
+
::
|
|
2892
|
+
|
|
2893
|
+
sage: x = polygen(ZZ)
|
|
2894
|
+
sage: K.<a> = NumberField(x^2 - x + 2)
|
|
2895
|
+
sage: E = EllipticCurve([1, a-1, a+1, -2*a-2, -5*a+7]) # 2.0.7.1-268.3-b1
|
|
2896
|
+
sage: P = next(filter(bool, E.torsion_points()))
|
|
2897
|
+
sage: P._has_order_at_least(11)
|
|
2898
|
+
True
|
|
2899
|
+
sage: P._has_order_at_least(12)
|
|
2900
|
+
False
|
|
2901
|
+
sage: P.order()
|
|
2902
|
+
11
|
|
2903
|
+
sage: Q = E.lift_x(123*a + 456, extend=True)
|
|
2904
|
+
sage: Q._has_order_at_least(10^100)
|
|
2905
|
+
True
|
|
2906
|
+
"""
|
|
2907
|
+
n = getattr(self, '_order', None)
|
|
2908
|
+
if n is not None:
|
|
2909
|
+
return n >= bound
|
|
2910
|
+
|
|
2911
|
+
from sage.sets.primes import Primes
|
|
2912
|
+
from sage.rings.finite_rings.finite_field_constructor import GF
|
|
2913
|
+
field_deg = self.curve().base_field().absolute_degree()
|
|
2914
|
+
if field_deg > 1:
|
|
2915
|
+
K = self.curve().base_field().absolute_field('T')
|
|
2916
|
+
_, iso = K.structure()
|
|
2917
|
+
E = self.curve().change_ring(iso)
|
|
2918
|
+
P = self.change_ring(iso)
|
|
2919
|
+
poly = lambda elt: elt.polynomial()
|
|
2920
|
+
if field_deg == 2:
|
|
2921
|
+
# Kamienny-Kenku-Momose
|
|
2922
|
+
bound = min(bound, 18 + 1)
|
|
2923
|
+
else:
|
|
2924
|
+
K, E, P = QQ, self.curve(), self
|
|
2925
|
+
poly = lambda elt: QQ['x'](elt)
|
|
2926
|
+
# Mazur / Ogg's torsion conjecture
|
|
2927
|
+
# Torsion points can only have order <= 12, so order of > 12 -> infinite order
|
|
2928
|
+
bound = min(bound, 12 + 1)
|
|
2929
|
+
assert P.curve() is E
|
|
2930
|
+
|
|
2931
|
+
n = ZZ.one()
|
|
2932
|
+
no_progress = 0
|
|
2933
|
+
for p in Primes():
|
|
2934
|
+
try:
|
|
2935
|
+
f,_ = K.defining_polynomial().change_ring(GF(p)).factor()[0]
|
|
2936
|
+
except ZeroDivisionError:
|
|
2937
|
+
continue
|
|
2938
|
+
F = GF(p).extension(f,'t')
|
|
2939
|
+
red = lambda elt: F(f.parent()(poly(elt)).change_ring(GF(p)) % f)
|
|
2940
|
+
|
|
2941
|
+
try:
|
|
2942
|
+
Ered = E.change_ring(red)
|
|
2943
|
+
Pred = Ered(*map(red, P))
|
|
2944
|
+
except (ZeroDivisionError, ArithmeticError):
|
|
2945
|
+
continue
|
|
2946
|
+
|
|
2947
|
+
o = Pred.order()
|
|
2948
|
+
if not o.divides(n):
|
|
2949
|
+
n = n.lcm(o)
|
|
2950
|
+
no_progress = 0
|
|
2951
|
+
else:
|
|
2952
|
+
no_progress += 1
|
|
2953
|
+
|
|
2954
|
+
if n >= bound:
|
|
2955
|
+
return True
|
|
2956
|
+
if no_progress >= attempts:
|
|
2957
|
+
return
|
|
2958
|
+
|
|
2959
|
+
assert False # unreachable unless there are only finitely many primes
|
|
2960
|
+
|
|
2961
|
+
def is_on_identity_component(self, embedding=None):
|
|
2962
|
+
r"""
|
|
2963
|
+
Return ``True`` iff this point is on the identity component of
|
|
2964
|
+
its curve with respect to a given (real or complex) embedding.
|
|
2965
|
+
|
|
2966
|
+
INPUT:
|
|
2967
|
+
|
|
2968
|
+
- ``self`` -- a point on a curve over any ordered field (e.g. `\QQ`)
|
|
2969
|
+
|
|
2970
|
+
- ``embedding`` -- an embedding from the base_field of the
|
|
2971
|
+
point's curve into `\RR` or `\CC`; if ``None`` (the
|
|
2972
|
+
default) it uses the first embedding of the base_field into
|
|
2973
|
+
`\RR` if any, else the first embedding into `\CC`.
|
|
2974
|
+
|
|
2975
|
+
OUTPUT:
|
|
2976
|
+
|
|
2977
|
+
boolean; ``True`` iff the point is on the identity component of
|
|
2978
|
+
the curve. (If the point is zero then the result is ``True``.)
|
|
2979
|
+
|
|
2980
|
+
EXAMPLES:
|
|
2981
|
+
|
|
2982
|
+
For `K=\QQ` there is no need to specify an embedding::
|
|
2983
|
+
|
|
2984
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
2985
|
+
sage: E = EllipticCurve('5077a1')
|
|
2986
|
+
sage: [E.lift_x(x).is_on_identity_component() for x in srange(-3,5)]
|
|
2987
|
+
[False, False, False, False, False, True, True, True]
|
|
2988
|
+
|
|
2989
|
+
An example over a field with two real embeddings::
|
|
2990
|
+
|
|
2991
|
+
sage: # needs sage.rings.number_field
|
|
2992
|
+
sage: L.<a> = QuadraticField(2)
|
|
2993
|
+
sage: E = EllipticCurve(L, [0,1,0,a,a])
|
|
2994
|
+
sage: P = E(-1,0)
|
|
2995
|
+
sage: [P.is_on_identity_component(e) for e in L.embeddings(RR)]
|
|
2996
|
+
[False, True]
|
|
2997
|
+
|
|
2998
|
+
We can check this as follows::
|
|
2999
|
+
|
|
3000
|
+
sage: # needs sage.rings.number_field
|
|
3001
|
+
sage: [e(E.discriminant()) > 0 for e in L.embeddings(RR)]
|
|
3002
|
+
[True, False]
|
|
3003
|
+
sage: e = L.embeddings(RR)[0]
|
|
3004
|
+
sage: E1 = EllipticCurve(RR, [e(ai) for ai in E.ainvs()])
|
|
3005
|
+
sage: e1, e2, e3 = E1.two_division_polynomial().roots(RR,
|
|
3006
|
+
....: multiplicities=False)
|
|
3007
|
+
sage: e1 < e2 < e3 and e(P[0]) < e3
|
|
3008
|
+
True
|
|
3009
|
+
"""
|
|
3010
|
+
if self.is_zero(): # trivial case
|
|
3011
|
+
return True
|
|
3012
|
+
|
|
3013
|
+
e = embedding
|
|
3014
|
+
# It is also trivially true if we have a complex embedding
|
|
3015
|
+
if e is not None:
|
|
3016
|
+
if not isinstance(e.codomain(), sage.rings.abc.RealField):
|
|
3017
|
+
return True
|
|
3018
|
+
|
|
3019
|
+
# find a suitable embedding if none was supplied:
|
|
3020
|
+
E = self.curve()
|
|
3021
|
+
K = E.base_field()
|
|
3022
|
+
if e is None:
|
|
3023
|
+
try:
|
|
3024
|
+
e = K.embeddings(RealField())[0]
|
|
3025
|
+
except IndexError:
|
|
3026
|
+
e = K.embeddings(ComplexField())[0]
|
|
3027
|
+
|
|
3028
|
+
# If there is only one component, the result is True:
|
|
3029
|
+
if not isinstance(e.codomain(), sage.rings.abc.RealField): # complex embedding
|
|
3030
|
+
return True
|
|
3031
|
+
if e(E.discriminant()) < 0: # only one component
|
|
3032
|
+
return True
|
|
3033
|
+
|
|
3034
|
+
# Now we have a real embedding and two components and have to work:
|
|
3035
|
+
gx = E.two_division_polynomial()
|
|
3036
|
+
gxd = gx.derivative()
|
|
3037
|
+
gxdd = gxd.derivative()
|
|
3038
|
+
return (e(gxd(self[0])) > 0 and e(gxdd(self[0])) > 0)
|
|
3039
|
+
|
|
3040
|
+
def has_good_reduction(self, P=None) -> bool:
|
|
3041
|
+
r"""
|
|
3042
|
+
Return ``True`` iff this point has good reduction modulo a prime.
|
|
3043
|
+
|
|
3044
|
+
INPUT:
|
|
3045
|
+
|
|
3046
|
+
- ``P`` -- a prime of the base_field of the point's curve, or
|
|
3047
|
+
``None`` (default)
|
|
3048
|
+
|
|
3049
|
+
OUTPUT:
|
|
3050
|
+
|
|
3051
|
+
boolean; if a prime `P` of the base field is specified, returns
|
|
3052
|
+
``True`` iff the point has good reduction at `P`; otherwise,
|
|
3053
|
+
return ``True`` if the point has god reduction at all primes in
|
|
3054
|
+
the support of the discriminant of this model.
|
|
3055
|
+
|
|
3056
|
+
EXAMPLES::
|
|
3057
|
+
|
|
3058
|
+
sage: # needs database_cremona_mini_ellcurve eclib
|
|
3059
|
+
sage: E = EllipticCurve('990e1')
|
|
3060
|
+
sage: P = E.gen(0); P
|
|
3061
|
+
(15 : 51 : 1)
|
|
3062
|
+
sage: [E.has_good_reduction(p) for p in [2,3,5,7]]
|
|
3063
|
+
[False, False, False, True]
|
|
3064
|
+
sage: [P.has_good_reduction(p) for p in [2,3,5,7]]
|
|
3065
|
+
[True, False, True, True]
|
|
3066
|
+
sage: [E.tamagawa_exponent(p) for p in [2,3,5,7]]
|
|
3067
|
+
[2, 2, 1, 1]
|
|
3068
|
+
sage: [(2*P).has_good_reduction(p) for p in [2,3,5,7]]
|
|
3069
|
+
[True, True, True, True]
|
|
3070
|
+
sage: P.has_good_reduction()
|
|
3071
|
+
False
|
|
3072
|
+
sage: (2*P).has_good_reduction()
|
|
3073
|
+
True
|
|
3074
|
+
sage: (3*P).has_good_reduction()
|
|
3075
|
+
False
|
|
3076
|
+
|
|
3077
|
+
::
|
|
3078
|
+
|
|
3079
|
+
sage: # needs sage.rings.number_field
|
|
3080
|
+
sage: x = polygen(ZZ, 'x')
|
|
3081
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
3082
|
+
sage: E = EllipticCurve(K, [0,1,0,-160,308])
|
|
3083
|
+
sage: P = E(26, -120)
|
|
3084
|
+
sage: E.discriminant().support()
|
|
3085
|
+
[Fractional ideal (i - 1),
|
|
3086
|
+
Fractional ideal (2*i - 1),
|
|
3087
|
+
Fractional ideal (-2*i - 1),
|
|
3088
|
+
Fractional ideal (3)]
|
|
3089
|
+
sage: [E.tamagawa_exponent(p) for p in E.discriminant().support()]
|
|
3090
|
+
[1, 4, 4, 4]
|
|
3091
|
+
sage: P.has_good_reduction()
|
|
3092
|
+
False
|
|
3093
|
+
sage: (2*P).has_good_reduction()
|
|
3094
|
+
False
|
|
3095
|
+
sage: (4*P).has_good_reduction()
|
|
3096
|
+
True
|
|
3097
|
+
|
|
3098
|
+
TESTS:
|
|
3099
|
+
|
|
3100
|
+
An example showing that :issue:`8498` is fixed::
|
|
3101
|
+
|
|
3102
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
3103
|
+
sage: E = EllipticCurve('11a1')
|
|
3104
|
+
sage: K.<t> = NumberField(x^2 + 47)
|
|
3105
|
+
sage: EK = E.base_extend(K)
|
|
3106
|
+
sage: T = EK(5, 5)
|
|
3107
|
+
sage: P = EK(-2, -1/2*t - 1/2)
|
|
3108
|
+
sage: p = K.ideal(11)
|
|
3109
|
+
sage: T.has_good_reduction(p)
|
|
3110
|
+
False
|
|
3111
|
+
sage: P.has_good_reduction(p)
|
|
3112
|
+
True
|
|
3113
|
+
"""
|
|
3114
|
+
if self.is_zero(): # trivial case
|
|
3115
|
+
return True
|
|
3116
|
+
|
|
3117
|
+
E = self.curve()
|
|
3118
|
+
if P is None:
|
|
3119
|
+
return all(self.has_good_reduction(Pr)
|
|
3120
|
+
for Pr in E.discriminant().support())
|
|
3121
|
+
K = E.base_field()
|
|
3122
|
+
from sage.schemes.elliptic_curves.ell_local_data import check_prime
|
|
3123
|
+
P = check_prime(K, P)
|
|
3124
|
+
|
|
3125
|
+
# If the curve has good reduction at P, the result is True:
|
|
3126
|
+
t = E.local_data(P).bad_reduction_type()
|
|
3127
|
+
if t is None:
|
|
3128
|
+
return True
|
|
3129
|
+
|
|
3130
|
+
# Make sure the curve is integral and locally minimal at P:
|
|
3131
|
+
Emin = E.local_minimal_model(P)
|
|
3132
|
+
urst = E.isomorphism_to(Emin)
|
|
3133
|
+
Q = urst(self)
|
|
3134
|
+
|
|
3135
|
+
# Scale the homogeneous coordinates of the point to be primitive:
|
|
3136
|
+
xyz = list(Q)
|
|
3137
|
+
e = min([c.valuation(P) for c in xyz])
|
|
3138
|
+
if e != 0:
|
|
3139
|
+
if K is QQ:
|
|
3140
|
+
pi = P
|
|
3141
|
+
else:
|
|
3142
|
+
pi = K.uniformizer(P)
|
|
3143
|
+
pie = pi**e
|
|
3144
|
+
xyz = [c/pie for c in xyz]
|
|
3145
|
+
|
|
3146
|
+
# Evaluate the partial derivatives at the point to see if they
|
|
3147
|
+
# are zero mod P
|
|
3148
|
+
|
|
3149
|
+
# See #8498: sometimes evaluating F's derivatives at xyz
|
|
3150
|
+
# returns a constant polynomial instead of a constant
|
|
3151
|
+
|
|
3152
|
+
F = Emin.defining_polynomial()
|
|
3153
|
+
for v in F.variables():
|
|
3154
|
+
c = (F.derivative(v))(xyz)
|
|
3155
|
+
try:
|
|
3156
|
+
val = c.valuation(P)
|
|
3157
|
+
except AttributeError:
|
|
3158
|
+
val = c.constant_coefficient().valuation(P)
|
|
3159
|
+
if val == 0:
|
|
3160
|
+
return True
|
|
3161
|
+
return False
|
|
3162
|
+
|
|
3163
|
+
def reduction(self, p):
|
|
3164
|
+
"""
|
|
3165
|
+
This finds the reduction of a point `P` on the elliptic curve
|
|
3166
|
+
modulo the prime `p`.
|
|
3167
|
+
|
|
3168
|
+
INPUT:
|
|
3169
|
+
|
|
3170
|
+
- ``self`` -- a point on an elliptic curve
|
|
3171
|
+
|
|
3172
|
+
- ``p`` -- a prime number
|
|
3173
|
+
|
|
3174
|
+
OUTPUT: the point reduced to be a point on the elliptic curve modulo `p`
|
|
3175
|
+
|
|
3176
|
+
EXAMPLES::
|
|
3177
|
+
|
|
3178
|
+
sage: E = EllipticCurve([1,2,3,4,0])
|
|
3179
|
+
sage: P = E(0,0)
|
|
3180
|
+
sage: P.reduction(5)
|
|
3181
|
+
(0 : 0 : 1)
|
|
3182
|
+
sage: Q = E(98,931)
|
|
3183
|
+
sage: Q.reduction(5)
|
|
3184
|
+
(3 : 1 : 1)
|
|
3185
|
+
sage: Q.reduction(5).curve() == E.reduction(5)
|
|
3186
|
+
True
|
|
3187
|
+
|
|
3188
|
+
::
|
|
3189
|
+
|
|
3190
|
+
sage: # needs sage.rings.number_field
|
|
3191
|
+
sage: x = polygen(ZZ, 'x')
|
|
3192
|
+
sage: F.<a> = NumberField(x^2 + 5)
|
|
3193
|
+
sage: E = EllipticCurve(F, [1,2,3,4,0])
|
|
3194
|
+
sage: Q = E(98, 931)
|
|
3195
|
+
sage: Q.reduction(a)
|
|
3196
|
+
(3 : 1 : 1)
|
|
3197
|
+
sage: Q.reduction(11)
|
|
3198
|
+
(10 : 7 : 1)
|
|
3199
|
+
|
|
3200
|
+
::
|
|
3201
|
+
|
|
3202
|
+
sage: # needs sage.rings.number_field
|
|
3203
|
+
sage: F.<a> = NumberField(x^3 + x^2 + 1)
|
|
3204
|
+
sage: E = EllipticCurve(F, [a,2])
|
|
3205
|
+
sage: P = E(a, 1)
|
|
3206
|
+
sage: P.reduction(F.ideal(5))
|
|
3207
|
+
(abar : 1 : 1)
|
|
3208
|
+
sage: P.reduction(F.ideal(a^2 - 4*a - 2))
|
|
3209
|
+
(abar : 1 : 1)
|
|
3210
|
+
"""
|
|
3211
|
+
P = self
|
|
3212
|
+
E = P.curve()
|
|
3213
|
+
return E.reduction(p)(P)
|
|
3214
|
+
|
|
3215
|
+
def height(self, precision=None, normalised=True, algorithm='pari'):
|
|
3216
|
+
r"""Return the Néron-Tate canonical height of the point.
|
|
3217
|
+
|
|
3218
|
+
INPUT:
|
|
3219
|
+
|
|
3220
|
+
- ``self`` -- a point on an elliptic curve over a number field `K`
|
|
3221
|
+
|
|
3222
|
+
- ``precision`` -- positive integer, or ``None`` (default). The
|
|
3223
|
+
precision in bits of the result. If ``None``, the default real
|
|
3224
|
+
precision is used.
|
|
3225
|
+
|
|
3226
|
+
- ``normalised`` -- boolean. If ``True`` (default), the height is
|
|
3227
|
+
normalised to be invariant under extension of `K`. If ``False``,
|
|
3228
|
+
return this normalised height multiplied by the degree of `K`.
|
|
3229
|
+
|
|
3230
|
+
- ``algorithm`` -- string; either ``'pari'`` (default) or ``'sage'``.
|
|
3231
|
+
If ``'pari'`` and the base field is `\QQ`, use the PARI library
|
|
3232
|
+
function; otherwise use the Sage implementation.
|
|
3233
|
+
|
|
3234
|
+
OUTPUT:
|
|
3235
|
+
|
|
3236
|
+
The rational number 0, or a nonnegative real number.
|
|
3237
|
+
|
|
3238
|
+
There are two normalisations used in the literature, one of
|
|
3239
|
+
which is double the other. We use the larger of the two, which
|
|
3240
|
+
is the one appropriate for the BSD conjecture. This is
|
|
3241
|
+
consistent with [Cre1997]_ and double that of [Sil2009]_.
|
|
3242
|
+
|
|
3243
|
+
See :wikipedia:`Néron-Tate height`.
|
|
3244
|
+
|
|
3245
|
+
.. NOTE::
|
|
3246
|
+
|
|
3247
|
+
The correct height to use for the regulator in the BSD
|
|
3248
|
+
formula is the non-normalised height.
|
|
3249
|
+
|
|
3250
|
+
EXAMPLES::
|
|
3251
|
+
|
|
3252
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3253
|
+
sage: E = EllipticCurve('11a'); E
|
|
3254
|
+
Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field
|
|
3255
|
+
sage: P = E([5,5]); P
|
|
3256
|
+
(5 : 5 : 1)
|
|
3257
|
+
sage: P.height()
|
|
3258
|
+
0
|
|
3259
|
+
sage: Q = 5*P
|
|
3260
|
+
sage: Q.height()
|
|
3261
|
+
0
|
|
3262
|
+
|
|
3263
|
+
::
|
|
3264
|
+
|
|
3265
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3266
|
+
sage: E = EllipticCurve('37a'); E
|
|
3267
|
+
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
|
|
3268
|
+
sage: P = E([0,0])
|
|
3269
|
+
sage: P.height()
|
|
3270
|
+
0.0511114082399688
|
|
3271
|
+
sage: P.order()
|
|
3272
|
+
+Infinity
|
|
3273
|
+
sage: E.regulator() # needs eclib
|
|
3274
|
+
0.0511114082399688...
|
|
3275
|
+
sage: def naive_height(P):
|
|
3276
|
+
....: return log(RR(max(abs(P[0].numerator()), abs(P[0].denominator()))))
|
|
3277
|
+
sage: for n in [1..10]:
|
|
3278
|
+
....: print(naive_height(2^n*P)/4^n)
|
|
3279
|
+
0.000000000000000
|
|
3280
|
+
0.0433216987849966
|
|
3281
|
+
0.0502949347635656
|
|
3282
|
+
0.0511006335618645
|
|
3283
|
+
0.0511007834799612
|
|
3284
|
+
0.0511013666152466
|
|
3285
|
+
0.0511034199907743
|
|
3286
|
+
0.0511106492906471
|
|
3287
|
+
0.0511114081541082
|
|
3288
|
+
0.0511114081541180
|
|
3289
|
+
|
|
3290
|
+
::
|
|
3291
|
+
|
|
3292
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3293
|
+
sage: E = EllipticCurve('4602a1'); E
|
|
3294
|
+
Elliptic Curve defined by y^2 + x*y = x^3 + x^2 - 37746035*x - 89296920339
|
|
3295
|
+
over Rational Field
|
|
3296
|
+
sage: x = 77985922458974949246858229195945103471590
|
|
3297
|
+
sage: y = 19575260230015313702261379022151675961965157108920263594545223
|
|
3298
|
+
sage: d = 2254020761884782243
|
|
3299
|
+
sage: E([ x / d^2, y / d^3 ]).height()
|
|
3300
|
+
86.7406561381275
|
|
3301
|
+
|
|
3302
|
+
::
|
|
3303
|
+
|
|
3304
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3305
|
+
sage: E = EllipticCurve([17, -60, -120, 0, 0]); E
|
|
3306
|
+
Elliptic Curve defined by y^2 + 17*x*y - 120*y = x^3 - 60*x^2 over Rational Field
|
|
3307
|
+
sage: E([30, -90]).height()
|
|
3308
|
+
0
|
|
3309
|
+
|
|
3310
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3311
|
+
sage: E = EllipticCurve('389a1'); E
|
|
3312
|
+
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
|
|
3313
|
+
sage: P, Q = E(-1,1), E(0,-1)
|
|
3314
|
+
sage: P.height(precision=100)
|
|
3315
|
+
0.68666708330558658572355210295
|
|
3316
|
+
sage: (3*Q).height(precision=100)/Q.height(precision=100)
|
|
3317
|
+
9.0000000000000000000000000000
|
|
3318
|
+
sage: _.parent()
|
|
3319
|
+
Real Field with 100 bits of precision
|
|
3320
|
+
|
|
3321
|
+
Canonical heights over number fields are implemented as well::
|
|
3322
|
+
|
|
3323
|
+
sage: R.<x> = QQ[]
|
|
3324
|
+
sage: K.<a> = NumberField(x^3 - 2) # needs sage.rings.number_field
|
|
3325
|
+
sage: E = EllipticCurve([a, 4]); E # needs sage.rings.number_field
|
|
3326
|
+
Elliptic Curve defined by y^2 = x^3 + a*x + 4
|
|
3327
|
+
over Number Field in a with defining polynomial x^3 - 2
|
|
3328
|
+
sage: P = E((0,2)) # needs sage.rings.number_field
|
|
3329
|
+
sage: P.height() # needs sage.rings.number_field
|
|
3330
|
+
0.810463096585925
|
|
3331
|
+
sage: P.height(precision=100) # needs sage.rings.number_field
|
|
3332
|
+
0.81046309658592536863991810577
|
|
3333
|
+
sage: P.height(precision=200) # needs sage.rings.number_field
|
|
3334
|
+
0.81046309658592536863991810576865158896130286417155832378086
|
|
3335
|
+
sage: (2*P).height() / P.height() # needs sage.rings.number_field
|
|
3336
|
+
4.00000000000000
|
|
3337
|
+
sage: (100*P).height() / P.height() # needs sage.rings.number_field
|
|
3338
|
+
10000.0000000000
|
|
3339
|
+
|
|
3340
|
+
Setting ``normalised=False`` multiplies the height by the degree of `K`::
|
|
3341
|
+
|
|
3342
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3343
|
+
sage: E = EllipticCurve('37a')
|
|
3344
|
+
sage: P = E([0,0])
|
|
3345
|
+
sage: P.height()
|
|
3346
|
+
0.0511114082399688
|
|
3347
|
+
sage: P.height(normalised=False)
|
|
3348
|
+
0.0511114082399688
|
|
3349
|
+
sage: K.<z> = CyclotomicField(5) # needs sage.rings.number_field
|
|
3350
|
+
sage: EK = E.change_ring(K) # needs sage.rings.number_field
|
|
3351
|
+
sage: PK = EK([0,0]) # needs sage.rings.number_field
|
|
3352
|
+
sage: PK.height() # needs sage.rings.number_field
|
|
3353
|
+
0.0511114082399688
|
|
3354
|
+
sage: PK.height(normalised=False) # needs sage.rings.number_field
|
|
3355
|
+
0.204445632959875
|
|
3356
|
+
|
|
3357
|
+
Some consistency checks::
|
|
3358
|
+
|
|
3359
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3360
|
+
sage: E = EllipticCurve('5077a1')
|
|
3361
|
+
sage: P = E([-2,3,1])
|
|
3362
|
+
sage: P.height()
|
|
3363
|
+
1.36857250535393
|
|
3364
|
+
sage: EK = E.change_ring(QuadraticField(-3,'a')) # needs sage.rings.number_field
|
|
3365
|
+
sage: PK = EK([-2,3,1]) # needs sage.rings.number_field
|
|
3366
|
+
sage: PK.height() # needs sage.rings.number_field
|
|
3367
|
+
1.36857250535393
|
|
3368
|
+
|
|
3369
|
+
sage: # needs sage.rings.number_field
|
|
3370
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
3371
|
+
sage: E = EllipticCurve(K, [0,0,4,6*i,0])
|
|
3372
|
+
sage: Q = E.lift_x(-9/4); Q
|
|
3373
|
+
(-9/4 : 27/8*i - 4 : 1)
|
|
3374
|
+
sage: Q.height()
|
|
3375
|
+
2.69518560017909
|
|
3376
|
+
sage: (15*Q).height() / Q.height()
|
|
3377
|
+
225.000000000000
|
|
3378
|
+
|
|
3379
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3380
|
+
sage: E = EllipticCurve('37a')
|
|
3381
|
+
sage: P = E([0,-1])
|
|
3382
|
+
sage: P.height()
|
|
3383
|
+
0.0511114082399688
|
|
3384
|
+
sage: K.<a> = QuadraticField(-7) # needs sage.rings.number_field
|
|
3385
|
+
sage: ED = E.quadratic_twist(-7) # needs sage.rings.number_field
|
|
3386
|
+
sage: Q = E.isomorphism_to(ED.change_ring(K))(P); Q # needs sage.rings.number_field
|
|
3387
|
+
(0 : -7/2*a - 1/2 : 1)
|
|
3388
|
+
sage: Q.height() # needs sage.rings.number_field
|
|
3389
|
+
0.0511114082399688
|
|
3390
|
+
sage: Q.height(precision=100) # needs sage.rings.number_field
|
|
3391
|
+
0.051111408239968840235886099757
|
|
3392
|
+
|
|
3393
|
+
An example to show that the bug at :issue:`5252` is fixed::
|
|
3394
|
+
|
|
3395
|
+
sage: E = EllipticCurve([1, -1, 1, -2063758701246626370773726978, 32838647793306133075103747085833809114881])
|
|
3396
|
+
sage: P = E([-30987785091199, 258909576181697016447])
|
|
3397
|
+
sage: P.height()
|
|
3398
|
+
25.8603170675462
|
|
3399
|
+
sage: P.height(precision=100)
|
|
3400
|
+
25.860317067546190743868840741
|
|
3401
|
+
sage: P.height(precision=250)
|
|
3402
|
+
25.860317067546190743868840740735110323098872903844416215577171041783572513
|
|
3403
|
+
sage: P.height(precision=500)
|
|
3404
|
+
25.8603170675461907438688407407351103230988729038444162155771710417835725129551130570889813281792157278507639909972112856019190236125362914195452321720
|
|
3405
|
+
|
|
3406
|
+
sage: P.height(precision=100) == P.non_archimedean_local_height(prec=100)+P.archimedean_local_height(prec=100)
|
|
3407
|
+
True
|
|
3408
|
+
|
|
3409
|
+
An example to show that the bug at :issue:`8319` is fixed (correct height when the curve is not minimal)::
|
|
3410
|
+
|
|
3411
|
+
sage: E = EllipticCurve([-5580472329446114952805505804593498080000,-157339733785368110382973689903536054787700497223306368000000])
|
|
3412
|
+
sage: xP = 204885147732879546487576840131729064308289385547094673627174585676211859152978311600/23625501907057948132262217188983681204856907657753178415430361
|
|
3413
|
+
sage: P = E.lift_x(xP)
|
|
3414
|
+
sage: P.height()
|
|
3415
|
+
157.432598516754
|
|
3416
|
+
sage: Q = 2*P
|
|
3417
|
+
sage: Q.height() # long time (4s)
|
|
3418
|
+
629.730394067016
|
|
3419
|
+
sage: Q.height()-4*P.height() # long time
|
|
3420
|
+
0.000000000000000
|
|
3421
|
+
|
|
3422
|
+
An example to show that the bug at :issue:`12509` is fixed (precision issues)::
|
|
3423
|
+
|
|
3424
|
+
sage: # needs sage.rings.number_field
|
|
3425
|
+
sage: x = polygen(QQ)
|
|
3426
|
+
sage: K.<a> = NumberField(x^2 - x - 1)
|
|
3427
|
+
sage: v = [0, a + 1, 1, 28665*a - 46382, 2797026*a - 4525688]
|
|
3428
|
+
sage: E = EllipticCurve(v)
|
|
3429
|
+
sage: P = E([72*a - 509/5, -682/25*a - 434/25])
|
|
3430
|
+
sage: P.height()
|
|
3431
|
+
1.38877711688727
|
|
3432
|
+
sage: (2*P).height()/P.height()
|
|
3433
|
+
4.00000000000000
|
|
3434
|
+
sage: (2*P).height(precision=100)/P.height(precision=100)
|
|
3435
|
+
4.0000000000000000000000000000
|
|
3436
|
+
sage: (2*P).height(precision=1000)/P.height(precision=1000)
|
|
3437
|
+
4.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
3438
|
+
|
|
3439
|
+
This shows that the bug reported at :issue:`13951` has been fixed::
|
|
3440
|
+
|
|
3441
|
+
sage: E = EllipticCurve([0,17])
|
|
3442
|
+
sage: P1 = E(2,5)
|
|
3443
|
+
sage: P1.height()
|
|
3444
|
+
1.06248137652528
|
|
3445
|
+
sage: F = E.change_ring(QuadraticField(-3, 'a')) # needs sage.rings.number_field
|
|
3446
|
+
sage: P2 = F([2,5]) # needs sage.rings.number_field
|
|
3447
|
+
sage: P2.height() # needs sage.rings.number_field
|
|
3448
|
+
1.06248137652528
|
|
3449
|
+
|
|
3450
|
+
This shows that the bug reported at :issue:`36834` (incorrect
|
|
3451
|
+
value when the model is not integral) has been fixed::
|
|
3452
|
+
|
|
3453
|
+
sage: # needs sage.rings.number_field
|
|
3454
|
+
sage: K.<a> = NumberField(x^2 - 84131656042917)
|
|
3455
|
+
sage: E = EllipticCurve(K, [0, 0, 0, -5482707841/48, -244634179112639/864])
|
|
3456
|
+
sage: P = E(349189/12, 1/2*a)
|
|
3457
|
+
sage: P.height()
|
|
3458
|
+
10.4560438181991
|
|
3459
|
+
sage: [(n*P).height()/P.height() for n in [2,3,4,5]]
|
|
3460
|
+
[4.00000000000000, 9.00000000000000, 16.0000000000000, 25.0000000000000]
|
|
3461
|
+
|
|
3462
|
+
"""
|
|
3463
|
+
if self.has_finite_order():
|
|
3464
|
+
return QQ(0)
|
|
3465
|
+
|
|
3466
|
+
E = self.curve()
|
|
3467
|
+
K = E.base_ring()
|
|
3468
|
+
|
|
3469
|
+
if precision is None:
|
|
3470
|
+
precision = RealField().precision()
|
|
3471
|
+
|
|
3472
|
+
known_prec = -1
|
|
3473
|
+
try:
|
|
3474
|
+
height = self.__height
|
|
3475
|
+
known_prec = height.prec()
|
|
3476
|
+
if known_prec > precision:
|
|
3477
|
+
height = RealField(precision)(height)
|
|
3478
|
+
except AttributeError:
|
|
3479
|
+
pass
|
|
3480
|
+
|
|
3481
|
+
if known_prec < precision:
|
|
3482
|
+
if algorithm == 'pari' and K is QQ:
|
|
3483
|
+
Emin = E.minimal_model()
|
|
3484
|
+
iso = E.isomorphism_to(Emin)
|
|
3485
|
+
P = iso(self)
|
|
3486
|
+
h = Emin.pari_curve().ellheight(P, precision=precision)
|
|
3487
|
+
height = RealField(precision)(h)
|
|
3488
|
+
else:
|
|
3489
|
+
height = (self.non_archimedean_local_height(prec=precision)
|
|
3490
|
+
+ self.archimedean_local_height(prec=precision))
|
|
3491
|
+
|
|
3492
|
+
# The cached height is the one that is independent of the base field.
|
|
3493
|
+
self.__height = height
|
|
3494
|
+
if not normalised:
|
|
3495
|
+
height *= K.degree()
|
|
3496
|
+
return height
|
|
3497
|
+
|
|
3498
|
+
def archimedean_local_height(self, v=None, prec=None, weighted=False):
|
|
3499
|
+
"""
|
|
3500
|
+
Compute the local height of ``self`` at the archimedean place `v`.
|
|
3501
|
+
|
|
3502
|
+
INPUT:
|
|
3503
|
+
|
|
3504
|
+
- ``self`` -- a point on an elliptic curve over a number field `K`
|
|
3505
|
+
|
|
3506
|
+
- ``v`` -- a real or complex embedding of K, or None (default).
|
|
3507
|
+
If `v` is a real or complex embedding, return the local
|
|
3508
|
+
height of ``self`` at `v`. If `v` is None, return the total
|
|
3509
|
+
archimedean contribution to the global height.
|
|
3510
|
+
|
|
3511
|
+
- ``prec`` -- integer or ``None`` (default). The precision of the
|
|
3512
|
+
computation. If ``None``, the precision is deduced from `v`
|
|
3513
|
+
|
|
3514
|
+
- ``weighted`` -- boolean. If ``False`` (default), the height is
|
|
3515
|
+
normalised to be invariant under extension of `K`. If ``True``,
|
|
3516
|
+
return this normalised height multiplied by the local degree
|
|
3517
|
+
if `v` is a single place, or by the degree of `K` if `v` is ``None``.
|
|
3518
|
+
|
|
3519
|
+
OUTPUT:
|
|
3520
|
+
|
|
3521
|
+
A real number. The normalisation is twice that in Silverman's
|
|
3522
|
+
paper [Sil1988]_. Note that this local height depends on the
|
|
3523
|
+
model of the curve.
|
|
3524
|
+
|
|
3525
|
+
ALGORITHM:
|
|
3526
|
+
|
|
3527
|
+
See [Sil1988]_, Section 4.
|
|
3528
|
+
|
|
3529
|
+
EXAMPLES:
|
|
3530
|
+
|
|
3531
|
+
Examples 1, 2, and 3 from [Sil1988]_::
|
|
3532
|
+
|
|
3533
|
+
sage: # needs sage.rings.number_field
|
|
3534
|
+
sage: K.<a> = QuadraticField(-2)
|
|
3535
|
+
sage: E = EllipticCurve(K, [0,-1,1,0,0]); E
|
|
3536
|
+
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field
|
|
3537
|
+
in a with defining polynomial x^2 + 2 with a = 1.414213562373095?*I
|
|
3538
|
+
sage: P = E.lift_x(2 + a); P
|
|
3539
|
+
(a + 2 : -2*a - 2 : 1)
|
|
3540
|
+
sage: P.archimedean_local_height(K.places(prec=170)[0]) / 2
|
|
3541
|
+
0.45754773287523276736211210741423654346576029814695
|
|
3542
|
+
|
|
3543
|
+
sage: # needs sage.rings.number_field
|
|
3544
|
+
sage: x = polygen(ZZ, 'x')
|
|
3545
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
3546
|
+
sage: E = EllipticCurve(K, [0,0,4,6*i,0]); E
|
|
3547
|
+
Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x
|
|
3548
|
+
over Number Field in i with defining polynomial x^2 + 1
|
|
3549
|
+
sage: P = E((0,0))
|
|
3550
|
+
sage: P.archimedean_local_height(K.places()[0]) / 2
|
|
3551
|
+
0.510184995162373
|
|
3552
|
+
|
|
3553
|
+
sage: Q = E.lift_x(-9/4); Q # needs sage.rings.number_field
|
|
3554
|
+
(-9/4 : 27/8*i - 4 : 1)
|
|
3555
|
+
sage: Q.archimedean_local_height(K.places()[0]) / 2 # needs sage.rings.number_field
|
|
3556
|
+
0.654445619529600
|
|
3557
|
+
|
|
3558
|
+
An example over the rational numbers::
|
|
3559
|
+
|
|
3560
|
+
sage: E = EllipticCurve([0, 0, 0, -36, 0])
|
|
3561
|
+
sage: P = E([-3, 9])
|
|
3562
|
+
sage: P.archimedean_local_height()
|
|
3563
|
+
1.98723816350773
|
|
3564
|
+
|
|
3565
|
+
Local heights of torsion points can be nonzero (unlike the
|
|
3566
|
+
global height)::
|
|
3567
|
+
|
|
3568
|
+
sage: # needs sage.rings.number_field
|
|
3569
|
+
sage: K.<i> = QuadraticField(-1)
|
|
3570
|
+
sage: E = EllipticCurve([0, 0, 0, K(1), 0])
|
|
3571
|
+
sage: P = E(i, 0)
|
|
3572
|
+
sage: P.archimedean_local_height()
|
|
3573
|
+
0.346573590279973
|
|
3574
|
+
|
|
3575
|
+
TESTS:
|
|
3576
|
+
|
|
3577
|
+
See :issue:`12509`::
|
|
3578
|
+
|
|
3579
|
+
sage: # needs sage.rings.number_field
|
|
3580
|
+
sage: x = polygen(QQ)
|
|
3581
|
+
sage: K.<a> = NumberField(x^2 - x - 1)
|
|
3582
|
+
sage: v = [0, a + 1, 1, 28665*a - 46382, 2797026*a - 4525688]
|
|
3583
|
+
sage: E = EllipticCurve(v)
|
|
3584
|
+
sage: P = E([72*a - 509/5, -682/25*a - 434/25])
|
|
3585
|
+
sage: P.archimedean_local_height()
|
|
3586
|
+
-0.220660795546828
|
|
3587
|
+
|
|
3588
|
+
See :issue:`19276`::
|
|
3589
|
+
|
|
3590
|
+
sage: # needs sage.rings.number_field
|
|
3591
|
+
sage: K.<a> = NumberField(x^2 - x - 104)
|
|
3592
|
+
sage: E = EllipticCurve([1, a - 1, 1, -816765673272*a - 7931030674178, 1478955604013312315*a + 14361086227143654561])
|
|
3593
|
+
sage: P = E(5393511/49*a + 52372721/49 , -33896210324/343*a - 329141996591/343 )
|
|
3594
|
+
sage: P.height()
|
|
3595
|
+
0.974232017827741
|
|
3596
|
+
|
|
3597
|
+
See :issue:`29966`::
|
|
3598
|
+
|
|
3599
|
+
sage: # needs sage.rings.number_field
|
|
3600
|
+
sage: K.<a> = NumberField(x^3 - x^2 - 6*x + 2)
|
|
3601
|
+
sage: E = EllipticCurve([1, -a^2 + 2*a + 4, 0, -6056450500590472699700624*a^2 - 11239394326797569935861742*a + 4241549693833829432516231,
|
|
3602
|
+
....: 1904879037869682826729875958079326124520*a^2 + 3535022146945771697732350459284777382011*a - 1334055169621036218710397707677347972626])
|
|
3603
|
+
sage: P = E([1033399668533*a^2 + 1917754693229*a - 723726883800 , 12536493059202326563*a^2 + 23264879148900575548*a - 8779756111574815918 , 1])
|
|
3604
|
+
sage: P.height()
|
|
3605
|
+
0.297318833424763
|
|
3606
|
+
sage: (2*P).height() / P.height()
|
|
3607
|
+
4.00000000000000
|
|
3608
|
+
sage: P.height(200)
|
|
3609
|
+
0.29731883342476341806143743594519935578696537745294661858984
|
|
3610
|
+
sage: (2*P).height(200) / P.height(200)
|
|
3611
|
+
4.0000000000000000000000000000000000000000000000000000000000
|
|
3612
|
+
"""
|
|
3613
|
+
from sage.rings.number_field.number_field import refine_embedding
|
|
3614
|
+
from sage.rings.real_mpfr import RealField
|
|
3615
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
3616
|
+
from sage.rings.infinity import Infinity
|
|
3617
|
+
|
|
3618
|
+
E = self.curve()
|
|
3619
|
+
K = E.base_ring()
|
|
3620
|
+
|
|
3621
|
+
if v is None:
|
|
3622
|
+
|
|
3623
|
+
if prec is None:
|
|
3624
|
+
prec = 53
|
|
3625
|
+
if K is QQ:
|
|
3626
|
+
v = K.embeddings(RR)[0]
|
|
3627
|
+
h = self.archimedean_local_height(v, prec+10)
|
|
3628
|
+
else:
|
|
3629
|
+
r1, r2 = K.signature()
|
|
3630
|
+
pl = K.places()
|
|
3631
|
+
h = (sum(self.archimedean_local_height(pl[i], prec+10, weighted=False)
|
|
3632
|
+
for i in range(r1))
|
|
3633
|
+
+ 2 * sum(self.archimedean_local_height(pl[i], prec+10, weighted=False)
|
|
3634
|
+
for i in range(r1, r1 + r2)))
|
|
3635
|
+
if not weighted:
|
|
3636
|
+
h /= K.degree()
|
|
3637
|
+
return RealField(prec)(h)
|
|
3638
|
+
|
|
3639
|
+
prec_v = v.codomain().prec()
|
|
3640
|
+
if prec is None:
|
|
3641
|
+
prec = prec_v
|
|
3642
|
+
if K is QQ:
|
|
3643
|
+
v = K.embeddings(RealField())[0]
|
|
3644
|
+
v_inf = refine_embedding(v, Infinity)
|
|
3645
|
+
v_is_real = v_inf(K.gen()).imag().is_zero()
|
|
3646
|
+
|
|
3647
|
+
# Find a suitable working precision. See trac#29666 for an
|
|
3648
|
+
# example where 100 extra bits is not enough when the
|
|
3649
|
+
# discriminant is ~1e-92, but this code uses a working
|
|
3650
|
+
# precision of 333 and gets it right.
|
|
3651
|
+
|
|
3652
|
+
D = v_inf(E.discriminant())
|
|
3653
|
+
|
|
3654
|
+
if D.abs().real_number(RealField()).round():
|
|
3655
|
+
extra_prec = 100
|
|
3656
|
+
else: # then |D| is small
|
|
3657
|
+
extra_prec = 10 + (1/D).abs().real_number(RealField()).round().nbits()
|
|
3658
|
+
|
|
3659
|
+
working_prec = prec + extra_prec
|
|
3660
|
+
RC = RealField(working_prec) if v_is_real else ComplexField(working_prec)
|
|
3661
|
+
# print("Using working precision {}, |D| = {}".format(working_prec, RC(D).abs()))
|
|
3662
|
+
|
|
3663
|
+
# NB We risk losing much precision if we compute the embedding
|
|
3664
|
+
# of K into RR or CC to some precision and then apply that to
|
|
3665
|
+
# elements of K. Instead we map elements of K into AA or Qbar
|
|
3666
|
+
# (with infinite precision) and then trim back to RR or CC.
|
|
3667
|
+
|
|
3668
|
+
x = RC(v_inf(self[0]))
|
|
3669
|
+
b2, b4, b6, b8 = (RC(v_inf(b)) for b in E.b_invariants())
|
|
3670
|
+
|
|
3671
|
+
# The following comes from Silverman Theorem 4.2. Silverman
|
|
3672
|
+
# uses decimal precision d, so his term (5/3)d =
|
|
3673
|
+
# (5/3)*(log(2)/log(10))*prec = 0.5017*prec, which we round
|
|
3674
|
+
# up. The rest of the expression was wrongly transcribed in
|
|
3675
|
+
# Sage versions <5.6 (see #12509).
|
|
3676
|
+
|
|
3677
|
+
H = max(RC(4).abs(), b2.abs(), 2*b4.abs(), 2*b6.abs(), b8.abs())
|
|
3678
|
+
absdisc = RC(v_inf(E.discriminant())).abs()
|
|
3679
|
+
adl3 = 0 if absdisc >= 1 else absdisc.log() / 3
|
|
3680
|
+
nterms = int(math.ceil(0.51*working_prec + 0.5 + 0.75 * (7 + 4*H.log()/3 - adl3).log()))
|
|
3681
|
+
|
|
3682
|
+
b2p = b2 - 12
|
|
3683
|
+
b4p = b4 - b2 + 6
|
|
3684
|
+
b6p = b6 - 2*b4 + b2 - 4
|
|
3685
|
+
b8p = b8 - 3*b6 + 3*b4 - b2 + 3
|
|
3686
|
+
|
|
3687
|
+
fz = lambda T: 1 - T**2 * (b4 + T*(2*b6 + T*b8))
|
|
3688
|
+
fzp = lambda T: 1 - T**2 * (b4p + T*(2*b6p + T*b8p))
|
|
3689
|
+
fw = lambda T: T*(4 + T*(b2 + T*(2*b4 + T*b6)))
|
|
3690
|
+
fwp = lambda T: T*(4 + T*(b2p + T*(2*b4p + T*b6p)))
|
|
3691
|
+
|
|
3692
|
+
if abs(x) >= .5:
|
|
3693
|
+
t = 1/x
|
|
3694
|
+
beta = True
|
|
3695
|
+
else:
|
|
3696
|
+
t = 1/(x+1)
|
|
3697
|
+
beta = False
|
|
3698
|
+
lam = -t.abs().log()
|
|
3699
|
+
mu = 0
|
|
3700
|
+
four_to_n = QQ(1)
|
|
3701
|
+
|
|
3702
|
+
for n in range(nterms):
|
|
3703
|
+
if beta:
|
|
3704
|
+
w = fw(t)
|
|
3705
|
+
z = fz(t)
|
|
3706
|
+
if abs(w) <= 2 * z.abs():
|
|
3707
|
+
mu += four_to_n * z.abs().log()
|
|
3708
|
+
t = w/z
|
|
3709
|
+
else:
|
|
3710
|
+
mu += four_to_n * (z+w).abs().log()
|
|
3711
|
+
t = w/(z+w)
|
|
3712
|
+
beta = not beta
|
|
3713
|
+
else:
|
|
3714
|
+
w = fwp(t)
|
|
3715
|
+
z = fzp(t)
|
|
3716
|
+
if abs(w) <= 2 * z.abs():
|
|
3717
|
+
mu += four_to_n * z.abs().log()
|
|
3718
|
+
t = w/z
|
|
3719
|
+
else:
|
|
3720
|
+
mu += four_to_n * (z-w).abs().log()
|
|
3721
|
+
t = w/(z-w)
|
|
3722
|
+
beta = not beta
|
|
3723
|
+
four_to_n >>= 2
|
|
3724
|
+
|
|
3725
|
+
h = RealField(prec)(lam + mu/4)
|
|
3726
|
+
if weighted and not v_is_real:
|
|
3727
|
+
h *= 2
|
|
3728
|
+
return h
|
|
3729
|
+
|
|
3730
|
+
def non_archimedean_local_height(self, v=None, prec=None,
|
|
3731
|
+
weighted=False, is_minimal=None):
|
|
3732
|
+
"""
|
|
3733
|
+
Compute the local height of ``self`` at non-archimedean places.
|
|
3734
|
+
|
|
3735
|
+
INPUT:
|
|
3736
|
+
|
|
3737
|
+
- ``self`` -- a point on an elliptic curve over a number field `K`
|
|
3738
|
+
|
|
3739
|
+
- ``v`` -- a non-archimedean place of `K`, or ``None`` (default).
|
|
3740
|
+
If `v` is a non-archimedean place, return the local height
|
|
3741
|
+
of ``self`` at `v`. If `v` is ``None``, return the total
|
|
3742
|
+
non-archimedean contribution to the global height.
|
|
3743
|
+
|
|
3744
|
+
- ``prec`` -- integer; or ``None`` (default). The precision of the
|
|
3745
|
+
computation. If ``None``, the height is returned symbolically
|
|
3746
|
+
|
|
3747
|
+
- ``weighted`` -- boolean. If ``False`` (default), the height is
|
|
3748
|
+
normalised to be invariant under extension of `K`. If ``True``,
|
|
3749
|
+
return this normalised height multiplied by the local degree
|
|
3750
|
+
if `v` is a single place, or by the degree of `K` if `v` is ``None``.
|
|
3751
|
+
|
|
3752
|
+
- ``is_minimal`` -- boolean, or ``None`` (default). Ignored
|
|
3753
|
+
when ``v`` is ``None`` (default) or ``True``. Otherwise,
|
|
3754
|
+
when the place ``v`` is specified: if ``True``, the model is
|
|
3755
|
+
assumed to be both locally integral and a local minimal
|
|
3756
|
+
model; if ``None`` (default) or ``False``, a local minimal
|
|
3757
|
+
model is computed and the computation is done on that model.
|
|
3758
|
+
|
|
3759
|
+
OUTPUT:
|
|
3760
|
+
|
|
3761
|
+
A real number. The normalisation is twice that in Silverman's
|
|
3762
|
+
paper [Sil1988]_. Note that this local height depends on the
|
|
3763
|
+
model of the curve.
|
|
3764
|
+
|
|
3765
|
+
ALGORITHM:
|
|
3766
|
+
|
|
3767
|
+
See [Sil1988]_, Section 5.
|
|
3768
|
+
|
|
3769
|
+
EXAMPLES:
|
|
3770
|
+
|
|
3771
|
+
Examples 2 and 3 from [Sil1988]_::
|
|
3772
|
+
|
|
3773
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
3774
|
+
sage: x = polygen(ZZ, 'x')
|
|
3775
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
3776
|
+
sage: E = EllipticCurve(K, [0,0,4,6*i,0]); E
|
|
3777
|
+
Elliptic Curve defined by y^2 + 4*y = x^3 + 6*i*x
|
|
3778
|
+
over Number Field in i with defining polynomial x^2 + 1
|
|
3779
|
+
sage: P = E((0,0))
|
|
3780
|
+
sage: P.non_archimedean_local_height(K.ideal(i+1))
|
|
3781
|
+
-1/2*log(2)
|
|
3782
|
+
sage: P.non_archimedean_local_height(K.ideal(3))
|
|
3783
|
+
0
|
|
3784
|
+
sage: P.non_archimedean_local_height(K.ideal(1-2*i))
|
|
3785
|
+
0
|
|
3786
|
+
sage: Q = E.lift_x(-9/4); Q
|
|
3787
|
+
(-9/4 : 27/8*i - 4 : 1)
|
|
3788
|
+
sage: Q.non_archimedean_local_height(K.ideal(1+i))
|
|
3789
|
+
2*log(2)
|
|
3790
|
+
sage: Q.non_archimedean_local_height(K.ideal(3))
|
|
3791
|
+
0
|
|
3792
|
+
sage: Q.non_archimedean_local_height(K.ideal(1-2*i))
|
|
3793
|
+
0
|
|
3794
|
+
sage: Q.non_archimedean_local_height()
|
|
3795
|
+
2*log(2)
|
|
3796
|
+
|
|
3797
|
+
An example over the rational numbers::
|
|
3798
|
+
|
|
3799
|
+
sage: E = EllipticCurve([0, 0, 0, -36, 0])
|
|
3800
|
+
sage: P = E([-3, 9])
|
|
3801
|
+
sage: P.non_archimedean_local_height() # needs sage.symbolic
|
|
3802
|
+
-log(3)
|
|
3803
|
+
|
|
3804
|
+
Local heights of torsion points can be nonzero (unlike the
|
|
3805
|
+
global height)::
|
|
3806
|
+
|
|
3807
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
3808
|
+
sage: K.<i> = QuadraticField(-1)
|
|
3809
|
+
sage: E = EllipticCurve([0, 0, 0, K(1), 0])
|
|
3810
|
+
sage: P = E(i, 0)
|
|
3811
|
+
sage: P.non_archimedean_local_height()
|
|
3812
|
+
-1/2*log(2)
|
|
3813
|
+
|
|
3814
|
+
TESTS::
|
|
3815
|
+
|
|
3816
|
+
sage: Q.non_archimedean_local_height(prec=100) # needs sage.rings.number_field sage.symbolic
|
|
3817
|
+
1.3862943611198906188344642429
|
|
3818
|
+
sage: (3*Q).non_archimedean_local_height() # needs sage.rings.number_field sage.symbolic
|
|
3819
|
+
1/2*log(75923153929839865104)
|
|
3820
|
+
|
|
3821
|
+
sage: # needs sage.rings.number_field
|
|
3822
|
+
sage: x = polygen(ZZ, 'x')
|
|
3823
|
+
sage: F.<a> = NumberField(x^4 + 2*x^3 + 19*x^2 + 18*x + 288)
|
|
3824
|
+
sage: F.ring_of_integers().basis()
|
|
3825
|
+
[1, 5/6*a^3 + 1/6*a, 1/6*a^3 + 1/6*a^2, a^3]
|
|
3826
|
+
sage: F.class_number()
|
|
3827
|
+
12
|
|
3828
|
+
sage: E = EllipticCurve('37a').change_ring(F)
|
|
3829
|
+
sage: P = E((-a^2/6 - a/6 - 1, a)); P
|
|
3830
|
+
(-1/6*a^2 - 1/6*a - 1 : a : 1)
|
|
3831
|
+
sage: P[0].is_integral()
|
|
3832
|
+
True
|
|
3833
|
+
sage: P.non_archimedean_local_height() # needs sage.symbolic
|
|
3834
|
+
0
|
|
3835
|
+
|
|
3836
|
+
This shows that the bug reported at :issue:`13951` has been fixed::
|
|
3837
|
+
|
|
3838
|
+
sage: E = EllipticCurve([0,17])
|
|
3839
|
+
sage: P = E(2,5)
|
|
3840
|
+
sage: P.non_archimedean_local_height(2) # needs sage.symbolic
|
|
3841
|
+
-2/3*log(2)
|
|
3842
|
+
|
|
3843
|
+
This shows that the bug reported at :issue:`36834` (incorrect
|
|
3844
|
+
value when the model is not integral) has been fixed::
|
|
3845
|
+
|
|
3846
|
+
sage: # needs sage.rings.number_field sage.symbolic
|
|
3847
|
+
sage: K.<a> = QuadraticField(84131656042917)
|
|
3848
|
+
sage: E = EllipticCurve(K, [0, 0, 0, -5482707841/48, -244634179112639/864])
|
|
3849
|
+
sage: P = E(349189/12, 1/2*a)
|
|
3850
|
+
sage: h = P.non_archimedean_local_height()
|
|
3851
|
+
sage: h
|
|
3852
|
+
1/2*log(144) - log(3) - 2*log(2)
|
|
3853
|
+
sage: h.numerator().simplify_log()
|
|
3854
|
+
0
|
|
3855
|
+
|
|
3856
|
+
"""
|
|
3857
|
+
if prec:
|
|
3858
|
+
log = lambda x: RealField(prec)(x).log()
|
|
3859
|
+
else:
|
|
3860
|
+
from sage.functions.log import log
|
|
3861
|
+
|
|
3862
|
+
if v is None:
|
|
3863
|
+
D = self.curve().discriminant()
|
|
3864
|
+
K = self.curve().base_ring()
|
|
3865
|
+
if K is QQ:
|
|
3866
|
+
factorD = D.factor()
|
|
3867
|
+
if self[0] == 0:
|
|
3868
|
+
c = 1
|
|
3869
|
+
else:
|
|
3870
|
+
c = self[0].denominator()
|
|
3871
|
+
# The last sum is for bad primes that divide c where
|
|
3872
|
+
# the model is not minimal.
|
|
3873
|
+
h = (log(c)
|
|
3874
|
+
+ sum(self.non_archimedean_local_height(p, prec, weighted=True, is_minimal=(e < 12))
|
|
3875
|
+
for p, e in factorD if not p.divides(c))
|
|
3876
|
+
+ sum(self.non_archimedean_local_height(p, prec, weighted=True)
|
|
3877
|
+
- c.valuation(p) * log(p)
|
|
3878
|
+
for p, e in factorD if e >= 12 and c.valuation(p)))
|
|
3879
|
+
else:
|
|
3880
|
+
factorD = K.factor(D)
|
|
3881
|
+
if self[0] == 0:
|
|
3882
|
+
c = K.ideal(1)
|
|
3883
|
+
else:
|
|
3884
|
+
c = K.ideal(self[0]).denominator()
|
|
3885
|
+
h = (log(c.norm())
|
|
3886
|
+
+ sum(self.non_archimedean_local_height(v, prec, weighted=True)
|
|
3887
|
+
- c.valuation(v) * log(v.norm())
|
|
3888
|
+
for v, e in factorD))
|
|
3889
|
+
if not weighted:
|
|
3890
|
+
h /= K.degree()
|
|
3891
|
+
return h
|
|
3892
|
+
|
|
3893
|
+
if is_minimal:
|
|
3894
|
+
E = self.curve()
|
|
3895
|
+
P = self
|
|
3896
|
+
offset = ZZ.zero()
|
|
3897
|
+
else:
|
|
3898
|
+
E = self.curve().local_minimal_model(v)
|
|
3899
|
+
P = self.curve().isomorphism_to(E)(self)
|
|
3900
|
+
# Silverman's normalization is not invariant under change of model,
|
|
3901
|
+
# but it all cancels out in the global height.
|
|
3902
|
+
offset = (self.curve().discriminant()/E.discriminant()).valuation(v)
|
|
3903
|
+
|
|
3904
|
+
a1, a2, a3, a4, a6 = E.a_invariants()
|
|
3905
|
+
b2, b4, b6, b8 = E.b_invariants()
|
|
3906
|
+
c4 = E.c4()
|
|
3907
|
+
x, y = P.xy()
|
|
3908
|
+
D = E.discriminant()
|
|
3909
|
+
N = D.valuation(v)
|
|
3910
|
+
A = (3*x**2 + 2*a2*x + a4 - a1*y).valuation(v)
|
|
3911
|
+
B = (2*y+a1*x+a3).valuation(v)
|
|
3912
|
+
C = (3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8).valuation(v)
|
|
3913
|
+
if A <= 0 or B <= 0:
|
|
3914
|
+
r = max(0, -x.valuation(v))
|
|
3915
|
+
elif c4.valuation(v) == 0:
|
|
3916
|
+
n = min(B, N/2)
|
|
3917
|
+
r = -n*(N-n)/N
|
|
3918
|
+
elif C >= 3*B:
|
|
3919
|
+
r = -2*B/3
|
|
3920
|
+
else:
|
|
3921
|
+
r = -C/4
|
|
3922
|
+
r -= offset/6
|
|
3923
|
+
if not r:
|
|
3924
|
+
return QQ.zero()
|
|
3925
|
+
else:
|
|
3926
|
+
if E.base_ring() is QQ:
|
|
3927
|
+
Nv = Integer(v)
|
|
3928
|
+
else:
|
|
3929
|
+
Nv = v.norm()
|
|
3930
|
+
if not weighted:
|
|
3931
|
+
r = r / (v.ramification_index() * v.residue_class_degree())
|
|
3932
|
+
return r * log(Nv)
|
|
3933
|
+
|
|
3934
|
+
def elliptic_logarithm(self, embedding=None, precision=100,
|
|
3935
|
+
algorithm='pari'):
|
|
3936
|
+
r"""
|
|
3937
|
+
Return the elliptic logarithm of this elliptic curve point.
|
|
3938
|
+
|
|
3939
|
+
An embedding of the base field into `\RR` or `\CC` (with
|
|
3940
|
+
arbitrary precision) may be given; otherwise the first real
|
|
3941
|
+
embedding is used (with the specified precision) if any, else
|
|
3942
|
+
the first complex embedding.
|
|
3943
|
+
|
|
3944
|
+
INPUT:
|
|
3945
|
+
|
|
3946
|
+
- ``embedding`` -- an embedding of the base field into `\RR` or `\CC`
|
|
3947
|
+
|
|
3948
|
+
- ``precision`` -- a positive integer (default: 100) setting the
|
|
3949
|
+
number of bits of precision for the computation
|
|
3950
|
+
|
|
3951
|
+
- ``algorithm`` -- either ``'pari'`` (default: for real embeddings)
|
|
3952
|
+
to use PARI's :pari:`ellpointtoz`, or ``'sage'`` for a native
|
|
3953
|
+
implementation. Ignored for complex embeddings.
|
|
3954
|
+
|
|
3955
|
+
ALGORITHM:
|
|
3956
|
+
|
|
3957
|
+
See [Coh1993]_ for the case of real embeddings,
|
|
3958
|
+
and Cremona, J.E. and Thongjunthug, T. 2010 for the complex
|
|
3959
|
+
case.
|
|
3960
|
+
|
|
3961
|
+
AUTHORS:
|
|
3962
|
+
|
|
3963
|
+
- Michael Mardaus (2008-07),
|
|
3964
|
+
- Tobias Nagel (2008-07) -- original version from [Coh1993]_.
|
|
3965
|
+
- John Cremona (2008-07) -- revision following eclib code.
|
|
3966
|
+
- John Cremona (2010-03) -- implementation for complex embeddings.
|
|
3967
|
+
|
|
3968
|
+
EXAMPLES::
|
|
3969
|
+
|
|
3970
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3971
|
+
sage: E = EllipticCurve('389a')
|
|
3972
|
+
sage: E.discriminant() > 0
|
|
3973
|
+
True
|
|
3974
|
+
sage: P = E([-1,1])
|
|
3975
|
+
sage: P.is_on_identity_component ()
|
|
3976
|
+
False
|
|
3977
|
+
sage: P.elliptic_logarithm (precision=96)
|
|
3978
|
+
0.4793482501902193161295330101 + 0.985868850775824102211203849...*I
|
|
3979
|
+
sage: Q = E([3,5])
|
|
3980
|
+
sage: Q.is_on_identity_component()
|
|
3981
|
+
True
|
|
3982
|
+
sage: Q.elliptic_logarithm (precision=96)
|
|
3983
|
+
1.931128271542559442488585220
|
|
3984
|
+
|
|
3985
|
+
An example with negative discriminant, and a torsion point::
|
|
3986
|
+
|
|
3987
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
3988
|
+
sage: E = EllipticCurve('11a1')
|
|
3989
|
+
sage: E.discriminant() < 0
|
|
3990
|
+
True
|
|
3991
|
+
sage: P = E([16,-61])
|
|
3992
|
+
sage: P.elliptic_logarithm(precision=70)
|
|
3993
|
+
0.25384186085591068434
|
|
3994
|
+
sage: E.period_lattice().real_period(prec=70) / P.elliptic_logarithm(precision=70)
|
|
3995
|
+
5.0000000000000000000
|
|
3996
|
+
|
|
3997
|
+
A larger example. The default algorithm uses PARI and makes
|
|
3998
|
+
sure the result has the requested precision::
|
|
3999
|
+
|
|
4000
|
+
sage: E = EllipticCurve([1, 0, 1, -85357462, 303528987048]) #18074g1
|
|
4001
|
+
sage: P = E([4458713781401/835903744, -64466909836503771/24167649046528, 1])
|
|
4002
|
+
sage: P.elliptic_logarithm() # 100 bits
|
|
4003
|
+
0.27656204014107061464076203097
|
|
4004
|
+
|
|
4005
|
+
The native algorithm ``'sage'`` used to have trouble with
|
|
4006
|
+
precision in this example, but no longer::
|
|
4007
|
+
|
|
4008
|
+
sage: P.elliptic_logarithm(algorithm='sage') # 100 bits
|
|
4009
|
+
0.27656204014107061464076203097
|
|
4010
|
+
|
|
4011
|
+
This shows that the bug reported at :issue:`4901` has been fixed::
|
|
4012
|
+
|
|
4013
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
4014
|
+
sage: E = EllipticCurve("4390c2")
|
|
4015
|
+
sage: P = E(683762969925/44944,-565388972095220019/9528128)
|
|
4016
|
+
sage: P.elliptic_logarithm()
|
|
4017
|
+
0.00025638725886520225353198932529
|
|
4018
|
+
sage: P.elliptic_logarithm(precision=64)
|
|
4019
|
+
0.000256387258865202254
|
|
4020
|
+
sage: P.elliptic_logarithm(precision=65)
|
|
4021
|
+
0.0002563872588652022535
|
|
4022
|
+
sage: P.elliptic_logarithm(precision=128)
|
|
4023
|
+
0.00025638725886520225353198932528666427412
|
|
4024
|
+
sage: P.elliptic_logarithm(precision=129)
|
|
4025
|
+
0.00025638725886520225353198932528666427412
|
|
4026
|
+
sage: P.elliptic_logarithm(precision=256)
|
|
4027
|
+
0.0002563872588652022535319893252866642741168388008346370015005142128009610936373
|
|
4028
|
+
sage: P.elliptic_logarithm(precision=257)
|
|
4029
|
+
0.00025638725886520225353198932528666427411683880083463700150051421280096109363730
|
|
4030
|
+
|
|
4031
|
+
Examples over number fields::
|
|
4032
|
+
|
|
4033
|
+
sage: # needs sage.rings.number_field
|
|
4034
|
+
sage: x = polygen(ZZ, 'x')
|
|
4035
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
4036
|
+
sage: embs = K.embeddings(CC)
|
|
4037
|
+
sage: E = EllipticCurve([0,1,0,a,a])
|
|
4038
|
+
sage: Ls = [E.period_lattice(e) for e in embs]
|
|
4039
|
+
sage: [L.real_flag for L in Ls]
|
|
4040
|
+
[0, 0, -1]
|
|
4041
|
+
sage: P = E(-1,0) # order 2
|
|
4042
|
+
sage: [L.elliptic_logarithm(P) for L in Ls]
|
|
4043
|
+
[-1.73964256006716 - 1.07861534489191*I,
|
|
4044
|
+
-0.363756518406398 - 1.50699412135253*I, 1.90726488608927]
|
|
4045
|
+
|
|
4046
|
+
sage: # needs sage.rings.number_field
|
|
4047
|
+
sage: E = EllipticCurve([-a^2 - a - 1, a^2 + a])
|
|
4048
|
+
sage: Ls = [E.period_lattice(e) for e in embs]
|
|
4049
|
+
sage: pts = [E(2*a^2 - a - 1 , -2*a^2 - 2*a + 6 ),
|
|
4050
|
+
....: E(-2/3*a^2 - 1/3 , -4/3*a - 2/3 ),
|
|
4051
|
+
....: E(5/4*a^2 - 1/2*a , -a^2 - 1/4*a + 9/4 ),
|
|
4052
|
+
....: E(2*a^2 + 3*a + 4 , -7*a^2 - 10*a - 12 )]
|
|
4053
|
+
sage: [[L.elliptic_logarithm(P) for P in pts] for L in Ls]
|
|
4054
|
+
[[0.250819591818930 - 0.411963479992219*I, -0.290994550611374 - 1.37239400324105*I,
|
|
4055
|
+
-0.693473752205595 - 2.45028458830342*I, -0.151659609775291 - 1.48985406505459*I],
|
|
4056
|
+
[1.33444787667954 - 1.50889756650544*I, 0.792633734249234 - 0.548467043256610*I,
|
|
4057
|
+
0.390154532655013 + 0.529423541805758*I, 0.931968675085317 - 0.431006981443071*I],
|
|
4058
|
+
[1.14758249500109 + 0.853389664016075*I, 2.59823462472518 + 0.853389664016075*I,
|
|
4059
|
+
1.75372176444709, 0.303069634723001]]
|
|
4060
|
+
|
|
4061
|
+
::
|
|
4062
|
+
|
|
4063
|
+
sage: # needs sage.rings.number_field
|
|
4064
|
+
sage: K.<i> = QuadraticField(-1)
|
|
4065
|
+
sage: E = EllipticCurve([0,0,0,9*i-10,21-i])
|
|
4066
|
+
sage: emb = K.embeddings(CC)[1]
|
|
4067
|
+
sage: L = E.period_lattice(emb)
|
|
4068
|
+
sage: P = E(2-i, 4+2*i)
|
|
4069
|
+
sage: L.elliptic_logarithm(P, prec=100)
|
|
4070
|
+
0.70448375537782208460499649302 - 0.79246725643650979858266018068*I
|
|
4071
|
+
"""
|
|
4072
|
+
from sage.rings.number_field.number_field import refine_embedding
|
|
4073
|
+
from sage.rings.real_mpfr import RealField
|
|
4074
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
4075
|
+
from sage.rings.rational_field import QQ
|
|
4076
|
+
|
|
4077
|
+
# Check the trivial case:
|
|
4078
|
+
|
|
4079
|
+
C = ComplexField(precision)
|
|
4080
|
+
if self.is_zero():
|
|
4081
|
+
return C.zero()
|
|
4082
|
+
|
|
4083
|
+
# find a suitable embedding if none was supplied:
|
|
4084
|
+
|
|
4085
|
+
E = self.curve()
|
|
4086
|
+
K = E.base_field()
|
|
4087
|
+
rational = (K is QQ)
|
|
4088
|
+
emb = embedding
|
|
4089
|
+
|
|
4090
|
+
if emb is None:
|
|
4091
|
+
emb = K.embeddings(RealField(precision))
|
|
4092
|
+
if emb:
|
|
4093
|
+
emb = emb[0]
|
|
4094
|
+
else:
|
|
4095
|
+
emb = K.embeddings(ComplexField(precision))[0]
|
|
4096
|
+
else:
|
|
4097
|
+
# Get the precision of the supplied embedding
|
|
4098
|
+
prec = emb.codomain().precision()
|
|
4099
|
+
# if the precision parameter is greater, refine the embedding:
|
|
4100
|
+
if precision > prec:
|
|
4101
|
+
emb = refine_embedding(emb, precision)
|
|
4102
|
+
|
|
4103
|
+
L = E.period_lattice(emb)
|
|
4104
|
+
|
|
4105
|
+
if algorithm == 'sage' or not isinstance(emb.codomain, sage.rings.abc.RealField):
|
|
4106
|
+
return L.elliptic_logarithm(self, precision)
|
|
4107
|
+
|
|
4108
|
+
if algorithm != 'pari':
|
|
4109
|
+
raise ValueError("algorithm must be either 'pari' or 'sage'")
|
|
4110
|
+
|
|
4111
|
+
# From now on emb() is a real embedding of K into
|
|
4112
|
+
# RealField(precision). We interface with the PARI library.
|
|
4113
|
+
|
|
4114
|
+
x, y = self.xy()
|
|
4115
|
+
if rational: # work with exact coordinates
|
|
4116
|
+
E_work = E
|
|
4117
|
+
pt_pari = pari([x, y])
|
|
4118
|
+
else: # use the embedding to get real coordinates
|
|
4119
|
+
ai = [emb(a) for a in E.a_invariants()]
|
|
4120
|
+
E_work = EllipticCurve(ai) # defined over RR
|
|
4121
|
+
pt_pari = pari([emb(x), emb(y)])
|
|
4122
|
+
working_prec = precision
|
|
4123
|
+
E_pari = E_work.pari_curve()
|
|
4124
|
+
log_pari = E_pari.ellpointtoz(pt_pari, precision=working_prec)
|
|
4125
|
+
|
|
4126
|
+
while log_pari.bitprecision() < precision:
|
|
4127
|
+
# result is not precise enough, re-compute with double
|
|
4128
|
+
# precision. if the base field is not QQ, this
|
|
4129
|
+
# requires modifying the precision of the embedding,
|
|
4130
|
+
# the curve, and the point
|
|
4131
|
+
working_prec = 2*working_prec
|
|
4132
|
+
if not rational:
|
|
4133
|
+
emb = refine_embedding(emb, working_prec)
|
|
4134
|
+
ai = [emb(a) for a in E.a_invariants()]
|
|
4135
|
+
E_work = EllipticCurve(ai) # defined over RR
|
|
4136
|
+
pt_pari = pari([emb(x), emb(y)])
|
|
4137
|
+
E_pari = E_work.pari_curve()
|
|
4138
|
+
log_pari = E_pari.ellpointtoz(pt_pari, precision=working_prec)
|
|
4139
|
+
|
|
4140
|
+
# normalization step
|
|
4141
|
+
r, i = C(log_pari)
|
|
4142
|
+
wR, wI = L.basis(prec=precision)
|
|
4143
|
+
k = (r/wR).floor()
|
|
4144
|
+
if k:
|
|
4145
|
+
r -= k*wR
|
|
4146
|
+
if self.is_on_identity_component(emb):
|
|
4147
|
+
return C(r)
|
|
4148
|
+
# Now there are two components and P is on the non-identity one
|
|
4149
|
+
return C(r)+C(wI/2)
|
|
4150
|
+
|
|
4151
|
+
def padic_elliptic_logarithm(self, p, absprec=20):
|
|
4152
|
+
r"""
|
|
4153
|
+
Compute the `p`-adic elliptic logarithm of this point.
|
|
4154
|
+
|
|
4155
|
+
INPUT:
|
|
4156
|
+
|
|
4157
|
+
- ``p`` -- integer; a prime
|
|
4158
|
+
|
|
4159
|
+
- ``absprec`` -- integer (default: 20); the initial `p`-adic absolute
|
|
4160
|
+
precision of the computation
|
|
4161
|
+
|
|
4162
|
+
OUTPUT:
|
|
4163
|
+
|
|
4164
|
+
The `p`-adic elliptic logarithm of self, with precision ``absprec``.
|
|
4165
|
+
|
|
4166
|
+
AUTHORS:
|
|
4167
|
+
|
|
4168
|
+
- Tobias Nagel
|
|
4169
|
+
- Michael Mardaus
|
|
4170
|
+
- John Cremona
|
|
4171
|
+
|
|
4172
|
+
ALGORITHM:
|
|
4173
|
+
|
|
4174
|
+
For points in the formal group (i.e. not integral at `p`) we
|
|
4175
|
+
take the ``log()`` function from the formal groups module and
|
|
4176
|
+
evaluate it at `-x/y`. Otherwise we first multiply the point
|
|
4177
|
+
to get into the formal group, and divide the result
|
|
4178
|
+
afterwards.
|
|
4179
|
+
|
|
4180
|
+
.. TODO::
|
|
4181
|
+
|
|
4182
|
+
See comments at :issue:`4805`. Currently the absolute
|
|
4183
|
+
precision of the result may be less than the given value
|
|
4184
|
+
of absprec, and error-handling is imperfect.
|
|
4185
|
+
|
|
4186
|
+
EXAMPLES::
|
|
4187
|
+
|
|
4188
|
+
sage: E = EllipticCurve([0,1,1,-2,0])
|
|
4189
|
+
sage: E(0).padic_elliptic_logarithm(3) # needs sage.rings.padics
|
|
4190
|
+
0
|
|
4191
|
+
sage: P = E(0, 0) # needs sage.rings.padics
|
|
4192
|
+
sage: P.padic_elliptic_logarithm(3) # needs sage.rings.padics
|
|
4193
|
+
2 + 2*3 + 3^3 + 2*3^7 + 3^8 + 3^9 + 3^11 + 3^15 + 2*3^17 + 3^18 + O(3^19)
|
|
4194
|
+
sage: P.padic_elliptic_logarithm(3).lift() # needs sage.rings.padics
|
|
4195
|
+
660257522
|
|
4196
|
+
sage: P = E(-11/9, 28/27) # needs sage.rings.padics
|
|
4197
|
+
sage: [(2*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(20)] # long time, needs sage.rings.padics
|
|
4198
|
+
[2 + O(2^19), 2 + O(3^20), 2 + O(5^19), 2 + O(7^19), 2 + O(11^19), 2 + O(13^19), 2 + O(17^19), 2 + O(19^19)]
|
|
4199
|
+
sage: [(3*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time, needs sage.rings.padics
|
|
4200
|
+
[1 + 2 + O(2^19), 3 + 3^20 + O(3^21), 3 + O(5^19), 3 + O(7^19), 3 + O(11^19)]
|
|
4201
|
+
sage: [(5*P).padic_elliptic_logarithm(p)/P.padic_elliptic_logarithm(p) for p in prime_range(12)] # long time, needs sage.rings.padics
|
|
4202
|
+
[1 + 2^2 + O(2^19), 2 + 3 + O(3^20), 5 + O(5^19), 5 + O(7^19), 5 + O(11^19)]
|
|
4203
|
+
|
|
4204
|
+
An example which arose during reviewing :issue:`4741`::
|
|
4205
|
+
|
|
4206
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
4207
|
+
sage: E = EllipticCurve('794a1')
|
|
4208
|
+
sage: P = E(-1,2)
|
|
4209
|
+
sage: P.padic_elliptic_logarithm(2) # default precision=20 # needs sage.rings.padics
|
|
4210
|
+
2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + O(2^16)
|
|
4211
|
+
sage: P.padic_elliptic_logarithm(2, absprec=30) # needs sage.rings.padics
|
|
4212
|
+
2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + 2^22 + 2^23 + 2^24 + O(2^26)
|
|
4213
|
+
sage: P.padic_elliptic_logarithm(2, absprec=40) # needs sage.rings.padics
|
|
4214
|
+
2^4 + 2^5 + 2^6 + 2^8 + 2^9 + 2^13 + 2^14 + 2^15 + 2^22 + 2^23 + 2^24
|
|
4215
|
+
+ 2^28 + 2^29 + 2^31 + 2^34 + O(2^35)
|
|
4216
|
+
"""
|
|
4217
|
+
if not p.is_prime():
|
|
4218
|
+
raise ValueError('p must be prime')
|
|
4219
|
+
debug = False # True
|
|
4220
|
+
if debug:
|
|
4221
|
+
print("P=", self, "; p=", p, " with precision ", absprec)
|
|
4222
|
+
E = self.curve()
|
|
4223
|
+
Q_p = Qp(p, absprec)
|
|
4224
|
+
if self.has_finite_order():
|
|
4225
|
+
return Q_p(0)
|
|
4226
|
+
while True:
|
|
4227
|
+
try:
|
|
4228
|
+
Ep = E.change_ring(Q_p)
|
|
4229
|
+
P = Ep(self)
|
|
4230
|
+
x, y = P.xy()
|
|
4231
|
+
break
|
|
4232
|
+
except (PrecisionError, ArithmeticError, ZeroDivisionError):
|
|
4233
|
+
absprec *= 2
|
|
4234
|
+
Q_p = Qp(p, absprec)
|
|
4235
|
+
if debug:
|
|
4236
|
+
print("x,y=", (x, y))
|
|
4237
|
+
f = 1 # f will be such that f*P is in the formal group E^1(Q_p)
|
|
4238
|
+
if x.valuation() >= 0: # P is not in E^1
|
|
4239
|
+
if not self.has_good_reduction(p): # P is not in E^0
|
|
4240
|
+
n = E.tamagawa_exponent(p) # n*P has good reduction at p
|
|
4241
|
+
if debug:
|
|
4242
|
+
print("Tamagawa exponent = =", n)
|
|
4243
|
+
f = n
|
|
4244
|
+
P = n*P # lies in E^0
|
|
4245
|
+
if debug:
|
|
4246
|
+
print("P=", P)
|
|
4247
|
+
try:
|
|
4248
|
+
x, y = P.xy()
|
|
4249
|
+
except ZeroDivisionError:
|
|
4250
|
+
raise ValueError("Insufficient precision in "
|
|
4251
|
+
"p-adic_elliptic_logarithm()")
|
|
4252
|
+
if debug:
|
|
4253
|
+
print("x,y=", (x, y))
|
|
4254
|
+
if x.valuation() >= 0: # P is still not in E^1
|
|
4255
|
+
t = E.local_data(p).bad_reduction_type()
|
|
4256
|
+
if t is None:
|
|
4257
|
+
m = E.reduction(p).abelian_group().exponent()
|
|
4258
|
+
else:
|
|
4259
|
+
m = p - t
|
|
4260
|
+
if debug:
|
|
4261
|
+
print("mod p exponent = =", m)
|
|
4262
|
+
# now m*(n*P) reduces to the identity mod p, so is
|
|
4263
|
+
# in E^1(Q_p)
|
|
4264
|
+
f *= m
|
|
4265
|
+
P = m*P # lies in E^1
|
|
4266
|
+
try:
|
|
4267
|
+
x, y = P.xy()
|
|
4268
|
+
except ZeroDivisionError:
|
|
4269
|
+
raise ValueError("Insufficient precision in "
|
|
4270
|
+
"p-adic_elliptic_logarithm()")
|
|
4271
|
+
if debug:
|
|
4272
|
+
print("f=", f)
|
|
4273
|
+
print("x,y=", (x, y))
|
|
4274
|
+
vx = x.valuation()
|
|
4275
|
+
vy = y.valuation()
|
|
4276
|
+
v = vx-vy
|
|
4277
|
+
if not (v > 0 and vx == -2*v and vy == -3*v):
|
|
4278
|
+
raise ValueError("Insufficient precision in "
|
|
4279
|
+
"p-adic_elliptic_logarithm()")
|
|
4280
|
+
try:
|
|
4281
|
+
t = -x/y
|
|
4282
|
+
except (ZeroDivisionError, PrecisionError):
|
|
4283
|
+
raise ValueError("Insufficient precision in "
|
|
4284
|
+
"p-adic_elliptic_logarithm()")
|
|
4285
|
+
if debug:
|
|
4286
|
+
print("t=", t, ", with valuation ", v)
|
|
4287
|
+
phi = Ep.formal().log(prec=1+absprec//v)
|
|
4288
|
+
return phi(t)/f
|
|
4289
|
+
|
|
4290
|
+
|
|
4291
|
+
class EllipticCurvePoint_finite_field(EllipticCurvePoint_field):
|
|
4292
|
+
r"""
|
|
4293
|
+
Class for elliptic curve points over finite fields.
|
|
4294
|
+
"""
|
|
4295
|
+
def _magma_init_(self, magma):
|
|
4296
|
+
"""
|
|
4297
|
+
Return a string representation of ``self`` that ``MAGMA`` can
|
|
4298
|
+
use for input.
|
|
4299
|
+
|
|
4300
|
+
EXAMPLES::
|
|
4301
|
+
|
|
4302
|
+
sage: E = EllipticCurve(GF(17), [1,-1])
|
|
4303
|
+
sage: P = E([13, 4])
|
|
4304
|
+
sage: P._magma_init_(magma) # optional - magma
|
|
4305
|
+
'EllipticCurve([_sage_ref...|GF(17)!0,GF(17)!0,GF(17)!0,GF(17)!1,GF(17)!16])![13,4]'
|
|
4306
|
+
"""
|
|
4307
|
+
E = self.curve()._magma_init_(magma)
|
|
4308
|
+
x, y = self.xy()
|
|
4309
|
+
return "%s![%s,%s]" % (E, x, y)
|
|
4310
|
+
|
|
4311
|
+
def _acted_upon_(self, other, side):
|
|
4312
|
+
r"""
|
|
4313
|
+
We implement ``_acted_upon_`` to make use of the specialized faster
|
|
4314
|
+
scalar multiplication from PARI, and to keep track of cached point
|
|
4315
|
+
orders when scalar multiplications are applied.
|
|
4316
|
+
|
|
4317
|
+
EXAMPLES::
|
|
4318
|
+
|
|
4319
|
+
sage: # needs sage.rings.finite_rings
|
|
4320
|
+
sage: P = EllipticCurve(GF(65537), [2,2]).lift_x(6)
|
|
4321
|
+
sage: P.order().factor()
|
|
4322
|
+
2^2 * 3 * 37^2
|
|
4323
|
+
sage: getattr(74*P, '_order', None)
|
|
4324
|
+
222
|
|
4325
|
+
sage: getattr(P*4070, '_order', None)
|
|
4326
|
+
222
|
|
4327
|
+
sage: getattr(506*P*37, '_order', None)
|
|
4328
|
+
222
|
|
4329
|
+
"""
|
|
4330
|
+
k = ZZ(other)
|
|
4331
|
+
E = self.curve()
|
|
4332
|
+
|
|
4333
|
+
try:
|
|
4334
|
+
pariQ = pari.ellmul(E, self, k)
|
|
4335
|
+
except PariError as err:
|
|
4336
|
+
if str(err.errdata().component(1)) == "Fp_inv":
|
|
4337
|
+
val = err.errdata().component(2)
|
|
4338
|
+
a = val.lift()
|
|
4339
|
+
N = val.mod()
|
|
4340
|
+
N1 = N.gcd(a)
|
|
4341
|
+
N2 = N//N1
|
|
4342
|
+
raise ZeroDivisionError(
|
|
4343
|
+
f"Inverse of {a} does not exist"
|
|
4344
|
+
f" (characteristic = {N} = {N1}*{N2})")
|
|
4345
|
+
pariQ = None
|
|
4346
|
+
|
|
4347
|
+
if pariQ is not None:
|
|
4348
|
+
if pariQ == [0]:
|
|
4349
|
+
vQ = 0
|
|
4350
|
+
else:
|
|
4351
|
+
assert len(pariQ) == 2
|
|
4352
|
+
vQ = Sequence(tuple(pariQ) + (1,), E.base_ring())
|
|
4353
|
+
Q = EllipticCurvePoint_finite_field(E, vQ, check=False)
|
|
4354
|
+
|
|
4355
|
+
else:
|
|
4356
|
+
Q = IntegerMulAction(ZZ, self.parent())._act_(k, self)
|
|
4357
|
+
|
|
4358
|
+
n = getattr(self, '_order', None)
|
|
4359
|
+
if n is not None:
|
|
4360
|
+
Q._order = n // n.gcd(k) # Lagrange's theorem
|
|
4361
|
+
|
|
4362
|
+
return Q
|
|
4363
|
+
|
|
4364
|
+
def log(self, base):
|
|
4365
|
+
r"""
|
|
4366
|
+
Return the discrete logarithm of this point to the given ``base``.
|
|
4367
|
+
In other words, return an integer `x` such that `xP = Q` where
|
|
4368
|
+
`P` is ``base`` and `Q` is this point.
|
|
4369
|
+
|
|
4370
|
+
If ``base`` is a list or tuple of two points, then this function
|
|
4371
|
+
solves a two-dimensional discrete logarithm: Given `(P_1,P_2)` in
|
|
4372
|
+
``base``, it returns a tuple of integers `(x,y)` such that
|
|
4373
|
+
`[x]P_1 + [y]P_2 = Q`, where `Q` is this point.
|
|
4374
|
+
|
|
4375
|
+
A :exc:`ValueError` is raised if there is no solution.
|
|
4376
|
+
|
|
4377
|
+
ALGORITHM:
|
|
4378
|
+
|
|
4379
|
+
To compute the actual logarithm, :pari:`elllog` is called.
|
|
4380
|
+
|
|
4381
|
+
However, ``elllog()`` does not guarantee termination if `Q`
|
|
4382
|
+
is not a multiple of `P`, so we first need to check subgroup
|
|
4383
|
+
membership. This is done as follows:
|
|
4384
|
+
|
|
4385
|
+
- Let `n` denote the order of `P`. First check that `nQ` equals
|
|
4386
|
+
the point at infinity (and hence the order of `Q` divides `n`).
|
|
4387
|
+
|
|
4388
|
+
- If the curve order `\#E` has been cached, check whether
|
|
4389
|
+
`\gcd(n^2, \#E) = n`. If this holds, the curve has cyclic
|
|
4390
|
+
`n`-torsion, hence all points whose order divides `n` must be
|
|
4391
|
+
multiples of `P` and we are done.
|
|
4392
|
+
|
|
4393
|
+
- Otherwise (if this test is inconclusive), check that the Weil
|
|
4394
|
+
pairing of `P` and `Q` is trivial.
|
|
4395
|
+
|
|
4396
|
+
For anomalous curves with `\#E = p`, the
|
|
4397
|
+
:meth:`padic_elliptic_logarithm` function is called.
|
|
4398
|
+
|
|
4399
|
+
For two-dimensional logarithms, we first compute the Weil pairings
|
|
4400
|
+
of `Q` with `P_1` and `P_2` and their logarithms relative to the
|
|
4401
|
+
pairing of `P_1` and `P_2`; this allows reading off `x` and `y`
|
|
4402
|
+
modulo the part of the order where `P_1` and `P_2` are independent.
|
|
4403
|
+
Modulo the remaining part of the order the logarithm ends up being
|
|
4404
|
+
effectively one-dimensional, so we can reduce the problem to the
|
|
4405
|
+
basic one-dimensional case and finally recombine the results.
|
|
4406
|
+
|
|
4407
|
+
INPUT:
|
|
4408
|
+
|
|
4409
|
+
- ``base`` -- another point or sequence of two points on the same
|
|
4410
|
+
curve as ``self``
|
|
4411
|
+
|
|
4412
|
+
OUTPUT:
|
|
4413
|
+
|
|
4414
|
+
(integer) -- The discrete logarithm of `Q` with respect to `P`,
|
|
4415
|
+
which is an integer `x` with `0\le x<\mathrm{ord}(P)` such that
|
|
4416
|
+
`xP=Q`, if one exists. In the case of two points `P_1,P_2`, two
|
|
4417
|
+
integers `x,y` with `0\le x<\mathrm{ord}(P_1)` and
|
|
4418
|
+
`0\le y<\mathrm{ord}(P_2)` such that `[x]P_1 + [y]P_2 = Q`.
|
|
4419
|
+
|
|
4420
|
+
AUTHORS:
|
|
4421
|
+
|
|
4422
|
+
- John Cremona. Adapted to use generic functions 2008-04-05.
|
|
4423
|
+
- Lorenz Panny (2022): switch to PARI.
|
|
4424
|
+
- Lorenz Panny (2024): the two-dimensional case.
|
|
4425
|
+
|
|
4426
|
+
EXAMPLES::
|
|
4427
|
+
|
|
4428
|
+
sage: # needs sage.rings.finite_rings
|
|
4429
|
+
sage: F = GF((3,6),'a')
|
|
4430
|
+
sage: a = F.gen()
|
|
4431
|
+
sage: E = EllipticCurve([0,1,1,a,a])
|
|
4432
|
+
sage: E.cardinality()
|
|
4433
|
+
762
|
|
4434
|
+
sage: P = E.gens()[0]
|
|
4435
|
+
sage: Q = 400*P
|
|
4436
|
+
sage: Q.log(P)
|
|
4437
|
+
400
|
|
4438
|
+
|
|
4439
|
+
::
|
|
4440
|
+
|
|
4441
|
+
sage: # needs sage.rings.finite_rings
|
|
4442
|
+
sage: F = GF((5, 60), 'a')
|
|
4443
|
+
sage: E = EllipticCurve(F, [1, 1])
|
|
4444
|
+
sage: E.abelian_group()
|
|
4445
|
+
Additive abelian group isomorphic to Z/194301464603136995341424045476456938000 + Z/4464 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^60
|
|
4446
|
+
sage: P, Q = E.gens() # cached generators from .abelian_group()
|
|
4447
|
+
sage: T = 1234567890987654321*P + 1337*Q
|
|
4448
|
+
sage: T.log([P, Q])
|
|
4449
|
+
(1234567890987654321, 1337)
|
|
4450
|
+
|
|
4451
|
+
TESTS:
|
|
4452
|
+
|
|
4453
|
+
Some random testing::
|
|
4454
|
+
|
|
4455
|
+
sage: # needs sage.rings.finite_rings
|
|
4456
|
+
sage: sz = randint(8,32)
|
|
4457
|
+
sage: e = randint(1,3)
|
|
4458
|
+
sage: p = random_prime(ceil(2**(sz/e)))
|
|
4459
|
+
sage: E = EllipticCurve(j=GF((p,e),'a').random_element())
|
|
4460
|
+
sage: P = E.random_point()
|
|
4461
|
+
sage: Q = randrange(2**999) * P
|
|
4462
|
+
sage: x = Q.log(P)
|
|
4463
|
+
sage: x*P == Q
|
|
4464
|
+
True
|
|
4465
|
+
|
|
4466
|
+
::
|
|
4467
|
+
|
|
4468
|
+
sage: # needs sage.rings.finite_rings
|
|
4469
|
+
sage: sz = randint(16,24)
|
|
4470
|
+
sage: e = randint(1,6)
|
|
4471
|
+
sage: p = random_prime(ceil(2**(sz/e)))
|
|
4472
|
+
sage: E = EllipticCurve(j=GF((p,e),'a').random_element())
|
|
4473
|
+
sage: E = choice(E.twists())
|
|
4474
|
+
sage: P = E.random_point()
|
|
4475
|
+
sage: Q = E.random_point()
|
|
4476
|
+
sage: T = randrange(2^99) * P + randrange(2^99) * Q
|
|
4477
|
+
sage: x, y = T.log([P, Q])
|
|
4478
|
+
sage: 0 <= x < P.order()
|
|
4479
|
+
True
|
|
4480
|
+
sage: 0 <= y < Q.order()
|
|
4481
|
+
True
|
|
4482
|
+
sage: T == x*P + y*Q
|
|
4483
|
+
True
|
|
4484
|
+
"""
|
|
4485
|
+
# handle the two-dimensional case first
|
|
4486
|
+
if isinstance(base, (list, tuple)):
|
|
4487
|
+
if not base:
|
|
4488
|
+
return self.log(self.curve().zero())
|
|
4489
|
+
elif len(base) == 1:
|
|
4490
|
+
return self.log(base[0])
|
|
4491
|
+
elif len(base) > 2:
|
|
4492
|
+
raise ValueError('sequence must have length <= 2')
|
|
4493
|
+
|
|
4494
|
+
P1, P2 = base
|
|
4495
|
+
if P1 not in self.parent() or P2 not in self.parent():
|
|
4496
|
+
raise ValueError('points do not lie on the same curve')
|
|
4497
|
+
|
|
4498
|
+
n1, n2 = P1.order(), P2.order()
|
|
4499
|
+
n = n1.lcm(n2)
|
|
4500
|
+
if not hasattr(self, '_order'):
|
|
4501
|
+
if n * self:
|
|
4502
|
+
raise ValueError('ECDLog problem has no solution (order does not divide order of base)')
|
|
4503
|
+
self.set_order(multiple=n, check=False)
|
|
4504
|
+
if not self.order().divides(n):
|
|
4505
|
+
raise ValueError('ECDLog problem has no solution (order does not divide order of base)')
|
|
4506
|
+
|
|
4507
|
+
# find the solution modulo the part where P1,P2 are independent
|
|
4508
|
+
z = P1.weil_pairing(P2, n)
|
|
4509
|
+
o = generic.order_from_multiple(z, n1.gcd(n2), operation='*')
|
|
4510
|
+
if o.is_one():
|
|
4511
|
+
# slight optimization, but also workaround for PARI bug #2562
|
|
4512
|
+
x0, y0 = ZZ.zero(), ZZ.zero()
|
|
4513
|
+
else:
|
|
4514
|
+
v = self.weil_pairing(P2, n)
|
|
4515
|
+
w = P1.weil_pairing(self, n)
|
|
4516
|
+
x0, y0 = v.log(z, o), w.log(z, o)
|
|
4517
|
+
|
|
4518
|
+
T = self - x0*P1 - y0*P2
|
|
4519
|
+
if not T:
|
|
4520
|
+
return x0, y0
|
|
4521
|
+
|
|
4522
|
+
T1 = n//n1 * T
|
|
4523
|
+
T2 = n//n2 * T
|
|
4524
|
+
T1.set_order(multiple=n1, check=False)
|
|
4525
|
+
T2.set_order(multiple=n2, check=False)
|
|
4526
|
+
x1 = T1.log(o*P1)
|
|
4527
|
+
y1 = T2.log(o*P2)
|
|
4528
|
+
|
|
4529
|
+
# assert n//n1 * self == (x1*o + n//n1*x0) * P1 + n//n1*y0 * P2
|
|
4530
|
+
# assert n//n2 * self == n//n2*x0 * P1 + (y1*o + n//n2*y0) * P2
|
|
4531
|
+
|
|
4532
|
+
_,u,v = (n//n1).xgcd(n//n2)
|
|
4533
|
+
assert _.is_one()
|
|
4534
|
+
x = (u * (x1*o + n//n1*x0) + v * (n//n2*x0)) % n1
|
|
4535
|
+
y = (u * (n//n1*y0) + v * (y1*o + n//n2*y0)) % n2
|
|
4536
|
+
|
|
4537
|
+
# assert x*P1 + y*P2 == self
|
|
4538
|
+
return x, y
|
|
4539
|
+
|
|
4540
|
+
if base not in self.parent():
|
|
4541
|
+
raise ValueError('not a point on the same curve')
|
|
4542
|
+
n = base.order()
|
|
4543
|
+
if (hasattr(self, '_order') and not self._order.divides(n)) or n*self:
|
|
4544
|
+
raise ValueError('ECDLog problem has no solution (order does not divide order of base)')
|
|
4545
|
+
E = self.curve()
|
|
4546
|
+
F = E.base_ring()
|
|
4547
|
+
p = F.cardinality()
|
|
4548
|
+
|
|
4549
|
+
if F.is_prime_field() and n == p:
|
|
4550
|
+
# Anomalous case
|
|
4551
|
+
return base.padic_elliptic_logarithm(self, p)
|
|
4552
|
+
elif hasattr(E, '_order') and E._order.gcd(n**2) == n:
|
|
4553
|
+
pass # cyclic rational n-torsion -> okay
|
|
4554
|
+
elif base.weil_pairing(self, n) != 1:
|
|
4555
|
+
raise ValueError('ECDLog problem has no solution (non-trivial Weil pairing)')
|
|
4556
|
+
|
|
4557
|
+
return ZZ(pari.elllog(self.curve(), self, base, n))
|
|
4558
|
+
|
|
4559
|
+
def discrete_log(self, Q):
|
|
4560
|
+
r"""
|
|
4561
|
+
Legacy version of :meth:`log` with its arguments swapped.
|
|
4562
|
+
|
|
4563
|
+
Note that this method uses the opposite argument ordering
|
|
4564
|
+
of all other logarithm methods in Sage; see :issue:`37150`.
|
|
4565
|
+
|
|
4566
|
+
EXAMPLES::
|
|
4567
|
+
|
|
4568
|
+
sage: E = EllipticCurve(j=GF(101)(5))
|
|
4569
|
+
sage: P, = E.gens()
|
|
4570
|
+
sage: (2*P).log(P)
|
|
4571
|
+
2
|
|
4572
|
+
sage: (2*P).discrete_log(P)
|
|
4573
|
+
doctest:warning ...
|
|
4574
|
+
DeprecationWarning: The syntax P.discrete_log(Q) ... Please update your code. ...
|
|
4575
|
+
45
|
|
4576
|
+
sage: P.discrete_log(2*P)
|
|
4577
|
+
2
|
|
4578
|
+
"""
|
|
4579
|
+
from sage.misc.superseded import deprecation
|
|
4580
|
+
deprecation(37150, 'The syntax P.discrete_log(Q) is being replaced by '
|
|
4581
|
+
'Q.log(P) to make the argument ordering of logarithm'
|
|
4582
|
+
' methods in Sage uniform. Please update your code.')
|
|
4583
|
+
return Q.log(self)
|
|
4584
|
+
|
|
4585
|
+
def padic_elliptic_logarithm(self, Q, p):
|
|
4586
|
+
r"""
|
|
4587
|
+
Return the discrete logarithm of `Q` to base `P` = ``self``,
|
|
4588
|
+
that is, an integer `x` such that `xP = Q` only for anomalous curves.
|
|
4589
|
+
|
|
4590
|
+
ALGORITHM:
|
|
4591
|
+
|
|
4592
|
+
Discrete logarithm computed as in [Sma1999]_ with a loop to avoid
|
|
4593
|
+
the canonical lift.
|
|
4594
|
+
|
|
4595
|
+
INPUT:
|
|
4596
|
+
|
|
4597
|
+
- ``Q`` -- point; another point on the same curve as ``self``
|
|
4598
|
+
- ``p`` -- integer; a prime equal to the order of the curve
|
|
4599
|
+
|
|
4600
|
+
OUTPUT:
|
|
4601
|
+
|
|
4602
|
+
(integer) -- The discrete logarithm of `Q` with respect to `P`,
|
|
4603
|
+
which is an integer `x` with `0\le x<\mathrm{ord}(P)` such that
|
|
4604
|
+
`xP=Q`.
|
|
4605
|
+
|
|
4606
|
+
AUTHORS:
|
|
4607
|
+
|
|
4608
|
+
- Sylvain Pelissier (2022) based on Samuel Neves code_.
|
|
4609
|
+
|
|
4610
|
+
.. _code: https://crypto.stackexchange.com/questions/70454/why-smarts-attack-doesnt-work-on-this-ecdlp/70508#70508
|
|
4611
|
+
|
|
4612
|
+
EXAMPLES::
|
|
4613
|
+
|
|
4614
|
+
sage: # needs sage.rings.finite_rings
|
|
4615
|
+
sage: p = 235322474717419
|
|
4616
|
+
sage: b = 8856682
|
|
4617
|
+
sage: E = EllipticCurve(GF(p), [0, b])
|
|
4618
|
+
sage: P = E(200673830421813, 57025307876612)
|
|
4619
|
+
sage: Q = E(40345734829479, 211738132651297)
|
|
4620
|
+
sage: x = P.padic_elliptic_logarithm(Q, p) # needs sage.rings.padics
|
|
4621
|
+
sage: x * P == Q # needs sage.rings.padics
|
|
4622
|
+
True
|
|
4623
|
+
|
|
4624
|
+
TESTS:
|
|
4625
|
+
|
|
4626
|
+
Some testing::
|
|
4627
|
+
|
|
4628
|
+
sage: # needs sage.rings.finite_rings
|
|
4629
|
+
sage: a = 49850651047495986645822557378918223
|
|
4630
|
+
sage: b = 21049438014429831351540675253466229
|
|
4631
|
+
sage: p = 54283205379427155782089046839411711
|
|
4632
|
+
sage: E = EllipticCurve(GF(p), [a, b])
|
|
4633
|
+
sage: P = E.random_point()
|
|
4634
|
+
sage: Q = randrange(0, p-1) * P
|
|
4635
|
+
sage: x = P.padic_elliptic_logarithm(Q, p) # needs sage.rings.padics
|
|
4636
|
+
sage: x*P == Q # needs sage.rings.padics
|
|
4637
|
+
True
|
|
4638
|
+
"""
|
|
4639
|
+
E = self.curve()
|
|
4640
|
+
F = E.base()
|
|
4641
|
+
|
|
4642
|
+
if Q.is_zero():
|
|
4643
|
+
k = 0
|
|
4644
|
+
else:
|
|
4645
|
+
for k in range(p):
|
|
4646
|
+
Eqp = EllipticCurve(Qp(p, 2), [ZZ(t) + k * p for t in E.a_invariants()])
|
|
4647
|
+
|
|
4648
|
+
P_Qps = Eqp.lift_x(ZZ(self.x()), all=True)
|
|
4649
|
+
for P_Qp in P_Qps:
|
|
4650
|
+
if F(P_Qp.y()) == self.y():
|
|
4651
|
+
break
|
|
4652
|
+
|
|
4653
|
+
Q_Qps = Eqp.lift_x(ZZ(Q.x()), all=True)
|
|
4654
|
+
for Q_Qp in Q_Qps:
|
|
4655
|
+
if F(Q_Qp.y()) == Q.y():
|
|
4656
|
+
break
|
|
4657
|
+
|
|
4658
|
+
pP = p * P_Qp
|
|
4659
|
+
pQ = p * Q_Qp
|
|
4660
|
+
if (pP.is_zero() or pQ.is_zero()):
|
|
4661
|
+
# Should happen with probability 1/p
|
|
4662
|
+
continue
|
|
4663
|
+
else:
|
|
4664
|
+
break
|
|
4665
|
+
|
|
4666
|
+
x_P,y_P = pP.xy()
|
|
4667
|
+
x_Q,y_Q = pQ.xy()
|
|
4668
|
+
|
|
4669
|
+
phi_P = -(x_P / y_P)
|
|
4670
|
+
phi_Q = -(x_Q / y_Q)
|
|
4671
|
+
k = phi_Q / phi_P
|
|
4672
|
+
|
|
4673
|
+
return ZZ(k % p)
|
|
4674
|
+
|
|
4675
|
+
def has_finite_order(self) -> bool:
|
|
4676
|
+
r"""
|
|
4677
|
+
Return ``True`` if this point has finite additive order as an element
|
|
4678
|
+
of the group of points on this curve.
|
|
4679
|
+
|
|
4680
|
+
Since the base field is finite, the answer will always be ``True``.
|
|
4681
|
+
|
|
4682
|
+
EXAMPLES::
|
|
4683
|
+
|
|
4684
|
+
sage: E = EllipticCurve(GF(7), [1,3])
|
|
4685
|
+
sage: P = E.points()[3]
|
|
4686
|
+
sage: P.has_finite_order()
|
|
4687
|
+
True
|
|
4688
|
+
"""
|
|
4689
|
+
return True
|
|
4690
|
+
|
|
4691
|
+
def order(self):
|
|
4692
|
+
r"""
|
|
4693
|
+
Return the order of this point on the elliptic curve.
|
|
4694
|
+
|
|
4695
|
+
ALGORITHM: Use PARI function :pari:`ellorder`.
|
|
4696
|
+
|
|
4697
|
+
.. NOTE::
|
|
4698
|
+
|
|
4699
|
+
:meth:`additive_order` is a synonym for :meth:`order`
|
|
4700
|
+
|
|
4701
|
+
EXAMPLES::
|
|
4702
|
+
|
|
4703
|
+
sage: # needs sage.rings.finite_rings
|
|
4704
|
+
sage: k.<a> = GF((5,5))
|
|
4705
|
+
sage: E = EllipticCurve(k,[2,4]); E
|
|
4706
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 4 over Finite Field in a of size 5^5
|
|
4707
|
+
sage: P = E(3*a^4 + 3*a, 2*a + 1)
|
|
4708
|
+
sage: P.order()
|
|
4709
|
+
3227
|
|
4710
|
+
sage: Q = E(0,2)
|
|
4711
|
+
sage: Q.order()
|
|
4712
|
+
7
|
|
4713
|
+
sage: Q.additive_order()
|
|
4714
|
+
7
|
|
4715
|
+
|
|
4716
|
+
::
|
|
4717
|
+
|
|
4718
|
+
sage: # needs sage.rings.finite_rings
|
|
4719
|
+
sage: p = next_prime(2^150)
|
|
4720
|
+
sage: E = EllipticCurve(GF(p), [1,1])
|
|
4721
|
+
sage: P = E(831623307675610677632782670796608848711856078,
|
|
4722
|
+
....: 42295786042873366706573292533588638217232964)
|
|
4723
|
+
sage: P.order()
|
|
4724
|
+
1427247692705959881058262545272474300628281448
|
|
4725
|
+
sage: P.order() == E.cardinality()
|
|
4726
|
+
True
|
|
4727
|
+
|
|
4728
|
+
The next example has `j(E)=0`::
|
|
4729
|
+
|
|
4730
|
+
sage: # needs sage.rings.finite_rings
|
|
4731
|
+
sage: p = 33554501
|
|
4732
|
+
sage: F.<u> = GF((p,2))
|
|
4733
|
+
sage: E = EllipticCurve(F, [0,1])
|
|
4734
|
+
sage: E.j_invariant()
|
|
4735
|
+
0
|
|
4736
|
+
sage: P = E.random_point()
|
|
4737
|
+
sage: P.order() # random
|
|
4738
|
+
16777251
|
|
4739
|
+
|
|
4740
|
+
Similarly when `j(E)=1728`::
|
|
4741
|
+
|
|
4742
|
+
sage: # needs sage.rings.finite_rings
|
|
4743
|
+
sage: p = 33554473
|
|
4744
|
+
sage: F.<u> = GF((p,2))
|
|
4745
|
+
sage: E = EllipticCurve(F, [1,0])
|
|
4746
|
+
sage: E.j_invariant()
|
|
4747
|
+
1728
|
|
4748
|
+
sage: P = E.random_point()
|
|
4749
|
+
sage: P.order() # random
|
|
4750
|
+
46912611635760
|
|
4751
|
+
|
|
4752
|
+
TESTS:
|
|
4753
|
+
|
|
4754
|
+
Check that the order actually gets cached (:issue:`32786`)::
|
|
4755
|
+
|
|
4756
|
+
sage: # needs sage.rings.finite_rings
|
|
4757
|
+
sage: E = EllipticCurve(GF(31337), [42,1])
|
|
4758
|
+
sage: P = E.lift_x(1)
|
|
4759
|
+
sage: hasattr(P, '_order')
|
|
4760
|
+
False
|
|
4761
|
+
sage: P.order()
|
|
4762
|
+
15649
|
|
4763
|
+
sage: P._order
|
|
4764
|
+
15649
|
|
4765
|
+
|
|
4766
|
+
The curve order should also get cached as a side effect
|
|
4767
|
+
of computing a point order::
|
|
4768
|
+
|
|
4769
|
+
sage: E._order # needs sage.rings.finite_rings
|
|
4770
|
+
31298
|
|
4771
|
+
"""
|
|
4772
|
+
try:
|
|
4773
|
+
return self._order
|
|
4774
|
+
except AttributeError:
|
|
4775
|
+
pass
|
|
4776
|
+
|
|
4777
|
+
E = self.curve()
|
|
4778
|
+
|
|
4779
|
+
if getattr(E, '_order', None) is None:
|
|
4780
|
+
# The curve order will be computed and cached by PARI during
|
|
4781
|
+
# ellorder() anyway. We might as well cache it here too.
|
|
4782
|
+
E._order = Integer(E.pari_curve().ellcard())
|
|
4783
|
+
|
|
4784
|
+
self._order = Integer(E.pari_curve().ellorder(self, E._order))
|
|
4785
|
+
return self._order
|
|
4786
|
+
|
|
4787
|
+
additive_order = order
|