-3

Say I choose a value for x that can be between 0 and 2147483647. (Int32.MaxValue) I am trying to figure out how I can find values for a,b,n so that (a^b)%n=x I already know that I can use ModPow to verify the values, but I don't know how I can find a fitting a,b and n.

#include <iostream>

/// Calculate (a^b)%n
/// \param a The base
/// \param b The exponent
/// \param n The modulo
/// \return (a^b)%n
int ModPow(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;
}

int main() {

    int x = 1337;

    // How to find a,b,n so that (a^b)%n=x
    int a = ?;
    int b = ?;
    int n = ?;

    if(x == ModPow(a,b,n))
        printf("ok");

    return 0;
}
Kyu96
  • 1,159
  • 2
  • 17
  • 35
  • 5
    Try a=x, b=1, n = x+1 – alter_igel Jun 22 '18 at 18:08
  • How is the routine to choose between the infinitely many possible answers? Are you counting on the `int32` limitation to reduce the number of solutions much? – Rory Daulton Jun 22 '18 at 18:09
  • 4
    Brute force it. There is no other way. That equation is at the root of PKI cryptography. If you find a faster way you will get a prize. – Richard Critten Jun 22 '18 at 18:09
  • @alterigel I want them to be 'somewhat random', aka `a != x`. – Kyu96 Jun 22 '18 at 18:10
  • 3
    @RichardCritten ... and roll an entire industry to its knees in the process. =P. I put it on my bucket list to solve this as soon as I finish up that other task of [solving the halting problem](https://en.wikipedia.org/wiki/Halting_problem) first. – WhozCraig Jun 22 '18 at 18:10
  • @RoryDaulton Yes I want to limit the solutions to the first possible one. – Kyu96 Jun 22 '18 at 18:14
  • What exactly is "the first possible one"? Alter igel already gave you one solution. What ordering of solutions are you using to choose the "first one"? – Rory Daulton Jun 22 '18 at 18:18
  • Any solution with `a != x` and `b != 1` will do, as long as there is one within int32 range. – Kyu96 Jun 22 '18 at 18:27
  • I assume that `x` is the smallest solution between 0 and int32.maxvalue – Kyu96 Jun 22 '18 at 18:28
  • @RichardCritten: Not really, since he gets to choose `a` and `n`. – President James K. Polk Jun 22 '18 at 19:48
  • 1
    @RichardCritten: So where do I go witj my (rewritten) answer to claim that price? ;) – MvG Jun 24 '18 at 10:26

2 Answers2

2
int n = 2147483647
int a = ModPow(x, 9241, n);
int b = 464773;

n = 231 − 1 is a prime number. So due to Fermat's little theorem, xn mod n = x and xn − 1 mod n = 1 (unless x = 0) so x2 n − 1 mod n = x, too. 2 n − 1 = 9241 × 464773. So (x9241 mod n)464773 mod n = x. Note that you need x < n for this to work; x = 2147483647 cannot work if n is a 31 bit (i.e. signed) integer, too.

It took me a while to get here; for a long time I've had this answer messing about with Carmichael numbers and the Carmichael function before I reached this easy solution. See edit history for details.

MvG
  • 57,380
  • 22
  • 148
  • 276
1

The modulus operator:

Yields the remainder given by the following expression, where e1 is the first operand and e2 is the second: e1 – (e1 / e2) * e2

Therefor whatever the max value of x is, n must be larger. Since you're validating with n as an int and you're specifying the range: 0 and numeric_limits<int>::max() that must be an exclusive range, and for n to be an int the only possible value it can take is: numeric_limits<int>::max().

With n forced our equation effectively becomes: ab = x.
We'll need to do a check here that x is not 1, if it is b = 0 and a can be anything in our legal range so we can arbitrarily pick a = 2. But baring this:

Our requirements are:

  • 1 < a < x and a is an int
  • 1 < b < x and b is an int

Given x, we can search for a combination of a and b that will fit as follows:

auto a = 0.0;
auto b = 1;

if(x == 1) {
    a = 2.0;
    b = 0;
} else {
    while((a = pow(x, 1.0 / ++b)) > 2.0) {
        double dummy;

        if(modf(a, &dummy) == 0.0) {
            break;
        }
    }
}

At this point, if a >= 2.0 then there is a valid solution to the problem. Now as you as you are probably well aware, pow is a very expensive function so this will likely take a very long time to execute for larger values of x, I'd personally suggest finding an a and b for every number for which such a pair exists and storing them in a map and doing a lookup on that.
Anyway this is a demonstration of working code:

Live Example

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288