University of Tokyo Student Recruitment Poster Challenge 2013

It has been University of Tokyo’s tradition to hide challenge information on student recruitment posters since 2010. (see poster of past years) Those zeros and ones on the posters are not random numbers but meaningful binary information.

Let’s grab the poster of this year and see what we can do!

Poster 2013

First and foremost, we must extract those binaries from the image. With OCR and a bit of collation, we have

0010101100101101001011010010110100101101001010110000101001111100010010010111000001110111011001110111110000
0010100111110001101111001011100010111001110101011111000100010101000110010010000100100100100000010010110100
1110010011110101001000001010011111000110000101100011011101000110111101111100011111000111110001111100011111
0000100000011111000111110001111100011111000000101001111100011101010111001101110111001000010111110001010110
0101011001010110010101100010000001010110010101100101011001010110000010100010101100101101001011010010110100
1011010010101100101101001011010010110100101101001010110010110100101101001011010010110100101011001011010010
1101001011010010110100101011000010100111110000100000011101010110100101101100011111000110111100100000001000
0001110100011111000110100001110111001110100010000001111100011000010110101100101110011110010111110000101101
0011111001010011000010100111110000100000011001100111010000100000011111000101001100101101011101000110111101
1111000110111001110111001011110111001001111100010111110010111101100001011011110111110000101101001111100101
0100000010100111110001110011011000110111100101110011011111000110100101100001011010010010000001111100011011
1100101110011011110010000001111100010111110111010001110100011011000111110000101101001111100101010100001010
0111110001110100011101010111010101100101011111000110111001101110011011100010111001111100011011110110101001
1010110110100101111100011011000110101100101110001000000111110000101101001111100101011000101100010110010000
1010001010110010110100101101001011010010110100101011001011010010110100101101001011010010101100101101001011
0100101101001011010010101100101101001011010010110100101101001010110000101001111100010001110101010001100001
0110010001111100000010100111110001101000001011110111001101100101011111000000101001111100011011000110100000
1000000111001001111100000010100111110001000011010100110111000001000110011111000000101000101011001011010010
1101001011010010110100101011000010100000101001010010011011110111010001100001011101000110010100100000011101
0001101000011010010111001100100000011000110111010101100010011001010010000001100010011110010010000001110010
0110010101110000011001010110000101110100011010010110111001100111000010100101010000101100010010000010110001
0001010010110001010101001011000100111000101100010010010010110001010110001011000100010100101100010100100010
1100010100110010110001001001001011000101010000101100010110010010110001001111001011000100011000101100010101
0000101100010011110010110001001011001011000101100100101100010011110000101000110010001100000011000101011110
0101111000110011001000000111010001101001011011010110010101110011001011100000101000001010011000010101111001
0111100110001000100000011010010111001100100000011101010111000000101101011000010111001001110010011011110111
01110010000001101110011011110111010001100001011101000110100101101111011011100010111000001010

which is a total of 2848 zero or ones.

Since 2848 is a multiple of 8, by instinct we may want to convert the binary string above to binary data, and this is what we get

+----+
|Ipwg|
|o..u|EFHI KNOR
|acto||||| ||||
|usw!|VVVV VVVV
+----+----+----+----+
| uil|o  t|hw: |ak.y|->S
| ft |S-to|nw/r|_/ao|->T
|scys|iai |o.o |_ttl|->U
|tuue|nnn.|ojki|lk. |->V,Y
+----+----+----+----+
|GTad|
|h/se|
|lh r|
|CSpF|
+----+

Rotate this cube by repeating
T,H,E,U,N,I,V,E,R,S,I,T,Y,O,F,T,O,K,Y,O
201^^3 times.

a^^b is up-arrow notation.

Ah-ha! So there really is information hidden in those zeros and ones!

Umm… Looks like we’re going to play around with a 4x4x4 Rubik’s cube. It’s quite intuitive that “E”, “F”, “H”, “I”, and so forth are notations of rotating separate layers; the question then arises: What the heck is up-arrow notation?

Thanks to Wikipedia, the definition of up-arrow notation is easily accessible, so now we know 201^^3 means
\[201 \uparrow\uparrow 3 = 201^{201^{201}}\]
which is enormously large!!!

Some pre-programming research

Luckily, according to group theory, we’re able to substantially reduce the number of operation yet having the effect of “repeating the operation 201^^3 times”. Here’s how….

Let
\[(\text{operation THEUNIVERSITYOFTOKYO})^n \equiv M^n \equiv \text{identity (nothing moves)}\]
In consequence of Rubik’s cube group order being finite, it’s guaranteed to find an positive integer \(n\) (order of cyclic group with \(M\) as its generator) satisfying
\[M^n \equiv M^0 \equiv \text{identity}\]
Thus,
\[M^{201 \uparrow\uparrow 3} \equiv M^{(201 \uparrow\uparrow 3)\mod{n}}\]
If \(n\) is sufficiently small, then we’re happy. :p

And here is programming comes into play

To find the actual value of \(n\), we must first find a way to perform “rotation” in a program.

For a Rubik’s cube net with each block number labeled:

