P5451 [THUPC2018]密码学第三次小作业
P5451 [THUPC2018]密码学第三次小作业
题目大意
现在有两个用户由于巧合,拥有了相同的模数 \(N\),但是私钥不同。设两个用户的公钥分别为 \(e_1\) 和 \(e_2\),且两者互质。明文消息为 \(m\),密文分别为:
\[\begin{matrix}c_1=m^{e_1}\bmod N\\c_2=m^{e_2}\bmod N\end{matrix}
\]
现在,一个攻击者截获了 \(c_1\) ,\(c_2\),\(e_1\),\(e_2\),\(N\),请帮助他恢复出明文 \(m\) 。
分析
太妙啦,我们来顺一遍思路啊。
首先我们要求m,但给的式子都不是m的一次幂。那我们先放一下给的式子。我们可以发现给的m的次幂是e1和e2,则我们考虑一下能不能用e1,e2凑出1。
我们注意到e1,e2互质,那我们想到用裴蜀定理。得到,\(e_1x+e_2y=1\)的式子。
我们带入一下,\(m=m^{e_1x+e_2y}=m^{e_1x}*m^{e_2y}\),再结合给的式子,我们可以得到,\(m=c_1^x*c_2^y(mod\ N)\)。
而x,y我们可以很简单的用exgcd求得。还有一个小问题,如果x,y不是正数怎么办,那就转化一下,假设x为负数则,式子可以转化为\((c_1^{-1})^{-x}\)
而,c1的逆元,需要注意,不能直接用费马小定理求,用exgcd求,结束啦。
Ac_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
typedef long long LL;
typedef __int128_t i128;
LL exgcd(LL a, LL b, LL& x, LL& y)
{
if (!b)
{
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL get_inv(LL a,LL p)
{
LL x,y;
LL d = exgcd(a,p,x,y);
return (x%p+p)%p;
}
LL ksm(LL a,LL b,LL mod)
{
LL res = 1;
while(b)
{
if(b&1) res = (i128)res*a%mod;
b>>=1;
a = (i128)a*a%mod;
}
return res;
}
int main()
{
ios;
int T;cin>>T;
while(T--)
{
LL c1,c2,e1,e2,N;
LL s,t;
cin>>c1>>c2>>e1>>e2>>N;
exgcd(e1,e2,s,t);
LL k,ans = 0;
if(s<0) k = ceil((1.0-s)/e2),s += e2*k,t -= e1*k;
ans = ksm(c1,s,N);
if(t<0) ans = (i128)ans*ksm(get_inv(c2,N),-t,N)%N;
else ans = (i128)ans*ksm(c2,t,N)%N;
cout<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号