-
-
Notifications
You must be signed in to change notification settings - Fork 523
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
Fix .multiplication_by_m
when m is not coprime to characteristic (#6413)
#37096
Changes from all commits
2fe08b6
4273b70
8ab1081
6a81d72
ac0ce58
94fc871
ae5c5b1
826ec07
a9b05b4
d466ecb
bbb2786
929d0e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,7 @@ | |
# **************************************************************************** | ||
|
||
import math | ||
from sage.arith.misc import valuation | ||
|
||
import sage.rings.abc | ||
from sage.rings.finite_rings.integer_mod import mod | ||
|
@@ -66,8 +67,6 @@ | |
|
||
from sage.arith.functions import lcm | ||
from sage.rings.integer import Integer | ||
from sage.rings.big_oh import O | ||
from sage.rings.infinity import Infinity as oo | ||
from sage.rings.rational import Rational | ||
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF | ||
from sage.rings.rational_field import RationalField | ||
|
@@ -2421,15 +2420,53 @@ def multiplication_by_m(self, m, x_only=False): | |
sage: my_eval = lambda f,P: [fi(P[0],P[1]) for fi in f] | ||
sage: f = E.multiplication_by_m(2) | ||
sage: assert(E(eval(f,P)) == 2*P) | ||
|
||
The following test shows that :trac:`6413` is fixed for elliptic curves over finite fields:: | ||
sage: p = 7 | ||
sage: K.<a> = GF(p^2) | ||
sage: E = EllipticCurve(K, [a + 3, 5 - a]) | ||
sage: k = p^2 * 3 | ||
sage: f, g = E.multiplication_by_m(k) | ||
sage: for _ in range(100): | ||
....: P = E.random_point() | ||
....: if P * k == 0: | ||
....: continue | ||
....: Qx = f.subs(x=P[0]) | ||
....: Qy = g.subs(x=P[0], y=P[1]) | ||
....: assert (P * k).xy() == (Qx, Qy) | ||
|
||
However, it still fails for elliptic curves over positive-characteristic fields:: | ||
|
||
sage: F.<a> = FunctionField(GF(7)) | ||
sage: E = EllipticCurve(F, [a, 1 / a]) | ||
sage: E.multiplication_by_m(7) | ||
Traceback (most recent call last): | ||
... | ||
NotImplementedError: multiplication by integer not coprime to p is only implemented for curves over finite fields | ||
|
||
:: | ||
|
||
sage: p = 7 | ||
sage: K.<a> = GF(p^2) | ||
sage: E = EllipticCurve(K, [K.random_element(), K.random_element()]) | ||
sage: E.multiplication_by_m(p * 2)[0] == E.multiplication_by_m(p * 2, x_only=True) | ||
True | ||
""" | ||
# Coerce the input m to be an integer | ||
m = Integer(m) | ||
p = self.base_ring().characteristic() | ||
|
||
if m == 0: | ||
raise ValueError("m must be a non-zero integer") | ||
|
||
if x_only: | ||
x = polygen(self.base_ring(), 'x') | ||
else: | ||
from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic | ||
if p != 0 and m % p == 0 and not isinstance(self.base_ring(), FiniteField_generic): | ||
# TODO: Implement the correct formula? | ||
raise NotImplementedError("multiplication by integer not coprime to p " | ||
"is only implemented for curves over finite fields") | ||
x, y = polygens(self.base_ring(), 'x,y') | ||
|
||
# Special case of multiplication by 1 is easy. | ||
|
@@ -2440,30 +2477,41 @@ def multiplication_by_m(self, m, x_only=False): | |
return x | ||
|
||
# Grab curve invariants | ||
a1, a2, a3, a4, a6 = self.a_invariants() | ||
a1, _, a3, _, _ = self.a_invariants() | ||
|
||
if m == -1: | ||
if not x_only: | ||
return (x, -y-a1*x-a3) | ||
else: | ||
return x | ||
|
||
# the x-coordinate does not depend on the sign of m. The work | ||
# If we only require the x coordinate, it is faster to use the recursive formula | ||
# since substituting polynomials is quite slow. | ||
v_p = 0 if p == 0 else valuation(m, p) | ||
if not x_only: | ||
m //= p**v_p | ||
|
||
# the x-coordinate does not depend on the sign of m. The work | ||
# here is done by functions defined earlier: | ||
|
||
mx = (x.parent()(self._multiple_x_numerator(m.abs(), x)) | ||
/ x.parent()(self._multiple_x_denominator(m.abs(), x))) | ||
|
||
if x_only: | ||
# Return it if the optional parameter x_only is set. | ||
return mx | ||
|
||
# Consideration of the invariant differential | ||
# w=dx/(2*y+a1*x+a3) shows that m*w = d(mx)/(2*my+a1*mx+a3) | ||
# and hence 2*my+a1*mx+a3 = (1/m)*(2*y+a1*x+a3)*d(mx)/dx | ||
|
||
# Consideration of the invariant differential | ||
# w=dx/(2*y+a1*x+a3) shows that m*w = d(mx)/(2*my+a1*mx+a3) | ||
# and hence 2*my+a1*mx+a3 = (1/m)*(2*y+a1*x+a3)*d(mx)/dx | ||
my = ((2*y+a1*x+a3)*mx.derivative(x)/m - a1*mx-a3)/2 | ||
|
||
if v_p > 0: | ||
isog = self.multiplication_by_p_isogeny()**v_p | ||
fx, fy = isog.rational_maps() | ||
# slow... | ||
mx = mx.subs(x=fx) | ||
my = my.subs(x=fx, y=fy) | ||
|
||
return mx, my | ||
|
||
def multiplication_by_m_isogeny(self, m): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I acknowledge that we are technically "allowed" to remove this method now, but I'm wondering if it's a good idea at this point: Debian and Ubuntu are still on Sage 9.5, so most of their users have never even seen the deprecation warning. Since keeping this method in Sage a little longer is essentially free of harm, I'd suggest to do so. |
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test fails at random with probability ~ 1/49 or something like that (i.e. when the discriminant is 0).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix this in a separate PR since this is merged already. Sorry for not spotting this earlier (there's one similar above)