--- /dev/null
+
+package main
+
+import (
+ "fmt"
+)
+
+// Encrypt message using columnar transposition:
+// 1. Write text in n*m matrix row by row.
+// 2. Then read message column by column. The order of columns to read is
+// determined by key.
+//
+// This is similar to https://www.boxentriq.com/code-breaking/columnar-transposition-cipher ,
+// except that if message does not fit into integer number of n*m matrixes,
+// here i'll pad the message.
+//
+// Encoding/decoding is done matrix by matrix.
+
+func encryption[T any](s []T, n, m int, key []int, pad T) []T {
+ var enc []T
+
+ // Matrix size.
+ size := n*m
+ if len(s)%size == 0 {
+ enc = make([]T, len(s))
+ } else {
+ enc = make([]T, len(s) + (size - len(s)%size))
+ }
+ fmt.Printf("enc len = %v, size = %v\n", len(enc), size)
+
+ // mx - matrix number, i - index inside the given matrix.
+ enc_elem := func (mx, i int, c T) {
+ bl := key[i%n] - 1 // m-block number
+ pos := i/n // position in m-block
+ res := mx*size + bl*m + pos
+ //fmt.Printf("[%v]: '%c' --> mx: %v, bl: %v, pos: %v, res: %v\n", i, c, mx, bl, pos, res)
+ enc[res] = c
+ }
+
+ // Each matrix contains 'size' elements.
+ enc_matrix := func(i int, c T) { enc_elem(i/size, i%size, c) }
+
+ for i := 0; i < len(s); i++ {
+ enc_matrix(i, s[i])
+ }
+ // Padding
+ for i := len(s); i < len(enc); i++ {
+ enc_matrix(i, pad)
+ }
+
+ return enc
+}
+
+func decryption[T any](s []T, n, m int, key []int) []T {
+ var dec []T
+
+ size := n*m
+ if len(s)%size == 0 {
+ dec = make([]T, len(s))
+ } else {
+ dec = make([]T, len(s) + (size - len(s)%size))
+ }
+
+ inv_key := make([]int, len(key))
+ for i := 0; i < len(key); i ++ {
+ inv_key[key[i]-1] = i
+ }
+ //fmt.Printf("inv key = %v\n", inv_key)
+
+ // mx - matrix number, i - index inside the given matrix.
+ dec_elem := func(mx, i int, c T) {
+ col := inv_key[i/m] // column
+ row := i%m // row
+ res := mx*size + row*n + col
+ //fmt.Printf("[%v]: '%v' --> mx: %v, col: %v, row: %v, res: %v\n", i, c, mx, col, row, res)
+ dec[res] = c
+ }
+
+ dec_matrix := func(i int, c T) { dec_elem(i/size, i%size, c) }
+
+ for i, c := range(s) {
+ dec_matrix(i, c)
+ }
+
+ return dec
+}
+
+func main() {
+ var n, m int
+ fmt.Printf("n m: ");
+ if _, err := fmt.Scanln(&n, &m); err != nil {
+ panic(err)
+ }
+ fmt.Printf("Read n=%v m=%v\n", n, m)
+
+ key := make([]int, 0)
+ fmt.Printf("Key: ")
+ for i := 0; i < n; i++ {
+ var v int
+ if _, err := fmt.Scan(&v); err != nil {
+ break
+ }
+ key = append(key, v)
+ }
+ fmt.Printf("Read key=%v\n", key);
+
+ var txt string
+ fmt.Printf("Text:")
+ if _, err := fmt.Scanf("%s", &txt); err != nil {
+ panic(err)
+ }
+ fmt.Printf("Read text=%v\n", txt);
+
+ enc := encryption([]byte(txt), n, m, key, '_')
+ fmt.Printf("enc = %v\n", string(enc))
+ dec := decryption(enc, n, m, key)
+ //dec := decryption([]byte(txt), n, m, key)
+ fmt.Printf("dec = %v\n", string(dec))
+}
+
--- /dev/null
+
+package main
+
+import (
+ "fmt"
+ "testing"
+ "bytes"
+ "strings"
+)
+
+type genKey struct {
+ i int // current swap index
+ n int // done permutations
+ max int // max number of permutations
+ key []int
+}
+
+func (g *genKey) init(key []int) {
+ g.key = key
+
+ g.max = 1
+ for t := 1; t <= len(key); t++ {
+ g.max = g.max * t
+ }
+}
+
+func (g *genKey) next() bool {
+ if g.n == 0 {
+ g.n++
+ return true
+ }
+
+ if g.n >= g.max {
+ return false
+ }
+
+ g.n++
+ j := g.i + 1
+ if j >= len(g.key) {
+ j = 0
+ }
+ g.key[g.i], g.key[j] = g.key[j], g.key[g.i]
+
+ g.i++
+ if (g.i >= len(g.key)) {
+ g.i = 0
+ }
+
+ return true
+}
+
+func TestEncDec(t *testing.T) {
+
+ run := func(n, m, l int) {
+ var buf bytes.Buffer
+ for i := 1; i <= l; i++ {
+ fmt.Fprintf(&buf, "%d", i%10)
+ }
+
+ var g genKey
+ key := make([]int, 0, n)
+ for i := 1; i <= n; i++ {
+ key = append(key, i)
+ }
+ g.init(key)
+
+ for g.next() {
+ bs := buf.Bytes()
+ fmt.Printf("Testing %vx%v: '%v' (%v) with %v\n", n, m, string(bs), l, key)
+
+ enc := encryption(bs, n, m, key, '_')
+ fmt.Printf("Encrypted: %v\n", string(enc))
+ //dec := decryption(enc, n, m, key)
+ dec := decryption([]byte(strings.TrimRight(string(enc), "_")), n, m, key)
+ for i := 0; i < len(bs); i++ {
+ if bs[i] != dec[i] {
+ t.Errorf("Failed at %v: %c != %c\n", i, bs[i], dec[i])
+ }
+ }
+ }
+ }
+
+ for n := 1; n < 4; n++ {
+ for m := 1; m < 4; m++ {
+ for l := (n*m)/2; l <= n*m + (n*m)/2; l++ {
+ //for l := n*m-1; l <= n*m; l++ {
+ run(n, m, l)
+ }
+ }
+ }
+
+}
+