mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-30 16:31:08 +00:00
60895366c0
* fix(mypy): type annotations for cipher algorithms * Update mypy workflow to include cipher directory * fix: mypy errors in hill_cipher.py * fix build errors
104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
alphabet = {
|
|
"A": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"),
|
|
"B": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"),
|
|
"C": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"),
|
|
"D": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"),
|
|
"E": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"),
|
|
"F": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"),
|
|
"G": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"),
|
|
"H": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"),
|
|
"I": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"),
|
|
"J": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"),
|
|
"K": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"),
|
|
"L": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"),
|
|
"M": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"),
|
|
"N": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"),
|
|
"O": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"),
|
|
"P": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"),
|
|
"Q": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"),
|
|
"R": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"),
|
|
"S": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"),
|
|
"T": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"),
|
|
"U": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"),
|
|
"V": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"),
|
|
"W": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"),
|
|
"X": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"),
|
|
"Y": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"),
|
|
"Z": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"),
|
|
}
|
|
|
|
|
|
def generate_table(key: str) -> list[tuple[str, str]]:
|
|
"""
|
|
>>> generate_table('marvin') # doctest: +NORMALIZE_WHITESPACE
|
|
[('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'),
|
|
('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'),
|
|
('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')]
|
|
"""
|
|
return [alphabet[char] for char in key.upper()]
|
|
|
|
|
|
def encrypt(key: str, words: str) -> str:
|
|
"""
|
|
>>> encrypt('marvin', 'jessica')
|
|
'QRACRWU'
|
|
"""
|
|
cipher = ""
|
|
count = 0
|
|
table = generate_table(key)
|
|
for char in words.upper():
|
|
cipher += get_opponent(table[count], char)
|
|
count = (count + 1) % len(table)
|
|
return cipher
|
|
|
|
|
|
def decrypt(key: str, words: str) -> str:
|
|
"""
|
|
>>> decrypt('marvin', 'QRACRWU')
|
|
'JESSICA'
|
|
"""
|
|
return encrypt(key, words)
|
|
|
|
|
|
def get_position(table: tuple[str, str], char: str) -> tuple[int, int]:
|
|
"""
|
|
>>> get_position(generate_table('marvin')[0], 'M')
|
|
(0, 12)
|
|
"""
|
|
# `char` is either in the 0th row or the 1st row
|
|
row = 0 if char in table[0] else 1
|
|
col = table[row].index(char)
|
|
return row, col
|
|
|
|
|
|
def get_opponent(table: tuple[str, str], char: str) -> str:
|
|
"""
|
|
>>> get_opponent(generate_table('marvin')[0], 'M')
|
|
'T'
|
|
"""
|
|
row, col = get_position(table, char.upper())
|
|
if row == 1:
|
|
return table[0][col]
|
|
else:
|
|
return table[1][col] if row == 0 else char
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
|
|
doctest.testmod() # Fist ensure that all our tests are passing...
|
|
"""
|
|
Demo:
|
|
|
|
Enter key: marvin
|
|
Enter text to encrypt: jessica
|
|
Encrypted: QRACRWU
|
|
Decrypted with key: JESSICA
|
|
"""
|
|
key = input("Enter key: ").strip()
|
|
text = input("Enter text to encrypt: ").strip()
|
|
cipher_text = encrypt(key, text)
|
|
|
|
print(f"Encrypted: {cipher_text}")
|
|
print(f"Decrypted with key: {decrypt(key, cipher_text)}")
|