{"record":{"id":"8cc05f29dd2dd69a","repo":"gchq/CyberChef","slug":"the-values-of-a-and-b-can-only-be-integers-8cc05f","errorCode":null,"errorMessage":"The values of a and b can only be integers.","messagePattern":"The values of a and b can only be integers\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/AffineCipherDecode.mjs","lineNumber":56,"sourceCode":"            }\n        ];\n    }\n\n    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {string}\n     *\n     * @throws {OperationError} if a or b values are invalid\n     */\n    run(input, args) {\n        const alphabet = \"abcdefghijklmnopqrstuvwxyz\",\n            [a, b] = args,\n            aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a\n        let output = \"\";\n\n        if (!/^\\+?(0|[1-9]\\d*)$/.test(a) || !/^\\+?(0|[1-9]\\d*)$/.test(b)) {\n            throw new OperationError(\"The values of a and b can only be integers.\");\n        }\n\n        if (Utils.gcd(a, 26) !== 1) {\n            throw new OperationError(\"The value of `a` must be coprime to 26.\");\n        }\n\n        for (let i = 0; i < input.length; i++) {\n            if (alphabet.indexOf(input[i]) >= 0) {\n                // Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)\n                output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];\n            } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {\n                // Same as above, accounting for uppercase\n                output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();\n            } else {\n                // Non-alphabetic characters\n                output += input[i];\n            }\n        }","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/AffineCipherDecode.mjs#L38-L74","documentation":"Thrown by AffineCipherDecode.run when either argument a (multiplicative slope) or b (additive shift) is not a non-negative integer. The regex /^\\+?(0|[1-9]\\d*)$/ coerces each value to a string and rejects decimals, negative numbers, empty strings, and any non-numeric input before the modular arithmetic runs. Both args are declared as type 'number' in the operation's recipe, so this guards against a number field that was filled with a fractional or out-of-range value.","triggerScenarios":"Passing a fractional value (e.g. a=1.5 or b=2.7), a negative number (e.g. b=-3), NaN, or an empty/non-numeric string for a or b in the recipe arguments. The regex coerces the number to a string, so 1.5 becomes \"1.5\" which fails to match.","commonSituations":"User types a decimal into the a or b number field; parameters copied from another tool that used real-valued coefficients; a recipe imported from JSON where the value was serialized as a float; programmatic ChefNode/Recipe construction passing a float.","solutions":["Set both a and b to non-negative integers (e.g. a=5, b=8).","If you need a negative shift, keep b non-negative and use the Affine Cipher Encode direction or transform the math instead of passing a negative b.","When building the recipe in code, validate with Number.isInteger(v) && v >= 0 before passing the args array."],"exampleFix":"// before\nrecipe.setArgs([1.5, 8]);\nconst out = chef.affineCipherDecode(\"HELLO\", [1.5, 8]);\n\n// after\nrecipe.setArgs([5, 8]); // a=5 is coprime to 26, b=8 shift\nconst out = chef.affineCipherDecode(\"HELLO\", [5, 8]);","handlingStrategy":"validation","validationCode":"function assertAffineIntegers(a, b) {\n  const re = /^\\+?(0|[1-9]\\d*)$/;\n  if (!re.test(String(a)) || !re.test(String(b))) {\n    throw new Error(`a and b must be non-negative integers; got a=${a}, b=${b}`);\n  }\n}\n// call before recipe.run()\nassertAffineIntegers(a, b);","typeGuard":"function isNonNegIntArg(v) {\n  return (typeof v === \"number\" && Number.isInteger(v) && v >= 0)\n      || (typeof v === \"string\" && /^\\+?(0|[1-9]\\d*)$/.test(v));\n}","tryCatchPattern":null,"preventionTips":["Type the a and b fields as integers in the UI number inputs.","In code, pass JS numbers that satisfy Number.isInteger(v) && v >= 0.","Sanitize imported recipe JSON so a/b are integers before execution."],"tags":["cipher","input-validation","affine-cipher","argument-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}