"use strict"; function luhnSum(fullDigits) { const digits = fullDigits.split("").map(Number).reverse(); let sum = 0; for (let i = 0; i < digits.length; i++) { let d = digits[i]; if (i % 2 === 1) { d *= 2; if (d > 9) d -= 9; } sum += d; } return sum; } function computeCheckDigit(numberWithoutCheck) { for (let c = 0; c <= 9; c++) { if (luhnSum(numberWithoutCheck + c) % 10 === 0) return c; } throw new Error("no check digit found (unreachable)"); } module.exports = { slug: "luhn-check-digit", title: "Luhn check digit", deck_category: "other", description: "Validates a number against the Luhn checksum, or computes the Luhn check digit to append to a number.", inputs: [ { name: "mode", type: "string", required: true, description: "Whether to validate a full number or compute a check digit for a number missing one.", enum: ["validate", "compute_check_digit"] }, { name: "number", type: "string", required: true, description: "Digits only. For validate: the full number including its check digit. For compute_check_digit: the number without its check digit." } ], outputs: [ { name: "result", description: "For validate: true or false. For compute_check_digit: the single check digit (0-9)." } ], steps: [ "The Luhn algorithm (used for card numbers per ISO/IEC 7812-1): starting from the rightmost digit of the full number (the check digit) and moving left, double every second digit; if doubling produces a number greater than 9, subtract 9 from it.", "Sum all the digits (doubled ones after the above adjustment, others unchanged).", "The number is valid if that sum is a multiple of 10.", "To compute a missing check digit: try each digit 0-9 appended to the given number until the resulting full number's Luhn sum is a multiple of 10; that digit is the check digit." ], constants: [], sources: [ { kind: "standard", value: "ISO/IEC 7812-1:2017, Identification cards - Identification of issuers - Part 1: Numbering system.", title: "ISO/IEC 7812-1 (Luhn checksum for card numbers)", publisher: "ISO/IEC", retrieved_utc: "2026-09-30T20:01:00Z", note: "Standard specifying the Luhn (mod 10) check algorithm for payment card numbers." } ], disclaimer: null, questionText(inputs) { if (inputs.mode === "validate") return `Does the number ${inputs.number} pass the Luhn check?`; return `What is the Luhn check digit for ${inputs.number}?`; }, run(inputs) { const { mode, number } = inputs || {}; if (mode !== "validate" && mode !== "compute_check_digit") throw new Error("mode must be validate or compute_check_digit"); if (typeof number !== "string" || !/^\d+$/.test(number)) throw new Error("number must be a string of digits only"); if (mode === "validate") { const valid = luhnSum(number) % 10 === 0; return { answer: `${valid}`, values: { result: valid } }; } const digit = computeCheckDigit(number); return { answer: `${digit}`, values: { result: digit } }; }, examples: [ { name: "worked example", inputs: { mode: "validate", number: "4111111111111111" }, expected: { answer: "true" }, check: "4111111111111111 is the widely published Visa test card number, well documented as passing the Luhn check; the algorithm confirms it is valid." }, { name: "test vector: compute check digit", inputs: { mode: "compute_check_digit", number: "7992739871" }, expected: { answer: "3" }, check: "7992739871 with check digit 3 (full number 79927398713) is the widely published worked example used to illustrate the Luhn algorithm; the computed check digit matches that published example." } ] };