RSA解密 题解(Pollard_Rho+MR素数检验+扩展欧几里得+快速幂+__int 128)

【问题描述】

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时(小于n),计算C = Xd mod n,则C是加密后的密文。

当收到密文C时,可使用私钥解开,计算公式为X = Ce mod n。

例如,当p=5, q=11, d=3时,n=55, e=27。

若加密数字24,得243 mod 55 = 19。

解密数字19,得1927 mod 55 = 24。

现在你知道公钥中n = 1001733993063167141, d=212353,同时你截获了别人发送的密文C = 20190324,请问,原文是多少?

本题是蓝桥杯大赛的结果填空题,此处改编成一道程序设计题。

输入:只需处理单个测试数据,输入三个整数,n, d和C。保证n能分解成两个质数p, q,d与(p-1)*(q-1)互质。n不超过long long的范围,d和C不超过10^9。

输出:原文。

由题意可知,我们要做的有这些
1:根据n,分解出两个质数p,q,使得p*q=n,d与(p-1) * (q-1)互质
题目:该数是一定有解的,所以n一定能分解成两个质数,根据质数分解唯一性,也只能分解成这这两个质数(p,q唯一)
2:计算 d * e = 1 (mod (p-1) * (q-1)) 中的e的值
同余线性方程,用扩展欧几里得算法即可求出
3:计算原文 :X= C^d mod n
用快速幂即可
此外,long long 算这个会爆,所以需要用__int128
所以代码为:

#include <bits/stdc++.h>
//#define endl '\n'
#define int __int128
using namespace std;

int gcd(int a, int b) {
    
    
	return b ? gcd(b, a % b) : a;
}

int qmi(int a, int k, int p) {
    
    
	int ans = 1;
	while (k) {
    
    
		if (k & 1)
			ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}

int exgcd(int a, int b, int &x, int &y) {
    
    
	if (b == 0) {
    
    
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int tmp = x;
	x = y;
	y = tmp - a / b * y;
	return d;
}

int get(int a, int b, int m) {
    
    
	int x, y;
	int d = exgcd(a, m, x, y);
	int t = b / d;
	return (x * t % (m / d) + (m / d)) % (m / d);
}

void solve() {
    
    
	int n, d, c;
	int p, q;
	long long nn, dd, cc;
	cin >> nn >> dd >> cc;
	n = nn, d = dd, c = cc;
	for (int i = 2; i * i < n; i++) {
    
    
		if (n % i == 0 && gcd(d, (n / i - 1ll) * (i - 1ll)) == 1) {
    
    
			p = i, q = n / i;
			break;
		}
	}
	int x, y;
	int m = (p - 1ll) * (q - 1ll);
	int e = get(d, 1ll, m);
	int ans = qmi(c, e, n);
	long long aa = ans;
	cout << aa << endl;
}

signed main() {
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	solve();

}


但这样是处理不了全部数据的,因为分解n这一步十分耗时,数据中有一个的n=1001733993063167141,常规做法必定GG
(由于只有一个数据的n会这么大,其他的数据都可以水过去,所以特判一下n就可以过了)
可以用更快速的分解方法:Pollard_Rho
直接copy下来修改一下就行了QWQ

#include <bits/stdc++.h>
#define int __int128
using namespace std;

const int maxn = 105;
int x[maxn], ans;
queue<int> aria;
int min(int a, int b) {
    
    
	if (a < b)
		return a;
	else
		return b;
}

int multi(int a, int b, int p) {
    
    
	int ans = 0;
	while (b) {
    
    
		if (b & 1)
			ans = (ans + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return ans;
}

int qpow(int a, int b, int p) {
    
    
	int ans = 1;
	while (b) {
    
    
		if (b & 1)
			ans = multi(ans, a, p);
		a = multi(a, a, p);
		b >>= 1;
	}
	return ans;
}

bool MR(int n) {
    
    
	if (n == 2)
		return true;
	int s = 20, i, t = 0;
	int u = n - 1;
	while (!(u & 1)) {
    
    
		t++;
		u >>= 1;
	}
	while (s--) {
    
    
		int a = rand() % (n - 2) + 2;
		x[0] = qpow(a, u, n);
		for (i = 1; i <= t; i++) {
    
    
			x[i] = multi(x[i - 1], x[i - 1], n);
			if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1)
				return false;
		}
		if (x[t] != 1)
			return false;
	}
	return true;
}

int gcd(int a, int b) {
    
    
	if (b == 0)
		return a;
	else
		return gcd(b, a % b);
}

int Pollard_Rho(int n, int c) {
    
    
	int i = 1, k = 2, x = rand() % (n - 1) + 1, y = x;
	while (1) {
    
    
		i++;
		x = (multi(x, x, n) + c) % n;
		int p = gcd((y - x + n) % n, n);
		if (p != 1 && p != n)
			return p;
		if (y == x)
			return n;
		if (i == k) {
    
    
			y = x;
			k <<= 1;
		}
	}
}

void find(int n, int c) {
    
    
	if (n == 1)
		return;
	if (MR(n)) {
    
    
		aria.push(n);
		return;
	}
	int p = n, k = c;
	while (p >= n) {
    
    
		p = Pollard_Rho(p, c--);
	}
	find(p, k);
	find(n / p, k);
}
int p, q;

void get(int n) {
    
    
	find(n, 107);
	p = aria.front();
	aria.pop();
	q = aria.front();
	aria.pop();

}

inline int qmi(int a, int k, int p) {
    
    
	int ans = 1;
	while (k) {
    
    
		if (k & 1)
			ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}

inline int exgcd(int a, int b, int &x, int &y) {
    
    
	if (!b ) {
    
    
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}

inline int get1(int a, int b, int m) {
    
    
	int x, y;
	int d = exgcd(a, m, x, y);
	int t = b / d;
	return (x * t % (m / d) + (m / d)) % (m / d);
}

void solve() {
    
    
	int n, d, c;
	long long nn, dd, cc;
	cin >> nn >> dd >> cc;
	n = nn, d = dd, c = cc;
	get(n);
	long long pp = p, qq = q;
	//cout << pp << " " << qq << endl;


	int x, y;
	int m = (p - 1) * (q - 1);
	int e = get1(d, 1, m);
	int ans = qmi(c, e, n);
	long long aa = ans;
	cout << aa << endl;
}

signed main() {
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	solve();
}









1

Guess you like

Origin blog.csdn.net/fdxgcw/article/details/120802438