整數因子分解(轉)
相對於素數判定來說,因子分解的實現就沒辦法達到那麼快速了。因子分解至今仍沒有類似於素數判定的多項式演算法,這也成為了RSA公開金鑰系統安全得以保
障的基礎。鑒於這兩個問題的難度相差較大,在我們施行分解之前,最好是預Crowdsourced Security Testing道目標整數的確不是一個素數,否則很可能花費了很大力氣只幹了素數判定的活
——殺雞用牛刀了。
因子分解的分為一般方法和特殊方法兩大類,通常傾向於先針對數的特殊性(例如
)使用特殊方法,如果目標數的形式不那麼特殊,再嘗試使用一般方法。當然,前者往往要比後者快上許多。
我們這裡著重介紹因子分解的一般方法,且總是用
表示待分解的目標數。特殊方法可以以後視實際情況逐漸加入。
-
試除法
-
Euclid演算法
-
Pollard
方法
-
Pollard
方法
-
平方型分解(SQUFOF)
-
連分式方法(CFRAC)
-
Lenstra橢圓曲線方法(ECM)
-
二次篩法(QS)
-
-
單個多項式二次篩法(SPQS)
-
多個多項式二次篩法(MPQS)
-
數域篩法(NFS)
試除法
無論素數判定還是因子分解,試除法(Trial Division)都是首先要進行的步驟。在試除的策略上有兩種不同的選擇:
- 用足夠大的空間來儲存試除用的素數因子(儲存方法可以相當緊湊,比如用
對應的0-1向量表示的大整數)。
- 不耗費大量空間來儲存所有需要的素因子,這時需要一個快速產生素數的子程式,或者乾脆只用2,3以及
型的整數來作為試除因子。
很少發生一個數沒有小因子的情況,例如根據Mertens定理[1]
,奇數中沒有
以下因子的比例
可以知道76%的奇數都有小於100的素因子,而沒有小於
因子的奇數比例僅為6.1%[2]
。因此在大多數情況,試除法的第二種選擇已經足夠,實現卻是最為簡單的。
Euclid演算法
Euclid演算法用於因子分解也非常簡單。我們預先計算好小於100的素數之積
然後將
與目標數
進行Euclid演算法,最終得到
與
的最大公因子,繼續分解公因子就可以得到在100以下的因子分解了。同樣可以預先計算出100到200,200到300的素數乘積
,
等等。這本質上是試除法的一個實現,當
非常大時,必須藉助高精度算術來進行
除以
的操作,因此頻繁的試除會十分耗時,而Euclid方法可以施行很少次數,再在機器精度上完成最終的分解,提高效率。
Pollard
方法
Pollard
方法由Pollard於1974年提出,其基本想法是這樣的:設素數
,由Fermat小定理,又有
,因此
就可能是
的一個非平凡因子。當然,問題在於我們並不知道
是多少。一個合理的假設是
的因子都很小,比如說,
所有素因子都包含在因子基
中,我們來嘗試著找到一個
能夠“覆蓋”
,即是說
,從而
,因此我們可以轉而求
來獲得所要的非平凡因子。例如設素因子上限為
,便可以簡單的取
或是最小公倍數
.
下面給出Pollard
方法的一個版本:
演算法1
(Pollard
方法)
- 設素因子搜尋的上限為
,產生
以下的形如
數對應的素數因子之表
,即:2,3,2,5,7,2,3,11,13,2...
- 隨機播放正整數
,順次計算
b_1&=a//
b_{i+1}&/equiv b_i^{p_i}/pmod{N}/quad i=1,2,/ldots
/end{align*}" width="580" height="48">
- 定期檢查(例如每當
為20的倍數時)
,若
,則得到一個
的因子;否則繼續第2步中的遞推計算。
注1
由于越小素數在
分解中出現的冪次可能越高,
中小素數(例如2,3)應當較多重複出現,第1步中的產生方法便考慮到了這一點,(實際上最終計算了
)
注2
在極少的情形,也可能出現
,即所有
的素因子都同時出現在了
之中,這時可以重新選取定期檢查的時機或者換一個
進行計算。
注3
另一種類似的Williams
方法依賴於
只有小的因子,著名的Lucas序列替代了這裡的
的冪次,乘法群
(
為
的二次非剩餘)代替了乘法群
。因此Pollard
方法與Williams
方法的關係就好像素數檢測中的Lehmer
檢測與Lucas
檢測的關係一樣。具體可參看[3]
.
注4
實踐中
一般取
左右。
注5
Pollard
方法的時間複雜度為
,其中
為一個正數[4]
。
Pollard
方法
目前幾乎所有實用的分解方法都是機率性的演算法,目標是找到能計算
的演算法,使得
的機率較大(而最大公因子可以很快地計算)。上面的Pollard
就是一例,下面即將看到的Pollard
方法也不例外。
Pollard
方法由Pollard在1975年提出,它來自一個有趣的事實:隨機選取大約
個整數(
為一個常數),就有很大機率在這些整數中找到兩個是
同餘的。實踐中可以採用同餘遞推序列
來產生偽隨機數,其中
為映射:
。設
是
的一個因子,且找到
,則計算
便可能得到
的一個非平凡因子。
由
的有限性,如上定義的一階的遞推序列
在
意義下必定是最終迴圈的(,看上去就像希臘字母
)。設其開頭的非迴圈部分長度為
,迴圈節長度為
。著名的Floyd演算法可以在
步內高效地找出序列中的兩個重複元素,並且只用常數的儲存空間。
演算法2
(Floyd)
- 依次判斷是否
,
- 若相等,則終止;否則繼續第1步。
證明
(演算法的有效性)
只需證明必定存在
滿足
且
。由於
等價於
,因此取
為
中
的倍數即可。演算法過程中不必儲存所有
,可以存下當前的
並遞推計算
,
。
□
實踐中常採用的
為
選擇二次的遞推序列一方面能提供足夠的隨機性,另一方面計算起來也非常簡便。
演算法3
(Pollard
)
- 隨機選取
與
。
- 順次計算
。
- 計算
- 每隔一段時間(例如
),檢測
,若非平凡則演算法終止,否則繼續第2步。
注6
當
較大時,對每個
都去檢測
可能會耗費大量時間,因為我們的目標只是得到
的非平凡因子,可以通過計算
,再定時檢測
來減少計算次數。
注7
如同Pollard
方法,也可能出現計算出來的最大公因子
,這時可改變活動訊號間隔時間
或乾脆改變
重新進行計算。
注8
Pollard
方法的時間複雜度為[4]
。
實際上複雜度依賴於
的最小素因子
,在分離
的小因子時尤其有效。
注9
1980年,Brent[5]
給出了Pollard
方法的一個改進,在分解整數時,該方法平均能夠加速24%。這個改進是針對Floyd的演算法2
的,因為Floyd演算法中,往往要重複計算
等,Brent有如下改進,無需重複計算,但仍能同樣有效找出重複元素,並且只要常數的儲存空間。
演算法4
(Brent的改進)
- 令
,
,若
,則演算法終止。
- 若
為2的冪,即
,令
, 依次令
,判斷是否有
,若相等則演算法終止。
證明
(演算法的有效性)
注意演算法過程中
能夠依次遍曆所有正整數,重複演算法2
的論證可知。
□
平方型分解(SQUFOF)
平方型分解(SQUare FOrm Factorization)是由Shanks在大約三十前發展的演算法,但他從來沒有正式發表過[6]
。儘管SQUFOF複雜度為
也是一個指數級的演算法(而下面介紹的CFRAC, ECM, QS等都是次指數級的),但其仍有自身的優勢:一方面演算法十分簡潔優美、便於實現(甚至可以在袖珍計算機上實現),並且在
到
範圍的整數分解仍然是最快的。
SQUFOF依賴於對二次域結構的分析,我們在這裡僅給出演算法的描述,略去證明,具體可參見[6]
:
演算法5
(SQUFOF)
設
非平方數,非素數,一下演算法輸出
的一個非平凡因子。
- 設
,
,
。
- 順次計算
,
,
,直到
為完全平方數。(
)
- 計算
,
,
,
。
- 重複第二步中的計算,直到
,輸出
。
連分式方法(CFRAC)
連分式方法(Continued FRACtion)是由Morrison和Brillhart於1975年提出的[7]
,他們運用此方法成功地分解了Fermat數
。它以及之後要介紹的二次篩(QS)以及數域篩(NFS)都基於如下一個簡單的事實:如果
則
就是
的一個非平凡因子。
當然,尋找這樣的
不能只靠運氣,CFRAC方法構造一組同餘式
x_k^2/equiv (-1)^{e_{0k}}p_1^{e_{1k}} /cdots p_m^{e_{mk}}/pmod{N},/tag{1}
/end{equation*}" width="580" height="20">
其中
都是因子基
中較小的素數。如果找到足夠多這樣的同餘式(例如個數
),那麼利用二元域
上的Gauss消元法,可以找到組合係數
使得
我們記
此時若令
x=/prod_{k=1}^nx_k^{/varepsilon_k},/quad y=(-1)^{v_0}/prod_{i=1}^m{p_i^{v_i}},/tag{2}
/end{equation*}" width="580" height="45">
便則有我們所需要的
如何構造這麼多同餘式呢?我們知道用連分式部分展式可以得到二次無理數
(
)的好的有理數逼近。設
為其近似分數,那麼
的絕對值就很小,從而
很可能在因子基
下分解,同時
,便能得到我們所期望的同餘式(1)
。
演算法6
(CFRAC方法)
- 選擇適當的
(通常取為1,當連分式展式周期太小而無法產生足夠的同餘式時選擇另一個
),令
,使得
。
- 計算
的連分式展式,得到一系列近似分式
。
- 計算
,嘗試在
下得到
的分解,若分解成功則有
- 當得到足夠多的同餘式時(
即可),用
上的Gauss消元法得到(2)
中的
。
- 若
,輸出
的非平凡因子
。
注10
由於
,因此若
,必有
,因此
必定為模
的平方數,從而第一步中可以只選擇限定條件的素數
。
注11
連分式的計算可以只用簡單的四則運算,Gauss消元法可以用一些疏鬆陣列的專用演算法來加速,因此CFRAC最花時間的部分在
的分解上,當分解
花去太久時間時可以直接放棄,轉而求下一個同餘式。
注12
CFRAC方法的時間複雜度為
(見[4]
),其中
記號如下定義:
注13
尋找同餘式(1)
來進行分解的想法首先來自Dixon[8]
,他當時的做法是直接隨機地選取
,然後在
下分解
,演算法複雜度為
,這也是第一個次指數階的一般整數分解方法。
Lenstra橢圓曲線方法(ECM)
因子分解說到底就是尋找
,使得
非平凡,關鍵在於提高尋找的
的成功率。Pollard
方法通過計算
來提高成功率,實質上是在群
中考慮問題。橢圓曲線方法(Elliptic Curve Method)轉而在有限域上隨機的橢圓曲線群中考慮問題。由於橢圓曲線可以有許多不同的選擇,ECM方法要比Pollard
高效許多,到目前為止是第三快的因子分解方法,僅次於數域篩和二次篩。
首先我們給出域上橢圓曲線的定義:
定義1
(域
上的橢圓曲線)
設
是特徵不為2,3的域,
無平方因子,
表示無窮遠點,則
稱為
上的一條橢圓曲線。
注14
無平方因子等價於判別式
,即橢圓曲線是非奇異的,在幾何上看沒有“尖點”。
橢圓曲線既是代數曲線又是一個加法群:
定義2
(橢圓曲線上的加法運算)
設
為一橢圓曲線,
,過
的直線交
於三點
。
表示
關於
軸的對稱點。定義加法
另有三種特殊約定:
- 若
,則直線視為
處的切線;
- 若
,則定義
為無窮遠點
;
- 若
,則定義
。
由定義通過簡單的計算我們可以得到:
命題1
(加法的顯式表達)
設
,
,
,則
/begin{cases}
x_3=/lambda^2-x_1-x_2//
y_3=/lambda(x_1-x_3)-y_1
/end{cases}/tag{3}
/end{equation*}" width="580" height="61">
其中
/lambda=
/begin{cases}