luhn.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright (C) 2014 Jakob Borg
  2. // Package luhn generates and validates Luhn mod N check digits.
  3. package luhn
  4. import (
  5. "fmt"
  6. "strings"
  7. )
  8. // An alphabet is a string of N characters, representing the digits of a given
  9. // base N.
  10. type Alphabet string
  11. var (
  12. Base32 Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
  13. )
  14. // Generate returns a check digit for the string s, which should be composed
  15. // of characters from the Alphabet a.
  16. func (a Alphabet) Generate(s string) (rune, error) {
  17. if err := a.check(); err != nil {
  18. return 0, err
  19. }
  20. factor := 1
  21. sum := 0
  22. n := len(a)
  23. for i := range s {
  24. codepoint := strings.IndexByte(string(a), s[i])
  25. if codepoint == -1 {
  26. return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
  27. }
  28. addend := factor * codepoint
  29. if factor == 2 {
  30. factor = 1
  31. } else {
  32. factor = 2
  33. }
  34. addend = (addend / n) + (addend % n)
  35. sum += addend
  36. }
  37. remainder := sum % n
  38. checkCodepoint := (n - remainder) % n
  39. return rune(a[checkCodepoint]), nil
  40. }
  41. // Validate returns true if the last character of the string s is correct, for
  42. // a string s composed of characters in the alphabet a.
  43. func (a Alphabet) Validate(s string) bool {
  44. t := s[:len(s)-1]
  45. c, err := a.Generate(t)
  46. if err != nil {
  47. return false
  48. }
  49. return rune(s[len(s)-1]) == c
  50. }
  51. // check returns an error if the given alphabet does not consist of unique characters
  52. func (a Alphabet) check() error {
  53. cm := make(map[byte]bool, len(a))
  54. for i := range a {
  55. if cm[a[i]] {
  56. return fmt.Errorf("Digit %q non-unique in alphabet %q", a[i], a)
  57. }
  58. cm[a[i]] = true
  59. }
  60. return nil
  61. }