Miller-Rabin素数测试与Pollard Rho大整数分解

Miller-Rabin素数测试

对一个整数n的朴素的素数测试方法是对 [ 2 , n ] [2,\sqrt{n}] [2,n ]内的数进行试除以查找是否存在因子,时间复杂度为 O ( n ) O(\sqrt n) O(n )
而Miller-Rabin素数测试是一个以概率为基础的随机算法,时间复杂度可以达到 O ( 1 ) O(1) O(1)

前置定理

费马小定理:若 p p p为素数,则 a p − 1 ≡ 1 ( m o d    p ) a^{p-1}\equiv 1(\mod p) ap11(modp)对所有 a ∈ Z p ∗ a \in Z_p^{*} aZp均成立

其中 Z p ∗ Z_p^{*} Zp是与素数 p p p互素的所有数的集合

p p p是一个奇素数,则方程 x 2 ≡ 1 ( m o d    p 2 ) x^2\equiv 1(\mod p^2) x21(modp2)仅有两个解 x = 1 x=1 x=1 x = − 1 x=-1 x=1

我们定义若一个数 x x x满足方程 x 2 ≡ 1 ( m o d    n ) x^2\equiv 1(\mod n) x21(modn),但 x x x不等于1或-1,则 x x x是一个以 n n n为膜的1的非平凡平方根
则我们根据上述定理可以得到推论

如果对膜 n n n存在1的非平凡平方根,则 n n n为合数

Miller-Rabin的思想

Miller-Rabin素数测试的想法十分简单,即随机一个整数带入上述两个定理检查n是否不是素数

具体过程如下:
随机准备一个小素数 a a a,并令 n − 1 = 2 t u n-1=2^tu n1=2tu
x 2 = ( a u ) 2 k   ( k = 1 , 2 , 3 , . . . , t ) x^2=(a^{u})^{2^k}\ (k=1,2,3,...,t) x2=(au)2k (k=1,2,3,...,t)分别判断是否满足 x 2 ≡ 1 ( m o d    n ) x^2\equiv 1(\mod n) x21(modn)的解不为 x = 1 x=1 x=1 x − 1 x-1 x1,若满足则可判定n不是质数
最后再利用费马小定理判断 n n n是否满足 a n − 1 ≡ 1 ( m o d    n ) a^{n-1}\equiv 1(\mod n) an11(modn),若不满足则判定 n n n不是质数

若上述检查都未找到 n n n是合数的证据,则 n n n通过了一次Miller-Rabin测试
若s次测试后仍未找到可判定n未合数的证据,则判定n未素数

算法导论中证明

对任意奇数 n > 2 n>2 n>2,进行 s s s次Miller-Rabin测试,出错的概率至多为 2 − s 2^{-s} 2s

代码实现
bool witness(int a, int n, int u, int t)
{	
	int x = qpow(a, u, n); // a^u mod n
	for(int i=1;i<=t;++i)
	{
		int nx = x*x%n; // (a^u) ^ (2^k)
		if(nx==1 && x!=1 && x!=n-1) return true; // x^2为以n为膜的1的非平凡平方根,判断n是合数
		x = nx;
	}
	if(x!=1) return true; // 此时x = (a^u) ^ (2^t) = n-1,费马测试 x!=-1 则判断n是合数
	else return false;
}

bool millerRabin(int n)
{
	if(n==2) return true;
	if(n<2 || (n&1)==0) return false; // n=0或1或n为偶数
	
	int u=n-1; // n-1=u*2^t
	int t=0;
	while(!(u&1))
	{
		u>>=1;
		t++;
	}
	
	// 进行s次Miller-Rabin素数测试
	for(int i=0;i<s&&prime[i]<n;++i){
		if(witness(prime[i], n, u, t)) return false;
	}
	return true;
}

Pollard Rho大整数分解

众所周知对一个大整数进行质因数分解是十分困难的
朴素的 O ( n ) O(\sqrt n) O(n )的试除法即使使用超级计算机也不可能分解千位的大整数,这也是当今密码学的一个重要基础

Pollard给出的Rho启发式算法是一个基于概率的随机算法
算法导论中证明他能在 O ( p ) O(\sqrt p) O(p )的期望时间内计算n的某个非平凡因子,其中 p p p是某个n的最小的因子,满足 p p p n / p n/p n/p互质

Rho随机数

一个最简单的随机算法思路就是随机一个数x判断其是否为n的因子
但实际上,若采用"组合随机采样"的方法,满足答案的组合比单个要多很多,生日悖论便是一个例子

那我们不妨产生一组随机数 x 1 , x 2 , x 3 . . . , x n x_1,x_2,x_3...,x_n x1,x2,x3...,xn,并每次随机选择一对数 x i , x j x_i,x_j xi,xj,若 d = g c d ( ∣ x i − x j ∣ , n ) > 1 d=gcd(|x_i-x_j|,n)>1 d=gcd(xixj,n)>1则d是n的一个因子
为此Pollard设计了伪随机数列 x i = ( x i − 1 + c ) m o d    n x_i=(x_i-1+c)\mod n xi=(xi1+c)modn,其中c是一个随机的常数

