2021年寒假每日一题,2017~2019年的省赛真题。本文内容由倪文迪(华东理工大学计算机系软件192班)和罗勇军老师提供。每日一题,关注蓝桥杯专栏: https://blog.csdn.net/weixin_43914593/category_10721247.html
每题提供C++、Java、Python三种语言的代码。
2019省赛A组第5题“RSA解密” ,题目链接:
http://oj.ecustacm.cn/problem.php?id=1456
1、题目描述
仍然是填空。
RSA 是一种经典的加密算法。它的基本加密过程如下。
首先生成两个质数
p
,
q
p, q
p,q,令
n
=
p
⋅
q
n = p · q
n=p⋅q,设
d
d
d与
(
p
−
1
)
⋅
(
q
−
1
)
(p-1) · (q-1)
(p−1)⋅(q−1) 互质,则可找到
e
e
e 使得
d
⋅
e
d · e
d⋅e 除
(
p
−
1
)
⋅
(
q
−
1
)
(p-1) · (q- 1)
(p−1)⋅(q−1) 的余数为 1。
n
,
d
,
e
n, d, e
n,d,e 组成了私钥,
n
,
d
n, d
n,d 组成了公钥。
当使用公钥加密一个整数
X
X
X 时(小于
n
n
n),计算
C
=
X
d
m
o
d
n
C = X^d mod\ n
C=Xdmod n,则
C
C
C 是加密后的密文。
当收到密文
C
C
C 时,可使用私钥解开,计算公式为
X
=
C
e
m
o
d
n
X = C^e mod \ n
X=Cemod n。
例如,当
p
=
5
,
q
=
11
,
d
=
3
时
,
n
=
55
,
e
=
27
p = 5, q = 11, d = 3 时,n = 55, e = 27
p=5,q=11,d=3时,n=55,e=27。
若加密数字 24,得
2
4
3
m
o
d
55
=
19
24^3 mod\ 55 = 19
243mod 55=19。
解密数字 19,得
1
9
2
7
m
o
d
55
=
24
19^27 mod\ 55 = 24
1927mod 55=24。
现在你知道公钥中
n
=
1001733993063167141
,
d
=
212353
n = 1001733993063167141, d = 212353
n=1001733993063167141,d=212353,同时你截获了别人发送的密文
C
=
20190324
C = 20190324
C=20190324,请问,原文是多少?
2、题解
2.1 求p、q
先求
n
n
n的素因子
p
p
p和
q
q
q。注意,n只有这2个因子,没有别的因子。
p
p
p和
q
q
q必然有 一个小于
n
\sqrt n
n,找到一个,另一个就知道了。
没有什么好办法,只能暴力,也就是简单地用
i
i
i循环从2到
n
\sqrt n
n一个个试。若
n
n
n除以
i
i
i,余数是0,
i
i
i就是因子。
如果预先知道素数序列,只试这些素数,当然能更快。不过,用素数筛预计算出比
n
\sqrt n
n小的素数,也需要至少
n
\sqrt n
n次。还不如直接用暴力。
下面的代码,循环次数是
n
\sqrt n
n=
1001733993063167141
=
1000866621
\sqrt {1001733993063167141}=1000866621
1001733993063167141=1000866621,即十亿次计算。得到:
p
=
891234941
、
q
=
1123984201
p=891234941、q=1123984201
p=891234941、q=1123984201。
1、C++代码
执行实际约十秒。
//大概10秒
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ll n = 1001733993063167141;
ll k= sqrt(n);
for(ll i = 2 ; i < k; i++)
if(n % i == 0)
cout << i << " " << n / i << endl;
return 0;
}
2、python代码
竟然要几分钟!Python在做循环的时候失去了威力。
网上有大量吐槽Python的**for
循环慢**的帖子。
from math import *
n = 1001733993063167141
k = int(sqrt(n))
for i in range(2,k):
if n%i == 0:
print(i,n//i)
2.2 求e
这时候要用到真正的大数了。c++的64位long long不够用,虽然有_int128,但是有些编译器不支持。
还是靠Python吧。下面代码打印出e=823816093931522017。注意e有很多个,取最小的一个就行了。
n = 1001733993063167141
d = 212353
p=891234941
q=1123984201
tmp = (p - 1) * (q - 1)
print(tmp)
for i in range(2,n+1):
now = i * tmp + 1
if (now % d == 0):
print(now // d) #打印e
break #有很多e,求第一个就行了
2.3 求 X = C e m o d n X = C^e mod \ n X=Cemod n
原来,本题是考了一个快速幂。还是用Python吧:
def qpow(a,b,mod):
ret = 1
while b:
if(b&1):
ret = ret*a % mod
a = a*a % mod
b>>=1
return ret
n = 1001733993063167141
e = 823816093931522017 #试试其他的e
C = 20190324
print(qpow(C,e,n)) #579706994112328949
3、快速幂
快速幂的原理,在《算法竞赛入门到进阶》京东 当当156页做了清晰简明的解释。大家可能没有这本书,这里贴图:
![](https://i-blog.csdnimg.cn/blog_migrate/c3bb8af6db794b95ae00f1d7640c08a0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/51cd75704a97a2b8c751a463ff5014fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/32f413d4f1ddfd9dbd1ab7ef27b59ae4.png)