# John's revenge!

You are a spy that wanted to find out the job of a man named John. There are 100 glasses in front of you. There is also a note:

Hello! 99 of the glasses in front of you are poisoned! One is safe, however. Just remember that you only get one try! Here's a hint, to make it easier:

VDFVXDVADXVAAVGAGXAVAVGGGGXAFGGAXGAGVVXFGAVDXGDX

Enjoy your drink, if you can!

- John

P.S. If you don't drink one, a huge elephant shall fall out of the sky and crush you to death. You have one week.

Which glass should you drink from?

• This looks like a pretty famous cipher, but the text is definitely too short to decrypt without a key. Are you sure we have all the information we need? Is the cipher text the only relevant part, or something in the story or its wording is important too? – Aioros Aug 17 '15 at 15:52
• @Aioros Search everywhere. The key is hidden in a method I've used on various occasions. – user9377 Aug 17 '15 at 16:11
• @Kslkgh, I think I know the cipher and I think I know the key, but I can't for the life of me figure out what the keyword is...am I on the right track? – Bailey M Aug 17 '15 at 19:35
• I guess the key here is "Kslkgh" / "ADFGVX"/ "John" / "JohnsRevenge" . And the cipher is ADFGVX. Am I right? Also your comment The key is hidden in a ->method<- I've used on various occasions makes me think more about key ADFGVX though it's insecure key... I will continue research after some hours because I have no time now, hope it will not get answered till then;) – Jet Aug 18 '15 at 6:52
• Maybe keysquare is in your text? e.g. take your question, remove all repeating letters and get square? In that case I see only 3 numbers in your text 0,1,9, and probably encrypted text has a number inside. So maybe non-poisoned glass is one of 1, 9, 10, 11, 19, 90, 91, 99, 100, right? – Jet Aug 18 '15 at 7:56

The solution is:

youmustdrinkfromglasssix

The first step is to find the keysquare:

When looking "deeper" you can find it in the source of the question (click on "edit"): 20zsd5vt1wjipe4hfnmq8gbxy3lou6ra7k9c

I don't know if the rest of the solution is allowed (I'm new here):

I have written a program to brute force all possible transpositions, and looked for the word "glass" in the decoded text. The numeric representation of the transposition key is [6, 3, 1, 4, 0, 7, 5, 2]. This matches the word "MECHANIC" (thanks to moonbutt74).

Source code:

import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.regex.Pattern;

public class JohnsRevenge {
private static final int MAX_TRANSPOSITION_KEY_LENGTH = 10;
private static final char[] KEYSQUARE = "20zsd5vt1wjipe4hfnmq8gbxy3lou6ra7k9c".toCharArray();
private static final char[] CIPHER_TEXT = "VDFVXDVADXVAAVGAGXAVAVGGGGXAFGGAXGAGVVXFGAVDXGDX".toCharArray();
private static final Pattern PATTERN = Pattern.compile("glass");

private static int[] transpositionKey = null;
private static int[] inverseTranspositionKey = null;
private static char[] untransposed = new char[CIPHER_TEXT.length];
private static char[] decoded = new char[CIPHER_TEXT.length / 2];
private static CharBuffer buffer = CharBuffer.wrap(decoded);

private static void untranspose() {
int width = inverseTranspositionKey.length;
int height = (CIPHER_TEXT.length + width - 1) / width;
int heightChange = CIPHER_TEXT.length - (height - 1) * width;

int cipherTextPos = 0;
for (int x : inverseTranspositionKey) {
int currentHeight = (x < heightChange ? height : height - 1);
for (int y = 0; y < currentHeight; ++ y) {
untransposed[x + y * width] = CIPHER_TEXT[cipherTextPos++];
}
}
}

private static int charToIndex(char c) {
switch (c) {
case 'A': return 0;
case 'D': return 1;
case 'F': return 2;
case 'G': return 3;
case 'V': return 4;
case 'X': return 5;
default: throw new IllegalArgumentException();
}
}

private static void decode() {
for (int i = 0; i < decoded.length; ++ i) {
decoded[i] = KEYSQUARE[charToIndex(untransposed[i * 2]) * 6 + charToIndex(untransposed[i * 2 + 1])];
}
}

private static void check() {
if (PATTERN.matcher(buffer).find()) {
System.out.println(buffer + " " + Arrays.toString(transpositionKey));
}
}

private static void generateKeys(int pos) {
outer:
for (int i = 0; i < transpositionKey.length; ++ i) {
for (int j = 0; j < pos; j ++) {
if (i == transpositionKey[j]) {
continue outer;
}
}
transpositionKey[pos] = i;
inverseTranspositionKey[i] = pos;
if (pos < transpositionKey.length - 1) {
generateKeys(pos + 1);
} else {
untranspose();
decode();
check();
}
}
}

public static void main(String[] args) {
for (int i = 1; i <= MAX_TRANSPOSITION_KEY_LENGTH; ++ i) {
System.out.println("[" + i + "]");
transpositionKey = new int[i];
inverseTranspositionKey = new int[i];
generateKeys(0);
}
}
}

