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.
Original | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Encoded | Z | Y | X | W | V | U | T | S | R | Q | P | O | N | M | L | K | J | I | H | G | F | E | D | C | B | A |
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:
Letter | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Number | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
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
:
Text | s | t | u | d | y | i | n | g |
---|---|---|---|---|---|---|---|---|
Keyword | c | i | p | h | e | r | c | i |
Key | 2 | 8 | 15 | 7 | 4 | 17 | 2 | 8 |
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.