BZOJ-4522 [Cqoi2016]金鑰破解(Pollard-Rho演算法+exgcd)
阿新 • • 發佈:2020-12-05
題目描述
一種非對稱加密演算法的金鑰生成過程如下:
\(1.\) 任選兩個不同的質數 \(p,q\)。
\(2.\) 計算 \(N=pq,r=(p-1)(q-1)\)。
\(3.\) 選取小於 \(r\) ,且與 \(r\) 互質的整數 \(e\)。
\(4.\) 計算整數 \(d\),使得 \(ed\equiv 1 \pmod {r}\)。
\(5.\) 二元組 \((N,e)\) 稱為公鑰,二元組 \((N,d)\) 稱為私鑰。
當需要加密訊息 \(n\) 時(假設 \(n\) 是一個小於 N 的整數,因為任何格式的訊息都可轉為整數表示),使用公鑰 \((N,e)\)
對密文 \(c\) 解密時,用私鑰 \((N,d)\),按照 \(c^d\equiv n \pmod {N}\) 運算,可得到原文 \(n\)。演算法正確性證明省略。
由於用公鑰加密的密文僅能用對應的私鑰解密,而不能用公鑰解密,因此稱為非對稱加密演算法。通常情況下,公鑰由訊息的接收方公開,而私鑰由訊息的接收方自己持有。這樣任何傳送訊息的人都可以用公鑰對訊息加密,而只有訊息的接收方自己能夠解密訊息。
現在,你的任務是尋找一種可行的方法來破解這種加密演算法,即根據公鑰破解出私鑰,並據此解密密文。
輸入:\(e,N,c(N\leq 2^{62},c<N)\),輸出:\(d,n\)。
分析
\(1.\) \(\text{Pollard-Rho}\) 分解 \(N\)。
$2. $ 取 \(N\) 兩個質因數 $p,q $,得到 \(r\)。
\(3.\) 利用擴充套件歐幾里得演算法求出 \(e\) 的逆元 \(d\)。
\(4.\) \(c,d\) 都已知,快速冪算 \(n\)。
程式碼
#include<bits/stdc++.h> using namespace std; #define int128 __int128 long long e,N,c,r,d,n; long long quick_pow(long long a,long long b,long long mod) { long long ans=1; while(b) { if(b&1) ans=(int128)ans*a%mod; a=(int128)a*a%mod; b>>=1; } return ans; } long long max_factor; bool Miller_Rabin(long long p) { if(p<2) return 0; if(p==2) return 1; if(p==3) return 1; long long d=p-1,r=0; while(d%2==0) { r++; d>>=1; } for(long long k=0;k<10;k++) { long long a=rand()%(p-2)+2; long long x=quick_pow(a,d,p); if(x==1||x==p-1) continue; for(int i=0;i<r-1;i++) { x=(int128)x*x%p; if(x==p-1) break; } if(x!=p-1) return 0; } return 1; } long long f(long long x,long long c,long long n) { return ((int128)x*x+c)%n; } long long Pollard_Rho(long long n) { long long s=0,t=0; long long c=rand()%(n-1)+1; int step=0,goal=1; long long val=1; for(goal=1; ;goal<<=1,s=t,val=1) { for(step=1;step<=goal;step++) { t=f(t,c,n); val=(int128)val*abs(t-s)%n; if(step%127==0) { long long d=__gcd(val,n); if(d>1) return d; } } long long d=__gcd(val,n); if(d>1) return d; } } vector<long long> factor; void fac(long long x) { if(x<=max_factor||x<2) return ; if(Miller_Rabin(x)) { factor.push_back(x); //max_factor=max(max_factor,x); return ; } long long p=x; while(p>=x) p=Pollard_Rho(x); while(x%p==0) x=x/p; fac(x);fac(p); } void exgcd(long long a,long long b,long long &x,long long &y) { if(!b) { x=1; y=0; return ; } exgcd(b,a%b,y,x); y=y-(int128)(a/b)*x%r; y=(y%r+r)%r; } long long inv(long long a,long long b)//ax=1(mod b) { long long x,y; exgcd(a,b,x,y); x=(x%b+b)%b; return x; } int main() { srand((unsigned)time(NULL)); cin>>e>>N>>c; fac(N); r=(factor[0]-1)*(factor[1]-1); d=inv(e,r); n=quick_pow(c,d,N); cout<<d<<" "<<n<<endl; return 0; }