On this page are copies of all published parts of our 24-part weekly series on bech32 sending support, from March 19th to August 28th, 2019.

  1. Introduction to Bech32 Sending Support
    1. Sending to a legacy address
    2. Sending to a bech32 address
  2. Bech32 usage statistics
  3. Using the bech32 reference libraries
  4. Locating typos in bech32 addresses
  5. Fee savings with native segwit
  6. Top bech32 questions from the Bitcoin StackExchange
  7. Other addresses formats based on bech32
  8. Automatic bech32 support for future soft forks
  9. Creating more efficient QR codes with bech32 addresses
  10. Bech32 support as a proxy for competence
  11. Wallets that only support bech32 receiving

Introduction to Bech32 Sending Support

Originally published in Newsletter #38.

Bech32 native segwit addresses were first publicly proposed almost exactly two years ago, becoming the BIP173 standard. This was followed by the segwit soft fork’s lock-in on 24 August 2017. Yet, seventeen months after lock-in, some popular wallets and services still don’t support sending bitcoins to bech32 addresses. Developers of other wallets and services are tired of waiting and want to default to receiving payments to bech32 addresses so that they can achieve additional fee savings and improved privacy. Bitcoin Optech would like to help this process along so, from now until the two-year anniversary of segwit lock-in, each of our newsletters will include a short section with resources to help get bech32 sending support fully deployed.

Note, we are only directly advocating bech32 sending support. This allows the people you pay to use segwit but doesn’t require you to implement segwit yourself. (If you want to use segwit yourself to save fees or access its other benefits, that’s great! We just encourage you to implement bech32 sending support first so that the people you pay can begin taking advantage of it immediately while you upgrade the rest of your code and infrastructure to fully support segwit.) To that end, this week’s section focuses on showing exactly how small the differences are between sending to a legacy address and sending to a bech32 address.

Sending to a legacy address

For a P2PKH legacy address that you already support such as 1B6FkNg199ZbPJWG5zjEiDekrCc2P7MVyC, your base58check library will decode that to a 20-byte commitment:

 6eafa604a503a0bb445ad1f6daa80f162b5605d6

This commitment is inserted into a scriptPubKey template:

OP_DUP OP_HASH160 OP_PUSH20 6eafa604a503a0bb445ad1f6daa80f162b5605d6 OP_EQUALVERIFY OP_CHECKSIG

Converting the opcodes to hex, this looks like:

76a9146eafa604a503a0bb445ad1f6daa80f162b5605d688ac

This is inserted into the scriptPubKey part of an output that also includes the length of the script (25 bytes) and the amount being paid:

     amount                           scriptPubKey
|--------------|  |------------------------------------------------|
00e1f505000000001976a9146eafa604a503a0bb445ad1f6daa80f162b5605d688ac
                |
    size: 0x19 -> 25 bytes

This output can then be added to the transaction, which is then signed and broadcast.

Sending to a bech32 address

For an equivalent bech32 P2WPKH address such as bc1qd6h6vp99qwstk3z668md42q0zc44vpwkk824zh, you can use one of the reference libraries to decode the address to a pair of values:

0 6eafa604a503a0bb445ad1f6daa80f162b5605d6

These two values are also inserted into a scriptPubKey template. The first value is the witness script version byte that’s used to add a value to the stack using one of the opcodes from OP_0 to OP_16. The second is the commitment that’s also pushed onto the stack:

OP_0 OP_PUSH20 6eafa604a503a0bb445ad1f6daa80f162b5605d6

Converting the opcodes to hex, this looks like:

00146eafa604a503a0bb445ad1f6daa80f162b5605d6

Then, just as before, this is inserted into the scriptPubKey part of an output:

     amount                        scriptPubKey
|--------------|  |------------------------------------------|
00e1f505000000001600146eafa604a503a0bb445ad1f6daa80f162b5605d6
                |
    size: 0x16 -> 22 bytes

The output is added to the transaction. The transaction is then signed and broadcast.

For bech32 P2WSH (the segwit equivalent of P2SH) or for future segwit witness versions, you don’t need to do anything special. The witness script version may be a different number, requiring you to use the corresponding OP_0 to OP_16 opcode, and the commitment may be a different length (from 2 to 40 bytes), but nothing else about the output changes. Because length variations are allowed, ensure your fee estimation software considers the actual size of the scriptPubKey rather than using a constant someone previously calculated based on P2PKH or P2SH sizes.

