The BIP173 specification defines how to create Bech32 Segwit native addresses.

In the examples section a public key is given: 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798.

Based on that key it is somewhat easy to generate a P2WPKH address, one hashes the key with SHA256, then with RIPEMD160 and use the hex decoded result as the witness program (first two commands are simple CLI and the last is from the Dart bech32 library):

$ echo 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 | xxd -r -p | openssl sha256
(stdin)= 0f715baf5d4c2ed329785cef29e562f73488c8a2bb9dbc5700b361d54b9b0554                                                                                                                                                                                                                                      

$ echo 0f715baf5d4c2ed329785cef29e562f73488c8a2bb9dbc5700b361d54b9b0554 | xxd -r -p | openssl ripemd160                                                                                                                                                         
(stdin)= 751e76e8199196d454941c45d1b3a323f1433bd

Segwit('bc', 0, HEX.decode("751e76e8199196d454941c45d1b3a323f1433bd"))
// bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3

Generating a P2WSH involves the script key OP_CHECKSIG followed by once SHA256 hashing. I'm at a loss how to construct said script. The opcode OP_CHECKSIG is encoded as 0xac. But appending that to the key seems silly (and doesn't work). Besides the CHECKSIG opcode requires two parameters. What do I hash?


When you push items on the stack you must use an opcode to state how long the item you are pushing is. In this case you want to push 33 bytes so OP_PUSH33

Your script would be:

OP_PUSH33 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 OP_CHECKSIG



Then your witness program becomes witprog = sha256(script) or 1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262

Then you bech32 encode and you get bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3

Besides the CHECKSIG opcode requires two parameters.

The other parameter will be the signature and it will be provided by the person spending the coins as part of their scriptSig. Your scriptPubkey is only the second half of the script, the first half comes from the input.


First of all, what are you trying to do? Why do you need a P2WSH address?

A P2WSH address (and P2SH addresses earlier) send coins to a script, which requires satisfying that script to decode. A script of the form <key> CHECKSIG is wasteful - you should be using P2WPKH instead. In general, you use P2WSH when you have more complex spending requirements than a single key. This most often happens when you need multisig (multiple devices or people need to sign off on a spend).

Now, all of this is outside of the scope of BIP173, which only specifies how to encode segwit outputs into human-readable strings and back.

A segwit output is an output whose scriptPubKey starts with OP_0, OP_1, ..., OP_16, and is followed by a push of 2 to 40 bytes. That's it, and BIP173 can encode any of those.

Now, since the activation of BIP141 in Bitcoin, a small subset of segwit outputs have been given a meaning:

  • OP_0 + 20-byte push of RIPEMD160(SHA256(pubkey)) is called a P2WPKH for that public key.
  • OP_0 + 32-byte push of SHA256(script) is called P2WSH for that script.

All other kinds of segwit outputs are meaningless right now (non-standard and spendable by anyone), but that could change in the future. However, all of them can be encoded in Bech32 using BIP173. It doesn't care what the context or meaning is; it just encodes the version number (the OP_n opcode at the start) and the data bytes (what is being pushed afterwards).

Perhaps your confusion comes from the fact that the BIP173 test vectors use "key + OP_CHECKSIG" in its examples. That was just a simple way of constructing examples that are reproducible. They're not representative for how to actually use it.

  • I totally missed that the "key + OP_CHECKSIG" was meaningless in itself. What I wanted to do is add tests to make absolutely sure my implementation was correct: I've added those test now! (See: github.com/Kolibri-POS/bech32/blob/master/test/…) – harm Nov 19 '18 at 8:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.