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