What you see above is the entire change you need to make on the backend of your software in order to enable sending to bech32 addresses. For most platforms, it should be a very easy change. See BIP173 and the reference implementations for a set of test vectors you can use to ensure your implementation works correctly.

Bech32 usage statistics

Originally published in Newsletter #39.

As described last week, implementing just segwit spending should be easy. Yet we suspect some managers might wonder whether there are enough people using segwit to justify their team spending development effort on it. This week, we look at sites that track various segwit adoption statistics so that you can decide whether it’s popular enough that your wallet or service might become an outlier by failing to support it soon.

Optech tracks statistics about segwit use on our dashboard; another site tracking related statistics is P2SH.info. We see an average of about 200 outputs per block are sent to native segwit addresses (bech32). Those outputs are then spent in about 10% of all Bitcoin transactions. That makes payments involving native segwit addresses more popular than almost all altcoins.

Screenshot of Optech Dashboard segwit usage stats

However, many wallets want to use segwit but still need to deal with services that don’t yet have bech32 sending support. These wallets can generate a P2SH address that references their segwit details, which is less efficient than using bech32 but more efficient than not using segwit at all. Because these are normal P2SH addresses, we can’t tell just by looking at transaction outputs which P2SH addresses are pre-segwit P2SH outputs and which contain a nested segwit commitment, and so we don’t know the actual number of payments to nested-segwit addresses. However, when one of these outputs is spent, the spender reveals whether the output was segwit. The above statistics sites report that currently about 37% of transactions contain at least one spend from a nested-segwit output. That corresponds to about 1,400 outputs per block on average.

Any wallet that supports P2SH nested segwit addresses also likely supports bech32 native addresses, so the number of transactions made by wallets that want to take advantage of bech32 sending support is currently over 45% and rising.

To further gauge segwit popularity, you might also want to know which notable Bitcoin wallets and services support it. For that, we recommend the community-maintained bech32 adoption page on the Bitcoin Wiki or the when segwit page maintained by BRD wallet.

The statistics and compatibility data show that segwit is already well supported and frequently used, but that there are a few notable holdouts that haven’t yet provided support. It’s our hope that our campaign and other community efforts will help convince the stragglers to catch up on bech32 sending support so that all wallets that want to take advantage of native segwit can do so in the next few months.

Using the bech32 reference libraries

Originally published in Newsletter #40.

In a previous week, we discussed how small the differences are between creating the output for a legacy address versus a native segwit address. In that section we simply pointed you towards the bech32 reference libraries and told you that you’d get two values back. In this week, we walkthrough the exact steps of using the Python reference library so you can see how little work this is. We start by importing the library:

>>> import segwit_addr

Bech32 addresses have a Human-Readable Part (HRP) that indicates what network the address is for. These are the first few characters of the address and are separated from the data part of the address by the delimiter 1. For example, Bitcoin testnet uses tb and an example testnet address is tb1q3w[…]g7a. We’ll set the Bitcoin mainnet HRP of bc in our code so that we can later ensure that the addresses we parse are for the network we expect.

>>> HRP='bc'

Finally, we have a few addresses we want to check—one that should work and two that should fail. (See BIP173 for a complete set of reference test vectors.)

>>> good_address='bc1qd6h6vp99qwstk3z668md42q0zc44vpwkk824zh'
>>> typo_address='bc1qd6h6vp99qwstk3z669md42q0zc44vpwkk824zh'
>>> wrong_network_address='tb1q3wrc5yq9c300jxlfeg7ae76tk9gsx044ucyg7a'

Now we can simply attempt to decode each of these addresses

>>> segwit_addr.decode(HRP, good_address)
(0, [110, 175, 166, 4, 165, 3, 160, 187, 68, 90, 209,
     246, 218, 168, 15, 22, 43, 86, 5, 214])

>>> segwit_addr.decode(HRP, typo_address)
(None, None)

>>> segwit_addr.decode(HRP, wrong_network_address)
(None, None)

If we get back a None for the first value (the witness version), the address is invalid on our chosen network. If that happens, you want to throw an exception up the stack so that whatever process is interfacing with the user can get them to provide you with a correct address. If you actually get a number and an array, the decode succeeded, the checksum was valid, and the length was within the allowed range.

