12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- // Copyright (C) 2014 The Protocol Authors.
- package protocol
- import (
- "fmt"
- "strings"
- )
- // An alphabet is a string of N characters, representing the digits of a given
- // base N.
- type luhnAlphabet string
- var (
- luhnBase32 luhnAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
- )
- // generate returns a check digit for the string s, which should be composed
- // of characters from the Alphabet a.
- // Doesn't follow the actual Luhn algorithm
- // see https://forum.syncthing.net/t/v0-9-0-new-node-id-format/478/6 for more.
- func (a luhnAlphabet) generate(s string) (rune, error) {
- factor := 1
- sum := 0
- n := len(a)
- for i := range s {
- codepoint := strings.IndexByte(string(a), s[i])
- if codepoint == -1 {
- return 0, fmt.Errorf("digit %q not valid in alphabet %q", s[i], a)
- }
- addend := factor * codepoint
- if factor == 2 {
- factor = 1
- } else {
- factor = 2
- }
- addend = (addend / n) + (addend % n)
- sum += addend
- }
- remainder := sum % n
- checkCodepoint := (n - remainder) % n
- return rune(a[checkCodepoint]), nil
- }
- // luhnValidate returns true if the last character of the string s is correct, for
- // a string s composed of characters in the alphabet a.
- func (a luhnAlphabet) luhnValidate(s string) bool {
- t := s[:len(s)-1]
- c, err := a.generate(t)
- if err != nil {
- return false
- }
- return rune(s[len(s)-1]) == c
- }
|