Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated luhn checksum operation to work with different bases #1933

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 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,11 +21,17 @@ 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
}
];
}

/**
Expand All @@ -33,26 +40,27 @@ class LuhnChecksum extends Operation {
* @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
Loading