看了一些别人的博客,发现里面涉及到的公式没有证明,于是就打算自己写一篇比较详细的讲解。
先看两个引理及其证明(建议把证明搞懂)。
PS:以下图片均为作者用wps制作,如想使用请附上作者博客链接,谢谢O(∩_∩)O。
看完了上面的引理,那就可以正式开始Miller-Rabin算法的讲解了。
背景:
素性测试(即测试给定的数是否为素数)是近代密码学中的一个非常重要的课题。虽然Wilson定理(对于给定的正整数n,n是素数的充要条件为)给出了一个数是素数的充要条件,但根据它来素性测试所需的计算量太大,无法实现对较大整数的测试。目前,尽管高效的确定性的素性算法尚未找到,但已有一些随机算法可用于素性测试及大整数的因数分解。下面描述的Miller-Rabin素性测试算法就是一个这样的算法。
算法:
首先要知道费马定理只是n是素数的必要条件。即费马定理不成立,n一定是合数;费马定理成立,n可能是素数。接下来请看Miller-Rabin算法的分析过程。
如果仔细看的话,应该能看懂大致原理了,数论基础好的甚至都可以开始写代码了吧,哈哈。
示例代码如下:
typedef long long int ll;
ll mod_mul(ll a, ll b, ll mod)
{
ll res = 0;
while (b)
{
if (b & 1)
res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res;
}
ll mod_pow(ll a, ll n, ll mod)
{
ll res = 1;
while (n)
{
if (n & 1)
res = mod_mul(res, a, mod);
a = mod_mul(a, a, mod);
n >>= 1;
}
return res;
}
// Miller-Rabin随机算法检测n是否为素数
bool Miller_Rabin(ll n)
{
if (n == 2)
return true;
if (n < 2 || !(n & 1))
return false;
ll m = n - 1, k = 0;
while (!(m & 1))
{
k++;
m >>= 1;
}
for (int i = 1; i <= 20; i++) // 20为Miller-Rabin测试的迭代次数
{
ll a = rand() % (n - 1) + 1;
ll x = mod_pow(a, m, n);
ll y;
for (int j = 1; j <= k; j++)
{
y = mod_mul(x, x, n);
if (y == 1 && x != 1 && x != n - 1)
return false;
x = y;
}
if (y != 1)
return false;
}
return true;
}