3
votes

I discovered the following code. I know, it looks less weird/exciting than this one using seemingly random numbers, but it seems to be more complex than this one using bit shifts on a large number:

long[] c = {130636800L, -5080148640L, 13802573088L, -14974335980L, 8683908340L,
           -3006955245L, 651448014L, -89047770L, 7457160L, -349165L, 6998L};

for (int x = 0; x < 11; x++) {
    long s = 0;
    for (int i = 0; i < 11; i++)
        s += c[i] * Math.pow(x, i);

    System.out.print((char)(s / 1814400));
}

Code on Ideone

Output:

HELLO WORLD

How does it work? Is it some form of encryption or did anyone get mad constructing it?

2
Hint: what about reversing the whole computation?! There is nothing magic in there, just numbers that undergo some computations.GhostCat
"How does it work?" - it's pencil and paper time.....Mitch Wheat
@MitchWheat Maybe maybe with a calculator, too.GhostCat
I wouldn't call it "encryption" so much as "obfuscation".Fred Larson
No one went mad constructing it, but they likely had a lot of free time. :) They just took each code point of the message, applied a few operations on it, ended up with a value, then wrote a program that reversed those operations to recover the original code points. Someone is likely to provide full details in the answer section.Ray Toal

2 Answers

5
votes

Let's get into some math:

Solve the below equations and you get your answers. These equations have one unique solution as the number of equations equals the number of unknown variables.

Let c[0] = 72, which is the ASCII value of 'H'.

For clarity: I've used ^ for raised to convention. Now solve:

1^0 * c[0] + 1^1 * c[1] + 1^2 * c[2] + 1^3 * c[3] + 1^4 * c[4] + 1^5 * c[5] + 1^6 * c[6] + 1^7 * c[7] + 1^8 * c[8] + 1^9 * c[9] + 1^10 * c[10] = 69
2^0 * c[0] + 2^1 * c[1] + 2^2 * c[2] + 2^3 * c[3] + 2^4 * c[4] + 2^5 * c[5] + 2^6 * c[6] + 2^7 * c[7] + 2^8 * c[8] + 2^9 * c[9] + 2^10 * c[10] = 76
3^0 * c[0] + 3^1 * c[1] + 3^2 * c[2] + 3^3 * c[3] + 3^4 * c[4] + 3^5 * c[5] + 3^6 * c[6] + 3^7 * c[7] + 3^8 * c[8] + 3^9 * c[9] + 3^10 * c[10] = 76
4^0 * c[0] + 4^1 * c[1] + 4^2 * c[2] + 4^3 * c[3] + 4^4 * c[4] + 4^5 * c[5] + 4^6 * c[6] + 4^7 * c[7] + 4^8 * c[8] + 4^9 * c[9] + 4^10 * c[10] = 79
5^0 * c[0] + 5^1 * c[1] + 5^2 * c[2] + 5^3 * c[3] + 5^4 * c[4] + 5^5 * c[5] + 5^6 * c[6] + 5^7 * c[7] + 5^8 * c[8] + 5^9 * c[9] + 5^10 * c[10] = 32
6^0 * c[0] + 6^1 * c[1] + 6^2 * c[2] + 6^3 * c[3] + 6^4 * c[4] + 6^5 * c[5] + 6^6 * c[6] + 6^7 * c[7] + 6^8 * c[8] + 6^9 * c[9] + 6^10 * c[10] = 87  
7^0 * c[0] + 7^1 * c[1] + 7^2 * c[2] + 7^3 * c[3] + 7^4 * c[4] + 7^5 * c[5] + 7^6 * c[6] + 7^7 * c[7] + 7^8 * c[8] + 7^9 * c[9] + 7^10 * c[10] = 79  
8^0 * c[0] + 8^1 * c[1] + 8^2 * c[2] + 8^3 * c[3] + 8^4 * c[4] + 8^5 * c[5] + 8^6 * c[6] + 8^7 * c[7] + 8^8 * c[8] + 8^9 * c[9] + 8^10 * c[10] = 82  
9^0 * c[0] + 9^1 * c[1] + 9^2 * c[2] + 9^3 * c[3] + 9^4 * c[4] + 9^5 * c[5] + 9^6 * c[6] + 9^7 * c[7] + 9^8 * c[8] + 9^9 * c[9] + 9^10 * c[10] = 76
10^0 * c[0] + 10^1 * c[1] + 10^2 * c[2] + 10^3 * c[3] + 10^4 * c[4] + 10^5 * c[5] + 10^6 * c[6] + 10^7 * c[7] + 10^8 * c[8] + 10^9 * c[9] + 10^10 * c[10] = 68

Note that the number of unknowns are c[1] to c[10], so 10. We know that c[0] = 72, so it is not an unknown and the number of equations is 10.

Now we just multiply all numbers with 1814400, divide by the same in the answer, so it doesn't change anything or probably the answer found by solving the equations would not be whole numbers, so multiply by 1814400 to get whole numbers.

You can solve these equations by using this code for solving simultaneous equations of any order.

2
votes

Inspired by the answer from user9823668, I found another way on how to reverse the calculation. The inner loop of the code (including the division from the output line) basically represents the following polynomial:

Polynomial of the inner loop

This polynomial is calculated for the values 0 to 10 in the outer loop of the code and yields the resulting ASCII characters. So the question is: How to fit a polynomial through given consecutive data points?

One of my search results points to the term Newton polynomial. This is a so-called interpolation polynomial for a given set of data points. As the polynomial is calculated for the values 0 to 10, we have the special case of xi = i here. Thus, in order to construct the above polynomial, we have to calculate some binomial coefficients.

At first we have to calculate the divided differences on the data points (i.e. the ASCII-encoded function output):

 0: H = 72
 1: E = 69  -3
 2: L = 76   7  10
 3: L = 76   0  -7  -17
 4: O = 79   3   3   10   27
 5:   = 32 -47 -50  -53  -63  -90
 6: W = 87  55 102  152  205  268   358
 7: O = 79  -8 -63 -165 -317 -522  -790 -1148
 8: R = 82   3  11   74  239  556  1078  1868  3016
 9: L = 76  -6  -9  -20  -94 -333  -889 -1967 -3835 -6851
10: D = 68  -8  -2   7    27  121   454  1343  3310  7145 13996

Then, the topmost entries in each column are the coefficients that we need to construct the interpolating polynomial:

72
-     3 /       1 x
+    10 /       2 x(x-1)
-    17 /       6 x(x-1)(x-2)
+    27 /      24 x(x-1)(x-2)(x-3)
-    90 /     120 x(x-1)(x-2)(x-3)(x-4)
+   358 /     720 x(x-1)(x-2)(x-3)(x-4)(x-5)
-  1148 /    5040 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)
+  3016 /   40320 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)
-  6851 /  362880 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)(x-8)
+ 13996 / 3628800 x(x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7)(x-8)(x-9)

Here, the denominators represents n! (see the special case). By expanding this formula (e.g. by using WolframAlpha), you get the polynomial shown above. In case anyone wonders, the polynomial looks as follows:

Plot of the polynomial