2
大学数学基礎解説
文献あり

Baillie-PSW素数判定法

353
0
$$$$

概要

この記事ではbaillie2021strengtheningの記述を基にBaillie-PSW素数判定法について解説する.Baillie-PSW素数判定法とは,底$2$のミラー・ラビン素数判定法とリュカの強素数判定法を組み合わせた手法である.このアルゴリズムは高速であり,擬素数(素数と誤って判定される合成数)の割合が相当少ないことが予想されている.そのため,最近のソフトウェアにおける素数判定法の実装でよく用いられている.

この記事での前提知識は合同式のみである.また,最短で素数判定法にたどり着けるようにするため,証明や細かい話は全て省略している.気になる人は参考文献を参照のこと.

プログラムが載っていなかったり,脚注が増えていたりなど一部内容が異なるが,この記事の原稿となった PDF版 のノートも配布する.

準備

最大公約数

最大公約数

整数$a, b$の最大公約数を$\gcd(a,b)$と書く.

最大公約数はユークリッドの互除法を用いて,計算量$O(\log n)$で計算できる.Pythonでの実装例は次の通りである.

      def gcd(a, b):
    while b:
        a, b = b, a % b
    return a
    

平方剰余とルジャンドル記号,ヤコビ記号

平方剰余

$n$を正の整数とする.法$n$の下で,正の整数$a$平方剰余(quadratic residue)であるとは,合同方程式$x^2 \equiv a \pmod{n}$の解が存在することである.存在しない場合,平方非剰余(quadratic nonresidue)であるという.

たとえば,法$5$の下では
\begin{align*} 1^2\equiv1, \quad 2^2\equiv4, \quad 3^2\equiv4, \quad 4^2\equiv1, \pmod{5} \end{align*}
なので,$1$$4$は平方剰余,$2$$3$は平方非剰余である.

特に法が奇素数のとき,平方剰余は様々な性質を持つ.このことを表すために次の記法を導入する.

ルジャンドル記号

$p$を奇素数とする.正の整数$a$について,

\begin{equation} \left(\frac{a}{p}\right)= \begin{cases}0 & \text { if } \operatorname{gcd}(a, p) \neq 1, \\ +1 & \text { if } a \text { is a quadratic residue,} \\ -1 & \text { if } a \text { is a quadratic nonresidue, }\end{cases} \end{equation}

と定義する.この$(a/p)$ルジャンドル記号(Legendre Symbol)と呼ぶ.

たとえば,$p=5$のとき,
\begin{align*} \left(\frac{1}{5}\right)=1, \quad\left(\frac{2}{5}\right)=-1, \quad\left(\frac{3}{5}\right)=-1, \quad\left(\frac{4}{5}\right)=1, \quad\left(\frac{5}{5}\right)=0, \end{align*}
となる.

ルジャンドル記号は法を奇素数に制限した.それを正の奇数に拡張したものがヤコビ記号である.

ヤコビ記号

$n$を正の奇数とし,$n = \prod_{i=1}^{k} (p_i)^{e_i}$$p_i$は素数)とする.正の整数$a$について,
\begin{align} \left(\frac{a}{n}\right)=\prod_{i=1}^k\left(\frac{a}{p_i}\right)^{e_i}=\left(\frac{a}{p_1}\right)^{e_1}\left(\frac{a}{p_2}\right)^{e_2}\cdots\left(\frac{a}{p_k}\right)^{e_k}, \end{align}
と定義する(右辺はルジャンドル記号である).この$(a/n)$ヤコビ記号(Jacobi Symbol)と呼ぶ.

$n$が奇素数の場合はルジャンドル記号と一致する.ヤコビ記号は最速で計算量$O(M(n)\log n)$で計算できることが知られているbrent2010m.以下,$(a/n)$はヤコビ記号を表すものとする.

アルゴリズムは異なるが,Pythonを使った単純なアルゴリズムの実装例を紹介する.実際に動かしてみるとわかるが,大きい数でも十分高速に動作する.

Jacobi symbol - Rosetta Code

      def jacobi(a, n):
    if n <= 0:
        raise ValueError("'n' must be a positive integer.")
    if n % 2 == 0:
        raise ValueError("'n' must be odd.")
    a %= n
    result = 1
    while a != 0:
        while a % 2 == 0:
            a /= 2
            n_mod_8 = n % 8
            if n_mod_8 in (3, 5):
                result = -result
        a, n = n, a
        if a % 4 == 3 and n % 4 == 3:
            result = -result
        a %= n
    if n == 1:
        return result
    else:
        return 0
    

