Skip to content

Commit 72b99f9

Browse files
committed
allow supplying a value of q for special_supersingular_curve()
1 parent a880b3f commit 72b99f9

File tree

1 file changed

+120
-54
lines changed

1 file changed

+120
-54
lines changed

src/sage/schemes/elliptic_curves/ell_finite_field.py

Lines changed: 120 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,10 +2565,12 @@ def is_j_supersingular(j, proof=True):
25652565
return E.trace_of_frobenius() % p == 0
25662566

25672567

2568-
def special_supersingular_curve(F, *, endomorphism=False):
2568+
def special_supersingular_curve(F, q=None, *, endomorphism=False):
25692569
r"""
2570-
Given a finite field ``F``, construct a "special" supersingular
2571-
elliptic curve `E` defined over ``F``.
2570+
Given a finite field ``F`` of characteristic `p`, and optionally
2571+
a positive integer `q` such that the Hilbert conductor of `-q`
2572+
and `-p` equals `p`, construct a "special" supersingular elliptic
2573+
curve `E` defined over ``F``.
25722574
25732575
Such a curve
25742576
@@ -2577,21 +2579,32 @@ def special_supersingular_curve(F, *, endomorphism=False):
25772579
- has group structure `E(\mathbb F_p) \cong \ZZ/(p+1)` and
25782580
`E(\mathbb F_{p^2}) \cong \ZZ/(p+1) \times \ZZ/(p+1)`;
25792581
2580-
- has an endomorphism `\vartheta` of small degree `q` that
2582+
- has an endomorphism `\vartheta` of degree `q` that
25812583
anticommutes with the `\mathbb F_p`-Frobenius on `E`.
25822584
25832585
(The significance of `\vartheta` is that any such endomorphism,
25842586
together with the `\mathbb F_p`-Frobenius, generates the endomorphism
25852587
algebra `\mathrm{End}(E) \otimes \QQ`.)
25862588
2589+
The complexity grows exponentially in `\log(q)`. Automatically
2590+
chosen values of `q` lie in `O((\log p)^2)` assuming GRH.
2591+
25872592
INPUT:
25882593
2589-
- ``F`` -- finite field `\mathbb F_{p^r}`;
2594+
- ``F`` -- finite field `\mathbb F_{p^r}`
2595+
2596+
- ``q`` -- positive integer (optional, default ``None``)
25902597
25912598
- ``endomorphism`` -- boolean (default: ``False``); when set to ``True``,
25922599
it is required that `2 \mid r`, and the function then additionally
25932600
returns `\vartheta`
25942601
2602+
.. WARNING::
2603+
2604+
Due to :issue:`38481`, calling this function with a value of `q`
2605+
larger than approximately `p/4` may currently fail. This failure
2606+
will not occur for automatically chosen values of `q`.
2607+
25952608
EXAMPLES::
25962609
25972610
sage: special_supersingular_curve(GF(1013^2), endomorphism=True)
@@ -2604,8 +2617,8 @@ def special_supersingular_curve(F, *, endomorphism=False):
26042617
Via: (u,r,s,t) = (389*z2 + 241, 0, 0, 0))
26052618
26062619
sage: special_supersingular_curve(GF(1021^2), endomorphism=True)
2607-
(Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2,
2608-
Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2 to Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2)
2620+
(Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2,
2621+
Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2 to Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2)
26092622
26102623
sage: special_supersingular_curve(GF(1031^2), endomorphism=True)
26112624
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2,
@@ -2630,6 +2643,20 @@ def special_supersingular_curve(F, *, endomorphism=False):
26302643
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2
26312644
Via: (u,r,s,t) = (922*z2 + 129, 0, 0, 0))
26322645
2646+
We can also supply a suitable value of `q` ourselves::
2647+
2648+
sage: special_supersingular_curve(GF(1019), q=99)
2649+
Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field of size 1019
2650+
2651+
sage: special_supersingular_curve(GF(1019^2), q=99, endomorphism=True)
2652+
(Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2,
2653+
Isogeny of degree 99 from Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2 to Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2)
2654+
2655+
sage: special_supersingular_curve(GF(1013), q=99)
2656+
Traceback (most recent call last):
2657+
...
2658+
ValueError: invalid choice of q
2659+
26332660
TESTS::
26342661
26352662
sage: p = random_prime(1000)
@@ -2678,6 +2705,35 @@ def special_supersingular_curve(F, *, endomorphism=False):
26782705
sage: pi * endo == -endo * pi
26792706
True
26802707
2708+
Also try it when `q` is given:
2709+
2710+
sage: p = random_prime(300, lbound=10)
2711+
sage: k = ZZ(randrange(1, 5))
2712+
sage: while True:
2713+
....: q = randrange(1, p//4) # upper bound p//4 is a workaround for #38481
2714+
....: if QuaternionAlgebra(-q, -p).discriminant() == p:
2715+
....: break
2716+
sage: E = special_supersingular_curve(GF((p, k)), q)
2717+
sage: E.is_supersingular()
2718+
True
2719+
sage: F.<t> = GF((p, 2*k))
2720+
sage: E, endo = special_supersingular_curve(F, q, endomorphism=True)
2721+
sage: E.is_supersingular()
2722+
True
2723+
sage: E.j_invariant() in GF(p)
2724+
True
2725+
sage: endo.domain() is endo.codomain() is E
2726+
True
2727+
sage: endo.degree() == q
2728+
True
2729+
sage: endo.trace()
2730+
0
2731+
sage: pi = E.frobenius_isogeny()
2732+
sage: pi.codomain() is pi.domain() is E
2733+
True
2734+
sage: pi * endo == -endo * pi
2735+
True
2736+
26812737
.. NOTE::
26822738
26832739
This function makes no guarantees about the distribution of
@@ -2694,42 +2750,49 @@ def special_supersingular_curve(F, *, endomorphism=False):
26942750
if endomorphism and deg % 2:
26952751
raise ValueError('endomorphism was requested but is not defined over given field')
26962752

2697-
E = None
2753+
if q is not None:
2754+
from sage.arith.misc import hilbert_conductor
2755+
if p.divides(q) or hilbert_conductor(-q, -p) != p:
2756+
raise ValueError('invalid choice of q')
26982757

26992758
# first find the degree q of our special endomorphism
2700-
if p == 2:
2701-
q = 3
2702-
E = EllipticCurve(F, [0,0,1,0,0])
2703-
2704-
elif p % 4 == 3:
2705-
q = 1
2706-
E = EllipticCurve(F, [1,0])
2707-
2708-
elif p % 3 == 2:
2709-
q = 3
2710-
E = EllipticCurve(F, [0,1])
2711-
2712-
elif p % 8 == 5:
2713-
q = 2
2714-
E = EllipticCurve(F, [-4320, 96768])
2715-
2716-
else:
2717-
from sage.arith.misc import legendre_symbol
2718-
for q in map(ZZ, range(3,p,4)):
2719-
if not q.is_prime():
2720-
continue
2721-
if legendre_symbol(-q, p) == -1:
2722-
break
2759+
if q is None:
2760+
if p == 2:
2761+
q = 3
2762+
elif p % 4 == 3:
2763+
q = 1
2764+
elif p % 3 == 2:
2765+
q = 3
2766+
elif p % 8 == 5:
2767+
q = 2
27232768
else:
2724-
assert False # should never happen
2769+
from sage.arith.misc import legendre_symbol
2770+
for q in map(ZZ, range(3,p,4)):
2771+
if not q.is_prime():
2772+
continue
2773+
if legendre_symbol(-q, p) == -1:
2774+
break
2775+
else: # should never happen
2776+
assert False, 'bug in special_supersingular_curve()'
2777+
q = ZZ(q)
27252778

2726-
if E is None:
2727-
from sage.arith.misc import fundamental_discriminant
2728-
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
2729-
H = hilbert_class_polynomial(fundamental_discriminant(-q))
2730-
j = H.change_ring(GF(p)).any_root()
2779+
from sage.arith.misc import fundamental_discriminant
2780+
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
2781+
H = hilbert_class_polynomial(fundamental_discriminant(-q))
2782+
j = H.change_ring(GF(p)).any_root()
2783+
if j.is_zero():
2784+
if p == 2:
2785+
ainvs = [0,0,1,0,0]
2786+
elif p == 3:
2787+
ainvs = [1,0]
2788+
else:
2789+
ainvs = [0,1]
2790+
elif j == 1728:
2791+
ainvs = [1,0]
2792+
else:
27312793
a = 27 * j / (4 * (1728-j))
2732-
E = EllipticCurve(F, [a,-a])
2794+
ainvs = [a,-a]
2795+
E = EllipticCurve(F, ainvs)
27332796

27342797
if ZZ(2).divides(deg):
27352798
k = deg//2
@@ -2740,23 +2803,26 @@ def special_supersingular_curve(F, *, endomorphism=False):
27402803
if not endomorphism:
27412804
return E
27422805

2743-
if q == 1 or p <= 13:
2744-
if q == 1:
2745-
endos = E.automorphisms()
2746-
else:
2747-
endos = (iso*phi for phi in E.isogenies_prime_degree(q)
2748-
for iso in phi.codomain().isomorphisms(E))
2749-
endo = next(endo for endo in endos if endo.trace().is_zero())
2750-
2806+
if q.is_one():
2807+
endo = next(auto for auto in E.automorphisms() if auto.trace().is_zero())
27512808
else:
2752-
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
2753-
iso = WeierstrassIsomorphism(None, (F(-q).sqrt(),0,0,0), E)
2754-
if q == 3 and E.a_invariants() == (0,0,0,0,1):
2755-
# workaround for #21883
2756-
endo = E.isogeny(E(0,1))
2757-
else:
2758-
endo = E.isogeny(None, iso.domain(), degree=q)
2759-
endo = iso * endo
2809+
iso = E.isomorphism(F(-q).sqrt(), is_codomain=True)
2810+
try:
2811+
endo = iso * E.isogeny(None, iso.domain(), degree=q)
2812+
except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481
2813+
#FIXME this code could be simplified/optimized after #37388 and/or #35949
2814+
def _isogs(E, d):
2815+
if d.is_one():
2816+
yield E.identity_morphism()
2817+
return
2818+
l = d.prime_factors()[-1]
2819+
for phi in E.isogenies_prime_degree(l):
2820+
for psi in _isogs(phi.codomain(), d//l):
2821+
yield psi * phi
2822+
endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E))
2823+
# endos = (iso*phi for phi in E.isogenies_degree(q)
2824+
# for iso in phi.codomain().isomorphisms(E))
2825+
endo = next(endo for endo in endos if endo.trace().is_zero())
27602826

27612827
endo._degree = ZZ(q)
27622828
endo.trace.set_cache(ZZ.zero())

0 commit comments

Comments
 (0)