zoukankan      html  css  js  c++  java
  • poj2447

    题意:两个素数P,Q。N=P*Q; T=(P-1)*(Q-1); (E*D)mod T = 1; (0<=D<T)。E与T互质,公钥是{E,N},私钥是{D,N}。原始信息M的加密过程为C=(M^E)mod N; 解密过程为 M=(C^D)mod N;("^"表示幂) 现在给出C,E,N(<2^62)。求M。

    分析:先通过N分解求P,Q(pollard-rho+Miller-rabin)。通过P,Q求T,通过(E*D)mod T = 1求D(扩展欧几里德),通过M=(C^D)mod N求M。

    如何使用扩展欧几里德呢,

    (E*D)mod T = 1 <=> (E*D) = 1 + k*T <=> E*(D*g) + T*[(-k)*g] = g(g是T和E的最大公约数gcd(T,E))。

    不过这道题好像不用这么麻烦,因为E和T互质,所以g=1。

    这样就变成了a*x+b*y=gcd(a,b)的形式了。

    pollard-rho和Miller-rabin算法参见poj1811解题报告 http://www.cnblogs.com/rainydays/archive/2011/09/01/2162049.html

    扩展欧几里德算法参见poj1061解题报告 http://www.cnblogs.com/rainydays/archive/2013/07/19/3201618.html

    #include <cstdio>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    typedef long long LL;
    #define maxn 10000
    const int S=20;
    
    LL factor[maxn];
    int tot;
    
    LL muti_mod(LL a,LL b,LL c){    //返回(a*b) mod c,a,b,c<2^63
        a%=c;
        b%=c;
        LL ret=0;
        while (b){
            if (b&1){
                ret+=a;
                if (ret>=c) ret-=c;
            }
            a<<=1;
            if (a>=c) a-=c;
            b>>=1;
        }
        return ret;
    }
    
    LL pow_mod(LL x,LL n,LL mod){  //返回x^n mod c ,非递归版
        if (n==1) return x%mod;
        int bit[64],k=0;
        while (n){
            bit[k++]=n&1;
            n>>=1;
        }
        LL ret=1;
        for (k=k-1;k>=0;k--){
            ret=muti_mod(ret,ret,mod);
            if (bit[k]==1) ret=muti_mod(ret,x,mod);
        }
        return ret;
    }
    
    bool check(LL a,LL n,LL x,LL t){   //以a为基,n-1=x*2^t,检验n是不是合数
        LL ret=pow_mod(a,x,n),last=ret;
        for (int i=1;i<=t;i++){
            ret=muti_mod(ret,ret,n);
            if (ret==1&& last!=1&& last!=n-1) return 1;
            last=ret;
        }
        if (ret!=1) return 1;
        return 0;
    }
    
    bool Miller_Rabin(LL n){
        LL x=n-1,t=0;
        while ((x&1)==0) x>>=1,t++;
        bool flag=1;
        if (t>=1&& (x&1)==1){
            for (int k=0;k<S;k++){
                LL a=rand()%(n-1)+1;
                if (check(a,n,x,t)) {flag=1;break;}
                flag=0;
            }
        }
        if (!flag || n==2) return 0;
        return 1;
    }
    
    LL gcd(LL a,LL b){
        if (a==0) return 1;
        if (a<0) return gcd(-a,b);
        while (b){
            LL t=a%b; a=b; b=t;
        }
        return a;
    }
    
    LL Pollard_rho(LL x,LL c){
        LL i=1,x0=rand()%x,y=x0,k=2;
        while (1){
            i++;
            x0=(muti_mod(x0,x0,x)+c)%x;
            LL d=gcd(y-x0,x);
            if (d!=1&& d!=x){
                return d;
            }
            if (y==x0) return x;
            if (i==k){
                y=x0;
                k+=k;
            }
        }
    }
    
    void findfac(LL n){           //递归进行质因数分解N
        if (!Miller_Rabin(n)){
            factor[tot++] = n;
            return;
        }
        LL p=n;
        while (p>=n) p=Pollard_rho(p,rand() % (n-1) +1);
        findfac(p);
        findfac(n/p);
    }
    
    void gcdExtend(long long a,long long b,long long &d,long long &x,long long &y)
    {
         if(!b) {d=a;x=1;y=0;return;}
         gcdExtend(b,a%b,d,y,x);
         y-=a/b*x;
    }
    
    int main()
    {
        LL C, E, N, T, M, D;
        LL x, y, d;
        while (~scanf("%lld%lld%lld", &C, &E, &N))
        {
            tot = 0;
            findfac(N);
            T = (factor[0] - 1) * (factor[1] - 1);
            gcdExtend(E, T, d, x, y);
            D = (x % T + T) % T;
            M = pow_mod(C, D, N);
            printf("%lld
    ", M);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/rainydays/p/3292475.html
Copyright © 2011-2022 走看看