Cicada 3301 Python utilities for decryption purposes.
There is a lot of documented material on Cicada 3301 and the currently unsolved version 2 of their rune-based encrypted "book", AKA Liber Primus
or LP2
for short.
Based on the encrypted payload, I hafe a few assumptions:
- The cipher encrypts entire words in some fashion (based on the word lengths and punctuation).
- The cipher works on at least two letters at the same time (Digraphs) due to IoC tests.
- The cipher probably treats two consecutive letters differently (e.g. like
Playfair
cipher does). This is a conclusion from the low distribution of doublets in the entireLP2
.
- Using
Hill cipher
with one of the magic squares used as the matrix key, optionally withAtbash
,Shifts
andprime substruction
. - Using sophisticated shifts on a decrypted
Vigenere cipher
with the wordINSTAR
as the key.
The following section includes coding and useful classes:
Contains utilities for LP
and LP2
translations:
- Each translation class inherits from
Translation
base class and should implement one methoddecrypt(self, page
). Parameters to translation classes should be assigned at their construction. - A class called
UnsolvedTranslation
marks pages that are not translated. - The
LiberPrimusPages
class contains aPAGES
member which is a list of 2-tuples:(cipher, translation)
. - The
LiberPrimusPages
class also exports convinience methods such asget_unsolved_pages()
.
Contains a class called Cicada
which does a lot of basic encryption, decryption and heuristics.
- It contains the members
RUNES
andLATIN
that translate runes to latin as per the Cicada Gematria Primus. - Helper methods such as
find_next_prime
,totient
,heuristically_english
andpress_enter
. - Working translations such as
runes_to_latin
,hill_decrypt_to_runes
,autokey_decrypt_to_runes
andvigenere_decrypt
. - Outside of the
Cicada
class there is a method calledtests
which shows all the translated pages, and a method calledsolve
which will hopefully one day solveLP2
. As of now,solve
is the main way to experiment.
Assuming we wish to use "INSTAR" as a vigenere cipher, we could code the following:
def solve():
"""
Wishful thinking.
"""
# Get all unsolved pages
pages = LiberPrimus.LiberPrimusPages.get_unsolved_pages()
# Good luck!
idx = 0
for page in pages:
idx += 1
print(f'PAGE {idx}\n\n')
print(Cicada.vigenere_decrypt(page, 'ᛁᚾᛋᛏᚪᚱ'))
Cicada.press_enter()