All articles
Go

Capstone Project: The Vigenere Cipher

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

Antique cipher wheel

Description

This is the second capstone project in the book Get Programming with Go by Nathan Youngman and Roger Peppe (2018). The "The Vigenere 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 Vigenere cipher (see en.wikipedia.org/wiki/Vigenere_cipher). The Vigenere 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, Peppe, 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 Unicode 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 & Peppe, Roger. (2018). Get programming with go. Manning Publications.