A few months ago, while discussing about cryptography (the art of writing or solving codes), my friend told me about the 75th Anniversary Commemorative Coin. This limited edition fifty cent coin was released on 1 September 2022 by Australian Mint to celebrate the 75th anniversary of the Australian Signals Directorate (ASD). The specialty of this coin is that there are several cryptography puzzles minted on this coin.
This blog post aims to explain the methods to crack the codes using the Python programming language. If you do not code and are simply interested in the code-breaking process, I plan to explain how the puzzles can also be solved manually.
Following this, there are going to be spoilers to the puzzles. So, if you want to solve this on your own, I highly recommend you to go to ASD's website to solve these puzzles.
When we look at the Queen’s head on the coin, the following letters have a series of dots shown below them. It seems obvious that these dots signify Braille characters used by visually impaired people to read by sensing the embossed dots on a surface.
The Braille characters use a 3 x 2
(3 rows, 2 columns) grid sytem:
1-2
(top row)3-4
(middle row)5-6
(bottom row)+---+---+
| 1 | 2 |
+---+---+
| 3 | 4 |
+---+---+
| 5 | 6 |
+---+---+
Based on the grid system mentioned-above, the following letters on the coin consist the dots underneath.
B 1 2
T 1 3
H 1 2 3
A 1
S 1 4
A 1 2 4
The pattern of each Braille character underneath the letters on the coin represent a decimal number. We can map these Braille characters to their corresponding decimal numbers as follows:
+----+----+----+----+----+----+
| B | T | H | A | S | A |
+----+----+----+----+----+----+
| oo | o | oo | o | o | oo |
| | o | o | | o | o |
+----+----+----+----+----+----+
| 3 | 2 | 6 | 1 | 5 | 4 |
+----+----+----+----+----+----+
Sorting the characters in the ascending order of their decimal values, we get ATBASH
.
Following is the python code to solve this:
1
2
3
4
5
6
7
8
9
10
11
12
secret_dict = {'B': 3,
'T': 2,
'H': 6,
'A0': 1,
'S': 5,
'A1': 4
}
sorted_secret = {k: v for k, v in sorted(secret_dict.items(), key=lambda item:item[1])}
for k in sorted_secret:
print(k)
The above-mentioned code will give the following result:
A0
T
B
A1
S
H
Solution: ATBASH
The text from the outer ring is as follows:
.DVZIVZFWZXRLFHRMXLMXVKGZMWNVGRXFOLFHRMVCVXFGRLM.URMWXOZIRGBRM7DRWGSC5WVKGS
Solving level one of the puzzle gives us the clue: ATBASH
.
ATBASH is a monoalphabetic substitution cipher. This cipher was originally used to encrypt the Hebrew alphabets. This cipher system can be modified to any writing system where the alphabets/characters are in standard order.
Using ATBASH cipher, the alphabets can be mapped as follows:
Plain : A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Cipher: Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
So, the word ATBASH
can be encrypted by matching the alphabets in the plain text to the cipher which results in ZGYZHS
.
The decryption involves matching the cipher text characters to the plain text characters from the map mentioned above.
The decryption can be done manually, but if you have a large text to decrypt, it is better to take help of a computer. Following is the Python code to decrypt the message.
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
import re
outer_ring = ".DVZIVZFWZXRLFHRMXLMXVKGZMWNVGRXFOLFHRMVCVXFGRLM.URMWXOZIRGBRM7DRWGSC5WVKGS"
def atbash(message):
"""Decrypts the message with ATBASH encryption.
Parameters
----------
message: str
The message that is encrypted using ATBASH encryption.
Returns
-------
str
A string of the decrypted message using ATBASH decryption.
"""
# Removing any special characters from the message
message = re.sub(r'[^\w]', '', message)
# 26 alphabets
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
# reversing the alphabet for mapping
reverse_alpha = alpha[::-1]
# mapping all the reversed alphabets to the non-reversed alphabets
map_atbash = dict()
for a, r in zip(alpha, reverse_alpha):
map_atbash[a] = r
decryption = ''
# decrypting the message from the alphabet map of ATBASH
for c in message:
try:
decryption += map_atbash[c]
except:
decryption += c
continue
return decryption
print(atbash(outer_ring))
The above-mentioned code will give the following result:
WEAREAUDACIOUSINCONCEPTANDMETICULOUSINEXECUTIONFINDCLARITYIN7WIDTHX5DEPTH
Solution:
WE ARE AUDACIOUS IN CONCEPT AND METICULOUS IN EXECUTION
FIND CLARITY IN 7 WIDTH X 5 DEPTH
The text on the inner ring of the coin is as follows:
BGOAMVOEIATSIRLNGTTNEOGRERGXNTEAIFCECAIEOALEKFNR5LWEFCHDEEAEEE7NMDRXX5
Solving level two gave us the clue: 7 WIDTH X 5 DEPTH
.
This clue suggests a dimension.
Transposition ciphers are based on organising
the text in a grid/matrix of a certain dimension.
In transposition cipher, the decryption process is performed
by organising the decrypted text in a grid.
Consider the following example where the key (4 x 5)
indicates that we must write 5
columns starting a new
column after every 4
letters. Then, sequentially go through each row
of the grid to get the plain text.
Encryption: ICOHLRGYOYREVPANETPD
key = 4 x 5 (width x depth)
ILOVE
CRYPT
OGRAP
HYEND
Plain: ILOVECRYPTOGRAPHYEND
You can manually solve the puzzle by simply rearranging
the letters in a 7 x 5
grid and create multiple grids when
the 7
width runs.
Then continue to read the message by following each row.
BELON
GINGT
OAGRE
ATTEA
MSTRI
VINGF
OREXC
ELLEN
CEWEM
AKEAD
IFFER
ENCEX
ORHEX
A5D75
Decrypting such type of ciphers manually can become time consuming and often frustrating process. So, here’s the Python code to get the result.
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
inner_ring = 'BGOAMVOEIATSIRLNGTTNEOGRERGXNTEAIFCECAIEOALEKFNR5LWEFCHDEEAEEE7NMDRXX5'
def transposition(message, size=(7,5)):
"""Transposition cipher.
Parameters
----------
message: str
The message string encrypted using transposition cipher.
size: tuple, default ``(7,5)``
The size of the matrix ``(row, column)``.
Returns
-------
str
The decrypted message.
"""
# holding width information
v = []
# matrix holding the depth and width information
M = []
# width
m = size[0]
# depth
n = size[1]
initial = 0
# Getting the width
for i in range(int(len(message)/m)):
v.append(message[initial: initial+m])
initial += m
initial = 0
# getting the depth
for i in range(int(len(v)/n)):
M.append(v[initial: initial+n])
initial += n
decryption = ''
for k in range(len(M)):
for i in range(m):
for j in range(n):
decryption += M[k][j][i]
return decryption
print(transposition(inner_ring, (7,5)))
This code will give the following result:
BELONGINGTOAGREATTEAMSTRIVINGFOREXCELLENCEWEMAKEADIFFERENCEXORHEXA5D75
Solution:
BELONGING TO A GREAT TEAM STRIVING FOR EXCELLENCE WE MAKE A DIFFERENCE XOR HEX A5D75
The text in 1/3rd of the inner circle of the coin is as follows:
E3B
8287D4
290F723381
4D7A47A291DC
0F71B2806D1A53B
311CC4B97A0E1CC2B9
3B31068593332F10C6A335
2F14D1B27A3514D6F7382F1A
D0B0322955D1B83D3801CDB2
287D05C0B82A311085A03329
1D85A3323855D6BC333119D
6FB7A3C11C4A72E3C17CCB
B33290C85B6343955CCBA3
B3A1CCBB62E341ACBF72
E3255CAA73F2F14D1B27A
341B85A3323855D6BB33
3055C4A53F3C55C7B22
E2A10C0B97A291DC0F
73E3413C3BE392819
D1F73B331185A33
23855CCBA2A3
206D6BE383
1108B
From level three, we have a clue at the end of the message:
XOR HEX A5D75
.
XOR
also known as Exclusive or is a logical operator
that is true if and only if its arguments are different.
The truth table for XOR is as follows:
A | B | A xor B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
HEX A5D75
indicates that the hexadecimal number A5D75
must
be mapped with the hexadecimal numbers present in 1/3rd region
of the coin.
We can organise hexadecimal numbers on the coin and the key as follows:
E3B8287D4...
A5D75A5D7...
It is worth noting how we keep repeating the key till we reach
the end of the hexadecimal text.
Then we can perform the logical XOR
operation and convert
the result to a decimal number.
+-----+----------+---------+
| hex | binary | decimal |
+-----+----------+---------+
| E3 | 11100011 | |
| A5 | 10100101 | |
+-----+----------+---------+
| XOR | 01000110 | 70 |
+-----+----------+---------+
The first decimal number obtained by matching the
hexadecimal number on the coin with the hexadecimal key
gives 70
.
ASCII
(American Standard Code for Information Interchange)
is a 7-bit character code where every single bit represents
a unique character.
Tracking the number 70
on the ASCII
table, we get the
character F
corresponding to 70
.
This XOR
decryption is a tedious process and I would recommend using
a computer to solve this puzzle.
Using the following Python code, we can solve this puzzle.
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
import re
hex_text = """E3B
8287D4
290F723381
4D7A47A291DC
0F71B2806D1A53B
311CC4B97A0E1CC2B9
3B31068593332F10C6A335
2F14D1B27A3514D6F7382F1A
D0B0322955D1B83D3801CDB2
287D05C0B82A311085A03329
1D85A3323855D6BC333119D
6FB7A3C11C4A72E3C17CCB
B33290C85B6343955CCBA3
B3A1CCBB62E341ACBF72
E3255CAA73F2F14D1B27A
341B85A3323855D6BB33
3055C4A53F3C55C7B22
E2A10C0B97A291DC0F
73E3413C3BE392819
D1F73B331185A33
23855CCBA2A3
206D6BE383
1108B"""
def xor_decoding(hex_text, hex_key):
"""Uses XOR operation to decode hexadecimal message.
Parameters
----------
hex_text: str
A string of the hexadecimal encrypted message.
hex_key: str
A string of the hexadecimal key for decryption.
Returns
-------
str
The decrypted message.
"""
# Getting rid of any new line
hex_text = hex_text.strip()
hex_text = re.sub('\n','', hex_text)
# matching hex key for decryption (same length as hex_text)
key_text = ''
count = 0
for i in range(len(hex_text)):
c = count % len(hex_key)
key_text += hex_key[c]
count += 1
# counter variable for incrementing by 2 hex digits
initial = 0
# Empty string for storing decrypted message
decryption = ''
for i in range(int(len(hex_text)/2)):
message_hex = hex_text[initial:initial+2]
match_hex = key_text[initial:initial+2]
# bitwise XOR operation
xor = int(message_hex, 16) ^ int(match_hex, 16)
# converting the decimal to ASCII character
decryption += chr(xor)
# incrementing the counter variable
initial += 2
return decryption
print(xor_decoding(hex_text, hex_key="A5D75"))
The above-mentioned code will give the following output:
For 75 years the Australian Signals Directorate has brought together people with the skills, adaptability and imagination to operate in the slim area between the difficult and the impossible.
The result mentioned above contains spaces, commas, and periods because each of these characters have a specific
designation in ASCII
. These characters appeared
in the decrypted text because they were considered
while encrypting the plain text.
Solution:
For 75 years the Australian Signals Directorate has brought together people with the skills, adaptability and imagination to operate in the slim area between the difficult and the impossible.
I had fun in solving these puzzles. I appreciate the thoughts and efforts that went into creating these fun puzzles and minting them on a 50 cent coin.
Full disclosure, I did not figure out the methods to solve these puzzles. I looked up the hints on the ASD’s website and developed simple programmes in Python to get the results. Comparing my results with the results published on ASD’s website was still a joyful experience.
There is also a bonus level puzzle on this coin (solution not mentioned in this blog). If you are interested in cracking the bonus level code, head to ASD’s website and try it out. If you are simply curious and do not want to try cracking the codes, then you can still check out the methods and solutions to these puzzles and enjoy the code-breaking experience.
All the images of the coins including the header image belong to ASD and Royal Australian Mint.