Modular Exponentiation over a Power of 2

2019-09-03 07:31发布

问题:

So I've been doing some work recently with the modpow function. One of the forms I needed was Modular Exponentiation when the Modulus is a Power of 2. So I got the code up and running. Great, no problems. Then I read that one trick you can make to get it faster is, instead of using the regular exponent, takes it's modulus over the totient of the modulus.

Now when the modulus is a power of two, the answer is simply the power of 2 less than the current one. Well, that's simple enough. So I coded it, and it worked..... sometimes.

For some reason there are some values that aren't working, and I just can't figure out what it is.

uint32 modpow2x(uint32 B, uint32 X, uint32 M)
{
    uint32 D;

    M--;
    B &= M;
    X &= (M >> 1);
    D = 1;
    if ((X & 1) == 1)
    {
        D = B;
    }

    while ((X >>= 1) != 0)
    {
        B = (B * B) & M;
        if ((X & 1) == 1)
        {
            D = (D * B) & M;
        }
    }
    return D;
}

And this is one set of numbers that it doesn't work for.

Base = 593803430
Exponent = 3448538912
Modulus = 8

And no, there is no check in this function to determine if the Modulus is a power of 2. The reason is that this is an internal function and I already know that only Powers of 2 will be passed to it. However, I have already double checked to make sure that no non-powers of 2 are getting though.

Thanks for any help you guys can give!

回答1:

It's true that if x is relatively prime to n (x and n have no common factors), then x^a = x^(phi(a)) (mod n), where phi is Euler's totient function. That's because then x belongs to the multiplicative group of (Z/nZ), which has order phi(a).

But, for x not relatively prime to n, this is no longer true. In your example, the base does have a common factor with your modulus, namely 2. So the trick will not work here. If you wanted to, though, you could write some extra code to deal with this case -- maybe find the largest power of 2 that x is divisible by, say 2^k. Then divide x by 2^k, run your original code, shift its output left by k*e, where e is your exponent, and reduce modulo M. Of course, if k isn't zero, this would usually result in an answer of zero.