である。
と表せる。
このとき、次の定理が成り立つ。
各変数を上のように定義したとき、
または
が成り立つ。
以下これを示す。
そういうものがない場合、
となるので
これの対偶を取ると、
かつ
ならば、
がいえる。
定理②を用いて確率的な素数判定をするものが Miller–Rabin 素数判定法である。
具体的には、
-
$n-1$ を$2$ の冪$2^s$ と奇数$d$ の積に分解する - 以下の試行を何回か繰り返す
- 正整数
$0 < a \le n-1$ をランダムに選ぶ -
$a$ と$n$ が互いに素でないなら$n$ は合成数。終了 - 上の条件
$\mathrm{(c)}, \mathrm{(d)}$ をともに満たす場合、$n$ は合成数。終了 - i. に戻る
- 正整数
- 試行に引っかからなかった場合、
$n$ は確率的素数である。終了
ここで、定理②の逆は成り立たない。つまり
しかし
/**
* Miller-Rabin 素数判定法 (n < 2^64 の場合決定的に判定)
* @param {bigint} n_ 判定したい整数
*/
const millerRabin = (n_) => {
if (typeof n_ !== 'bigint') throw TypeError('引数型は \`bigint\` でなければなりません');
if (n_ < 0n) throw Error('引数は正の整数でなければなりません');
const n = n_;
if (n === 2n) return true;
if (n === 1n || n % 2n === 0n) return false;
const bit_num = n.toString(2).length;
const s = BigInt((n - 1n).toString(2).match(/0+$/g)?.[0].length ?? 0);
const d = (n - 1n) >> s;
if (n < 2n ** 64n) {
/** n が 2^64 未満の時、決定的に判定できる 参考: https://miller-rabin.appspot.com/#bases7 */
const bases_under_64 = Object.freeze([2n, 325n, 9375n, 28178n, 450775n, 9780504n, 1795265022n]);
challenge: for (const b_ of bases_under_64) {
const base = (b_ >= n) ? b_ % n : b_;
if (base === 0n) continue challenge;
if (exEuclidean(base, n).gcd != 1n) return false;
let y = modPow(base, d, n);
if (y === 1n) continue challenge;
for (let i = 0n; i < s; i++) {
if (y === n - 1n) continue challenge;
y = y * y % n;
}
return false;
}
return true;
} else {
/** 試行回数 */
const max_rot = 40;
challenge2: for (let i = 0; i < max_rot; i++) {
let b_ = 0n;
while (b_ < 2n || b_ >= n) {
b_ = getRandBI(bit_num); // 2以上n未満の乱数を取得
}
// 最大公約数が1でない (互いに素でない) なら合成数
if (exEuclidean(b_, n).gcd !== 1n) return false;
const base = b_;
let y = modPow(base, d, n);
if (y === 1n) continue challenge2;
for (let i = 0n; i < s; i++) {
if (y === n - 1n) continue challenge2;
y = y * y % n;
}
return false;
}
return true;
}
}