二次ふるい法

**二次ふるい法**（にじふるいほう、英：Quadratic sieve、略称：QS）とは、素因数分解に関するアルゴリズムで、実用では一般数体篩法に次いで2番目に早い計算方法であるとされている
。

10進数で100桁までなら計算は最速であり、一般数体篩法よりかなり単純である。

## 基本となるアイデア

与えられた自然数 n を因数分解するものとしよう。 n は素数テストなどで素数ではないことは分かっており、またエラトステネスの篩のようなシンプルな方法では、実用的な時間内で分解できない程度には大きいものとする。

### を2つの平方数の差で表す

もし、 x^2 - y^2 = n を満たすような2つの自然数 x, y が発見できれば、x^2 - y^2 = (x-y)(x+y) = n であるから、 n は因数  (x-y), (x+y) を持つことになる。ただし、x, y の組と因数  (x-y), (x+y) の組は1対1対応であるから、 x, y の組を発見するにしろ、因数  (x-y), (x+y) の組を発見するにしろ、総当たり法(Brute-force attack)を用いるのであれば、必要な計算量は同じであり、このままではこの方法は利点は無い。

式 x^2 - y^2 = n の見方をやや変えて、x^2 - n = b と定義すれば、b が平方数であるか否かを比較的容易に判定できる方法があれば、x, y の組を総当たり法によるよりも効率的に求められる可能性が有る。また、b が平方数となる x を見つけるのは運によるので、なるべく多数の x について、b が平方数かを判定する必要があるだろう。

このためには、まず b がなるべく小さい整数となることが好ましい。そこで x を次のように組織的に変化させることにする。

* まず、(s-1)^2  となる整数 s を二分法やニュートン法などで求める。 s の桁数は(2進法にしろ10進法にしろ) n の桁数の約半分になる。
* x_0 = s+0, \, \cdots , \, x_i = s+i, \, \cdots , \, x_m = s+m
: b_0 = {x_0}^2 - n, \, \cdots , \, b_i = {x_i}^2 - n,  \, \cdots , \, b_m = {x_m}^2 - n 
: と置いて、b_i が平方数であるかを判定する。ここで m は、適当に決めた試行回数の上限となる非負整数であり、i は 0 \le i \le m の範囲の非負整数とする。b_i = s^2 + 2s i + i^2 - n \fallingdotseq  2s i であるから、b_i の上限値は 2sm 程度になる。
* b_i が平方数であるかは、その平方根を二分法やニュートン法などで求めれば分かる。
* b_i が平方数であれば、その平方根を y_i とすれば、n = {x_i}^2 - {y_i}^2 = (x_i-y_i)(x_i+y_i) というように因数が求められる。

残念ながら、この方法でストレートに因数を求めるのであれば、m の値は (\sqrt{2}-1)s 程度まで大きくしなければならない。n が10進100桁程度の整数とすれば m は10進50桁程度の整数とする必要があり、まだ実用的な方法とは言えない。

### 平方数の差が  となる数の組を組織的に探す

そこで、さらに発想を少し変えて、(x_1, b_1) と (x_2, b_2) という数の組があって、それぞれ {x_1}^2 - n = b_1 {x_2}^2 - n = b_2 という式を満たしており、b_1, b_2 は平方数ではないが、b_1 b_2 が平方数 y^2 となる場合を考えよう。この場合、b_1\,b_2 = y^2 = ({x_1}^2 - n) ({x_2}^2 - n) = ({x_1\,x_2})^2 - n ({x_1}^2 + {x_2}^2 - n)  となる。x_1\,x_2 = x および u = {x_1}^2 + {x_2}^2 - n と置けば、x^2 - n\,u = y^2 であるから x^2 - y^2 = (x-y)(x+y) = u\,n となる。

この場合、ユークリッドの互除法で n と (x-y) または (x+y) の共通因数を計算すれば、運が良ければ n の因数が求められるが、運が悪ければ (x-y)(x+y) が u の因数となって、n と (x-y) および (x+y) が互いに素となり、 n の因数が求められない場合もあり得る
。

この方法の優れている点は、数の組を2つではなく、もっと多数の組の場合に拡張することが容易なことである。(x_1, b_1), \, \cdots \, \, (x_m, b_m) という m 個の数の組があって、それぞれ {x_i}^2 - n = b_i \, (1 \le i \le m) という式を満たしており、各 b_i は平方数ではないが、b_1 \cdots b_m が平方数 y^2 となるとしよう。この場合、b_1 \cdots b_m = y^2 = ({x_1}^2 - n) \cdots ({x_m}^2 - n) = ({x_1 \cdots x_m})^2 - n u  となる整数 u が存在する。 x_1 \cdots x_m = x と置けば、x^2 - n\,u = y^2 であるから x^2 - y^2 = (x-y)(x+y) = u\,n となる。

