Added Damm algorithm

This commit is contained in:
Alexander Kiryukhin 2019-08-30 01:43:12 +03:00
parent b0fba45d68
commit 878cb24695
6 changed files with 132 additions and 10 deletions

View file

@ -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)
}
```

49
damm/damm.go Normal file
View file

@ -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
}

32
damm/damm_test.go Normal file
View file

@ -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)
}
}

View file

@ -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)
}
}
}

View file

@ -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, "")

View file

@ -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)
}
}