Skip to content

Commit

Permalink
Merge pull request #1933 from k3ach/master
Browse files Browse the repository at this point in the history
Updated luhn checksum operation to work with different bases
  • Loading branch information
a3957273 authored Feb 16, 2025
2 parents 95c6406 + 3187ff6 commit fb8e1be
Show file tree
Hide file tree
Showing 2 changed files with 422 additions and 33 deletions.
53 changes: 36 additions & 17 deletions src/core/operations/LuhnChecksum.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* @author n1073645 [[email protected]]
* @author k3ach [[email protected]]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
Expand All @@ -20,39 +21,46 @@ class LuhnChecksum extends Operation {

this.name = "Luhn Checksum";
this.module = "Default";
this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers.";
this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
this.description = "The Luhn mod N algorithm using the english alphabet. The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2.";
this.infoURL = "https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm";
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.args = [
{
"name": "Radix",
"type": "number",
"value": 10
}
];
}

/**
* Generates the Luhn Checksum from the input.
* Generates the Luhn checksum from the input.
*
* @param {string} inputStr
* @returns {number}
*/
checksum(inputStr) {
checksum(inputStr, radix = 10) {
let even = false;
return inputStr.split("").reverse().reduce((acc, elem) => {
// Convert element to integer.
let temp = parseInt(elem, 10);
// Convert element to an integer based on the provided radix.
let temp = parseInt(elem, radix);

// If element is not an integer.
if (isNaN(temp))
throw new OperationError("Character: " + elem + " is not a digit.");
// If element is not a valid number in the given radix.
if (isNaN(temp)) {
throw new Error("Character: " + elem + " is not valid in radix " + radix + ".");
}

// If element is in an even position
if (even) {
// Double the element and add the quotient and remainder together.
temp = 2 * elem;
temp = Math.floor(temp/10) + (temp % 10);
// Double the element and sum the quotient and remainder.
temp = 2 * temp;
temp = Math.floor(temp / radix) + (temp % radix);
}

even = !even;
return acc + temp;
}, 0) % 10;
}, 0) % radix; // Use radix as the modulus base
}

/**
Expand All @@ -63,9 +71,20 @@ class LuhnChecksum extends Operation {
run(input, args) {
if (!input) return "";

const checkSum = this.checksum(input);
let checkDigit = this.checksum(input + "0");
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
const radix = args[0];

if (radix < 2 || radix > 36) {
throw new OperationError("Error: Radix argument must be between 2 and 36");
}

if (radix % 2 !== 0) {
throw new OperationError("Error: Radix argument must be divisible by 2");
}

const checkSum = this.checksum(input, radix).toString(radix);
let checkDigit = this.checksum(input + "0", radix);
checkDigit = checkDigit === 0 ? 0 : (radix - checkDigit);
checkDigit = checkDigit.toString(radix);

return `Checksum: ${checkSum}
Checkdigit: ${checkDigit}
Expand Down
Loading

0 comments on commit fb8e1be

Please sign in to comment.