RosettaCodeData/Task/Bifid-cipher/Go/bifid-cipher.go

181 lines
4.1 KiB
Go

/*
Only use ASCII letters between A and Z or the Characters in square... . If the row with 'J' is removed from the squares,
then the square is a 'Polybios square' and you must use removeSpaceI(text) to encrypt and decrypt
*/
package main
import (
"fmt"
"strings"
)
var (
squareRosetta [][]byte = [][]byte{ //rosettacode
{'A', 'B', 'C', 'D', 'E'},
{'F', 'G', 'H', 'I', 'K'},
{'L', 'M', 'N', 'O', 'P'},
{'Q', 'R', 'S', 'T', 'U'},
{'V', 'W', 'X', 'Y', 'Z'},
{'J', '1', '2', '3', '4'},
}
squareWikipedia [][]byte = [][]byte{ // wikipedia
{'B', 'G', 'W', 'K', 'Z'},
{'Q', 'P', 'N', 'D', 'S'},
{'I', 'O', 'A', 'X', 'E'},
{'F', 'C', 'L', 'U', 'M'},
{'T', 'H', 'Y', 'V', 'R'},
{'J', '1', '2', '3', '4'},
}
textRosetta string = "0ATTACKATDAWN"
textRosettaEncoded string = "DQBDAXDQPDQH" // only for test
textWikipedia string = "FLEEATONCE"
textWikipediaEncoded string = "UAEOLWRINS" // only for test
textTest string = "The invasion will start on the first of January"
textTextEncoded string = "RASOAQXFIOORXESXADETSWLTNIAZQOISBRGBALY" // only for test
)
type koord struct {
X byte
Y byte
}
func (k *koord) LessThen(other *koord) bool {
if k.Y > other.Y {
return false
}
if k.Y < other.Y {
return true
}
if k.X < other.X {
return true
}
return false
}
func (k *koord) EqualTo(other koord) bool {
if k.X == other.X && k.Y == other.Y {
return true
}
return false
}
var encryptMap map[byte]koord
var decryptMap map[koord]byte
func squareToMaps(square [][]byte) (map[byte]koord, map[koord]byte) {
eMap := make(map[byte]koord)
dMap := make(map[koord]byte)
for x, col := range square {
for y, v := range col {
eMap[v] = koord{byte(x), byte(y)}
dMap[koord{byte(x), byte(y)}] = v
}
}
return eMap, dMap
}
func removeSpaceI(text string) string {
var n string
s := strings.ToUpper(text)
for _, b := range []byte(s) {
//use only ASCII Characters from A to Z
if b < 'A' || b > 'Z' {
continue
}
if b == 'J' {
b = 'I'
}
n = n + string(b)
}
return n
}
func removeSpace(text string, square map[byte]koord) string {
var n string
//to UpperCase and then remove all Spaces an Characters witch are not in square
s := strings.ReplaceAll(strings.ToUpper(text), " ", "")
for _, b := range []byte(s) {
_, ok := square[b]
if ok {
n = n + string(b)
}
}
return n
}
func encrypt(text string, emap map[byte]koord, dmap map[koord]byte) string {
text = removeSpace(text, emap)
var row0, row1 []byte
for _, b := range []byte(text) {
xy := emap[b]
row0 = append(row0, xy.X)
row1 = append(row1, xy.Y)
}
row0 = append(row0, row1...)
var s string
for i := 0; i < len(row0); i += 2 {
s = s + string(dmap[koord{row0[i], row0[i+1]}])
}
return s
}
func decrypt(text string, emap map[byte]koord, dmap map[koord]byte) string {
text = removeSpace(text, emap)
k := make([]koord, len(text))
for i, b := range []byte(text) {
k[i] = emap[b]
}
kl := make([]byte, len(k)*2)
i := int(0)
for _, ki := range k {
kl[i] = ki.X
kl[i+1] = ki.Y
i += 2
}
l := len(kl) / 2
k1 := kl[:l]
k2 := kl[l:]
var s string
for i := 0; i < l; i++ {
s = s + string(dmap[koord{k1[i], k2[i]}])
}
return s
}
func main() {
encryptMap, decryptMap = squareToMaps(squareRosetta)
fmt.Println("from Rosettacode")
fmt.Println("original:\t", textRosetta)
s := encrypt(textRosetta, encryptMap, decryptMap)
fmt.Println("codiert:\t", s)
s = decrypt(s, encryptMap, decryptMap)
fmt.Println("and back:\t", s)
fmt.Println("from Wikipedia")
encryptMap, decryptMap = squareToMaps(squareWikipedia)
fmt.Println("original:\t", textWikipedia)
s = encrypt(textWikipedia, encryptMap, decryptMap)
fmt.Println("codiert:\t", s)
s = decrypt(s, encryptMap, decryptMap)
fmt.Println("and back:\t", s)
encryptMap, decryptMap = squareToMaps(squareWikipedia)
fmt.Println("from Rosettacode long part")
fmt.Println("original:\t", textTest)
s = encrypt(textTest, encryptMap, decryptMap)
fmt.Println("codiert:\t", s)
// Wenn der Text eine ungerade Anzahl Buchstaben hat, funktioniert der Algorithmus nicht!!!
s = decrypt(s, encryptMap, decryptMap)
fmt.Println("and back:\t", s)
}