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

Implemented error when incorrect bounds cause discrete_log to give incorrect answer #39484

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
25 changes: 21 additions & 4 deletions src/sage/groups/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No
raise ValueError("Pollard rho algorithm failed to find a logarithm")


def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, algorithm='bsgs'):
def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, algorithm='bsgs', *, verify=True):
r"""
Totally generic discrete log function.

Expand All @@ -702,6 +702,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i
- ``op`` -- function of 2 arguments ``x``, ``y``, returning ``x*y`` in the group
- ``algorithm`` -- string denoting what algorithm to use for prime-order
logarithms: ``'bsgs'``, ``'rho'``, ``'lambda'``
- ``verify`` -- boolean (default: ``True``); whether to verify that output is
correct before returning it.

``a`` and ``base`` must be elements of some group with identity
given by ``identity``, inverse of ``x`` by ``inverse(x)``, and group
Expand Down Expand Up @@ -784,7 +786,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i
sage: discrete_log(eta,eps,bounds=(0,100)) # needs sage.rings.number_field
Traceback (most recent call last):
...
ValueError: no discrete log of -11515*a - 55224 found to base 5*a - 24
ValueError: no discrete log of -11515*a - 55224 found to base 5*a - 24 with bounds (0, 100)

But we can invert the base (and negate the result) instead::

Expand Down Expand Up @@ -888,6 +890,16 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i
....: else:
....: assert res == sol

Verify that :issue:`38316` is fixed::

sage: F = GF(5)
sage: base = F(3)
sage: a = F(1)
sage: discrete_log(a, base, bounds=(1,2), operation="*")
Traceback (most recent call last):
...
ValueError: no discrete log of 1 found to base 3 with bounds (1, 2)

AUTHORS:

- William Stein and David Joyner (2005-01-05)
Expand All @@ -897,6 +909,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i
from operator import mul, add, pow
power = mul if operation in addition_names else pow
mult = add if operation in addition_names else mul
original_a = a # Store the original value of a so we can verify the answer
if op:
mult = op
power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op)
Expand Down Expand Up @@ -963,9 +976,13 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i
break # we have log%running_mod. if we know that log<running_mod, then we have the value of log.
l = l[:i + 1]
from sage.arith.misc import CRT_list
return (CRT_list(l, mods) + offset) % ord
result = (CRT_list(l, mods) + offset) % ord
if (verify and power(base, result) != original_a):
raise ValueError
return result
except ValueError:
raise ValueError("no discrete log of %s found to base %s" % (a, base))
with_bounds = f" with bounds {bounds}" if bounds else ""
raise ValueError(f"no discrete log of {original_a} found to base {base}{with_bounds}")


def discrete_log_generic(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, algorithm='bsgs'):
Expand Down
Loading