forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trifid_cipher.py
135 lines (107 loc) · 3.6 KB
/
trifid_cipher.py
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# https://en.wikipedia.org/wiki/Trifid_cipher
from __future__ import annotations
def __encrypt_part(message_part: str, character_to_number: dict[str, str]) -> str:
one, two, three = "", "", ""
tmp = []
for character in message_part:
tmp.append(character_to_number[character])
for each in tmp:
one += each[0]
two += each[1]
three += each[2]
return one + two + three
def __decrypt_part(
message_part: str, character_to_number: dict[str, str]
) -> tuple[str, str, str]:
tmp, this_part = "", ""
result = []
for character in message_part:
this_part += character_to_number[character]
for digit in this_part:
tmp += digit
if len(tmp) == len(message_part):
result.append(tmp)
tmp = ""
return result[0], result[1], result[2]
def __prepare(
message: str, alphabet: str
) -> tuple[str, str, dict[str, str], dict[str, str]]:
# Validate message and alphabet, set to upper and remove spaces
alphabet = alphabet.replace(" ", "").upper()
message = message.replace(" ", "").upper()
# Check length and characters
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!")
# 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 = {}
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
def encrypt_message(
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
) -> str:
message, alphabet, character_to_number, number_to_character = __prepare(
message, alphabet
)
encrypted, encrypted_numeric = "", ""
for i in range(0, len(message) + 1, period):
encrypted_numeric += __encrypt_part(
message[i : i + period], character_to_number
)
for i in range(0, len(encrypted_numeric), 3):
encrypted += number_to_character[encrypted_numeric[i : i + 3]]
return encrypted
def decrypt_message(
message: str, alphabet: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.", period: int = 5
) -> str:
message, alphabet, character_to_number, number_to_character = __prepare(
message, alphabet
)
decrypted_numeric = []
decrypted = ""
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)):
decrypted_numeric.append(a[j] + b[j] + c[j])
for each in decrypted_numeric:
decrypted += number_to_character[each]
return decrypted
if __name__ == "__main__":
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}")