Capstone Project: The Vigenère Cipher

An exercise in data types, Unicode code points and type conversions.

Image credit: Tomasz Mikołajczyk, pixabay

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.

Adrian Evertsson
Adrian Evertsson
Economist

My research interests include macroeconometrics, economic growth theory and data science.