Skip to content

Commit d2257c1

Browse files
committed
allow supplying a value of q for special_supersingular_curve()
1 parent 0f34773 commit d2257c1

File tree

1 file changed

+121
-55
lines changed

1 file changed

+121
-55
lines changed

src/sage/schemes/elliptic_curves/ell_finite_field.py

Lines changed: 121 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,10 +2465,12 @@ def is_j_supersingular(j, proof=True):
24652465

24662466
return E.trace_of_frobenius() % p == 0
24672467

2468-
def special_supersingular_curve(F, *, endomorphism=False):
2468+
def special_supersingular_curve(F, q=None, *, endomorphism=False):
24692469
r"""
2470-
Given a finite field ``F``, construct a "special" supersingular
2471-
elliptic curve `E` defined over ``F``.
2470+
Given a finite field ``F`` of characteristic `p`, and optionally
2471+
a positive integer `q` such that the Hilbert conductor of `-q`
2472+
and `-p` equals `p`, construct a "special" supersingular elliptic
2473+
curve `E` defined over ``F``.
24722474
24732475
Such a curve
24742476
@@ -2477,21 +2479,32 @@ def special_supersingular_curve(F, *, endomorphism=False):
24772479
- has group structure `E(\mathbb F_p) \cong \ZZ/(p+1)` and
24782480
`E(\mathbb F_{p^2}) \cong \ZZ/(p+1) \times \ZZ/(p+1)`;
24792481
2480-
- has an endomorphism `\vartheta` of small degree `q` that
2482+
- has an endomorphism `\vartheta` of degree `q` that
24812483
anticommutes with the `\mathbb F_p`-Frobenius on `E`.
24822484
24832485
(The significance of `\vartheta` is that any such endomorphism,
24842486
together with the `\mathbb F_p`-Frobenius, generates the endomorphism
24852487
algebra `\mathrm{End}(E) \otimes \QQ`.)
24862488
2489+
The complexity grows exponentially in `\log(q)`. Automatically
2490+
chosen values of `q` lie in `O((\log p)^2)` assuming GRH.
2491+
24872492
INPUT:
24882493
2489-
- ``F`` -- finite field `\mathbb F_{p^r}`;
2494+
- ``F`` -- finite field `\mathbb F_{p^r}`
2495+
2496+
- ``q`` -- positive integer (optional, default ``None``)
24902497
24912498
- ``endomorphism`` -- boolean (default: ``False``); when set to ``True``,
24922499
it is required that `2 \mid r`, and the function then additionally
24932500
returns `\vartheta`
24942501
2502+
.. WARNING::
2503+
2504+
Due to :issue:`38381`, calling this function with a value of `q`
2505+
larger than approximately `p/4` may currently fail. This failure
2506+
will not occur for automatically chosen values of `q`.
2507+
24952508
EXAMPLES::
24962509
24972510
sage: special_supersingular_curve(GF(1013^2), endomorphism=True)
@@ -2504,8 +2517,8 @@ def special_supersingular_curve(F, *, endomorphism=False):
25042517
Via: (u,r,s,t) = (389*z2 + 241, 0, 0, 0))
25052518
25062519
sage: special_supersingular_curve(GF(1021^2), endomorphism=True)
2507-
(Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2,
2508-
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)
2520+
(Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2,
2521+
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)
25092522
25102523
sage: special_supersingular_curve(GF(1031^2), endomorphism=True)
25112524
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2,
@@ -2530,6 +2543,20 @@ def special_supersingular_curve(F, *, endomorphism=False):
25302543
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2
25312544
Via: (u,r,s,t) = (922*z2 + 129, 0, 0, 0))
25322545
2546+
We can also supply a suitable value of `q` ourselves::
2547+
2548+
sage: special_supersingular_curve(GF(1019), q=99)
2549+
Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field of size 1019
2550+
2551+
sage: special_supersingular_curve(GF(1019^2), q=99, endomorphism=True)
2552+
(Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2,
2553+
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)
2554+
2555+
sage: special_supersingular_curve(GF(1013), q=99)
2556+
Traceback (most recent call last):
2557+
...
2558+
ValueError: invalid choice of q
2559+
25332560
TESTS::
25342561
25352562
sage: p = random_prime(1000)
@@ -2578,6 +2605,35 @@ def special_supersingular_curve(F, *, endomorphism=False):
25782605
sage: pi * endo == -endo * pi
25792606
True
25802607
2608+
Also try it when `q` is given:
2609+
2610+
sage: p = random_prime(300, lbound=10)
2611+
sage: k = ZZ(randrange(1, 5))
2612+
sage: while True:
2613+
....: q = randrange(1, p//4) # upper bound p//4 is a workaround for #38481
2614+
....: if QuaternionAlgebra(-q, -p).discriminant() == p:
2615+
....: break
2616+
sage: E = special_supersingular_curve(GF((p, k)), q)
2617+
sage: E.is_supersingular()
2618+
True
2619+
sage: F.<t> = GF((p, 2*k))
2620+
sage: E, endo = special_supersingular_curve(F, q, endomorphism=True)
2621+
sage: E.is_supersingular()
2622+
True
2623+
sage: E.j_invariant() in GF(p)
2624+
True
2625+
sage: endo.domain() is endo.codomain() is E
2626+
True
2627+
sage: endo.degree() == q
2628+
True
2629+
sage: endo.trace()
2630+
0
2631+
sage: pi = E.frobenius_isogeny()
2632+
sage: pi.codomain() is pi.domain() is E
2633+
True
2634+
sage: pi * endo == -endo * pi
2635+
True
2636+
25812637
.. NOTE::
25822638
25832639
This function makes no guarantees about the distribution of
@@ -2594,42 +2650,49 @@ def special_supersingular_curve(F, *, endomorphism=False):
25942650
if endomorphism and deg % 2:
25952651
raise ValueError('endomorphism was requested but is not defined over given field')
25962652

2597-
E = None
2653+
if q is not None:
2654+
from sage.arith.misc import hilbert_conductor
2655+
if p.divides(q) or hilbert_conductor(-q, -p) != p:
2656+
raise ValueError('invalid choice of q')
25982657

25992658
# first find the degree q of our special endomorphism
2600-
if p == 2:
2601-
q = 3
2602-
E = EllipticCurve(F, [0,0,1,0,0])
2603-
2604-
elif p % 4 == 3:
2605-
q = 1
2606-
E = EllipticCurve(F, [1,0])
2607-
2608-
elif p % 3 == 2:
2609-
q = 3
2610-
E = EllipticCurve(F, [0,1])
2611-
2612-
elif p % 8 == 5:
2613-
q = 2
2614-
E = EllipticCurve(F, [-4320, 96768])
2615-
2616-
else:
2617-
from sage.arith.misc import legendre_symbol
2618-
for q in map(ZZ, range(3,p,4)):
2619-
if not q.is_prime():
2620-
continue
2621-
if legendre_symbol(-q, p) == -1:
2622-
break
2659+
if q is None:
2660+
if p == 2:
2661+
q = 3
2662+
elif p % 4 == 3:
2663+
q = 1
2664+
elif p % 3 == 2:
2665+
q = 3
2666+
elif p % 8 == 5:
2667+
q = 2
26232668
else:
2624-
assert False # should never happen
2625-
2626-
if E is None:
2627-
from sage.arith.misc import fundamental_discriminant
2628-
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
2629-
H = hilbert_class_polynomial(fundamental_discriminant(-q))
2630-
j = H.change_ring(GF(p)).any_root()
2669+
from sage.arith.misc import legendre_symbol
2670+
for q in map(ZZ, range(3,p,4)):
2671+
if not q.is_prime():
2672+
continue
2673+
if legendre_symbol(-q, p) == -1:
2674+
break
2675+
else: # should never happen
2676+
assert False, 'bug in special_supersingular_curve()'
2677+
q = ZZ(q)
2678+
2679+
from sage.arith.misc import fundamental_discriminant
2680+
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
2681+
H = hilbert_class_polynomial(fundamental_discriminant(-q))
2682+
j = H.change_ring(GF(p)).any_root()
2683+
if j.is_zero():
2684+
if p == 2:
2685+
ainvs = [0,0,1,0,0]
2686+
elif p == 3:
2687+
ainvs = [1,0]
2688+
else:
2689+
ainvs = [0,1]
2690+
elif j == 1728:
2691+
ainvs = [1,0]
2692+
else:
26312693
a = 27 * j / (4 * (1728-j))
2632-
E = EllipticCurve(F, [a,-a])
2694+
ainvs = [a,-a]
2695+
E = EllipticCurve(F, ainvs)
26332696

26342697
if ZZ(2).divides(deg):
26352698
k = deg//2
@@ -2640,23 +2703,26 @@ def special_supersingular_curve(F, *, endomorphism=False):
26402703
if not endomorphism:
26412704
return E
26422705

2643-
if q == 1 or p <= 13:
2644-
if q == 1:
2645-
endos = E.automorphisms()
2646-
else:
2647-
endos = (iso*phi for phi in E.isogenies_prime_degree(q)
2648-
for iso in phi.codomain().isomorphisms(E))
2649-
endo = next(endo for endo in endos if endo.trace().is_zero())
2650-
2706+
if q.is_one():
2707+
endo = next(auto for auto in E.automorphisms() if auto.trace().is_zero())
26512708
else:
2652-
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
2653-
iso = WeierstrassIsomorphism(None, (F(-q).sqrt(),0,0,0), E)
2654-
if q == 3 and E.a_invariants() == (0,0,0,0,1):
2655-
# workaround for #21883
2656-
endo = E.isogeny(E(0,1))
2657-
else:
2658-
endo = E.isogeny(None, iso.domain(), degree=q)
2659-
endo = iso * endo
2709+
iso = E.isomorphism(F(-q).sqrt(), is_codomain=True)
2710+
try:
2711+
endo = iso * E.isogeny(None, iso.domain(), degree=q)
2712+
except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481
2713+
#FIXME this code could be simplified/optimized after #37388 and/or #35949
2714+
def _isogs(E, d):
2715+
if d.is_one():
2716+
yield E.identity_morphism()
2717+
return
2718+
l = d.prime_factors()[-1]
2719+
for phi in E.isogenies_prime_degree(l):
2720+
for psi in _isogs(phi.codomain(), d//l):
2721+
yield psi * phi
2722+
endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E))
2723+
# endos = (iso*phi for phi in E.isogenies_degree(q)
2724+
# for iso in phi.codomain().isomorphisms(E))
2725+
endo = next(endo for endo in endos if endo.trace().is_zero())
26602726

26612727
endo._degree = ZZ(q)
26622728
endo.trace.set_cache(ZZ.zero())

0 commit comments

Comments
 (0)