aboutsummaryrefslogtreecommitdiff
path: root/verhoeff
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2019-08-30 01:26:24 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2019-08-30 01:26:24 +0300
commit2d69c4db4db25e256c22b8fd544dc7b95d71da9c (patch)
tree4a0f35c6b88b92305d460f4ebbd4d81619f1def0 /verhoeff
Initial
Diffstat (limited to 'verhoeff')
-rw-r--r--verhoeff/verhoeff.go69
-rw-r--r--verhoeff/verhoeff_test.go34
2 files changed, 103 insertions, 0 deletions
diff --git a/verhoeff/verhoeff.go b/verhoeff/verhoeff.go
new file mode 100644
index 0000000..259a7df
--- /dev/null
+++ b/verhoeff/verhoeff.go
@@ -0,0 +1,69 @@
+package verhoeff
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/neonxp/checksum"
+)
+
+var d = [10][10]int{
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ {1, 2, 3, 4, 0, 6, 7, 8, 9, 5},
+ {2, 3, 4, 0, 1, 7, 8, 9, 5, 6},
+ {3, 4, 0, 1, 2, 8, 9, 5, 6, 7},
+ {4, 0, 1, 2, 3, 9, 5, 6, 7, 8},
+ {5, 9, 8, 7, 6, 0, 4, 3, 2, 1},
+ {6, 5, 9, 8, 7, 1, 0, 4, 3, 2},
+ {7, 6, 5, 9, 8, 2, 1, 0, 4, 3},
+ {8, 7, 6, 5, 9, 3, 2, 1, 0, 4},
+ {9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+}
+
+var p = [8][10]int{
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ {1, 5, 7, 6, 2, 8, 3, 0, 9, 4},
+ {5, 8, 0, 3, 7, 9, 6, 1, 4, 2},
+ {8, 9, 1, 6, 0, 4, 3, 5, 2, 7},
+ {9, 4, 5, 3, 1, 2, 6, 8, 7, 0},
+ {4, 2, 8, 6, 5, 7, 3, 9, 0, 1},
+ {2, 7, 9, 3, 8, 0, 6, 4, 1, 5},
+ {7, 0, 4, 6, 9, 1, 3, 2, 5, 8},
+}
+
+var inv = [10]int{0, 4, 3, 2, 1, 5, 6, 7, 8, 9}
+
+// Check number is correct by luhn algorithm
+func Check(number string) error {
+ c := 0
+ numbers := strings.Split(number, "")
+ l := len(numbers)
+ for i := l; i > 0; i-- {
+ ch := numbers[i-1]
+ num, err := strconv.Atoi(string(ch))
+ if err != nil {
+ return checksum.ErrInvalidNumber
+ }
+ c = d[c][p[(l-i)&7][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
+ numbers := strings.Split(number, "")
+ l := len(numbers)
+ for i := l; i > 0; i-- {
+ ch := numbers[i-1]
+ num, err := strconv.Atoi(string(ch))
+ if err != nil {
+ return "", checksum.ErrInvalidNumber
+ }
+ c = d[c][p[(l-i+1)&7][num]]
+ }
+ return strconv.Itoa(inv[c]), nil
+}
diff --git a/verhoeff/verhoeff_test.go b/verhoeff/verhoeff_test.go
new file mode 100644
index 0000000..7678b1f
--- /dev/null
+++ b/verhoeff/verhoeff_test.go
@@ -0,0 +1,34 @@
+package verhoeff
+
+import (
+ "testing"
+
+ "github.com/neonxp/checksum"
+)
+
+func TestVerhoeff(t *testing.T) {
+ samples := map[string]error{
+ "4561261212345464": checksum.ErrInvalidChecksum,
+ "A561261212345464": checksum.ErrInvalidNumber,
+ "758722": nil,
+ "123451": nil,
+ "1428570": nil,
+ "1234567890120": nil,
+ "84736430954837284567892": nil,
+ }
+ for num, result := range samples {
+ if err := Check(num); err != result {
+ t.Errorf("Expected %+v actual %+v", result, err)
+ }
+ }
+
+ num := "4561261212345467"
+ checksum, err := Generate(num)
+ if err != nil {
+ t.Error(err)
+ }
+ numberWithChecksum := num + checksum
+ if err := Check(numberWithChecksum); err != nil {
+ t.Errorf("Expected no error actual %+v", err)
+ }
+}