{"record":{"id":"dbff38228d2cc83f","repo":"gchq/CyberChef","slug":"modulus-must-be-greater-than-zero-dbff38","errorCode":null,"errorMessage":"Modulus must be greater than zero","messagePattern":"Modulus must be greater than zero","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/ModularInverse.mjs","lineNumber":87,"sourceCode":"            // Case 2: value missing - take from input\n            a = inputVal;\n            m = mParam;\n            if (!a) throw new OperationError(\"Value (a) must be defined\");\n        } else if (aParam && !mParam) {\n            // Case 3: modulus missing - take from input\n            a = aParam;\n            m = inputVal;\n            if (!m) throw new OperationError(\"Modulus (m) must be defined\");\n        } else if (!aParam && !mParam) {\n            // Case 4: value and modulus both missing\n            throw new OperationError(\"Value (a) and Modulus (m) must be defined\");\n        }\n\n        const aBI = parseBigInt(a, \"Value (a)\");\n        const mBI = parseBigInt(m, \"Modulus (m)\");\n\n        if (mBI <= 0n) {\n            throw new OperationError(\"Modulus must be greater than zero\");\n        }\n\n        const aNorm = ((aBI % mBI) + mBI) % mBI;\n        const [g, x] = egcd(aNorm, mBI);\n\n        if (g !== 1n && g !== -1n) {\n            throw new OperationError(\"Inverse does not exist because gcd(a, m) ≠ 1\");\n        }\n\n        let inv = x;\n        if (g === -1n) inv = -inv;\n\n        inv = ((inv % mBI) + mBI) % mBI;\n\n\n        return inv.toString();\n    }\n}","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/ModularInverse.mjs#L69-L105","documentation":"Thrown by Modular Inverse after parsing: the modulus parses to a BigInt that is <= 0n (zero or negative). The multiplicative inverse is only defined for a positive modulus, so any non-positive value is rejected. Unlike Modular Exponentiation, this check also catches negative values because parseBigInt accepts signed decimals.","triggerScenarios":"run(input, args) where the resolved modulus string is '0', '-1', '-7', '0x0', or any decimal/hex that parses to a non-positive BigInt. Reached after the emptiness checks pass.","commonSituations":"Negative modulus passed from an upstream operation that subtracts; modulus defaulting to 0 in a generated recipe; sign error in computed parameters; copy-paste of a negative coordinate into the modulus field.","solutions":["Set the modulus to a positive integer greater than zero.","If the modulus is computed dynamically, abs() it or clamp to >=1 before passing.","Audit upstream operations that feed into Modulus to ensure they never emit 0 or negatives."],"exampleFix":"// before\nchef.bake(\"Modular Inverse\", [\"3\", \"-7\"], \"\");  // mBI <= 0n\n// after\nchef.bake(\"Modular Inverse\", [\"3\", \"7\"], \"\");","handlingStrategy":"validation","validationCode":"function validInverseModulus(mStr) {\n  const v = (mStr ?? \"\").trim();\n  if (!/^(0x[0-9a-f]+|[+-]?[0-9]+)$/i.test(v)) return false;\n  return BigInt(v) > 0n;\n}","typeGuard":"const isPositiveModulusStr = (s) => {\n  const v = (s ?? \"\").trim();\n  if (!/^(0x[0-9a-f]+|[+-]?[0-9]+)$/i.test(v)) return false;\n  try { return BigInt(v) > 0n; } catch { return false; }\n};","tryCatchPattern":"try { chef.bake(\"Modular Inverse\", [a, m]); }\ncatch (e) { if (e.message === \"Modulus must be greater than zero\") fixModulus(); else throw e; }","preventionTips":["Reject negative or zero modulus upstream.","Use abs() then ensure >= 1 when modulus is computed.","Prefer prime moduli to avoid sign/zero pitfalls."],"tags":["crypto","modular-arithmetic","argument-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}