Skip to content

Commit

Permalink
feat(cipher/polybius): add fuzz test to polybius cipher (#600)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcaci authored Nov 11, 2022
1 parent aa85e4e commit 7523f41
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.
7. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity.
8. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided.
9. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit
10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L12): LongestCommonSubsequence function
10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L13): LongestCommonSubsequence function
11. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order
12. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/
13. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L25): LpsDp function
Expand Down Expand Up @@ -778,6 +778,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.
3. [`Queue`](./structure/queue/queuelinkedlist.go#L19): No description provided.


---
</details><details>
<summary> <strong> rot13 </strong> </summary>

---

##### Package rot13 is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. ref: https://en.wikipedia.org/wiki/ROT13

---
##### Functions:

1. [`FuzzRot13`](./cipher/rot13/rot13_test.go#L72): No description provided.

---
</details><details>
<summary> <strong> rsa </strong> </summary>
Expand Down
21 changes: 16 additions & 5 deletions cipher/polybius/polybius.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,22 @@ type Polybius struct {
// If the size of "chars" is longer than "size",
// "chars" are truncated to "size".
func NewPolybius(key string, size int, chars string) (*Polybius, error) {
if size < 0 {
return nil, fmt.Errorf("provided size %d cannot be negative", size)
}
key = strings.ToUpper(key)
if size > len(chars) {
return nil, fmt.Errorf("provided size %d is too small to use to slice string %q of len %d", size, chars, len(chars))
}
for _, r := range chars {
if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') {
return nil, fmt.Errorf("provided string %q should only contain latin characters", chars)
}
}
chars = strings.ToUpper(chars)[:size]
for idx, ch := range chars {
if strings.Contains(chars[idx+1:], string(ch)) {
return nil, fmt.Errorf("\"chars\" contains same character: %c", ch)
for i, r := range chars {
if strings.ContainsRune(chars[i+1:], r) {
return nil, fmt.Errorf("%q contains same character %q", chars[i+1:], r)
}
}

Expand Down Expand Up @@ -63,7 +74,7 @@ func (p *Polybius) Decrypt(text string) (string, error) {
func (p *Polybius) encipher(char rune) (string, error) {
index := strings.IndexRune(p.key, char)
if index < 0 {
return "", fmt.Errorf("%c does not exist in keys", char)
return "", fmt.Errorf("%q does not exist in keys", char)
}
row := index / p.size
col := index % p.size
Expand All @@ -83,5 +94,5 @@ func (p *Polybius) decipher(chars []rune) (string, error) {
if col < 0 {
return "", fmt.Errorf("%c does not exist in characters", chars[1])
}
return string([]rune(p.key)[row*p.size+col]), nil
return string(p.key[row*p.size+col]), nil
}
43 changes: 41 additions & 2 deletions cipher/polybius/polybius_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package polybius
import (
"fmt"
"log"
"strings"
"testing"
)

Expand Down Expand Up @@ -54,7 +55,7 @@ func TestNewPolybius(t *testing.T) {
name: "invalid key", size: 5, characters: "HogeFuga", key: "abcdefghi", wantErr: "len(key): 9 must be as long as size squared: 25",
},
{
name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"chars\" contains same character: H",
name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"OGEH\" contains same character 'H'",
},
}

Expand All @@ -79,7 +80,7 @@ func TestPolybiusEncrypt(t *testing.T) {
name: "correct encryption", text: "HogeFugaPiyoSpam", want: "OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG",
},
{
name: "invalid encryption", text: "hogz", want: "failed encipher: Z does not exist in keys",
name: "invalid encryption", text: "hogz", want: "failed encipher: 'Z' does not exist in keys",
},
}
// initialize
Expand Down Expand Up @@ -149,3 +150,41 @@ func TestPolybiusDecrypt(t *testing.T) {
})
}
}

func FuzzPolybius(f *testing.F) {
const (
size = 5
characters = "HogeF"
key = "abcdefghijklmnopqrstuvwxy"
)
f.Add(size, characters, key)
f.Fuzz(func(t *testing.T, size int, characters, key string) {
p, err := NewPolybius(key, size, characters)
switch {
case err == nil:
case strings.Contains(err.Error(), "cannot be negative"),
strings.Contains(err.Error(), "is too small"),
strings.Contains(err.Error(), "should only contain latin characters"),
strings.Contains(err.Error(), "contains same character"),
strings.Contains(err.Error(), "must be as long as size squared"):
return
default:
t.Fatalf("unexpected error when creating a new polybius variable: %v", err)
}
encrypted, err := p.Encrypt(characters)
switch {
case err == nil:
case strings.Contains(err.Error(), "does not exist in keys"):
return
default:
t.Fatalf("unexpected error during encryption: %v", err)
}
decrypted, err := p.Decrypt(encrypted)
if err != nil {
t.Fatalf("unexpected error during decryption: %v", err)
}
if decrypted != strings.ToUpper(characters) {
t.Errorf("Expecting output to match with %q but was %q", characters, decrypted)
}
})
}

0 comments on commit 7523f41

Please sign in to comment.