def tonelli(a,p): # Return x with x^2 == a mod p (-1 if no x) # Pre: a >= 0, p odd prime # Post: 0 <= x < p, x*x == a mod p (return -1 if no such x) if a % p == 0: return 0 if legendre(a,p) != 1: return -1 d = 1 while d <= 1 or legendre(d,p) != -1: d = int(random.random() * p) % p # Represent p-1 == 2^s t t = p-1 s = 0 while (t % 2) == 0: t //= 2 s += 1 A = mod_pow(a, t, p) D = mod_pow(d, t, p) m = 0 for i in range(0,s): ADm = (A * mod_pow(D, m, p)) % p q = ADm for j in range(s-i-1): q = (q * q) % p if(q == p-1): m += 2**i x = (mod_pow(a, (t+1)//2, p) * mod_pow(D, m//2, p)) % p return x
def legendre(a,p): # Return Legendre symbol (a|p): either 0, 1, or -1 # Pre: a >= 0, p odd prime l = mod_pow(a % p, (p-1)//2, p) return [l, -1][l == p-1]