题目链接:
http://poj.org/problem?id=2447
题目大意:
RSA是个有名的公匙密码系统。在这个系统中,每个参与者有一个只能自己知道的私匙和一个每个人都
知道的公匙。为了安全地把信息传递给对方,应该用公匙对信息进行加密,对方用自己的私匙进行解密。
对RSA系统的描述如下:
首先,选择两个大素数P、Q,计算N = P * Q。
然后,选择一个正整数E作为加密密匙,令T = (p-1)*(q-1),且gcd(E,T) = 1。
最后,计算解密密匙D,使得(E * D) mod T = 1,这里D是E模T的逆元。
公匙表示为{E,N},私匙表示为{D,N},P和Q被舍弃。
加密数据的过程为
C = M^E mod N
解密数据的过程为
M = C^D mod N
M是一个比N小的非负整数成为明文,C是密文。
现在问题来了:给你密文C和公匙{E,N},能找到明文M吗?
思路:
因为N是一个大整数,先用PollardRho对N做大整数的数分解,得到一个素因子P,那么另一个素因子
Q = N/Q,这样得到了两个素数p和q。再求出T = (P-1)*(Q-1)。然后用扩展欧几里得的方法求出E关于
模T的逆元D。根据公匙M = C^D mod N,从而得到明文。
AC代码:
#include<iostream> #include<algorithm> #include<ctime> #include<cmath> #include<cstdio> #include<cstring> #define LL long long using namespace std; LL mod_mul(LL x,LL y,LL mo) { LL t; x %= mo; for(t = 0; y; x = (x<<1)%mo,y>>=1) if(y & 1) t = (t+x) %mo; return t; } //LL mod_mul(LL x,LL y,LL mo) //{ // LL t,T,a,b,c,d,e,f,g,h,v,ans; // T = (LL)(sqrt(double(mo)+0.5)); // t = T*T - mo; // a = x / T; // b = x % T; // c = y / T; // d = y % T; // e = a*c / T; // f = a*c % T; // v = ((a*d+b*c)%mo + e*t) % mo; // g = v / T; // h = v % T; // ans = (((f+g)*t%mo + b*d)% mo + h*T)%mo; // while(ans < 0) // ans += mo; // return ans; //} LL mod_exp(LL num,LL t,LL mo) { LL ret = 1, temp = num % mo; for(; t; t >>=1,temp=mod_mul(temp,temp,mo)) if(t & 1) ret = mod_mul(ret,temp,mo); return ret; } //PollarRho大整数因子分解 LL gcd(LL a,LL b) { if(b == 0) return a; return gcd(b, a % b); } LL PollarRho(LL n, int c) { int i = 1; srand(time(NULL)); LL x = rand() % (n-1) + 1; LL y = x; int k = 2; while(true) { i++; x = (mod_exp(x,2,n) + c) % n; LL d = gcd(n+y-x,n); if(1 < d && d < n) return d; if(y == x) return n; if(i == k) { y = x; k *= 2; } } } void ExGCD(LL a,LL b,LL &d,LL &x,LL &y) { if(b == 0) { x = 1; y = 0; d = a; } else { ExGCD(b,a%b,d,y,x); y -= x*(a/b); } } int main() { LL p,q,t,c,e,n; while(cin >> c >> e >> n) { p = PollarRho(n,10007); q = n/p; t = (p-1)*(q-1); LL d,x0,y0; ExGCD(e,t,d,x0,y0); x0 = (x0%t + t) % t; cout << mod_exp(c,x0,n) << endl; } return 0; }