The witness version must be a number between 0 and 16, so you’ll want to check that (e.g. 0 <= x <= 16) and then convert it into the corresponding opcodes OP_0 through OP_16. For OP_0, this is 0x00; for OP_1 through OP_16, this is 0x51 through 0x60. You then need to add a push byte for the data depending on its length (0x02 through 0x28 for 2 to 40 bytes), and then append the data as a series of bytes. Pieter Wuille’s code does this quite succinctly:

>>> witver, witprog = segwit_addr.decode(HRP, good_address)
>>> bytes([witver + 0x50 if witver else 0, len(witprog)] + witprog).hex()
'00146eafa604a503a0bb445ad1f6daa80f162b5605d6'

That’s your entire scriptPubKey. You can use that in the output of a transaction and send it. Note that bech32 scriptPubKeys can vary in size from 4 to 42 vbytes, so you need to consider the actual size of the scriptPubKey in your fee estimation code.

Your code doesn’t need to be written in Python. Reference libraries are also provided for C, C++, Go, Haskell, JavaScript, Ruby, and Rust. Further, BIP173 describes bech32 well enough that any decent programmer should be able to implement it from scratch in their preferred language without requiring anything beyond what most programming languages provide in their builtins and standard library.

Other bech32 sending support updates: BitGo announced that their API now supports sending to bech32 addresses; see their announcement for additional details about bech32 receiving support. The Gemini exchange also apparently added bech32 sending support this week, and users report that Gemini defaults to accepting deposits to bech32 addresses as well.

Locating typos in bech32 addresses

Originally published in Newsletter #41.

In last week’s newsletter, we used the Python reference library for bech32 to decode an address into a scriptPubKey that you could pay. However, sometimes the user provides an address containing a typo. The code we suggested would detect the typo and ensure you didn’t pay a wrong address, but bech32 is also able to help detect the location of typos for your users. This week, we’ll demonstrate this capability using the Javascript sample code.

The code is written using Node.js-style module inclusion syntax, so the first step is to compile it into code we can use in the browser. For that, we install a browserify tool:

sudo apt install node-browserify-lite

Then we compile it into a standalone file:

browserify-lite ./segwit_addr_ecc.js --outfile bech32-demo.js --standalone segwit_addr_ecc

Followed by including it in our HTML:

<script src="bech32-demo.js"></script>

For convenience, we’ve included that file on the web version of this newsletter, so you can follow along with the rest of this example by simply opening the developer console in your web browser. Let’s start by checking a valid address. Recall from last week that we provide the network identifier when checking an address (bc for Bitcoin mainnet):

>> segwit_addr_ecc.check('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', 'bc')
error: null
program: Array(20) [ 117, 30, 118, … ]
version: 0

We see above that, just like last week, we get back the witness version and the witness program. The presence of the version field, plus the lack of an error, indicate that this program decoded without any checksum failure.

Now we replace one character in the above address with a typo and try checking that:

>> segwit_addr_ecc.check('bc1qw508d6qejxtdg4y5r4zarvary0c5xw7kv8f3t4', 'bc')
error: "Invalid"
pos: Array [ 21 ]

This time we get back the description of the error (the address is invalid because it doesn’t match its checksum) and a position. If we place the addresses above each other with each position marked, we see that this “21” identifies the location of the specific error:

                   1x        2x
         0123456789012345678901
>> good='bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
>> typo='bc1qw508d6qejxtdg4y5r4zarvary0c5xw7kv8f3t4'
                              ^

What if we make an additional replacement to the typo address and try again?

>> segwit_addr_ecc.check('bc1qw508d6qejxtdg4y5r4zarvary0c5yw7kv8f3t4', 'bc')
error: "Invalid"
pos: Array [ 32, 21 ]

We get two locations. Once again, when we compare the addresses to each other, we see this has identified both incorrect characters:

                   1x        2x        3x
         012345678901234567890123456789012
>> good='bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
>> typo='bc1qw508d6qejxtdg4y5r4zarvary0c5yw7kv8f3t4'
                              ^          ^

Pieter Wuille’s interactive demo of this Javascript code includes a few lines of additional code (view source on that page to see the function) that uses the position of the typo characters to emphasize them in red:

Screenshot of the bech32 interactive demo with the typo address above

