AutokeyCipher
=============

The ``AutokeyCipher`` class implements the Autokey cipher, a polyalphabetic substitution cipher that uses a keyword and the plaintext itself for encryption, making it a variation of the Vigenère cipher.

.. class:: AutokeyCipher(key: str)

    Creates a new AutokeyCipher instance with the specified keyword.

    :param key: The keyword used for encryption. The key is followed by the plaintext itself for encryption.
    :type key: str

.. attention::

   AutokeyCipher is a basic symmetric cipher, which should be used ONLY for educational purposes, and NOT in production. Proceed accordingly.

Introduction
------------
The Autokey cipher is a form of polyalphabetic substitution cipher, which means that it encrypts text by using multiple substitutions based on a keyword. It is similar to the Vigenère cipher but with an important difference: the key used for encryption is not a fixed word or phrase. Instead, the key is generated by appending the plaintext itself to the end of the keyword. This makes the cipher less vulnerable to frequency analysis, but it also introduces some weaknesses if the key is too short or predictable.

Mathematical Details
--------------------
In the Autokey cipher:

- The plaintext is encrypted by shifting each letter based on the corresponding letter of the key.

- The key is formed by appending the plaintext to the keyword, starting from the first letter of the plaintext.

- The encryption formula is:
   .. math::

      C_i = (P_i + K_i) \mod 26

   where:
     - :math:`C_i` is the ciphertext letter,
     - :math:`P_i` is the plaintext letter,
     - :math:`K_i` is the key letter (the letters from the keyword followed by the plaintext itself).

- The decryption formula is:
   .. math::

      P_i = (C_i - K_i) \mod 26

   where :math:`K_i` is the key letter used for decryption.

Usage
-----
.. code-block:: python

    # Example usage of Playfair Cipher to encrypt and decrypt a message
    from cryptosystems import AutoKeyCipher
    cipher = AutoKeyCipher("key")
    ciphertext = cipher.encrypt("Hello World")
    print(ciphertext) # 'Rijss Hzfhr'
    plaintext = cipher.decrypt(ciphertext)
    print(plaintext) # 'Hello World'

Methods
-------
.. function:: encrypt(plaintext: str) -> str

    Encrypts the given plaintext using the Autokey cipher.

    :param plaintext: The plaintext message to be encrypted.
    :type plaintext: str
    :return: The encrypted ciphertext.
    :rtype: str

.. function:: decrypt(ciphertext: str) -> str

    Decrypts the given ciphertext using the Autokey cipher.

    :param ciphertext: The ciphertext message to be decrypted.
    :type ciphertext: str
    :return: The decrypted plaintext.
    :rtype: str

Notes
-----
- **Key**: The key is formed by combining the given keyword with the plaintext itself. If the plaintext is longer than the keyword, the keyword is repeated.
- **Security**: The Autokey cipher is less vulnerable to frequency analysis than the Vigenère cipher because the key changes with each letter of the plaintext. However, if the key is known or predictable, it is still susceptible to cryptanalysis.
- **Application**: The Autokey cipher is useful for educational purposes and cryptographic exercises but is not considered secure for modern applications, especially with short or predictable keys.