{"record":{"id":"5ab8228ed2162446","repo":"gchq/CyberChef","slug":"invalid-witness-program-length-for-v0-witnesspr","errorCode":null,"errorMessage":"Invalid witness program length for v0: ${witnessProgram.length}. Must be 20 or 32 bytes.","messagePattern":"Invalid witness program length for v0: (.+?)\\. Must be 20 or 32 bytes\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Bech32.mjs","lineNumber":202,"sourceCode":"\n    // Convert HRP to lowercase\n    const hrpLower = hrp.toLowerCase();\n\n    let words;\n    if (segwit && data.length >= 2) {\n        // SegWit encoding: first byte is witness version (0-16), rest is witness program\n        const witnessVersion = data[0];\n        if (witnessVersion > 16) {\n            throw new OperationError(`Invalid witness version: ${witnessVersion}. Must be 0-16.`);\n        }\n        const witnessProgram = Array.prototype.slice.call(data, 1);\n\n        // Validate witness program length per BIP-0141\n        if (witnessProgram.length < 2 || witnessProgram.length > 40) {\n            throw new OperationError(`Invalid witness program length: ${witnessProgram.length}. Must be 2-40 bytes.`);\n        }\n        if (witnessVersion === 0 && witnessProgram.length !== 20 && witnessProgram.length !== 32) {\n            throw new OperationError(`Invalid witness program length for v0: ${witnessProgram.length}. Must be 20 or 32 bytes.`);\n        }\n\n        // Witness version is kept as single 5-bit value, program is converted\n        words = [witnessVersion].concat(toWords(witnessProgram));\n    } else {\n        // Generic encoding: convert all bytes to 5-bit words\n        words = toWords(data);\n    }\n\n    // Create checksum\n    const checksum = createChecksum(hrpLower, words, encoding);\n\n    // Build result string\n    let result = hrpLower + \"1\";\n    for (const w of words.concat(checksum)) {\n        result += CHARSET[w];\n    }\n","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Bech32.mjs#L184-L220","documentation":"Thrown by encode() in src/core/lib/Bech32.mjs:202 in SegWit mode when witnessVersion is 0 and the program length is neither 20 nor 32 bytes. BIP-0173 fixes v0 programs to exactly 20 bytes (P2WPKH, HASH160) or 32 bytes (P2WSH, SHA256); any other length for v0 is invalid and consensus-illegal, so the library refuses to produce an address that no node would accept.","triggerScenarios":"encode('bc', [0, ...15bytes], 'Bech32', true), encode('bc', [0, ...21bytes], 'Bech32', true), encode('bc', [0, ...33bytes], 'Bech32', true). Triggered after the general 2-40 length check passes but the v0-specific check fails.","commonSituations":"Using a v0 program with the wrong hash length (e.g. SHA256 of a script for what was meant to be P2WPKH); truncating a 20-byte hash to 19; appending a checksum or version byte to the program; mismatch between intended address type (PKH vs SH) and hash function.","solutions":["For P2WPKH (v0): use HASH160 (ripemd160(sha256(pubkey))) -> exactly 20 bytes.","For P2WSH (v0): use SHA256 of the script -> exactly 32 bytes.","If your program is a different length, use witness version 1+ (Taproot etc.) where 2-40 bytes are allowed.","Re-derive the hash with the correct algorithm and verify the byte count before encoding."],"exampleFix":"// before - v0 program is 21 bytes (invalid)\nencode('bc', [0, ...hashWithExtraByte], 'Bech32', true);\n\n// after - 20-byte HASH160 for P2WPKH\nencode('bc', [0, ...ripemd160(sha256(pubkey))], 'Bech32', true);","handlingStrategy":"validation","validationCode":"function validateV0Program(program) {\n  if (program.length !== 20 && program.length !== 32) {\n    throw new RangeError(`v0 program must be 20 or 32 bytes, got ${program.length}`);\n  }\n  return program;\n}","typeGuard":"function isV0ProgramLength(bytes) {\n  return Array.isArray(bytes) && (bytes.length === 20 || bytes.length === 32);\n}","tryCatchPattern":"try {\n  encode('bc', [0, ...program], 'Bech32', true);\n} catch (e) {\n  if (e instanceof OperationError && /witness program length for v0/.test(e.message)) {\n    // wrong hash function used; re-hash with HASH160 or SHA256\n  }\n}","preventionTips":["P2WPKH: HASH160 (20 bytes). P2WSH: SHA256 (32 bytes). Never mix them.","If the program is not 20 or 32 bytes, use witness version >= 1.","Verify hash byte length in a unit test before integrating."],"tags":["bech32","segwit","bitcoin","bip-0173","consensus","input-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}