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)
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))