Skip to content

Instantly share code, notes, and snippets.

@yb66
Last active April 23, 2018 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yb66/f9784cb34440c498b715d26f54af5852 to your computer and use it in GitHub Desktop.
Save yb66/f9784cb34440c498b715d26f54af5852 to your computer and use it in GitHub Desktop.
Luhn algorithm with the broken Syncthing implementation
# Implemented because Syncthing (kind of) uses it
# @example
# @luhn = Luhn.new Base32.table
# @luhn.check_character "P56IOI7MZJNU2"
# # => "S"
class Luhn
def initialize alphabet
@alphabet = alphabet
@table_alpha = Hash[ @alphabet.split(//).zip(0 .. @alphabet.length - 1) ]
@table_code = Hash[ (0 .. @alphabet.length - 1).zip(@alphabet.split(//))]
end
attr_reader :alphabet, :table_alpha, :table_code
def n
@n ||= @alphabet.length
end
FACTOR = 2
# Starting from the right and working leftwards is easier since
# the initial "factor" will always be "2"
def check_character input, factor=FACTOR
sum = input.reverse.each_char.inject(0) do |sum,char|
addend = factor * @table_alpha[char]
# Alternate the "factor" that each "codePoint" is multiplied by
factor = (factor == 2) ? 1 : 2
# Sum the digits of the "addend" as expressed in base "n"
sum += Integer(addend / n) + (addend % n)
end
# Calculate the number that must be added to the "sum"
# to make it divisible by "n"
remainder = sum % n
checkcode = (n - remainder) % n
@table_code[checkcode]
end
# @see https://forum.syncthing.net/t/v0-9-0-new-node-id-format/478/7
# @example
# @luhn = Luhn.new Base32.table
# @luhn.check_for_syncthing "P56IOI7MZJNU2"
# # => "Y"
def check_for_syncthing input
check_character input.reverse, 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment