From: sgf Date: Tue, 5 Dec 2023 20:56:13 +0000 (+0300) Subject: new(transposition): Implementation of simple column transposition cipher. X-Git-Url: https://gitweb.sgf-dma.tk/?a=commitdiff_plain;h=98073b986aca18f11fc1d0c8ce0482940c418ad0;p=go.git new(transposition): Implementation of simple column transposition cipher. --- diff --git a/trans-cipher/.gitignore b/trans-cipher/.gitignore new file mode 100644 index 0000000..d848d0c --- /dev/null +++ b/trans-cipher/.gitignore @@ -0,0 +1,2 @@ +[0-9].cpp +a.out diff --git a/trans-cipher/main.go b/trans-cipher/main.go new file mode 100644 index 0000000..0ad6312 --- /dev/null +++ b/trans-cipher/main.go @@ -0,0 +1,120 @@ + +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)) +} + diff --git a/trans-cipher/main_test.go b/trans-cipher/main_test.go new file mode 100644 index 0000000..86b4594 --- /dev/null +++ b/trans-cipher/main_test.go @@ -0,0 +1,93 @@ + +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) + } + } + } + +} +