def test_inverse_mod(self): self.assertRaisesRegexp(ValueError, "inverse_mod: Integers must be relatively prime.", inverse_mod, 2, 4) self.assertRaisesRegexp(ValueError, "inverse_mod: Must have m >= 2.", inverse_mod, 10, 1) self.assertEqual(inverse_mod(5, 17), 7) self.assertEqual(inverse_mod(2, 9), 5) for k in xrange(1, 101): a = inverse_mod(k, 101) self.assertEqual(a*k % 101, 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 hensel(a, r, p, k): """ Lifts solution r^2 = a (mod p^k) to solutions modulo p^{k + 1}. """ solutions = [] if 2*r % p != 0: # In this case, r lifts to a unique solution. inverse = inverse_mod(2*r, p) # Note that r^2 = a (mod p^k) so the division below is exact. t = (-inverse*((r*r - a)//p**k)) % p root = r + t*p**k solutions.append(root) else: # Here, r lifts to p incongruent solutions modulo p^k. if (r*r - a) % (p**(k + 1)) == 0: for t in xrange(p): root = r + t*p**k solutions.append(root) solutions.sort() return solutions
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 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 _quadratic_lift(a, r, p, k): """Lifts a solution v to the congruence r**2 = a (mod p**k) to solutions modulo p**(k + 1). Suppose that for some k >= 1 we have an integer r satisfying r**2 = a (mod p**k). This function returns all solutions q satisfying q**2 = a (mod p**(k + 1)). Input: * a: int * r: int The root the the congruence r**2 = a (mod p**k). * p: int (p >= 2) A prime p, the primality of which is not verified. * k: int (k >= 1) The exponent such that r**2 = a (mod p**k). Returns: * solutions: list A list of all solutions c to the congruence c**2 = a (mod p**(k + 1)) Raises: * ValueError: if k < 1 or p < 2 or r**2 != a (mod p**k). Examples: >>> 5154**2 % 11213 119 >>> _quadratic_lift(119, 5154, 11213, 1) [5869553] >>> 5869553**2 % 11213**2 119 >>> _quadratic_lift(0, 0, 7, 1) [0, 7, 14, 21, 28, 35, 42] Details: This function uses a simple form of Hensel lifting to obtain solutions modulo higher powers. See Section 12.5.2 of "A Computational Introduction to Number Theory and Algebra" by Shoup for details. See also Section 15.1 of "Introduction to Number Theory" by Hua and Theorem 2.24 in "Fundamental Number Theory with Applications" by Mollin. """ if k < 1: raise ValueError("_quadratic_lift: Must have k >= 1.") if p < 2: raise ValueError("_quadratic_lift: Must have p >= 2.") if (r * r - a) % p**k != 0: raise ValueError("_quadratic_lift: Must have r**2 = a (mod p**k).") solutions = [] if 2 * r % p != 0: # In this case, r lifts to a unique solution. inverse = inverse_mod(2 * r, p) # Note that r**2 = a (mod p**k) so the division below is exact. t = (-inverse * ((r * r - a) // p**k)) % p root = r + t * p**k solutions.append(root) else: # Here, r lifts to p incongruent solutions modulo p**k. if (r * r - a) % (p**(k + 1)) == 0: for t in xrange(p): root = r + t * p**k solutions.append(root) solutions.sort() return solutions
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 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 _quadratic_lift(a, r, p, k): """Lifts a solution v to the congruence r**2 = a (mod p**k) to solutions modulo p**(k + 1). Suppose that for some k >= 1 we have an integer r satisfying r**2 = a (mod p**k). This function returns all solutions q satisfying q**2 = a (mod p**(k + 1)). Input: * a: int * r: int The root the the congruence r**2 = a (mod p**k). * p: int (p >= 2) A prime p, the primality of which is not verified. * k: int (k >= 1) The exponent such that r**2 = a (mod p**k). Returns: * solutions: list A list of all solutions c to the congruence c**2 = a (mod p**(k + 1)) Raises: * ValueError: if k < 1 or p < 2 or r**2 != a (mod p**k). Examples: >>> 5154**2 % 11213 119 >>> _quadratic_lift(119, 5154, 11213, 1) [5869553] >>> 5869553**2 % 11213**2 119 >>> _quadratic_lift(0, 0, 7, 1) [0, 7, 14, 21, 28, 35, 42] Details: This function uses a simple form of Hensel lifting to obtain solutions modulo higher powers. See Section 12.5.2 of "A Computational Introduction to Number Theory and Algebra" by Shoup for details. See also Section 15.1 of "Introduction to Number Theory" by Hua and Theorem 2.24 in "Fundamental Number Theory with Applications" by Mollin. """ if k < 1: raise ValueError("_quadratic_lift: Must have k >= 1.") if p < 2: raise ValueError("_quadratic_lift: Must have p >= 2.") if (r*r - a) % p**k != 0: raise ValueError("_quadratic_lift: Must have r**2 = a (mod p**k).") solutions = [] if 2*r % p != 0: # In this case, r lifts to a unique solution. inverse = inverse_mod(2*r, p) # Note that r**2 = a (mod p**k) so the division below is exact. t = (-inverse*((r*r - a)//p**k)) % p root = r + t*p**k solutions.append(root) else: # Here, r lifts to p incongruent solutions modulo p**k. if (r*r - a) % (p**(k + 1)) == 0: for t in xrange(p): root = r + t*p**k solutions.append(root) solutions.sort() return solutions