这个伪随机数列显然是有循环节的,以 x i = ( x i − 1 − 1 ) m o d    n x_i=(x_i-1-1)\mod n xi=(xi11)modn为例,它的随机序列如下图(取自算法导论)
因为形似 ρ \rho ρ,所以便取名为Rho启发式方法
在这里插入图片描述

Floyd优化的Pollard Rho算法

为了不在rho形伪随机数序列中陷入死循环,可以采用floyd判圈法
令p,q同时从rho的“尾巴”出出发,每次p走一步,q走两步
x p = x q x_p=x_q xp=xq时,两者走过的路径差恰好是环长的整数倍,此时便可退出循环

对于循环中每一对 x p , x q x_p,x_q xp,xq都计算 d = g c d ( ∣ x p , x q ∣ , n ) d=gcd(|x_p,x_q|,n) d=gcd(xp,xq,n),若d>1则找到了n的一个因数d
若直到推出循环都未找到满足条件的d,可以重新随机一个c再次进行算法

int f(int x,int c, int n)
{
	return (x*x + c) % n;
}

int pollardRho(int n)
{
	int c = randint(1, n);
	int t1 = randint(0, n-1);
	int t2 = f(t1, c, n);
	
	while(t1!=t2)
	{
		int d = gcd(abs(t1-t2), n);
		if(d!=1 && d!=n) return d;
		t1 = f(t1, c, n);
		t2 = f(f(t2, c, n), c, n);
	}
	return n; // 没有找到因数
}

例题

洛谷P4718 【模板】Pollard-Rho算法
题目比较卡常,pollardRho做了一些减少gcd次数的常数优化,这部分可以翻看洛谷题解的解释

#include<iostream>
#include<cstdlib> 
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef __int128 ll128;
typedef long long lt;
typedef double db;
typedef unsigned long long ull;
#define eps 1e-8
#define abs(x) (x>=0 ?x :-(x))
#define cmax(a, b) (a>=b?a:b)
#define cmin(a, b) (a<=b?a:b)

lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

lt prime[11]={2,3,5,7,11,13,19,61,1103,2333,24251};
lt ans;

lt gcd(lt a, lt b){
	return b==0 ?a :gcd(b, a%b);
}

lt qpow(lt a, lt k, lt mod)
{
	lt res=1;
	while(k){
		if(k&1) res=(ll128)res*a%mod;
		a=(ll128)a*a%mod; k>>=1;
	}
	return res;
}

bool witness(lt a, lt n, lt u, int t)
{	
	lt x = qpow(a, u, n);
	for(int i=1;i<=t;++i)
	{
		lt nx = (ll128)x*x%n;
		if(nx==1 && x!=1 && x!=n-1) return true;
		x = nx;
	}
	if(x!=1) return true;
	else return false;
}

bool millerRabin(lt n)
{
	if(n==2) return true;
	if(n==3 || n==7 || n==61 || n==2333 || n==24251) return true;
	if(n<2 || (n&1)==0 || n==46856248255981ll) return false;
	
	lt u=n-1; 
	int t=0;
	while(!(u&1))
	{
		u>>=1;
		t++;
	}
	
	for(int i=0;i<11&&prime[i]<n;++i){
		if(witness(prime[i], n, u, t)) return false;
	}
	return true;
}

lt randint(lt mi, lt mx)
{
	return rand() * (mx-mi) + mi;
}

lt f(lt x,lt c, lt n)
{
	return ((ll128)x*x + c) % n;
}

//lt pollardRho(lt n)
//{
//	lt c = randint(1, n);
//	lt t1 = randint(0, n-1);
//	lt t2 = f(t1, c, n);
//	
//	while(t1!=t2)
//	{
//		lt d = gcd(abs(t1-t2), n);
//		if(d!=1 && d!=n) return d;
//		t1 = f(t1, c, n);
//		t2 = f(f(t2, c, n), c, n);
//	}
//	return n;
//}

lt pollardRho(lt n)
{
	if(n==4) return 2;
	lt c = randint(1, n);
	lt t1 = randint(0, n-1), t2 = t1;
	
	t1 = f(t1, c, n);
	t2 = f(f(t2, c, n), c, n);
	
	for(int lim=1; t1!=t2; lim=cmin(128, lim<<1))
	{
		lt pro = 1;
		for(int i=1; i<=lim; ++i)
		{
			lt tmp = (ll128)pro*abs(t1-t2)%n;
			if(!tmp) break;
			pro = tmp;
			
			t1 = f(t1, c, n);
			t2 = f(f(t2, c, n), c, n);
		}
		lt d = gcd(pro, n);
		if(d!=1) return d;
	}
	return n;
}

void find(lt x)
{
	if(x<=ans || x<2) return;
	if(millerRabin(x))
	{
		ans = cmax(ans, x);
		return;
	}
	
	lt d = x;
	while(x==d){
		d = pollardRho(x);
	}
	
	while(x%d==0){
		x /= d;
	}
	
	find(x); find(d);
}

int main()
{
	int T=read();
	while(T--)
	{
		lt n=read();
		
		ans=0;
		find(n);
		if(ans==n) printf("Prime\n");
		else printf("%lld\n", ans);
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值