Skip to content

Commit

Permalink
feat: added a few algorithms that will be used for rewriting RSA algo…
Browse files Browse the repository at this point in the history
…rithm that currently fails the tests (TheAlgorithms#288)

* feat: added a few algorithms that will be used for rsa algorithm

* fix: renamed the directory for better import string organisation

* fix: rename of a file

* updating DIRECTORY.md

* fix: corrected the mistakes in the documetation comments of some code

* fix: missplelling

* fix: spelling errors

* fix: reduced cyclomatic complexity

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
  • Loading branch information
tjgurwara99 and github-actions authored Mar 8, 2021
1 parent e701407 commit 8bc4e86
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 77 deletions.
10 changes: 7 additions & 3 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,19 @@
* Gcd
* [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go)
* [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go)
* [Gcditerative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcditerative.go)
* Lcm
* [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/lcm.go)
* Modulararithmetic
* [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go)
* [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go)
* Power
* [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go)
* [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go)
* Primecheck
* [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck.go)
* [Primecheck Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck_test.go)
* Prime
* [Millerrabinprimalitytest](https://github.com/TheAlgorithms/Go/blob/master/math/prime/millerrabinprimalitytest.go)
* [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go)
* [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/prime/primecheck.go)
* Pythagoras
* [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go)
* [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go)
Expand Down
2 changes: 1 addition & 1 deletion ciphers/polybius/polybius_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestNewPolybius(t *testing.T) {
wantErr string
}{
{
name: "correct initalization", size: 5, characters: "HogeF", key: "abcdefghijklmnopqrstuvwxy", wantErr: "",
name: "correct initialization", size: 5, characters: "HogeF", key: "abcdefghijklmnopqrstuvwxy", wantErr: "",
},
{
name: "truncate characters", size: 5, characters: "HogeFuga", key: "abcdefghijklmnopqrstuvwxy", wantErr: "",
Expand Down
6 changes: 3 additions & 3 deletions math/gcd/gcd.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package gcd

// Gcd finds and returns the greatest common divisor of a given integer.
func Gcd(a, b int) int {
// Recursive finds and returns the greatest common divisor of a given integer.
func Recursive(a, b int64) int64 {
if b == 0 {
return a
}
return Gcd(b, a%b)
return Recursive(b, a%b)
}
32 changes: 25 additions & 7 deletions math/gcd/gcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,48 @@ package gcd

import "testing"

type testFunction func(int64, int64) int64

var testCases = []struct {
name string
a int
b int
output int
a int64
b int64
output int64
}{
{"gcd of 10 and 0", 10, 0, 10},
{"gcd of 98 and 56", 98, 56, 14},
{"gcd of 0 and 10", 0, 10, 10},
}

func TestGCD(t *testing.T) {
func TemplateTestGCD(t *testing.T, f testFunction) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual := Gcd(tc.a, tc.b)
actual := f(tc.a, tc.b)
if actual != tc.output {
t.Errorf("Expected GCD of %d and %d to be: %v, but got: %d", tc.a, tc.b, tc.output, actual)
}
})
}
}

func BenchmarkGCD(b *testing.B) {
func TestGCDRecursive(t *testing.T) {
TemplateTestGCD(t, Recursive)
}

func TestGCDIterative(t *testing.T) {
TemplateTestGCD(t, Iterative)
}

func TemplateBenchmarkGCD(b *testing.B, f testFunction) {
for i := 0; i < b.N; i++ {
Gcd(98, 56)
f(98, 56)
}
}

func BenchmarkGCDRecursive(b *testing.B) {
TemplateBenchmarkGCD(b, Recursive)
}

func BenchmarkGCDIterative(b *testing.B) {
TemplateBenchmarkGCD(b, Iterative)
}
9 changes: 9 additions & 0 deletions math/gcd/gcditerative.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gcd

// Iterative Faster iterative version of GcdRecursive without holding up too much of the stack
func Iterative(a, b int64) int64 {
for b != 0 {
a, b = b, a%b
}
return a
}
12 changes: 12 additions & 0 deletions math/lcm/lcm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package lcm

import (
"math"

"github.com/TheAlgorithms/Go/math/gcd"
)

// Lcm returns the lcm of two numbers using the fact that lcm(a,b) * gcd(a,b) = | a * b |
func Lcm(a, b int64) int64 {
return int64(math.Abs(float64(a*b)) / float64(gcd.Iterative(a, b)))
}
6 changes: 3 additions & 3 deletions math/modulararithmetic/modularexponentiation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ func TestModularExponentiation(t *testing.T) {
result, err := ModularExponentiation(test.base, test.exponent, test.mod)
if err != test.expectedError {
t.Logf("Test Failed for %s", test.name)
t.Logf("Unexpected error occured")
t.Errorf("Expected error: %v, Recieved error: %v", test.expectedError, err)
t.Logf("Unexpected error occurred")
t.Errorf("Expected error: %v, Received error: %v", test.expectedError, err)
}
if result != test.expected {
t.Logf("Test Failed for %s", test.description)
t.Fatalf("Expected: %d, Recieved: %d", test.expected, result)
t.Fatalf("Expected: %d, Received: %d", test.expected, result)
}
})
}
Expand Down
73 changes: 73 additions & 0 deletions math/prime/millerrabinprimalitytest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package prime

import (
"math/rand"

"github.com/TheAlgorithms/Go/math/modulararithmetic"
)

// findD accepts a number and returns the
// odd number d such that num = 2^r * d - 1
func findRD(num int64) (int64, int64) {
r := int64(0)
d := num - 1
for num%2 == 0 {
d /= 2
r++
}
return d, r
}

// MillerTest This is the intermediate step that repeats within the
// miller rabin primality test for better probabilitic chances of
// receiving the correct result.
func MillerTest(d, num int64) (bool, error) {
random := rand.Int63n(num-1) + 2

res, err := modulararithmetic.ModularExponentiation(random, d, num)

if err != nil {
return false, err
}
// miller conditions checks
if res == 1 || res == num-1 {
return true, nil
}

for d != num-1 {
res = (res * res) % num
d *= 2
if res == 1 {
return false, nil
}
if res == num-1 {
return true, nil
}
}
return false, nil
}

// MillerRabinTest Probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin.
func MillerRabinTest(num, rounds int64) (bool, error) {
if num <= 4 {
if num == 2 || num == 3 {
return true, nil
}
return false, nil
}
if num%2 == 0 {
return false, nil
}
d, _ := findRD(num)

for i := int64(0); i < rounds; i++ {
val, err := MillerTest(d, num)
if err != nil {
return false, err
}
if !val {
return false, nil
}
}
return true, nil
}
29 changes: 28 additions & 1 deletion math/primecheck/primecheck_test.go → math/prime/prime_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package primecheck
package prime

import (
"testing"
Expand Down Expand Up @@ -49,6 +49,33 @@ func TestTablePairApproach(t *testing.T) {

}

func TestMillerRabinTest(t *testing.T) {
var tests = []struct {
name string
input int64
expected bool
rounds int64
err error
}{
{"smallest prime", 2, true, 5, nil},
{"random prime", 3, true, 5, nil},
{"neither prime nor composite", 1, false, 5, nil},
{"random non-prime", 10, false, 5, nil},
{"another random prime", 23, true, 5, nil},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
output, err := MillerRabinTest(test.input, test.rounds)
if err != test.err {
t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err)
}
if output != test.expected {
t.Errorf("For input: %d, expected: %v", test.input, output)
}
})
}
}

