from utils import AlphabetUtils as au from utils import CipherUtils as cu ALLOWED_KEYS = [1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25] def encrypt_text(cleartext: str, key1: int, key2: int) -> str: """ Encrypts the given text with the given keys :param cleartext: The text to encrypt :param key1: The first key. Has to be between 1 and 25 and a coprime to 26 :param key2: The second key. Has to be between 0 and 26 :return: The encrypted text """ # key1 has to be coprime to 26 if key1 not in ALLOWED_KEYS: raise AttributeError # key2 has to be between 0 and 25 if key2 < 0 or key2 > 25: raise AttributeError cleartext = cu.transform_invalid_chars(cleartext) resulting = '' for char in cleartext: index = au.get_index_of_letter(char) new_index = (index * key1 + key2) % 26 resulting += au.get_letter_at_index(new_index) return resulting def decrypt_text(ciphertext: str, key1: int, key2: int) -> str: """ Decrypts the given ciphertext with the given keys :param ciphertext: The text to decrypt :param key1: The first key. Has to be between 1 and 25 and a coprime to 26 :param key2: The second key. Has to be between 0 and 26 :return: The decrypted text """ # key1 has to be coprime to 26 if key1 not in ALLOWED_KEYS: raise AttributeError # key2 has to be between 0 and 25 if key2 < 0 or key2 > 25: raise AttributeError decrypt_key1 = _get_key_reverse(key1) resulting = '' for char in ciphertext: index = au.get_index_of_letter(char) new_index = ((index - key2) * decrypt_key1) % 26 resulting += au.get_letter_at_index(new_index) return resulting def _get_key_reverse(key: int) -> int: """ Calculates the decryption key (inverse of the original key) based on the following formula: s * s' mod 26 = 1 :param key: The key to reverse :return: The decryption key """ for possibility in ALLOWED_KEYS: if (key * possibility) % 26 == 1: return possibility if __name__ == '__main__': print(encrypt_text('BonkRocks', 11, 7)) print(decrypt_text('sfunmfdnx', 11, 7))