従来の素数判定法

フェルマーテスト

法が素数のとき,フェルマーの小定理(Fermat's little theorem)という有名な定理が成り立つ.

フェルマーの小定理

$p$を素数とする.$\gcd(a,p)=1$を満たす任意の正の整数$a$について,$a^{p-1} \equiv 1 \pmod{p}$が成り立つ.

一般にフェルマーの小定理の逆は成立しない.実際,
\begin{equation*} 2^{561-1} \equiv 4^{561-1} \equiv \cdots \equiv 1 \pmod{561} \end{equation*}
であるが,$561=3 \times 11 \times 17$は合成数である.このように,$\gcd(a,n)=1$となる任意の整数$a$について,$a^{n-1}\equiv1\pmod{n}$を満たす合成数$n$カーマイケル数(Carmichael's number)と呼び,無数に存在する.実際,$10^{21}$までのカーマイケル数は$20{,}138{,}200$個であるpinch2007carmichael.とはいえ,こういったフェルマーの小定理の逆を満たす合成数が稀であることを期待して,次のような確率的素数判定法が提案された.

フェルマーテスト

正の奇数$n$を素数判定の対象とする.$\gcd(a,n)=1$を満たす正の整数$a$をランダムに選び,$a^{n-1}\not\equiv1\pmod{n}$であれば合成数,そうでなければ底$a$確率的素数 (base-$\boldsymbol{a}$ probable prime)とする.

上述の通り,フェルマーテストを潜り抜ける合成数$n$は無数に存在する.この合成数$n$を判定時の整数$a$を用いて,底$a$擬素数(base-$\boldsymbol{a}$ pseudoprime)という.フェルマーテストは後述の確率的素数判定法と比べると精度が悪いので,実際に用いられることは滅多にない.

Pythonでの実装例は次の通りである.

      import math
import random

def is_prime(n, KMAX=100):
    if n == 1: return False
    if n == 2: return True
    for k in range(KMAX):
        a = random.randint(2, n - 1)
        if math.gcd(n, a) != 1:
            return False
        if pow(a, n - 1, n) != 1:
            return False
    return True
    

ミラー・ラビン素数判定法

ミラー・ラビン素数判定法(Miller-Rabin primality test)は次の定理に基づいた確率的素数判定法である.

$p$が素数であれば,$p-1=2^sd$(ただし,$d$は奇数)と分解でき,$\gcd(a,p)=1$である任意の整数$a$に対して,次のいずれかのことが成り立つ.

  • $a^d \equiv 1 \pmod{p}$が成立する.
  • $a^{2^rd} \equiv -1 \pmod{p}$となる$0 \leq r < s$が存在する.

ミラー・ラビン素数判定法はこの定理の対偶を利用して,合成数を判定する.

ミラー・ラビン素数判定法

正の奇数$n$を素数判定の対象とする.$\gcd(a,n)=1$を満たす正の整数$a$をランダムに選び,$a^d \not\equiv 1 \pmod{n}$かつ任意の整数$r \in [0, s)$について$a^{2^rd} \not\equiv -1 \pmod{n}$であれば合成数と判定する.もし,成り立たなければ,底$a$強確率的素数(base-$\boldsymbol{a}$ strong probable prime)とする.

フェルマーテストと違って「強(strong)」がついているのは,素数の確率がより高いことを意味する.同様に,素数と誤って判定されてしまう合成数$n$を,底$a$強擬素数(base-$\boldsymbol{a}$ strong pseudoprime)という.精度と計算効率の良さから,実用上はミラー・ラビン素数判定法が採用されることが多い.ところが,最近ではこのミラー・ラビン素数判定法と後述のリュカの強素数判定法を組み合わせたBaillie-PSW素数判定法が使われることが増えている.

ミラー・ラビン素数判定法のPythonの実装例を紹介する.

素数判定いろいろ - フェルマーテスト・ミラーラビン素数判定法 #Python - Qiita

      import random

def is_prime(n):
    if n == 2: return True
    if n == 1 or n & 1 == 0: return False
    d = (n - 1) >> 1
    while d & 1 == 0:
        d >>= 1
    for k in range(100):
        a = random.randint(1, n - 1)
        t = d
        y = pow(a, t, n)
        while t != n - 1 and y != 1 and y != n - 1:
            y = (y * y) % n
            t <<= 1
        if y != n - 1 and t & 1 == 0:
            return False
    return True
    

Baillie-PSW素数判定法

リュカ数列とリュカの素数判定法

リュカ数列

整数$D, P, Q$$P>0$, $D = P^2 - 4Q \ne 0$を満たすように選ぶ.$U_0=0, U_1=1, V_0=2, V_1=P$と定義する.パラメータ$(P, Q)$リュカ数列(Lucas Sequences)$\{U_k\}$, $\{V_k\}$ ($k\geq2$) は次の式で再帰的に定義される.
\begin{align} U_k &= PU_{k-1} - QU_{k-2},\\ V_k &= PV_{k-1} - QV_{k-2}. \end{align}

リュカ数列と素数に対して,次の定理が成り立つ.

$p$を素数とする.パラメータ$(P, Q)$のリュカ数列$\{U_k\}, \{V_k\}$に対して,$\gcd(p,Q)=1$であれば,
\begin{align} U_{p-(D/p)} & \equiv 0 \pmod{p}, \\ V_{p-(D/p)} & \equiv 2 Q^{(1-(D / p)) / 2} \pmod{p}, \quad \text { provided } \gcd(p, D)=1, \\ U_p & \equiv(D / p) \pmod{p}, \tag{1}\label{eq:dame1} \\ V_p & \equiv P \pmod{p}, \tag{2}\label{eq:dame2} \end{align}
が成り立つ.もし,$\gcd(p, 2PQD)=1$であれば,これらの合同式のうち2つは他の2つを包含する.

リュカ数列のパラメータを$(D/p)=-1$となるように取ると,この定理は次のように書ける.
\begin{align} U_{p+1} &\equiv 0 \pmod{p}, \tag{3}\label{eq:Uprime}\\ V_{p+1} &\equiv 2Q \pmod{p}.\tag{4}\label{eq:Vprime} \end{align}
式(\ref{eq:Uprime})から,フェルマーテストと同様の論法でリュカの素数判定法を定義する.ちなみに,式(\ref{eq:dame1}), (\ref{eq:dame2})は合成数であっても成立するケースが多いので素数判定では使われない.

リュカの素数判定法

正の奇数$n$を素数判定の対象とする.リュカ数列$\{U_k\}, \{V_k\}$のパラメータを$\gcd(n, Q)=1$かつ$(D/n)=-1$となるように選択する.このとき,$U_{n+1} \not\equiv 0 \pmod{n}$であれば合成数,そうでなければパラメータ$(P,Q)$に対するリュカの確率的素数(Lucas probable prime)とする.

リュカの素数判定法で素数と誤って判定される合成数をリュカの擬素数(Lucas pseudoprime)という.また,$\{V_k\}$の式(\ref{eq:Vprime})についてのリュカの素数判定法で得られる確率的素数をリュカの$V$確率的素数(Lucas-V probable prime)と呼ぶ.これを使うと,計算量を悪化させることなくリュカの素数判定法の判定率を向上できる.しかし,現状はまだ普及していないので,この記事では紹介しない.

リュカの素数判定法におけるパラメータ$(P,Q)$の選び方の一例を紹介する.3つ目のステップが無くても,生成される擬素数は同じである.また,これは後述のリュカの強素数判定法においても同様である.

  • $D$$5, -7, 9, -11, 13, -15, \dots$という数列の中で$(D/n)=-1$を最初に満たす要素として選ぶ.
  • $P=1$, $Q=(1-D)/4$とする.
  • もし,$Q=-1$であれば,$P=Q=5$とする.

この方法を用いた場合,リュカの擬素数は
$$ 323, 377, 1159, 1829, 3827, 5459, 5777, 9071, 9179, 10877,\dots $$

となる.また,$10^{15}$以下のリュカの擬素数は$2{,}402{,}549$個である.

フェルマーテストからミラー・ラビン素数判定法への強化と同じようにして,次の定理を用いてリュカの強確率的素数と強擬素数を定義する.

$p$を素数とし,$p+1=2^sd$(ただし,$d$は奇数)と分解する.リュカ数列$\{U_k\}, \{V_k\}$のパラメータを$\gcd(p,D)=1$かつ$(D/p)=-1$となるように選択する.このとき,次のいずれかのことが成立する.

  • $U_d \equiv 0 \pmod{p}$が成り立つ.
  • $V_{d \cdot 2^r} \equiv 0 \pmod{p}$となる$0 \leq r < s$が存在する.
リュカの強素数判定法

正の奇数$n$を素数判定の対象とする.リュカ数列$\{U_k\}, \{V_k\}$のパラメータを$\gcd(n,D)=1$かつ$(D/n)=-1$となるように選択する.このとき,$U_d \not\equiv 0 \pmod{n}$かつ任意の整数$r\in[0,s)$について$V_{d \cdot 2^r} \not\equiv 0 \pmod{n}$であれば合成数と判定する.もし,成り立たなければ,パラメータ$(P,Q)$に対するリュカの強確率的素数(strong Lucas probable prime)とする.

リュカの強素数判定法をすり抜ける合成数を,パラメータ$(P,Q)$に対するリュカの強擬素数(strong Lucas pseudoprime)と呼ぶ.リュカの素数判定法と同様の方法でパラメータを選択した場合,リュカの強擬素数は
$$ 5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309, 58519, \dots $$
となる.また,$10^{15}$以下のリュカの強擬素数は$474{,}971$個であり,大幅に判定率が改善されていることがわかる.

Baillie-PSW素数判定法

Baillie-PSW素数判定法は,ミラー・ラビン素数判定法とリュカの強素数判定法を組み合わせた手法である.ミラー・ラビン素数判定法における強擬素数と,リュカの強擬素数は異なる数となる傾向がある.すなわち,両方の素数判定法をすり抜ける擬素数は極めて稀ということである.実際,$2^{64}$以下では擬素数が存在しないことが知られている.

Baillie-PSW素数判定法

正の奇数$n$を素数判定の対象とする.

  • $2$のミラー・ラビン素数判定法を行う.合成数であれば終了.
  • リュカの強素数判定法を行う.合成数であれば終了.そうでなければ,確率的素数として終了.

実用上,ミラー・ラビン素数判定法の前にしきい値$k$以下の素数で試し割り法を行うことが多い.また,この素数判定法は非常に効率的なので,多くのソフトウェアではこの方法が採用されているalbrecht2018prime

さきほど,Baillie-PSW素数判定法をすり抜ける合成数が極めて稀と述べたが,実際のところは未解決問題である.ヒューリスティックな解析によると,無数に擬素数は存在すると予想されているが不明であるpomerance1984there.もし,反例を見つけた場合は620ドルの賞金が手に入るようだ.ちなみに,文献によって書いている賞金額が違うので,実際にはもっと少ない可能性がある.baillie2021strengtheningでは620ドル,pomerance1984thereでは120ドルと書かれている.また wikipedia によると,620ドルは別の問題に対する賞金だという指摘もある.

Baillie-PSW素数判定法のPythonの実装例は以下のページを参照のこと.愚直に実装するとリュカ数列の計算量が大変なことになるが,ビット表示して効率的に計算できる.

Baillie-PSW/baillie_psw.py at main · armchaircaver/Baillie-PSW (github.com)

参考文献

[1]
Martin R Albrecht, Jake Massimo, Kenneth G Paterson, and Juraj Somorovsky, Prime and prejudice: primality testing under adversarial conditions, Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications Security, 2018, 281-298
[2]
Robert Baillie, Andrew Fiori, and Samuel Wagstaff Jr, Strengthening the Baillie-PSW primality test, Mathematics of Computation, 2021, 1931-1955
[3]
Robert Baillie and Samuel S Wagstaff, Lucas pseudoprimes, Mathematics of Computation, 1980, 1391-1417
[4]
Richard P Brent and Paul Zimmermann, An O(M(n)log n) algorithm for the Jacobi symbol, International Algorithmic Number Theory Symposium, 2010, 83-95
[5]
RICHARD GE PINCH, THE CARMICHAEL NUMBERS UP TO $10^{21}$, 2007
[6]
Carl Pomerance, Are there counter-examples to the Baillie-PSW primality test, Dopo Le Parole aangeboden aan Dr. AK Lenstra. Privately published Amsterdam, 1981
[7]
William Stein, Elementary number theory: primes, congruences, and secrets: a computational approach, Springer Science & Business Media, 2008
投稿日:229
OptHub AI Competition

この記事を高評価した人

高評価したユーザはいません

この記事に送られたバッジ

バッジはありません。

投稿者

情報系の高専生/音楽と麻雀がそれなりに好きです/量子コンピュータ・情報セキュリティ・機械学習・物理?/CTF:Crypto/Hack The Box:Pro Hacker/JNSA学生賞2023

コメント

他の人のコメント

コメントはありません。
読み込み中...
読み込み中