破解 D-H 协议(这辈子都学不会的数论之BSGS算法)

                                       破解 D-H 协议

                                                          时间限制: 1 Sec  内存限制: 128 MB
                                                                           提交: 133  解决: 53
                                                           [提交] [状态] [讨论版] [命题人:admin]

题目描述

Diffie-Hellman密钥交换协议是一种简单有效的密钥交换方法。它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信道(可能被窃听)建立一个安全的密钥K,用于加密之后的通讯内容。
假定通讯双方名为Alice和Bob,协议的工作过程描述如下(其中mod表示取模运算):
协议规定一个固定的质数P,以及模P的一个原根g。P和g的数值都是公开的,无需保密。
Alice生成一个随机数a,并计算A=ga mod P,将A通过不安全信道发送给Bob。
Bob生成一个随机数b,并计算B=gb mod P,将B通过不安全信道发送给Alice。
Bob根据收到的A计算出K=Ab mod P ,而Alice根据收到的B计算出K=Ba mod P。
双方得到了相同的K,即gab mod P。K可以用于之后通讯的加密密钥。
可见,这个过程中可能被窃听的只有A,B,而a,b,K是保密的。并且根据A,B,P,g这4个数,不能轻易计算出K,因此K可以作为一个安全的密钥。
当然安全是相对的,该协议的安全性取决于数值的大小,通常a,b,P都选取数百位以上的大整数以避免被破解。然而如果Alice和Bob编程时偷懒,为了避免实现大数运算,选择的数值都小于231,那么破解他们的密钥就比较容易了。

输入

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

输出

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

样例输入

3 31
3
27 16
21 3
9 26

样例输出

4
21
25

提示

对于30%的数据,2≤A,B,P≤1000。
对于100%的数据,2≤A,B<P<231,2≤g<20,1≤n≤20。

                                                                          [提交] [状态]

题意 :

给你A B g  p ,让你去求K  k=A^b%p 或者k=B^a%p ,bsgs算法解同余方程 a^x % p = b % p

A=g^a%p  等价于  A%p=g^a%p  等价于A≡g^a(mod p) (事实)  就可以套用BSGS算法了    

(恒成立 一般是表示含有未知量的)

因为(    aX=kb+c 等于 aX≡c(mod b)    )。

题解

【bsgs算法】

对于同余方程a^{x}\equiv b\%p      a,b,p都一直,且p为素数,求解x

令 m = sqrt(p) + 1 ( 稍大于sqrt(p)的一个整数)

令 x = i*m - j ,ij均为整数,那么i*m-j一定可以凑出任意一个整数x,并且i只需从1到m,如果有误差,可以通过 j 来调整。

这样一来,同余方程变为a^{i*m}\equiv b*a^{j}\%p

那么恒等式右边,可以枚举 j 预处理放到map里,然后左边枚举 i ,直到在map存在相等的右边值,则结束

解得:x = i*m - j

时间复杂度O(\sqrt{p}logp),当p很大时(1e9),还是要考虑优化,一不小心就超时

所以本题目已知     g^{b}\equiv A\%p   利用bsgs求解b,所以答案K=A^{b}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;


ll qpow(ll n,ll m,ll p)
{

    n%=p;
    ll ans=1;
    for(;m;m>>=1)
    {

        if(m&1)ans=ans*n%p;
        n=n*n%p;
    }
    return ans;
}

int main()
{

    ll g,p,A,B,n;
    scanf("%lld%lld%lld",&g,&p,&n);
    ll m=sqrt(p)+1; //x=i*m-j,注意m必须大于sqrt(p)
    map<ll,ll>M; //预处理g^j
    ll res=1; //a^0
    for(int j=0;j<=m;j++)
    {
        M[res%p]=j;
        res=res*g%p;
    }
    ll dk=qpow(g,m,p);
    while(n--)
    {
        scanf("%lld%lld",&A,&B);
        int a,b;
        ll k=dk*qpow(B,p-2,p)%p;
        for(int i=1;i<=m;i++)
        {

            if(M.count(k))
            {
                b=i*m-M[k];
                break;
            }
            k=k*dk%p;
        }
        ll ans=qpow(A,b,p);
        printf("%lld\n",ans);

    }

}

猜你喜欢

转载自blog.csdn.net/qq_41021816/article/details/81582932