luhn.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  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. factor := 1
  18. sum := 0
  19. n := len(a)
  20. for i := range s {
  21. codepoint := strings.IndexByte(string(a), s[i])
  22. if codepoint == -1 {
  23. return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
  24. }
  25. addend := factor * codepoint
  26. if factor == 2 {
  27. factor = 1
  28. } else {
  29. factor = 2
  30. }
  31. addend = (addend / n) + (addend % n)
  32. sum += addend
  33. }
  34. remainder := sum % n
  35. checkCodepoint := (n - remainder) % n
  36. return rune(a[checkCodepoint]), nil
  37. }
  38. // Validate returns true if the last character of the string s is correct, for
  39. // a string s composed of characters in the alphabet a.
  40. func (a Alphabet) Validate(s string) bool {
  41. t := s[:len(s)-1]
  42. c, err := a.Generate(t)
  43. if err != nil {
  44. return false
  45. }
  46. return rune(s[len(s)-1]) == c
  47. }
  48. // NewAlphabet converts the given string an an Alphabet, verifying that it
  49. // is correct.
  50. func NewAlphabet(s string) (Alphabet, error) {
  51. cm := make(map[byte]bool, len(s))
  52. for i := range s {
  53. if cm[s[i]] {
  54. return "", fmt.Errorf("Digit %q non-unique in alphabet %q", s[i], s)
  55. }
  56. cm[s[i]] = true
  57. }
  58. return Alphabet(s), nil
  59. }