Private key → P2WPKH address (bech32)
The native SegWit bc1q… address, built one layer at a time: compressed public key → hash160 (the 20-byte witness program) → 5-bit bech32 data words → 6-character checksum → address. Every layer is shown separately so you can verify the chain by hand.
Enter a value above and press Convert. Not sure what to type? Press “Use example” to load the sample from the placeholder.
What this page computes
You give it one 256-bit private key. It gives you back the native SegWit address for that
key — the string that starts with bc1q. Rather than printing only the final answer, the page
keeps every layer of the derivation separate, so each step can be checked against the next one by hand:
1. What SegWit actually changed, and why this address exists
"SegWit" (segregated witness, BIP141/143/173) activated on 24 August 2017 and is usually described as one change. It was really four, and this address type is the visible surface of all of them.
Transaction malleability. Before SegWit an ECDSA signature travelled inside the
scriptSig of the input it authorised. A signature is a DER-encoded pair of integers, and several
different byte strings decode to the same mathematical signature — so a third party could re-encode a
signature, or wrap it in extra push operations, without invalidating the transaction. That mutated the
transaction id: the money still moved, but any second-layer protocol that had committed to the old txid
(unconfirmed child spends, payment channels, Lightning's ancestors) broke. The fix was structural: sign the
input, then move the signature out of the transaction proper into a parallel witness
structure. The txid is now computed from the serialization without witness data, so it can no
longer be changed by touching a signature; a separate wtxid covers the witness.
Block weight instead of block size. A block is no longer measured in bytes but in weight units (WU). Non-witness bytes cost 4 WU each; witness bytes cost 1 WU each. The cap is 4,000,000 WU, which still enforces the old 1 MB limit on the non-witness part of a block while leaving room for witness data on top.
The witness discount. Because witness bytes are 4× cheaper in weight terms, moving data into the witness cuts the effective fee. Spending a P2WPKH output is roughly a third lighter than spending the equivalent P2PKH output — the table below is the arithmetic for one input, computed from the exact byte counts rather than quoted from folklore.
Script versioning. The "witness program" is a byte string plus a version number, and the consensus rules for it are chosen by that version. Version 0 is P2WPKH/P2WSH; version 1 is Taproot. That upgrade path is the reason SegWit mattered for the future as much as for the present.
2. Where the fee saving comes from
A P2WPKH input carries an empty scriptSig (one byte, the length 00) and puts the
signature and the public key in the witness instead. The numbers below assume one input, a 72-byte DER
signature, a 33-byte compressed public key, and a 64-byte Schnorr signature for Taproot; vsize
is weight ÷ 4 (rounded up, as nodes do).
| Input type | Non-witness bytes | Witness bytes | Weight (WU) | vsize |
|---|---|---|---|---|
| P2PKH (compressed key) | 148 | none | 592 | 148 vB |
| P2SH-P2WPKH (nested) | 64 | 108 | 364 | 91 vB |
| P2WPKH (this page) | 41 | 108 | 272 | 68 vB |
| P2TR key path | 41 | 66 | 230 | 57.5 vB |
That is 54.1% less weight than P2PKH for the same single-key spend, before any output changes. On a busy
chain, that difference is the whole reason wallets pushed users onto bc1q addresses.
3. The witness program: OP_0 <20-byte push>
What actually lives on the blockchain is a 22-byte output script. The address is only a human-friendly encoding of its middle 20 bytes.
| Offset | Bytes | Content | Meaning |
|---|---|---|---|
| 0 | 1 | 00 | OP_0 — pushes an empty array, which doubles as witness version 0 |
| 1 | 1 | 14 | push the next 20 bytes (0x14 = 20) |
| 2 | 20 | hash160 | the witness program: RIPEMD160(SHA256(compressed pubkey)) |
to spend it, the witness stack supplies exactly two items: a signature and the full compressed public key. The script interpreter hashes the key, compares the result with the 20 bytes in the program, and checks the signature against that key. Nothing in the program commits to a signature encoding, and nothing is executed from the script itself — that is what removes the malleability surface.
BIP143 requires v0 witness spends to use compressed public keys. A 20-byte program computed from the
65-byte uncompressed serialization produces a perfectly well-formed-looking bc1q… string that
no standard wallet can spend. If you ever see two different bc1q addresses for one key, that is
usually the mistake: one was built from the compressed key, the other from the uncompressed one.
4. bech32, byte by byte
bech32 (BIP173) is a base-32 encoding with a checksum, designed for QR codes and for reading aloud. An address has exactly four parts:
| Part | Example (demo address) | Rule |
|---|---|---|
Human-readable part (hrp) | bc | bc = mainnet, tb = testnet; 1–83 characters, lower case |
| Separator | 1 | the last 1 in the string; 1 is not in the data charset, so it can never be ambiguous |
| Data part | q + 32 characters | witness version, then the program as 5-bit words |
| Checksum | naerk6 | the last 6 characters; BCH code over GF(32), includes the hrp |
The 32 characters of the data payload are not the 20 program bytes written out. base32 has an alphabet of 32 symbols, i.e. 5 bits per character, while the program is a sequence of 8-bit bytes. bech32 therefore re-groups the bit stream: it takes the 160 bits of the program and emits 160 ÷ 5 = 32 groups of 5 bits. No padding is needed here because 160 divides by 5 exactly; for a 32-byte program (Taproot) the division leaves a remainder, and the final word is padded with zero bits on the right.
Each 5-bit group indexes this alphabet (the same one Bitcoin uses everywhere in bech32):
| Value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Character | q | p | z | r | y | 9 | x | 8 | g | f | 2 | t | v | d | w | 0 |
| Value | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
| Character | s | 3 | j | n | 5 | 4 | k | h | c | e | 6 | m | u | a | 7 | l |
Note which characters are absent: 1, b, i and o.
They are missing because they are the characters people confuse when copying by hand or reading a screen
(1/l, 0/o, b/6). The alphabet was
chosen for human transcription, not for compactness.
The checksum is a BCH code computed by a 30-bit polynomial accumulator ("polymod") fed with
hrpExpand(hrp) ‖ data ‖ 000000, XORed with the constant 1 for bech32, and split into
6 five-bit characters. Its published error-detection properties are the reason bech32 is trusted for money:
it detects any error affecting at most four characters, and has a failure probability below
1 in 109 for larger errors. Because the hrp is part of the input, changing
bc to tb also invalidates the checksum — this page verifies both claims against the
demo address by mutating it and re-decoding.
Case. bech32 strings must be either entirely lower case or entirely upper case. Mixed case is a hard failure, not a normalisation opportunity, because the two cases would otherwise encode the same program in two different strings. The canonical form on-chain and in wallets is lower case; upper case exists so that a QR code or a printed label can be transcribed without ambiguity.
5. Worked example — the real demo key
Everything below is what this page computes for the sample key, and every value in the results panel is recomputed live from your input.
| Layer | Value |
|---|---|
Private key k | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
| Compressed public key (33 B) | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| SHA-256 of that key | 067eb00a0b9864633b020eef374476142daba913c5481ad6a4741cc8ab702617 |
| hash160 = the witness program | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| Output script | 001421f57b6debcfc5b67182dfb4af1641f0a8189012 (22 bytes) |
Data part (q = version 0, then 32 words) | qy86hkm0telzmvuvzm76279jp7z5p3yqj |
| Program as 5-bit values | 4 7 26 23 22 27 15 11 25 31 2 27 12 28 12 2 27 30 26 10 30 5 18 1 30 2 20 1 17 4 0 18 |
| Checksum characters | naerk6 (values 19 29 25 3 22 26) |
| P2WPKH address (42 characters) | bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6 |
| Same key on testnet | tb1qy86hkm0telzmvuvzm76279jp7z5p3yqjemzsdf |
Notice the testnet address: the data part is character-for-character identical, and only the
hrp and therefore the checksum differ (naerk6 vs emzsdf).
6. Witness v0 requires bech32 — never bech32m
There are two checksum variants in use. bech32 (BIP173, constant 1) is for witness version 0;
bech32m (BIP350, constant 0x2bc830a3 = 734539939 decimal) is for witness version 1 and above.
The pairing is mandatory, and a decoder that does not enforce it will silently accept addresses that other
nodes reject. This page's decoder enforces it, and you can watch it fail: re-encoding the demo address with
the bech32m constant gives bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjxpf0nc, which decodes to the error
"Witness v0 must use bech32, not bech32m".
BIP350 introduced bech32m because the original constant 1 has an insertion weakness, stated
in BIP350 itself: whenever the final character of a bech32 string is p, inserting or
deleting any number of q characters immediately before it does not invalidate the
checksum — the checksum characters simply shift, so one checksum can validate strings with data
parts of different lengths. This is easy to check, and the server behind this page did check it: the valid
address bc1qgey9e3xtk8fpdsgchch25saytdp6nlhdt9gm0p still satisfies the checksum after inserting
one, two or three q characters before that final p
(…gm0qp, …gm0qqp, …gm0qqqp). Across 78,624 single-character
insertions attempted on bc-prefixed strings, every insertion that kept the checksum valid had
exactly that shape, and every one of them was a bech32 string — not a single bech32m string accepted
an insertion.
Witness version 0 was not affected in practice: v0 programs are restricted to exactly 20 or 32 bytes, so
a decoder that also enforces the structural rules (padding, program length) rejects the mutated string — this
page's decoder reports "Invalid padding". The demo address itself ends in 6, not
p, so the trick does not even apply to it. Newer witness versions have no such escape hatch,
which is why v1+ mandates bech32m. Never "upgrade" a bc1q address to the other checksum variant
by hand — the two are not interchangeable, and sending to a hand-mutated address burns the coins.
7. P2WPKH next to its neighbours
| P2PKH | P2SH-P2WPKH | P2WPKH (this page) | P2TR | |
|---|---|---|---|---|
| Address prefix | 1… | 3… | bc1q… | bc1p… |
| Encoding | Base58Check, version 0x00 | Base58Check, version 0x05 | bech32 (BIP173) | bech32m (BIP350) |
| Committed value | hash160(compressed key) | hash160(0014‖hash160(key)) | hash160(key) — the witness program | x-only tweaked output key (32 B) |
| Output script | 76a914…88ac (25 B) | a914…87 (23 B) | 0014… (22 B) | 5120… (34 B) |
| Weight per input | 592 WU | 364 WU | 272 WU | 230 WU |
| Signature inside | ECDSA in scriptSig | ECDSA in witness | ECDSA in witness | Schnorr (BIP340) in witness |
| Introduced | 2009, original client | BIP49, 2017 (wrapped for old wallets) | BIP141/173, activated 24 Aug 2017 | BIP341/350, activated 14 Nov 2021 |
| Where you meet it | Old wallets, exchanges, paper wallets | Wallets that had to stay compatible with pre-SegWit senders | The default for new single-key wallets | Newest wallets; the only form with script-path privacy |
8. Where this fits in the chain
- Before it: private key → compressed public key, then hash160. The compressed key is not optional here.
- Sibling: P2PKH (same hash160, Base58Check instead of bech32) and P2SH-P2WPKH (the same program wrapped inside a P2SH address).
- After it: P2TR / Taproot uses the same key but a different program size, a different checksum variant and a key tweak.
- To take an address apart again: the bech32 decoder.
9. Security notes
- The address commits to a hash of the public key, not to the key itself. The key stays hidden until the output is spent — after which it is public forever, together with the address it funded.
- Reusing one address for many payments links them publicly and destroys the privacy of everyone who ever paid you. Derive a fresh address per payment (that is what HD wallets are for).
- The checksum protects against typos, not against a deliberately substituted address. Compare the first and last few characters on the sending device, and prefer QR codes over retyping.
- An address is not a secret, but it is also not a proof of ownership: whoever holds
kcan spend. Never paste a private key into a web page you do not fully trust — this page computes locally on the host you are talking to, and it never sends your key anywhere else.
10. Common mistakes
- Hashing the uncompressed key. Produces a different 20-byte program and a different address, unspendable under BIP143's compressed-key rule.
- Using bech32m for v0. Every modern wallet rejects it; only the length-extension weakness of the original checksum and 6 characters of it differ.
- Treating the separator as the first
1. Parsers must split at the last1. The data charset has no1, which makes this unambiguous. - Lower-casing a QR payload by hand. All-upper is fine, mixed case is not; a converter that flips only some characters produces a string that no verifier will accept.
- Assuming "SegWit" means "the address starts with bc1". P2SH-P2WPKH is also SegWit and
still starts with
3.
11. Quick reference
| Item | Value |
|---|---|
| Address type | P2WPKH, witness version 0, native SegWit |
hrp | bc mainnet, tb testnet |
| Witness program | 20 bytes = hash160(compressed public key) |
| Data characters | 1 version character + 32 program characters (160 bits ÷ 5, no padding) |
| Checksum | 6 characters, BCH code with constant 1; detects any error in up to 4 characters |
| Total length | 42 characters on mainnet, all lower case |
| Output script | OP_0 0x14 ‖ 20-byte program (22 bytes) |
| Case rule | all lower case or all upper case — never mixed |