创作灵感
在探索计算机科学的广阔领域中,我们经常遇到需要将理论知识应用到实践中的机会。特别是在现代加密技术,如RSA加密算法中,理解其背后的数学原理对于加强我们的技术能力至关重要。本文通过分析一个简洁但功能强大的程序,旨在帮助读者深入理解快速幂运算和扩展欧几里得算法,并展示它们是如何在RSA加密技术中发挥关键作用的。
正文
描述
近日来勒索病毒的事件频繁发生,小Y对它的加密原理非常感兴趣,研究了一番相关知识之后,他就来给你看他的加密程序,并给你一段密文,和你炫耀说就算把程序给你看你也破解不出来
你扫了一眼代码发现加密的公式为b=(a^e)%m其中e是质数。
进一步分析发现m=p*q,p和q都为质树,p!=q.
作为一个计算机高手,你早就对加密算法烂熟于心,一眼就看出这个程序的算法和原理,找到了破解的方法,发现小Y疏忽在于给了你一个不够大的m。
你知道解密的公式与加密对称,为a =(b^d)%m。但是你仍然无法心算解出这个d,因此你需要借助计算机来将密文破解。
输入
第一行有一个整数T表示数据组数。(T<=100)
接着有T组数据,每组数据两行
第一行有四个数e、p、q和n,其中e、p、q如题所描述,n表示需要解密的数字序列长度。第二行是需要解密的数字序列a1..an。1<p,q,e<=10^8,p、q、e为质数且p!=q。关$0<=a_i保证解密的结果即原数列的值小于min(p,q)并大于等于0
1<=n<=100
保证m有且仅有两个不同的质因数p和q,并且一定存在一个题中描述的参数d使得解密公式能够无损解密出所有0~min(p,q)-1范围之间的数字
输出
对于每组数据输出一行,表示解密后的数字序列,数字之间以空格隔开。
样例输入
1
5 19 29 3
335 440 514
样例输出
65 67 77
提示
对于样例,存在d=101使得解密公式成立。
注章m和ai的大小可能超过int的范围
#include <iostream>
// 快速幂运算函数 - 进行模幂运算
long long quick_pow(long long a, long long b, long long m) {
long long ans = 1;
a %= m;
// 加速幂运算
while(b) {
// 若b为奇数
if(b & 1) {
ans = ans * a % m; // 更新结果
}
b >>= 1; // 将b除以2
a = a * a % m; // 更新底数
}
return ans;
}
// 欧几里得算法计算最大公约数
long long gcd(long long a, long long b) {
return b ? gcd(b, a % b) : a;
}
// 扩展欧几里得算法,用于寻找一组x和y使得ax+by=gcd(a,b)
void exgcd(long long a, long long b, long long *x, long long *y) {
if(!b) {
*x = 1;
*y = 0;
return;
}
exgcd(b, a % b, y, x);
*y -= a / b * (*x); // 更新y
}
// 计算a关于模m下的逆元
long long inv(long long a, long long m) {
long long x, y;
exgcd(a, m, &x, &y); // 找到一对x和y满足ax+my=1
// 返回逆元,注意要取模m的余数且结果为正
return (x % m + m) %m;
}
int main(){
int T;
std::cin >> T; //读取组数据量
while(T--) {
long long e, p, q, n;
std::cin >> e >> p >> q >> n; // 读取数据
long long phi =(p-1) * (q-1); // 计算欧拉函数值(公式: φ(pq) = (p-1)(q-1))
long long d = inv(e, phi); // 找到e关于phi的模逆元
long long m = p * q; // 计算m值
while(n--) {
long long a;
std::cin >> a; // 读取待解密的数字
std::cout << quick_pow(a, d, m) << " "; // 解密并输出
}
std::cout << "\n";
}
return 0;
}