この場合も同じく、ユークリッドの互除法で n と (x-y) または (x+y) の共通因数を計算すれば、運が良ければ n の因数が求められるが、運が悪ければ (x-y)(x+y) が u の因数となって、n と (x-y) および (x+y) が互いに素となり、 n の因数が求められない場合もあり得る。

さて問題は、b_1 \cdots b_m が平方数となる (x_1, b_1), \cdots , (x_m, b_m) の組をどうやって見つけるかであるが、先に示した
:x_0 = s+0, \, \cdots , \, x_i = s+i, \, \cdots , \, x_m = s+m
:b_0 = {x_0}^2 - n, \, \cdots , \, b_i = {x_i}^2 - n,  \, \cdots , \, b_m = {x_m}^2 - n 
と置く方法で、多数の (x_i, b_i) の組について、b_i を比較的簡単に素因数分解できれば、どのような b_i を組み合わせて乗ずれば平方数になるかを、かなり効率よく算出できる可能性があるだろう。

そこで、比較的簡単に素因数分解できる b_i のみを選別する、つまり b_i を「ふるい」(sieve) にかけることを考える。このため「比較的簡単に素因数分解できる」ということをさらに厳密に定義するために、B-smooth という概念を導入する。

### B-smooth と素因数ベクトル

;定義 (B-smooth)
:B, \, l を自然数とする。l の素因数が全て B 以下の場合、l は B-smooth であるという。

自然数 B を適当に決めて固定する。F を B 以下の全ての素数の集合とし、F の元の個数を f とする。F の元はエラトステネスの篩などの方法であらかじめ算出し、昇順にリスト化しておくものとする。これらの素数には昇順に番号が1から振られており、 i 番目の元を p_i と表すものとする。つまり、p_1 = 2、p_2 = 3、p_3 = 5、…、p_{464} = 3301、… となっているものとする。

l が B-smooth である場合、l は一意的に {p_1}^{q_1} \cdots {p_k}^{q_k} \cdots p_f^{q_f} と表すことができる。ここで、{q_1}, \cdots, {q_k}, \cdots, q_f は {p_1}, \cdots, {p_k}, \cdots, p_f の多重度を表す非負整数とする。これを成分とする行ベクトル q = ({q_1}, \cdots, {q_k}, \cdots, q_f) を考え、B についての l の素因数ベクトルと呼ぶことにする。{q_k} = 0 の場合、l は {p_k} を含んでいないことを意味する。従ってl が 1 でなければ、各 {q_k} が同時に 0 となることはない。 

l が B-smooth であるか否かの判定は、F の素数リストで昇順に l が p_k で何回割れるかを調べて q_k を決定し、l = {p_1}^{q_1} \cdots {p_k}^{q_k} \cdots p_f^{q_f} と表すことができるかを実際に調べるしか方法は無い。

b_i と b_j が B-smooth であり、その素因数ベクトルがそれぞれ、(q_{i1}, \cdots, q_{ik}, \cdots, q_{if}) 、 (q_{j1}, \cdots, q_{jk}, \cdots, q_{jf}) である場合、b_i b_j も B-smooth であり、その素因数ベクトルは、(q_{i1} + q_{j1}, \cdots, q_{ik} + q_{jk}, \cdots, q_{if} + q_{jf}) となる。

以下、
:x_0 = s+0, \, \cdots , \, x_i = s+i, \, \cdots , \, x_m = s+m
:b_0 = {x_0}^2 - n, \, \cdots , \, b_i = {x_i}^2 - n,  \, \cdots , \, b_m = {x_m}^2 - n 
と置く方法で、b_i が B-smooth である (x_i, b_i) の組のみを順にm 個選別し、x_i の昇順で番号を 1 \sim m に付け替えておくものとする。

### 素因数パリティ(偶奇性)ベクトル

b_i の素因数ベクトルの成分が全て偶数の場合、b_i は平方数であることになる。素因数ベクトルの成分は非負整数であるが、b_i が平方数であるか否かを判定するためなら、成分が奇数か遇数かという情報があれば十分である。そこで、素因数ベクトルの各成分を2で除した余り(2を法とした剰余)を成分とするベクトルを考え、素因数パリティ(偶奇性)ベクトルと呼び、w_i = (w_{i1}, \cdots, w_{ik}, \cdots, w_{if}) と表すことにする。w_{ik} = q_{ik} \, mod \, 2 であり、これらが取り得る値は 0 または 1 のみである。

