diff options
author | Alexander Kiryukhin <a.kiryukhin@mail.ru> | 2019-08-30 01:43:12 +0300 |
---|---|---|
committer | Alexander Kiryukhin <a.kiryukhin@mail.ru> | 2019-08-30 01:43:12 +0300 |
commit | 878cb24695b7d39fa9de65a1e164abc84dc67ead (patch) | |
tree | 73946dd08310c2a3b7535297906a4ff5535db756 | |
parent | b0fba45d68c9ec6c2274ebd61b28ca22bb5deff6 (diff) |
Added Damm algorithm
-rw-r--r-- | README.md | 53 | ||||
-rw-r--r-- | damm/damm.go | 49 | ||||
-rw-r--r-- | damm/damm_test.go | 32 | ||||
-rw-r--r-- | luhn/luhn_test.go | 2 | ||||
-rw-r--r-- | verhoeff/verhoeff.go | 2 | ||||
-rw-r--r-- | verhoeff/verhoeff_test.go | 4 |
6 files changed, 132 insertions, 10 deletions
@@ -11,13 +11,16 @@ Pure Go implementations. ### Usage ```golang -import "github.com/neonxp/checksum/luhn" +import ( + "github.com/neonxp/checksum" + "github.com/neonxp/checksum/luhn" +) ... err := luhn.Check("4561261212345467") switch err { - case luhn.ErrInvalidNumber: + case checksum.ErrInvalidNumber: // Not a number - case luhn.ErrInvalidChecksum: + case checksum.ErrInvalidChecksum: // Invalid checksum case nil: // Valid number @@ -33,14 +36,17 @@ switch err { ### Usage ```golang -import "github.com/neonxp/checksum/verhoeff" +import ( + "github.com/neonxp/checksum" + "github.com/neonxp/checksum/verhoeff" +) ... numberWithoutChecksum := "4561261212345467" err := verhoeff.Check(number) switch err { - case luhn.ErrInvalidNumber: + case checksum.ErrInvalidNumber: // Not a number - case luhn.ErrInvalidChecksum: + case checksum.ErrInvalidChecksum: // Invalid checksum case nil: // Valid number @@ -55,3 +61,38 @@ if err := verhoeff.Check(numberWithChecksum); err != nil { panic(err) } ``` + +# Damm algorithm + +> In error detection, the Damm algorithm is a check digit algorithm that detects all single-digit errors and all adjacent transposition errors. It was presented by H. Michael Damm in 2004. + +[Wikipedia](https://en.wikipedia.org/wiki/Damm_algorithm) + +### Usage + +```golang +import ( + "github.com/neonxp/checksum" + "github.com/neonxp/checksum/damm" +) +... +numberWithoutChecksum := "4561261212345467" +err := damm.Check(number) +switch err { + case checksum.ErrInvalidNumber: + // Not a number + case checksum.ErrInvalidChecksum: + // Invalid checksum + case nil: + // Valid number +} + +checksum, err := damm.Generate(numberWithoutChecksum) +if err != nil { + panic(err) +} +numberWithChecksum := numberWithoutChecksum + checksum +if err := damm.Check(numberWithChecksum); err != nil { + panic(err) +} +``` diff --git a/damm/damm.go b/damm/damm.go new file mode 100644 index 0000000..388eb00 --- /dev/null +++ b/damm/damm.go @@ -0,0 +1,49 @@ +package damm + +import ( + "strconv" + + "github.com/neonxp/checksum" +) + +var d = [10][10]int{ + {0, 3, 1, 7, 5, 9, 8, 6, 4, 2}, + {7, 0, 9, 2, 1, 5, 4, 8, 6, 3}, + {4, 2, 0, 6, 8, 7, 1, 3, 5, 9}, + {1, 7, 5, 0, 9, 8, 3, 4, 2, 6}, + {6, 1, 2, 3, 0, 4, 5, 9, 7, 8}, + {3, 6, 7, 4, 2, 0, 9, 5, 8, 1}, + {5, 8, 6, 9, 7, 2, 0, 1, 3, 4}, + {8, 9, 4, 5, 3, 6, 2, 0, 1, 7}, + {9, 4, 3, 8, 6, 1, 7, 2, 0, 5}, + {2, 5, 8, 1, 4, 3, 6, 7, 9, 0}, +} + +// Check number is correct by damm algorithm +func Check(number string) error { + c := 0 + for _, ch := range number { + num, err := strconv.Atoi(string(ch)) + if err != nil { + return checksum.ErrInvalidNumber + } + c = d[c][num] + } + if c != 0 { + return checksum.ErrInvalidChecksum + } + return nil +} + +// Generate checksum (must be added to number at right) +func Generate(number string) (string, error) { + c := 0 + for _, ch := range number { + num, err := strconv.Atoi(string(ch)) + if err != nil { + return "", checksum.ErrInvalidNumber + } + c = d[c][num] + } + return strconv.Itoa(c), nil +} diff --git a/damm/damm_test.go b/damm/damm_test.go new file mode 100644 index 0000000..1f338b8 --- /dev/null +++ b/damm/damm_test.go @@ -0,0 +1,32 @@ +package damm + +import ( + "log" + "testing" + + "github.com/neonxp/checksum" +) + +func TestLuhn(t *testing.T) { + samples := map[string]error{ + "456126121234546": checksum.ErrInvalidChecksum, + "A56126121234546": checksum.ErrInvalidNumber, + "5724": nil, + } + for num, result := range samples { + if err := Check(num); err != result { + t.Errorf("Expected %+v actual %+v for %s", result, err, num) + } + } + + num := "572" + checksum, err := Generate(num) + if err != nil { + t.Error(err) + } + numberWithChecksum := num + checksum + log.Println(numberWithChecksum) + if err := Check(numberWithChecksum); err != nil { + t.Errorf("Expected no error actual %+v for %s", err, numberWithChecksum) + } +} diff --git a/luhn/luhn_test.go b/luhn/luhn_test.go index ea36119..24e57f2 100644 --- a/luhn/luhn_test.go +++ b/luhn/luhn_test.go @@ -14,7 +14,7 @@ func TestLuhn(t *testing.T) { } for num, result := range samples { if err := Check(num); err != result { - t.Errorf("Expected %+v actual %+v", result, err) + t.Errorf("Expected %+v actual %+v for %s", result, err, num) } } } diff --git a/verhoeff/verhoeff.go b/verhoeff/verhoeff.go index 259a7df..1bc5281 100644 --- a/verhoeff/verhoeff.go +++ b/verhoeff/verhoeff.go @@ -33,7 +33,7 @@ var p = [8][10]int{ var inv = [10]int{0, 4, 3, 2, 1, 5, 6, 7, 8, 9} -// Check number is correct by luhn algorithm +// Check number is correct by verhoeff algorithm func Check(number string) error { c := 0 numbers := strings.Split(number, "") diff --git a/verhoeff/verhoeff_test.go b/verhoeff/verhoeff_test.go index 7678b1f..005caf0 100644 --- a/verhoeff/verhoeff_test.go +++ b/verhoeff/verhoeff_test.go @@ -18,7 +18,7 @@ func TestVerhoeff(t *testing.T) { } for num, result := range samples { if err := Check(num); err != result { - t.Errorf("Expected %+v actual %+v", result, err) + t.Errorf("Expected %+v actual %+v for %s", result, err, num) } } @@ -29,6 +29,6 @@ func TestVerhoeff(t *testing.T) { } numberWithChecksum := num + checksum if err := Check(numberWithChecksum); err != nil { - t.Errorf("Expected no error actual %+v", err) + t.Errorf("Expected no error actual %+v for %s", err, numberWithChecksum) } } |