Homework 2: Secret Messages

For this homework, you’ll be writing algorithms to encode and decode secret messages.

You will work on three kinds of ciphers:

  • Atbash cipher
  • Caesar cipher
  • Vigenère cipher

Your code will need to be able to encode and decode messages. For all of the _encode and _decode functions, your code is expected to work with lowercase letters from a-z. Your code will not be tested on uppercase letters, spaces, numbers, or any other characters besides lowercase a-z.

For each cipher, you will begin by encoding an example by hand to make sure that you understand the algorithm for the cipher before you start to code. Your encoding will be checked by the autograder on gradescope, so you should submit to make sure that your answer is correct before continuing!

After you get the right answer by hand, you are ready to write your code. You can also use this as a test case to debug your code.

You’ll write your code in this template file.

Starter code

I have provided a few functions to get you started:

  • letter_to_index: gives an index from 0 to 25 for a lowercase character (a = 0, b = 1, …, z = 25)
  • index_to_letter: takes an index from 0 to 25 and gives a lowercase character (a = 0, b = 1, …, z = 25)

Atbash Cipher

The atbash cipher is a substitution cipher in which you map each letter to another by reversing the alphabet. A becomes Z, B becomes Y, etc.

OriginalABCDEFGHIJKLMNOPQRSTUVWXYZ
EncodedZYXWVUTSRQPONMLKJIHGFEDCBA

As an example, "dog" encoded using atbash is "wlt" (each character is replaced with the corresponding character in the table above). The atbash cipher is the most straightforward to write in Python, as the encoding and decoding processes are exactly the same.

Using a simple mathematical formula, you should be able to do the following:

  • convert each letter to a number from 0 to 25 using letter_to_index
  • use your formula to convert it to the “opposite” number
  • convert the number to the correct letter using index_to_letter

Each letter is assigned a number from 0-25:

LetterABCDEFGHIJKLMNOPQRSTUVWXYZ
Number012345678910111213141516171819202122232425

Problem 1: Atbash on paper

Encode the message compsci by hand using the atbash cipher, and set the variable ENCODED_ATBASH to the result.

Problem 2: atbash_encode_decode function

Write one function, atbash_encode_decode. It should take one argument, a string message, and return the encoded/decoded message. Make sure your function has a docstring comment!

Caesar Cipher

In a Caesar cipher, each character is replaced with the character $n$ positions away from it in the alphabet
Image Source

In the example above, $n = 3$. We will call this number our key.

The algorithm for encoding each letter is a follows:

  • convert each letter to a number from 0 to 25 using letter_to_index
  • shift it by key; use % (modulo) to “wrap” around if the index exceeds the number of letter in the alphabet
  • convert the number to the correct letter using index_to_letter

To decode, you do the opposite: simply shift in the other direction.

As an example, "dog" encoded using the caesar cipher and the key 12 is "pas".

The Caesar Cipher is slightly more secure than the Atbash cipher, because there are 25 different options for the key (using 0 or 26 would lead to no change from the original message).

For more information about the Caesar Cipher, see this article:

Problem 3: Caesar on paper

Encode the message programming by hand using the caesar cipher and the key 6, and set the variable ENCODED_CAESAR to the result.

Problem 4: caesar_encode and caesar_decode functions

Write two functions, caesar_encode and caesar_decode. They should both take two arguments, a string message and an int key, and return the encoded (or decoded) message. Make sure your functions both have docstring comments!

Vigenère cipher

The Vigenère cipher is a lot like the Caesar cipher, but different keys are used for different letters. This is accomplished by defining a keyword.

The keyword is repeated until it is the length of our string (it is okay if the keyword is cut off at the end). Here’s an example with the message studying and the keyword cipher:

Textstudying
Keywordcipherci
Key2815741728

To determine the key of a letter to encode, you look to it’s corresponding letter in the repeating keyword string. As we saw in the Caesar cipher, all letters correspond to some index, and the index of this corresponding letter is going to be our key! So, if the keyword letter is a, the key is 0, if it is b, the key is 1, etc. To do this conversion, you can use the letter_to_index function.

Looking at the example above, you can see that each letter in the text corresponds to a letter in the repeated keyword. The key of our first letter ‘s’ will be 2, as it corresponds to the letter ‘c’. The key to our second letter ‘t’ will be 8, as it corresponds to the letter ‘i’.

Once you know the key for each letter, you can simply use your caesar encode and decode functions with that single letter and key pair. As an example, "dog" encoded using the Vigenère cipher and the keyword "de" is "gsj".

This process makes the Vigenère cipher much more secure than the Caesar cipher, as you can use many more than 26 different keywords!

To align your string and keyword, you will want to use a loop with string indices. You’ll write a function that repeats your keyword; for this function, it will probably be helpful to use %, but it can be completed with conditionals as well.

Problem 5: Vigenère on paper

Encode the message middlebury by hand using the vigenere cipher and the keyword abc, and set the variable ENCODED_VIGENERE to the result.

Problem 6: keyword_repeat function

You’ll start by writing a function keyword_repeat. keyword_repeat should take two arguments: a string keyword and an int length. It should return a list of length length where keyword is repeated. Make sure your function has as docstring comment!

For example, keyword_repeat("tree", 7) should return ["t", "r", "e", "e", "t", "r", "e"].

Problem 7: vigenere_encode and vigenere_decode functions

Write two functions, vigenere_encode and vigenere_decode. They should both take two arguments, a string message and a string keyword, and return the encoded (or decoded) message. Make sure your functions both have docstring comments!

I suggest using your keyword_repeat function in your implementation, but any working implementation will be accepted.

For more information about the Vigenère Cipher, see this article:

Submission

Rename your file submission.py and submit your assignment on gradescope. All components (excluding style) are autograded.