Skip to content

Commit

Permalink
Add railfence cipher (#715)
Browse files Browse the repository at this point in the history
* added rail fence cipher implementation

* updated readme

* fixed typo

---------

Co-authored-by: Rak Laptudirm <[email protected]>
  • Loading branch information
Chandrahas77 and raklaptudirm authored Apr 24, 2024
1 parent 0d0b97a commit c5173f3
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.
2. [`Encrypt`](./cipher/xor/xor.go#L10): Encrypt encrypts with Xor encryption after converting each character to byte The returned value might not be readable because there is no guarantee which is within the ASCII range If using other type such as string, []int, or some other types, add the statements for converting the type to []byte.
3. [`FuzzXOR`](./cipher/xor/xor_test.go#L108): No description provided.

---
</details>

##### Package rail fence is a classical type of transposition cipher ref : https://en.wikipedia.org/wiki/Rail_fence_cipher

---
##### Functions:

1. [`Encrypt`](.cipher/railfence/railfence.go#L7): Encrypt encrypts a message using rail fence cipher
2. [`Decrypt`](.cipher/railfence/railfence.go#L44): decrypt decrypts a message using rail fence cipher
3. [`TestEncrypt`](.cipher/railfence/railfence_test.go#L7) Test function for Encrypt
4. [`TestDecrypt`](.cipher/railfence/railfence_test.go#L50) Test function for Decrypt

---
</details>
<!--- GODOCMD END --->
75 changes: 75 additions & 0 deletions cipher/railfence/railfence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package railfence

import (
"strings"
)

func Encrypt(text string, rails int) string {
if rails == 1 {
return text
}

// Create a matrix for the rail fence pattern
matrix := make([][]rune, rails)
for i := range matrix {
matrix[i] = make([]rune, len(text))
}

// Fill the matrix
dirDown := false
row, col := 0, 0
for _, char := range text {
if row == 0 || row == rails-1 {
dirDown = !dirDown
}
matrix[row][col] = char
col++
if dirDown {
row++
} else {
row--
}
}
var result strings.Builder
for _, line := range matrix {
for _, char := range line {
if char != 0 {
result.WriteRune(char)
}
}
}

return result.String()
}
func Decrypt(cipherText string, rails int) string {
if rails == 1 || rails >= len(cipherText) {
return cipherText
}

// Placeholder for the decrypted message
decrypted := make([]rune, len(cipherText))

// Calculate the zigzag pattern and place characters accordingly
index := 0
for rail := 0; rail < rails; rail++ {
position := rail
down := true // Direction flag
for position < len(cipherText) {
decrypted[position] = rune(cipherText[index])
index++

// Determine the next position based on the current rail and direction
if rail == 0 || rail == rails-1 {
position += 2 * (rails - 1)
} else if down {
position += 2 * (rails - 1 - rail)
down = false
} else {
position += 2 * rail
down = true
}
}
}

return string(decrypted)
}
91 changes: 91 additions & 0 deletions cipher/railfence/railfence_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package railfence

import (
"testing"
)

func TestEncrypt(t *testing.T) {
var railFenceTestData = []struct {
description string
input string
rails int
expected string
}{
{
"Encrypt with 2 rails",
"hello",
2,
"hloel",
},
{
"Encrypt with 3 rails",
"hello world",
3,
"horel ollwd",
},
{
"Encrypt with edge case: 1 rail",
"hello",
1,
"hello",
},
{
"Encrypt with more rails than letters",
"hi",
100,
"hi",
},
}

for _, test := range railFenceTestData {
t.Run(test.description, func(t *testing.T) {
actual := Encrypt(test.input, test.rails)
if actual != test.expected {
t.Errorf("FAIL: %s - Encrypt(%s, %d) = %s, want %s", test.description, test.input, test.rails, actual, test.expected)
}
})
}
}

func TestDecrypt(t *testing.T) {
var railFenceTestData = []struct {
description string
input string
rails int
expected string
}{
{
"Decrypt with 2 rails",
"hloel",
2,
"hello",
},
{
"Decrypt with 3 rails",
"ho l lewrdlo",
3,
"hld olle wor",
},
{
"Decrypt with edge case: 1 rail",
"hello",
1,
"hello",
},
{
"Decrypt with more rails than letters",
"hi",
100,
"hi",
},
}

for _, test := range railFenceTestData {
t.Run(test.description, func(t *testing.T) {
actual := Decrypt(test.input, test.rails)
if actual != test.expected {
t.Errorf("FAIL: %s - Decrypt(%s, %d) = %s, want %s", test.description, test.input, test.rails, actual, test.expected)
}
})
}
}

0 comments on commit c5173f3

Please sign in to comment.