[Adleman-Pomerance-Rumely 1983]里面提到了一个典型的例子:当
的时候,
的“免费”素因子的乘积是
这意味着对于
以内的正整数来说,这些“免费”的
的素因子的乘积就已经超过了
,接下来就可以直接证明
是素数了。(为何是
?这是因为我们现在的计算是在一个很大的分圆域里做的,这种情况下“之前提到的进一步的改进”会严重影响运行时间。) 如果将这个算法一般化,有结果证明总可以找到一个
使得相应的“免费素因子”的乘积超过
,这就是开始提到的那个时间复杂度的来源。
Adleman,Pomerance 和Rumely 提出这个算法之后,[Cohen-Lenstra, 1984] 对其中的计算过程做出了重要的改进(粗略地说:用Jacobi和代替了Gauss和,这样需要处理的分圆域的次数就大大降低了)。改进后的算法就以这五个人的名字命名,叫做APR-CL算法。这是历史上第一个相对快速的可以对任意正整数生效的素数判定/证明算法。
最后提一句:这个时间复杂度理论上不是多项式算法,但是实际应用中
的增长极慢,几乎是个常数,所以实际的运行时间“几乎是多项式的”。
椭圆曲线算法(Elliptic Curve Primality Proving, ECPP)
适用范围:一切正整数
时间复杂度:
(有随机性,这个是期望运行时间);算法会生成相对简短的证书(空间复杂度
),通过这个证书可以快速验证
是素数(时间复杂度
)而不用重复整个计算过程
这个算法可以看做是
方法的另一方面的推广:将乘法群
推广到了一般的椭圆曲线群
。使用椭圆曲线群的优点很明确:它的阶数不再是固定的
,而是一个随着曲线变化,取值范围可以落在
这个区间里面的整数。和上文中提到的Pocklinton定理类似,ECPP的理论基础是如下的定理:
定理(可能已经是forklore了):如果存在一条
上的椭圆曲线
,以及曲线上的一个点
,满足以下几个条件:
,其中
是素数且
;在
中,
则
是素数。
利用这个定理证明
是素数,需要两个先决条件:找到合适的椭圆曲线
,以及证明我们用到的
确实是素数。
第二个问题很好解决,因为我们把一个关于
的问题化归成了关于
的问题,而一般来说
,所以这个算法可以无限递归下去,直到涉及的素数规模足够小可以用Rabin-Miller甚至试除来搞定。剩下的就是第一个问题:怎样找到合适的椭圆曲线,使得相应的群的阶数是
的形式?
Goldwasser-Kilian的第一版ECPP算法使用了非常原始的方式:随机取一条椭圆曲线
(严格的说,随机取
中的
和
),用Schoof算法算出阶数
,试着对算出来的阶数做因子分解;如果得不到
这个形式就扔掉换一条。算法最大的硬伤在于Schoof算法本身太慢(
),拖慢了整个ECPP方法的运行时间。
1993年的Atkin-Morain算法解决了这个问题。他们注意到如果一条椭圆曲线有复乘(complex multiplication),那么相应的曲线群的阶数就很好计算(这个理论背景我不太懂,希望有熟悉相关领域的朋友在评论区补充一下);所以只要把“随机选择一条曲线”的范围限定在complex multiplication的范围里,就可以大大提高整个算法的效率。
需要指出一点:整个计算过程中最费时间的步骤是“找到合适的椭圆曲线,并且对曲线群的阶数进行分解”。如果在运行过程中把这些信息记录下来(准确的说:在这个过程中的每一步,记录下来四元组
),那它们就可以用来快速的验证
就是素数。这些记录下来的信息就是本节开头提到的证书(certificate)。
ECPP算法是目前为止最快速的“不需要特殊形式”的素数判定算法。一般对于
左右的素数,在当今普通的个人电脑上只需要不到半个小时就可以完成;当前(截止到2019年1月18日)用这个算法证明的最大素数有
个十进制位(参考https://primes.utm.edu/top20/page.php?id=27),据维基说运行时间大概是两年。AKS算法
适用范围:一切正整数
时间复杂度:
;空间复杂度:
;为啥在这要提到空间复杂度?因为上文提到的一切算法的空间复杂度都是
,只有AKS不一样
注意:这个方法目前只有理论价值,没有实用价值!
AKS算法的本质可以看作“验证特定的多项式环上的Fermat小定理”。它的大概过程如下:
输入一个正整数
。检验
不是其他正整数的幂。