#!/usr/bin/env nix-shell
#!nix-shell -i python -p python3

# NOTE: the colors are used to keep track of which letters have been
#       already substituted, and which are still unknown.

def green(s):
    return f"\033[42m{s}\033[0m"

def red(s):
    return f"\033[41m{s}\033[0m"

def substitute(cipher_text, substitution_map):
    for letter in cipher_text:
        if letter.lower() in substitution_map:
            if letter.isupper():
                x = substitution_map[letter.lower()].upper()
            else:
                x = substitution_map[letter]
            print(green(x), end="")
        else:
            print(red(letter), end="")

with open('message.txt', 'r') as file:
    enc = file.read()

# Here, I will be slowly substituting the letters in the ciphertext
# based on what I believe the words to be. I have commented out the
# invocations of substitute, and commented the newly found letters
# after each invocation.

# Starting off, "sxzqZNV{...}" looks like "picoCTF{...}"

substitution_map = {
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
    '_': '_',
    '{': '{',
    '}': '}',
    's': 'p',
    'x': 'i',
    'z': 'c',
    'q': 'o',
    'n': 't',
    'v': 'f',
}

# substitute(enc, substitution_map)

# Using frequency analysis (https://www.dcode.fr/frequency-analysis), we find that:

# F	175×	13.87%
# N	125×	9.9%
# X	103×	8.16%
# Q	102×	8.08%
# L	98×	7.77%
# E	83×	6.58%
# T	68×	5.39%
# Z	63×	4.99%
# Y	61×	4.83%
# A	56×	4.44%
# P	46×	3.65%
# W	42×	3.33%
# V	39×	3.09%
# G	35×	2.77%
# B	34×	2.69%
# S	28×	2.22%
# R	24×	1.9%
# U	20×	1.58%
# H	19×	1.51%
# K	16×	1.27%
# M	9×	0.71%
# C	9×	0.71%
# O	5×	0.4%
# I	2×	0.16%

# Based on this, and the frequency of letters in the english alphabet, we can guess for 'e'

substitution_map['f'] = 'e' # 13.87% ~= 12.7%

# 'petitiol' -> 'petition'

substitution_map['l'] = 'n'

# 'incpwbinr' -> 'including'
# 'effectiue' -> 'effective'

substitution_map['p'] = 'l'
substitution_map['w'] = 'u'
substitution_map['b'] = 'd'
substitution_map['r'] = 'g'

# 'encountey' -> 'encounter'

substitution_map['y'] = 'r'

# 'eecurith' -> 'security'

substitution_map['e'] = 's'
substitution_map['h'] = 'y'

# 'effectiuely' -> 'effectively'

substitution_map['u'] = 'v'

# 'cogputer' -> 'computer'

substitution_map['g'] = 'm'

# 'catllenge' -> 'challenge'

substitution_map['a'] = 'h'
substitution_map['t'] = 'a'

# 'thinc' -> 'think'

substitution_map['c'] = 'k'

# 'valuakle' -> 'valuable'

substitution_map['k'] = 'b'

# 'thereeoists' -> 'there exists'

substitution_map['o'] = 'x'

# 'homever' -> 'however'

substitution_map['m'] = 'w'

# 'techniiue' -b 'technique'

substitution_map['i'] = 'q'

substitute(enc, substitution_map)

