Description
一种非对称加密算法的密钥生成过程如下:
1.任选两个不同的质数 p,q
2.计算 N=pq,r=(p−1)(q−1)
3.选取小于 r ,且与 r 互质的整数 e
4.计算整数 d ,使得 ed≡1(modr)
5.二元组 (N,e) 称为公钥,二元组 (N,d) 称为私钥
当需要加密消息 M 时(假设 M 是一个小于 N 的整数,因为任何格式的消息都可转为整数表示),
使用公钥 (N,e) ,按照 ne≡c(modN) 运算,可得到密文 C 。
对密文 C 解密时,用私钥 (N,d) ,按照 cd≡n(modN) 运算,可得到原文 M 。算法正确性证明省略。
由于用公钥加密的密文仅能用对应的私钥解密,而不能用公钥解密,因此称为非对称加密算法。
通常情况下,公钥由消息的接收方公开,而私钥由消息的接收方自己持有。这样任何发送消息的
人都可以用公钥对消息加密,而只有消息的接收方自己能够解密消息。
现在,你的任务是寻找一种可行的方法来破解这种加密算法,即根据公钥破解出私钥,并据此解密密文。
Input
输入文件内容只有一行,为空格分隔的 3 个正整数 e,N,c 。 N≤262,c<N .
Output
输出文件内容只有一行,为空格分隔的 2 个整数 d,n 。
Sample Input
3 187 45
Sample Output
107 12
//样例中 p = 11, q = 17
这个题真的是题意即题解……对 N 素因子分解得 r ,然后算 e 对 r 的逆元 d ,最后 cd 快速幂一下就好了。
关键在于对于 262 级别的数如何快速分解质因子。
这里有一个专门的算法叫做PollardRho,期望时间复杂度是 O(n14) 。主要是用一个有圈的随机数生成器来随机一个数与要分解的数求gcd。具体实现在判圈有所不同,可以采用标准的PollardRho方法 xi=(x2i−1+c) ,或者是Floyd判圈算法。这个题保证只有两个素因子,所以可以省去用来判断结尾的MillerRabin。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
LL e,N,c;
inline LL gcd(LL a,LL b)
{ if(!b)return a;
return gcd(b,a%b);
}
inline LL Abs(LL a){if(a<0)return -a;else return a;}
const int MAXN=10000000LL;
LL Maxn;
LL P[MAXN+5];bool vst[MAXN+5];
void Preload()
{ int i,j;P[0]=0;
for(i=1;i<=Maxn;i++)vst[i]=0;
for(i=2;i<=Maxn;i++)
{ if(!vst[i])P[++P[0]]=i;
for(j=1;j<=P[0];j++)
{ if(i*P[j]>Maxn)break;
vst[i*P[j]]=1;
if(i%P[j]==0)break;
}
}
//for(i=1;i<=100;i++)printf("%lld ",P[i]);putchar('\n');
}
LL QM_Normal(LL a,LL b,LL M)
{ LL ret=1;a%=M;
while(b)
{ if(b&1LL)ret=ret*a%M;
b>>=1LL;a=a*a%M;
}
return ret;
}
LL Multi(LL a,LL b,LL M)
{ LL ret=0;a%=M;
while(b)
{ if(b&1LL)ret=(ret+a)%M;
b>>=1LL;a=(a+a)%M;
}
return ret;
}
LL QM(LL a,LL b,LL M)
{ LL ret=1;a%=M;
while(b)
{ if(b&1LL)ret=Multi(ret,a,M);
b>>=1LL;a=Multi(a,a,M);
}
return ret;
}
LL d;
void ExEuclid(LL a,LL b,LL &x,LL &y)
{ if(!b){d=a;x=1;y=0;return;}
ExEuclid(b,a%b,x,y);
LL t=x;x=y;y=t-a/b*y;
}
LL Inverse(LL x,LL p)
{ LL inv,t;
ExEuclid(x,p,inv,t);
return (inv%p+p)%p;
}
void Solve1()
{ LL r,D,i;
Maxn=1000;Preload();
for(i=1;i<=P[0];i++)
if(N%P[i]==0)break;
r=(P[i]-1)*(N/P[i]-1);
D=Inverse(e,r);
printf("%lld %lld\n",D,QM_Normal(c,D,N));
}
void Solve2()
{ LL r,i,D;
Maxn=10000000LL;Preload();
for(i=1;i<=P[0];i++)
if(N%P[i]==0)break;
r=(P[i]-1)*(N/P[i]-1);
D=Inverse(e,r);
printf("%lld %lld\n",D,QM(c,D,N));
}
LL PollardRho(LL n,LL c)
{ LL i=2,j=1,x,y,tmp;
x=rand()%(n-1)+1;
y=(Multi(x,x,n)+c)%n;
while(1)
{ j++;
if(x==y)return n;
tmp=gcd(Abs(y-x),n);
if(1<tmp&&tmp<n)return tmp;
if(i==j){i<<=1LL;x=y;}
y=(Multi(y,y,n)+c)%n;
}
}
void Solve3()
{ LL r,p,K=10007,D;
p=N;while(p>=N)p=PollardRho(N,K--);
r=(p-1)*(N/p-1);
D=Inverse(e,r);
//printf("%lld ",r);
printf("%lld %lld\n",D,QM(c,D,N));
}
int main(){
freopen("crack.in","r",stdin);
freopen("crack.out","w",stdout);
srand(10007);
scanf("%lld%lld%lld",&e,&N,&c);
if(N<=1000000)Solve1();
else if(N<=100000000000000LL)Solve2();
else Solve3();
fclose(stdin);fclose(stdout);
return 0;
}