aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md53
-rw-r--r--damm/damm.go49
-rw-r--r--damm/damm_test.go32
-rw-r--r--luhn/luhn_test.go2
-rw-r--r--verhoeff/verhoeff.go2
-rw-r--r--verhoeff/verhoeff_test.go4
6 files changed, 132 insertions, 10 deletions
diff --git a/README.md b/README.md
index 20d0e3f..989ebbf 100644
--- a/README.md
+++ b/README.md
@@ -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)
}
}