diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c1aeaa031565..ac5f80206e35 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: python -m pip install mypy pytest-cov -r requirements.txt # FIXME: #4052 fix mypy errors in the exclude directories and remove them below - run: mypy --ignore-missing-imports - --exclude '(ciphers|conversions|data_structures|digital_image_processing|dynamic_programming|graphs|linear_algebra|maths|matrix|other|project_euler|scripts|searches|strings*)/$' . + --exclude '(conversions|data_structures|digital_image_processing|dynamic_programming|graphs|linear_algebra|maths|matrix|other|project_euler|scripts|searches|strings*)/$' . - name: Run tests run: pytest --doctest-modules --ignore=project_euler/ --ignore=scripts/ --cov-report=term-missing:skip-covered --cov=. . - if: ${{ success() }} diff --git a/ciphers/diffie_hellman.py b/ciphers/diffie_hellman.py index ea35b67b483e..072f4aaaa6da 100644 --- a/ciphers/diffie_hellman.py +++ b/ciphers/diffie_hellman.py @@ -241,9 +241,7 @@ def generate_shared_key(self, other_key_str: str) -> str: return sha256(str(shared_key).encode()).hexdigest() @staticmethod - def is_valid_public_key_static( - local_private_key_str: str, remote_public_key_str: str, prime: int - ) -> bool: + def is_valid_public_key_static(remote_public_key_str: int, prime: int) -> bool: # check if the other public key is valid based on NIST SP800-56 if 2 <= remote_public_key_str and remote_public_key_str <= prime - 2: if pow(remote_public_key_str, (prime - 1) // 2, prime) == 1: @@ -257,9 +255,7 @@ def generate_shared_key_static( local_private_key = int(local_private_key_str, base=16) remote_public_key = int(remote_public_key_str, base=16) prime = primes[group]["prime"] - if not DiffieHellman.is_valid_public_key_static( - local_private_key, remote_public_key, prime - ): + if not DiffieHellman.is_valid_public_key_static(remote_public_key, prime): raise ValueError("Invalid public key") shared_key = pow(remote_public_key, local_private_key, prime) return sha256(str(shared_key).encode()).hexdigest() diff --git a/ciphers/hill_cipher.py b/ciphers/hill_cipher.py index 8237abf6aa5d..bc8f5b41b624 100644 --- a/ciphers/hill_cipher.py +++ b/ciphers/hill_cipher.py @@ -64,13 +64,12 @@ class HillCipher: to_int = numpy.vectorize(lambda x: round(x)) - def __init__(self, encrypt_key: int): + def __init__(self, encrypt_key: numpy.ndarray) -> None: """ encrypt_key is an NxN numpy array """ self.encrypt_key = self.modulus(encrypt_key) # mod36 calc's on the encrypt key self.check_determinant() # validate the determinant of the encryption key - self.decrypt_key = None self.break_key = encrypt_key.shape[0] def replace_letters(self, letter: str) -> int: @@ -139,8 +138,8 @@ def encrypt(self, text: str) -> str: for i in range(0, len(text) - self.break_key + 1, self.break_key): batch = text[i : i + self.break_key] - batch_vec = [self.replace_letters(char) for char in batch] - batch_vec = numpy.array([batch_vec]).T + vec = [self.replace_letters(char) for char in batch] + batch_vec = numpy.array([vec]).T batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[ 0 ] @@ -151,7 +150,7 @@ def encrypt(self, text: str) -> str: return encrypted - def make_decrypt_key(self): + def make_decrypt_key(self) -> numpy.ndarray: """ >>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]])) >>> hill_cipher.make_decrypt_key() @@ -184,17 +183,15 @@ def decrypt(self, text: str) -> str: >>> hill_cipher.decrypt('85FF00') 'HELLOO' """ - self.decrypt_key = self.make_decrypt_key() + decrypt_key = self.make_decrypt_key() text = self.process_text(text.upper()) decrypted = "" for i in range(0, len(text) - self.break_key + 1, self.break_key): batch = text[i : i + self.break_key] - batch_vec = [self.replace_letters(char) for char in batch] - batch_vec = numpy.array([batch_vec]).T - batch_decrypted = self.modulus(self.decrypt_key.dot(batch_vec)).T.tolist()[ - 0 - ] + vec = [self.replace_letters(char) for char in batch] + batch_vec = numpy.array([vec]).T + batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0] decrypted_batch = "".join( self.replace_digits(num) for num in batch_decrypted ) @@ -203,12 +200,12 @@ def decrypt(self, text: str) -> str: return decrypted -def main(): +def main() -> None: N = int(input("Enter the order of the encryption key: ")) hill_matrix = [] print("Enter each row of the encryption key with space separated integers") - for i in range(N): + for _ in range(N): row = [int(x) for x in input().split()] hill_matrix.append(row) diff --git a/ciphers/mixed_keyword_cypher.py b/ciphers/mixed_keyword_cypher.py index 59298d310ce0..178902173477 100644 --- a/ciphers/mixed_keyword_cypher.py +++ b/ciphers/mixed_keyword_cypher.py @@ -29,8 +29,8 @@ def mixed_keyword(key: str = "college", pt: str = "UNIVERSITY") -> str: # print(temp) alpha = [] modalpha = [] - for i in range(65, 91): - t = chr(i) + for j in range(65, 91): + t = chr(j) alpha.append(t) if t not in temp: temp.append(t) @@ -38,23 +38,23 @@ def mixed_keyword(key: str = "college", pt: str = "UNIVERSITY") -> str: r = int(26 / 4) # print(r) k = 0 - for i in range(r): - t = [] + for _ in range(r): + s = [] for j in range(len_temp): - t.append(temp[k]) + s.append(temp[k]) if not (k < 25): break k += 1 - modalpha.append(t) + modalpha.append(s) # print(modalpha) d = {} j = 0 k = 0 for j in range(len_temp): - for i in modalpha: - if not (len(i) - 1 >= j): + for m in modalpha: + if not (len(m) - 1 >= j): break - d[alpha[k]] = i[j] + d[alpha[k]] = m[j] if not k < 25: break k += 1 diff --git a/ciphers/mono_alphabetic_ciphers.py b/ciphers/mono_alphabetic_ciphers.py index 0a29d6442896..46013f4936bc 100644 --- a/ciphers/mono_alphabetic_ciphers.py +++ b/ciphers/mono_alphabetic_ciphers.py @@ -1,7 +1,11 @@ +from typing import Literal + LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -def translate_message(key, message, mode): +def translate_message( + key: str, message: str, mode: Literal["encrypt", "decrypt"] +) -> str: """ >>> translate_message("QWERTYUIOPASDFGHJKLZXCVBNM","Hello World","encrypt") 'Pcssi Bidsm' @@ -40,7 +44,7 @@ def decrypt_message(key: str, message: str) -> str: return translate_message(key, message, "decrypt") -def main(): +def main() -> None: message = "Hello World" key = "QWERTYUIOPASDFGHJKLZXCVBNM" mode = "decrypt" # set to 'encrypt' or 'decrypt' diff --git a/ciphers/morse_code_implementation.py b/ciphers/morse_code_implementation.py index 1cce2ef8b386..eec4183fa56e 100644 --- a/ciphers/morse_code_implementation.py +++ b/ciphers/morse_code_implementation.py @@ -83,7 +83,7 @@ def decrypt(message: str) -> str: return decipher -def main(): +def main() -> None: message = "Morse code here" result = encrypt(message.upper()) print(result) diff --git a/ciphers/onepad_cipher.py b/ciphers/onepad_cipher.py index a91f2b4d31c5..3ace9b098cba 100644 --- a/ciphers/onepad_cipher.py +++ b/ciphers/onepad_cipher.py @@ -2,7 +2,8 @@ class Onepad: - def encrypt(self, text: str) -> ([str], [int]): + @staticmethod + def encrypt(text: str) -> tuple[list[int], list[int]]: """Function to encrypt text using pseudo-random numbers""" plain = [ord(i) for i in text] key = [] @@ -14,14 +15,14 @@ def encrypt(self, text: str) -> ([str], [int]): key.append(k) return cipher, key - def decrypt(self, cipher: [str], key: [int]) -> str: + @staticmethod + def decrypt(cipher: list[int], key: list[int]) -> str: """Function to decrypt text using pseudo-random numbers.""" plain = [] for i in range(len(key)): p = int((cipher[i] - (key[i]) ** 2) / key[i]) plain.append(chr(p)) - plain = "".join([i for i in plain]) - return plain + return "".join([i for i in plain]) if __name__ == "__main__": diff --git a/ciphers/playfair_cipher.py b/ciphers/playfair_cipher.py index 219437448e53..7c0ee5bd5ae1 100644 --- a/ciphers/playfair_cipher.py +++ b/ciphers/playfair_cipher.py @@ -1,8 +1,9 @@ import itertools import string +from typing import Generator, Iterable -def chunker(seq, size): +def chunker(seq: Iterable[str], size: int) -> Generator[tuple[str, ...], None, None]: it = iter(seq) while True: chunk = tuple(itertools.islice(it, size)) @@ -37,7 +38,7 @@ def prepare_input(dirty: str) -> str: return clean -def generate_table(key: str) -> [str]: +def generate_table(key: str) -> list[str]: # I and J are used interchangeably to allow # us to use a 5x5 table (25 letters) diff --git a/ciphers/porta_cipher.py b/ciphers/porta_cipher.py index 29043c4c9fac..498ae294041e 100644 --- a/ciphers/porta_cipher.py +++ b/ciphers/porta_cipher.py @@ -28,7 +28,7 @@ } -def generate_table(key: str) -> [(str, str)]: +def generate_table(key: str) -> list[tuple[str, str]]: """ >>> generate_table('marvin') # doctest: +NORMALIZE_WHITESPACE [('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), @@ -60,30 +60,21 @@ def decrypt(key: str, words: str) -> str: return encrypt(key, words) -def get_position(table: [(str, str)], char: str) -> (int, int) or (None, None): +def get_position(table: tuple[str, str], char: str) -> tuple[int, int]: """ - >>> table = [ - ... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), - ... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'), - ... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')] - >>> get_position(table, 'A') - (None, None) + >>> get_position(generate_table('marvin')[0], 'M') + (0, 12) """ - if char in table[0]: - row = 0 - else: - row = 1 if char in table[1] else -1 - return (None, None) if row == -1 else (row, table[row].index(char)) + # `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: [(str, str)], char: str) -> str: +def get_opponent(table: tuple[str, str], char: str) -> str: """ - >>> table = [ - ... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), - ... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'), - ... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')] - >>> get_opponent(table, 'A') - 'A' + >>> get_opponent(generate_table('marvin')[0], 'M') + 'T' """ row, col = get_position(table, char.upper()) if row == 1: @@ -97,14 +88,16 @@ def get_opponent(table: [(str, str)], char: str) -> str: doctest.testmod() # Fist ensure that all our tests are passing... """ - ENTER KEY: marvin - ENTER TEXT TO ENCRYPT: jessica - ENCRYPTED: QRACRWU - DECRYPTED WITH KEY: JESSICA + 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() + 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)}") + print(f"Encrypted: {cipher_text}") + print(f"Decrypted with key: {decrypt(key, cipher_text)}") diff --git a/ciphers/rail_fence_cipher.py b/ciphers/rail_fence_cipher.py index 2596415207ae..cba593ca7335 100644 --- a/ciphers/rail_fence_cipher.py +++ b/ciphers/rail_fence_cipher.py @@ -20,7 +20,7 @@ def encrypt(input_string: str, key: int) -> str: ... TypeError: sequence item 0: expected str instance, int found """ - grid = [[] for _ in range(key)] + temp_grid: list[list[str]] = [[] for _ in range(key)] lowest = key - 1 if key <= 0: @@ -31,8 +31,8 @@ def encrypt(input_string: str, key: int) -> str: for position, character in enumerate(input_string): num = position % (lowest * 2) # puts it in bounds num = min(num, lowest * 2 - num) # creates zigzag pattern - grid[num].append(character) - grid = ["".join(row) for row in grid] + temp_grid[num].append(character) + grid = ["".join(row) for row in temp_grid] output_string = "".join(grid) return output_string @@ -63,7 +63,7 @@ def decrypt(input_string: str, key: int) -> str: if key == 1: return input_string - temp_grid = [[] for _ in range(key)] # generates template + temp_grid: list[list[str]] = [[] for _ in range(key)] # generates template for position in range(len(input_string)): num = position % (lowest * 2) # puts it in bounds num = min(num, lowest * 2 - num) # creates zigzag pattern @@ -84,7 +84,7 @@ def decrypt(input_string: str, key: int) -> str: return output_string -def bruteforce(input_string: str) -> dict: +def bruteforce(input_string: str) -> dict[int, str]: """Uses decrypt function by guessing every key >>> bruteforce("HWe olordll")[4] diff --git a/ciphers/rot13.py b/ciphers/rot13.py index 21dbda98eecc..b367c3215127 100644 --- a/ciphers/rot13.py +++ b/ciphers/rot13.py @@ -20,7 +20,7 @@ def dencrypt(s: str, n: int = 13) -> str: return out -def main(): +def main() -> None: s0 = input("Enter message: ") s1 = dencrypt(s0, 13) diff --git a/ciphers/rsa_cipher.py b/ciphers/rsa_cipher.py index 0df37d6ea3ff..b1e8a73f33c6 100644 --- a/ciphers/rsa_cipher.py +++ b/ciphers/rsa_cipher.py @@ -7,144 +7,144 @@ BYTE_SIZE = 256 -def main(): - filename = "encrypted_file.txt" - response = input(r"Encrypt\Decrypt [e\d]: ") - - if response.lower().startswith("e"): - mode = "encrypt" - elif response.lower().startswith("d"): - mode = "decrypt" - - if mode == "encrypt": - if not os.path.exists("rsa_pubkey.txt"): - rkg.makeKeyFiles("rsa", 1024) - - message = input("\nEnter message: ") - pubKeyFilename = "rsa_pubkey.txt" - print("Encrypting and writing to %s..." % (filename)) - encryptedText = encryptAndWriteToFile(filename, pubKeyFilename, message) - - print("\nEncrypted text:") - print(encryptedText) - - elif mode == "decrypt": - privKeyFilename = "rsa_privkey.txt" - print("Reading from %s and decrypting..." % (filename)) - decryptedText = readFromFileAndDecrypt(filename, privKeyFilename) - print("writing decryption to rsa_decryption.txt...") - with open("rsa_decryption.txt", "w") as dec: - dec.write(decryptedText) - - print("\nDecryption:") - print(decryptedText) - - -def getBlocksFromText(message: int, blockSize: int = DEFAULT_BLOCK_SIZE) -> [int]: - messageBytes = message.encode("ascii") - - blockInts = [] - for blockStart in range(0, len(messageBytes), blockSize): - blockInt = 0 - for i in range(blockStart, min(blockStart + blockSize, len(messageBytes))): - blockInt += messageBytes[i] * (BYTE_SIZE ** (i % blockSize)) - blockInts.append(blockInt) - return blockInts - - -def getTextFromBlocks( - blockInts: [int], messageLength: int, blockSize: int = DEFAULT_BLOCK_SIZE +def get_blocks_from_text( + message: str, block_size: int = DEFAULT_BLOCK_SIZE +) -> list[int]: + message_bytes = message.encode("ascii") + + block_ints = [] + for block_start in range(0, len(message_bytes), block_size): + block_int = 0 + for i in range(block_start, min(block_start + block_size, len(message_bytes))): + block_int += message_bytes[i] * (BYTE_SIZE ** (i % block_size)) + block_ints.append(block_int) + return block_ints + + +def get_text_from_blocks( + block_ints: list[int], message_length: int, block_size: int = DEFAULT_BLOCK_SIZE ) -> str: - message = [] - for blockInt in blockInts: - blockMessage = [] - for i in range(blockSize - 1, -1, -1): - if len(message) + i < messageLength: - asciiNumber = blockInt // (BYTE_SIZE ** i) - blockInt = blockInt % (BYTE_SIZE ** i) - blockMessage.insert(0, chr(asciiNumber)) - message.extend(blockMessage) + message: list[str] = [] + for block_int in block_ints: + block_message: list[str] = [] + for i in range(block_size - 1, -1, -1): + if len(message) + i < message_length: + ascii_number = block_int // (BYTE_SIZE ** i) + block_int = block_int % (BYTE_SIZE ** i) + block_message.insert(0, chr(ascii_number)) + message.extend(block_message) return "".join(message) -def encryptMessage( - message: str, key: (int, int), blockSize: int = DEFAULT_BLOCK_SIZE -) -> [int]: - encryptedBlocks = [] +def encrypt_message( + message: str, key: tuple[int, int], blockSize: int = DEFAULT_BLOCK_SIZE +) -> list[int]: + encrypted_blocks = [] n, e = key - for block in getBlocksFromText(message, blockSize): - encryptedBlocks.append(pow(block, e, n)) - return encryptedBlocks + for block in get_blocks_from_text(message, blockSize): + encrypted_blocks.append(pow(block, e, n)) + return encrypted_blocks -def decryptMessage( - encryptedBlocks: [int], - messageLength: int, - key: (int, int), - blockSize: int = DEFAULT_BLOCK_SIZE, +def decrypt_message( + encrypted_blocks: list[int], + message_length: int, + key: tuple[int, int], + block_size: int = DEFAULT_BLOCK_SIZE, ) -> str: - decryptedBlocks = [] + decrypted_blocks = [] n, d = key - for block in encryptedBlocks: - decryptedBlocks.append(pow(block, d, n)) - return getTextFromBlocks(decryptedBlocks, messageLength, blockSize) + for block in encrypted_blocks: + decrypted_blocks.append(pow(block, d, n)) + return get_text_from_blocks(decrypted_blocks, message_length, block_size) -def readKeyFile(keyFilename: str) -> (int, int, int): - with open(keyFilename) as fo: +def read_key_file(key_filename: str) -> tuple[int, int, int]: + with open(key_filename) as fo: content = fo.read() - keySize, n, EorD = content.split(",") - return (int(keySize), int(n), int(EorD)) + key_size, n, EorD = content.split(",") + return (int(key_size), int(n), int(EorD)) -def encryptAndWriteToFile( - messageFilename: str, - keyFilename: str, +def encrypt_and_write_to_file( + message_filename: str, + key_filename: str, message: str, - blockSize: int = DEFAULT_BLOCK_SIZE, + block_size: int = DEFAULT_BLOCK_SIZE, ) -> str: - keySize, n, e = readKeyFile(keyFilename) - if keySize < blockSize * 8: + key_size, n, e = read_key_file(key_filename) + if key_size < block_size * 8: sys.exit( "ERROR: Block size is %s bits and key size is %s bits. The RSA cipher " "requires the block size to be equal to or greater than the key size. " "Either decrease the block size or use different keys." - % (blockSize * 8, keySize) + % (block_size * 8, key_size) ) - encryptedBlocks = encryptMessage(message, (n, e), blockSize) + encrypted_blocks = [str(i) for i in encrypt_message(message, (n, e), block_size)] - for i in range(len(encryptedBlocks)): - encryptedBlocks[i] = str(encryptedBlocks[i]) - encryptedContent = ",".join(encryptedBlocks) - encryptedContent = f"{len(message)}_{blockSize}_{encryptedContent}" - with open(messageFilename, "w") as fo: - fo.write(encryptedContent) - return encryptedContent + encrypted_content = ",".join(encrypted_blocks) + encrypted_content = f"{len(message)}_{block_size}_{encrypted_content}" + with open(message_filename, "w") as fo: + fo.write(encrypted_content) + return encrypted_content -def readFromFileAndDecrypt(messageFilename: str, keyFilename: str) -> str: - keySize, n, d = readKeyFile(keyFilename) - with open(messageFilename) as fo: +def read_from_file_and_decrypt(message_filename: str, key_filename: str) -> str: + key_size, n, d = read_key_file(key_filename) + with open(message_filename) as fo: content = fo.read() - messageLength, blockSize, encryptedMessage = content.split("_") - messageLength = int(messageLength) - blockSize = int(blockSize) + message_length_str, block_size_str, encrypted_message = content.split("_") + message_length = int(message_length_str) + block_size = int(block_size_str) - if keySize < blockSize * 8: + if key_size < block_size * 8: sys.exit( "ERROR: Block size is %s bits and key size is %s bits. The RSA cipher " "requires the block size to be equal to or greater than the key size. " "Did you specify the correct key file and encrypted file?" - % (blockSize * 8, keySize) + % (block_size * 8, key_size) ) - encryptedBlocks = [] - for block in encryptedMessage.split(","): - encryptedBlocks.append(int(block)) + encrypted_blocks = [] + for block in encrypted_message.split(","): + encrypted_blocks.append(int(block)) + + return decrypt_message(encrypted_blocks, message_length, (n, d), block_size) + + +def main() -> None: + filename = "encrypted_file.txt" + response = input(r"Encrypt\Decrypt [e\d]: ") + + if response.lower().startswith("e"): + mode = "encrypt" + elif response.lower().startswith("d"): + mode = "decrypt" - return decryptMessage(encryptedBlocks, messageLength, (n, d), blockSize) + if mode == "encrypt": + if not os.path.exists("rsa_pubkey.txt"): + rkg.makeKeyFiles("rsa", 1024) + + message = input("\nEnter message: ") + pubkey_filename = "rsa_pubkey.txt" + print("Encrypting and writing to %s..." % (filename)) + encryptedText = encrypt_and_write_to_file(filename, pubkey_filename, message) + + print("\nEncrypted text:") + print(encryptedText) + + elif mode == "decrypt": + privkey_filename = "rsa_privkey.txt" + print("Reading from %s and decrypting..." % (filename)) + decrypted_text = read_from_file_and_decrypt(filename, privkey_filename) + print("writing decryption to rsa_decryption.txt...") + with open("rsa_decryption.txt", "w") as dec: + dec.write(decrypted_text) + + print("\nDecryption:") + print(decrypted_text) if __name__ == "__main__": diff --git a/ciphers/rsa_factorization.py b/ciphers/rsa_factorization.py index b18aab609e2d..6df32b6cc887 100644 --- a/ciphers/rsa_factorization.py +++ b/ciphers/rsa_factorization.py @@ -13,7 +13,7 @@ import random -def rsafactor(d: int, e: int, N: int) -> [int]: +def rsafactor(d: int, e: int, N: int) -> list[int]: """ This function returns the factors of N, where p*q=N Return: [p, q] diff --git a/ciphers/shuffled_shift_cipher.py b/ciphers/shuffled_shift_cipher.py index 22628f3c9d9e..01d099641dd2 100644 --- a/ciphers/shuffled_shift_cipher.py +++ b/ciphers/shuffled_shift_cipher.py @@ -1,5 +1,6 @@ import random import string +from typing import Optional class ShuffledShiftCipher: @@ -26,7 +27,7 @@ class ShuffledShiftCipher: cip2 = ShuffledShiftCipher() """ - def __init__(self, passcode: str = None): + def __init__(self, passcode: Optional[str] = None) -> None: """ Initializes a cipher object with a passcode as it's entity Note: No new passcode is generated if user provides a passcode @@ -36,13 +37,13 @@ def __init__(self, passcode: str = None): self.__key_list = self.__make_key_list() self.__shift_key = self.__make_shift_key() - def __str__(self): + def __str__(self) -> str: """ :return: passcode of the cipher object """ return "Passcode is: " + "".join(self.__passcode) - def __neg_pos(self, iterlist: list) -> list: + def __neg_pos(self, iterlist: list[int]) -> list[int]: """ Mutates the list by changing the sign of each alternate element @@ -54,7 +55,7 @@ def __neg_pos(self, iterlist: list) -> list: iterlist[i] *= -1 return iterlist - def __passcode_creator(self) -> list: + def __passcode_creator(self) -> list[str]: """ Creates a random password from the selection buffer of 1. uppercase letters of the English alphabet @@ -65,10 +66,10 @@ def __passcode_creator(self) -> list: :return: a password of a random length between 10 to 20 """ choices = string.ascii_letters + string.digits - password = [random.choice(choices) for i in range(random.randint(10, 20))] + password = [random.choice(choices) for _ in range(random.randint(10, 20))] return password - def __make_key_list(self) -> list: + def __make_key_list(self) -> list[str]: """ Shuffles the ordered character choices by pivoting at breakpoints Breakpoints are the set of characters in the passcode @@ -99,7 +100,7 @@ def __make_key_list(self) -> list: # creates points known as breakpoints to break the key_list_options at those # points and pivot each substring breakpoints = sorted(set(self.__passcode)) - temp_list = [] + temp_list: list[str] = [] # algorithm for creating a new shuffled list, keys_l, out of key_list_options for i in key_list_options: @@ -109,7 +110,7 @@ def __make_key_list(self) -> list: # keys_l if i in breakpoints or i == key_list_options[-1]: keys_l.extend(temp_list[::-1]) - temp_list = [] + temp_list.clear() # returning a shuffled keys_l to prevent brute force guessing of shift key return keys_l @@ -167,7 +168,7 @@ def encrypt(self, plaintext: str) -> str: return encoded_message -def test_end_to_end(msg: str = "Hello, this is a modified Caesar cipher"): +def test_end_to_end(msg: str = "Hello, this is a modified Caesar cipher") -> str: """ >>> test_end_to_end() 'Hello, this is a modified Caesar cipher' diff --git a/ciphers/simple_keyword_cypher.py b/ciphers/simple_keyword_cypher.py index 71c3083e9dfc..447bacfc2e6c 100644 --- a/ciphers/simple_keyword_cypher.py +++ b/ciphers/simple_keyword_cypher.py @@ -15,7 +15,7 @@ def remove_duplicates(key: str) -> str: return key_no_dups -def create_cipher_map(key: str) -> dict: +def create_cipher_map(key: str) -> dict[str, str]: """ Returns a cipher map given a keyword. :param key: keyword to use @@ -40,7 +40,7 @@ def create_cipher_map(key: str) -> dict: return cipher_alphabet -def encipher(message: str, cipher_map: dict) -> str: +def encipher(message: str, cipher_map: dict[str, str]) -> str: """ Enciphers a message given a cipher map. :param message: Message to encipher @@ -52,7 +52,7 @@ def encipher(message: str, cipher_map: dict) -> str: return "".join(cipher_map.get(ch, ch) for ch in message.upper()) -def decipher(message: str, cipher_map: dict) -> str: +def decipher(message: str, cipher_map: dict[str, str]) -> str: """ Deciphers a message given a cipher map :param message: Message to decipher @@ -67,7 +67,7 @@ def decipher(message: str, cipher_map: dict) -> str: return "".join(rev_cipher_map.get(ch, ch) for ch in message.upper()) -def main(): +def main() -> None: """ Handles I/O :return: void diff --git a/ciphers/simple_substitution_cipher.py b/ciphers/simple_substitution_cipher.py index 646ea449fc06..a763bd6b6b48 100644 --- a/ciphers/simple_substitution_cipher.py +++ b/ciphers/simple_substitution_cipher.py @@ -4,7 +4,7 @@ LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -def main(): +def main() -> None: message = input("Enter message: ") key = "LFWOAYUISVKMNXPBDCRJTQEGHZ" resp = input("Encrypt/Decrypt [e/d]: ") @@ -68,7 +68,7 @@ def translateMessage(key: str, message: str, mode: str) -> str: return translated -def getRandomKey(): +def getRandomKey() -> str: key = list(LETTERS) random.shuffle(key) return "".join(key) diff --git a/ciphers/trafid_cipher.py b/ciphers/trafid_cipher.py index 328814f97744..1c8ea3024d33 100644 --- a/ciphers/trafid_cipher.py +++ b/ciphers/trafid_cipher.py @@ -1,7 +1,7 @@ # https://en.wikipedia.org/wiki/Trifid_cipher -def __encryptPart(messagePart: str, character2Number: dict) -> str: +def __encryptPart(messagePart: str, character2Number: dict[str, str]) -> str: one, two, three = "", "", "" tmp = [] @@ -16,7 +16,9 @@ def __encryptPart(messagePart: str, character2Number: dict) -> str: return one + two + three -def __decryptPart(messagePart: str, character2Number: dict) -> (str, str, str): +def __decryptPart( + messagePart: str, character2Number: dict[str, str] +) -> tuple[str, str, str]: tmp, thisPart = "", "" result = [] @@ -32,7 +34,9 @@ def __decryptPart(messagePart: str, character2Number: dict) -> (str, str, str): return result[0], result[1], result[2] -def __prepare(message: str, alphabet: str) -> (str, str, dict, dict): +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() diff --git a/ciphers/transposition_cipher.py b/ciphers/transposition_cipher.py index 6a0a22d3e31d..589bb8cb5cd5 100644 --- a/ciphers/transposition_cipher.py +++ b/ciphers/transposition_cipher.py @@ -8,7 +8,7 @@ """ -def main(): +def main() -> None: message = input("Enter message: ") key = int(input("Enter key [2-%s]: " % (len(message) - 1))) mode = input("Encryption/Decryption [e/d]: ") diff --git a/ciphers/transposition_cipher_encrypt_decrypt_file.py b/ciphers/transposition_cipher_encrypt_decrypt_file.py index 45aab056109a..b91c73c9f2ad 100644 --- a/ciphers/transposition_cipher_encrypt_decrypt_file.py +++ b/ciphers/transposition_cipher_encrypt_decrypt_file.py @@ -5,7 +5,7 @@ from . import transposition_cipher as transCipher -def main(): +def main() -> None: inputFile = "Prehistoric Men.txt" outputFile = "Output.txt" key = int(input("Enter key: ")) diff --git a/ciphers/vigenere_cipher.py b/ciphers/vigenere_cipher.py index eb523d078005..d97a96949fb8 100644 --- a/ciphers/vigenere_cipher.py +++ b/ciphers/vigenere_cipher.py @@ -1,7 +1,7 @@ LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -def main(): +def main() -> None: message = input("Enter message: ") key = input("Enter key [alphanumeric]: ") mode = input("Encrypt/Decrypt [e/d]: ") diff --git a/ciphers/xor_cipher.py b/ciphers/xor_cipher.py index 32a350d4e61c..12d580e720bc 100644 --- a/ciphers/xor_cipher.py +++ b/ciphers/xor_cipher.py @@ -28,7 +28,7 @@ def __init__(self, key: int = 0): # private field self.__key = key - def encrypt(self, content: str, key: int) -> [str]: + def encrypt(self, content: str, key: int) -> list[str]: """ input: 'content' of type string and 'key' of type int output: encrypted string 'content' as a list of chars @@ -53,7 +53,7 @@ def encrypt(self, content: str, key: int) -> [str]: return ans - def decrypt(self, content: str, key: int) -> [str]: + def decrypt(self, content: str, key: int) -> list[str]: """ input: 'content' of type list and 'key' of type int output: decrypted string 'content' as a list of chars