예제 #1
0
def det_from_modp_and_divisor(A,
                              d,
                              p,
                              z_mod,
                              moduli,
                              z_so_far=ZZ(1),
                              N_so_far=ZZ(1)):
    """
    This is used for internal purposes for computing determinants
    quickly (with the hybrid p-adic / multimodular algorithm).

    INPUT:

    - A -- a square matrix
    - d -- a divisor of the determinant of A
    - p -- a prime
    - z_mod -- values of det/d (mod ...)
    - moduli -- the moduli so far
    - z_so_far -- for a modulus p in the list moduli,
      (z_so_far mod p) is the determinant of A modulo p.
    - N_so_far -- N_so_far is the product over the primes in the list moduli.

    OUTPUT:

    - A triple (det bound, new z_so_far, new N_so_far).

    EXAMPLES::

        sage: a = matrix(ZZ, 3, [6, 1, 2, -56, -2, -1, -11, 2, -3])
        sage: factor(a.det())
        -1 * 13 * 29
        sage: d = 13
        sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf
        sage: matrix_integer_dense_hnf.det_from_modp_and_divisor(a, d, 97, [], [])
        (-377, -29, 97)
        sage: a.det()
        -377
    """
    tm = verbose("Multimodular stage of det calculation -- using p = %s" % p,
                 level=2)
    z = A.mod(p).det() / d
    z = z.lift()
    z_mod.append(z)
    moduli.append(p)
    z = CRT_list([z_so_far, z], [N_so_far, p])
    N = N_so_far * p

    if z > N // 2:
        z -= N
    verbose("Finished multimodular det for p = %s" % p, tm, level=2)
    return (d * z, z, N)
예제 #2
0
def discrete_log(a,
                 base,
                 ord=None,
                 bounds=None,
                 operation='*',
                 identity=None,
                 inverse=None,
                 op=None):
    r"""
    Totally generic discrete log function.

    INPUT:

    - ``a``    - group element
    - ``base`` - group element (the base)
    - ``ord``  - integer (multiple of order of base, or ``None``)
    - ``bounds`` - a priori bounds on the log
    - ``operation`` - string: '*', '+', 'other'
    - ``identity`` - the group's identity
    - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x``
    - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group

    ``a`` and ``base`` must be elements of some group with identity
    given by identity, inverse of ``x`` by ``inverse(x)``, and group
    operation on ``x``, ``y`` by ``op(x,y)``.

    If operation is '*' or '+' then the other
    arguments are provided automatically; otherwise they must be
    provided by the caller.

    OUTPUT: Returns an integer `n` such that `b^n = a` (or `nb = a`),
    assuming that ``ord`` is a multiple of the order of the base `b`.
    If ``ord`` is not specified, an attempt is made to compute it.

    If no such `n` exists, this function raises a ValueError exception.

    .. warning::

       If ``x`` has a log method, it is likely to be vastly faster
       than using this function.  E.g., if ``x`` is an integer modulo
       `n`, use its log method instead!

    ALGORITHM: Pohlig-Hellman and Baby step giant step.

    EXAMPLES::

        sage: b = Mod(2,37);  a = b^20
        sage: discrete_log(a, b)
        20
        sage: b = Mod(2,997);  a = b^20
        sage: discrete_log(a, b)
        20

        sage: K = GF(3^6,'b')
        sage: b = K.gen()
        sage: a = b^210
        sage: discrete_log(a, b, K.order()-1)
        210

        sage: b = Mod(1,37);  x = Mod(2,37)
        sage: discrete_log(x, b)
        Traceback (most recent call last):
        ...
        ValueError: No discrete log of 2 found to base 1
        sage: b = Mod(1,997);  x = Mod(2,997)
        sage: discrete_log(x, b)
        Traceback (most recent call last):
        ...
        ValueError: No discrete log of 2 found to base 1

    See :trac:`2356`::

        sage: F.<w> = GF(121)
        sage: v = w^120
        sage: v.log(w)
        0

        sage: K.<z>=CyclotomicField(230)
        sage: w=z^50
        sage: discrete_log(w,z)
        50

    An example where the order is infinite: note that we must give
    an upper bound here::

        sage: K.<a> = QuadraticField(23)
        sage: eps = 5*a-24        # a fundamental unit
        sage: eps.multiplicative_order()
        +Infinity
        sage: eta = eps^100
        sage: discrete_log(eta,eps,bounds=(0,1000))
        100

    In this case we cannot detect negative powers::

        sage: eta = eps^(-3)
        sage: discrete_log(eta,eps,bounds=(0,100))
        Traceback (most recent call last):
        ...
        ValueError: No discrete log of -11515*a - 55224 found to base 5*a - 24

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

        sage: - discrete_log(eta^-1,eps,bounds=(0,100))
        -3

    An additive example: elliptic curve DLOG::

        sage: F=GF(37^2,'a')
        sage: E=EllipticCurve(F,[1,1])
        sage: F.<a>=GF(37^2,'a')
        sage: E=EllipticCurve(F,[1,1])
        sage: P=E(25*a + 16 , 15*a + 7 )
        sage: P.order()
        672
        sage: Q=39*P; Q
        (36*a + 32 : 5*a + 12 : 1)
        sage: discrete_log(Q,P,P.order(),operation='+')
        39

    An example of big smooth group::

        sage: F.<a>=GF(2^63)
        sage: g=F.gen()
        sage: u=g**123456789
        sage: discrete_log(u,g)
        123456789

    AUTHORS:

    - William Stein and David Joyner (2005-01-05)
    - John Cremona (2008-02-29) rewrite using ``dict()`` and make generic

    """
    if ord is None:
        if operation in multiplication_names:
            try:
                ord = base.multiplicative_order()
            except Exception:
                ord = base.order()
        elif operation in addition_names:
            try:
                ord = base.additive_order()
            except Exception:
                ord = base.order()
        else:
            try:
                ord = base.order()
            except Exception:
                raise ValueError("ord must be specified")
    try:
        from sage.rings.infinity import Infinity
        if ord == +Infinity:
            return bsgs(base, a, bounds, operation=operation)
        if ord == 1 and a != base:
            raise ValueError
        f = ord.factor()
        l = [0] * len(f)
        for i, (pi, ri) in enumerate(f):
            for j in range(ri):
                if operation in multiplication_names:
                    c = bsgs(base**(ord // pi),
                             (a / base**l[i])**(ord // pi**(j + 1)), (0, pi),
                             operation=operation)
                    l[i] += c * (pi**j)
                elif operation in addition_names:
                    c = bsgs(base * (ord // pi),
                             (a - base * l[i]) * (ord // pi**(j + 1)), (0, pi),
                             operation=operation)
                    l[i] += c * (pi**j)
        from sage.arith.all import CRT_list
        return CRT_list(l, [pi**ri for pi, ri in f])
    except ValueError:
        raise ValueError("No discrete log of %s found to base %s" % (a, base))