Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow supplying a value of q for special_supersingular_curve() #38483

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 120 additions & 54 deletions src/sage/schemes/elliptic_curves/ell_finite_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2565,10 +2565,12 @@
return E.trace_of_frobenius() % p == 0


def special_supersingular_curve(F, *, endomorphism=False):
def special_supersingular_curve(F, q=None, *, endomorphism=False):
r"""
Given a finite field ``F``, construct a "special" supersingular
elliptic curve `E` defined over ``F``.
Given a finite field ``F`` of characteristic `p`, and optionally
a positive integer `q` such that the Hilbert conductor of `-q`
and `-p` equals `p`, construct a "special" supersingular elliptic
curve `E` defined over ``F``.

Such a curve

Expand All @@ -2577,21 +2579,32 @@
- has group structure `E(\mathbb F_p) \cong \ZZ/(p+1)` and
`E(\mathbb F_{p^2}) \cong \ZZ/(p+1) \times \ZZ/(p+1)`;

- has an endomorphism `\vartheta` of small degree `q` that
- has an endomorphism `\vartheta` of degree `q` that
anticommutes with the `\mathbb F_p`-Frobenius on `E`.

(The significance of `\vartheta` is that any such endomorphism,
together with the `\mathbb F_p`-Frobenius, generates the endomorphism
algebra `\mathrm{End}(E) \otimes \QQ`.)

The complexity grows exponentially in `\log(q)`. Automatically
chosen values of `q` lie in `O((\log p)^2)` assuming GRH.

INPUT:

- ``F`` -- finite field `\mathbb F_{p^r}`;
- ``F`` -- finite field `\mathbb F_{p^r}`

- ``q`` -- positive integer (optional, default ``None``)

- ``endomorphism`` -- boolean (default: ``False``); when set to ``True``,
it is required that `2 \mid r`, and the function then additionally
returns `\vartheta`

.. WARNING::

Due to :issue:`38481`, calling this function with a value of `q`
larger than approximately `p/4` may currently fail. This failure
will not occur for automatically chosen values of `q`.

EXAMPLES::

sage: special_supersingular_curve(GF(1013^2), endomorphism=True)
Expand All @@ -2604,8 +2617,8 @@
Via: (u,r,s,t) = (389*z2 + 241, 0, 0, 0))

sage: special_supersingular_curve(GF(1021^2), endomorphism=True)
(Elliptic Curve defined by y^2 = x^3 + 785*x + 794 over Finite Field in z2 of size 1021^2,
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)
(Elliptic Curve defined by y^2 = x^3 + 791*x + 230 over Finite Field in z2 of size 1021^2,
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)

sage: special_supersingular_curve(GF(1031^2), endomorphism=True)
(Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1031^2,
Expand All @@ -2630,6 +2643,20 @@
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 1051^2
Via: (u,r,s,t) = (922*z2 + 129, 0, 0, 0))

We can also supply a suitable value of `q` ourselves::

sage: special_supersingular_curve(GF(1019), q=99)
Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field of size 1019

sage: special_supersingular_curve(GF(1019^2), q=99, endomorphism=True)
(Elliptic Curve defined by y^2 = x^3 + 211*x + 808 over Finite Field in z2 of size 1019^2,
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)

sage: special_supersingular_curve(GF(1013), q=99)
Traceback (most recent call last):
...
ValueError: invalid choice of q

TESTS::

sage: p = random_prime(1000)
Expand Down Expand Up @@ -2678,6 +2705,35 @@
sage: pi * endo == -endo * pi
True

Also try it when `q` is given:

sage: p = random_prime(300, lbound=10)
sage: k = ZZ(randrange(1, 5))
sage: while True:
....: q = randrange(1, p//4) # upper bound p//4 is a workaround for #38481
....: if QuaternionAlgebra(-q, -p).discriminant() == p:
....: break
sage: E = special_supersingular_curve(GF((p, k)), q)
sage: E.is_supersingular()
True
sage: F.<t> = GF((p, 2*k))
sage: E, endo = special_supersingular_curve(F, q, endomorphism=True)
sage: E.is_supersingular()
True
sage: E.j_invariant() in GF(p)
True
sage: endo.domain() is endo.codomain() is E
True
sage: endo.degree() == q
True
sage: endo.trace()
0
sage: pi = E.frobenius_isogeny()
sage: pi.codomain() is pi.domain() is E
True
sage: pi * endo == -endo * pi
True

.. NOTE::

This function makes no guarantees about the distribution of
Expand All @@ -2694,42 +2750,49 @@
if endomorphism and deg % 2:
raise ValueError('endomorphism was requested but is not defined over given field')

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

# first find the degree q of our special endomorphism
if p == 2:
q = 3
E = EllipticCurve(F, [0,0,1,0,0])

elif p % 4 == 3:
q = 1
E = EllipticCurve(F, [1,0])

elif p % 3 == 2:
q = 3
E = EllipticCurve(F, [0,1])

elif p % 8 == 5:
q = 2
E = EllipticCurve(F, [-4320, 96768])

else:
from sage.arith.misc import legendre_symbol
for q in map(ZZ, range(3,p,4)):
if not q.is_prime():
continue
if legendre_symbol(-q, p) == -1:
break
if q is None:
if p == 2:
q = 3

Check warning on line 2761 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2761

Added line #L2761 was not covered by tests
elif p % 4 == 3:
q = 1
elif p % 3 == 2:
q = 3
elif p % 8 == 5:
q = 2
else:
assert False # should never happen
from sage.arith.misc import legendre_symbol
for q in map(ZZ, range(3,p,4)):
if not q.is_prime():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it work just iterating through primes() here instead of checking primality?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think primes() supports the "step" argument (4). What could work is iterating through the primes and skipping the ones that aren't congruent to 3 modulo 4, but it's the same amount of code, and this part should be negligible in terms of computation anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah my thinking was it's maybe faster to ask for the primes and check if it's the right congruence versus ensuring the right congruence and checking primality, but i agree that the majority of CPU time is not spent here (hence the positive review either way :) )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review!

continue

Check warning on line 2772 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2772

Added line #L2772 was not covered by tests
if legendre_symbol(-q, p) == -1:
break
else: # should never happen
assert False, 'bug in special_supersingular_curve()'

Check warning on line 2776 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2776

Added line #L2776 was not covered by tests
q = ZZ(q)

if E is None:
from sage.arith.misc import fundamental_discriminant
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
H = hilbert_class_polynomial(fundamental_discriminant(-q))
j = H.change_ring(GF(p)).any_root()
from sage.arith.misc import fundamental_discriminant
from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial
H = hilbert_class_polynomial(fundamental_discriminant(-q))
j = H.change_ring(GF(p)).any_root()
if j.is_zero():
if p == 2:
ainvs = [0,0,1,0,0]

Check warning on line 2785 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2785

Added line #L2785 was not covered by tests
elif p == 3:
ainvs = [1,0]

Check warning on line 2787 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2787

Added line #L2787 was not covered by tests
else:
ainvs = [0,1]
elif j == 1728:
ainvs = [1,0]
else:
a = 27 * j / (4 * (1728-j))
E = EllipticCurve(F, [a,-a])
ainvs = [a,-a]
E = EllipticCurve(F, ainvs)

if ZZ(2).divides(deg):
k = deg//2
Expand All @@ -2740,23 +2803,26 @@
if not endomorphism:
return E

if q == 1 or p <= 13:
if q == 1:
endos = E.automorphisms()
else:
endos = (iso*phi for phi in E.isogenies_prime_degree(q)
for iso in phi.codomain().isomorphisms(E))
endo = next(endo for endo in endos if endo.trace().is_zero())

if q.is_one():
endo = next(auto for auto in E.automorphisms() if auto.trace().is_zero())
else:
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
iso = WeierstrassIsomorphism(None, (F(-q).sqrt(),0,0,0), E)
if q == 3 and E.a_invariants() == (0,0,0,0,1):
# workaround for #21883
endo = E.isogeny(E(0,1))
else:
endo = E.isogeny(None, iso.domain(), degree=q)
endo = iso * endo
iso = E.isomorphism(F(-q).sqrt(), is_codomain=True)
try:
endo = iso * E.isogeny(None, iso.domain(), degree=q)
except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481
#FIXME this code could be simplified/optimized after #37388 and/or #35949
def _isogs(E, d):
if d.is_one():
yield E.identity_morphism()
return

Check warning on line 2817 in src/sage/schemes/elliptic_curves/ell_finite_field.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/ell_finite_field.py#L2817

Added line #L2817 was not covered by tests
l = d.prime_factors()[-1]
for phi in E.isogenies_prime_degree(l):
for psi in _isogs(phi.codomain(), d//l):
yield psi * phi
endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E))
# endos = (iso*phi for phi in E.isogenies_degree(q)
# for iso in phi.codomain().isomorphisms(E))
endo = next(endo for endo in endos if endo.trace().is_zero())

endo._degree = ZZ(q)
endo.trace.set_cache(ZZ.zero())
Expand Down
Loading