b_i と b_j の積 b_i b_j の素因数パリティベクトルは、定義により ( (q_{i1} + q_{j1}) \, mod \, 2, \cdots, (q_{ik} + q_{jk}) \, mod \, 2, \cdots, (q_{if} + q_{jf}) \, mod \, 2) となるが、これは ((w_{i1} + w_{j1}) \, mod \, 2, \cdots, (w_{ik} + w_{jk}) \, mod \, 2, \cdots, (w_{if} + w_{jf}) \, mod \, 2) に等しい。つまり、積 b_i b_j の素因数パリティベクトルの成分は、b_i と b_j の素因数パリティベクトルの成分の、2を法とした剰余加法になる。

線形代数的に見れば、B についての 素因数パリティベクトルの全体は、有限体 \mathbf{F}_2 上の f 次元の線形空間(ベクトル空間)を成している。
\mathbf{F}_2 は 2つの元 \{ 0, \, 1 \} のみから成る体であり、その加法と乗法は 2を法とした剰余算になる。 c を \mathbf{F}_2 の元とすれば、 c と w_i のは、
:c w_i = (c w_{i1}, \cdots, c w_{ik}, \cdots, c w_{if}) と定義される。

線型独立、線型従属といった線形代数的な概念は、素因数パリティベクトルが成す線形空間でも成り立ち、m 個の \mathbf{F}_2 の元 c_k \, (1 \le k \le m) ((c_1, \, \cdots, \,  c_m) をm 次元ベクトルと見なして「スカラーベクトル」と呼ぶことにする) とm 個の素因数パリティベクトル w_k \, (1 \le k \le m) が、

:c_{1} w_{1} +  \cdots + c_{k} w_{k} + \cdots + c_{m} w_{m} = (0, \cdots, 0)

という関係を満たすのは、c_k \, (1 \le k \le m) が全て 0 である場合に限られるとき、 w_k \, (1 \le k \le m) は線型独立であると呼び、そうでない場合は線型従属であると呼ぶ。

線型従属となる m 個の素因数パリティベクトルの組 w_k \, (1 \le k \le m) を見つけることができれば、b = {b_{1}}^{c_{1}} \cdots {b_{k}}^{c_{k}} \cdots {b_{m}}^{c_{m}} が求めていた平方数の 1 つとなる(c_k \, (1 \le k \le m) の内のいずれかは 0 でないから b は 1 ではない)。 y の値は、各 b_k の素因数ベクトルから b の素因数ベクトルを計算して、その各成分(全て偶数)を2で割れば求められる。また、x の値は、x = {x_{1}}^{c_{1}} \cdots {x_{k}}^{c_{k}}  \cdots {x_{m}}^{c_{m}} で求められる(以上は簡単なので証明略)。

ただし、この場合も得られる関係式は x^2 - y^2 = (x-y)(x+y) = u\,n と、余計な整数 u が残った状態となる。ユークリッドの互除法で n と (x-y) または (x+y) の共通因数を計算すれば、運が良ければ n の因数が求められるが、運が悪ければ (x-y)(x+y) が u の因数となって、n と (x-y) および (x+y) が互いに素となり、 n の因数が求められない場合もあり得る。

因数が求められるか否かは多分に運によるので、なるべく多数の B-smooth となる b_i の組を求め、さらにそれらを線型従属にするスカラーベクトル (c_1, \, \cdots, \,  c_m) をなるべく多数見つける必要があることになる。

f 次元線形空間においては、一般に f より多いベクトルの組は線型従属となる。従って f より多い B-smooth となる b_i の組を探せば、1 つ以上の平方数を見つけることが出来ることになる。スカラーベクトル (c_1, \, \cdots, \,  c_m) は、具体的にはガウスの消去法(掃き出し法)によって求めることができる。

### ガウスの消去法

### 実際の計算規模

B の値は小さい方が素因数ベクトルの算出などに要する計算量が少なくて済むが、各 b_i が B-smooth となる確率はより少なくなり、試行すべき b_i の数が大きくなってしまう。n が10進100桁以上の場合、コンピューターの能力も勘案して、実用的には B は {10}^8 程度とする。 B = {10}^8 の場合 f = 5,761,455 となり、これが素因数ベクトルの次数となる。

## 算法(アルゴリズム)
# パラメータの選択
# 篩
# 有効式の選択
# 分解

## 実装
* C Quadratic Sieve – C言語で書かれた二次ふるい法のパブリックドメイン実装。2022年に公開され、最大330ビットまでの数のバッチ因数分解をサポートし、JSONまたはCSV形式で出力可能。

## 脚注

## 出典
* 

*