simple keyword cypher Algorithm

The simple keyword cipher algorithm, also known as the Caesar cipher, is a substitution cipher technique used in cryptography to encrypt or decrypt messages. This type of algorithm works by replacing each letter in the plaintext with another letter, which is a fixed number of positions down the alphabet. For instance, if the shift value is 3, the letter 'A' in the plaintext would be replaced with 'D', 'B' would be replaced with 'E', and so on. The key used in this algorithm is the number that determines the shift in the alphabet, which can range from 1 to 25 for the English alphabet. The Caesar cipher is considered a monoalphabetic cipher because it uses only one alphabet and a single, fixed substitution for each letter. While simple keyword cipher algorithms like the Caesar cipher are easy to understand and implement, they are also highly vulnerable to cryptanalysis, making them unsuitable for use in modern applications that require secure communications. Frequency analysis, a technique that exploits the frequency distribution of letters in a language, can easily break this type of cipher, as common letters like 'E' and 'T' in the plaintext are replaced with the same letter in the ciphertext. Despite its lack of security, the Caesar cipher still holds historical significance and serves as an excellent introduction to the field of cryptography for beginners.
def remove_duplicates(key: str) -> str:
    """
    Removes duplicate alphabetic characters in a keyword (letter is ignored after its
        first appearance).
    :param key: Keyword to use
    :return: String with duplicates removed
    >>> remove_duplicates('Hello World!!')
    'Helo Wrd'
    """

    key_no_dups = ""
    for ch in key:
        if ch == " " or ch not in key_no_dups and ch.isalpha():
            key_no_dups += ch
    return key_no_dups


def create_cipher_map(key: str) -> dict:
    """
    Returns a cipher map given a keyword.
    :param key: keyword to use
    :return: dictionary cipher map
    """
    # Create alphabet list
    alphabet = [chr(i + 65) for i in range(26)]
    # Remove duplicate characters from key
    key = remove_duplicates(key.upper())
    offset = len(key)
    # First fill cipher with key characters
    cipher_alphabet = {alphabet[i]: char for i, char in enumerate(key)}
    # Then map remaining characters in alphabet to
    # the alphabet from the beginning
    for i in range(len(cipher_alphabet), 26):
        char = alphabet[i - offset]
        # Ensure we are not mapping letters to letters previously mapped
        while char in key:
            offset -= 1
            char = alphabet[i - offset]
        cipher_alphabet[alphabet[i]] = char
    return cipher_alphabet


def encipher(message: str, cipher_map: dict) -> str:
    """
    Enciphers a message given a cipher map.
    :param message: Message to encipher
    :param cipher_map: Cipher map
    :return: enciphered string
    >>> encipher('Hello World!!', create_cipher_map('Goodbye!!'))
    'CYJJM VMQJB!!'
    """
    return "".join(cipher_map.get(ch, ch) for ch in message.upper())


def decipher(message: str, cipher_map: dict) -> str:
    """
    Deciphers a message given a cipher map
    :param message: Message to decipher
    :param cipher_map: Dictionary mapping to use
    :return: Deciphered string
    >>> cipher_map = create_cipher_map('Goodbye!!')
    >>> decipher(encipher('Hello World!!', cipher_map), cipher_map)
    'HELLO WORLD!!'
    """
    # Reverse our cipher mappings
    rev_cipher_map = {v: k for k, v in cipher_map.items()}
    return "".join(rev_cipher_map.get(ch, ch) for ch in message.upper())


def main():
    """
    Handles I/O
    :return: void
    """
    message = input("Enter message to encode or decode: ").strip()
    key = input("Enter keyword: ").strip()
    option = input("Encipher or decipher? E/D:").strip()[0].lower()
    try:
        func = {"e": encipher, "d": decipher}[option]
    except KeyError:
        raise KeyError("invalid input option")
    cipher_map = create_cipher_map(key)
    print(func(message, cipher_map))


if __name__ == "__main__":
    import doctest

    doctest.testmod()
    main()

LANGUAGE:

DARK MODE: