@@ -1100,14 +1100,17 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
1100
1100
else :
1101
1101
raise ValueError (" element is not a square" )
1102
1102
1103
- def log (self , base ):
1103
+ def log (self , base , order = None , *, check = False ):
1104
1104
"""
1105
1105
Return a discrete logarithm of ``self`` with respect to the
1106
1106
given base.
1107
1107
1108
1108
INPUT:
1109
1109
1110
1110
- ``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.
1111
1114
1112
1115
OUTPUT:
1113
1116
@@ -1133,6 +1136,23 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
1133
1136
sage: F(1).log(a)
1134
1137
0
1135
1138
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: %t imeit (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: %t imeit (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
+
1136
1156
Some cases where the logarithm is not defined or does not exist::
1137
1157
1138
1158
sage: F.<a> = GF(3^10, impl='pari_ffelt')
@@ -1148,27 +1168,44 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
1148
1168
Traceback (most recent call last):
1149
1169
...
1150
1170
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
1151
1183
"""
1152
1184
base = self ._parent(base)
1153
1185
if self .is_zero():
1154
1186
raise ArithmeticError (" discrete logarithm of 0 is not defined" )
1155
1187
if base.is_zero():
1156
1188
raise ArithmeticError (" discrete logarithm with base 0 is not defined" )
1157
1189
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
1165
1196
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)):
1170
1207
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} ' )
1172
1209
x = FF_log(self .val, (< FiniteFieldElement_pari_ffelt> base).val, base_order)
1173
1210
return Integer(new_gen(x))
1174
1211
0 commit comments