赞
踩
题面:(开始码字)
RSA是一种经典的加密算法。它的基本加密过程如下。
首先生成两个大质数p,q, 令n = p*q,设d与(p-1)*(q-1)互质,则可以找到e,使得d*e除以(p-1)*(q-1)的余数为1
n,d,e组成了私钥,n,d构成了公钥。
当使用公钥加密一个整数X时(X<=n-1),计算C = X^d mod n,则C是加密后的密文。
当收到密文C时,可以使用私钥解开,计算公式为:X = C^e mod n。
例如:当p = 5, q = 11, n = 55, e = 27。
若加密数字24,得24^3 % 55 = 19。
解密数字19,得19^27 % 55 = 24。
现在你知道公钥中n = 1001733993063167141,d = 212353,同时,你截获了别人发送的密文C = 20190324,请问,原文是多少?
码字码得好累啊~
题意:
给一个n,分解质因数成p*q, 然后计算d关于(p-1)*(q-1)的逆元,结果为e,
求C^e % n的结果
n = 1001733993063167141
d = 212353
c = 20190324
解题过程:
//筛素数 const int maxn = 1e8+10; int a[maxn]; int sushu[maxn/10]; bool notPrime[maxn]; ///筛素数分解不出来,目测是9位数*10位数 int cnt; void getPrime(int n) { for(int i=2;i<=n;++i) { if(!notPrime[i]) sushu[cnt++] = i; for(int j=0;j<cnt&&1ll*i*sushu[j]<=n;++j) { notPrime[i*sushu[j]] = true; if(i%sushu[j]==0) break; } } }
然后分解质因数:
//#define LL long long
void fenjie(LL x)
{
cout<<x<<" = 1";
for(int i=0;i<cnt&&sushu[i]<=x/sushu[i];++i)
{
while(x%sushu[i]==0)
{
cout<<" * "<<sushu[i];
x /= sushu[i];
}
}
if(x>1) cout<<" * "<<x;
cout<<endl;
}
结果是这样的:1001733993063167141 = 1 * 1001733993063167141
显然没分解出来,就是说p和q都是大于1E8的大质数
欧拉筛筛不出来,我又不会杜教筛,所以还是暴力吧
void BF(LL x) //蛮力法
{
cout<<x<<" = ";
for(LL i=1e8+1;i<x;i+=2)
{
if(x%i==0)
cout<<i<<" * ",x/=i;
}
cout<<x<<endl;
}
结果:
1001733993063167141 = 891234941 * 1123984201
好了,现在我们知道了:
p = 891234941
q = 1123984201
这种题,暴力也用不了10s,以后还是写暴力吧…
LL y = (p-1)*(q-1); //y = 1001733991047948000
接下来我们来求逆元:
因为这个mod = y = 1001733991047948000,它不是个质数
我们要求:
d(212353)关于y(1001733991047948000)的乘法逆元
我用的exgcd:
//#define LL long long void exgcd(LL a,LL b,LL &d,LL &x,LL &y) { if(b==0) { d = a; x = 1; y = 0; return; } exgcd(b,a%b,d,y,x); y -= (a/b)*x; } LL rev(LL t,LL m) { LL d,x,y; exgcd(t,m,d,x,y); return (x%m+m)%m; } LL e = rev(d,y); //e = 823816093931522017
然后,我们求c^e%mod
c = 20190324
e = 823816093931522017
mod = 1001733993063167141
注意:
由于这里的mod>1e18太大,快速幂相乘的时候会爆long long的!
这个时候,我们就要用到快速乘
LL fast_product(LL a,LL b,LL mod)//快速乘
{
LL ans = 0;
while(b)
{
if(b&1) ans = (ans+a)%mod;
a = (a+a)%mod;
b>>=1;
}
return ans;
}
然后,我们用快速乘来写快速幂
LL fast_pow(LL a,LL b,LL mod)//快速幂
{
LL ans = 1;
while(b)
{
if(b&1) ans = fast_product(ans,a,mod);
a = fast_product(a,a,mod);
b>>=1;
}
return ans;
}
最后答案为:579706994112328949
附上完整代码:
///Author: xzc #include <bits/stdc++.h> #define LL long long using namespace std; const int maxn = 1e8+10; const LL n = 1001733993063167141ll; const LL p = 891234941ll; const LL q = 1123984201ll; const LL d = 212353; const LL c = 20190324; int a[maxn]; int sushu[maxn/10]; bool notPrime[maxn]; ///筛素数分解不出来,目测是9位数*10位数 int cnt; void getPrime(int n) { for(int i=2;i<=n;++i) { if(!notPrime[i]) sushu[cnt++] = i; for(int j=0;j<cnt&&1ll*i*sushu[j]<=n;++j) { notPrime[i*sushu[j]] = true; if(i%sushu[j]==0) break; } } for(int i=0;i<20;++i) cout<<sushu[i]<<" ";cout<<endl; } void fenjie(LL x) { cout<<x<<" = 1"; for(int i=0;i<cnt&&sushu[i]<=x/sushu[i];++i) { while(x%sushu[i]==0) { cout<<" * "<<sushu[i]; x /= sushu[i]; } } if(x>1) cout<<" * "<<x; cout<<endl; } void BF(LL x) { cout<<x<<" = "; for(LL i=1e8+1;i<x;i+=2) { if(x%i==0) cout<<i<<" * ",x/=i; } cout<<x<<endl; } void exgcd(LL a,LL b,LL &d,LL &x,LL &y) { if(b==0) { d = a; x = 1; y = 0; return; } exgcd(b,a%b,d,y,x); y -= (a/b)*x; } LL rev(LL t,LL m) { LL d,x,y; exgcd(t,m,d,x,y); return (x%m+m)%m; } LL fast_product(LL a,LL b,LL mod) { LL ans = 0; while(b) { if(b&1) ans = (ans+a)%mod; a = (a+a)%mod; b>>=1; } return ans; } LL fast_pow(LL a,LL b,LL mod) { LL ans = 1; while(b) { if(b&1) ans = fast_product(ans,a,mod); a = fast_product(a,a,mod); b>>=1; } return ans; } int main() { //getPrime(maxn-5); //fenjie(n); BF(n); LL y = (p-1)*(q-1); LL e = rev(d,y); LL answer = fast_pow(c,e,n); cout<<answer<<endl; return 0; }
后记: 大数分解质因数还是很难的,18位的大数暴力分解了出来,位数再多一点儿,没有私钥,是很难解码的~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。