Skip to content

Instantly share code, notes, and snippets.

@Evanion
Created August 30, 2021 11:07
Show Gist options
  • Save Evanion/2d2979952083b0880e8a59c0ac37ceb5 to your computer and use it in GitHub Desktop.
Save Evanion/2d2979952083b0880e8a59c0ac37ceb5 to your computer and use it in GitHub Desktop.
Luhn mod N algorithm
const rawToken = "v83dtres";
const checksum = Luhn.generate(rawToken);
const testToken = `${rawToken}${checksum}`;
const isValid = Luhn.validate(testToken);
// Luhn mod N algorithm: https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm
export class Luhn {
public static dictionary =
"0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
public static generate(input: string) {
const n = Luhn.dictionary.length;
const sum = input
.split("")
.filter(Luhn.filterValid)
.reverse()
.reduce(Luhn.reduce(2), 0);
let remainder = sum % n;
let checkCodePoint = (n - remainder) % n;
return Luhn.dict2char(checkCodePoint);
}
public static validate(input: string) {
const sum = input
.split("")
.filter(Luhn.filterValid)
.reverse()
.reduce(Luhn.reduce(1), 0);
return !(sum % Luhn.dictionary.length);
}
private static char2dict = (character: string) =>
Luhn.dictionary.indexOf(character);
private static dict2char = (codePoint: number) =>
Luhn.dictionary.charAt(codePoint);
private static filterValid = (str: string) =>
str.indexOf(Luhn.dictionary) === -1;
private static reduce =
(factor: number = 1) =>
(sum: number, current: string) => {
let codePoint = Luhn.char2dict(current);
let addend = factor * codePoint;
factor = factor == 2 ? 1 : 2;
addend =
Math.floor(addend / Luhn.dictionary.length) +
(addend % Luhn.dictionary.length);
return (sum += addend);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment