Capstone Project: The Vigenère Cipher
An exercise in data types, Unicode code points and type conversions.
Description
This is the second capstone project in the book Get Programming with Go by Nathan Youngman and Roger Peppé (2018). The “The Vigenère Cipher” project closes off unit two of the book, which covers real numbers, memory-versus-precision trade-offs, big numbers, multilingual text, type conversions and more.
Task
Decipher the given string (see cipherText below), which is encrypted using the Vigenère cipher (see en.wikipedia.org/wiki/Vigenere_cipher). The Vigenère cipher is essentially a Caesar cipher (see en.wikipedia.org/wiki/Caesar_cipher) but with modular shifts instead of fixed shifts. In our scenario the key is “golang” with wrap around.
cipherText := "CSOITEUIWUIZNSROCNKFD"
keyword := "GOLANG"
For a full description of the project, see Get Programming with Go (Youngman, Peppé, 2018).
Method
The first part was to construct the key, i.e. the string “golang” repeating itself for the length of the text to be deciphered. The key could of course just have been hardcoded into the script but doing it this way I got to use for-loops with more than one variable, which was good practice. Before I figured out that the type conversion could be as simple as calling string()
, I constructed a more lengthy switch
statement,
switch keyword[j] {
case 71:
repeatedKeyword += "G"
case 79:
repeatedKeyword += "O"
case 76:
repeatedKeyword += "L"
case 65:
repeatedKeyword += "A"
case 78:
repeatedKeyword += "N"
}
which essentially is just a more cumbersome way of converting a uint8
Uniocode code point to a string
. Although this way of converting works, it involves a fair bit of hardcoding, so just calling string()
is to be preferred.
Constructing the key proved to be the hardest part, since the actual deciphering is done by just shifting bytes and code points around. A note for the reader would be that the code point 65
in Unicode corresponds to the capital letter “A”. This means that in order to check for wrap arounds in the alphabet the conditional if
statement below is needed:
if (cipherText[i] - (repeatedKeyword[i] - 65)) < 65 {
fmt.Printf("%c", cipherText[i]-(repeatedKeyword[i]-65)+26)
} else {
fmt.Printf("%c", cipherText[i]-(repeatedKeyword[i]-65))
All in all this was another fun exercise.
Output
GOLANGGOLANGGOLANGGOL
WEDIGYOULUVTHEGOPHERS%
Code
package main
import "fmt"
func main() {
cipherText := "CSOITEUIWUIZNSROCNKFD"
keyword := "GOLANG"
var repeatedKeyword string
for i, j := 0, 0; i < len(cipherText); i, j = i+1, j+1 {
if j == 6 {
j = 0
}
repeatedKeyword += string(keyword[j])
}
fmt.Printf("%v\n", repeatedKeyword)
for i := 0; i < len(cipherText); i++ {
if (cipherText[i] - (repeatedKeyword[i] - 65)) < 65 {
fmt.Printf("%c", cipherText[i]-(repeatedKeyword[i]-65)+26)
} else {
fmt.Printf("%c", cipherText[i]-(repeatedKeyword[i]-65))
}
}
}
References
Youngman, Nathan & Peppé, Roger. (2018). Get programming with go. Manning Publications.