+-----------+
| 0  1  2  3|
| 4  5  6  7|
| 8  9 10 11|
|12 13 14 15|
+-----------+-----------+-----------+-----------+
|16 17 18 19|20 21 22 23|24 25 26 27|28 29 30 31|
|32 33 34 35|36 37 38 39|40 41 42 43|44 45 46 47|
|48 49 50 51|52 53 54 55|56 57 58 59|60 61 62 63|
|64 65 66 67|68 69 70 71|72 73 74 75|76 77 78 79|
+-----------+-----------+-----------+-----------+
|80 81 82 83|
|84 85 86 87|
|88 89 90 91|
|92 93 94 95|
+-----------+

After rotation “E”, the net will become:

+-----------+
| 0  1  2  3|
| 4  5  6  7|
| 8  9 10 11|
|79 63 47 31|
+-----------+-----------+-----------+-----------+
|64 48 32 16|12 21 22 23|24 25 26 27|28 29 30 80|
|65 49 33 17|13 37 38 39|40 41 42 43|44 45 46 81|
|66 50 34 18|14 53 54 55|56 57 58 59|60 61 62 82|
|67 51 35 19|15 69 70 71|72 73 74 75|76 77 78 83|
+-----------+-----------+-----------+-----------+
|68 52 36 20|
|84 85 86 87|
|88 89 90 91|
|92 93 94 95|
+-----------+

which is in fact an operation of “remapping blocks and numbers”. Once we realize that, the remaining part should be easy.

For future convenience, I personally write a simple Python module for challenge Rubik’s cube operations.

# identity element
identity = range(4*4*6)

rotate_maps = dict()

rotate_maps['E'] = [
     0,  1,  2,  3, 
     4,  5,  6,  7, 
     8,  9, 10, 11, 
    79, 63, 47, 31, 
    64, 48, 32, 16, 12, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 80, 
    65, 49, 33, 17, 13, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 81, 
    66, 50, 34, 18, 14, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 82, 
    67, 51, 35, 19, 15, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 83, 
    68, 52, 36, 20, 
    84, 85, 86, 87, 
    88, 89, 90, 91, 
    92, 93, 94, 95, 
]
rotate_maps['F'] = [
     0,  1,  2,  3, 
     4,  5,  6,  7, 
    78, 62, 46, 30, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20,  8, 22, 23, 24, 25, 26, 27, 28, 29, 84, 31, 
    32, 33, 34, 35, 36,  9, 38, 39, 40, 41, 42, 43, 44, 45, 85, 47, 
    48, 49, 50, 51, 52, 10, 54, 55, 56, 57, 58, 59, 60, 61, 86, 63, 
    64, 65, 66, 67, 68, 11, 70, 71, 72, 73, 74, 75, 76, 77, 87, 79, 
    80, 81, 82, 83, 
    69, 53, 37, 21, 
    88, 89, 90, 91, 
    92, 93, 94, 95, 
]
rotate_maps['H'] = [
     0,  1,  2,  3, 
    77, 61, 45, 29, 
     8,  9, 10, 11, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21,  4, 23, 24, 25, 26, 27, 28, 88, 30, 31, 
    32, 33, 34, 35, 36, 37,  5, 39, 40, 41, 42, 43, 44, 89, 46, 47, 
    48, 49, 50, 51, 52, 53,  6, 55, 56, 57, 58, 59, 60, 90, 62, 63, 
    64, 65, 66, 67, 68, 69,  7, 71, 72, 73, 74, 75, 76, 91, 78, 79, 
    80, 81, 82, 83, 
    84, 85, 86, 87, 
    70, 54, 38, 22, 
    92, 93, 94, 95, 
]
rotate_maps['I'] = [
    76, 60, 44, 28, 
     4,  5,  6,  7, 
     8,  9, 10, 11, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22,  0, 27, 43, 59, 75, 92, 29, 30, 31, 
    32, 33, 34, 35, 36, 37, 38,  1, 26, 42, 58, 74, 93, 45, 46, 47, 
    48, 49, 50, 51, 52, 53, 54,  2, 25, 41, 57, 73, 94, 61, 62, 63, 
    64, 65, 66, 67, 68, 69, 70,  3, 24, 40, 56, 72, 95, 77, 78, 79, 
    80, 81, 82, 83, 
    84, 85, 86, 87, 
    88, 89, 90, 91, 
    71, 55, 39, 23, 
]
rotate_maps['K'] = [
     0,  1,  2, 19, 
     4,  5,  6, 35, 
     8,  9, 10, 51, 
    12, 13, 14, 67, 
    16, 17, 18, 83, 68, 52, 36, 20, 15, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 87, 69, 53, 37, 21, 11, 41, 42, 43, 44, 45, 46, 47, 
    48, 49, 50, 91, 70, 54, 38, 22,  7, 57, 58, 59, 60, 61, 62, 63, 
    64, 65, 66, 95, 71, 55, 39, 23,  3, 73, 74, 75, 76, 77, 78, 79, 
    80, 81, 82, 72, 
    84, 85, 86, 56, 
    88, 89, 90, 40, 
    92, 93, 94, 24, 
]
rotate_maps['N'] = [
     0,  1, 18,  3, 
     4,  5, 34,  7, 
     8,  9, 50, 11, 
    12, 13, 66, 15, 
    16, 17, 82, 19, 20, 21, 22, 23, 24, 14, 26, 27, 28, 29, 30, 31, 
    32, 33, 86, 35, 36, 37, 38, 39, 40, 10, 42, 43, 44, 45, 46, 47, 
    48, 49, 90, 51, 52, 53, 54, 55, 56,  6, 58, 59, 60, 61, 62, 63, 
    64, 65, 94, 67, 68, 69, 70, 71, 72,  2, 74, 75, 76, 77, 78, 79, 
    80, 81, 73, 83, 
    84, 85, 57, 87, 
    88, 89, 41, 91, 
    92, 93, 25, 95, 
]
rotate_maps['O'] = [
     0, 17,  2,  3, 
     4, 33,  6,  7, 
     8, 49, 10, 11, 
    12, 65, 14, 15, 
    16, 81, 18, 19, 20, 21, 22, 23, 24, 25, 13, 27, 28, 29, 30, 31, 
    32, 85, 34, 35, 36, 37, 38, 39, 40, 41,  9, 43, 44, 45, 46, 47, 
    48, 89, 50, 51, 52, 53, 54, 55, 56, 57,  5, 59, 60, 61, 62, 63, 
    64, 93, 66, 67, 68, 69, 70, 71, 72, 73,  1, 75, 76, 77, 78, 79, 
    80, 74, 82, 83, 
    84, 58, 86, 87, 
    88, 42, 90, 91, 
    92, 26, 94, 95, 
]
rotate_maps['R'] = [
    16,  1,  2,  3, 
    32,  5,  6,  7, 
    48,  9, 10, 11, 
    64, 13, 14, 15, 
    80, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 12, 31, 47, 63, 79, 
    84, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,  8, 30, 46, 62, 78, 
    88, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,  4, 29, 45, 61, 77, 
    92, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,  0, 28, 44, 60, 76, 
    75, 81, 82, 83, 
    59, 85, 86, 87, 
    43, 89, 90, 91, 
    27, 93, 94, 95, 
]
rotate_maps['S'] = [
     3,  7, 11, 15, 
     2,  6, 10, 14, 
     1,  5,  9, 13, 
     0,  4,  8, 12, 
    28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 
    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
    80, 81, 82, 83, 
    84, 85, 86, 87, 
    88, 89, 90, 91, 
    92, 93, 94, 95, 
]
rotate_maps['T'] = [
     0,  1,  2,  3, 
     4,  5,  6,  7, 
     8,  9, 10, 11, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    44, 45, 46, 47, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 
    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
    80, 81, 82, 83, 
    84, 85, 86, 87, 
    88, 89, 90, 91, 
    92, 93, 94, 95, 
]
rotate_maps['U'] = [
     0,  1,  2,  3, 
     4,  5,  6,  7, 
     8,  9, 10, 11, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 
    60, 61, 62, 63, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 
    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
    80, 81, 82, 83, 
    84, 85, 86, 87, 
    88, 89, 90, 91, 
    92, 93, 94, 95, 
]
rotate_maps['V'] = [
     0,  1,  2,  3, 
     4,  5,  6,  7, 
     8,  9, 10, 11, 
    12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 
    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 
    76, 77, 78, 79, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 
    92, 88, 84, 80, 
    93, 89, 85, 81, 
    94, 90, 86, 82, 
    95, 91, 87, 83, 
]
rotate_maps['Y'] = rotate_maps['V']

