RosettaCodeData/Task/Vigen-re-cipher/Go/vigen-re-cipher.go

70 lines
1.6 KiB
Go

package main
import "fmt"
type vkey string
func newVigenère(key string) (vkey, bool) {
v := vkey(upperOnly(key))
return v, len(v) > 0 // key length 0 invalid
}
func (k vkey) encipher(pt string) string {
ct := upperOnly(pt)
for i, c := range ct {
ct[i] = 'A' + (c-'A'+k[i%len(k)]-'A')%26
}
return string(ct)
}
func (k vkey) decipher(ct string) (string, bool) {
pt := make([]byte, len(ct))
for i := range pt {
c := ct[i]
if c < 'A' || c > 'Z' {
return "", false // invalid ciphertext
}
pt[i] = 'A' + (c-k[i%len(k)]+26)%26
}
return string(pt), true
}
// upperOnly extracts letters A-Z, a-z from a string and
// returns them all upper case in a byte slice.
// Useful for vkey constructor and encipher function.
func upperOnly(s string) []byte {
u := make([]byte, 0, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
if c >= 'A' && c <= 'Z' {
u = append(u, c)
} else if c >= 'a' && c <= 'z' {
u = append(u, c-32)
}
}
return u
}
const testKey = "Vigenère Cipher"
const testPT = `Beware the Jabberwock, my son!
The jaws that bite, the claws that catch!`
func main() {
fmt.Println("Supplied key: ", testKey)
v, ok := newVigenère(testKey)
if !ok {
fmt.Println("Invalid key")
return
}
fmt.Println("Effective key:", v)
fmt.Println("Plain text:", testPT)
ct := v.encipher(testPT)
fmt.Println("Enciphered:", ct)
dt, ok := v.decipher(ct)
if !ok {
fmt.Println("Invalid ciphertext")
return
}
fmt.Println("Deciphered:", dt)
}