Python/ciphers/trifid_cipher.py

136 lines
3.6 KiB
Python
Raw Normal View History

2019-10-05 05:14:13 +00:00
# https://en.wikipedia.org/wiki/Trifid_cipher
from __future__ import annotations
2019-10-05 05:14:13 +00:00
2019-04-03 19:27:36 +00:00
def __encrypt_part(message_part: str, character_to_number: dict[str, str]) -> str:
2019-04-03 19:27:36 +00:00
one, two, three = "", "", ""
tmp = []
for character in message_part:
tmp.append(character_to_number[character])
2019-04-03 19:27:36 +00:00
for each in tmp:
one += each[0]
two += each[1]
three += each[2]
2019-10-05 05:14:13 +00:00
return one + two + three
2019-04-03 19:27:36 +00:00
def __decrypt_part(
message_part: str, character_to_number: dict[str, str]
) -> tuple[str, str, str]:
tmp, this_part = "", ""
2019-04-03 19:27:36 +00:00
result = []
for character in message_part:
this_part += character_to_number[character]
2019-04-03 19:27:36 +00:00
for digit in this_part:
2019-04-03 19:27:36 +00:00
tmp += digit
if len(tmp) == len(message_part):
2019-04-03 19:27:36 +00:00
result.append(tmp)
tmp = ""
2019-04-03 19:27:36 +00:00
return result[0], result[1], result[2]
2019-10-05 05:14:13 +00:00
def __prepare(
message: str, alphabet: str
) -> tuple[str, str, dict[str, str], dict[str, str]]:
2019-10-05 05:14:13 +00:00
# Validate message and alphabet, set to upper and remove spaces
2019-04-03 19:27:36 +00:00
alphabet = alphabet.replace(" ", "").upper()
message = message.replace(" ", "").upper()
2019-10-05 05:14:13 +00:00
# Check length and characters
2019-04-03 19:27:36 +00:00
if len(alphabet) != 27:
raise KeyError("Length of alphabet has to be 27.")
for each in message:
if each not in alphabet:
raise ValueError("Each message character has to be included in alphabet!")
2019-10-05 05:14:13 +00:00
# Generate dictionares
numbers = (
"111",
"112",
"113",
"121",
"122",
"123",
"131",
"132",
"133",
"211",
"212",
"213",
"221",
"222",
"223",
"231",
"232",
"233",
"311",
"312",
"313",
"321",
"322",
"323",
"331",
"332",
"333",
)
character_to_number = {}
number_to_character = {}
2019-04-03 19:27:36 +00:00
for letter, number in zip(alphabet, numbers):
character_to_number[letter] = number
number_to_character[number] = letter
return message, alphabet, character_to_number, number_to_character
2019-04-03 19:27:36 +00:00
2019-10-05 05:14:13 +00:00
def encrypt_message(
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
) -> str:
message, alphabet, character_to_number, number_to_character = __prepare(
message, alphabet
)
2019-04-03 19:27:36 +00:00
encrypted, encrypted_numeric = "", ""
2019-10-05 05:14:13 +00:00
for i in range(0, len(message) + 1, period):
encrypted_numeric += __encrypt_part(
message[i : i + period], character_to_number
)
2019-04-03 19:27:36 +00:00
for i in range(0, len(encrypted_numeric), 3):
encrypted += number_to_character[encrypted_numeric[i : i + 3]]
2019-04-03 19:27:36 +00:00
return encrypted
2019-10-05 05:14:13 +00:00
def decrypt_message(
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
) -> str:
message, alphabet, character_to_number, number_to_character = __prepare(
message, alphabet
)
2019-04-03 19:27:36 +00:00
decrypted_numeric = []
decrypted = ""
2019-10-05 05:14:13 +00:00
for i in range(0, len(message) + 1, period):
a, b, c = __decrypt_part(message[i : i + period], character_to_number)
for j in range(len(a)):
2019-10-05 05:14:13 +00:00
decrypted_numeric.append(a[j] + b[j] + c[j])
2019-04-03 19:27:36 +00:00
for each in decrypted_numeric:
decrypted += number_to_character[each]
2019-04-03 19:27:36 +00:00
return decrypted
2019-10-05 05:14:13 +00:00
if __name__ == "__main__":
2019-04-03 19:27:36 +00:00
msg = "DEFEND THE EAST WALL OF THE CASTLE."
encrypted = encrypt_message(msg, "EPSDUCVWYM.ZLKXNBTFGORIJHAQ")
decrypted = decrypt_message(encrypted, "EPSDUCVWYM.ZLKXNBTFGORIJHAQ")
print(f"Encrypted: {encrypted}\nDecrypted: {decrypted}")