Skip to content

Commit 62562c3

Browse files
author
Release Manager
committed
sagemathgh-36994: Use PARI when computing the Tate pairing To match `weil_pairing()` this pull request now uses PARI to compute the non-reduced Tate pairing for elliptic curves over finite fields. This has been included for efficiency, with PARI offering a significant performance speed up: ```py sage: GF(65537^2).inject_variables() Defining z2 sage: E = EllipticCurve(GF(65537^2), [0,1]) sage: P = E(22, 28891) sage: Q = E.random_point() sage: # Old timing sage: %timeit P.tate_pairing(Q, 7282, 2) 1.4 ms ± 66 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) sage: # New timing sage: %timeit P.tate_pairing(Q, 7282, 2) 50.8 µs ± 674 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each) ``` ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> <!-- Feel free to remove irrelevant items. --> - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation accordingly. URL: sagemath#36994 Reported by: Giacomo Pope Reviewer(s): John Cremona
2 parents 6eec3fe + d118f1c commit 62562c3

File tree

1 file changed

+58
-23
lines changed

1 file changed

+58
-23
lines changed

src/sage/schemes/elliptic_curves/ell_point.py

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
from sage.rings.integer import Integer
131131
from sage.rings.integer_ring import ZZ
132132
from sage.rings.rational_field import QQ
133+
from sage.rings.finite_rings.integer_mod import Mod
133134
from sage.rings.real_mpfr import RealField
134135
from sage.rings.real_mpfr import RR
135136
import sage.groups.generic as generic
@@ -2013,18 +2014,52 @@ def tate_pairing(self, Q, n, k, q=None):
20132014
sage: Px.weil_pairing(Qx, 41)^e == num/den
20142015
True
20152016
2016-
.. NOTE::
2017+
TESTS:
2018+
2019+
Check that the PARI output matches the original Sage implementation::
2020+
2021+
sage: # needs sage.rings.finite_rings
2022+
sage: GF(65537^2).inject_variables()
2023+
Defining z2
2024+
sage: E = EllipticCurve(GF(65537^2), [0,1])
2025+
sage: P = E(22, 28891)
2026+
sage: Q = E(-93, 40438*z2 + 31573)
2027+
sage: P.tate_pairing(Q, 7282, 2)
2028+
34585*z2 + 4063
2029+
2030+
The point ``P (self)`` must have ``n`` torsion::
2031+
2032+
sage: P.tate_pairing(Q, 163, 2)
2033+
Traceback (most recent call last):
2034+
...
2035+
ValueError: The point P must be n-torsion
2036+
2037+
We must have that ``n`` divides ``q^k - 1``, this is only checked when q is supplied::
20172038
2018-
This function uses Miller's algorithm, followed by a naive
2019-
exponentiation. It does not do anything fancy. In the case
2020-
that there is an issue with `Q` being on one of the lines
2021-
generated in the `r*P` calculation, `Q` is offset by a random
2022-
point `R` and ``P.tate_pairing(Q+R,n,k)/P.tate_pairing(R,n,k)``
2023-
is returned.
2039+
sage: P.tate_pairing(Q, 7282, 2, q=123)
2040+
Traceback (most recent call last):
2041+
...
2042+
ValueError: n does not divide (q^k - 1) for the supplied value of q
2043+
2044+
The Tate pairing is only defined for points on curves defined over finite fields::
2045+
2046+
sage: E = EllipticCurve([0,1])
2047+
sage: P = E(2,3)
2048+
sage: P.tate_pairing(P, 6, 1)
2049+
Traceback (most recent call last):
2050+
...
2051+
NotImplementedError: Reduced Tate pairing is currently only implemented for finite fields
2052+
2053+
ALGORITHM:
2054+
2055+
- :pari:`elltatepairing` computes the
2056+
non-reduced tate pairing and the exponentiation is handled by
2057+
Sage using user input for `k` (and optionally `q`).
20242058
20252059
AUTHORS:
20262060
20272061
- Mariah Lenox (2011-03-07)
2062+
- Giacomo Pope (2024): Use of PARI for the non-reduced Tate pairing
20282063
"""
20292064
P = self
20302065
E = P.curve()
@@ -2033,6 +2068,9 @@ def tate_pairing(self, Q, n, k, q=None):
20332068
raise ValueError("Points must both be on the same curve")
20342069

20352070
K = E.base_ring()
2071+
if not K.is_finite():
2072+
raise NotImplementedError("Reduced Tate pairing is currently only implemented for finite fields")
2073+
20362074
d = K.degree()
20372075
if q is None:
20382076
if d == 1:
@@ -2041,22 +2079,19 @@ def tate_pairing(self, Q, n, k, q=None):
20412079
q = K.base_ring().order()
20422080
else:
20432081
raise ValueError("Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^%s))." % k)
2044-
2045-
if n*P != E(0):
2046-
raise ValueError('This point is not of order n=%s' % n)
2047-
2048-
# In small cases, or in the case of pairing an element with
2049-
# itself, Q could be on one of the lines in the Miller
2050-
# algorithm. If this happens we try again, with an offset of a
2051-
# random point.
2052-
try:
2053-
ret = self._miller_(Q, n)
2054-
e = Integer((q**k - 1)/n)
2055-
ret = ret**e
2056-
except (ZeroDivisionError, ValueError):
2057-
R = E.random_point()
2058-
ret = self.tate_pairing(Q + R, n, k)/self.tate_pairing(R, n, k)
2059-
return ret
2082+
# The user has supplied q, so we check here that it's a sensible value
2083+
elif Mod(q, n)**k != 1:
2084+
raise ValueError("n does not divide (q^k - 1) for the supplied value of q")
2085+
2086+
if pari.ellmul(E, P, n) != [0]:
2087+
raise ValueError("The point P must be n-torsion")
2088+
2089+
# NOTE: Pari returns the non-reduced Tate pairing, so we
2090+
# must perform the exponentation ourselves using the supplied
2091+
# k value
2092+
ePQ = pari.elltatepairing(E, P, Q, n)
2093+
exp = Integer((q**k - 1)/n)
2094+
return K(ePQ**exp) # Cast the PARI type back to the base ring
20602095

20612096
def ate_pairing(self, Q, n, k, t, q=None):
20622097
r"""

0 commit comments

Comments
 (0)