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


    题目链接:Link

    Problem

    题目背景

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

    题目描述

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

    1. 协议规定一个固定的质数P,以及模P 的一个原根g。P 和g 的数值都是公开的,无需保密。
    2. Alice 生成一个随机数a,并计算 $ A=g^a mod P $ , 将A 通过不安全信道发送给Bob。
    3. Bob 生成一个随机数b,并计算 $ B=g^b mod P $ ,将B 通过不安全信道发送给Alice。
    4. Bob 根据收到的A 计算出 $ K=A^b mod P $ ,而Alice 根据收到的B 计算出 $ K=B^a mod P $ 。
    5. 双方得到了相同的K,即 $ g^{ab} mod P $。K 可以用于之后通讯的加密密钥。

    可见,这个过程中可能被窃听的只有A、B,而a、b、K 是保密的。并且根据A、B、P、g 这4个数,不能轻易计算出K,因此K 可以作为一个安全的密钥。
    当然安全是相对的,该协议的安全性取决于数值的大小,通常a、b、P 都选取数百位以上的大整数以避免被破解。然而如果Alice 和Bob 编程时偷懒,为了避免实现大数运算,选择的数值都小于2312^{31}231,那么破解他们的密钥就比较容易了。

    输入输出格式

    输入格式:

    输入文件第一行包含两个空格分开的正整数g 和P。
    第二行为一个正整数n, 表示Alice 和Bob 共进行了n 次连接(即运行了n 次协议)。
    接下来n 行,每行包含两个空格分开的正整数A 和B,表示某次连接中,被窃听的A、B 数值。

    输出格式:

    输出包含n行,每行1个正整数K,为每次连接你破解得到的密钥。

    输入输出样例

    in #1

    3 31
    3
    27 16
    21 3
    9 26
    

    out #1

    4
    21
    25
    

    说明

    对于30%的数据,$ 2 leq A,B,P leq 1000 ( 对于100%的数据,) 2 leq A,B le P le 2^{31} , 2 leq g le 20 , 1 leq n leq 20 $


    Solution

    在仔细揣摩题意后,不难发现,实际上就是求 $ g^a equiv A pmod{p} $ 中的a,然后我们就可以愉快地套用BSGS的模板了。
    但有些事情要特别注意:

    • 这道题目中每次BSGS的A都为g,所以预处理要放在循环外面防止重复计算
    • 不全局开long long容易写炸
    • 只要算出A和B中的一个的BSGS就行了,答案是$ B^{BSGS(g,A)} mod p $

    Code

    #include<cstdio>
    #include<cmath>
    #include<map>
    using namespace std;
    typedef long long LL;
    LL g,p,A,B,a,b,n,m,inv;
    map<LL,int> mp;
    inline LL ksm(LL a,LL b) { LL res=1; for(;b;b>>=1,a=a*a%p) b&1?res=res*a%p:0; return res; }
    inline LL BSGS(LL A,LL B)
    {
    	A%=p; B%=p;
    	for(int i=0;i<m;i++)
    	{
    		if(mp[B]) return (i*m+mp[B])%p;
    		B=B*inv%p;
    	}
    	return -1;
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%lld%lld%lld",&g,&p,&n);
    	m=ceil(sqrt(p));
    	LL x=1;
    	for(int i=1;i<=m;i++)
    	{
    		x=x*g%p;
    		mp[x]=i;
    	}
    	inv=ksm(g,p-m-1)%p;
    	while(n-->0)
    	{
    		scanf("%lld%lld",&A,&B);
    		//printf("a=%d b=%d
    ",a,b);
    		printf("%lld
    ",ksm(B,BSGS(g,A))%p);
    	}
    	return 0;
    }
    
  • 相关阅读:
    layui动态修改select的选中项
    ES6数组新增方法
    A Realtime BigData Dashboad
    Spark Streaming
    使用Converter实现控件的动态显隐
    Mysql 使用mysqldump进行备份与还原
    大型Java进阶专题(六) 设计模式之代理模式
    HTML开发之--marquee标签
    iOS开发之--instancetype和id
    请求处理常见tag语法
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11379586.html
Copyright © 2020-2023  润新知