There’s a limit to how many errors the check() function can specifically identify. After that it can still tell that an address contains an error, but it can’t identify where to look in the address for the error. In that case, it’ll still return the address as invalid but it won’t return the position details:

>> segwit_addr_ecc.check('bc1qw508z6qejxtdg4y5r4zarvary0c5yw7kv8f3t4', 'bc')
error: "Invalid"
pos: null

In the case where there are other problems with the address, the error field will be set to a more descriptive message that may or may not include a position of the error. For example:

>> segwit_addr_ecc.check('bc1zw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4yolo', 'bc')
error: "Invalid character"
pos: Array [ 43 ]

You can review the source for a complete list of errors.

Although we spent a lot of time looking at errors in this mini tutorial, we’ve hopefully shown how easy it is to provide nice interactive feedback to users entering bech32 addresses on a web-based platform. We encourage you to play around with the interactive demo to get an idea of what your users might see if you make use of this bech32 address feature.

Fee savings with native segwit

Originally published in Newsletter #42.

One reason your users and customers may want you to implement bech32 sending support is because it’ll allow the receivers of those payments to save on fees when they re-spend that money. This week, we’ll look at how much money they’ll save and discuss how their savings could also help you save money.

For the legacy P2PKH address format implemented in the first version of Bitcoin, the scriptSig that authorizes a spend is typically 107 vbytes. For P2SH-wrapped segwit P2WPKH, this same information is moved to a witness data field that only consumes 1/4 as many vbytes (27 vbytes) but whose P2SH overhead adds 23 vbytes for a total of 50 vbytes. For native segwit P2WPKH, there’s no P2SH overhead, so 27 vbytes is all that’s used.

This means you could argue that P2SH-P2WPKH saves over 50% compared to P2PKH, and that P2WPKH saves another almost 50% compared to P2SH-P2WPKH or 75% compared to P2PKH alone. However, spending transactions contain more than just scriptSigs and witness data, so the way we usually compare savings is by looking at prototype transactions. For example, we imagine a typical transaction containing a single input and two outputs (one to the receiver; one as change back to the spender). In that case:

  • Spending P2PKH has a total transaction size of 220 vbytes
  • Spending P2SH-P2WPKH has a size of 167 vbytes (24% savings)
  • Spending P2WPKH output has a size of 141 vbytes (16% savings vs P2SH-P2WPKH or 35% vs P2PKH)

To compare simple multisig transactions (those that just use a single OP_CHECKMULTSIG opcode), things get more complex because k-of-n multisig inputs vary in size depending on the number of signatures (k) and the number of public keys (n). So, for simplicity’s sake, we’ll just plot the sizes of legacy P2SH-multisig compared to wrapped P2SH-P2WSH multisig (up to the maximum 15-of-15 supported by legacy P2SH). We can see that switching to P2SH-P2WSH can save from about 40% (1-of-2 multisig) to about 70% (15-of-15).

Plot of multisig transaction sizes with P2SH and P2SH-P2WSH

We can then compare P2SH-P2WSH to native P2WSH to see the additional constant-sized savings of about 35 bytes per transaction or about 5% to 15%.

Plot of multisig transaction sizes with P2SH-P2WSH and P2WSH

The scripts described above account for almost all scripts being used with addresses that aren’t native segwit. (Users of more complex scripts, such as those used in LN, are mostly using native segwit today.) Those less efficient script types currently consume a majority fraction of block capacity (total block weight). Switching to native segwit in order to reduce a transaction’s weight allows you to reduce its fee by the same percentage without changing how long it’ll take to confirm—all other things being equal.

But all other things aren’t equal. Because the transactions use less block weight, there’s more weight available for other transactions. If the supply of available block weight increases and demand remains constant, we expect prices to go down (unless they’re already at the default minimum relay fee). This means more people spending native segwit inputs lowers the fee not just for those spenders but for everyone who creates transactions—including wallets and services that support sending to bech32 addresses.

Top bech32 questions from the Bitcoin StackExchange

Originally published in Newsletter #43.

