7

Given the code:

uint Function(uint value)
{
  return value * 0x123456D;
}

Inputting the value 0x300 yields the result 0x69D04700. This is only the lower 32 bits of the result. Given the result 0x69D04700 and the factor 0x123456D, is it possible to retrieve all numbers such that (value * 0x123456D) & 0xFFFFFFFF = 0x69D04700 in a fast way?

Edit: The code I show is pseudocode - I can't widen the return type.

jakobbotsch
  • 6,167
  • 4
  • 26
  • 39

6 Answers6

4

What you need is modular division, which can be computed with a version of Euclid's algorithm. In this case the result is 768.

This is very fast -- time (log n)2 even for a naive implementation. (If you needed to work with large numbers I could give references to better algorithms.)

See extended Euclidean algorithm for a sketch of how to implement this.

Charles
  • 11,269
  • 13
  • 67
  • 105
  • The 300 was decimal, not hex, but this looks promising. Anywhere I can read up on this specific version of Euclid's algorithm? – jakobbotsch Aug 04 '11 at 16:36
  • The 300 was hex, my bad, so 768 is correct! How did you come to this answer? I can't just calculate GCD(0x69D04700, 0x123456D). – jakobbotsch Aug 04 '11 at 17:13
  • 1
    In GP you'd type `Mod(1775257344,2^32)/19088749`. But you'll have to define your own operator, starting with the extended Euclidean algorithm. I edited in a Wikipedia reference. – Charles Aug 04 '11 at 18:17
  • There is also a thread [C# ModInverse function](https://stackoverflow.com/questions/7483706/). – Jeppe Stig Nielsen Jul 03 '17 at 19:31
0

Your function:

uint Function(uint value)
{
  return value * 0x123456D;
}

multiplies in uint (which works just like the integers modulo 2**64 in so-called unchecked context) by an odd number. Such an odd number has a unique inverse, modulo 2**64. In this case it is 0xE2D68C65u, because as you may check (C# syntax):

unchecked(0x123456Du * 0xE2D68C65u) == 1u

This multiplication is associative and commutative. So your "reverse" method is:

uint UndoFunction(uint value)
{
  return value * 0xE2D68C65u;
}

(unckecked context assumed).

For any input x, both UndoFunction(Function(x)) and Function(UndoFunction(x)) give you back the original x.


PS! To find the modular inverse 0xE2D68C65u, I used something other than .NET. Actually GP/PARI like Charles in his answer. In GP, you can do 1/Mod(19088749, 2^32) or Mod(19088749, 2^32)^-1. It uses decimal notation by default.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
0

Well, you could construct long values with the low half equal to your result and the high half = 1,2,3,4,5..., divide by your fixed multiplier, and see if you get a result with no remainder. It's possible this could be sped up slightly by understanding patterns in the numbers, such that you could throw out even values or some such.

But I'm thinking that there's no significantly less exhaustive approach (and have the vague suspicion that the fact that this is hard to do is related to some encryption techniques).

Well ...

Take that all back

import java.io.*;
public class multiply {
    public static void main(String[] argv) {
        long multiplier = 0x123456DL;
        // long result = 0x69D04700L;
        long result = (multiplier * 300L) & 0xFFFFFFFFL;
        System.out.println("New result = " + Long.toHexString(result));
        long offset = (multiplier * 300L) >> 32;
        System.out.println("New offset = " + offset);
        for (int i = 0; i < 30; i++) {
            long test = result + (((i * multiplier) + offset) << 32);
            long quotient = test / multiplier;
            long remainder = test % multiplier;
            System.out.println("Test: " + Long.toHexString(test) + " quotient: " + Long.toHexString(quotient) + " remainder: " + Long.toHexString(remainder));
        }
    }
}

Results (corrected):

C:\JavaTools>java multiply
New result = 55555bbc
New offset = 1
Test: 155555bbc quotient: 12c remainder: 0
Test: 123456e55555bbc quotient: 10000012c remainder: 0
Test: 2468adb55555bbc quotient: 20000012c remainder: 0
Test: 369d04855555bbc quotient: 30000012c remainder: 0
Test: 48d15b555555bbc quotient: 40000012c remainder: 0
Test: 5b05b2255555bbc quotient: 50000012c remainder: 0
Test: 6d3a08f55555bbc quotient: 60000012c remainder: 0
Test: 7f6e5fc55555bbc quotient: 70000012c remainder: 0
Test: 91a2b6955555bbc quotient: 80000012c remainder: 0
Test: a3d70d655555bbc quotient: 90000012c remainder: 0
Test: b60b64355555bbc quotient: a0000012c remainder: 0
Test: c83fbb055555bbc quotient: b0000012c remainder: 0
Test: da7411d55555bbc quotient: c0000012c remainder: 0
Test: eca868a55555bbc quotient: d0000012c remainder: 0
Test: fedcbf755555bbc quotient: e0000012c remainder: 0
Test: 1111116455555bbc quotient: f0000012c remainder: 0
Test: 123456d155555bbc quotient: 100000012c remainder: 0
Test: 13579c3e55555bbc quotient: 110000012c remainder: 0
Test: 147ae1ab55555bbc quotient: 120000012c remainder: 0
Test: 159e271855555bbc quotient: 130000012c remainder: 0
Test: 16c16c8555555bbc quotient: 140000012c remainder: 0
Test: 17e4b1f255555bbc quotient: 150000012c remainder: 0
Test: 1907f75f55555bbc quotient: 160000012c remainder: 0
Test: 1a2b3ccc55555bbc quotient: 170000012c remainder: 0
Test: 1b4e823955555bbc quotient: 180000012c remainder: 0
Test: 1c71c7a655555bbc quotient: 190000012c remainder: 0
Test: 1d950d1355555bbc quotient: 1a0000012c remainder: 0
Test: 1eb8528055555bbc quotient: 1b0000012c remainder: 0
Test: 1fdb97ed55555bbc quotient: 1c0000012c remainder: 0
Test: 20fedd5a55555bbc quotient: 1d0000012c remainder: 0

OK, I see the quotients (other than the first) are > 32 bits.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • That was what I was afraid of. If no one can give a better answer I will mark this as the answer later. – jakobbotsch Aug 04 '11 at 16:33
  • I was about to say that there are a nearly infinite number of answers, but on reflection I'm guessing there are only about 224. – Hot Licks Aug 04 '11 at 16:45
  • There is only one answer that satisfies the condition (value * 0x123456D) & 0xFFFFFFFF == 0x69D04700, and that is, as noted above, 768. – jakobbotsch Aug 04 '11 at 16:57
  • I don't know the "*300L" which is what I want to begin with. There is no way for me to get the variable "offset" as you use. – jakobbotsch Aug 04 '11 at 17:23
0

If you take 0x100000000 and divide it by 0x123456D, you get 224.9999 (decimal). This tells you that approximately every 225 numbers, you'll hit the remainder. Of course, because it isn't exactly 225, you don't hit the remainder with integers. As @Jacob has pointed out, in 32-bit world, you'll only hit one value (768 or 0x300). So for this particular test, the answer is 2^32 * X + 768, for all integers X >= 0.

Joel Rondeau
  • 7,486
  • 2
  • 42
  • 54
0

Yes, it is possible.

Use the Chinese Remainder Theorem.

You know that

n = 0 (mod 0x123456D)

and

n = 0x69D04700 (mod 0x100000000)

These are relatively prime, since 0x123456D is odd and '0x100000000' is a power of two. So the Chinese remainder theorem applies, and it gives you

n = 0x369D04700 (mod 0x123456D00000000)

This tells you that the results without truncation are 0x369D04700 + k * 0x123456D00000000. Dividing that by 0x123456D gives you 0x300 + k * 0x100000000.

starblue
  • 55,348
  • 14
  • 97
  • 151
-1

Not with the return type you specify. If you want to be able to handle 64 bits, you have to specify the return type as a ulong (or UInt64). C# uses strict static typing in cases like this, and will not automatically "upconvert" values if the result cannot be stored in the defined type. Even if it did upconvert, it would have to cast back down to provide a legal return type, because in .NET's inheritance hierarchy, UInt64 is not derived from UInt32.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • I am aware that the operation overflows and only the lower 32 bits are returned. This is only pseudocode, not actual production code. I want to know if there is a fast way to find all values that multiplied with a known factor, even if overflowing, produces a specific result. – jakobbotsch Aug 04 '11 at 16:30