<jupyter_start><jupyter_text>The Caesar CipherA cipher is a technique that can encrypt or decrypt data (which is commonly referred to as "plaintext" or "cleartext"). During encryption, the input plaintext is converted into what is known as the "ciphertext". It is impossible to read or extract any meaning from the ciphertext unless you happen to know how the cipher works, and also a special input to the cipher known as the "key". The same cipher, with the same key, can be used to decrypt the ciphertext back into plaintext to make it readable again.In this tutorial we will examine a very simple cipher known as the Caesar cipher. We have the notion of an "alphabet", which is the set of symbols that can be used to write down the plain and cipher texts. For example, the alphabet could consist of only lowercase letters in the English alphabet (26 symbols), upper and lowercase (52 symbols), or upper, lower and numbers (62 symbols). During encryption, each symbol in the plaintext will be replaced by another symbol in the same alphabet. The mapping between symbols thus forms the "key". While this key can be represented in binary, we shall not do so at this time to avoid confusion. Let's generate the key using Python, assume that the alphabet consists of lowercase letters only:<jupyter_code>import random
alphabet = 'abcdefghijklmnopqrstuvwxyz'
key = ''.join(random.sample(alphabet, len(alphabet)))
key_dict = {}

for i in range(len(alphabet)):
    key_dict[alphabet[i]] = key[i]

for key in key_dict.keys():
    print(key, "will be replaced by", key_dict[key], "during encryption")<jupyter_output><empty_output><jupyter_text>EncryptionWe need to replace each letter in the plaintext according to above mapping.<jupyter_code>plaintext = 'hello'
ciphertext = ''
for char in plaintext:
    ctext = key_dict[char]
    ciphertext += ctext
    print(char, "was replaced by", ctext)

print("ciphertext is", ciphertext)<jupyter_output><empty_output><jupyter_text>Note that patterns involving repetition of letters are still visible in the ciphertext. Since `hello` contains two `l`s in sequence, the ciphertext also contains two `h`s in sequence, *at exactly the same position in the word*. This important drawback makes this Caesar cipher easily breakable, using a technique called frequency analysis. DecryptionDecryption is equally simple - we simply do a reverse lookup in the above mapping. To make things easy, let us build a reverse dictionary:<jupyter_code>reverse_dict = {}

for key in key_dict.keys():
    val = key_dict[key]
    reverse_dict[val] = key
    print(val, "will be replaced by", reverse_dict[val], "during decryption")<jupyter_output><empty_output><jupyter_text>We are now ready to decrypt the ciphertext<jupyter_code>decrypted = ''
for char in ciphertext:
    ptxt = reverse_dict[char]
    decrypted += ptxt
    print(char, "was replaced by", ptxt)

print("decrypted string is", decrypted)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07091957923311842, 'fraction_numerical': 0.0020359687818120122, 'mean_word_length': 5.219409282700422, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '436288', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 831, 'n_tokens_neox': 791, 'n_words': 386, 'path': 'stage4/06-jupyter/files/02-caesar.ipynb', 'repo_name': 'ADMETE-OHIO/pi-gen', 'size': '2947'}