【CQOI 2018】破解D-H协议

【题目】

传送门

题目描述:

Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法。它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信道(可能被窃听)建立一个安全的密钥 k k k,用于加密之后的通讯内容。

假定通讯双方名为 AliceBob,协议的工作过程描述如下(其中 m o d mod mod 表示取模运算):

  1. 协议规定一个固定的质数 p p p,以及模 p p p 的一个原根 g g g p p p g g g 的数值都是公开的,无需保密。
  2. 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
  3. 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
  4. 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
  5. 双方得到了相同的 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 都选取数百位以上的大整数以避免被破解。然而如果 AliceBob 编程时偷懒,为了避免实现大数运算,选择的数值都小于 2 31 2^{31} 231,那么破解他们的密钥就比较容易了。

输入格式:

输入文件第一行包含两个空格分开的正整数 g g g p p p

第二行为一个正整数 n n n,表示 AliceBob 共进行了 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 2A,B,p1000
对于 100 % 100\% 100% 的数据, 2 ≤ A , B < p < 2 31 2≤\mathrm A,\mathrm B<p<2^{31} 2A,B<p<231 2 ≤ g < 20 2≤g<20 2g<20 1 ≤ n ≤ 20 1≤n≤20 1n20


【分析】

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值