# 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? Aug 17, 2015 at 15:52
• @Aioros Search everywhere. The key is hidden in a method I've used on various occasions.
– user9377
Aug 17, 2015 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? Aug 17, 2015 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, 2015 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, 2015 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 Aug 18, 2015 at 16:26
• 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. Aug 19, 2015 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]);. Aug 19, 2015 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...