Home
Blog
Products
Profile
Study
Collatz
© 2024 Oizumi Yuta

p - 1 法の仕組み

2025-1-11

今までの検証でわかったことをまとめる。

p−1p - 1p−1 法とは

素因数分解のアルゴリズム。合成数 nnn の素因数の 1 つを ppp とするとき、p−1p - 1p−1 が小さな素数たちの積であるとき高速に ppp を見つけることができる。

アルゴリズム

nnn を合成数とする。正の整数 a, ka,\ ka, k を選び、最大公約数

d:=gcd⁡(ak−1, n)d := \gcd(a^k - 1,\ n)d:=gcd(ak−1, n)

を計算する。1<d<n1 \lt d \lt n1<d<n のとき、nnn の非自明な約数を得ることができたため成功、d=1d = 1d=1 または d=nd = nd=n のとき失敗である。

例

  • n=15n = 15n=15

a=2, k=1a = 2,\ k = 1a=2, k=1 のとき

d=gcd⁡(21−1, 15)=1d = \gcd(2^1 - 1,\ 15) = 1d=gcd(21−1, 15)=1

結果: 失敗

>>> from math import gcd
>>> gcd(2 ** 1 - 1, 15)
1

a=2, k=2a = 2,\ k = 2a=2, k=2 のとき

d=gcd⁡(22−1, 15)=3d = \gcd(2^2 - 1,\ 15) = 3d=gcd(22−1, 15)=3

結果: 成功

>>> from math import gcd
>>> gcd(2 ** 2 - 1, 15)
3

a=2, k=3a = 2,\ k = 3a=2, k=3 のとき

d=gcd⁡(23−1, 15)=1d = \gcd(2^3 - 1,\ 15) = 1d=gcd(23−1, 15)=1

結果: 失敗

>>> from math import gcd
>>> gcd(2 ** 3 - 1, 15)
1

a=2, k=4a = 2,\ k = 4a=2, k=4 のとき

d=gcd⁡(24−1, 15)=15d = \gcd(2^4 - 1,\ 15) = 15d=gcd(24−1, 15)=15

結果: 失敗

>>> from math import gcd
>>> gcd(2 ** 4 - 1, 15)
15
aaakkkddd結果
222111111失敗
222222333成功
222333111失敗
222444151515失敗

解説

p−1p - 1p−1 法で素因数を見つけることができる理由を解説する。そのために実際に素因数が見つかった場合に着目する。

p=gcd⁡(ak−1, n)p = \gcd(a^k - 1,\ n)p=gcd(ak−1, n)

とする。このとき ak≡1(modp)a^k\equiv 1\pmod{p}ak≡1(modp) である。一方フェルマーの小定理により ppp が整数 aaa を割らなければ ap−1≡1(modp)a^{p - 1} \equiv 1\pmod{p}ap−1≡1(modp) である。フェルマーの小定理の逆は成り立たないため、この合同式から p−1∣kp - 1\mid kp−1∣k かどうかはわからない。しかし kkk を大きくしていけば、そのうち p−1∣kp - 1\mid kp−1∣k となる。

ただし kkk が大きくなりすぎると、nnn のほかの素因数 qqq に対しても q−1∣kq - 1\mid kq−1∣k となる場合がある。もし n=pqn = pqn=pq の場合、ak≡1(modp)a^k \equiv 1\pmod{p}ak≡1(modp) かつ ak≡1(modq)a^k \equiv 1\pmod{q}ak≡1(modq) となり、n=gcd⁡(ak−1, n)n = \gcd(a^k - 1,\ n)n=gcd(ak−1, n) となってしまい失敗する。この場合、kkk を大きくする速さを緩やかにするか、aaa を取り換える。

gcd⁡(ak−1, n)=1\gcd(a^k - 1,\ n) = 1gcd(ak−1, n)=1 となる場合、ppp が ak−1a^k - 1ak−1 を割ることができるほど kkk が大きくないため kkk を大きくする必要がある。

:::note warn 注意 a∈(Z/pZ)×a\in \left(\mathbb{Z}/p\mathbb{Z}\right)^\timesa∈(Z/pZ)× の位数が小さい場合、p−1∣kp - 1\mid kp−1∣k でなくても ak≡1(modp)a^k \equiv 1\pmod{p}ak≡1(modp) が成り立つため、必ずしも p−1∣kp - 1\mid kp−1∣k が必要であるわけではない。例えば 49981=151×33149981 = 151 \times 33149981=151×331 に対して 150150150 は 151515 を割らないが gcd⁡(215−1, 49981)=151\gcd(2^{15} - 1,\ 49981) = 151gcd(215−1, 49981)=151 となる。

>>> from math import gcd
>>> gcd(2 ** 15 - 1, 49981)
151

:::

nnn との最大公約数を取ればよいため、ak−1a^k - 1ak−1 は常に mod n\textrm{mod}\ nmod n で計算する。こうすることで繰り返し二乗法が使えるので高速になる。

1<d<n1\lt d\lt n1<d<n となっても、ddd が素数であるとは限らない。例えば、n=105n = 105n=105 とすると gcd⁡(24, 105)=15\gcd(2^4,\ 105) =15gcd(24, 105)=15 となる。

>>> from math import gcd
>>> gcd(2 ** 4 - 1, 105)
15

参考

楕円曲線論入門