【题解】P4454 [CQOI2018] 破解D-H协议

P4454 CQOI2018 破解D-H协议 - 洛谷 (luogu.com.cn)

终于做到密码学相关的啦好开心!

正好复习一下 BSGS,学了这么多年的数论终于有用武之地!

这道题是板子,很简单,但我会拓展一些密码学、数论、群论相关内容,自行选读。


0.与解题无关

Diffie-Hellman(迪菲-赫尔曼密钥交换,简称 D-H)

是一种在不安全通信信道上,安全地交换加密密钥的密码学协议。

大致流程:

  1. 双方公开约定两个数字:一个大质数 和一个底数 (原根)。

  2. Enigma 选一个秘密数 (私钥),计算 ,把 (公钥)发给 Ulrich。

  3. Ulrich 选一个秘密数 (私钥),计算 ,把 (公钥)发给 Enigma。

  4. Enigma 计算:

  5. Ulrich 计算:

由于模幂运算的交换律,两者得出的 是完全相同的。

而外界黑客只知道 ,想要算出 ,就必须解决离散对数难题。

在现有计算机能力下,对大质数极其难解,这就是 D-H 的安全性基石。

概念解释:

原根(Primitive Root),也叫本原元。

定义:对于一个质数 ,如果存在一个整数 。

使得 的 次方、 次方、 次方......一直到 次方,

分别 后得到的余数,不重不漏地覆盖了 到 之间的所有整数。

那么 就是模 的一个原根。

初等数论定义:

设整数 与模数 互质,

阶 是指让 成立的最小正整数 ,记作 。

在以上基础上, 的阶等于欧拉函数 ,则称 是模 的原根。

写成公式:

其中 表示小于等于 且与 互质的正整数个数。

另:当 为质数,。

群论定义:

是模 乘法群 ​ 的生成元,即:

这表示 的幂次能遍历所有与 互质的余数集合。
模幂运算的交换律:


离散对数:

形如 。

因为 操作导致结果并非连续,而是在 的余数域上不规律跳动。
现有计算机与 D-H 的安全性:

离散对数在数学结构上是一个没有逆向公式的单向函数,

且其破译时间复杂度随着数据变大而指数级增长。

但如果使用量子计算机,能在多项式时间内快速求解离散对数。

这也是为什么现在全球密码学界在大力推进**后量子密码学(PQC)**的原因。

1.题意解读

Diffie-Hellman 密钥交换过程中,公开的信息有:

  • 固定公开 :质数 ,原根

  • 信道窃听得到 :

要破解的是最终密钥:

已知 ,但不知道私密的随机数 或 。

破解思路 :

只要算出其中一个私密数,比如 ,那么:

而 就是以 为底、 的离散对数:

所以,每组数据都是在解一个离散对数问题。

BSGS 就是专门用来求解 中 的算法。

它的时空复杂度都是 。

本题数据范围:,用 BSGS 轻松过。

PS:本人还是认为题意很有意思,有真的在破译密码的感觉。

虽然只是 BSGS 板子,某种意义上还有隐私安全教育环节。

2.代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
map<LL, LL> mp;

// a ^ x  = b (mod p)
LL BSGS(LL a, LL b, LL p) {
	a %= p; b %= p;
	
	if (b == 1) {   // 特判 
		return 0;
	}	
	
	mp.clear();
	mp[b] = 0;   // 不走小步 
	LL m = ceil(sqrt(p));
	
	LL am = a;
	for (LL j = 1, t = b; j < m; j ++) {
		t = t * a % p;
		mp[t] = j;
		am = am * a % p;
	}
	
	for (LL i = 1, t = 1; i <= m; i ++) {
		t = t * am % p;
		if (mp.count(t)) {
			return i * m - mp[t];
		}
	}
	return -1;
}

LL g, P;

LL q_pow(LL a, LL b) {
	LL c = 1;
	while (b) {
		if (b & 1) {
			c = c * a % P;
		}
		a = a * a % P;
		b >>= 1;
	}
	return c;
}

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> g >> P;
	int n;
	cin >> n;
	for (int i = 1; i <= n; i ++) {
		LL A, B;
		cin >> A >> B;
		LL a = BSGS(g, A, P);
		LL K = q_pow(B, a);
		cout << K << "\n";
	}
	
	return 0;
}
相关推荐
Omics Pro8 分钟前
经典多组学整合算法→商用云平台
数据库·人工智能·算法·机器学习·自然语言处理
ting945200014 分钟前
深度拆解|1752vc Pitch Deck Analyzer 底层技术架构与核心算法原理
人工智能·算法·架构
无名猿15 分钟前
list 与 forward_list:链表真的比 vector 快吗
c++·性能优化·stl·内存管理·标准库
笑鸿的学习笔记18 分钟前
C++笔记之SIMD与SSE指令集
开发语言·c++·笔记
贾斯汀frank21 分钟前
基于 Java + Playwright 实现网站自动访问与数据采集
算法
早睡早起不秃头&22 分钟前
【架构】- 移动机器人系统的插件化:让定位算法独立演进
算法·架构
汉克老师36 分钟前
GESP2026年9月认证C++一级( 第二部分判断题(1~10题)精讲
c++·gesp·小学生·学c++编程
mmmmath_31 小时前
LeetCode.020.有效的括号
数据结构·算法·leetcode
Doubbbbbbble云1 小时前
算法优化中的数学建模与理论界限分析4
算法·数学建模
垆边人似月.1 小时前
华为机考题:字符个数统计
数据结构·算法·华为