luhn.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // Copyright (C) 2014 The Protocol Authors.
  2. package protocol
  3. import (
  4. "fmt"
  5. "strings"
  6. )
  7. // An alphabet is a string of N characters, representing the digits of a given
  8. // base N.
  9. type luhnAlphabet string
  10. var (
  11. luhnBase32 luhnAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
  12. )
  13. // generate returns a check digit for the string s, which should be composed
  14. // of characters from the Alphabet a.
  15. func (a luhnAlphabet) generate(s string) (rune, error) {
  16. factor := 1
  17. sum := 0
  18. n := len(a)
  19. for i := range s {
  20. codepoint := strings.IndexByte(string(a), s[i])
  21. if codepoint == -1 {
  22. return 0, fmt.Errorf("Digit %q not valid in alphabet %q", s[i], a)
  23. }
  24. addend := factor * codepoint
  25. if factor == 2 {
  26. factor = 1
  27. } else {
  28. factor = 2
  29. }
  30. addend = (addend / n) + (addend % n)
  31. sum += addend
  32. }
  33. remainder := sum % n
  34. checkCodepoint := (n - remainder) % n
  35. return rune(a[checkCodepoint]), nil
  36. }
  37. // luhnValidate returns true if the last character of the string s is correct, for
  38. // a string s composed of characters in the alphabet a.
  39. func (a luhnAlphabet) luhnValidate(s string) bool {
  40. t := s[:len(s)-1]
  41. c, err := a.generate(t)
  42. if err != nil {
  43. return false
  44. }
  45. return rune(s[len(s)-1]) == c
  46. }