FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: Transposition cipher (#375) · gitgitcode/Go@9cdf346 · GitHub

/ Go Public
forked from TheAlgorithms/Go

Commit 9cdf346

Browse files
authored
feat: Transposition cipher (TheAlgorithms#375)
1 parent fefa8ca commit 9cdf346

2 files changed

Lines changed: 209 additions & 0 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// transposition.go
2+
// description: Transposition cipher
3+
// details:
4+
// Implementation "Transposition cipher" is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext [Transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher)
5+
// author(s) [red_byte](https://github.com/i-redbyte)
6+
// see transposition_test.go
7+
8+
package transposition
9+
10+
import (
11+
"sort"
12+
"strings"
13+
)
14+
15+
type NoTextToEncryptError struct{}
16+
type KeyMissingError struct{}
17+
18+
func (n *NoTextToEncryptError) Error() string {
19+
return "No text to encrypt"
20+
}
21+
func (n *KeyMissingError) Error() string {
22+
return "Missing Key"
23+
}
24+
25+
func getKey(keyWord string) []int {
26+
keyWord = strings.ToLower(keyWord)
27+
word := []rune(keyWord)
28+
var sortedWord = make([]rune, len(word))
29+
copy(sortedWord, word)
30+
sort.Slice(sortedWord, func(i, j int) bool { return sortedWord[i] < sortedWord[j] })
31+
usedLettersMap := make(map[rune]int)
32+
wordLength := len(word)
33+
resultKey := make([]int, wordLength)
34+
for i := 0; i < wordLength; i++ {
35+
char := word[i]
36+
numberOfUsage := usedLettersMap[char]
37+
resultKey[i] = getIndex(sortedWord, char) + numberOfUsage + 1 //+1 -so that indexing does not start at 0
38+
numberOfUsage++
39+
usedLettersMap[char] = numberOfUsage
40+
}
41+
return resultKey
42+
}
43+
44+
func getIndex(wordSet []rune, subString rune) int {
45+
n := len(wordSet)
46+
for i := 0; i < n; i++ {
47+
if wordSet[i] == subString {
48+
return i
49+
}
50+
}
51+
return 0
52+
}
53+
54+
func Encrypt(text []rune, keyWord string) (string, error) {
55+
key := getKey(keyWord)
56+
space := ' '
57+
keyLength := len(key)
58+
textLength := len(text)
59+
if keyLength <= 0 {
60+
return "", &KeyMissingError{}
61+
}
62+
if textLength <= 0 {
63+
return "", &NoTextToEncryptError{}
64+
}
65+
n := textLength % keyLength
66+
67+
for i := 0; i < keyLength-n; i++ {
68+
text = append(text, space)
69+
}
70+
textLength = len(text)
71+
result := ""
72+
for i := 0; i < textLength; i += keyLength {
73+
transposition := make([]rune, keyLength)
74+
for j := 0; j < keyLength; j++ {
75+
transposition[key[j]-1] = text[i+j]
76+
}
77+
result += string(transposition)
78+
}
79+
return result, nil
80+
}
81+
82+
func Decrypt(text []rune, keyWord string) (string, error) {
83+
key := getKey(keyWord)
84+
textLength := len(text)
85+
if textLength <= 0 {
86+
return "", &NoTextToEncryptError{}
87+
}
88+
keyLength := len(key)
89+
if keyLength <= 0 {
90+
return "", &KeyMissingError{}
91+
}
92+
space := ' '
93+
n := textLength % keyLength
94+
for i := 0; i < keyLength-n; i++ {
95+
text = append(text, space)
96+
}
97+
result := ""
98+
for i := 0; i < textLength; i += keyLength {
99+
transposition := make([]rune, keyLength)
100+
for j := 0; j < keyLength; j++ {
101+
transposition[j] = text[i+key[j]-1]
102+
}
103+
result += string(transposition)
104+
}
105+
return result, nil
106+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// transposition_test.go
2+
// description: Transposition cipher
3+
// author(s) [red_byte](https://github.com/i-redbyte)
4+
// see transposition.go
5+
6+
package transposition
7+
8+
import (
9+
"errors"
10+
"math/rand"
11+
"strings"
12+
"testing"
13+
)
14+
15+
const enAlphabet = "abcdefghijklmnopqrstuvwxyz "
16+
17+
func getTexts() []string {
18+
return []string{
19+
"Ilya Sokolov",
20+
"A slice literal is declared just like an array literal, except you leave out the element count",
21+
"Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.",
22+
"Go’s treatment of errors as values has served us well over the last decade. Although the standard library’s support for errors has been minimal—just the errors.New and fmt.Errorf functions, which produce errors that contain only a message—the built-in error interface allows Go programmers to add whatever information they desire. All it requires is a type that implements an Error method:",
23+
"А тут для примера русский текст",
24+
}
25+
}
26+
27+
func getRandomString() string {
28+
enRunes := []rune(enAlphabet)
29+
b := make([]rune, rand.Intn(100))
30+
for i := range b {
31+
b[i] = enRunes[rand.Intn(len(enRunes))]
32+
}
33+
return string(b)
34+
}
35+
36+
func TestEncrypt(t *testing.T) {
37+
fn := func(text string, keyWord string) (bool, error) {
38+
encrypt, err := Encrypt([]rune(text), keyWord)
39+
if err != nil && !errors.Is(err, &NoTextToEncryptError{}) && !errors.Is(err, &KeyMissingError{}) {
40+
t.Error("Unexpected error ", err)
41+
}
42+
return text == encrypt, err
43+
}
44+
for _, s := range getTexts() {
45+
if check, err := fn(s, getRandomString()); check || err != nil {
46+
t.Error("String ", s, " not encrypted")
47+
}
48+
}
49+
if _, err := fn(getRandomString(), ""); err == nil {
50+
t.Error("Error! empty string encryption")
51+
}
52+
}
53+
54+
func TestDecrypt(t *testing.T) {
55+
for _, s := range getTexts() {
56+
keyWord := getRandomString()
57+
encrypt, errEncrypt := Encrypt([]rune(s), keyWord)
58+
if errEncrypt != nil &&
59+
!errors.Is(errEncrypt, &NoTextToEncryptError{}) &&
60+
!errors.Is(errEncrypt, &KeyMissingError{}) {
61+
t.Error("Unexpected error ", errEncrypt)
62+
}
63+
if errEncrypt != nil {
64+
t.Error(errEncrypt)
65+
}
66+
decrypt, errDecrypt := Decrypt([]rune(encrypt), keyWord)
67+
if errDecrypt != nil &&
68+
!errors.Is(errDecrypt, &NoTextToEncryptError{}) &&
69+
!errors.Is(errDecrypt, &KeyMissingError{}) {
70+
t.Error("Unexpected error ", errDecrypt)
71+
}
72+
if errDecrypt != nil {
73+
t.Error(errDecrypt)
74+
}
75+
if encrypt == decrypt {
76+
t.Error("String ", s, " not encrypted")
77+
}
78+
if encrypt == s {
79+
t.Error("String ", s, " not encrypted")
80+
}
81+
}
82+
}
83+
84+
func TestEncryptDecrypt(t *testing.T) {
85+
text := "Test text for checking the algorithm"
86+
key1 := "testKey"
87+
key2 := "Test Key2"
88+
encrypt, errEncrypt := Encrypt([]rune(text), key1)
89+
if errEncrypt != nil {
90+
t.Error(errEncrypt)
91+
}
92+
decrypt, errDecrypt := Decrypt([]rune(encrypt), key1)
93+
if errDecrypt != nil {
94+
t.Error(errDecrypt)
95+
}
96+
if strings.Contains(decrypt, text) == false {
97+
t.Error("The string was not decrypted correctly")
98+
}
99+
decrypt, _ = Decrypt([]rune(encrypt), key2)
100+
if strings.Contains(decrypt, text) == true {
101+
t.Error("The string was decrypted with a different key")
102+
}
103+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL