Calculating pow(a,b) mod n
Asked Answered
P

14

34

I want to calculate ab mod n for use in RSA decryption. My code (below) returns incorrect answers. What is wrong with it?

unsigned long int decrypt2(int a,int b,int n)
{
    unsigned long int res = 1;

    for (int i = 0; i < (b / 2); i++)
    {
        res *= ((a * a) % n);
        res %= n;
    }

    if (b % n == 1)
        res *=a;

    res %=n;
    return res;
}
Phellem answered 13/12, 2011 at 21:8 Comment(12)
-1: Have you tried stepping through your code in a debugger? Can you give an example of where it goes wrong?Fania
what is the grouping on your operators?Gymnast
@DanielA.White return wrong answerPhellem
why you don't do pow(a,b) % n?Virtuous
Could you provide an example of what a,b,n might be at run time.Hauge
You can use this library in C++ : mattmccutchen.net/bigint :PSkipper
@JeremyD Blakh,because numbers are too big,so we get Blakh from computer.Phellem
for example, I wanna printf("%ld",decrypt2(57958372,19333081,65541041));Phellem
Seem you need % 2 insted of % n in last ifNorword
For that example, int overflows, but a 64-bit type would be enough. However, if you're seriously going for RSA, you need large integers, gmp would be an option (and has modular power).Miler
What is a Blakh? I tried Googling, but it just thought I mistyped "blake" or "b-lak."Neon
@JeremyD: Because (a) pow() is a floating-point operation and (b) even if it weren't, it's rather wasteful to calculate the entirety of a^b only to throw out most of it in taking the modulus.Notification
D
70

You can try this C++ code. I've used it with 32 and 64-bit integers. I'm sure I got this from SO.

template <typename T>
T modpow(T base, T exp, T modulus) {
  base %= modulus;
  T result = 1;
  while (exp > 0) {
    if (exp & 1) result = (result * base) % modulus;
    base = (base * base) % modulus;
    exp >>= 1;
  }
  return result;
}

You can find this algorithm and related discussion in the literature on p. 244 of

Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, and Source Code in C, Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4.


Note that the multiplications result * base and base * base are subject to overflow in this simplified version. If the modulus is more than half the width of T (i.e. more than the square root of the maximum T value), then one should use a suitable modular multiplication algorithm instead - see the answers to Ways to do modulo multiplication with primitive types.

Dome answered 14/12, 2011 at 0:40 Comment(11)
+1 (I meant to leave a comment earlier) this was very helpful to this question it would be great to find the original source.Bandoline
But what if modulus > sqrt(std::numeric_limits<T>::max())? In that case (result * base) can overflow, and the result will be incorrect.Encamp
@RuudvA: To avoid that you can replace those multiplications with your preferred modular multiplication function. For example: Ways to do modulo multiplication with primitive typesDome
By definition, it is not possible for modulus to have a value that exceeds the maximum its type can represent.Tutty
For a full explanation, see: en.wikipedia.org/wiki/Modular_exponentiationVolsung
Also: khanacademy.org/computing/computer-science/cryptography/…Volsung
T result = 1; --> T result = modulus > 1; or result = 1%modulus to properly function with modpow(x, 0, 1).Controversy
Add if (base==0) return 0; in loop may quickly get result.Vortex
How does this code avoid overflowing the range of T in the calculation of result * base and base * base?Terreverte
@TobySpeight I mentioned that in a comment above. You can use modular multiplication (SO example link).Dome
@Blastfurnace: since that wasn't at all obvious, I've edited your answer to incorporate that link.Terreverte
D
18

In order to calculate pow(a,b) % n to be used for RSA decryption, the best algorithm I came across is Primality Testing 1) which is as follows:

 int modulo(int a, int b, int n){
    long long x=1, y=a; 
    while (b > 0) {
        if (b%2 == 1) {
            x = (x*y) % n; // multiplying with base
        }
        y = (y*y) % n; // squaring the base
        b /= 2;
    }
    return x % n;
}

See below reference for more details.


1) Primality Testing : Non-deterministic Algorithms – topcoder

Dietitian answered 4/4, 2016 at 9:30 Comment(1)
You seem to be assuming that long long has a wider range than int. There's no such guarantee in either C or C++, so this code is still subject to overflow.Terreverte
J
14

Usually it's something like this:

while (b)
{
    if (b % 2) { res = (res * a) % n; }

    a = (a * a) % n;
    b /= 2;
}

return res;
Justino answered 13/12, 2011 at 21:14 Comment(0)
B
7

The only actual logic error that I see is this line:

if (b % n == 1)

which should be this:

if (b % 2 == 1)