• That's neat! If i didn't still have an elephant on top of me, i'd shake your hand! You absolutely should post the complete solution. +1 I had tried mechanic but without the table it meant nothing. @Kslkgh ,that's sneaky. =D – moonbutt74 Aug 18 '15 at 16:26
• @moonbutt74 I have added the source code, and added more info in the third spoiler. Your transposition key is correct. – Sleafar Aug 18 '15 at 19:36
• thanks, i've been playing with this , do you have a version that will accept user input for the all the variables, i tried to patch in the scan function but i suck. xD If that's ok/doable can you link me to your git? Thanks. – moonbutt74 Aug 19 '15 at 3:16
• @moonbutt74 I don't have a public repository yet, and this code was just a quick and dirty solution. Instead of using the Scanner you can pass the values as arguments, like: int keyLength = Integer.valueOf(args[0]);. – Sleafar Aug 19 '15 at 5:20

OK, continuing the research I want to tell some facts:

1) Before permutating (rearranging) columns with key, free squares are filed with letter X, for example:

    K   E   Y               K   E   Y
1   F   A   G          1    F   A   G
2   V   D   F    <=>   2    V   D   F
3   F   A   A          3    F   A   A
4   F                  4    F   X   X


This means the final encrypted text length will be divisible by key length.
In this example length is 12 and key has 3 letters.
Now we our ciphertext's length is 48
VDFVXDVADXVAAVGAGXAVAVGGGGXAFGGAXGAGVVXFGAVDXGDX
123456789012345678901234567890123456789012345678
It means we have several possible key lengths, as 48 is divisible by:

1, 2,             - Hardly possible
3, 4, 6, 8, 12,   - Possible
16, 24, 48        - Hardly possible


Of which most probably key length is 3, 4, 6, 8, 12.
Maybe now we should find words with this lengths:

JohnsRevenge - 12
John - 4
Kslkgh ?- 6
etc


2) Empty boxes are filled with X. It means that last row can have more X-es, because count of X on last row doesn't change even after permutation.

Also probablity of X* pair the least, because usually all unused letters/numbers are in X row (in non-permutated ciphertext).

    A   D   F   G   V   X
...
V   B   N   0   1   2   3
X-> 4   5   6   7   8   9  - symbols in this row are used rarely, so X* is rare


Back to the game. When trying all possible key lengthes (write cipher VDFVX... upside down, left to right, in 3, 4, 6, 8, 12 columns) the more X-es we have on the last row the more possibility is that we have found the correct key length. (It's about possibility, not 100% correct)

3) Not a fact but interesting:
@Kslkgh, I think I know the cipher and I think I know the key, but I can't for the life of me figure out what the keyword is...am I on the right track?

@BaileyM Do you mean that you know what the ->keysquare<- is. If you do, you are definately on the right track! – Kslkgh
Seems like he the OP reacted more on keysquare (and doesn't care about permutation key?). So probably key is obvious/easy to find.
Also The key is hidden in a ->method<- I've used on various occasions – Kslkgh again makes me think the key is method name- ADFGVX (also it's length is equal to 6, and 48 is divisible by 6).

TO BE CONTINUED...