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,1290 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Square‑root Vélu algorithm for elliptic-curve isogenies
|
|
4
|
+
|
|
5
|
+
The square-root Vélu algorithm, also called the √élu algorithm,
|
|
6
|
+
computes isogenies of elliptic curves in time `\tilde
|
|
7
|
+
O(\sqrt\ell)` rather than naïvely `O(\ell)`, where `\ell` is the degree.
|
|
8
|
+
|
|
9
|
+
The core idea is to reindex the points in the kernel subgroup in a
|
|
10
|
+
baby-step-giant-step manner, then use fast resultant computations to evaluate
|
|
11
|
+
"elliptic polynomials" (see :class:`FastEllipticPolynomial`) in essentially
|
|
12
|
+
square-root time.
|
|
13
|
+
|
|
14
|
+
Based on experiments with Sage version 9.7, the isogeny degree where
|
|
15
|
+
:class:`EllipticCurveHom_velusqrt` begins to outperform
|
|
16
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`
|
|
17
|
+
can be as low as `\approx 100`, but is typically closer to `\approx 1000`,
|
|
18
|
+
depending on the exact situation.
|
|
19
|
+
|
|
20
|
+
REFERENCES: [BDLS2020]_
|
|
21
|
+
|
|
22
|
+
EXAMPLES::
|
|
23
|
+
|
|
24
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
25
|
+
sage: E = EllipticCurve(GF(6666679), [5,5])
|
|
26
|
+
sage: K = E(9970, 1003793, 1)
|
|
27
|
+
sage: K.order()
|
|
28
|
+
10009
|
|
29
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K)
|
|
30
|
+
sage: phi
|
|
31
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 10009:
|
|
32
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 6666679
|
|
33
|
+
To: Elliptic Curve defined by y^2 = x^3 + 227975*x + 3596133 over Finite Field of size 6666679
|
|
34
|
+
sage: phi.codomain()
|
|
35
|
+
Elliptic Curve defined by y^2 = x^3 + 227975*x + 3596133 over Finite Field of size 6666679
|
|
36
|
+
|
|
37
|
+
Note that the isogeny is usually not identical to the one computed by
|
|
38
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`::
|
|
39
|
+
|
|
40
|
+
sage: psi = EllipticCurveIsogeny(E, K)
|
|
41
|
+
sage: psi
|
|
42
|
+
Isogeny of degree 10009
|
|
43
|
+
from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 6666679
|
|
44
|
+
to Elliptic Curve defined by y^2 = x^3 + 5344836*x + 3950273 over Finite Field of size 6666679
|
|
45
|
+
|
|
46
|
+
However, they are certainly separable isogenies with the same kernel
|
|
47
|
+
and must therefore be equal *up to post-isomorphism*::
|
|
48
|
+
|
|
49
|
+
sage: isos = psi.codomain().isomorphisms(phi.codomain())
|
|
50
|
+
sage: sum(iso * psi == phi for iso in isos) # needs sage.symbolic
|
|
51
|
+
1
|
|
52
|
+
|
|
53
|
+
Just like
|
|
54
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`,
|
|
55
|
+
the constructor supports a ``model`` keyword argument::
|
|
56
|
+
|
|
57
|
+
sage: E = EllipticCurve(GF(6666679), [1,1])
|
|
58
|
+
sage: K = E(9091, 517864)
|
|
59
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery')
|
|
60
|
+
sage: phi
|
|
61
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 2999:
|
|
62
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 6666679
|
|
63
|
+
To: Elliptic Curve defined by y^2 = x^3 + 1559358*x^2 + x over Finite Field of size 6666679
|
|
64
|
+
|
|
65
|
+
Internally, :class:`EllipticCurveHom_velusqrt` works on short
|
|
66
|
+
Weierstraß curves, but it performs the conversion automatically::
|
|
67
|
+
|
|
68
|
+
sage: E = EllipticCurve(GF(101), [1,2,3,4,5])
|
|
69
|
+
sage: K = E(1, 2)
|
|
70
|
+
sage: K.order()
|
|
71
|
+
37
|
|
72
|
+
sage: EllipticCurveHom_velusqrt(E, K)
|
|
73
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 37:
|
|
74
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 101
|
|
75
|
+
To: Elliptic Curve defined by y^2 = x^3 + 66*x + 86 over Finite Field of size 101
|
|
76
|
+
|
|
77
|
+
However, this does imply not all elliptic curves are supported.
|
|
78
|
+
Curves without a short Weierstraß model exist in characteristics
|
|
79
|
+
`2` and `3`::
|
|
80
|
+
|
|
81
|
+
sage: F.<t> = GF(3^3)
|
|
82
|
+
sage: E = EllipticCurve(F, [1,1,1,1,1])
|
|
83
|
+
sage: P = E(t^2+2, 1)
|
|
84
|
+
sage: P.order()
|
|
85
|
+
19
|
|
86
|
+
sage: EllipticCurveHom_velusqrt(E, P)
|
|
87
|
+
Traceback (most recent call last):
|
|
88
|
+
...
|
|
89
|
+
NotImplementedError: only implemented for curves having a short Weierstrass model
|
|
90
|
+
|
|
91
|
+
Furthermore, the implementation is restricted to finite fields,
|
|
92
|
+
since this appears to be the most relevant application for the
|
|
93
|
+
square-root Vélu algorithm::
|
|
94
|
+
|
|
95
|
+
sage: E = EllipticCurve('26b1')
|
|
96
|
+
sage: P = E(1,0)
|
|
97
|
+
sage: P.order()
|
|
98
|
+
7
|
|
99
|
+
sage: EllipticCurveHom_velusqrt(E, P)
|
|
100
|
+
Traceback (most recent call last):
|
|
101
|
+
...
|
|
102
|
+
NotImplementedError: only implemented for elliptic curves over finite fields
|
|
103
|
+
|
|
104
|
+
.. NOTE::
|
|
105
|
+
|
|
106
|
+
Some of the methods inherited from :class:`EllipticCurveHom` compute data
|
|
107
|
+
whose size is linear in the degree; this includes kernel polynomial and
|
|
108
|
+
rational maps. In consequence, those methods cannot possibly run in the
|
|
109
|
+
otherwise advertised square-root complexity, as merely storing the result
|
|
110
|
+
already takes linear time.
|
|
111
|
+
|
|
112
|
+
AUTHORS:
|
|
113
|
+
|
|
114
|
+
- Lorenz Panny (2022)
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
# ****************************************************************************
|
|
118
|
+
# Copyright (C) 2022 Lorenz Panny
|
|
119
|
+
#
|
|
120
|
+
# This program is free software: you can redistribute it and/or modify
|
|
121
|
+
# it under the terms of the GNU General Public License as published by
|
|
122
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
123
|
+
# (at your option) any later version.
|
|
124
|
+
# https://www.gnu.org/licenses/
|
|
125
|
+
# ****************************************************************************
|
|
126
|
+
|
|
127
|
+
from sage.misc.cachefunc import cached_method
|
|
128
|
+
from sage.misc.misc_c import prod
|
|
129
|
+
from sage.rings.generic import ProductTree, prod_with_derivative
|
|
130
|
+
from sage.rings.integer import Integer
|
|
131
|
+
from sage.structure.all import coercion_model as cm
|
|
132
|
+
from sage.structure.richcmp import op_EQ
|
|
133
|
+
from sage.structure.sequence import Sequence
|
|
134
|
+
|
|
135
|
+
from .constructor import EllipticCurve
|
|
136
|
+
from .ell_finite_field import EllipticCurve_finite_field
|
|
137
|
+
from .hom import EllipticCurveHom, compare_via_evaluation
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class _VeluBoundObj:
|
|
141
|
+
"""
|
|
142
|
+
Helper object to define the point in which isogeny
|
|
143
|
+
computation should start using square-roor Velu formulae
|
|
144
|
+
instead of Velu.
|
|
145
|
+
|
|
146
|
+
EXAMPLES ::
|
|
147
|
+
|
|
148
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound
|
|
149
|
+
sage: _velu_sqrt_bound.get()
|
|
150
|
+
1000
|
|
151
|
+
sage: _velu_sqrt_bound.set(50)
|
|
152
|
+
sage: _velu_sqrt_bound.get()
|
|
153
|
+
50
|
|
154
|
+
"""
|
|
155
|
+
def __init__(self):
|
|
156
|
+
self.bound = Integer(1000)
|
|
157
|
+
|
|
158
|
+
def set(self, b):
|
|
159
|
+
self.bound = b
|
|
160
|
+
|
|
161
|
+
def get(self):
|
|
162
|
+
return self.bound
|
|
163
|
+
|
|
164
|
+
def __repr__(self):
|
|
165
|
+
return f"VeluSqrtBound Object with bound = {self.bound}"
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
_velu_sqrt_bound = _VeluBoundObj()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _choose_IJK(n):
|
|
172
|
+
r"""
|
|
173
|
+
Helper function to choose an "index system" for the set
|
|
174
|
+
`\{1,3,5,7,...,n-2\}` where `n \geq 5` is an odd integer.
|
|
175
|
+
|
|
176
|
+
INPUT:
|
|
177
|
+
|
|
178
|
+
- ``n`` -- odd :class:`~sage.rings.integer.Integer` `\geq 5`
|
|
179
|
+
|
|
180
|
+
REFERENCES: [BDLS2020]_, Examples 4.7 and 4.12
|
|
181
|
+
|
|
182
|
+
EXAMPLES::
|
|
183
|
+
|
|
184
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _choose_IJK
|
|
185
|
+
sage: IJK = _choose_IJK(101); IJK
|
|
186
|
+
(range(10, 91, 20), range(1, 10, 2), range(101, 101, 2))
|
|
187
|
+
sage: I,J,K = IJK
|
|
188
|
+
sage: sorted([i + s*j for i in iter(I) for j in iter(J) for s in (+1,-1)] + list(iter(K)))
|
|
189
|
+
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51,
|
|
190
|
+
53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
|
|
191
|
+
|
|
192
|
+
TESTS::
|
|
193
|
+
|
|
194
|
+
sage: for n in range(5,1000,2):
|
|
195
|
+
....: I,J,K = _choose_IJK(ZZ(n))
|
|
196
|
+
....: assert sorted([i + s*j for i in iter(I) for j in iter(J) for s in (+1,-1)] + list(iter(K))) == sorted(range(1,n,2))
|
|
197
|
+
"""
|
|
198
|
+
if n % 2 != 1 or n < 5:
|
|
199
|
+
raise ValueError('n must be odd and >= 5')
|
|
200
|
+
b = (n-1).isqrt() // 2
|
|
201
|
+
c = (n-1) // (4*b)
|
|
202
|
+
I = range(2*b, 2*b*(2*c-1)+1, 4*b)
|
|
203
|
+
J = range(1, 2*b, 2)
|
|
204
|
+
K = range(4*b*c+1, n, 2)
|
|
205
|
+
return I, J, K
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _points_range(rr, P, Q=None):
|
|
209
|
+
r"""
|
|
210
|
+
Return an iterator yielding all points `Q + [i]P` where `i` runs
|
|
211
|
+
through the :class:`range` object ``rr``.
|
|
212
|
+
|
|
213
|
+
INPUT:
|
|
214
|
+
|
|
215
|
+
- ``rr`` -- :class:`range` object defining a sequence `S \subseteq \ZZ`
|
|
216
|
+
- ``P`` -- element of an additive abelian group
|
|
217
|
+
- ``Q`` -- element of the same group, or ``None``
|
|
218
|
+
|
|
219
|
+
EXAMPLES::
|
|
220
|
+
|
|
221
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _points_range
|
|
222
|
+
sage: E = EllipticCurve(GF(1123), [4,5])
|
|
223
|
+
sage: P = E(1, 75)
|
|
224
|
+
sage: 2*P
|
|
225
|
+
(1038 : 498 : 1)
|
|
226
|
+
sage: 5*P
|
|
227
|
+
(236 : 598 : 1)
|
|
228
|
+
sage: 8*P
|
|
229
|
+
(717 : 530 : 1)
|
|
230
|
+
sage: list(_points_range(range(2,10,3), P))
|
|
231
|
+
[(1038 : 498 : 1), (236 : 598 : 1), (717 : 530 : 1)]
|
|
232
|
+
sage: Q = E(7, 202)
|
|
233
|
+
sage: Q + 2*P
|
|
234
|
+
(65 : 717 : 1)
|
|
235
|
+
sage: Q + 5*P
|
|
236
|
+
(1119 : 788 : 1)
|
|
237
|
+
sage: Q + 8*P
|
|
238
|
+
(949 : 315 : 1)
|
|
239
|
+
sage: list(_points_range(range(2,10,3), P, Q))
|
|
240
|
+
[(65 : 717 : 1), (1119 : 788 : 1), (949 : 315 : 1)]
|
|
241
|
+
"""
|
|
242
|
+
if not rr:
|
|
243
|
+
return
|
|
244
|
+
a,b,s = rr.start, rr.stop, rr.step
|
|
245
|
+
R = a*P if Q is None else Q + a*P
|
|
246
|
+
yield R
|
|
247
|
+
sP = s*P
|
|
248
|
+
for _ in range(a+s, b, s):
|
|
249
|
+
yield (R := R + sP)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class FastEllipticPolynomial:
|
|
253
|
+
r"""
|
|
254
|
+
A class to represent and evaluate an *elliptic polynomial*,
|
|
255
|
+
and optionally its derivative, in essentially square-root time.
|
|
256
|
+
|
|
257
|
+
The elliptic polynomials computed by this class are of the form
|
|
258
|
+
|
|
259
|
+
.. MATH::
|
|
260
|
+
|
|
261
|
+
h_S(Z) = \prod_{i\in S} (Z - x(Q + [i]P))
|
|
262
|
+
|
|
263
|
+
where `P` is a point of odd order `n \geq 5` and `Q` is either ``None``,
|
|
264
|
+
in which case it is assumed to be `\infty`, or an arbitrary point which is
|
|
265
|
+
not a multiple of `P`.
|
|
266
|
+
|
|
267
|
+
The index set `S` is chosen as follows:
|
|
268
|
+
|
|
269
|
+
- If `Q` is given, then `S = \{0,1,2,3,...,n-1\}`.
|
|
270
|
+
|
|
271
|
+
- If `Q` is omitted, then `S = \{1,3,5,...,n-2\}`. Note that in this case,
|
|
272
|
+
`h_{\{1,2,3,...,n-1\}}` can be computed as `h_S^2` since `n` is odd.
|
|
273
|
+
|
|
274
|
+
INPUT:
|
|
275
|
+
|
|
276
|
+
- ``E`` -- an elliptic curve in short Weierstraß form
|
|
277
|
+
- ``n`` -- an odd integer `\geq 5`
|
|
278
|
+
- ``P`` -- a point on `E`
|
|
279
|
+
- ``Q`` -- a point on `E`, or ``None``
|
|
280
|
+
|
|
281
|
+
ALGORITHM: [BDLS2020]_, Algorithm 2
|
|
282
|
+
|
|
283
|
+
.. NOTE::
|
|
284
|
+
|
|
285
|
+
Currently only implemented for short Weierstraß curves.
|
|
286
|
+
|
|
287
|
+
EXAMPLES::
|
|
288
|
+
|
|
289
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial
|
|
290
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
291
|
+
sage: P = E(4, 35)
|
|
292
|
+
sage: hP = FastEllipticPolynomial(E, P.order(), P); hP
|
|
293
|
+
Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1)
|
|
294
|
+
sage: hP(7)
|
|
295
|
+
19
|
|
296
|
+
sage: prod(7 - (i*P).x() for i in range(1,P.order(),2))
|
|
297
|
+
19
|
|
298
|
+
|
|
299
|
+
Passing `Q` changes the index set::
|
|
300
|
+
|
|
301
|
+
sage: Q = E(0, 17)
|
|
302
|
+
sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q)
|
|
303
|
+
sage: hPQ(7)
|
|
304
|
+
58
|
|
305
|
+
sage: prod(7 - (Q+i*P).x() for i in range(P.order()))
|
|
306
|
+
58
|
|
307
|
+
|
|
308
|
+
The call syntax has an optional keyword argument ``derivative``, which
|
|
309
|
+
will make the function return the pair `(h_S(\alpha), h_S'(\alpha))`
|
|
310
|
+
instead of just `h_S(\alpha)`::
|
|
311
|
+
|
|
312
|
+
sage: hP(7, derivative=True)
|
|
313
|
+
(19, 15)
|
|
314
|
+
sage: R.<Z> = E.base_field()[]
|
|
315
|
+
sage: HP = prod(Z - (i*P).x() for i in range(1,P.order(),2))
|
|
316
|
+
sage: HP
|
|
317
|
+
Z^9 + 16*Z^8 + 57*Z^7 + 6*Z^6 + 45*Z^5 + 31*Z^4 + 46*Z^3 + 10*Z^2 + 28*Z + 41
|
|
318
|
+
sage: HP(7)
|
|
319
|
+
19
|
|
320
|
+
sage: HP.derivative()(7)
|
|
321
|
+
15
|
|
322
|
+
|
|
323
|
+
::
|
|
324
|
+
|
|
325
|
+
sage: hPQ(7, derivative=True)
|
|
326
|
+
(58, 62)
|
|
327
|
+
sage: R.<Z> = E.base_field()[]
|
|
328
|
+
sage: HPQ = prod(Z - (Q+i*P).x() for i in range(P.order()))
|
|
329
|
+
sage: HPQ
|
|
330
|
+
Z^19 + 53*Z^18 + 67*Z^17 + 39*Z^16 + 56*Z^15 + 32*Z^14 + 44*Z^13 + 6*Z^12 + 27*Z^11 + 29*Z^10 + 38*Z^9 + 48*Z^8 + 38*Z^7 + 43*Z^6 + 21*Z^5 + 25*Z^4 + 33*Z^3 + 49*Z^2 + 60*Z
|
|
331
|
+
sage: HPQ(7)
|
|
332
|
+
58
|
|
333
|
+
sage: HPQ.derivative()(7)
|
|
334
|
+
62
|
|
335
|
+
|
|
336
|
+
The input can be an element of any algebra over the base ring::
|
|
337
|
+
|
|
338
|
+
sage: R.<T> = GF(71)[]
|
|
339
|
+
sage: S.<t> = R.quotient(T^2)
|
|
340
|
+
sage: hP(7 + t)
|
|
341
|
+
15*t + 19
|
|
342
|
+
"""
|
|
343
|
+
def __init__(self, E, n, P, Q=None):
|
|
344
|
+
r"""
|
|
345
|
+
Initialize this elliptic polynomial and precompute some
|
|
346
|
+
input-independent data required for evaluation.
|
|
347
|
+
|
|
348
|
+
EXAMPLES::
|
|
349
|
+
|
|
350
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial
|
|
351
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
352
|
+
sage: P = E(0, 17)
|
|
353
|
+
sage: FastEllipticPolynomial(E, P.order(), P)
|
|
354
|
+
Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 57, P = (0 : 17 : 1)
|
|
355
|
+
"""
|
|
356
|
+
if any(E.a_invariants()[:-2]):
|
|
357
|
+
raise NotImplementedError('only implemented for short Weierstrass curves')
|
|
358
|
+
|
|
359
|
+
n = Integer(n)
|
|
360
|
+
|
|
361
|
+
if Q is None:
|
|
362
|
+
IJK = _choose_IJK(n) # [1,3,5,7,...,n-4,n-2]
|
|
363
|
+
else:
|
|
364
|
+
IJK = _choose_IJK(2*n+1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1]
|
|
365
|
+
|
|
366
|
+
self.base = E.base_ring()
|
|
367
|
+
R, Z = self.base['Z'].objgen()
|
|
368
|
+
|
|
369
|
+
# Cassels, Lectures on Elliptic Curves, p.132
|
|
370
|
+
A,B = E.a_invariants()[-2:]
|
|
371
|
+
Fs = lambda X,Y: (
|
|
372
|
+
(X - Y)**2,
|
|
373
|
+
-2 * (X*Y + A) * (X + Y) - 4*B,
|
|
374
|
+
(X*Y - A)**2 - 4*B*(X+Y),
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
I, J, K = IJK
|
|
378
|
+
xI = (R.x() for R in _points_range(I, P, Q))
|
|
379
|
+
xJ = [R.x() for R in _points_range(J, P )]
|
|
380
|
+
xK = (R.x() for R in _points_range(K, P, Q))
|
|
381
|
+
|
|
382
|
+
self.hItree = ProductTree(Z - xi for xi in xI)
|
|
383
|
+
|
|
384
|
+
self.EJparts = [Fs(Z,xj) for xj in xJ]
|
|
385
|
+
|
|
386
|
+
DJ = prod(F0j for F0j,_,_ in self.EJparts)
|
|
387
|
+
self.DeltaIJ = self._hI_resultant(DJ)
|
|
388
|
+
|
|
389
|
+
self.hK = R(prod(Z - xk for xk in xK))
|
|
390
|
+
self.dhK = self.hK.derivative()
|
|
391
|
+
|
|
392
|
+
if Q is None:
|
|
393
|
+
self._repr = f"Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with {n = }, {P = }"
|
|
394
|
+
else:
|
|
395
|
+
self._repr = f"Fast elliptic polynomial prod(Z - x(Q+i*P) for i in range(n)) with {n = }, {P = }, {Q = }"
|
|
396
|
+
|
|
397
|
+
def __call__(self, alpha, *, derivative=False):
|
|
398
|
+
r"""
|
|
399
|
+
Evaluate this elliptic polynomial at a point `\alpha`,
|
|
400
|
+
and if ``derivative`` is set to ``True`` also return
|
|
401
|
+
the evaluation of the derivative at `\alpha`.
|
|
402
|
+
|
|
403
|
+
INPUT:
|
|
404
|
+
|
|
405
|
+
- ``alpha`` -- an element of any algebra over the base ring
|
|
406
|
+
- ``derivative`` -- boolean (default: ``False``)
|
|
407
|
+
|
|
408
|
+
EXAMPLES::
|
|
409
|
+
|
|
410
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial
|
|
411
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
412
|
+
sage: P = E(4, 35)
|
|
413
|
+
sage: hP = FastEllipticPolynomial(E, P.order(), P); hP
|
|
414
|
+
Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1)
|
|
415
|
+
sage: hP(7)
|
|
416
|
+
19
|
|
417
|
+
sage: hP(7, derivative=True)
|
|
418
|
+
(19, 15)
|
|
419
|
+
"""
|
|
420
|
+
base = cm.common_parent(self.base, alpha)
|
|
421
|
+
|
|
422
|
+
EJparts = [tuple(F.base_extend(base) for F in part) for part in self.EJparts]
|
|
423
|
+
|
|
424
|
+
EJfacs = [(F0j * alpha + F1j) * alpha + F2j for F0j,F1j,F2j in EJparts]
|
|
425
|
+
if not derivative:
|
|
426
|
+
EJ = prod(EJfacs)
|
|
427
|
+
else:
|
|
428
|
+
dEJfacs = [2 * F0j * alpha + F1j for F0j,F1j,_ in EJparts]
|
|
429
|
+
EJ, dEJ = prod_with_derivative(zip(EJfacs, dEJfacs))
|
|
430
|
+
|
|
431
|
+
EJrems = self.hItree.remainders(EJ)
|
|
432
|
+
R = self._hI_resultant(EJ, EJrems)
|
|
433
|
+
hK = self.hK(alpha)
|
|
434
|
+
res = hK * R / self.DeltaIJ
|
|
435
|
+
res = base(res)
|
|
436
|
+
|
|
437
|
+
if not derivative:
|
|
438
|
+
return res
|
|
439
|
+
|
|
440
|
+
dEJrems = self.hItree.remainders(dEJ)
|
|
441
|
+
cnt = EJrems.count(0)
|
|
442
|
+
if cnt == 0:
|
|
443
|
+
dR = sum(R // EJrem * dEJrem for EJrem, dEJrem in zip(EJrems, dEJrems))
|
|
444
|
+
elif cnt == 1:
|
|
445
|
+
dR = prod(EJrem or dEJrem for EJrem, dEJrem in zip(EJrems, dEJrems))
|
|
446
|
+
else:
|
|
447
|
+
dR = 0
|
|
448
|
+
dhK = self.dhK(alpha)
|
|
449
|
+
dres = (dhK * R + hK * dR) / self.DeltaIJ
|
|
450
|
+
dres = base(dres)
|
|
451
|
+
|
|
452
|
+
return res, dres
|
|
453
|
+
|
|
454
|
+
def _hI_resultant(self, poly, rems=None):
|
|
455
|
+
r"""
|
|
456
|
+
Internal helper function to evaluate a resultant with `h_I` quickly,
|
|
457
|
+
using the product tree constructed in :meth:`__init__`.
|
|
458
|
+
|
|
459
|
+
INPUT:
|
|
460
|
+
|
|
461
|
+
- ``poly`` -- an element of the base ring of this product tree,
|
|
462
|
+
which must be a polynomial ring supporting ``%``
|
|
463
|
+
- ``rems`` -- result of ``self.hItree.remainders(poly)``, or ``None``
|
|
464
|
+
|
|
465
|
+
EXAMPLES::
|
|
466
|
+
|
|
467
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial
|
|
468
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
469
|
+
sage: P = E(4, 35)
|
|
470
|
+
sage: hP = FastEllipticPolynomial(E, P.order(), P)
|
|
471
|
+
sage: f = GF(71)['Z']([5,4,3,2,1])
|
|
472
|
+
sage: hP._hI_resultant(f)
|
|
473
|
+
66
|
|
474
|
+
sage: prod(f(r) for fi in hP.hItree.layers[0]
|
|
475
|
+
....: for r in fi.roots(multiplicities=False))
|
|
476
|
+
66
|
|
477
|
+
|
|
478
|
+
::
|
|
479
|
+
|
|
480
|
+
sage: Q = E(0, 17)
|
|
481
|
+
sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q)
|
|
482
|
+
sage: f = GF(71)['Z']([9,8,7,6,5,4,3,2,1])
|
|
483
|
+
sage: hPQ._hI_resultant(f)
|
|
484
|
+
36
|
|
485
|
+
sage: prod(f(r) for fi in hPQ.hItree.layers[0]
|
|
486
|
+
....: for r in fi.roots(multiplicities=False))
|
|
487
|
+
36
|
|
488
|
+
"""
|
|
489
|
+
if rems is None:
|
|
490
|
+
rems = self.hItree.remainders(poly)
|
|
491
|
+
r = prod(rems)
|
|
492
|
+
s = -1 if len(self.hItree) % 2 == 1 == poly.degree() else 1
|
|
493
|
+
assert r.is_constant()
|
|
494
|
+
return s * r[0]
|
|
495
|
+
|
|
496
|
+
def __repr__(self):
|
|
497
|
+
r"""
|
|
498
|
+
Return a string representation of this elliptic polynomial.
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial
|
|
503
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
504
|
+
sage: P = E(4, 35)
|
|
505
|
+
sage: FastEllipticPolynomial(E, P.order(), P)
|
|
506
|
+
Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1)
|
|
507
|
+
sage: Q = E(0, 17)
|
|
508
|
+
sage: FastEllipticPolynomial(E, P.order(), P, Q)
|
|
509
|
+
Fast elliptic polynomial prod(Z - x(Q+i*P) for i in range(n)) with n = 19, P = (4 : 35 : 1), Q = (0 : 17 : 1)
|
|
510
|
+
"""
|
|
511
|
+
return self._repr
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _point_outside_subgroup(P):
|
|
515
|
+
r"""
|
|
516
|
+
Simple helper function to return a point on an elliptic
|
|
517
|
+
curve `E` that is not a multiple of a given point `P`.
|
|
518
|
+
The base field is extended if (and only if) necessary.
|
|
519
|
+
|
|
520
|
+
INPUT:
|
|
521
|
+
|
|
522
|
+
- ``P`` -- a point on an elliptic curve over a finite field
|
|
523
|
+
|
|
524
|
+
EXAMPLES::
|
|
525
|
+
|
|
526
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _point_outside_subgroup
|
|
527
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
528
|
+
sage: P = E(4, 35)
|
|
529
|
+
sage: Q = _point_outside_subgroup(P); Q # random
|
|
530
|
+
(14 : 11 : 1)
|
|
531
|
+
sage: Q.curve()(P).discrete_log(Q)
|
|
532
|
+
Traceback (most recent call last):
|
|
533
|
+
...
|
|
534
|
+
ValueError: ECDLog problem has no solution (...)
|
|
535
|
+
|
|
536
|
+
An example where `P` generates `E(\mathbb F_q)`::
|
|
537
|
+
|
|
538
|
+
sage: E.<P> = EllipticCurve(GF(71), [5,5])
|
|
539
|
+
sage: P.order() == E.cardinality()
|
|
540
|
+
True
|
|
541
|
+
sage: Q = _point_outside_subgroup(P); Q # random
|
|
542
|
+
(35*z2 + 7 : 24*z2 + 7 : 1)
|
|
543
|
+
sage: Q.curve()(P).discrete_log(Q)
|
|
544
|
+
Traceback (most recent call last):
|
|
545
|
+
...
|
|
546
|
+
ValueError: ECDLog problem has no solution (...)
|
|
547
|
+
|
|
548
|
+
An example where the group is non-cyclic::
|
|
549
|
+
|
|
550
|
+
sage: E.<P,_> = EllipticCurve(GF(71^2), [0,1])
|
|
551
|
+
sage: E.abelian_group()
|
|
552
|
+
Additive abelian group isomorphic to Z/72 + Z/72 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 71^2
|
|
553
|
+
sage: P = E.random_point()
|
|
554
|
+
sage: Q = _point_outside_subgroup(P); Q # random
|
|
555
|
+
(18*z2 + 46 : 58*z2 + 61 : 1)
|
|
556
|
+
sage: Q in E
|
|
557
|
+
True
|
|
558
|
+
sage: P.discrete_log(Q)
|
|
559
|
+
Traceback (most recent call last):
|
|
560
|
+
...
|
|
561
|
+
ValueError: ECDLog problem has no solution (...)
|
|
562
|
+
|
|
563
|
+
.. NOTE::
|
|
564
|
+
|
|
565
|
+
The field extension is only needed when `P` generates the
|
|
566
|
+
entire rational subgroup of `E`. But in that case, the
|
|
567
|
+
isogeny defined by `P` is simply `\pi-1` (where `\pi` is
|
|
568
|
+
Frobenius). Thus, once `\pi-1` can be represented in Sage,
|
|
569
|
+
we may just return that in
|
|
570
|
+
:meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.isogeny`
|
|
571
|
+
rather than insisting on using square-root Vélu.
|
|
572
|
+
"""
|
|
573
|
+
E = P.curve()
|
|
574
|
+
n = P.order()
|
|
575
|
+
if n == E.order():
|
|
576
|
+
d = 2 + (n == 7 and E.base_field().cardinality() == 3)
|
|
577
|
+
F = E.base_field().extension(d)
|
|
578
|
+
E = E.base_extend(F)
|
|
579
|
+
P = E(P)
|
|
580
|
+
# assert E.cardinality() > n
|
|
581
|
+
for _ in range(1000):
|
|
582
|
+
Q = E.random_point()
|
|
583
|
+
if n*Q or not P.weil_pairing(Q,n).is_one():
|
|
584
|
+
return Q
|
|
585
|
+
raise NotImplementedError('could not find a point outside the kernel')
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
class EllipticCurveHom_velusqrt(EllipticCurveHom):
|
|
589
|
+
r"""
|
|
590
|
+
This class implements separable odd-degree isogenies of elliptic
|
|
591
|
+
curves over finite fields using the square-root Vélu algorithm.
|
|
592
|
+
|
|
593
|
+
The complexity is `\tilde O(\sqrt{\ell})` base-field operations,
|
|
594
|
+
where `\ell` is the degree.
|
|
595
|
+
|
|
596
|
+
REFERENCES: [BDLS2020]_
|
|
597
|
+
|
|
598
|
+
INPUT:
|
|
599
|
+
|
|
600
|
+
- ``E`` -- an elliptic curve over a finite field
|
|
601
|
+
- ``P`` -- a point on `E` of odd order `\geq 9`
|
|
602
|
+
- ``codomain`` -- codomain elliptic curve (optional)
|
|
603
|
+
- ``model`` -- string (optional); input to
|
|
604
|
+
:meth:`~sage.schemes.elliptic_curves.ell_field.compute_model`
|
|
605
|
+
- ``Q`` -- a point on `E` outside `\langle P\rangle`, or ``None``
|
|
606
|
+
|
|
607
|
+
EXAMPLES::
|
|
608
|
+
|
|
609
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
610
|
+
sage: F.<t> = GF(10009^3)
|
|
611
|
+
sage: E = EllipticCurve(F, [t,t])
|
|
612
|
+
sage: K = E(2154*t^2 + 5711*t + 2899, 7340*t^2 + 4653*t + 6935)
|
|
613
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K); phi
|
|
614
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 601:
|
|
615
|
+
From: Elliptic Curve defined by y^2 = x^3 + t*x + t over Finite Field in t of size 10009^3
|
|
616
|
+
To: Elliptic Curve defined by y^2 = x^3 + (263*t^2+3173*t+4759)*x + (3898*t^2+6111*t+9443) over Finite Field in t of size 10009^3
|
|
617
|
+
sage: phi(K)
|
|
618
|
+
(0 : 1 : 0)
|
|
619
|
+
sage: P = E(2, 3163*t^2 + 7293*t + 5999)
|
|
620
|
+
sage: phi(P)
|
|
621
|
+
(6085*t^2 + 855*t + 8720 : 8078*t^2 + 9889*t + 6030 : 1)
|
|
622
|
+
sage: Q = E(6, 5575*t^2 + 6607*t + 9991)
|
|
623
|
+
sage: phi(Q)
|
|
624
|
+
(626*t^2 + 9749*t + 1291 : 5931*t^2 + 8549*t + 3111 : 1)
|
|
625
|
+
sage: phi(P + Q)
|
|
626
|
+
(983*t^2 + 4894*t + 4072 : 5047*t^2 + 9325*t + 336 : 1)
|
|
627
|
+
sage: phi(P) + phi(Q)
|
|
628
|
+
(983*t^2 + 4894*t + 4072 : 5047*t^2 + 9325*t + 336 : 1)
|
|
629
|
+
|
|
630
|
+
TESTS:
|
|
631
|
+
|
|
632
|
+
Check on a random example that the isogeny is a well-defined
|
|
633
|
+
group homomorphism with the correct kernel::
|
|
634
|
+
|
|
635
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing
|
|
636
|
+
sage: E, K = _random_example_for_testing()
|
|
637
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K)
|
|
638
|
+
sage: not phi(K)
|
|
639
|
+
True
|
|
640
|
+
sage: not phi(randrange(2^99) * K)
|
|
641
|
+
True
|
|
642
|
+
sage: P = E.random_point()
|
|
643
|
+
sage: phi(P) in phi.codomain()
|
|
644
|
+
True
|
|
645
|
+
sage: Q = E.random_point()
|
|
646
|
+
sage: phi(Q) in phi.codomain()
|
|
647
|
+
True
|
|
648
|
+
sage: phi(P + Q) == phi(P) + phi(Q)
|
|
649
|
+
True
|
|
650
|
+
|
|
651
|
+
Check that the isogeny preserves the field of definition::
|
|
652
|
+
|
|
653
|
+
sage: Sequence(K).universe() == phi.domain().base_field()
|
|
654
|
+
True
|
|
655
|
+
sage: phi.codomain().base_field() == phi.domain().base_field()
|
|
656
|
+
True
|
|
657
|
+
|
|
658
|
+
Check that the isogeny affects the Weil pairing in the correct way::
|
|
659
|
+
|
|
660
|
+
sage: m = lcm(P.order(), Q.order())
|
|
661
|
+
sage: e1 = P.weil_pairing(Q, m)
|
|
662
|
+
sage: e2 = phi(P).weil_pairing(phi(Q), m)
|
|
663
|
+
sage: e2 == e1^phi.degree()
|
|
664
|
+
True
|
|
665
|
+
|
|
666
|
+
Check that the isogeny matches (up to isomorphism) the one from
|
|
667
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`::
|
|
668
|
+
|
|
669
|
+
sage: psi = EllipticCurveIsogeny(E, K)
|
|
670
|
+
sage: check = lambda iso: all(iso(psi(Q)) == phi(Q) for Q in E.gens())
|
|
671
|
+
sage: any(map(check, psi.codomain().isomorphisms(phi.codomain())))
|
|
672
|
+
True
|
|
673
|
+
|
|
674
|
+
.. SEEALSO::
|
|
675
|
+
|
|
676
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`
|
|
677
|
+
"""
|
|
678
|
+
def __init__(self, E, P, *, codomain=None, model=None, Q=None):
|
|
679
|
+
r"""
|
|
680
|
+
Initialize this square-root Vélu isogeny from a kernel point of odd order.
|
|
681
|
+
|
|
682
|
+
EXAMPLES::
|
|
683
|
+
|
|
684
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
685
|
+
sage: E = EllipticCurve(GF(71), [5,5])
|
|
686
|
+
sage: P = E(-2, 22)
|
|
687
|
+
sage: EllipticCurveHom_velusqrt(E, P)
|
|
688
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 19:
|
|
689
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71
|
|
690
|
+
To: Elliptic Curve defined by y^2 = x^3 + 13*x + 11 over Finite Field of size 71
|
|
691
|
+
|
|
692
|
+
::
|
|
693
|
+
|
|
694
|
+
sage: E.<P> = EllipticCurve(GF(419), [1,0])
|
|
695
|
+
sage: K = 4*P
|
|
696
|
+
sage: EllipticCurveHom_velusqrt(E, K)
|
|
697
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 105:
|
|
698
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419
|
|
699
|
+
To: Elliptic Curve defined by y^2 = x^3 + 301*x + 86 over Finite Field of size 419
|
|
700
|
+
sage: E2 = EllipticCurve(GF(419), [0,6,0,385,42])
|
|
701
|
+
sage: EllipticCurveHom_velusqrt(E, K, codomain=E2)
|
|
702
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 105:
|
|
703
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419
|
|
704
|
+
To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 385*x + 42 over Finite Field of size 419
|
|
705
|
+
sage: EllipticCurveHom_velusqrt(E, K, model='montgomery')
|
|
706
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 105:
|
|
707
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419
|
|
708
|
+
To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + x over Finite Field of size 419
|
|
709
|
+
|
|
710
|
+
Note that the implementation in fact also works in almost all
|
|
711
|
+
cases when the degree is `5` or `7`. The reason we restrict to
|
|
712
|
+
degrees `\geq 9` is that (only!) when trying to compute a
|
|
713
|
+
`7`-isogeny from a rational point on an elliptic curve defined
|
|
714
|
+
over `\GF{3}`, the point `Q` required in the formulas has to be
|
|
715
|
+
defined over a cubic extension rather than an at most quadratic
|
|
716
|
+
extension, which can result in the constructed isogeny being
|
|
717
|
+
irrational. See :issue:`34467`. The assertion in the following
|
|
718
|
+
example currently fails if the minimum degree is lowered::
|
|
719
|
+
|
|
720
|
+
sage: E = EllipticCurve(GF(3), [2,1])
|
|
721
|
+
sage: P, = E.gens()
|
|
722
|
+
sage: P.order()
|
|
723
|
+
7
|
|
724
|
+
sage: psi = E.isogeny(P)
|
|
725
|
+
sage: phi = E.isogeny(P, algorithm='velusqrt') # not tested
|
|
726
|
+
sage: phi._Q.base_ring() # not tested
|
|
727
|
+
Finite Field in z3 of size 3^3
|
|
728
|
+
sage: assert phi.codomain().is_isomorphic(psi.codomain()) # not tested
|
|
729
|
+
"""
|
|
730
|
+
if not isinstance(E, EllipticCurve_finite_field):
|
|
731
|
+
raise NotImplementedError('only implemented for elliptic curves over finite fields')
|
|
732
|
+
|
|
733
|
+
if codomain is not None and model is not None:
|
|
734
|
+
raise ValueError('cannot specify a codomain curve and model name simultaneously')
|
|
735
|
+
|
|
736
|
+
try:
|
|
737
|
+
P = E(P)
|
|
738
|
+
except TypeError:
|
|
739
|
+
raise ValueError('given kernel point P does not lie on E')
|
|
740
|
+
self._degree = P.order()
|
|
741
|
+
if self._degree % 2 != 1 or self._degree < 9:
|
|
742
|
+
raise NotImplementedError('only implemented for odd degrees >= 9')
|
|
743
|
+
|
|
744
|
+
try:
|
|
745
|
+
self._raw_domain = E.short_weierstrass_model()
|
|
746
|
+
except ValueError:
|
|
747
|
+
raise NotImplementedError('only implemented for curves having a short Weierstrass model')
|
|
748
|
+
self._pre_iso = E.isomorphism_to(self._raw_domain)
|
|
749
|
+
self._P = self._pre_iso(P)
|
|
750
|
+
|
|
751
|
+
if Q is not None:
|
|
752
|
+
self._Q = self._pre_iso(E(Q))
|
|
753
|
+
EE = E
|
|
754
|
+
else:
|
|
755
|
+
self._Q = _point_outside_subgroup(self._P) # may extend base field
|
|
756
|
+
EE = self._Q.curve()
|
|
757
|
+
self._P = EE(self._P)
|
|
758
|
+
|
|
759
|
+
self._internal_base_ring = EE.base_ring()
|
|
760
|
+
|
|
761
|
+
self._h0 = FastEllipticPolynomial(EE, self._degree, self._P)
|
|
762
|
+
self._h1 = FastEllipticPolynomial(EE, self._degree, self._P, self._Q)
|
|
763
|
+
|
|
764
|
+
self._domain = E
|
|
765
|
+
self._compute_codomain(model=model)
|
|
766
|
+
|
|
767
|
+
if codomain is not None:
|
|
768
|
+
self._post_iso = self._codomain.isomorphism_to(codomain) * self._post_iso
|
|
769
|
+
self._codomain = codomain
|
|
770
|
+
|
|
771
|
+
super().__init__(self._domain, self._codomain)
|
|
772
|
+
|
|
773
|
+
def _raw_eval(self, x, y=None):
|
|
774
|
+
r"""
|
|
775
|
+
Evaluate the "inner" square-root Vélu isogeny
|
|
776
|
+
(i.e., without applying pre- and post-isomorphism)
|
|
777
|
+
at either just an `x`-coordinate or a pair
|
|
778
|
+
`(x,y)` of coordinates.
|
|
779
|
+
|
|
780
|
+
If the given point lies in the kernel, the empty tuple
|
|
781
|
+
``()`` is returned.
|
|
782
|
+
|
|
783
|
+
No checking of the input coordinates is performed.
|
|
784
|
+
|
|
785
|
+
ALGORITHM:
|
|
786
|
+
|
|
787
|
+
- [Ren2018]_, Theorem 1
|
|
788
|
+
- :class:`FastEllipticPolynomial`
|
|
789
|
+
|
|
790
|
+
EXAMPLES::
|
|
791
|
+
|
|
792
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
793
|
+
sage: E = EllipticCurve(GF(65537), [1,1])
|
|
794
|
+
sage: P = E(2112, 803)
|
|
795
|
+
sage: phi = EllipticCurveHom_velusqrt(E, P, Q=(32924,0))
|
|
796
|
+
sage: phi._raw_domain is E
|
|
797
|
+
True
|
|
798
|
+
sage: phi._raw_codomain
|
|
799
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 65537
|
|
800
|
+
sage: Q = E(42, 15860)
|
|
801
|
+
sage: phi._raw_eval(Q.x())
|
|
802
|
+
11958
|
|
803
|
+
sage: phi._raw_eval(*Q.xy())
|
|
804
|
+
(11958, 42770)
|
|
805
|
+
sage: phi._raw_codomain.defining_polynomial()(*phi._raw_eval(*Q.xy()), 1)
|
|
806
|
+
0
|
|
807
|
+
|
|
808
|
+
No checking is performed::
|
|
809
|
+
|
|
810
|
+
sage: E.defining_polynomial()(123, 456, 1)
|
|
811
|
+
50907
|
|
812
|
+
sage: phi._raw_eval(123, 456)
|
|
813
|
+
(3805, 29941)
|
|
814
|
+
|
|
815
|
+
TESTS::
|
|
816
|
+
|
|
817
|
+
sage: {t.parent() for t in phi._raw_eval(*Q.xy())}
|
|
818
|
+
{Finite Field of size 65537}
|
|
819
|
+
sage: {t.parent() for t in phi._raw_eval(123, 456)}
|
|
820
|
+
{Finite Field of size 65537}
|
|
821
|
+
"""
|
|
822
|
+
if y is None:
|
|
823
|
+
h0 = self._h0(x)
|
|
824
|
+
h1 = self._h1(x)
|
|
825
|
+
else:
|
|
826
|
+
h0, h0d = self._h0(x, derivative=True)
|
|
827
|
+
h1, h1d = self._h1(x, derivative=True)
|
|
828
|
+
|
|
829
|
+
# assert h0 == prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2))
|
|
830
|
+
# assert h1 == prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() ))
|
|
831
|
+
|
|
832
|
+
if not h0:
|
|
833
|
+
return ()
|
|
834
|
+
|
|
835
|
+
xx = h1 / h0**2
|
|
836
|
+
|
|
837
|
+
if y is None:
|
|
838
|
+
return xx
|
|
839
|
+
|
|
840
|
+
# assert h0d == sum(prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2) if i!=j) for j in range(1,self._P.order(),2))
|
|
841
|
+
# assert h1d == sum(prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() ) if i!=j) for j in range( self._P.order() ))
|
|
842
|
+
|
|
843
|
+
yy = y * (h1d - 2 * h1 / h0 * h0d) / h0**2
|
|
844
|
+
|
|
845
|
+
return xx, yy
|
|
846
|
+
|
|
847
|
+
def _compute_codomain(self, model=None):
|
|
848
|
+
r"""
|
|
849
|
+
Helper method to compute the codomain of this
|
|
850
|
+
square-root Vélu isogeny
|
|
851
|
+
once the data for :meth:`_raw_eval` has been initialized.
|
|
852
|
+
|
|
853
|
+
Called by the constructor.
|
|
854
|
+
|
|
855
|
+
INPUT:
|
|
856
|
+
|
|
857
|
+
- ``model`` -- string (optional); input to
|
|
858
|
+
:meth:`~sage.schemes.elliptic_curves.ell_field.compute_model`
|
|
859
|
+
|
|
860
|
+
EXAMPLES::
|
|
861
|
+
|
|
862
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
863
|
+
sage: E = EllipticCurve(GF(71), [0,5,0,1,0])
|
|
864
|
+
sage: P = E(4, 19)
|
|
865
|
+
sage: phi = EllipticCurveHom_velusqrt(E, P)
|
|
866
|
+
sage: phi._raw_codomain
|
|
867
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 71
|
|
868
|
+
sage: phi._codomain
|
|
869
|
+
Elliptic Curve defined by y^2 = x^3 + 8*x + 34 over Finite Field of size 71
|
|
870
|
+
sage: phi.codomain()
|
|
871
|
+
Elliptic Curve defined by y^2 = x^3 + 8*x + 34 over Finite Field of size 71
|
|
872
|
+
|
|
873
|
+
Passing a ``model`` parameter is supported::
|
|
874
|
+
|
|
875
|
+
sage: phi._compute_codomain('montgomery')
|
|
876
|
+
sage: phi
|
|
877
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 19:
|
|
878
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71
|
|
879
|
+
To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71
|
|
880
|
+
|
|
881
|
+
TESTS::
|
|
882
|
+
|
|
883
|
+
sage: F.<t> = GF(5^2)
|
|
884
|
+
sage: E = EllipticCurve([3*t, 2*t+4, 3*t+2, t+4, 3*t])
|
|
885
|
+
sage: K = E(3*t, 2)
|
|
886
|
+
sage: EllipticCurveHom_velusqrt(E, K) # indirect doctest
|
|
887
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 19:
|
|
888
|
+
From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2
|
|
889
|
+
To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2
|
|
890
|
+
"""
|
|
891
|
+
R, Z = self._internal_base_ring['Z'].objgen()
|
|
892
|
+
poly = self._raw_domain.two_division_polynomial().monic()(Z)
|
|
893
|
+
|
|
894
|
+
f = 1
|
|
895
|
+
for g,_ in poly.factor():
|
|
896
|
+
if g.degree() == 1:
|
|
897
|
+
f *= Z - self._raw_eval(-g[0])
|
|
898
|
+
else:
|
|
899
|
+
K, X0 = self._internal_base_ring.extension(g,'T').objgen()
|
|
900
|
+
imX0 = self._raw_eval(X0)
|
|
901
|
+
try:
|
|
902
|
+
imX0 = imX0.polynomial() # K is a FiniteField
|
|
903
|
+
except AttributeError:
|
|
904
|
+
imX0 = imX0.lift() # K is a PolynomialQuotientRing
|
|
905
|
+
V = R['V'].gen()
|
|
906
|
+
f *= (Z - imX0(V)).resultant(g(V))
|
|
907
|
+
|
|
908
|
+
a6,a4,a2,_ = f.monic().list()
|
|
909
|
+
|
|
910
|
+
self._raw_codomain = EllipticCurve(self._domain.base_ring(), [0,a2,0,a4,a6])
|
|
911
|
+
|
|
912
|
+
if model is None:
|
|
913
|
+
model = 'short_weierstrass'
|
|
914
|
+
|
|
915
|
+
from sage.schemes.elliptic_curves.ell_field import compute_model
|
|
916
|
+
self._codomain = compute_model(self._raw_codomain, model)
|
|
917
|
+
self._post_iso = self._raw_codomain.isomorphism_to(self._codomain)
|
|
918
|
+
|
|
919
|
+
def _eval(self, P):
|
|
920
|
+
r"""
|
|
921
|
+
Evaluate this square-root Vélu isogeny at a point.
|
|
922
|
+
|
|
923
|
+
INPUT:
|
|
924
|
+
|
|
925
|
+
- ``P`` -- point on the domain, defined over any algebra over the base field
|
|
926
|
+
|
|
927
|
+
EXAMPLES::
|
|
928
|
+
|
|
929
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
930
|
+
sage: E = EllipticCurve(GF(71), [0,5,0,1,0])
|
|
931
|
+
sage: K = E(4, 19)
|
|
932
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery')
|
|
933
|
+
sage: phi
|
|
934
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 19:
|
|
935
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71
|
|
936
|
+
To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71
|
|
937
|
+
sage: phi(K)
|
|
938
|
+
(0 : 1 : 0)
|
|
939
|
+
sage: phi(5*K)
|
|
940
|
+
(0 : 1 : 0)
|
|
941
|
+
sage: phi(E(0))
|
|
942
|
+
(0 : 1 : 0)
|
|
943
|
+
sage: phi(E(0,0))
|
|
944
|
+
(0 : 0 : 1)
|
|
945
|
+
sage: phi(E(7,13))
|
|
946
|
+
(70 : 31 : 1)
|
|
947
|
+
|
|
948
|
+
TESTS::
|
|
949
|
+
|
|
950
|
+
sage: P,Q = (E.random_point() for _ in 'PQ')
|
|
951
|
+
sage: assert phi(P) in phi.codomain()
|
|
952
|
+
sage: assert phi(Q) in phi.codomain()
|
|
953
|
+
sage: assert phi(P + Q) == phi(P) + phi(Q)
|
|
954
|
+
|
|
955
|
+
Randomized testing::
|
|
956
|
+
|
|
957
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
958
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing
|
|
959
|
+
sage: E, K = _random_example_for_testing()
|
|
960
|
+
sage: phi = EllipticCurveHom_velusqrt(E, K)
|
|
961
|
+
sage: phi.degree() == K.order()
|
|
962
|
+
True
|
|
963
|
+
sage: P = E.random_point()
|
|
964
|
+
sage: phi(P) in phi.codomain()
|
|
965
|
+
True
|
|
966
|
+
sage: Q = E.random_point()
|
|
967
|
+
sage: phi(Q) in phi.codomain()
|
|
968
|
+
True
|
|
969
|
+
sage: phi(P + Q) == phi(P) + phi(Q)
|
|
970
|
+
True
|
|
971
|
+
"""
|
|
972
|
+
if self._domain.defining_polynomial()(*P):
|
|
973
|
+
raise ValueError(f'{P} not on {self._domain}')
|
|
974
|
+
|
|
975
|
+
k = Sequence(P).universe()
|
|
976
|
+
|
|
977
|
+
if not P:
|
|
978
|
+
return self._codomain(0).change_ring(k)
|
|
979
|
+
|
|
980
|
+
P = self._pre_iso._eval(P)
|
|
981
|
+
|
|
982
|
+
xy = self._raw_eval(*P.xy())
|
|
983
|
+
|
|
984
|
+
if xy == ():
|
|
985
|
+
return self._codomain(0).change_ring(k)
|
|
986
|
+
|
|
987
|
+
return self._post_iso._eval(Sequence(xy, k) + [1])
|
|
988
|
+
|
|
989
|
+
_call_ = _eval
|
|
990
|
+
|
|
991
|
+
def _repr_(self):
|
|
992
|
+
r"""
|
|
993
|
+
Return basic information about this square-root Vélu isogeny as a string.
|
|
994
|
+
|
|
995
|
+
EXAMPLES::
|
|
996
|
+
|
|
997
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
998
|
+
sage: E.<P> = EllipticCurve(GF(71), [5,5])
|
|
999
|
+
sage: phi = EllipticCurveHom_velusqrt(E, P)
|
|
1000
|
+
sage: phi # indirect doctest
|
|
1001
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 57:
|
|
1002
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71
|
|
1003
|
+
To: Elliptic Curve defined by y^2 = x^3 + 19*x + 45 over Finite Field of size 71
|
|
1004
|
+
"""
|
|
1005
|
+
return f'Elliptic-curve isogeny (using square-root Vélu) of degree {self._degree}:' \
|
|
1006
|
+
f'\n From: {self._domain}' \
|
|
1007
|
+
f'\n To: {self._codomain}'
|
|
1008
|
+
|
|
1009
|
+
@staticmethod
|
|
1010
|
+
def _comparison_impl(left, right, op):
|
|
1011
|
+
r"""
|
|
1012
|
+
Compare a square-root Vélu isogeny to another elliptic-curve morphism.
|
|
1013
|
+
|
|
1014
|
+
Called by :meth:`EllipticCurveHom._richcmp_`.
|
|
1015
|
+
|
|
1016
|
+
INPUT:
|
|
1017
|
+
|
|
1018
|
+
- ``left``, ``right`` -- :class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`
|
|
1019
|
+
objects
|
|
1020
|
+
|
|
1021
|
+
ALGORITHM:
|
|
1022
|
+
|
|
1023
|
+
:func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`
|
|
1024
|
+
|
|
1025
|
+
EXAMPLES::
|
|
1026
|
+
|
|
1027
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
1028
|
+
sage: E = EllipticCurve(GF(101), [5,5,5,5,5])
|
|
1029
|
+
sage: phi = EllipticCurveHom_velusqrt(E, E.lift_x(11)); phi
|
|
1030
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 59:
|
|
1031
|
+
From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101
|
|
1032
|
+
To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101
|
|
1033
|
+
sage: psi = EllipticCurveHom_velusqrt(E, E.lift_x(-1)); psi
|
|
1034
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 59:
|
|
1035
|
+
From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101
|
|
1036
|
+
To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101
|
|
1037
|
+
sage: phi == psi # needs sage.symbolic
|
|
1038
|
+
True
|
|
1039
|
+
"""
|
|
1040
|
+
if op != op_EQ:
|
|
1041
|
+
return NotImplemented
|
|
1042
|
+
return compare_via_evaluation(left, right)
|
|
1043
|
+
|
|
1044
|
+
@cached_method
|
|
1045
|
+
def kernel_polynomial(self):
|
|
1046
|
+
r"""
|
|
1047
|
+
Return the kernel polynomial of this square-root Vélu isogeny.
|
|
1048
|
+
|
|
1049
|
+
.. NOTE::
|
|
1050
|
+
|
|
1051
|
+
The data returned by this method has size linear in the degree.
|
|
1052
|
+
|
|
1053
|
+
EXAMPLES::
|
|
1054
|
+
|
|
1055
|
+
sage: E = EllipticCurve(GF(65537^2,'a'), [5,5])
|
|
1056
|
+
sage: K = E.cardinality()//31 * E.gens()[0]
|
|
1057
|
+
sage: phi = E.isogeny(K, algorithm='velusqrt')
|
|
1058
|
+
sage: h = phi.kernel_polynomial(); h
|
|
1059
|
+
x^15 + 21562*x^14 + 8571*x^13 + 20029*x^12 + 1775*x^11 + 60402*x^10 + 17481*x^9 + 46543*x^8 + 46519*x^7 + 18590*x^6 + 36554*x^5 + 36499*x^4 + 48857*x^3 + 3066*x^2 + 23264*x + 53937
|
|
1060
|
+
sage: h == E.isogeny(K).kernel_polynomial()
|
|
1061
|
+
True
|
|
1062
|
+
sage: h(K.x())
|
|
1063
|
+
0
|
|
1064
|
+
|
|
1065
|
+
TESTS::
|
|
1066
|
+
|
|
1067
|
+
sage: phi.kernel_polynomial().parent()
|
|
1068
|
+
Univariate Polynomial Ring in x over Finite Field in a of size 65537^2
|
|
1069
|
+
"""
|
|
1070
|
+
R, x = self._domain.base_ring()['x'].objgen()
|
|
1071
|
+
h0 = self._h0(x)
|
|
1072
|
+
h = h0(self._pre_iso.x_rational_map())
|
|
1073
|
+
return R(h).monic()
|
|
1074
|
+
|
|
1075
|
+
@cached_method
|
|
1076
|
+
def dual(self):
|
|
1077
|
+
r"""
|
|
1078
|
+
Return the dual of this square-root Vélu
|
|
1079
|
+
isogeny as an :class:`EllipticCurveHom`.
|
|
1080
|
+
|
|
1081
|
+
.. NOTE::
|
|
1082
|
+
|
|
1083
|
+
The dual is computed by :class:`EllipticCurveIsogeny`,
|
|
1084
|
+
hence it does not benefit from the square-root Vélu speedup.
|
|
1085
|
+
|
|
1086
|
+
EXAMPLES::
|
|
1087
|
+
|
|
1088
|
+
sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1])
|
|
1089
|
+
sage: K = E.cardinality() // 11 * E.gens()[0]
|
|
1090
|
+
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
|
|
1091
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 11:
|
|
1092
|
+
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1
|
|
1093
|
+
over Finite Field in z2 of size 101^2
|
|
1094
|
+
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40
|
|
1095
|
+
over Finite Field in z2 of size 101^2
|
|
1096
|
+
sage: phi.dual()
|
|
1097
|
+
Isogeny of degree 11
|
|
1098
|
+
from Elliptic Curve defined by y^2 = x^3 + 39*x + 40
|
|
1099
|
+
over Finite Field in z2 of size 101^2
|
|
1100
|
+
to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1
|
|
1101
|
+
over Finite Field in z2 of size 101^2
|
|
1102
|
+
sage: phi.dual() * phi == phi.domain().scalar_multiplication(11) # needs sage.symbolic
|
|
1103
|
+
True
|
|
1104
|
+
sage: phi * phi.dual() == phi.codomain().scalar_multiplication(11) # needs sage.symbolic
|
|
1105
|
+
True
|
|
1106
|
+
"""
|
|
1107
|
+
# FIXME: This code fails if the degree is divisible by the characteristic.
|
|
1108
|
+
F = self._raw_domain.base_ring()
|
|
1109
|
+
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
1110
|
+
isom = ~WeierstrassIsomorphism(self._raw_domain, (~F(self._degree), 0, 0, 0))
|
|
1111
|
+
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
|
|
1112
|
+
phi = EllipticCurveIsogeny(self._raw_codomain, None, isom.domain(), self._degree)
|
|
1113
|
+
return ~self._pre_iso * isom * phi * ~self._post_iso
|
|
1114
|
+
|
|
1115
|
+
@cached_method
|
|
1116
|
+
def rational_maps(self):
|
|
1117
|
+
r"""
|
|
1118
|
+
Return the pair of explicit rational maps of this square-root Vélu isogeny
|
|
1119
|
+
as fractions of bivariate polynomials in `x` and `y`.
|
|
1120
|
+
|
|
1121
|
+
.. NOTE::
|
|
1122
|
+
|
|
1123
|
+
The data returned by this method has size linear in the degree.
|
|
1124
|
+
|
|
1125
|
+
EXAMPLES::
|
|
1126
|
+
|
|
1127
|
+
sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1])
|
|
1128
|
+
sage: K = (E.cardinality() // 11) * E.gens()[0]
|
|
1129
|
+
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
|
|
1130
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 11:
|
|
1131
|
+
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
|
|
1132
|
+
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2
|
|
1133
|
+
sage: phi.rational_maps()
|
|
1134
|
+
((-17*x^11 - 34*x^10 - 36*x^9 + ... - 29*x^2 - 25*x - 25)/(x^10 + 10*x^9 + 19*x^8 - ... + x^2 + 47*x + 24),
|
|
1135
|
+
(-3*x^16 - 6*x^15*y - 48*x^15 + ... - 49*x - 9*y + 46)/(x^15 + 15*x^14 - 35*x^13 - ... + 3*x^2 - 45*x + 47))
|
|
1136
|
+
|
|
1137
|
+
TESTS::
|
|
1138
|
+
|
|
1139
|
+
sage: phi.rational_maps()[0].parent()
|
|
1140
|
+
Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2
|
|
1141
|
+
sage: phi.rational_maps()[1].parent()
|
|
1142
|
+
Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2
|
|
1143
|
+
"""
|
|
1144
|
+
S = self._internal_base_ring['x,y']
|
|
1145
|
+
fx, fy = map(S, self._pre_iso.rational_maps())
|
|
1146
|
+
fx, fy = self._raw_eval(fx, fy)
|
|
1147
|
+
gx, gy = self._post_iso.rational_maps()
|
|
1148
|
+
fx, fy = gx(fx, fy), gy(fx, fy)
|
|
1149
|
+
R = self._domain.base_ring()['x,y'].fraction_field()
|
|
1150
|
+
return R(fx), R(fy)
|
|
1151
|
+
|
|
1152
|
+
@cached_method
|
|
1153
|
+
def x_rational_map(self):
|
|
1154
|
+
r"""
|
|
1155
|
+
Return the `x`-coordinate rational map of
|
|
1156
|
+
this square-root Vélu isogeny
|
|
1157
|
+
as a univariate rational function in `x`.
|
|
1158
|
+
|
|
1159
|
+
.. NOTE::
|
|
1160
|
+
|
|
1161
|
+
The data returned by this method has size linear in the degree.
|
|
1162
|
+
|
|
1163
|
+
EXAMPLES::
|
|
1164
|
+
|
|
1165
|
+
sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1])
|
|
1166
|
+
sage: K = (E.cardinality() // 11) * E.gens()[0]
|
|
1167
|
+
sage: phi = E.isogeny(K, algorithm='velusqrt'); phi
|
|
1168
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 11:
|
|
1169
|
+
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
|
|
1170
|
+
To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2
|
|
1171
|
+
sage: phi.x_rational_map()
|
|
1172
|
+
(84*x^11 + 67*x^10 + 65*x^9 + ... + 72*x^2 + 76*x + 76)/(x^10 + 10*x^9 + 19*x^8 + ... + x^2 + 47*x + 24)
|
|
1173
|
+
sage: phi.x_rational_map() == phi.rational_maps()[0]
|
|
1174
|
+
True
|
|
1175
|
+
|
|
1176
|
+
TESTS::
|
|
1177
|
+
|
|
1178
|
+
sage: phi.x_rational_map().parent()
|
|
1179
|
+
Fraction Field of Univariate Polynomial Ring in x over Finite Field in z2 of size 101^2
|
|
1180
|
+
"""
|
|
1181
|
+
S = self._internal_base_ring['x']
|
|
1182
|
+
fx = S(self._pre_iso.x_rational_map())
|
|
1183
|
+
fx = self._raw_eval(fx)
|
|
1184
|
+
gx = self._post_iso.x_rational_map()
|
|
1185
|
+
fx = gx(fx)
|
|
1186
|
+
R = self._domain.base_ring()['x'].fraction_field()
|
|
1187
|
+
return R(fx)
|
|
1188
|
+
|
|
1189
|
+
def scaling_factor(self):
|
|
1190
|
+
r"""
|
|
1191
|
+
Return the Weierstrass scaling factor associated to this
|
|
1192
|
+
square-root Vélu isogeny.
|
|
1193
|
+
|
|
1194
|
+
The scaling factor is the constant `u` (in the base field)
|
|
1195
|
+
such that `\varphi^* \omega_2 = u \omega_1`, where
|
|
1196
|
+
`\varphi: E_1\to E_2` is this isogeny and `\omega_i` are
|
|
1197
|
+
the standard Weierstrass differentials on `E_i` defined by
|
|
1198
|
+
`\mathrm dx/(2y+a_1x+a_3)`.
|
|
1199
|
+
|
|
1200
|
+
EXAMPLES::
|
|
1201
|
+
|
|
1202
|
+
sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1])
|
|
1203
|
+
sage: K = (E.cardinality() // 11) * E.gens()[0]
|
|
1204
|
+
sage: phi = E.isogeny(K, algorithm='velusqrt', model='montgomery'); phi
|
|
1205
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 11:
|
|
1206
|
+
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2
|
|
1207
|
+
To: Elliptic Curve defined by y^2 = x^3 + 61*x^2 + x over Finite Field in z2 of size 101^2
|
|
1208
|
+
sage: phi.scaling_factor()
|
|
1209
|
+
55
|
|
1210
|
+
sage: phi.scaling_factor() == phi.formal()[1]
|
|
1211
|
+
True
|
|
1212
|
+
"""
|
|
1213
|
+
return self._pre_iso.scaling_factor() * self._post_iso.scaling_factor()
|
|
1214
|
+
|
|
1215
|
+
def inseparable_degree(self):
|
|
1216
|
+
r"""
|
|
1217
|
+
Return the inseparable degree of this square-root Vélu
|
|
1218
|
+
isogeny.
|
|
1219
|
+
|
|
1220
|
+
Since :class:`EllipticCurveHom_velusqrt` only implements
|
|
1221
|
+
separable isogenies, this method always returns one.
|
|
1222
|
+
|
|
1223
|
+
TESTS::
|
|
1224
|
+
|
|
1225
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
1226
|
+
sage: EllipticCurveHom_velusqrt.inseparable_degree(None)
|
|
1227
|
+
1
|
|
1228
|
+
"""
|
|
1229
|
+
return Integer(1)
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
def _random_example_for_testing():
|
|
1233
|
+
r"""
|
|
1234
|
+
Function to generate somewhat random valid Vélu inputs
|
|
1235
|
+
for testing purposes.
|
|
1236
|
+
|
|
1237
|
+
EXAMPLES::
|
|
1238
|
+
|
|
1239
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing
|
|
1240
|
+
sage: E, K = _random_example_for_testing()
|
|
1241
|
+
sage: E # random
|
|
1242
|
+
Elliptic Curve defined by y^2 + (t^3+6*t^2)*x*y + (t^3+3*t^2+2*t+2)*y = x^3 + (6*t^3+2*t^2+t)*x^2 + (3*t^3+2*t^2+6*t+1)*x + (t^3+2*t^2+2) over Finite Field in t of size 7^4
|
|
1243
|
+
sage: E.short_weierstrass_model()
|
|
1244
|
+
Elliptic Curve defined by y^2 = x^3 + ... over Finite Field ...
|
|
1245
|
+
sage: K # random
|
|
1246
|
+
(3*t^3 + 4*t^2 + 4*t + 3 : 6*t^3 + 5*t^2 + 5*t : 1)
|
|
1247
|
+
sage: K.order() # random
|
|
1248
|
+
101
|
|
1249
|
+
sage: K in E
|
|
1250
|
+
True
|
|
1251
|
+
sage: K.order() % 2
|
|
1252
|
+
1
|
|
1253
|
+
sage: 5 <= K.order()
|
|
1254
|
+
True
|
|
1255
|
+
"""
|
|
1256
|
+
from sage.rings.fast_arith import prime_range
|
|
1257
|
+
from sage.misc.prandom import choice, randrange
|
|
1258
|
+
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
|
|
1259
|
+
from sage.arith.functions import lcm
|
|
1260
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
1261
|
+
|
|
1262
|
+
while True:
|
|
1263
|
+
p = choice(prime_range(2, 100))
|
|
1264
|
+
e = randrange(1,5)
|
|
1265
|
+
F,t = GF((p,e),'t').objgen()
|
|
1266
|
+
try:
|
|
1267
|
+
E = EllipticCurve([F.random_element() for _ in range(5)])
|
|
1268
|
+
except ArithmeticError:
|
|
1269
|
+
continue
|
|
1270
|
+
try:
|
|
1271
|
+
E.short_weierstrass_model()
|
|
1272
|
+
except ValueError:
|
|
1273
|
+
continue
|
|
1274
|
+
if E.cardinality() < 9:
|
|
1275
|
+
continue
|
|
1276
|
+
A = E.abelian_group()
|
|
1277
|
+
ds = max(A.invariants()).prime_to_m_part(2).divisors()
|
|
1278
|
+
ds = [d for d in ds if 9 <= d < 1000]
|
|
1279
|
+
if ds:
|
|
1280
|
+
deg = choice(ds)
|
|
1281
|
+
break
|
|
1282
|
+
G = A.torsion_subgroup(deg)
|
|
1283
|
+
os = G.generator_orders()
|
|
1284
|
+
while True:
|
|
1285
|
+
v = [randrange(o) for o in os]
|
|
1286
|
+
if lcm(Mod(c,o).additive_order() for c,o in zip(v,os)) == deg:
|
|
1287
|
+
break
|
|
1288
|
+
K = G(v).element()
|
|
1289
|
+
assert K.order() == deg
|
|
1290
|
+
return E, K
|