Skip to content

Commit 6bd17e5

Browse files
committed
add optional order= argument to .log() method for PARI finite-field elements
1 parent 30b3d78 commit 6bd17e5

File tree

1 file changed

+50
-13
lines changed

1 file changed

+50
-13
lines changed

src/sage/rings/finite_rings/element_pari_ffelt.pyx

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,14 +1100,17 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
11001100
else:
11011101
raise ValueError("element is not a square")
11021102

1103-
def log(self, base):
1103+
def log(self, base, order=None, *, check=False):
11041104
"""
11051105
Return a discrete logarithm of ``self`` with respect to the
11061106
given base.
11071107
11081108
INPUT:
11091109
11101110
- ``base`` -- non-zero field element
1111+
- ``order`` -- integer (optional), the order of the base
1112+
- ``check`` -- boolean (optional, default ``False``): If set,
1113+
test whether the given ``order`` is correct.
11111114
11121115
OUTPUT:
11131116
@@ -1133,6 +1136,23 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
11331136
sage: F(1).log(a)
11341137
0
11351138
1139+
::
1140+
1141+
sage: p = 2^127-1
1142+
sage: F.<t> = GF((p, 3))
1143+
sage: elt = F.random_element()^(p^2+p+1)
1144+
sage: (elt^2).log(elt, p-1)
1145+
2
1146+
1147+
Passing the ``order`` argument can lead to huge speedups when
1148+
factoring the order of the entire unit group is expensive but
1149+
the order of the base element is much smaller::
1150+
1151+
sage: %timeit (elt^2).log(elt) # not tested
1152+
6.18 s ± 85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1153+
sage: %timeit (elt^2).log(elt, p-1) # not tested
1154+
147 ms ± 1.39 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
1155+
11361156
Some cases where the logarithm is not defined or does not exist::
11371157
11381158
sage: F.<a> = GF(3^10, impl='pari_ffelt')
@@ -1148,27 +1168,44 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
11481168
Traceback (most recent call last):
11491169
...
11501170
ArithmeticError: discrete logarithm of 0 is not defined
1171+
1172+
TESTS:
1173+
1174+
An example for ``check=True``::
1175+
1176+
sage: a = GF(101^5).primitive_element()
1177+
sage: a.log(a, 10510100500, check=True)
1178+
1
1179+
sage: a.log(a, 5255050250, check=True)
1180+
Traceback (most recent call last):
1181+
...
1182+
ValueError: element does not have the provided order
11511183
"""
11521184
base = self._parent(base)
11531185
if self.is_zero():
11541186
raise ArithmeticError("discrete logarithm of 0 is not defined")
11551187
if base.is_zero():
11561188
raise ArithmeticError("discrete logarithm with base 0 is not defined")
11571189

1158-
# Compute the orders of self and base to check whether self
1159-
# actually lies in the cyclic group generated by base. PARI
1160-
# requires that this is the case.
1161-
# We also have to specify the order of the base anyway
1162-
# because PARI assumes by default that this element generates
1163-
# the multiplicative group.
1164-
cdef GEN x, base_order, self_order
1190+
# Compute the order of the base to check whether the element actually
1191+
# lies in the group generated by the base. PARI may otherwise enter an
1192+
# infinite loop.
1193+
# We also have to specify the order of the base anyway as PARI assumes
1194+
# by default that the base generates the entire multiplicative group.
1195+
cdef GEN x, base_order
11651196
sig_on()
1166-
base_order = FF_order((<FiniteFieldElement_pari_ffelt>base).val, NULL)
1167-
self_order = FF_order(self.val, NULL)
1168-
if not dvdii(base_order, self_order):
1169-
# self_order does not divide base_order
1197+
if order is None:
1198+
base_order = FF_order((<FiniteFieldElement_pari_ffelt>base).val, NULL)
1199+
else:
1200+
if check:
1201+
from sage.groups.generic import has_order
1202+
if not has_order(base, order, '*'):
1203+
clear_stack()
1204+
raise ValueError('element does not have the provided order')
1205+
base_order = _new_GEN_from_mpz_t((<Integer>order).value)
1206+
if not gequal1(powgi(self.val, base_order)):
11701207
clear_stack()
1171-
raise ArithmeticError("element %s does not lie in group generated by %s"%(self, base))
1208+
raise ArithmeticError(f'element {self} does not lie in group generated by {base}')
11721209
x = FF_log(self.val, (<FiniteFieldElement_pari_ffelt>base).val, base_order)
11731210
return Integer(new_gen(x))
11741211

0 commit comments

Comments
 (0)