def test_valuation(self): values = [ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 1, 3, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 1, 0, 6, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, 0, 1, 2, 0, 2, 0, 0 ] i = 0 for a in xrange(2, 101): for p in [2, 3, 5, 7, 11]: self.assertEqual(valuation(p, a), values[i]) i += 1
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 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