RSA简介
明文 M,密文 C。
n>M,且 n 为两个不相同大质数的乘积 n=pq,1<e<φ(n) 与 φ(n) 互素,ed≡1(modφ(n))。
公钥 n,e,私钥 d,利用分解大质因数的困难来保证数据安全。
加密 C=Memodn。
解密 M=Cdmodn。
证明解密的正确性
当 gcd(M,n)=1,由扩展欧拉定理 Cd≡Med≡Med mod φ(n)≡M(modn)。
当 gcd(M,n)=1,p∣M 或 q∣M,不妨设 M=kp。根据费马小定理有 (kp)q−1≡1(modq)。设非负整数 r 满足 ed=rφ(n)+1。显然有 [(kp)q−1]r(p−1)≡1(modq),即 (kp)r(p−1)(q−1)≡1(modq)。根据积性函数的性质,φ(n)=(p−1)(q−1),故 (kp)rφ(n)≡(kp)ed−1≡1(modq),两边同时乘 kp,有 (kp)ed≡kp(modq);可以写成 (kp)ed=sq+kp,s∈N。容易得到 p(kedped−1−k)=sq,所以 p∣s,不妨令 s=tp,t∈N。于是有 (kp)ed=tpq+kp,即 (kp)ed=kp+tn;将 M=kp 代入得到 Med=M+tn,显然有 Med≡M(modn)。解密时,Cd≡Med≡M(modn)。
证毕。
解码思路
输入 n,用 Pollard-Rho 算法分解质因数 p,q,算法导论给出的期望时间复杂度是 O(min(p,q)),接着计算 φ(n)=(p−1)(q−1)。输入 e,用扩展欧几里得算法解线性同余方程 ed≡1(modφ(n)),时间复杂度 O(logφ(n))。输入 C,用快速幂 O(logd) 得到 M。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| #include<iostream> #include<vector> #include<algorithm> using namespace std; typedef long long ll; typedef __int128 bll; vector<ll>primeFactor; ll QuickPower(ll a, ll b, ll MOD) { a %= MOD; ll res = 1 % MOD; while (b) { if (b & 1) { res = (bll)res * (bll)a % MOD; } b >>= 1; a = (bll)a * (bll)a % MOD; } return res; } bool MillerRabin(ll n, int repeat) { if (n == 2 || n == 3) { return true; } else if (n % 2 == 0 || n == 1) { return false; } ll d = n - 1; int s = 0; while (!(d & 1)) { ++s; d >>= 1; } while (repeat--) { ll a = rand() % (n - 3) + 2; ll x = QuickPower(a, d, n); ll y = 0; for (int i = 1;i <= s;i++) { y = (bll)x * (bll)x % n; if (y == 1 && x != 1 && x != n - 1) { return false; } x = y; } if (y != 1) { return false; } } return true; } ll PollardRho(ll n, ll c) { ll x = rand() % (n - 2) + 1; ll y = x, i = 1, k = 2; while (1) { ++i; x = (bll)x * (bll)x % n + c + n; ll d = abs(__gcd(y - x, n)); if (1 < d && d < n) { return d; } else if (y == x) { return n; } else if (i == k) { y = x; k <<= 1; } } } void FindPrimeFactor(ll n, ll c) { if (n == 1) { return; } if (MillerRabin(n, 50)) { primeFactor.emplace_back(n); return; } ll p = n; while (p >= n) { p = PollardRho(p, c--); } FindPrimeFactor(p, c); FindPrimeFactor(n / p, c); } void ExtendGCD(ll a, ll b, ll& x, ll& y) { if (!b) { x = 1; y = 0; return; } ExtendGCD(b, a % b, x, y); ll temp = x; x = y; y = temp - a / b * y; } int main() { ll n, e, C; cin >> n >> e >> C; FindPrimeFactor(n, 107); ll p = primeFactor.front(); ll q = primeFactor.back(); ll phi = (p - 1) * (q - 1); ll x = 0, y = 0; ExtendGCD(e, phi, x, y); ll d = (x % phi + phi) % phi; ll M = QuickPower(C, d, n); cout << M << endl; return 0; }
|
样例
输入1
输出1
输入2
输出2
输入3
输出3
用中国剩余定理优化
解密时 M=Cdmodn,若 n 是很大的数,会爆long long,可用中国剩余定理优化。
令 M1=Cdmodp,M2=Cdmodq,注意求 M1 和 M2 时用扩展欧拉定理降幂。有线性同余方程组 $\left\{\begin{matrix}x\equiv M_1\pmod p\\x\equiv M_2\pmod q\end{matrix}\right.$,由于p⊥q,x 必有解。设 p 模 q 的逆元为 p′,q 模 p 的逆元为 q′,根据中国剩余定理,其解集为 $\{x|k\in\mathbb Z, x=M_1q'q+M_2pp'+kn\}$;其中 Cd 也是一个解,设 Cd=M1q′q+M2pp′+k∗n,则 M=Cdmodn=(M1q′q+M2pp′)modn。