This week we look at some of the top-voted bech32 questions and answers from the Bitcoin StackExchange. This includes everything since bech32 was first announced about two years ago.

  • Will a Schnorr soft fork introduce a new address format? Although upgrading to bech32 sending support should be easy, you probably don’t want to repeat that work for Bitcoin’s next upgrade or the upgrade after that. Pieter Wuille answers this question by explaining how an upgrade to Schnorr-based public keys and signatures can still use bech32 addresses. (Optech will be covering this issue in greater detail in a future section.)

  • Is it safe to translate a bech32 P2WPKH address into a legacy P2PKH address? If you read Newsletter #38, you’ll notice that the difference between a P2WPKH and P2PKH address for the same underlying public key is only a few characters in a scriptPubKey, making it possible to automatically convert one into the other. This answer by Andrew Chow and its accompanying comments explains why that’s a bad idea that could cause users to lose funds.

  • Why does the bech32 decode function require specifying the address’s Human Readable Part (HRP) instead of extracting it automatically? The HRP is separated from the rest of the address by a 1, so it seems like the decoder could ignore that part all on its own. Pieter Wuille explains that calling the decoder with the expected HRP ensures that you don’t accidentally pay bitcoin to an address meant for testnet, litecoin, or some other network. Gregory Maxwell also corrects an additional assumption of the asker.

  • What block explorers recognize bech32 addresses? More than two years after bech32 was first proposed and a year after this question was first asked, several popular block explorers don’t support search or display of bech32 addresses. The answer to this question suggests anyone who wants to learn the bech32 status of various block explorers should check the bech32 adoption Bitcoin Wiki page.

Other addresses formats based on bech32

Originally published in Newsletter #44.

