PKU 2447 - RSA (欧几里得扩展 + 大合数分解)

题意

有几个数之间的关系。

P、Q是两个质数。$T = (P-1) (Q-1), N = P Q$

E是一个和T互质的数。

D是一个数,这个数符合$(E * D) \bmod T = {1}$

题目给出C, E, N,要求求出$M = C^{D} \bmod N

思路

通过N,分解出P、Q。
然后就可以得到T

因为知道E和T,根据D的那条式子化简得$ED + T*(-k) = 1$

求欧几里得扩展$ED + T*(-k) = gcd(E, T) = 1$

所以求出来得解正好是方程的解。

求出D之后用快速幂取模就能得出答案。

代码

set<LL> fac;
 
inline LL FixMod(LL a, LL mod)
{
    while (a < 0) a += mod;
    while (a >= mod) a -= mod;
    return a;
}
 
LL multi(LL a, LL b, LL m)
{
    LL ans = 0;
    a %= m;
    while(b)
    {
        if(b & 1)
        {
            ans = FixMod(ans + a, m);
            b--;
        }
        b >>= 1;
        a = FixMod((a<<1), m);
    }
    return ans;
}
 
LL quick_mod(LL a, LL b, LL m)
{
    LL ans = 1;
    a %= m;
    while(b)
    {
        if(b & 1)
        {
            ans = multi(ans, a, m);
            b--;
        }
        b >>= 1;
        a = multi(a, a, m);
    }
    return ans;
}
 
bool Miller_Rabin(LL n)
{
    if(n == 2) return true;
    if(n < 2 || !(n & 1)) return false;
    LL m = n - 1;
    int k = 0;
    while((m & 1) == 0)
    {
        k++;
        m >>= 1;
    }
    for(int i=0; i<10; i++)
    {
        LL a = rand() % (n - 1) + 1;
        LL x = quick_mod(a, m, n);
        LL y = 0;
        for(int j=0; j<k; j++)
        {
            y = multi(x, x, n);
            if(y == 1 && x != 1 && x != n - 1) return false;
            x = y;
        }
        if(y != 1) return false;
    }
    return true;
}
 
LL pollard_rho(LL n, LL c)
{
    LL i = 1, k = 2;
    LL x = rand() % (n - 1) + 1;
    LL y = x;
    while(true)
    {
        i++;
        x = (multi(x, x, n) + c) % n;
        LL d = __gcd((y - x + n) % n, n);
        if(1 < d && d < n) return d;
        if(y == x) return n;
        if(i == k)
        {
            y = x;
            k <<= 1;
        }
    }
}
 
bool Find(LL n, int c)          //如果是素数返回false
{
    if(n == 1) return false;
    if(Miller_Rabin(n))
    {
        fac.insert(n);
        return false;
    }
    LL p = n;
    LL k = c;
    while(p >= n) p = pollard_rho(p, c--);
    Find(p, k);
    Find(n / p, k);
    return true;
}
 
void GCD_Ext(LL a, LL b, LL &d, LL &x, LL &y)
{
    if (!b) d = a, x = 1, y = 0;
    else
    {
        GCD_Ext(b, a % b, d, y, x);
        y -= x * (a / b);
    }
}
 
int main()
{
    LL C, E, N;
    while (~scanf("%lld%lld%lld", &C, &E, &N))
    {
        fac.clear();
        Find(N, 120);
        LL p = *fac.begin(), q = *(++fac.begin());
        LL N = p * q, T = (p-1) * (q-1);
        LL d, x, y;
        GCD_Ext(E, T, d, x, y);
        x = (x % T + T) % T;
        printf("%lld\n", quick_mod(C, x, N));
    }
    return 0;
}

Powered by Jekyll and Theme by solid