square roots modulo a prime
概要
ある奇素数 \(p\) と \(p\) の平方剰余(Quadratic residue) となる \(y\) について \(x^2 \equiv y\) (mod \(p\)) となる \(x\) を求めるアルゴリズム。
具体的な計算
\(p-1 = 2^mQ\) とする。(\(m \ge 0\), \(Q\) は奇数)
まず平方非剰余となる \(z\) を一つ見つける。 (平方非剰余となる数は1からp-1の間に半分は存在する)
この \(z\) は オイラーの規準(Euler’s criterion) より \(z^\frac{p-1}{2} \equiv z^{2^{m-1}Q} \equiv -1\) を満たす。
\(t \equiv y^Q\) とする。この \(t\) はオイラーの規準 より \(t^{2^{m-1}} \equiv 1\) を満たす。
\(i = m-2\) から 0 まで \(i\) を小さくしながら
\(t^{2^i} \equiv -1\) を満たす \(i\) を見つけるたびに \(t\) に \(z^{2^{m-1-i}Q}\) を掛ける。
(この時、掛けたあとの \(t\) は \(t^{2^i} \equiv 1\) を満たす)
最終的に \(t\) は \(\displaystyle t \equiv y^Q z^{2^{j_1}Q} z^{2^{j_2}Q} \cdots z^{2^{j_k}Q} \equiv 1\) \((1 \le j_1 < j_2 < ... < j_k \le m-1)\) の形になるため、
\(\displaystyle x \equiv (ty)^\frac{1}{2} \equiv y^\frac{Q+1}{2} z^{2^{j_1-1}Q} z^{2^{j_2-1}Q} \cdots z^{2^{j_k-1}Q}\) を計算することで解が得られる。
実装
import random
random.seed()
def square_root(n, p):
n %= p
if pow(n, (p-1)>>1, p) != 1:
return -1
q = p-1; m = 0
while q & 1 == 0:
q >>= 1
m += 1
z = random.randint(1, p-1)
while pow(z, (p-1)>>1, p) == 1:
z = random.randint(1, p-1)
c = pow(z, q, p)
t = pow(n, q, p)
r = pow(n, (q+1)>>1, p)
if t == 0:
return 0
m -= 2
while t != 1:
while pow(t, 2**m, p) == 1:
c = c * c % p
m -= 1
r = r * c % p
c = c * c % p
t = t * c % p
m -= 1
return r
print(square_root(67, 73))
# => "33" or "40"
print(square_root(4, 37))
# => "2" or "35"
print(square_root(6, 37))
# => "-1"
# (12603242261242278713399181313 - 1) = 2^66 * 3 * 17 * 83 * 40351
print(square_root(32189, 12603242261242278713399181313))
# => "4979547606364809208986559660" or "7623694654877469504412621653"
参考
-
和田秀男. 「コンピュータと素因数分解」. 遊星社, 1987.