【题目】
题目描述:
Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法。它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信道(可能被窃听)建立一个安全的密钥 k k k,用于加密之后的通讯内容。
假定通讯双方名为 Alice 和 Bob,协议的工作过程描述如下(其中 m o d mod mod 表示取模运算):
- 协议规定一个固定的质数 p p p,以及模 p p p 的一个原根 g g g。 p p p 和 g g g 的数值都是公开的,无需保密。
- Alice 生成一个随机数 a a a,并计算 A = g a m o d p \mathrm A=g^a\; \mathrm{mod} \;p A=gamodp,将 A \mathrm A A 通过不安全信道发送给 Bob。
- Bob 生成一个随机数 b b b,并计算 B = g b m o d p \mathrm B=g^b\; \mathrm{mod}\; p B=gbmodp,将 B \mathrm{B} B 通过不安全信道发送给 Alice。
- Bob 根据收到的 A \mathrm A A 计算出 k = A b m o d p k=\mathrm A^b\;\mathrm{mod} \;p k=Abmodp,而 Alice 根据收到的 B \mathrm{B} B 计算出 k = B a m o d p k=\mathrm B^a\; \mathrm{mod}\; p k=Bamodp。
- 双方得到了相同的 k k k,即 g a b m o d p g^{ab}\;\mathrm{mod}\;p gabmodp。 k k k 可以用于之后通讯的加密密钥。
可见,这个过程中可能被窃听的只有 A \mathrm A A、 B \mathrm B B ,而 a a a、 b b b、 k k k 是保密的。并且根据 A \mathrm A A、 B \mathrm B B、 p p p、 g g g 这 4 4 4 个数,不能轻易计算出 k k k ,因此 k k k 可以作为一个安全的密钥。
当然安全是相对的,该协议的安全性取决于数值的大小,通常 a a a、 b b b、 p p p 都选取数百位以上的大整数以避免被破解。然而如果 Alice 和 Bob 编程时偷懒,为了避免实现大数运算,选择的数值都小于 2 31 2^{31} 231,那么破解他们的密钥就比较容易了。
输入格式:
输入文件第一行包含两个空格分开的正整数 g g g 和 p p p。
第二行为一个正整数 n n n,表示 Alice 和 Bob 共进行了 n n n 次连接(即运行了 n n n 次协议)。
接下来 n n n 行,每行包含两个空格分开的正整数 A \mathrm A A 和 B \mathrm B B ,表示某次连接中,被窃听的 A \mathrm A A、 B \mathrm B B 数值。
输出格式:
输出包含 n n n 行,每行 1 1 1 个正整数 k k k,为每次连接你破解得到的密钥。
样例数据:
输入
3 31
3
27 16
21 3
9 26
输出
4
21
25
备注:
【数据规模】
对于
30
%
30\%
30% 的数据,
2
≤
A
,
B
,
p
≤
1000
2≤\mathrm A,\mathrm B,p≤1000
2≤A,B,p≤1000;
对于
100
%
100\%
100% 的数据,
2
≤
A
,
B
<
p
<
2
31
2≤\mathrm A,\mathrm B<p<2^{31}
2≤A,B<p<231,
2
≤
g
<
20
2≤g<20
2≤g<20,
1
≤
n
≤
20
1≤n≤20
1≤n≤20。
【分析】
BSGS 模板题。
题目意思就是,已知 g a % p g^a\%p ga%p, g b % p g^b\%p gb%p,求 g a b % p g^{ab}\%p gab%p。
那么先用 BSGS 解出 a , b a,b a,b,然后用快速幂算 g a b % p g^{ab}\%p gab%p 就可以了。
很简单的一道题。
【代码】
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int g,p,n;
unordered_map<int,int>Hash;
int Power(ll a,ll b,int p){
ll ans=1;
for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;
return ans;
}
int BSGS(int a,int b,int p){
Hash.clear();
int i,now=b,t=ceil(sqrt(p));
for(i=0;i<t;++i)
Hash[now]=i,now=(ll)now*a%p;
now=1,a=Power(a,t,p);
for(i=0;i<=t;++i)
{
int j=(Hash.find(now)==Hash.end())?-1:Hash[now];
if(j>=0&&i*t-j>=0) return i*t-j;
now=(ll)now*a%p;
}
}
int main(){
scanf("%d%d%d",&g,&p,&n);
for(int i=1,a,b;i<=n;++i){
scanf("%d%d",&a,&b);
a=BSGS(g,a,p),b=BSGS(g,b,p);
printf("%d\n",Power(g,(ll)a*b,p));
}
return 0;
}