It’s said that “imitation is the most sincere form of flattery.” In this week’s section, we take a quick look at a few other systems that are using variations on bech32. If you’re already going to need to implement something that’s basically bech32 for another project, it’s probably worth your time to implement it for Bitcoin too.

  • LN invoices use the bech32 format with an extended Human-Readable Part (HRP) and without bech32’s normal 90-character limit. See BOLT11 for the full specification. Example: lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp

  • Bitcoin Cash new-style addresses use the bech32 format with the HRP bitcoincash and the separator :. Instead of the version byte encoding a segwit witness version, as in Bitcoin, it indicates whether the hash encoded by the address should be used with P2PKH or P2SH. See spec-cashaddr for the full specification. Example: bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a

  • Backup seeds: In June 2018, Jonas Schnelli proposed Bech32X, a scheme to encode Bitcoin private keys, extended private keys (xprivs), and extended public keys (xpubs) using bech32 for error correction. See the full draft specification. Example: pk1lmll7u25wppjn5ghyhgm7kndgjwgphae8lez0gra436mj7ygaptggl447a4xh7

  • Elements-based sidechains: sidechains based on ElementsProject.org, such as Blockstream Liquid, use both bech32 address and a variation of them called “blech32” addresses. Blech32 addresses are intended for use with that platform’s confidential assets and will soon be supported by the Esplora block explorer for the Liquid sidechain. We’re unaware of a specification document for blech32, but this code is labeled as the reference implementation and is cited elsewhere in the project as, “See liquid_addr.py for compact difference from bech32.” Example of a blech32 address: lq1qqf8er278e6nyvuwtgf39e6ewvdcnjupn9a86rzpx655y5lhkt0walu3djf9cklkxd3ryld97hu8h3xepw7sh2rlu7q45dcew5

  • Output script descriptors: although less directly related to bech32, checksums based on the same Bose-Chaudhuri-Hocquenghem (BCH) codes used in bech32 were added to the output script descriptors supported by Bitcoin Core. See Pieter Wuille’s detailed comment. Example: wpkh([f6bb4c63/0'/0'/28']02bf9d38386db60191f2f785cbf7ba90d01bed5958efb7b449a552b89da7550177)#efkksxw6

Automatic bech32 support for future soft forks

Originally published in Newsletter #45.

What do bip-taproot and bip-tapscript mean for people who have implemented bech32 sending support or who are planning to implement it? In particular, if you haven’t implemented segwit sending support yet, should you wait to implement it until the new features have been activated? In this weekly section, we’ll show why you shouldn’t wait and how implementing sending support now won’t cost you any extra effort in the future.

The designers of segwit and bech32 had a general idea what future protocol improvements would look like, so they engineered segwit scriptPubKeys and the bech32 address format to be forward compatible with those expected improvements. For example an address supporting Taproot might look like this:

bc1pqzkqvpm76ewe20lcacq740p054at9sv7vxs0jn2u0r90af0k63332hva8pt

You’ll notice that looks just like other bech32 addresses you’ve seen—because it is. You can use the exact same code we provided in Newsletter #40 (using the bech32 reference library for Python) to decode it.

>> import segwit_addr
>> address='bc1pqzkqvpm76ewe20lcacq740p054at9sv7vxs0jn2u0r90af0k63332hva8pt'
>> witver, witprog = segwit_addr.decode('bc', address)
>> witver
1
>> bytes(witprog).hex()
'00ac06077ed65d953ff8ee01eabc2fa57ab2c19e61a0f94d5c78cafea5f6d46315'

The differences here from the decoded bech32 addresses we’ve shown in previous newsletters are that this hypothetical Taproot address uses a witness version of 1 instead of 0 (meaning the scriptPubKey will start with OP_1 instead of OP_0) and the witness program is one byte longer than a P2WSH witness program. However, these don’t matter to your software if you’re just spending. We can use the exact same example code from Newsletter #40 to create the appropriate scriptPubKey for you to pay:

>> bytes([witver + 0x50 if witver else 0, len(witprog)] + witprog).hex()
'512100ac06077ed65d953ff8ee01eabc2fa57ab2c19e61a0f94d5c78cafea5f6d46315'

This means anyone who implements bech32 support in the generic way described in Newsletter #40 shouldn’t need to do anything special in order to support future script upgrades. In short, the work you invest into providing bech32 sending support now is something you won’t need to repeat when future expected changes to the Bitcoin protocol are deployed.

Creating more efficient QR codes with bech32 addresses

Originally published in Newsletter #46.

BIP173 forbids bech32 addresses from using mixed case. The preferred way to write a bech32 address is in all lowercase, but there’s one case where all uppercase makes sense: QR codes. Take a look at the following two QR codes for the same address with the only difference being lowercase versus uppercase:

bech32 uppercase

This is a deliberate design feature of bech32. QR codes can be created in several modes that support different character sets. The binary mode character set is used for legacy addresses because they require mixed case. However, Bech32 addresses for Bitcoin1 can be represented using only numbers and capital letters, so they can use the smaller uppercase alphanumeric character set. Because this set is smaller, it uses fewer bits to encode each character in a QR code, allowing the resultant code to be less complex.

Bitcoin addresses are often used in BIP21 URIs. BIP21 technically requires base58check formatting, but at least some wallets that support native segwit addresses (such as Bitcoin Core) allow them to be used with bech32. Although the preferred form of BIP21’s scheme identifier bitcoin: is lowercase, it can also be uppercased as allowed by both BIP21 and RFC3986. This also produces a less complex image (although in this case, our QR encoding library gave both images the same dimensions).

bech32 uppercase

Unfortunately, the ? and & needed for passing additional parameters in a BIP21 URI are not part of the QR code uppercase character set, so only binary mode can be used for those characters. Additionally, BIP21 specifies that query parameter names such as amount and label are case sensitive, so uppercase versions of them aren’t expected to work anyway.

However, QR codes can support mixed character sets and doing so will always be at least slightly more efficient when used with a string that either begins or ends with an all-caps substring containing a bech32 address. This is because the minimum allowed size of a bech32 address (14 characters) combined with the efficiency gain from using uppercase mode (31.25%) exceeds the worst-case overhead of switching modes (20 extra bits). At least two QR code encoders we’re aware of, libqrencode (C) and node-qrcode (JS), automatically mix character sets by default as necessary to produce the least-complex QR code possible:

BIP21/bech32 mixed character mode

In summary, when using bech32 addresses in QR codes, consider uppercasing them and any other adjacent characters that can be uppercased in order to produce smaller and less complex QR codes. (However, for all other purposes, bech32 addresses should use all lowercase characters.)

Correction: an earlier version of this section claimed that QR codes which included BIP21 query parameters needed to use binary mode. Nadav Ivgi kindly informed us that it was possible to mix character modes, and we’ve updated the final two paragraphs of this section accordingly.

Bech32 support as a proxy for competence

Originally publised in Newsletter #47.

Up until this point in our series encouraging wallets and services to support sending to bech32 native segwit addresses, we’ve focused almost exclusively on technical information. Today, this section expresses an opinion: the longer you delay implementing bech32 sending support, the worse some of your users and potential users will think of your software or service.

“They can only pay legacy addresses.”
“Oh. Let’s look for another service that supports current technology.”

Services that only support legacy addresses are likely to become a cue to users that minimal development effort is being put into maintaining their Bitcoin integration. We expect that it’ll send the same signal to users as a website in 2019 that’s covered in Shockwave/Adobe Flash elements and that claims it’s best viewed in Internet Explorer 7 (or see an even more imaginative comparison written by Gregory Maxwell.)

Bech32 sending is not some experimental new technology that still needs testing—native segwit unspent outputs currently hold over 200,000 bitcoins. Bech32 sending is also something that’s easy to implement (see Newsletters #38 and #40). Most importantly, as more and more wallets and services upgrade to bech32 receiving by default, it’s going to become obvious which other services haven fallen behind by not providing sending support.

If you haven’t implemented bech32 sending support yet, we suggest you try to get it implemented by 24 August 2019 (the two-year anniversary of segwit activation). Not long after that, Bitcoin Core’s next release is expected to begin defaulting to bech32 receiving addresses in its GUI and perhaps also its API methods (see Newsletters #40 and #42). We expect other wallets to do the same—except for the ones that have already made bech32 their default (or even their only supported address format).

Wallets that only support bech32 receiving

Originally published in Newsletter #48.

Last week, we described one of the costs of not upgrading to bech32 sending support—users might think your service is out-of-date and so look for alternative services. This week, we’ll look at the stronger form of that argument: wallets which already can only receive to bech32 addresses. If the users of these wallets want to receive a payment or make a withdrawal from your service, and you don’t yet support sending to bech32 addresses, they’ll either have to use a second wallet or have to use one of your competitors.

  • Wasabi wallet, known for its privacy-enhancing coinjoin mode and mandatory user coin control, only accepts payments to bech32 addresses. This relatively-new wallet was designed around compact block filters similar to those described in BIP158. However, since all of the filters are served by Wasabi’s infrastructure, the decision was made to minimize filter size by only including P2WPKH outputs and spends in the filter. This means the wallet can’t see payments to other output types, including P2SH for P2SH-wrapped segwit addresses.
  • Trust wallet is a fairly new proprietary wallet owned by the Binance cryptocurrency exchange and compatible with Android and iOS. As a new wallet, they didn’t need to implement legacy address receiving support, so they only implemented segwit. That makes bech32 the only supported way to send bitcoins to this wallet.
  • Electrum is a popular wallet for desktop and mobile. When creating a new wallet seed, you can choose between a legacy wallet and a segwit wallet, with segwit being the current default. Users choosing a segwit wallet seed will only be able to generate bech32 addresses for receiving. Electrum warns users about the compatibility issues this may create with software and services that haven’t upgraded to bech32 sending support yet:

    Dialog in Electrum allowing the user to choose the address type
  and warning them that some services may not support bech32
  addresses

    Please note that it’s neither required nor recommended for wallet authors to create a new seed in order to support a new address format. Other wallets, such as Bitcoin Core 0.16.0 and above, can produce legacy, p2sh-segwit, and bech32 addresses all from the same seed—the user just needs to specify which address type they want (if they don’t want the default).

As time goes on, we expect more new wallets to only implement receiving to the current best address format. Today that’s v0 segwit addresses for P2WPKH and P2WSH using bech32, but if Taproot is adopted, it will use v1 segwit addresses that will also use bech32. The longer your service delays implementing bech32 sending support, the more chance you’ll have of losing customers because they can’t request payments from you using their preferred wallet.

Footnotes

  1. Bech32 addresses have three parts, a Human Readable Prefix (HRP) such as bc, a separator (always a 1), and a data part. The separator and the data part are guaranteed to be part of QR code’s uppercase alphanumeric set, but the range of characters allowed in the HRP according to BIP173 includes punctuation that isn’t part of that uppercase alphanumeric set. Specifically, the following characters are allowed in bech32 HRPs but are not part of the QR code uppercase alphanumeric set:

    !"#&'()';<=>?@[\]^_`{|}~
    

    None of the bech32 HRPs used in Bitcoin (bc, tb, bcrt) use any of these characters, and neither does any other application as far as we know. However, you may not want to make any assumptions in your code about uppercase always providing smaller QR codes for non-Bitcoin bech32 addresses.