def rotate(vector, map):
    return [vector[map[i]] for i in identity]

M = identity
for c in 'THEUNIVERSITYOFTOKYO':
    M = rotate(M, rotate_maps[c])

With above module, we are able to find \(n\).

import rubiks

v = rubiks.identity
counter = 0
done = False
while not done:
    v = rubiks.rotate(v, rubiks.M)
    counter += 1
    if v == rubiks.identity:
        done = True
print 'n =', counter

which will give us \(n = 1008\).

For calculating \((201 \uparrow\uparrow 3)\mod{1008}\), I personally use PowerMod function in Mathematica, or we could also use Wolfram Alpha as a replacement. We have
\[M^{201 \uparrow\uparrow 3} \equiv M^{153}\]

Now we’re one final step from the solution! Extract ciphertext from the challenge and decipher by performing \(M^{153}\).

import rubiks

ciphertext = 'Ipwgo..uactousw! uilo  thw: ak.y ft S-tonw/r_/aoscysiai o.o _ttltuuennn.ojkilk. GTadh/selh rCSpF'

# PowerMod[201, 201^201, 1008] = 153
v = [c for c in ciphertext]
for i in range(153):
    v = rubiks.rotate(v, rubiks.M)

print ''.join(v)

BINGO!

Congratulations!Follow the link.http://www.is.s.u-tokyo.ac.jp/ist_ueno_yuuka    GradSch of  IST 

Follow the link, in it, there’s a song named Summer Prism by the girl on the poster (δΈŠι‡Žε„ͺ華).

And that’s it! Hope you find it interesting~ 😜

Posted in Technical.

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha loading...