BitcoinMachine
TECHNICAL_DOC // KEYS / BECH32
BECH32
Bech32 (BIP 173) is the encoding format for SegWit addresses. It uses a 32-character lowercase alphabet and a powerful BCH polynomial checksum that detects any error of up to 4 characters. Bech32m (BIP 350) is a small variant used for Taproot, designed to fix a length-extension weakness when used with witness-version-0-1/">witness version 1+.
ANATOMY OF A SEGWIT ADDRESS
bc 1 q w508d6qejxtdg4y5r3zarvary0c5xw7k v8f3t4 └┬┘ │ └─────────────┬─────────────┘ └──┬─┘ HRP │ data part checksum │ (witness version (6 chars) separator + witness program) "1" Components: HRP : human-readable prefix "bc"=mainnet, "tb"=testnet, "bcrt"=regtest separator : the character "1" (cannot appear in HRP) data : witness version (1 char) + program (5-bit groups) checksum : 6 characters (30-bit BCH code) Alphabet (32 chars): qpzry9x8gf2tvdw0s3jn54khce6mua7l Excluded: 1, b, i, o (visually ambiguous) All lowercase. Mixed case is invalid.
Encoding Procedure
PROCESS
Bech32 encodes the witness program as 5-bit groups, then appends a 6-character BCH checksum computed over HRP + data.
Step 1: Convert witness program from 8-bit to 5-bit groups 20-byte hash → 32 × 5-bit values (with padding) Step 2: Prepend witness version data = [witness_version] + [5-bit groups] Step 3: Compute BCH checksum values = expand_hrp(hrp) + data + [0,0,0,0,0,0] polymod = bech32_polymod(values) XOR const const = 1 for Bech32 (witness v0) const = 0x2bc830a3 for Bech32m (witness v1+) checksum = 6 × 5-bit values from polymod Step 4: Encode each 5-bit value via alphabet output = hrp + "1" + base32_chars(data || checksum) Result error-detection power: Any 4-character error: detected with certainty Any random error: ~10⁻⁹ undetected probability
Bech32 vs Bech32m
VARIANTS
Bech32m (BIP 350) was introduced to fix an insertion-error weakness in original Bech32 when used at lengths matching SegWit v1+ addresses. Witness version determines which variant to use.
Witness version 0 → Bech32 (constant: 1) P2WPKH: bc1q... (42 chars) P2WSH: bc1q... (62 chars) Witness version 1+ → Bech32m (constant: 0x2bc830a3) P2TR: bc1p... (62 chars) Detecting which to use: Decoder reads witness version (first data char): 'q' → version 0 → expect Bech32 checksum 'p' → version 1 → expect Bech32m checksum Why two variants: Bech32 has a vulnerability where appending or removing the character "p" at the end can yield another valid Bech32 string with the same checksum. Bech32m's different constant eliminates this. The two are mutually incompatible by design — preventing old wallets from sending to misinterpreted v1 outputs.
Address Examples
REAL ADDRESSES
All four SegWit address types use Bech32 family encoding. Witness version distinguishes them.
P2WPKH (Bech32, v0): bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 ↑ "q" = witness version 0 20-byte program (HASH160 of pubkey) P2WSH (Bech32, v0): bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3 ↑ "q" = witness version 0 32-byte program (SHA256 of script) P2TR (Bech32m, v1): bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297 ↑ "p" = witness version 1 32-byte program (x-only output key)
TERMINOLOGY_INDEX
HRP
Human Readable Part. "bc" mainnet, "tb" testnet/signet, "bcrt" regtest. Always lowercase.
Separator
The character "1" between HRP and data. Excluded from the 32-char alphabet to avoid ambiguity.
BCH Code
Bose-Chaudhuri-Hocquenghem error-correcting code. 30-bit checksum guarantees detection of 4 errors.
Bech32m
BIP 350 variant for witness version 1+. Different constant prevents insertion-error confusion.
Witness Version
First 5-bit value in the data part. 0 → SegWit v0, 1 → Taproot. Must match Bech32/Bech32m variant.
ENCODING / SEGWIT
Bech32 & Bech32m
SegWit addresses use a fundamentally different encoding: Bech32 (BIP 173). It replaces Base58Check's mixed-case alphabet with a purely lowercase 32-character charset, adds a human-readable part (bc for mainnet), and uses a BCH polynomial checksum that detects up to 4 substitution errors and all burst errors under 6 characters. Bech32m (BIP 350) fixes a length-extension weakness for Taproot (witness version ≥ 1).
ADDRESS DISSECTOR — HOVER EACH PARTclick a type to decode
bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8ihpd
HRP — human-readable part (bc/tb)
SEPseparator (always "1")
VER — witness version (5-bit)
DATA — program bytes as 5-bit groups
CHK — 6-char BCH checksum
The charset is qpzry9x8gf2tvdw0s3jn54khce6mua7l — 32 characters, all lowercase, chosen to minimise OCR errors and confusion between similar-looking characters. The character at index i encodes the 5-bit value i.
CHARSET VISUALIZER — INDEX → CHARACTERvalue 0–31
Why lowercase only? QR codes use uppercase alphanumeric mode which is smaller — a full uppercase Bech32 string in a QR code takes ~30% less space. Wallets typically display uppercase but the checksum is case-insensitive (the case is normalised before validation).
Encoding takes the 20-byte (P2WPKH) or 32-byte (P2WSH/P2TR) witness program, converts it from 8-bit groups to 5-bit groups (convertbits), prepends the witness version, computes the BCH checksum, and concatenates HRP + "1" + version + data + checksum.
BECH32 ENCODERhex program → address
v0 P2WPKH (20B)
v0 P2WSH (32B)
v1 P2TR / Taproot (32B)
BECH32 DECODERpaste any bc1... address
Bech32's BCH checksum is strictly stronger than Base58Check's truncated SHA256d. It can guarantee detection of up to 4 substitution errors and all burst errors ≤5 characters long. Click any character to substitute it — the BCH validator will reject it instantly.
BCH CHECKSUM DEMO — CLICK A CHARACTERany substitution fails
✓ CHECKSUM VALID
Bech32 has a subtle flaw: if you insert or delete a q immediately before the final p in the checksum, the checksum remains valid. This means Bech32 cannot detect length-extension for witness programs of lengths other than 20 or 32 bytes — dangerous for future witness versions. BIP 350 introduced Bech32m which changes the constant in the BCH polynomial from 1 to 0x2bc830a3, closing this gap.
BECH32 vs BECH32m COMPARISON
PROPERTYBECH32 (BIP 173)BECH32m (BIP 350)
BCH CONSTANT10x2bc830a3
WITNESS VERSIONv0 only (P2WPKH, P2WSH)v1+ (Taproot, future)
LENGTH EXTENSIONVulnerable — q-before-p trickFixed
CHARSETIdentical: qpzry9x8gf2tvdw0s3jn54khce6mua7l
INTRODUCED2017 (BIP 173)2021 (BIP 350)
ADDRESS EXAMPLEbc1q... (v0)bc1p... (v1/Taproot)
Taproot addresses start with bc1p. The "p" comes from witness version 1 being encoded as the value 1, which maps to 'p' in the charset. If you see a wallet generating bc1q for Taproot, it's using the wrong encoding variant.