2019-10-05 05:14:13 +00:00
|
|
|
# https://en.wikipedia.org/wiki/Trifid_cipher
|
2021-09-22 21:11:51 +00:00
|
|
|
from __future__ import annotations
|
2019-10-05 05:14:13 +00:00
|
|
|
|
2019-04-03 19:27:36 +00:00
|
|
|
|
2022-10-12 22:54:20 +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 = []
|
2019-08-06 10:14:23 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
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-08-06 10:14:23 +00:00
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
return one + two + three
|
|
|
|
|
2019-04-03 19:27:36 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def __decrypt_part(
|
|
|
|
message_part: str, character_to_number: dict[str, str]
|
2021-04-04 05:22:12 +00:00
|
|
|
) -> tuple[str, str, str]:
|
2022-10-12 22:54:20 +00:00
|
|
|
tmp, this_part = "", ""
|
2019-04-03 19:27:36 +00:00
|
|
|
result = []
|
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
for character in message_part:
|
|
|
|
this_part += character_to_number[character]
|
2019-04-03 19:27:36 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
for digit in this_part:
|
2019-04-03 19:27:36 +00:00
|
|
|
tmp += digit
|
2022-10-12 22:54:20 +00:00
|
|
|
if len(tmp) == len(message_part):
|
2019-04-03 19:27:36 +00:00
|
|
|
result.append(tmp)
|
2019-08-06 10:14:23 +00:00
|
|
|
tmp = ""
|
2019-04-03 19:27:36 +00:00
|
|
|
|
|
|
|
return result[0], result[1], result[2]
|
|
|
|
|
2019-10-05 05:14:13 +00:00
|
|
|
|
2021-04-04 05:22:12 +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",
|
|
|
|
)
|
2022-10-12 22:54:20 +00:00
|
|
|
character_to_number = {}
|
|
|
|
number_to_character = {}
|
2019-04-03 19:27:36 +00:00
|
|
|
for letter, number in zip(alphabet, numbers):
|
2022-10-12 22:54:20 +00:00
|
|
|
character_to_number[letter] = number
|
|
|
|
number_to_character[number] = letter
|
2019-08-06 10:14:23 +00:00
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
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
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def encrypt_message(
|
2020-10-16 06:11:52 +00:00
|
|
|
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
|
|
|
|
) -> str:
|
2022-10-12 22:54:20 +00:00
|
|
|
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):
|
2022-10-12 22:54:20 +00:00
|
|
|
encrypted_numeric += __encrypt_part(
|
|
|
|
message[i : i + period], character_to_number
|
|
|
|
)
|
2019-08-06 10:14:23 +00:00
|
|
|
|
2019-04-03 19:27:36 +00:00
|
|
|
for i in range(0, len(encrypted_numeric), 3):
|
2022-10-12 22:54:20 +00:00
|
|
|
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
|
|
|
|
2022-10-12 22:54:20 +00:00
|
|
|
def decrypt_message(
|
2020-10-16 06:11:52 +00:00
|
|
|
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
|
|
|
|
) -> str:
|
2022-10-12 22:54:20 +00:00
|
|
|
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):
|
2022-10-12 22:54:20 +00:00
|
|
|
a, b, c = __decrypt_part(message[i : i + period], character_to_number)
|
2019-08-06 10:14:23 +00:00
|
|
|
|
2023-08-29 13:18:10 +00:00
|
|
|
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:
|
2022-10-12 22:54:20 +00:00
|
|
|
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."
|
2022-10-12 22:54:20 +00:00
|
|
|
encrypted = encrypt_message(msg, "EPSDUCVWYM.ZLKXNBTFGORIJHAQ")
|
|
|
|
decrypted = decrypt_message(encrypted, "EPSDUCVWYM.ZLKXNBTFGORIJHAQ")
|
2019-12-07 05:39:59 +00:00
|
|
|
print(f"Encrypted: {encrypted}\nDecrypted: {decrypted}")
|