{"record":{"id":"be2ad4bd45fd97b0","repo":"gchq/CyberChef","slug":"invalid-padding-non-zero-bits-in-padding","errorCode":null,"errorMessage":"Invalid padding: non-zero bits in padding","messagePattern":"Invalid padding: non-zero bits in padding","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Bech32.mjs","lineNumber":155,"sourceCode":"        value = (value << 5) | words[i];\n        bits += 5;\n\n        while (bits >= 8) {\n            bits -= 8;\n            result.push((value >> bits) & 255);\n        }\n    }\n\n    // Check for invalid padding per BIP-0173\n    // Condition 1: Cannot have 5+ bits remaining (would indicate incomplete byte)\n    if (bits >= 5) {\n        throw new OperationError(\"Invalid padding: too many bits remaining\");\n    }\n    // Condition 2: Remaining padding bits must all be zero\n    if (bits > 0) {\n        const paddingValue = (value << (8 - bits)) & 255;\n        if (paddingValue !== 0) {\n            throw new OperationError(\"Invalid padding: non-zero bits in padding\");\n        }\n    }\n\n    return result;\n}\n\n/**\n * Encode data to Bech32/Bech32m string\n *\n * @param {string} hrp - Human-readable part\n * @param {number[]|Uint8Array} data - Data bytes to encode\n * @param {string} encoding - \"Bech32\" or \"Bech32m\"\n * @param {boolean} segwit - If true, treat first byte as witness version (for Bitcoin SegWit)\n * @returns {string} - Encoded Bech32/Bech32m string\n */\nexport function encode(hrp, data, encoding = \"Bech32\", segwit = false) {\n    // Validate HRP\n    if (!hrp || hrp.length === 0) {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Bech32.mjs#L137-L173","documentation":"Thrown by fromWords() in src/core/lib/Bech32.mjs:155 when, after consuming all 5-bit words into bytes, between 1 and 4 residual bits remain and at least one of them is non-zero. BIP-0173 requires padding bits to be zero; a non-zero residual means the encoding is non-canonical (the same data could be represented more than one way) and is treated as invalid.","triggerScenarios":"fromWords(words) where the residual 1-4 bits encode a non-zero value — e.g. words ending in a value whose low bits are set beyond the last byte boundary. Reached internally by decode() for strings like a hand-edited Bech32 whose last data word has stray low bits, or via direct fromWords call on non-canonical input.","commonSituations":"A character in the data part was altered (corruption) producing a word whose residual bits are non-zero; a non-canonical encoder that did not zero-pad; test vectors from an implementation that ignores BIP-0173's canonical-padding rule.","solutions":["Treat this as data corruption: re-obtain the Bech32 string from its source.","If you control encoding, ensure your toWords equivalent zero-pads the final word (this library's toWords at line 119-121 already does).","Validate the checksum first; non-zero padding almost always coincides with checksum failure.","Avoid hand-editing individual characters of a Bech32 string."],"exampleFix":"// before - last word has non-zero padding bits\nconst bytes = fromWords([0x1f, 0x1f, 0x1f, 0x10]); // residual bits may be non-zero\n\n// after - use canonical encoding via toWords/encode round-trip\nconst encoded = encode('bc', originalBytes, 'Bech32');\nconst { data } = decode(encoded);","handlingStrategy":"try-catch","validationCode":"function wordsHaveZeroPadding(words) {\n  let value = 0, bits = 0;\n  for (const w of words) { value = (value << 5) | w; bits += 5; while (bits >= 8) { bits -= 8; } }\n  if (bits === 0) return true;\n  return ((value << (8 - bits)) & 255) === 0;\n}","typeGuard":"function isCanonicalBech32Words(words) {\n  return Array.isArray(words) && wordsHaveZeroPadding(words);\n}","tryCatchPattern":"try {\n  const bytes = fromWords(words);\n} catch (e) {\n  if (e instanceof OperationError && /non-zero bits in padding/.test(e.message)) {\n    // non-canonical encoding; treat as corrupt\n  }\n}","preventionTips":["Only accept Bech32 produced by a canonical encoder (this library's toWords zero-pads).","Never hand-edit individual characters of a Bech32 string.","Pair this check with checksum verification to confirm integrity."],"tags":["bech32","decoding","bip-0173","padding","canonical"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}