Example #1
0
def dixon(n, num_trials=10000):
    B = int(exp((log(n)*log(log(n)))**(0.5))**(0.5)) + 1
    factor_base = rosemary.number_theory.sieves.primes(B)
    num_primes = len(factor_base)

    for p in factor_base:
        if n % p == 0:
            return p

    num_smooths_found = 0
    max_element = n
    power = 1
    while 2**power < max_element:
        power *= 2

    prod = 1
    for p in factor_base:
        prod *= p

    for trial in xrange(num_trials):
        exponent_matrix = []
        a_list = []
        while num_smooths_found <= num_primes:
            a = randint(1, n)
            s = a*a % n
            pp = pow(prod, power, s)
            g = gcd(s, pp)
            if g != s:
                continue

            exponent_vector = smooth_factor(s, factor_base, num_primes)
            exponent_matrix.append(exponent_vector)
            num_smooths_found += 1
            print num_smooths_found, num_primes
            a_list.append(a)

        kernel = z2_gaussian_elimination(exponent_matrix)

        for i in xrange(len(kernel)):
            y = 1
            x2_exponents = [0]*num_primes
            for j in xrange(len(kernel[i])):
                if kernel[i][j]:
                    y = (a_list[j]*y) % n
                    for f in xrange(num_primes):
                        x2_exponents[f] += exponent_matrix[j][f]

            x = 1
            for f in xrange(num_primes):
                x *= factor_base[f]**(x2_exponents[f]//2)

            for val in [x - y, x + y]:
                d = gcd(val, n)
                if 1 < d < n:
                    return d
Example #2
0
    def gcd(self, other):
        """
        Returns the greatest common divisor of self and other.

        Given polynomials self and other, this returns their greatest common
        divisor, using only exact integral arithmetic of the coefficients. The
        algorithm used is the Subresultant GCD algorithm. For details, see
        Algorithm 3.3.1 of "A Course in Computational Algebraic Number Theory"
        by Cohen, or Algorithm C in section 4.6.1 of "The Art of Computer
        Programmming: Vol II" by Knuth.
        """
        d = gcd(self.content(), other.content())
        u = self.primitive_part()
        v = other.primitive_part()
        h = g = 1
        dd = u.degree - v.degree

        if dd < 0:
            return other.gcd(self)

        while True:
            (q, r) = u.pseudo_quo_rem(v)
            if r == 0:
                return d * v.primitive_part()
            elif r.degree == 0:
                return Polynomial([d])
            u = v
            v = Polynomial([e // (g*h**dd) for e in r._coefficients])
            g = u.lead_coeff
            if dd > 1:
                h = g**dd // h**(dd - 1)
            else:
                h = h**(1 - dd) // g**(-dd)
Example #3
0
    def gcd(self, other):
        """
        Returns the greatest common divisor of self and other.

        Given polynomials self and other, this returns their greatest common
        divisor, using only exact integral arithmetic of the coefficients. The
        algorithm used is the Subresultant GCD algorithm. For details, see
        Algorithm 3.3.1 of "A Course in Computational Algebraic Number Theory"
        by Cohen, or Algorithm C in section 4.6.1 of "The Art of Computer
        Programmming: Vol II" by Knuth.
        """
        d = gcd(self.content(), other.content())
        u = self.primitive_part()
        v = other.primitive_part()
        h = g = 1
        dd = u.degree - v.degree

        if dd < 0:
            return other.gcd(self)

        while True:
            (q, r) = u.pseudo_quo_rem(v)
            if r == 0:
                return d * v.primitive_part()
            elif r.degree == 0:
                return Polynomial([d])
            u = v
            v = Polynomial([e // (g * h**dd) for e in r._coefficients])
            g = u.lead_coeff
            if dd > 1:
                h = g**dd // h**(dd - 1)
            else:
                h = h**(1 - dd) // g**(-dd)
Example #4
0
def lehman(n):
    """
    Returns a nontrivial divisor of n, or proves primality.

    Given an integer n > 1, this algorithm finds a nontrivial factor of n if
    n is not prime, or returns n if n is prime.

    Input:
        * n: int (n >= 3)

    Output:
        * d: int
            If d == n, then n is proven prime. Otherwise, d is a nontrivial
            divisor of n.

    Examples:
        >>> l = 1112470797641561909
        >>> lehman(l)
        1056689261L

    Details:
        The algorithm used is Lehman's Method. This algorithm runs in time
        O(n^(1/3)), where n is the number to be factored / proven prime. This is
        substantially better than O(n^(1/2)) trial division for reasonably small
        value of n, but this algorithm is not suited for large values of n. See
        section 8.4 of "A Course in Computational Algebraic Number Theory" by
        Cohen or section 5.1.2 of "Prime Numbers - A Computational Perspective"
        by Crandall and Pomerance for more details.


    """
    # first, we trial divide up to floor(n^(1/3))
    bound = integer_nth_root(3, n)
    d = trial_division(n, bound)
    if d < n:
        return d

    for k in xrange(1, bound + 1):
        if k % 2 == 0:
            r = 1
            m = 2
        else:
            r = k + n
            m = 4
        # we want to iterate over a, where 4*k*n <= a^2 <= 4*k*n + bound^2
        # and a = r (mod m)
        fkn = 4*k*n
        a = integer_sqrt(fkn)
        # now, increase a until a = r (mod m)
        rm = r % m
        while a % m != rm:
            a += 1
        ub = fkn + bound**2
        while fkn <= a*a <= ub:
            c = a*a - fkn
            b = integer_sqrt(c)
            if b*b == c:
                return gcd(a + b, n)
            a += m
    return n
Example #5
0
def pollard_rho(n):
    """
    Attempts to find a nontrivial factor of n.

    Given a composite number n, this algorithm attempts to find a nontrivial
    factor of n. The algorithm used is Pollard's rho algorithm.

    Input:
        * n: int (n > 1)

    Output:
        * d: int

    Examples:
        >>> m = 1112470797641561909
        >>> pollard_rho(m)
        1052788969L
        >>> m = 2175282241519502424792841
        >>> pollard_rho(m)
        513741730823L

    Details:
        The algorithm used is Pollard's rho factorization method. This method
        should return a nontrivial factor of n in O(sqrt(p)) steps, where p is
        the least prime factor of n. Because of this dependence on the smallest
        prime dividing n and not n itself, this method is especially useful for
        large composites with small prime factors out of range of trial
        division. For more details, see section 5.2.1 of "Prime Numbers - A
        Computational Perspective" by Crandall and Pomerance and section 8.5 of
        "A Course in Computational Algebraic Number Theory" by Cohen.
    """
    # Instead of computing a gcd in each iteration, we accumulate the products
    # and take the gcd only when the number of terms is a multiple of 'step'
    step = 20
    prod = 1
    terms = 0

    # a is the constant term of the polynomial x^2 + a
    a = randint(1, n - 3)

    # u is the random seed
    u = randint(0, n - 1)
    v = u

    while True:
        u = (u*u + a) % n
        v = (v*v + a) % n
        v = (v*v + a) % n
        prod = prod*(u - v) % n
        terms += 1

        if terms == step:
            g = gcd(prod, n)
            if 1 < g < n:
                return g
            elif g == n:
                return n
            prod = 1
            terms = 0
Example #6
0
def nth_roots_of_minus1_mod_p(n, p, g=None):
    """Returns the nth roots of -1 modulo p.

    Given a positive integer n and a prime p, this returns a list of the
    solutions to the congruence x**n == -1 (mod p).

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Returns:
        * roots: list
            List of all nth roots of -1 modulo p.

    Examples:
        >>> nth_roots_of_minus1_mod_p(5, 11)
        [2, 6, 7, 8, 10]
        >>> nth_roots_of_minus1_mod_p(2, 101)
        [10, 91]

    Details:
        The congruence x**n == -1 (mod p) has gcd(n, p - 1) roots. We find one
        solution to the congruence by considering g**((p - 1)/(2*d)), where d =
        gcd(n, p - 1), and g is a primitive root modulo p. We then find all
        other solutions by multiplying this solution by the nth roots of unity
        modulo p. See Section 3.7 of "Introduction to Number Theory" by Hua for
        more details.
    """
    if p == 2:
        return [1]

    d = gcd(n, p - 1)

    if (p - 1)//d % 2 != 0:
        return []

    if g is None:
        g = primitive_root(p, phi=p - 1)

    # This is one solution to x^n = -1 (mod p).
    root = pow(g, (p - 1)//(2*d), p)
    roots_of_unity = nth_roots_of_unity_mod_p(n, p, g)
    all_roots = [root*h % p for h in roots_of_unity]
    all_roots.sort()

    return all_roots
Example #7
0
def nth_roots_of_minus1_mod_p(n, p, g=None):
    """Returns the nth roots of -1 modulo p.

    Given a positive integer n and a prime p, this returns a list of the
    solutions to the congruence x**n == -1 (mod p).

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Returns:
        * roots: list
            List of all nth roots of -1 modulo p.

    Examples:
        >>> nth_roots_of_minus1_mod_p(5, 11)
        [2, 6, 7, 8, 10]
        >>> nth_roots_of_minus1_mod_p(2, 101)
        [10, 91]

    Details:
        The congruence x**n == -1 (mod p) has gcd(n, p - 1) roots. We find one
        solution to the congruence by considering g**((p - 1)/(2*d)), where d =
        gcd(n, p - 1), and g is a primitive root modulo p. We then find all
        other solutions by multiplying this solution by the nth roots of unity
        modulo p. See Section 3.7 of "Introduction to Number Theory" by Hua for
        more details.
    """
    if p == 2:
        return [1]

    d = gcd(n, p - 1)

    if (p - 1) // d % 2 != 0:
        return []

    if g is None:
        g = primitive_root(p, phi=p - 1)

    # This is one solution to x^n = -1 (mod p).
    root = pow(g, (p - 1) // (2 * d), p)
    roots_of_unity = nth_roots_of_unity_mod_p(n, p, g)
    all_roots = [root * h % p for h in roots_of_unity]
    all_roots.sort()

    return all_roots
Example #8
0
def nth_roots_of_unity_mod_p(n, p, g=None):
    """Returns the nth roots of unity modulo p.

    Given a positive integer n and a prime p, this returns a list of the
    solutions to the congruence x**n = 1 (mod p).

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Returns:
        * roots: list
            List of all nth roots of unity.

    Examples:
        >>> nth_roots_of_unity_mod_p(4, 101)
        [1, 10, 91, 100]
        >>> nth_roots_of_unity_mod_p(8, 17)
        [1, 2, 4, 8, 9, 13, 15, 16]

    Details:
        The congruence x**n == 1 (mod p) has gcd(n, p - 1) roots. We find one
        solution given by g**((p - 1)/d), where d = gcd(n, p - 1), and g is a
        primitive root modulo p. Given this, we find all other solutions by
        looking at the powers of this one solution. See Theorem 7.1 of
        "Introduction to Number Theory" by Hua for more information.
    """
    if p == 2:
        return [1]

    if g is None:
        g = primitive_root(p, phi=p-1)

    d = gcd(n, p - 1)
    # This is one solution. We find all others by looking at powers of this one.
    h = pow(g, (p - 1)//d, p)

    roots = []
    val = 1
    for _ in xrange(d):
        roots.append(val)
        val = (val*h) % p
    roots.sort()
    return roots
Example #9
0
def nth_roots_of_unity_mod_p(n, p, g=None):
    """Returns the nth roots of unity modulo p.

    Given a positive integer n and a prime p, this returns a list of the
    solutions to the congruence x**n = 1 (mod p).

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Returns:
        * roots: list
            List of all nth roots of unity.

    Examples:
        >>> nth_roots_of_unity_mod_p(4, 101)
        [1, 10, 91, 100]
        >>> nth_roots_of_unity_mod_p(8, 17)
        [1, 2, 4, 8, 9, 13, 15, 16]

    Details:
        The congruence x**n == 1 (mod p) has gcd(n, p - 1) roots. We find one
        solution given by g**((p - 1)/d), where d = gcd(n, p - 1), and g is a
        primitive root modulo p. Given this, we find all other solutions by
        looking at the powers of this one solution. See Theorem 7.1 of
        "Introduction to Number Theory" by Hua for more information.
    """
    if p == 2:
        return [1]

    if g is None:
        g = primitive_root(p, phi=p - 1)

    d = gcd(n, p - 1)
    # This is one solution. We find all others by looking at powers of this one.
    h = pow(g, (p - 1) // d, p)

    roots = []
    val = 1
    for _ in xrange(d):
        roots.append(val)
        val = (val * h) % p
    roots.sort()
    return roots
Example #10
0
def necklaces(n, k, weights=None):
    """
    Returns the number of necklace colorings.

    Given integers n >= 1 and k >= 2, this returns the number of ways to color a
    necklace of n beads with k colors. A necklace of length n colored by k
    colors is an equivalence class of n-character strings over an alphabet of
    size k, taking all rotations as equivalent.

    The optional argument weights can be a list or tuple of positive integers
    summing to n. If the colors used are k_0, k_1, ..., k_{n - 1}, then
    weights[i] is the number of times that color k_i is used.

    See Charalambides - Enumerative Combinatorics chapter 13 for more details.

    Input:
        n: Positive integer.
        k: Positive integer >= 2.
        weights: Optional list of weights.

    Returns:
        The number of colorings.

    Examples:
        >>> necklaces(3, 2)
        4
        >>> necklaces(10, 5)
        976887

        This is how we would count the colorings of a necklace with 6 beads
        using 3 colors, where each color is used exactly 2 times:
        >>> necklaces(6, 3, [2, 2, 2])
        16
    """
    if weights:
        j = gcd(weights)
        ss = 0
        for d in xdivisors(j):
            ll = [e/d for e in weights]
            ss += euler_phi(d)*multinomial(n//d, ll)
        return ss//n
    else:
        ss = 0
        for d in xdivisors(n):
            ss += euler_phi(d)*k**(n//d)
        return ss//n
Example #11
0
def necklaces(n, k, weights=None):
    """
    Returns the number of necklace colorings.

    Given integers n >= 1 and k >= 2, this returns the number of ways to color a
    necklace of n beads with k colors. A necklace of length n colored by k
    colors is an equivalence class of n-character strings over an alphabet of
    size k, taking all rotations as equivalent.

    The optional argument weights can be a list or tuple of positive integers
    summing to n. If the colors used are k_0, k_1, ..., k_{n - 1}, then
    weights[i] is the number of times that color k_i is used.

    See Charalambides - Enumerative Combinatorics chapter 13 for more details.

    Input:
        n: Positive integer.
        k: Positive integer >= 2.
        weights: Optional list of weights.

    Returns:
        The number of colorings.

    Examples:
        >>> necklaces(3, 2)
        4
        >>> necklaces(10, 5)
        976887

        This is how we would count the colorings of a necklace with 6 beads
        using 3 colors, where each color is used exactly 2 times:
        >>> necklaces(6, 3, [2, 2, 2])
        16
    """
    if weights:
        j = gcd(weights)
        ss = 0
        for d in xdivisors(j):
            ll = [e/d for e in weights]
            ss += euler_phi(d)*multinomial(n//d, ll)
        return ss//n
    else:
        ss = 0
        for d in xdivisors(n):
            ss += euler_phi(d)*k**(n//d)
        return ss//n
Example #12
0
def pollard_p_minus_1(n, B=20000):
    """
    Attempts to find a nontrivial factor of n.

    Given a composite number n and search bound B, this algorithm attempts to
    find a nontrivial factor of n.

    Input:
        * n: int (n > 1)
            A composite integer.

        * B: int (B > 0) (default=20000)
            Search bound.

    Output:
        * d: int
            Nontrivial divisor of n.

    Examples:
        >>> m = 1112470797641561909
        >>> pollard_p_minus_1(m)
        1056689261L

    Details:
        The algorithm used is Pollard's p - 1 method. We know that if p is an
        odd prime, then 2^(p - 1) = 1 (mod p), and 2^M = 1 (mod p) if (p - 1) |
        M. So if p is a prime factor of an integer n, then p divides gcd(2^M -
        1, n). The idea behind this algorithm is to choose M with many divisors
        of the form p - 1, and then search for many primes p as possible
        divisors of n at once. For more information, see section 5.4 of "Prime
        Numbers - A Computational Perspective" by Crandall and Pomerance.
    """
    c = randint(2, 20)
    p_list = rosemary.number_theory.sieves.primes(B)
    for p in p_list:
        a = integer_log(B, p)
        for _ in xrange(a):
            c = pow(c, p, n)
    g = gcd(c - 1, n)
    return g
Example #13
0
def nth_roots_of_minus1_mod_p(n, p, g=None):
    """
    Returns the nth roots of -1 modulo p.

    Given a positive integer n and a prime p, this returns a list of all nth
    roots of -1 modulo p. The primality of p is not verified.

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Output:
        * roots: list
            List of all nth roots of -1 modulo p.
    """
    if p == 2:
        return [1]

    d = gcd(n, p - 1)

    if (p - 1)//d % 2 != 0:
        return []

    if g is None:
        g = primitive_root_mod_p(p)

    # This is one solution to x^n = -1 (mod p).
    root = pow(g, (p - 1)//(2*d), p)
    roots_of_unity = nth_roots_of_unity_mod_p(n, p, g)
    all_roots = [root*h % p for h in roots_of_unity]
    all_roots.sort()
    return all_roots
Example #14
0
def nth_roots_of_unity_mod_p(n, p, g=None):
    """
    Returns the nth roots of unity modulo p.

    Given a positive integer n and a prime p, this returns a list of the nth
    roots of unity modulo p. The primality of p is assumed and not verified.

    Input:
        * n: int
            The index of the root.

        * p: int
            Prime modulus.

        * g: int (default=None)
            Primitive root modulo p.

    Output:
        * roots: list
            List of all nth roots of unity.
    """
    if p == 2:
        return [1]
    if g is None:
        g = primitive_root_mod_p(p)

    d = gcd(n, p - 1)
    # This is one solution. We find all others by looking at powers of this one.
    h = pow(g, (p - 1)//d, p)

    roots = []
    val = 1
    for _ in xrange(d):
        roots.append(val)
        val = (val*h) % p
    roots.sort()
    return roots
Example #15
0
def coprime_pairs_graph(n):
    """
    Graph with vertices 1, 2, ..., n, with edges between coprime pairs.

    Input:
        n: int

    Output:
        graph: Graph

    Examples:
        >>> G = coprime_pairs_graph(6)
        >>> G.num_vertices()
        6
        >>> G.edges()
        [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 3), (2, 5), (3, 4), (3, 5), (4, 5), (5, 6)]
    """
    graph = Graph()
    for i in xrange(1, n + 1):
        for j in xrange(1, i):
            if gcd(i, j) == 1:
                graph.add_edge(i, j)

    return graph
Example #16
0
def quadratic_congruence(coeff_list, n, n_factorization=None):
    """Returns a list of the roots of the quadratic equation modulo n.

    Input:
        * coeff_list: list
            A list of the coefficients of the quadratic.

        * n: int
            The modulus.

        * n_factorization: list (default=None)
            The factorization of the modulus n.

    Returns:
        * roots: list
            A sorted list of the roots of the quadratic modulo n.

    Examples:
        >>> quadratic_congruence([1, 3, -18], 1000)
        [3, 378, 619, 994]
        >>> quadratic_congruence([1, -31, -12], 36)
        [7, 15, 16, 24]
        >>> quadratic_congruence([11, 5, 18], 29)
        [22, 25]

    Details:
        The algorithm proceeds by finding roots modulo p**k for each prime power
        p**k in the factorization of the modulus n. These roots are then
        combined using the Chinese Remainder Theorem. See Chapter 5 of "The
        Theory of Numbers - A Text and Source Book of Problems" by Adler and
        Coury for detailed information.
    """
    if n_factorization is None:
        n_factorization = factor.factor(n)

    (a, b, c) = coeff_list
    discriminant = b * b - 4 * a * c
    all_roots = []

    if gcd(2 * a, n) == 1:
        # This is the easy case where we can complete the square.
        # First, we solve the congruence y^2 = b^2 - 4*a*c (mod n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, n, n_factorization)

        # Next, we solve the congruence 2*a*x = y - b (mod n) for x to obtain
        # the solutions to the quadratic. Since gcd(2*a, n) == 1, this is
        # simple, and each each value of y leads to one value of x.
        inverse = inverse_mod(2 * a, n)
        for y in discriminant_roots:
            x = (y - b) * inverse % n
            all_roots.append(x)
    else:
        # Here, gcd(4*a, n) != 1, so we can't complete the square as usual.
        # Write 4*a = a1*a2, with a2 coprime to n.
        a1 = 1
        a2 = 4 * a
        d = gcd(n, a2)
        while d > 1:
            a1 *= d
            a2 /= d
            d = gcd(n, a2)

        # We solve the congruence y^2 = b^2 - 4*a*c (mod a1*n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, a1 * n)

        # For each solution y, we solve 2*a*x = y - b (mod a1*n) for x. Since
        # gcd(2*a, n) > 1, each solution y leads to multiple values of x.
        for y in discriminant_roots:
            roots = linear_congruence(2 * a, y - b, a1 * n)
            all_roots.extend(roots)

        # Eliminate repeated solutions, and reduce modulo the original modulus.
        distinct_roots = {x % n for x in all_roots}
        all_roots = list(distinct_roots)

    all_roots.sort()
    return all_roots
Example #17
0
def pollard_rho(n, iterations=None):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n`, this algorithm attempts to find a
    nontrivial factor of `n` using Pollard's rho algorithm.

    Parameters
    ----------
    n : int (n > 1)
        Integer to be factored.

    iterations : int, optional (default=None)
        Maximum number of iterations. If None, then the algorithm runs
        until a factor is found.

    Returns
    -------
    d : int
        Factor of `n`.

    Notes
    -----
    This method should return a nontrivial factor of n in O(sqrt(p)) steps,
    where p is the least prime factor of n. Because of this dependence on
    the smallest prime dividing n and not n itself, this method is
    especially useful for large composites with small prime factors out of
    range of trial division. For more details, see section 5.2.1 of [2] and
    section 8.5 of [1].

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    Examples
    --------
    >>> pollard_rho(1112470797641561909)
    1052788969L
    >>> pollard_rho(2175282241519502424792841)
    513741730823L
    """
    # Instead of computing a gcd in each iteration, we accumulate the
    # products and take the gcd only when the number of terms is a multiple
    # of `step`
    step = 100
    prod = 1
    a = randint(1, n - 3)
    u = randint(0, n - 1)
    v = u
    d = 1

    if iterations is None:
        X = itertools.count()
    else:
        X = xrange(iterations)

    for k in X:
        u = (u * u + a) % n
        v = (v * v + a) % n
        v = (v * v + a) % n
        prod = prod * (u - v) % n

        if k % step == 0:
            d = gcd(prod, n)
            prod = 1
            if d > 1:
                return d

    return n
Example #18
0
def pollard_rho_brent(n):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n`, this algorithm attempts to find a
    nontrivial factor of `n` using Brent's improvement to the Pollard-rho
    algorithm.

    Parameters
    ----------
    n : int (n > 1)
        Integer to factor.

    Returns
    -------
    d : int
        Factor of `n`.

    Notes
    -----
    This method should return a nontrivial factor of n in O(sqrt(p)) steps,
    where p is the least prime factor of n. Because of this dependence on
    the smallest prime dividing n and not n itself, this method is
    especially useful for large composites with small prime factors out of
    range of trial division. For more details, see [1] and section 8.5 of
    [2].

    References
    ----------
    .. [1] R.P. Brent, "An Improved Monte Carlo Factorization Algorithm",
    BIT, Vol. 20, 1980.

    .. [2] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [3] J.M. Pollard, "A Monte Carlo Method for Factorization", BIT,
    Vol. 15, 1975.

    Examples
    --------
    >>> pollard_rho_brent(1112470797641561909)
    1052788969L
    >>> pollard_rho_brent(2175282241519502424792841)
    513741730823L
    """
    c = randint(1, n - 3)
    y = randint(0, n - 1)
    step = 100
    prod = 1
    r = 1

    while True:
        x = y
        for i in xrange(r):
            y = (y*y + c) % n

        for k in itertools.count(0, step):
            ys = y
            for i in xrange(min(step, r - k)):
                y = (y*y + c) % n
                prod = prod*(x - y) % n
            g = gcd(prod, n)
            if k >= r or g > 1:
                break

        r *= 2
        if g > 1:
            break

    if g == n:
        while True:
            ys = (ys*ys + c) % n
            g = gcd(x - ys, n)
            if g > 1:
                break
    return g
Example #19
0
def pollard_rho(n, iterations=None):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n`, this algorithm attempts to find a
    nontrivial factor of `n` using Pollard's rho algorithm.

    Parameters
    ----------
    n : int (n > 1)
        Integer to be factored.

    iterations : int, optional (default=None)
        Maximum number of iterations. If None, then the algorithm runs
        until a factor is found.

    Returns
    -------
    d : int
        Factor of `n`.

    Notes
    -----
    This method should return a nontrivial factor of n in O(sqrt(p)) steps,
    where p is the least prime factor of n. Because of this dependence on
    the smallest prime dividing n and not n itself, this method is
    especially useful for large composites with small prime factors out of
    range of trial division. For more details, see section 5.2.1 of [2] and
    section 8.5 of [1].

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    Examples
    --------
    >>> pollard_rho(1112470797641561909)
    1052788969L
    >>> pollard_rho(2175282241519502424792841)
    513741730823L
    """
    # Instead of computing a gcd in each iteration, we accumulate the
    # products and take the gcd only when the number of terms is a multiple
    # of `step`
    step = 100
    prod = 1
    a = randint(1, n - 3)
    u = randint(0, n - 1)
    v = u
    d = 1

    if iterations is None:
        X = itertools.count()
    else:
        X = xrange(iterations)

    for k in X:
        u = (u*u + a) % n
        v = (v*v + a) % n
        v = (v*v + a) % n
        prod = prod*(u - v) % n

        if k % step == 0:
            d = gcd(prod, n)
            prod = 1
            if d > 1:
                return d

    return n
Example #20
0
def cfrac(n, k=None):
    r"""Returns a nontrivial divisor of `n`.

    Given a composite integer `n` > 1, this algorithm attempts to find a
    factor of `n` using Morrison and Brillhart's continued fraction method
    CFRAC.

    Parameters
    ----------
    n : int (n > 1)
        Number to be factored.

    k : int, optional (default=None)
        Multiplier to use in case the period of sqrt(n) is too short.

    Returns
    -------
    d : int
        Divisor of n.

    Notes
    -----
    Morrison and Brillhart's continued fraction method was the first
    factorization algorithm of subexponential running time. The idea is to
    find a nontrivial solution to the congrunce x^2 = y^2 (mod n), and
    extracting a factor from gcd(x + y, n). See [1] for details, and see
    [2] for implementation details.

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] M.A. Morrison, J. Brillhart, "A Method of Factoring and the
    Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129,
    Jan. 1975.

    .. [3] H. Riesel, "Prime Numbers and Computer Methods for
    Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland,
    1994.

    Examples
    --------
    >>> cfrac(12007001)
    4001
    >>> cfrac(1112470797641561909)
    1052788969L
    >>> cfrac(2175282241519502424792841)
    513741730823L
    """
    # B is our smoothness bound.
    B = int(exp(0.5*sqrt(log(n)*log(log(n))))) + 1
    prime_list = sieves.primes(B)

    # Choose a multiplier if none is provided.
    if k is None:
        k = _cfrac_multiplier(n)
    kn = k*n

    # Perform simple trial division by the primes we computed to find any
    # small prime divisors.
    for p in prime_list:
        if n % p == 0:
            return p

    # Our factor base needs to include -1 and 2, and the odd primes p for
    # which (kN|p) = 0 or 1.
    factor_base = [-1]
    for p in prime_list:
        if p == 2 or jacobi_symbol(kn, p) >= 0:
            factor_base.append(p)

    num_primes = len(factor_base)

    # Compute the product of the elements in our factor base for smoothness
    # checking computations later.
    prod = 1
    for p in factor_base:
        prod *= p

    # Instead of using trial division to check each value for smoothness
    # individually, we use a batch smoothness test, processing batches of
    # size `batch_size` at once.

    # Set e as the least positive integer with n <= 2**e.
    e = 1
    while 2**e < n:
        e *= 2

    aq_pairs = _cfrac_aq_pairs(kn)

    num_smooths_found = 0
    exponent_matrix = []
    a_list = []

    while num_smooths_found <= num_primes:
        (i, a, q) = aq_pairs.next()

        # This is from the batch smoothness test given as Algorithm 3.3.1
        # in [1].
        if gcd(q, pow(prod, e, q)) != q:
            continue

        if i % 2 == 1:
            q *= -1

        # At this point, we know q is smooth, and we can factor it
        # completely using our factor base.
        exponent_vector = smooth_factor(q, factor_base)
        exponent_matrix.append(exponent_vector)
        num_smooths_found += 1
        a_list.append(a)

    kernel = _z2_gaussian_elimination(exponent_matrix)

    for i in xrange(len(kernel)):
        y = 1
        x2_exponents = [0]*num_primes
        for j in xrange(len(kernel[i])):
            if kernel[i][j]:
                y = (a_list[j]*y) % n
                for f in xrange(num_primes):
                    x2_exponents[f] += exponent_matrix[j][f]

        x = 1
        for j in xrange(num_primes):
            x *= factor_base[j]**(x2_exponents[j]//2)

        for val in [x - y, x + y]:
            d = gcd(val, n)
            if 1 < d < n:
                return d
Example #21
0
def is_primitive_root(a, n, phi=None, phi_divisors=None):
    """Returns True if a is a primitive root mod n and False otherwise.

    Given an integer a and modulus n, this method determines whether or not a is
    a primitive root modulo n.

    Input:
        * a: int

        * n: int (n > 0)
            The modulus.

        * phi: int (default=None)
            Value of euler_phi(n).

        * phi_divisors: list (default=None)
            List of prime divisors of euler_phi(n).

    Returns:
        * b: bool
            b is True if a is a primitive root mod n and False otherwise. Note
            that b will be False when no primitive roots exist modulo n.

    Raises:
        * ValueError: if n <= 1.

    Examples:
        >>> is_primitive_root(2, 11)
        True
        >>> is_primitive_root(3, 11)
        False
        >>> is_primitive_root(3, -2)
        Traceback (most recent call last):
        ...
        ValueError: is_primitive_root: n must be >= 2.

    Details:
        An integer a is called a primitive root mod n if a generates the
        multiplicative group of units modulo n. Equivalently, a is a primitive
        root modulo n if the order of a modulo m is euler_phi(n).

        The algorithm is based on the observation that an integer a coprime to n
        is a primitive root modulo n if and only if a**(euler_phi(n)/d) != 1
        (mod n) for each divisor d of euler_phi(n). See Lemma 6.4 of "Elementary
        Number Theory" by Jones and Jones for a proof.

        Primitive roots exist only for the moduli n = 1, 2, 4, p**a, and 2*p**a,
        where p is an odd prime and a >= 1. These cases are captured in the
        above Lemma, however some simple divisibility tests allow us to exit
        early for certain moduli. See Chapter 6 of "Elementary Number Theory" by
        Jones and Jones for more details. See also Chapter 10 of "Introduction
        to Analytic Number Theory" by Apostol.
    """
    if n <= 1:
        raise ValueError("is_primitive_root: n must be >= 2.")

    if n > 4 and n % 4 == 0:
        return False

    if gcd(a, n) != 1:
        return False

    if phi is None:
        phi = functions.euler_phi(n)

    if phi_divisors is None:
        phi_divisors = factor.prime_divisors(phi)

    for d in phi_divisors:
        if pow(a, phi // d, n) == 1:
            return False

    return True
Example #22
0
    def test_gcd(self):
        self.assertEqual(gcd(20, 10), 10)
        self.assertEqual(gcd(10, 20), 10)

        self.assertEqual(gcd(-10, 20), 10)
        self.assertEqual(gcd(-20, 10), 10)

        self.assertEqual(gcd(-10, -10), 10)

        self.assertEqual(gcd(1, 11213), 1)
        self.assertEqual(gcd(11213, 1), 1)

        self.assertEqual(gcd(0, 10), 10)
        self.assertEqual(gcd(10, 0), 10)
        self.assertEqual(gcd(0, -10), 10)

        values = [
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
            1, 2, 1, 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 2, 1, 4, 1, 2, 1, 4, 1, 2, 1, 4,
            1, 2, 1, 4, 1, 2, 1, 4, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 2, 3, 2, 1, 6, 1, 2,
            3, 2, 1, 6, 1, 2, 3, 2, 1, 6, 1, 2, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4,
            1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 1, 3, 1, 1, 3, 1, 1, 9, 1, 1, 3, 1, 1, 3, 1, 1, 9, 1, 1,
            1, 2, 1, 2, 5, 2, 1, 2, 1, 10, 1, 2, 1, 2, 5, 2, 1, 2, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 1, 2, 3, 4, 1, 6, 1, 4, 3, 2, 1, 12, 1, 2, 3, 4, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
            1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 7, 2, 1, 2, 1, 2, 1, 14, 1, 2, 1, 2, 1, 2, 1, 1, 3, 1, 5, 3,
            1, 1, 3, 5, 1, 3, 1, 1, 15, 1, 1, 3, 1, 5, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 16, 1, 2, 1, 4, 1,
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 2, 3, 2, 1, 6, 1, 2, 9, 2, 1, 6, 1, 2, 3, 2, 1,
            18, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 2, 1, 4, 5, 2, 1, 4, 1, 10, 1, 4,
            1, 2, 5, 4, 1, 2, 1, 20
        ]

        i = 0
        for a in xrange(1, 21):
            for b in xrange(1, 21):
                self.assertEqual(gcd(a, b), values[i])
                i += 1
Example #23
0
def quadratic_congruence(coeff_list, n, n_factorization=None):
    """
    Returns the roots of the quadratic equation modulo n.

    Input:
        * coeff_list: list
            A list of the coefficients of the quadratic.

        * n: int
            The modulus.

        * n_factorization: list (default=None)
            The factorization of the modulus n.

    Output:
        * roots: list
            A list of the roots of the quadratic modulo n.

    Details:
        The algorithm proceeds by finding roots modulo p^k for each prime power
        p^k in the factorization of the modulus n. These roots are then combined
        using the Chinese Remainder Theorem.

        The quadratic formula is used to find the roots, with the square roots
        computed modulo p^k, for each p^k dividing n. For odd primes p, the
        Tonelli-Shanks algorithm is used. For p = 2, a simple search is
        performed.

    Examples:
        >>> quadratic_congruence([1, 3, -18], 1000)
        [3, 378, 619, 994]
    """

    if n_factorization is None:
        n_factorization = rosemary.number_theory.factorization.factor(n)

    (a, b, c) = coeff_list
    discriminant = b*b - 4*a*c
    all_roots = []

    if gcd(2*a, n) == 1:
        # This is the easy case where we can complete the square.
        # First, we solve the congruence y^2 = b^2 - 4*a*c (mod n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, n, n_factorization)

        # Next, we solve the congruence 2*a*x = y - b (mod n) for x to obtain
        # the solutions to the quadratic. Since gcd(2*a, n) == 1, this is
        # simple, and each each value of y leads to one value of x.
        inverse = inverse_mod(2*a, n)
        for y in discriminant_roots:
            x = (y - b)*inverse % n
            all_roots.append(x)
    else:
        # Here, gcd(4*a, n) != 1, so we can't complete the square as usual.
        # Write 4*a = a1*a2, with a2 coprime to n.
        a1 = 1
        a2 = 4*a
        d = gcd(n, a2)
        while d > 1:
            a1 *= d
            a2 /= d
            d = gcd(n, a2)

        # We solve the congruence y^2 = b^2 - 4*a*c (mod a1*n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, a1*n)

        # For each solution y, we solve 2*a*x = y - b (mod a1*n) for x. Since
        # gcd(2*a, n) > 1, each solution y leads to multiple values of x.
        for y in discriminant_roots:
            roots = linear_congruence(2*a, y - b, a1*n)
            all_roots.extend(roots)

        # Eliminate repeated solutions, and reduce modulo the original modulus.
        distinct_roots = {x % n for x in all_roots}
        all_roots = list(distinct_roots)

    all_roots.sort()
    return all_roots
Example #24
0
def is_primitive_root(a, n, phi=None, phi_divisors=None):
    """Returns True if a is a primitive root mod n and False otherwise.

    Given an integer a and modulus n, this method determines whether or not a is
    a primitive root modulo n.

    Input:
        * a: int

        * n: int (n > 0)
            The modulus.

        * phi: int (default=None)
            Value of euler_phi(n).

        * phi_divisors: list (default=None)
            List of prime divisors of euler_phi(n).

    Returns:
        * b: bool
            b is True if a is a primitive root mod n and False otherwise. Note
            that b will be False when no primitive roots exist modulo n.

    Raises:
        * ValueError: if n <= 1.

    Examples:
        >>> is_primitive_root(2, 11)
        True
        >>> is_primitive_root(3, 11)
        False
        >>> is_primitive_root(3, -2)
        Traceback (most recent call last):
        ...
        ValueError: is_primitive_root: n must be >= 2.

    Details:
        An integer a is called a primitive root mod n if a generates the
        multiplicative group of units modulo n. Equivalently, a is a primitive
        root modulo n if the order of a modulo m is euler_phi(n).

        The algorithm is based on the observation that an integer a coprime to n
        is a primitive root modulo n if and only if a**(euler_phi(n)/d) != 1
        (mod n) for each divisor d of euler_phi(n). See Lemma 6.4 of "Elementary
        Number Theory" by Jones and Jones for a proof.

        Primitive roots exist only for the moduli n = 1, 2, 4, p**a, and 2*p**a,
        where p is an odd prime and a >= 1. These cases are captured in the
        above Lemma, however some simple divisibility tests allow us to exit
        early for certain moduli. See Chapter 6 of "Elementary Number Theory" by
        Jones and Jones for more details. See also Chapter 10 of "Introduction
        to Analytic Number Theory" by Apostol.
    """
    if n <= 1:
        raise ValueError("is_primitive_root: n must be >= 2.")

    if n > 4 and n % 4 == 0:
        return False

    if gcd(a, n) != 1:
        return False

    if phi is None:
        phi = functions.euler_phi(n)

    if phi_divisors is None:
        phi_divisors = factor.prime_divisors(phi)

    for d in phi_divisors:
        if pow(a, phi//d, n) == 1:
            return False

    return True
Example #25
0
def quadratic_congruence(coeff_list, n, n_factorization=None):
    """Returns a list of the roots of the quadratic equation modulo n.

    Input:
        * coeff_list: list
            A list of the coefficients of the quadratic.

        * n: int
            The modulus.

        * n_factorization: list (default=None)
            The factorization of the modulus n.

    Returns:
        * roots: list
            A sorted list of the roots of the quadratic modulo n.

    Examples:
        >>> quadratic_congruence([1, 3, -18], 1000)
        [3, 378, 619, 994]
        >>> quadratic_congruence([1, -31, -12], 36)
        [7, 15, 16, 24]
        >>> quadratic_congruence([11, 5, 18], 29)
        [22, 25]

    Details:
        The algorithm proceeds by finding roots modulo p**k for each prime power
        p**k in the factorization of the modulus n. These roots are then
        combined using the Chinese Remainder Theorem. See Chapter 5 of "The
        Theory of Numbers - A Text and Source Book of Problems" by Adler and
        Coury for detailed information.
    """
    if n_factorization is None:
        n_factorization = factor.factor(n)

    (a, b, c) = coeff_list
    discriminant = b*b - 4*a*c
    all_roots = []

    if gcd(2*a, n) == 1:
        # This is the easy case where we can complete the square.
        # First, we solve the congruence y^2 = b^2 - 4*a*c (mod n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, n, n_factorization)

        # Next, we solve the congruence 2*a*x = y - b (mod n) for x to obtain
        # the solutions to the quadratic. Since gcd(2*a, n) == 1, this is
        # simple, and each each value of y leads to one value of x.
        inverse = inverse_mod(2*a, n)
        for y in discriminant_roots:
            x = (y - b)*inverse % n
            all_roots.append(x)
    else:
        # Here, gcd(4*a, n) != 1, so we can't complete the square as usual.
        # Write 4*a = a1*a2, with a2 coprime to n.
        a1 = 1
        a2 = 4*a
        d = gcd(n, a2)
        while d > 1:
            a1 *= d
            a2 /= d
            d = gcd(n, a2)

        # We solve the congruence y^2 = b^2 - 4*a*c (mod a1*n) for y.
        discriminant_roots = sqrts_mod_n(discriminant, a1*n)

        # For each solution y, we solve 2*a*x = y - b (mod a1*n) for x. Since
        # gcd(2*a, n) > 1, each solution y leads to multiple values of x.
        for y in discriminant_roots:
            roots = linear_congruence(2*a, y - b, a1*n)
            all_roots.extend(roots)

        # Eliminate repeated solutions, and reduce modulo the original modulus.
        distinct_roots = {x % n for x in all_roots}
        all_roots = list(distinct_roots)

    all_roots.sort()
    return all_roots
Example #26
0
def pollard_p_minus_1(n, limit=100000):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n` and search bound `limit`, this algorithm
    attempts to find a nontrivial factor of `n` using Pollard's p - 1
    method.

    Parameters
    ----------
    n : int (n > 1)
        Integer to be factored.

    limit : int (limit > 0) (default=100000)
        Search limit for possible prime divisors of p - 1.

    Returns
    -------
    d : int
        Divisor of n.

    Notes
    -----
    The algorithm used here is a one-stage form of Pollard's p - 1 method.
    The idea used is that if p - 1 divides Q, then p divides a^Q - 1 if (a,
    p) == 1. So if p is a prime factor of an integer n, then p divides
    gcd(a^Q - 1, n). The idea here is to choose values Q with many divisors
    of the form p - 1, and so search for many primes p as possible divisors
    at once. This is not a general purpose factoring algorithm, but this
    technique works well when n has a prime factor P such that P - 1 is
    divisible by only small primes. See chapter 6 of [2] for details.

    References
    ----------
    .. [1] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    .. [2] H. Riesel, "Prime Numbers and Computer Methods for
    Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland,
    1994.

    Examples
    --------
    >>> pollard_p_minus_1(1112470797641561909)
    1056689261L
    """
    p_list = sieves.primes(limit)
    pow_list = []

    for p in p_list:
        pk = p
        while pk <= limit:
            pow_list.append((pk, p))
            pk *= p

    pow_list.sort()
    c = 13

    for (count, (pk, p)) in enumerate(pow_list):
        c = pow(c, p, n)
        if count % 100 == 0:
            g = gcd(c - 1, n)
            if 1 < g < n:
                return g

    return gcd(c - 1, n)
Example #27
0
def lehman(n):
    r"""Returns a nontrivial divisor of `n`, or proves primality.

    Given an integer `n` > 1, this algorithm attempts to find a factor of
    `n` using Lehman's method.

    Parameters
    ----------
    n : int (n > 1)

    Returns
    -------
    d : int
        If d == n, then n is proven prime. Otherwise, d is a nontrivial
        divisor of n.

    Notes
    -----
    This algorithm runs in time O(n^(1/3)). This is substantially better
    than O(n^(1/2)) trial division for reasonably small value of n, but
    this algorithm is not suited for large values of n. See section 8.4 of
    [1] or section 5.1.2 of [2] for more details.

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    Examples
    --------
    >>> lehman(100)
    2
    >>> lehman(1112470797641561909)
    1056689261L
    """
    # first, we trial divide up to floor(n^(1/3))
    bound = integer_nth_root(3, n)
    d = trial_division(n, bound)
    if d < n:
        return d

    for k in xrange(1, bound + 1):
        if k % 2 == 0:
            r = 1
            m = 2
        else:
            r = k + n
            m = 4
        # we want to iterate over a, where 4*k*n <= a^2 <= 4*k*n + bound^2
        # and a = r (mod m)
        fkn = 4 * k * n
        a = integer_sqrt(fkn)
        # now, increase a until a = r (mod m)
        rm = r % m
        while a % m != rm:
            a += 1
        ub = fkn + bound**2
        while fkn <= a * a <= ub:
            c = a * a - fkn
            b = integer_sqrt(c)
            if b * b == c:
                return gcd(a + b, n)
            a += m
    return n
Example #28
0
def pollard_p_minus_1(n, limit=100000):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n` and search bound `limit`, this algorithm
    attempts to find a nontrivial factor of `n` using Pollard's p - 1
    method.

    Parameters
    ----------
    n : int (n > 1)
        Integer to be factored.

    limit : int (limit > 0) (default=100000)
        Search limit for possible prime divisors of p - 1.

    Returns
    -------
    d : int
        Divisor of n.

    Notes
    -----
    The algorithm used here is a one-stage form of Pollard's p - 1 method.
    The idea used is that if p - 1 divides Q, then p divides a^Q - 1 if (a,
    p) == 1. So if p is a prime factor of an integer n, then p divides
    gcd(a^Q - 1, n). The idea here is to choose values Q with many divisors
    of the form p - 1, and so search for many primes p as possible divisors
    at once. This is not a general purpose factoring algorithm, but this
    technique works well when n has a prime factor P such that P - 1 is
    divisible by only small primes. See chapter 6 of [2] for details.

    References
    ----------
    .. [1] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    .. [2] H. Riesel, "Prime Numbers and Computer Methods for
    Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland,
    1994.

    Examples
    --------
    >>> pollard_p_minus_1(1112470797641561909)
    1056689261L
    """
    p_list = sieves.primes(limit)
    pow_list = []

    for p in p_list:
        pk = p
        while pk <= limit:
            pow_list.append((pk, p))
            pk *= p

    pow_list.sort()
    c = 13

    for (count, (pk, p)) in enumerate(pow_list):
        c = pow(c, p, n)
        if count % 100 == 0:
            g = gcd(c - 1, n)
            if 1 < g < n:
                return g

    return gcd(c - 1, n)
Example #29
0
def pollard_rho_brent(n):
    r"""Attempts to find a nontrivial factor of `n`.

    Given a composite number `n`, this algorithm attempts to find a
    nontrivial factor of `n` using Brent's improvement to the Pollard-rho
    algorithm.

    Parameters
    ----------
    n : int (n > 1)
        Integer to factor.

    Returns
    -------
    d : int
        Factor of `n`.

    Notes
    -----
    This method should return a nontrivial factor of n in O(sqrt(p)) steps,
    where p is the least prime factor of n. Because of this dependence on
    the smallest prime dividing n and not n itself, this method is
    especially useful for large composites with small prime factors out of
    range of trial division. For more details, see [1] and section 8.5 of
    [2].

    References
    ----------
    .. [1] R.P. Brent, "An Improved Monte Carlo Factorization Algorithm",
    BIT, Vol. 20, 1980.

    .. [2] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [3] J.M. Pollard, "A Monte Carlo Method for Factorization", BIT,
    Vol. 15, 1975.

    Examples
    --------
    >>> pollard_rho_brent(1112470797641561909)
    1052788969L
    >>> pollard_rho_brent(2175282241519502424792841)
    513741730823L
    """
    c = randint(1, n - 3)
    y = randint(0, n - 1)
    step = 100
    prod = 1
    r = 1

    while True:
        x = y
        for i in xrange(r):
            y = (y * y + c) % n

        for k in itertools.count(0, step):
            ys = y
            for i in xrange(min(step, r - k)):
                y = (y * y + c) % n
                prod = prod * (x - y) % n
            g = gcd(prod, n)
            if k >= r or g > 1:
                break

        r *= 2
        if g > 1:
            break

    if g == n:
        while True:
            ys = (ys * ys + c) % n
            g = gcd(x - ys, n)
            if g > 1:
                break
    return g
Example #30
0
def cfrac(n, k=None):
    r"""Returns a nontrivial divisor of `n`.

    Given a composite integer `n` > 1, this algorithm attempts to find a
    factor of `n` using Morrison and Brillhart's continued fraction method
    CFRAC.

    Parameters
    ----------
    n : int (n > 1)
        Number to be factored.

    k : int, optional (default=None)
        Multiplier to use in case the period of sqrt(n) is too short.

    Returns
    -------
    d : int
        Divisor of n.

    Notes
    -----
    Morrison and Brillhart's continued fraction method was the first
    factorization algorithm of subexponential running time. The idea is to
    find a nontrivial solution to the congrunce x^2 = y^2 (mod n), and
    extracting a factor from gcd(x + y, n). See [1] for details, and see
    [2] for implementation details.

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] M.A. Morrison, J. Brillhart, "A Method of Factoring and the
    Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129,
    Jan. 1975.

    .. [3] H. Riesel, "Prime Numbers and Computer Methods for
    Factorization", 2nd edition, Birkhauser Verlag, Basel, Switzerland,
    1994.

    Examples
    --------
    >>> cfrac(12007001)
    4001
    >>> cfrac(1112470797641561909)
    1052788969L
    >>> cfrac(2175282241519502424792841)
    513741730823L
    """
    # B is our smoothness bound.
    B = int(exp(0.5 * sqrt(log(n) * log(log(n))))) + 1
    prime_list = sieves.primes(B)

    # Choose a multiplier if none is provided.
    if k is None:
        k = _cfrac_multiplier(n)
    kn = k * n

    # Perform simple trial division by the primes we computed to find any
    # small prime divisors.
    for p in prime_list:
        if n % p == 0:
            return p

    # Our factor base needs to include -1 and 2, and the odd primes p for
    # which (kN|p) = 0 or 1.
    factor_base = [-1]
    for p in prime_list:
        if p == 2 or jacobi_symbol(kn, p) >= 0:
            factor_base.append(p)

    num_primes = len(factor_base)

    # Compute the product of the elements in our factor base for smoothness
    # checking computations later.
    prod = 1
    for p in factor_base:
        prod *= p

    # Instead of using trial division to check each value for smoothness
    # individually, we use a batch smoothness test, processing batches of
    # size `batch_size` at once.

    # Set e as the least positive integer with n <= 2**e.
    e = 1
    while 2**e < n:
        e *= 2

    aq_pairs = _cfrac_aq_pairs(kn)

    num_smooths_found = 0
    exponent_matrix = []
    a_list = []

    while num_smooths_found <= num_primes:
        (i, a, q) = aq_pairs.next()

        # This is from the batch smoothness test given as Algorithm 3.3.1
        # in [1].
        if gcd(q, pow(prod, e, q)) != q:
            continue

        if i % 2 == 1:
            q *= -1

        # At this point, we know q is smooth, and we can factor it
        # completely using our factor base.
        exponent_vector = smooth_factor(q, factor_base)
        exponent_matrix.append(exponent_vector)
        num_smooths_found += 1
        a_list.append(a)

    kernel = _z2_gaussian_elimination(exponent_matrix)

    for i in xrange(len(kernel)):
        y = 1
        x2_exponents = [0] * num_primes
        for j in xrange(len(kernel[i])):
            if kernel[i][j]:
                y = (a_list[j] * y) % n
                for f in xrange(num_primes):
                    x2_exponents[f] += exponent_matrix[j][f]

        x = 1
        for j in xrange(num_primes):
            x *= factor_base[j]**(x2_exponents[j] // 2)

        for val in [x - y, x + y]:
            d = gcd(val, n)
            if 1 < d < n:
                return d
Example #31
0
def pollard_rho_brent(n):
    """
    Attempts to find a nontrivial factor of n.

    Given a composite number n, this algorithm attempts to find a nontrivial
    factor of n. The method used is Brent's improvement to the Pollard-Rho
    algorithm.

    Input:
        * n: int (n > 1)

    Output:
        * d: int

    Examples:
        >>> m = 1112470797641561909
        >>> pollard_rho_brent(m)
        1052788969L
        >>> m = 2175282241519502424792841
        >>> pollard_rho_brent(m)
        513741730823L

    Details:
        The algorithm used is Brent's improvement to Pollard's rho factorization
        method. This method should return a nontrivial factor of n in O(sqrt(p))
        steps, where p is the least prime factor of n. Because of this
        dependence on the smallest prime dividing n and not n itself, this
        method is especially useful for large composites with small prime
        factors out of range of trial division. For more details, see the paper
        "An Improved Monte Carlo Factorization Algorithm" by R.P. Brent and
        section 8.5 of "A Course in Computational Algebraic Number Theory" by
        Cohen.
    """
    # c is the constant term of the polynomial
    c = randint(1, n - 3)

    # y is the random seed
    y = randint(0, n - 1)

    # m is the number of terms to multiply together before taking a gcd
    m = 100
    prod = 1
    r = 1

    while True:
        x = y
        for _ in xrange(r):
            y = (y*y + c) % n

        k = 0
        while True:
            ys = y
            for _ in xrange(m):
                y = (y*y + c) % n
                prod = prod*(x - y) % n
            g = gcd(prod, n)
            k += m
            if k >= r or g > 1:
                break

        r *= 2
        if g > 1:
            break

    if g == n:
        while True:
            ys = (ys*ys + c) % n
            g = gcd(x - ys, n)
            if g > 1:
                break
    return g
Example #32
0
    def test_gcd(self):
        self.assertEqual(gcd(20, 10), 10)
        self.assertEqual(gcd(10, 20), 10)

        self.assertEqual(gcd(-10, 20), 10)
        self.assertEqual(gcd(-20, 10), 10)

        self.assertEqual(gcd(-10, -10), 10)

        self.assertEqual(gcd(1, 11213), 1)
        self.assertEqual(gcd(11213, 1), 1)

        self.assertEqual(gcd(0, 10), 10)
        self.assertEqual(gcd(10, 0), 10)
        self.assertEqual(gcd(0, -10), 10)

        values = [
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
            1, 2, 1, 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 2, 1, 4, 1, 2, 1, 4, 1, 2, 1, 4,
            1, 2, 1, 4, 1, 2, 1, 4, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 1, 1, 1, 5, 1, 2, 3, 2, 1, 6, 1, 2,
            3, 2, 1, 6, 1, 2, 3, 2, 1, 6, 1, 2, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4,
            1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 1, 3, 1, 1, 3, 1, 1, 9, 1, 1, 3, 1, 1, 3, 1, 1, 9, 1, 1,
            1, 2, 1, 2, 5, 2, 1, 2, 1, 10, 1, 2, 1, 2, 5, 2, 1, 2, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 1, 2, 3, 4, 1, 6, 1, 4, 3, 2, 1, 12, 1, 2, 3, 4, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
            1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 7, 2, 1, 2, 1, 2, 1, 14, 1, 2, 1, 2, 1, 2, 1, 1, 3, 1, 5, 3,
            1, 1, 3, 5, 1, 3, 1, 1, 15, 1, 1, 3, 1, 5, 1, 2, 1, 4, 1, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 16, 1, 2, 1, 4, 1,
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 2, 3, 2, 1, 6, 1, 2, 9, 2, 1, 6, 1, 2, 3, 2, 1,
            18, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 2, 1, 4, 5, 2, 1, 4, 1, 10, 1, 4,
            1, 2, 5, 4, 1, 2, 1, 20
        ]

        i = 0
        for a in xrange(1, 21):
            for b in xrange(1, 21):
                self.assertEqual(gcd(a, b), values[i])
                i += 1
Example #33
0
def cfrac(n, k=1):
    """
    """
    def find_multiplier():
        """
        Computes a multiplier for input into the cfrac factorization algorithm.

        The method is based on Remark 5.3 from the paper "A Method of Factoring
        and the Factorization of F7" by Morrison and Brillhart.
        """
        choices = {}
        # Look for multpliers in the range [1, 1000).
        for k in xrange(1, 1000):
            if jacobi_symbol(k*n, 3) >= 0 and jacobi_symbol(k*n, 5) >= 0:
                # Find the multiplier k that allows the largest number of primes
                # <= 31 into the factor base.
                count = 0
                for p in prime_list:
                    # We've already looked at p = 3 and p = 5.
                    if p <= 5:
                        continue
                    if p > 31:
                        break
                    if jacobi_symbol(k*n, p) >= 0:
                        count += 1
                if count not in choices:
                    choices[count] = [k]
                else:
                    choices[count].append(k)
        # If several values of k allow this maximal number, we simply choose the
        # smallest of them.
        max_count = max(choices)
        return min(choices[max_count])

    def cfrac_aq_pairs(n):
        """
        Yields tripes (i, A_{i - 1}, Q_i) for i > 0, where
            A_{i - 1}^2 = (-1)^i Q_i (mod n)

        Input:
            * n: int

        Output:
            * X: generator

        Details
            This algorithm expands sqrt(n) into a simple continued fraction. The
            values (i, A_{i - 1}, Q_i) output by this algorithm correspond to
        """
        g = integer_sqrt(n)
        A0, A1 = 0, 1
        Q0, Q1 = n, 1
        P0 = 0
        r0 = g

        for i in itertools.count():
            q = (g + P0)//Q1
            r1 = g + P0 - q*Q1
            A2 = (q*A1 + A0) % n
            P1 = g - r1
            Q2 = Q0 + q*(r1 - r0)

            if i > 0:
                yield (i, A1, Q1)

            A0, A1 = A1, A2
            Q0, Q1 = Q1, Q2
            P0 = P1
            r0 = r1

    # B is our smoothness bound.
    B = int(exp(0.5*sqrt(log(n)*log(log(n))))) + 1
    prime_list = rosemary.number_theory.sieves.primes(B)

    # Choose a multiplier if none is provided.
    if k == 0:
        k = find_multiplier()
    kn = k*n

    # Perform simple trial division by the primes we computed to find any small
    # prime divisors.
    for p in prime_list:
        if n % p == 0:
            return p

    # Our factor base needs to include -1 and 2, and the odd primes p for which
    # (kN|p) = 0 or 1.
    factor_base = [-1]
    for p in prime_list:
        if p == 2 or jacobi_symbol(kn, p) >= 0:
            factor_base.append(p)

    # We compute the product of the elements in our factor base for smoothness
    # checking computations later.
    prod = 1
    for p in factor_base:
        prod *= p

    num_primes = len(factor_base)

    # Instead of using trial division to check each value for smoothness
    # individually, we use a batch smoothness test, processing batches of size
    # 'batch_size' at once.

    exponent_matrix = []
    num_smooths_found = 0
    a_list = []

    max_element = n
    power = 1
    while 2**power < max_element:
        power *= 2

    aq_pairs = cfrac_aq_pairs(kn)

    while num_smooths_found <= num_primes:
        (i, a, q) = aq_pairs.next()

        pp = pow(prod, power, q)
        g = gcd(q, pp)
        if g != q:
            continue

        if i % 2 == 1:
            q *= -1

        exponent_vector = smooth_factor(q, factor_base, num_primes)
        exponent_matrix.append(exponent_vector)
        num_smooths_found += 1
        a_list.append(a)

    kernel = z2_gaussian_elimination(exponent_matrix)

    for i in xrange(len(kernel)):
        y = 1
        x2_exponents = [0]*num_primes
        for j in xrange(len(kernel[i])):
            if kernel[i][j]:
                y = (a_list[j]*y) % n
                for f in xrange(num_primes):
                    x2_exponents[f] += exponent_matrix[j][f]

        x = 1
        for j in xrange(num_primes):
            x *= factor_base[j]**(x2_exponents[j]//2)

        for val in [x - y, x + y]:
            d = gcd(val, n)
            if 1 < d < n:
                return d
Example #34
0
def lehman(n):
    r"""Returns a nontrivial divisor of `n`, or proves primality.

    Given an integer `n` > 1, this algorithm attempts to find a factor of
    `n` using Lehman's method.

    Parameters
    ----------
    n : int (n > 1)

    Returns
    -------
    d : int
        If d == n, then n is proven prime. Otherwise, d is a nontrivial
        divisor of n.

    Notes
    -----
    This algorithm runs in time O(n^(1/3)). This is substantially better
    than O(n^(1/2)) trial division for reasonably small value of n, but
    this algorithm is not suited for large values of n. See section 8.4 of
    [1] or section 5.1.2 of [2] for more details.

    References
    ----------
    .. [1] H. Cohen, "A Course in Computational Algebraic Number Theory",
    Springer-Verlag, New York, 2000.

    .. [2] R. Crandall, C. Pomerance, "Prime Numbers: A Computational
    Perspective", Springer-Verlag, New York, 2001.

    Examples
    --------
    >>> lehman(100)
    2
    >>> lehman(1112470797641561909)
    1056689261L
    """
    # first, we trial divide up to floor(n^(1/3))
    bound = integer_nth_root(3, n)
    d = trial_division(n, bound)
    if d < n:
        return d

    for k in xrange(1, bound + 1):
        if k % 2 == 0:
            r = 1
            m = 2
        else:
            r = k + n
            m = 4
        # we want to iterate over a, where 4*k*n <= a^2 <= 4*k*n + bound^2
        # and a = r (mod m)
        fkn = 4*k*n
        a = integer_sqrt(fkn)
        # now, increase a until a = r (mod m)
        rm = r % m
        while a % m != rm:
            a += 1
        ub = fkn + bound**2
        while fkn <= a*a <= ub:
            c = a*a - fkn
            b = integer_sqrt(c)
            if b*b == c:
                return gcd(a + b, n)
            a += m
    return n