But your overall design is problematic: your function performs O(b) multiplications and modulus operations, but your use of b / 2 and a * a implies that you were aiming to perform O(log b) operations (which is usually how modular exponentiation is done).

Bedroll answered 13/12, 2011 at 21:17 Comment(2)
Another logic error I think is: If a == 0 the result is 1 instead of 0. And a should be assigned to a temporary 64 bit variable which in turn is used for the multiplication – to avoid the overflow.Marentic
@ChristianAmmer: Re: if a == 0. Actually no, because as long as b > 0, res will be multiplied by a or a * a at least once. (And if b == 0, then 1 is a perfectly valid return value even if a == 0.) Re: assigning a to a temporary 64-bit variable: I suppose so. Other commenters had already pointed out that 32-bit integers are not enough to use this for realistic RSA encryption, so my answer assumed that this function was just for trying it out with small numbers and getting a handle on how it worked. Maybe I should have made that explicit?Bedroll
U
4

Doing the raw power operation is very costly, hence you can apply the following logic to simplify the decryption.

From here,

Now say we want to encrypt the message m = 7,
c = m^e mod n = 7^3 mod 33 = 343 mod 33 = 13.
Hence the ciphertext c = 13.

To check decryption we compute
m' = c^d mod n = 13^7 mod 33 = 7.
Note that we don't have to calculate the full value of 13 to the power 7 here. We can make use of the fact that
a = bc mod n = (b mod n).(c mod n) mod n
so we can break down a potentially large number into its components and combine the results of easier, smaller calculations to calculate the final value.

One way of calculating m' is as follows:-
Note that any number can be expressed as a sum of powers of 2. So first compute values of
13^2, 13^4, 13^8, ... by repeatedly squaring successive values modulo 33. 13^2 = 169 ≡ 4, 13^4 = 4.4 = 16, 13^8 = 16.16 = 256 ≡ 25.
Then, since 7 = 4 + 2 + 1, we have m' = 13^7 = 13^(4+2+1) = 13^4.13^2.13^1
≡ 16 x 4 x 13 = 832 ≡ 7 mod 33

Unique answered 13/12, 2011 at 21:15 Comment(1)
Well, that appears to be the algorithm he's attempted to implement. The question is what he did wrong.Kazimir
P
2

Are you trying to calculate (a^b)%n, or a^(b%n) ?

If you want the first one, then your code only works when b is an even number, because of that b/2. The "if b%n==1" is incorrect because you don't care about b%n here, but rather about b%2.

If you want the second one, then the loop is wrong because you're looping b/2 times instead of (b%n)/2 times.

Either way, your function is unnecessarily complex. Why do you loop until b/2 and try to multiply in 2 a's each time? Why not just loop until b and mulitply in one a each time. That would eliminate a lot of unnecessary complexity and thus eliminate potential errors. Are you thinking that you'll make the program faster by cutting the number of times through the loop in half? Frankly, that's a bad programming practice: micro-optimization. It doesn't really help much: You still multiply by a the same number of times, all you do is cut down on the number of times testing the loop. If b is typically small (like one or two digits), it's not worth the trouble. If b is large -- if it can be in the millions -- then this is insufficient, you need a much more radical optimization.

Also, why do the %n each time through the loop? Why not just do it once at the end?

Partial answered 13/12, 2011 at 21:21 Comment(1)
Doing the modulo at the end --> res would get unnecessary big and overflow (what it does in his example anyway). Looping until b/2 --> Only half of the iterations are necessary because the compiler would optimize and precalculate (a*a) % n.Marentic
C
2

Calculating pow(a,b) mod n

  1. A key problem with OP's code is a * a. This is int overflow (undefined behavior) when a is large enough. The type of res is irrelevant in the multiplication of a * a.

    The solution is to ensure either:

    • the multiplication is done with 2x wide math or
    • with modulus n, n*n <= type_MAX + 1
  2. There is no reason to return a wider type than the type of the modulus as the result is always represent by that type.

    // unsigned long int decrypt2(int a,int b,int n)
    int decrypt2(int a,int b,int n)
    
  3. Using unsigned math is certainly more suitable for OP's RSA goals.


Also see Modular exponentiation without range restriction

// (a^b)%n
// n != 0

// Test if unsigned long long at least 2x values bits as unsigned
#if ULLONG_MAX/UINT_MAX  - 1 > UINT_MAX
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
  unsigned long long result = 1u % n;  // Insure result < n, even when n==1
  while (b > 0) {
    if (b & 1) result = (result * a) % n;
    a = (1ULL * a * a) %n;
    b >>= 1;
  }
  return (unsigned) result;
}

