zoukankan      html  css  js  c++  java
  • LG4718 【模板】Pollard-Rho算法 和 [Cqoi2016]密钥破解

    Pollard-Rho算法

    总结了各种卡常技巧的代码:

    #define int long long
    typedef __int128 LL;
    
    IN int fpow(int a,int b,int mod){
    	int ans=1%mod;
    	for(;b;b>>=1,a=(LL)a*a%mod)
    		if(b&1) ans=(LL)ans*a%mod;
    	return ans;
    }
    
    CO int p[3]={2,61,10007};
    
    bool Miller_Rabbin(int n){
    	if(n==1) return 0;
    	for(int i=0;i<3;++i)
    		if(p[i]==n) return 1;
    	for(int i=0;i<3;++i){
    		if(fpow(p[i],n-1,n)!=1) return 0;
    		int k=n-1,r=0; // k*2^r
    		while(~k&1) k>>=1,++r;
    		int last=fpow(p[i],k,n);
    		for(int i=1;i<=r;++i){
    			int now=(LL)last*last%n;
    			if(now==1 and last!=1 and last!=n-1) return 0;
    			last=now;
    		}
    	}
    	return 1;
    }
    
    int Pollard_Rho(int n){
    	if(Miller_Rabbin(n)) return n;
    	while(1){
    		int seed=(rand()|rand()<<15)%n;
    		auto calc=[seed,n](int x){
    			return ((LL)x*x+seed)%n;
    		};
    		int x=(rand()|rand()<<15)%n,y=x;
    		int sum=1,step=0,point=1;
    		while(sum){
    			x=calc(x);
    			sum=(LL)sum*(y+n-x)%n;
    			if(++step==point){
    				int d=__gcd(sum,n);
    				if(1<d and d<n) return max(Pollard_Rho(d),Pollard_Rho(n/d));	
    				y=x,point<<=1;
    			}
    		}
    	}
    }
    
    void real_main(){
    	int n=read<int>();
    	int ans=Pollard_Rho(n);
    	if(ans==n) puts("Prime");
    	else printf("%lld
    ",ans);
    }
    signed main(){
    //	freopen("LG4718.in","r",stdin),freopen("LG4718.out","w",stdout);
    	srand(20030506);
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    

    密钥破解

    一种非对称加密算法的密钥生成过程如下:

    1. 任选两个不同的质数 p ,q
    2. 计算 N=pq , r=(p-1)(q-1)
    3. 选取小于r ,且与 r 互质的整数 e
    4. 计算整数 d ,使得 ed≡1 mod r
    5. 二元组 (N,e) 称为公钥,二元组 (N,d) 称为私钥

    当需要加密消息 n 时(假设 n 是一个小于 N 整数,因为任何格式的消息都可转为整数表示),使用公钥 (N,e),按照

    n^e≡c mod N

    运算,可得到密文 c 。

    对密文 c 解密时,用私钥 (N,d) ,按照

    c^d≡n mod N

    运算,可得到原文 n 。算法正确性证明省略。

    由于用公钥加密的密文仅能用对应的私钥解密,而不能用公钥解密,因此称为非对称加密算法。通常情况下,公钥由消息的接收方公开,而私钥由消息的接收方自己持有。这样任何发送消息的人都可以用公钥对消息加密,而只有消息的接收方自己能够解密消息。

    现在,你的任务是寻找一种可行的方法来破解这种加密算法,即根据公钥破解出私钥,并据此解密密文。

    Input

    输入文件内容只有一行,为空格分隔的j个正整数e,N,c。N<=2^62,c<N

    Output

    输出文件内容只有一行,为空格分隔的k个整数d,n。

    Sample Input

    3 187 45

    Sample Output

    107 12
    //样例中 p = 11, q = 17

    题解

    CQOI破解密码专场。推荐MoebiusMeow的博客。

    虽然不知道为什么(x^{k(p-1)(q-1)+1}equiv 1 (mod pq)),但是分析题意我们只需要把(p,q)分解出来就行了。

    所以用上Pollard-Rho大整数分解算法,以及Miller-Rabbin素性测试。然后其他的就是常规同余内用了。

    最后说一下O(1)快速乘
    O(1)快速乘

    queue<LL> arr;
    il LL mul(LL a,LL b,LL mod){
    	LL ans=a*b-(LL)((long double)a/mod*b+1e-8)*mod;
    	return ans<0?ans+mod:ans;
    }
    LL pow(LL a,LL b,LL mod){
    	LL ans=1;
    	for(;b;b>>=1,a=mul(a,a,mod))
    		if(b&1) ans=mul(ans,a,mod);
    	return ans;
    }
    LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
    LL exgcd(LL a,LL b,LL&x,LL&y){
    	if(!b) return x=1,y=0,a;
    	LL z=exgcd(b,a%b,y,x);
    	return y-=a/b*x,z;
    }
    LL Pollard_Rho(LL n,LL sed){
    	LL i=1,k=2,x=rand()%(n-1)+1,y=x;
    	while(true){
    		x=(mul(x,x,n)+sed)%n;
    		LL p=gcd(n,(y-x+n)%n);
    		if(p!=1&&p!=n) return p;
    		if(y==x) return n;
    		if(++i==k) y=x,k<<=1;
    	}
    }
    LL x[100];
    bool Miller_Rabbin(LL n){
    	if(n==2) return 1;
    	LL s=20,t=0,u=n-1;
    	while(!(u&1)) ++t,u>>=1;
    	while(s--){
    		LL a=rand()*rand()%(n-2)+2;
    		x[0]=pow(a,u,n);
    		for(int i=1;i<=t;++i){
    			x[i]=mul(x[i-1],x[i-1],n);
    			if(x[i]==1&&x[i-1]!=1&&x[i-1]!=n-1) return 0;
    		}
    		if(x[t]!=1) return 0; // Fermat
    	}
    	return 1;
    }
    void find(LL n,LL sed){
    	if(n==1) return;
    	if(Miller_Rabbin(n)) return arr.push(n);
    	LL p=n,k=sed;
    	while(p==n) p=Pollard_Rho(p,sed--);
    	find(p,k),find(n/p,k);
    }
    LL p,q,e,d,N,c,r;
    int main(){
    	srand(19260817);
    	read(e),read(N),read(c);
    	find(N,107);
    	p=arr.front(),arr.pop();
    	q=arr.front(),arr.pop();
    	exgcd(e,r=(p-1)*(q-1),d,*(new LL));
    	d=(d%r+r)%r;
    	printf("%lld %lld
    ",d,pow(c,d,N));
    	return 0;
    }
    
  • 相关阅读:
    装饰器
    函数的初识
    python的文件操作
    深浅copy
    set集合,是一个无序且不重复的元素集合
    基础数据类型 :字典
    列表的增删改查
    易错点 默认参数陷阱
    js中Array对象常用方法
    printf用法demo
  • 原文地址:https://www.cnblogs.com/autoint/p/11095279.html
Copyright © 2011-2022 走看看