ミラー–ラビン素数判定法ミラー–ラビン素数判定法(英: Miller–Rabin primality test)またはラビン–ミラー素数判定法(英: Rabin–Miller primality test)は、与えられた数が素数かどうかを判定する素数判定アルゴリズムの一種。フェルマーの素数判定法や ソロベイ–シュトラッセン素数判定法と同じく、乱択アルゴリズムの一種である。Gary L. Miller が最初に開発したMillerテストは未だ証明されていない拡張リーマン予想に基づいた決定的アルゴリズムだったが、マイケル・ラビンがこれを無条件の確率的アルゴリズムに修正した。 概念フェルマーやソロベイ–シュトラッセンの素数判定法と同様、ミラー–ラビン素数判定法も素数に関して成り立つ等式に基づいており、与えられた数についてそれら等式が成り立つかどうかで判定を行う。 まず、有限体 の単位元の平方根についての補題を考える。ここで、p は奇素数である。p を法とした剰余(mod p)において、1と-1の二乗は常に1となる。これらを 1 の「自明な」平方根と呼ぶ。p は素数なので 1 の「自明でない」平方根は存在しない。これを示すため、1 mod p の非自明な平方根を x とする。このとき、以下が成り立つ: pは素数なので、これは または が pで割り切れることを示す。一方、x は 1 でも -1 でもないので(mod p)、 も も p で割り切れない。すなわち、二乗して 1 (mod p)となるのは、1 および -1 だけということになる。 さて、n を 奇素数とするが、一般に n > 2 の奇数の性質として、n − 1 を と表現できる。ここで s は正整数で、d は奇数である。つまり、d は n − 1 を繰り返し 2 で割った結果と同じである。すると、全ての について: または、ある に対して が成立する。 これら合同式のいずれかが真となることを示すため、以下のフェルマーの小定理を利用する: ここで、 であるから、この平方根は上述の補題から 1 または −1 (mod n)である。−1 の場合は後者の合同式が成り立つ。 1 の場合はさらに平方根を考えていくと、上述の補題から 1 または −1 (mod n)となる。一度も −1 (mod n)とならないまま、r = 0 となったとする。 この場合後者の合同式は成立せず、前者の合同式が成立する。 ミラー–ラビン素数判定法は上記の主張の対偶に基づいている。すなわち、整数 n に対し、以下が成り立つ a を見つけたとする。 かつ、任意の に対して すると、n は合成数であり、a は n の合成性の証拠(証人)である。証拠とならない a を「強い嘘つき; strong liar」と呼び、n を底 a についての「強擬素数; strong pseudoprime」と呼ぶ。「強い嘘つき」とは、n が合成数であるのに合同式が成立することによって素数であると嘘をつくことから来ている。 奇数の合成数には、多くの証拠(証人)a がある。しかし、そのような a を生成する単純な方法は知られていない。ミラー–ラビン素数判定法では、 であるような数をランダムに選択し、それが n の合成性の証拠(証人)となりうるかを調べる。n が合成数なら、ほとんどの a は証拠となるので、高い確率で n が合成数であることを検出できる。しかし、不運にも n に対する「強い嘘つき」となる a を選んでしまう可能性も若干ある。この確率を減らすには、いくつかの独立に選んだ a で判定を繰り返す。 アルゴリズムと実行時間このアルゴリズムは次のように表現される:
平方の繰り返しをべき剰余を使って実現すると、このアルゴリズムの実行時間は O(k × log3 n) となる。ここで、k は異なる a で判定を行う回数である。以上から、このアルゴリズムが多項式時間の効率のよいアルゴリズムであることがわかる。FFTベースの乗算によって実行時間を Õ(k × log2 n) まで抑えることができる。 コード例以下に Ruby での本アルゴリズムの実施例を示す。 class Integer
def prime?
n = self.abs()
return true if n == 2
return false if n == 1 || n & 1 == 0
d = n-1
d >>= 1 while d & 1 == 0
20.times do # 20 は上の説明の k に相当
a = rand(n-2) + 1
t = d
y = ModMath.pow(a,t,n) # 実装コードは下にある
while t != n-1 && y != 1 && y != n-1
y = (y * y) % n
t <<= 1
end
return false if y != n-1 && t & 1 == 0
end
return true
end
end
module ModMath
def ModMath.pow(base, power, mod)
result = 1
while power > 0
result = (result * base) % mod if power & 1 == 1
base = (base * base) % mod
power >>= 1;
end
result
end
end
判定の正確度より多くの a で判定を行えば、正確度が高くなる。任意の奇数の合成数 n について、a の少なくとも 3/4 が合成性の証拠となることがわかっている。ミラー–ラビン素数判定法において n についての「強い嘘つき」となる数の集合は、ソロベイ–シュトラッセン素数判定法で嘘つきとなる数の集合の部分集合であり、多くの場合は真部分集合となる。つまり、ミラー–ラビン素数判定法はソロベイ–シュトラッセン素数判定法よりも強力である。n が合成数なのに素数の可能性があると判定してしまう確率は最大で である。一方、ソロベイ–シュトラッセン素数判定法では最大 となる。 合成数を素数に間違ってしまう平均確率は よりずっと小さい。Damgård、Landrock、Pomeranceはこの値を正確に求めたことがある。しかし、そのような確率は素数を生成する際には利用できるが、素性の知れない数の素数判定には依存すべきでない。特に暗号では敵が素数を強擬素数にすり替える可能性を考慮しなくてはならない。従って、 という確率だけを信用すべきである。 決定的アルゴリズムミラー–ラビン素数判定法は、Gary L. Miller が最初に開発したMillerテストをマイケル・ラビンが無条件の確率的アルゴリズムに修正したものである。元となったMillerテストはある限度以下の全ての a を調べるという、未だ証明されていない拡張リーマン予想に基づいた決定的アルゴリズムである。とはいえ拡張リーマン予想全体を必要とするわけではなく、平方ディリクレ指標について拡張リーマン予想が成り立てばよい。 Millerテストは未証明の拡張リーマン予想を必要としていることや、それを修正したミラー–ラビン素数判定法が許容出来る誤判定確率から判定時間を調整でき速度面で有利であることから実際には使われていない。また同じく決定的アルゴリズムであるAKS素数判定法の方が、証明されていない予想に依存していないぶんだけMillerテストよりも強い。 Millerテストには、判定を信頼できるものにするには限度をどう決めたらよいかという問題がある。 判定対象の数 n が合成数なら、n と互いに素な「強い嘘つき」の a は群 の真の部分群に含まれる。つまり の生成元集合の全 a について判定するとき、その中には必ず n の合成性の証拠となる数が含まれる。拡張リーマン予想が真であると仮定すると、ミラーが既に指摘したように O((ln n)2) より小さい元から、この集合が生成されることがわかっている。big O記法の定数は Eric Bach によって 2 まで減らされた(1990年)。このことから、次のような素数判定アルゴリズムが導かれる:
このアルゴリズムの実行時間は Õ((log n)4) である。 判定対象の数 n が十分小さければ、全ての a < 2(ln n)2 を調べる必要はなく、もっと小さい証拠の可能性のある数の集合で十分である。例えば、Jaeschke (1993) は以下を検証した。
もちろん、a < n の場合だけ調べる。この種の基準については [1] を参照されたい。このような結果を活用することで、ある範囲の数については非常に高速で決定的な素数判定が可能である。 しかし、全ての合成数についてはこのような有限の集合では不十分である。Alford、Granville、Pomerance は、合成数 n について合成性の証拠となる最小の数が より大きい合成数が無数に存在する、X が十分大きいときには X 以下のそのような合成数の個数は少なくともであることを示した。また彼らはヒューリスティック的に、w 以下の合成性の証拠となる数のある n 以下の合成数について w のオーダーを であると示唆した。 参考文献
外部リンク |