#else
unsigned decrypt2(unsigned a, unsigned b, unsigned n) {
  // Detect if  UINT_MAX + 1 < n*n
  if (UINT_MAX/n < n-1) {
    return TBD_code_with_wider_math(a,b,n);
  }
  a %= n;
  unsigned result = 1u % n;
  while (b > 0) {
    if (b & 1) result = (result * a) % n;
    a = (a * a) % n;
    b >>= 1;
  }
  return result;
}

#endif
Controversy answered 16/1, 2018 at 0:40 Comment(1)
This is the only answer at present that identifies the cause of the problem and suggests an appropriate resolution. The other answers are all subject to overflow.Terreverte
H
0

Here is another way. Remember that when we find modulo multiplicative inverse of a under mod m. Then

a and m must be coprime with each other.

We can use gcd extended for calculating modulo multiplicative inverse.

For computing ab mod m when a and b can have more than 105 digits then its tricky to compute the result.

Below code will do the computing part :

#include <iostream>
#include <string>
using namespace std;
/*
*   May this code live long.
*/
long pow(string,string,long long);
long pow(long long ,long long ,long long);
int main() {
    string _num,_pow;
    long long _mod;
    cin>>_num>>_pow>>_mod;
    //cout<<_num<<" "<<_pow<<" "<<_mod<<endl;
    cout<<pow(_num,_pow,_mod)<<endl;
   return 0;
}
long pow(string n,string p,long long mod){
    long long num=0,_pow=0;
    for(char c: n){
        num=(num*10+c-48)%mod;
    }
    for(char c: p){
        _pow=(_pow*10+c-48)%(mod-1);
    }
    return pow(num,_pow,mod);
}
long pow(long long a,long long p,long long mod){
    long res=1;
    if(a==0)return 0;
    while(p>0){
        if((p&1)==0){
            p/=2;
            a=(a*a)%mod;
        }
        else{
            p--;
            res=(res*a)%mod;
        }
    }
    return res;
}
 

This code works because ab mod m can be written as (a mod m)b mod m-1 mod m.

Hope it helped { :)

Hefty answered 27/10, 2020 at 3:24 Comment(0)
P
-1

int's are generally not enough for RSA (unless you are dealing with small simplified examples)

you need a data type that can store integers up to 2256 (for 256-bit RSA keys) or 2512 for 512-bit keys, etc

Polyneuritis answered 13/12, 2011 at 21:13 Comment(1)
That's true, but this doesn't attempt to answer how to do "Calculating pow(a,b) mod n". This should be a comment.Psittacosis
O
-1

use fast exponentiation maybe..... gives same o(log n) as that template above

    int power(int base, int exp,int mod)
{
    if(exp == 0)
     return 1;

    int p=power(base, exp/2,mod);
    p=(p*p)% mod;
    return (exp%2 == 0)?p:(base * p)%mod;
}
Ovi answered 9/10, 2016 at 7:8 Comment(1)
Corner failure: power(x, 0, 1) as it returns 1 and not 0. More problems when exp < 0.Controversy
M
-1

This(encryption) is more of an algorithm design problem than a programming one. The important missing part is familiarity with modern algebra. I suggest that you look for a huge optimizatin in group theory and number theory. If n is a prime number, pow(a,n-1)%n==1 (assuming infinite digit integers).So, basically you need to calculate pow(a,b%(n-1))%n; According to group theory, you can find e such that every other number is equivalent to a power of e modulo n. Therefore the range [1..n-1] can be represented as a permutation on powers of e. Given the algorithm to find e for n and logarithm of a base e, calculations can be significantly simplified. Cryptography needs a tone of math background; I'd rather be off that ground without enough background.

Maldonado answered 6/12, 2018 at 18:29 Comment(0)
H
-2
#include <cmath>
...
static_cast<int>(std::pow(a,b))%n

but my best bet is you are overflowing int (IE: the number is two large for the int) on the power I had the same problem creating the exact same function.

Hauge answered 13/12, 2011 at 21:14 Comment(0)
A
-2

I'm using this function:

int CalculateMod(int base, int exp ,int mod){
    int result;
    result = (int) pow(base,exp);
    result = result % mod;
    return result;
}

I parse the variable result because pow give you back a double, and for using mod you need two variables of type int, anyway, in a RSA decryption, you should just use integer numbers.

Alsacelorraine answered 1/9, 2016 at 0:10 Comment(1)
If the result of pow(base, exp) is larger than MAXINT, then you will get an exception when you convert back to an int. Even if you didn't get an exception, you would be taking the mod of the wrong number.Volsung
A
-2

For my code a^k mod n in php:

function pmod(a, k, n)
{
    if (n==1) return 0;
    power = 1;
    for(i=1; i<=k; $i++)
    {
        power = (power*a) % n;
    }
    return power;
}
Anglesite answered 11/8, 2019 at 20:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.