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_multiplier(n): r"""Computes a multiplier for input into the cfrac algorithm. Parameters ---------- n : int Integer to be factored. Returns ------- k : int Multiplier for the cfrac algorithm. Notes ----- The continued fraction of sqrt(n) is always periodic. In the cases where the period of sqrt(n) is too short, it is necessary to expand sqrt(k*n) for some k > 1. We choose the multiplier `k` which allows th elargest number of primes <= 31 to be in the factor base. The method follows Remark 5.3 of [1]. References ---------- .. [1] M.A. Morrison, J. Brillhart, "A Method of Factoring and the Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129, Jan. 1975. Examples -------- >>> _cfrac_multiplier(5**77 - 1) 781 """ prime_list = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31] 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 = sum(1 for p in prime_list if jacobi_symbol(k*n, p) >= 0) 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_multiplier(n): r"""Computes a multiplier for input into the cfrac algorithm. Parameters ---------- n : int Integer to be factored. Returns ------- k : int Multiplier for the cfrac algorithm. Notes ----- The continued fraction of sqrt(n) is always periodic. In the cases where the period of sqrt(n) is too short, it is necessary to expand sqrt(k*n) for some k > 1. We choose the multiplier `k` which allows th elargest number of primes <= 31 to be in the factor base. The method follows Remark 5.3 of [1]. References ---------- .. [1] M.A. Morrison, J. Brillhart, "A Method of Factoring and the Factorization of F7", Mathematics of Computation, Vol. 29, Num. 129, Jan. 1975. Examples -------- >>> _cfrac_multiplier(5**77 - 1) 781 """ prime_list = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31] 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 = sum(1 for p in prime_list if jacobi_symbol(k * n, p) >= 0) 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 solovay_strassen(n, a=None): r"""Determines if `n` is a probable prime. Parameters ---------- n : positive integer Returns ------- b : boolean Returns the value True if `n` is a probable prime, and False otherwise. See Also -------- miller_rabin, solovay_strassen_deterministic, is_probable_prime Notes ----- This method uses the Solovay Strassen test to determine the compositeness of `n`. The test is based on the relationship ``a^((p - 1)/2) = (a | p) (mod p)`` proven by Euler, where ``(a | p)`` is the Jacobi symbol, `p` is prime, and ``gcd(a, p) == 1``. The Solovay Strassen test computes this for a random base `a` Since this is an identity for primes, this method always returns True when `n` is prime. On the other hand, for odd composite `n`, this test returns False for at least half of all `a` coprime to `n`. Thus, the likelihood of returning True for a composite number is less than 1/2. This idea may be used to create a more accurate compositeness test, and may even be generalized to a deterministic primality test, pending the Extended Riemann Hypothesis. References ---------- .. [1] Bach, Shallitt, "Algorithmic Number Theory", MIT Press, Cambridge, MA, 1996 Examples -------- >>> solovay_strassen(341, 2) False >>> solovay_strassen(341, 29) True """ if a is None: a = randint(2, n - 2) jacobi = jacobi_symbol(a, n) if jacobi == 0 or jacobi % n != pow(a, (n - 1) // 2, n): return False return True
def test_jacobi_symbol(self): values = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1, 1, 0, 1, -1, 0, -1, -1, 0, -1, 1, 1, 1, -1, 0, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, -1, 1, -1, 1, 0, -1, -1, 1, -1, 1, 1, 1, 0, -1, -1, -1, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, -1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, 0, 1, 1, 1, -1, -1, -1, 1, 0, 0, 1, 0, 1, -1, 0, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 0, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1 ] i = 0 for a in xrange(1, 21): for b in xrange(1, 21, 2): self.assertEqual(jacobi_symbol(a, b), values[i]) i += 1
def test_jacobi_symbol(self): self.assertRaisesRegexp(ValueError, "jacobi_symbol: Must have m odd.", jacobi_symbol, 19, 4) values = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1, 1, 0, 1, -1, 0, -1, -1, 0, -1, 1, 1, 1, -1, 0, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, -1, 1, -1, 1, 0, -1, -1, 1, -1, 1, 1, 1, 0, -1, -1, -1, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, -1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, 0, 1, 1, 1, -1, -1, -1, 1, 0, 0, 1, 0, 1, -1, 0, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 0, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1 ] i = 0 for a in xrange(1, 21): for b in xrange(1, 21, 2): self.assertEqual(jacobi_symbol(a, b), values[i]) i += 1
def test_jacobi_symbol(self): self.assertRaisesRegexp(ValueError, "jacobi_symbol: Must have m odd.", jacobi_symbol, 19, 4) values = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1, 1, 0, 1, -1, 0, -1, -1, 0, -1, 1, 1, 1, -1, 0, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, -1, 1, -1, 1, 0, -1, -1, 1, -1, 1, 1, 1, 0, -1, -1, -1, 1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 1, 1, -1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, 0, 1, 1, 1, -1, -1, -1, 1, 0, 0, 1, 0, 1, -1, 0, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 0, 1, -1, 0, -1, 1, 1, -1, 0, -1, 1 ] i = 0 for a in xrange(1, 21): for b in xrange(1, 21, 2): self.assertEqual(jacobi_symbol(a, b), values[i]) i += 1
def fibonacci_primitive_roots(p): """Returns a sorted list of the Fibonacci primitive roots mod p. Input: * p: int A prime number. The primality of p is not verified. Returns: * roots: list This is a list of the Fibonacci primitive roots mod p. This list will contain no more than 2 elements. Examples: >>> fibonacci_primitive_roots(11) [8] >>> fibonacci_primitive_roots(19) [15] >>> fibonacci_primitive_roots(41) [7, 35] Details: A Fibonacci primitive root mod p is a primitive root satisfying g**2 = g + 1. These can only exist for primes p = 1, 9 (mod 10). See the paper "Fibonacci Primitive Roots" by Shanks for details. """ if p % 2 == 0: return [] if p == 5: return [3] if p < 5 or jacobi_symbol(5, p) != 1: return [] sqrts = sqrts_mod_p(5, p) inverse = inverse_mod(2, p) quad_roots = [(1 + root) * inverse % p for root in sqrts] phi_divisors = factor.prime_divisors(p - 1) roots = [] for r in quad_roots: if is_primitive_root(r, p, phi=p - 1, phi_divisors=phi_divisors): roots.append(r) return sorted(roots)
def fibonacci_primitive_roots(p): """Returns a sorted list of the Fibonacci primitive roots mod p. Input: * p: int A prime number. The primality of p is not verified. Returns: * roots: list This is a list of the Fibonacci primitive roots mod p. This list will contain no more than 2 elements. Examples: >>> fibonacci_primitive_roots(11) [8] >>> fibonacci_primitive_roots(19) [15] >>> fibonacci_primitive_roots(41) [7, 35] Details: A Fibonacci primitive root mod p is a primitive root satisfying g**2 = g + 1. These can only exist for primes p = 1, 9 (mod 10). See the paper "Fibonacci Primitive Roots" by Shanks for details. """ if p % 2 == 0: return [] if p == 5: return [3] if p < 5 or jacobi_symbol(5, p) != 1: return [] sqrts = sqrts_mod_p(5, p) inverse = inverse_mod(2, p) quad_roots = [(1 + root)*inverse % p for root in sqrts] phi_divisors = factor.prime_divisors(p - 1) roots = [] for r in quad_roots: if is_primitive_root(r, p, phi=p - 1, phi_divisors=phi_divisors): roots.append(r) return sorted(roots)
def fibonacci_primitive_roots(p): """ Returns a list of the Fibonacci primitive roots mod p. A Fibonacci primitive root mod p is a primitive root satisfying g^2 = g + 1. These can only exist for primes p = 1, 9 (mod 10). Input: * p: int A prime number. The primality of p is not verified. Output: * roots: list This is a list of the fibonacci primitive roots mod p. This list will contain no more than 2 elements. Examples: >>> fibonacci_primitive_roots(11) [8] >>> fibonacci_primitive_roots(19) [15] >>> fibonacci_primitive_roots(41) [7, 35] """ if p % 2 == 0: return [] if p == 5: return [3] if p < 5 or jacobi_symbol(5, p) != 1: return [] sqrts = sqrts_mod_p(5, p) inverse = inverse_mod(2, p) roots = [(1 + root)*inverse % p for root in sqrts] prime_divisors = rosemary.number_theory.factorization.prime_divisors(p - 1) primitive_roots = [] for r in roots: if is_primitive_root(r, p, prime_divisors): primitive_roots.append(r) return primitive_roots
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 sqrts_mod_p(a, p): """Returns the solutions x to x**2 = a (mod p). Given a prime p and an integer a, this function returns a sorted list of all solutions to the congruence x**2 = a (mod p). Input: * a: int * p: int (p >= 2) The prime modulus. The primality of p is not verified. Returns: * solutions: list A sorted list of solutions to x**2 = a (mod p). Raises: * ValueError: if p < 2. Examples: >>> sqrts_mod_p(10, 13) [6, 7] >>> sqrts_mod_p(3615, 2**16 + 1) [367, 65170] >>> a = 552512556430486016984082237 >>> sqrts_mod_p(a, 2**89 - 1) [1000000000000000000L, 618970018642690137449562111L] >>> sqrts_mod_p(10, 1) Traceback (most recent call last): ... ValueError: sqrts_mod_p: Must have p >= 2 be prime. Details: This function uses the algorithm due to Tonelli and Shanks. One problem that must be solved in this algorithm is that of finding a quadratic nonresidue d (mod p). There is no known efficient deterministic algorithm to do this, so we use a randomized algorithm to find such a d. This gives the algorithm of Tonelli and Shanks an expected runtime of O(log(p)**4). Our implementation follows the description given as Algorithm 2.3.8 in "Prime Numbers - A Computational Perspective" by Crandall and Pomerance. See also Section 7.1 of "Algorithmic Number Theory - Efficient Algorithms" by Bach and Shallit. For information about some of the optimizations made, see Section 1.5 of "A Course in Computational Algebraic Number Theory" by Cohen. """ # We don't test the primality of p, but we do some simple error detection. if p < 2: raise ValueError("sqrts_mod_p: Must have p >= 2 be prime.") # The easy case is when p == 2. if p == 2: return [a % p] # Take care of the case when p | a. a = a % p if a == 0: return [0] # No solutions if a is not a square modulo p. if jacobi_symbol(a, p) != 1: return [] # Below, p is odd, so we use Tonelli-Shanks. # Half of the time, there is an easy solution. Namely, for primes # p = 3 (mod 4) a solution is given by x = a**((p + 1)/4) (mod p). if p % 8 in (3, 7): x = pow(a, (p + 1) // 4, p) # A slightly less trivial solution works for half of the remaining primes. # For p = 5 (mod 8), one can verify that a**((p - 1)/4) = 1, -1 (mod p). In # the positive case, then x = a**((p + 3)//8) (mod p) is a solution. elif p % 8 == 5: x = pow(a, (p + 3) // 8, p) if x * x % p != a: x = x * pow(2, (p - 1) // 4, p) % p # The remaining case is p = 1 (mod 8). else: # Find a quadratic nonresidue. Each choice of d will be a quadratic # nonresidue with probability close to 1/2, so we expect to find one # very quickly. d = randint(2, p - 1) while jacobi_symbol(d, p) != -1: d = randint(2, p - 1) # Write p - 1 = 2**s * t with t odd s = valuation(2, p - 1) t = (p - 1) >> s A = pow(a, t, p) D = pow(d, t, p) m = 0 for i in xrange(s): if pow(A * D**m, 2**(s - 1 - i), p) == p - 1: m += 2**i x = pow(a, (t + 1) // 2, p) * pow(D, m // 2, p) % p # We want both solutions. solutions = sorted([x, p - x]) return solutions
def sqrts_mod_p(a, p): """ Returns a solution x to x^2 = a (mod p). Given a prime p and an integer a, this function returns all solutions to the congruence x^2 = a (mod p). Input: * a: int * p: int Output: * solutions: list Examples: >>> sqrts_mod_p(10, 13) [6, 7] Details: For odd primes p, this function uses the algorithm due to Tonelli and Shanks. See Algorithm 2.3.8 in "Prime Numbers - A Computational Perspective" by Crandall and Pomerance for details of the algorithm. For p = 2, simple checking is done to find solutions. """ if p == 2: return [a % p] a = a % p if a == 0: return [0] if jacobi_symbol(a, p) != 1: return [] if p % 8 in (3, 7): x = pow(a, (p + 1)//4, p) elif p % 8 == 5: x = pow(a, (p + 3)//8, p) if x*x % p != a: x = x*pow(2, (p - 1)//4, p) % p else: # Find a quadratic nonresidue d = randint(2, p - 1) while jacobi_symbol(d, p) != -1: d = randint(2, p - 1) # Write p - 1 = 2^s * t with t odd s = valuation(2, p - 1) t = (p - 1) >> s A = pow(a, t, p) D = pow(d, t, p) m = 0 for i in xrange(s): if pow(A*D**m, 2**(s - 1 - i), p) == p - 1: m += 2**i x = pow(a, (t + 1)//2, p)*pow(D, m//2, p) % p solutions = [x, p - x] solutions.sort() return solutions
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 sqrts_mod_p(a, p): """Returns the solutions x to x**2 = a (mod p). Given a prime p and an integer a, this function returns a sorted list of all solutions to the congruence x**2 = a (mod p). Input: * a: int * p: int (p >= 2) The prime modulus. The primality of p is not verified. Returns: * solutions: list A sorted list of solutions to x**2 = a (mod p). Raises: * ValueError: if p < 2. Examples: >>> sqrts_mod_p(10, 13) [6, 7] >>> sqrts_mod_p(3615, 2**16 + 1) [367, 65170] >>> a = 552512556430486016984082237 >>> sqrts_mod_p(a, 2**89 - 1) [1000000000000000000L, 618970018642690137449562111L] >>> sqrts_mod_p(10, 1) Traceback (most recent call last): ... ValueError: sqrts_mod_p: Must have p >= 2 be prime. Details: This function uses the algorithm due to Tonelli and Shanks. One problem that must be solved in this algorithm is that of finding a quadratic nonresidue d (mod p). There is no known efficient deterministic algorithm to do this, so we use a randomized algorithm to find such a d. This gives the algorithm of Tonelli and Shanks an expected runtime of O(log(p)**4). Our implementation follows the description given as Algorithm 2.3.8 in "Prime Numbers - A Computational Perspective" by Crandall and Pomerance. See also Section 7.1 of "Algorithmic Number Theory - Efficient Algorithms" by Bach and Shallit. For information about some of the optimizations made, see Section 1.5 of "A Course in Computational Algebraic Number Theory" by Cohen. """ # We don't test the primality of p, but we do some simple error detection. if p < 2: raise ValueError("sqrts_mod_p: Must have p >= 2 be prime.") # The easy case is when p == 2. if p == 2: return [a % p] # Take care of the case when p | a. a = a % p if a == 0: return [0] # No solutions if a is not a square modulo p. if jacobi_symbol(a, p) != 1: return [] # Below, p is odd, so we use Tonelli-Shanks. # Half of the time, there is an easy solution. Namely, for primes # p = 3 (mod 4) a solution is given by x = a**((p + 1)/4) (mod p). if p % 8 in (3, 7): x = pow(a, (p + 1)//4, p) # A slightly less trivial solution works for half of the remaining primes. # For p = 5 (mod 8), one can verify that a**((p - 1)/4) = 1, -1 (mod p). In # the positive case, then x = a**((p + 3)//8) (mod p) is a solution. elif p % 8 == 5: x = pow(a, (p + 3)//8, p) if x*x % p != a: x = x*pow(2, (p - 1)//4, p) % p # The remaining case is p = 1 (mod 8). else: # Find a quadratic nonresidue. Each choice of d will be a quadratic # nonresidue with probability close to 1/2, so we expect to find one # very quickly. d = randint(2, p - 1) while jacobi_symbol(d, p) != -1: d = randint(2, p - 1) # Write p - 1 = 2**s * t with t odd s = valuation(2, p - 1) t = (p - 1) >> s A = pow(a, t, p) D = pow(d, t, p) m = 0 for i in xrange(s): if pow(A*D**m, 2**(s - 1 - i), p) == p - 1: m += 2**i x = pow(a, (t + 1)//2, p)*pow(D, m//2, p) % p # We want both solutions. solutions = sorted([x, p - x]) return solutions
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