func BenchmarkNaiveApproach(b *testing.B) {
for i := 0; i < b.N; i++ {
NaiveApproach(23)
Expand Down
2 changes: 1 addition & 1 deletion math/primecheck/primecheck.go → math/prime/primecheck.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package primecheck
package prime

// A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography.
//Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type Result struct {
// }
// r := ahoCorasick(string(textFile), patterns)
// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one)
// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key)
// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key)
// for i := range value {
// fmt.Printf("%d", value[i])
// if i != len(value)-1 {
Expand Down Expand Up @@ -77,7 +77,7 @@ func AhoCorasick(t string, p []string) Result {
for i := range f[current] {
if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match
// if debugMode == true {
// fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]])
// fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]])
// }
newOccurrences := IntArrayCapUp(occurrences[f[current][i]])
occurrences[f[current][i]] = newOccurrences
Expand Down
4 changes: 2 additions & 2 deletions strings/multiple-string-matching/aho-corasick/ac.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type Result struct {
// }
// r := ahoCorasick(string(textFile), patterns)
// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one)
// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key)
// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key)
// for i := range value {
// fmt.Printf("%d", value[i])
// if i != len(value)-1 {
Expand Down Expand Up @@ -85,7 +85,7 @@ func AhoCorasick(t string, p []string) Result {
for i := range f[current] {
if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match
// if debugMode == true {
// fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]])
// fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]])
// }
newOccurrences := intArrayCapUp(occurrences[f[current][i]])
occurrences[f[current][i]] = newOccurrences
Expand Down
Loading

0 comments on commit 8bc4e86

Please sign in to comment.