sbddesign/bip21-site

Optimize QR code

Closed this issue · 9 comments

by changing to uppercase a QR code only needs 5.5 bits instead of 8 bits
bech32 is designed to work in uppercase QR
the proposed strings are not 100% in the supported alphabet, but QR code has a mixed mode that means it can switch mode inside the same QR code
i suggest we simply uppercase the lightning invoice to start with, all wallets i know support uppercase lightning invoices.
bc1 on chain addresses should also be possible to uppercase in the same way since they are bech32
some wallets will probably have issues, but it is them that have to fix it.

small example, the example on https://bitcoinqr.dev/
image
only change is lightning invoice uppercased:
image
it is quite obvious that it needs fewer bits

image

some wallets will probably have issues, but it is them that have to fix it.

@robtex Yeah, I'm not too worried about wallet support for uppercasing. I think there's fairly wide support for it, actually. This data is from December 2020 but already has promising results. Wouldn't surprise me if some of these red Xs have become checkmarks in the past year and a half. btcpayserver/btcpayserver#2110

Ran some tests by generating QR codes with this tool. I decided to run this test with different variations, like changing number of URI params and changing the invoice.

In every case, the uppercase QR is a lower-resolution image. These codes are being generated with the qrcode NPM library. This lib is supposed to automatically choose the correct QR code mode for you based on what's most efficient for the input string. I imagine it's selecting "mixed" for most of these, but regardless, it's supposed to be choosing the most size efficient mode.

So I think this can serve as a proof of concept that the uppercasing can work very well.

URI with label and message

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file qr-bip21.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6&label=sbddesign&message=For%20lunch%20Tuesday

qr_bip21

URI with label and message (uppercase)

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file qr_bip21_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_uppercase

URI with label and message - alternate invoice

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3ff0wxpp5p3vchn8ehvpk2drll24x222crhx4auqj2aduxpuaxw9gj2jfprxsd8qfa3xummcd9hh2umv0ysxcmmwvusx6etddusz6gzzd96xxmmfdcsxjurnw4kjqer0d3hhygrnd96zqctdv46zugzyda6kymr994ehqetwvss8qun0vfkx2mfqwa5xjar9wpshqetjypf5ssfdxg6nvtpqv3hh2cnvv5khxur9dejzqurjda3xcetdypxk2untd3jjq4rjv4jjqmtfdejhygrzd3hkx6eqcqzpgxqzjcsp5ljee7p2gufjtda6jj5d3cxh977ew3npjx5ajhav68k3hf5xhd48q9qyyssqvjcg29x5jnas9lc5tmkstamgf8kghjqk2l0v326qgzq3s6xqftu9nmzkjt7t7607da9n44n0a8svtfuya0s4rtsr94tmtf7k8ng6tlsq2qdh2k' --file qr-bip21_longer.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=lnbc10u1p3ff0wxpp5p3vchn8ehvpk2drll24x222crhx4auqj2aduxpuaxw9gj2jfprxsd8qfa3xummcd9hh2umv0ysxcmmwvusx6etddusz6gzzd96xxmmfdcsxjurnw4kjqer0d3hhygrnd96zqctdv46zugzyda6kymr994ehqetwvss8qun0vfkx2mfqwa5xjar9wpshqetjypf5ssfdxg6nvtpqv3hh2cnvv5khxur9dejzqurjda3xcetdypxk2untd3jjq4rjv4jjqmtfdejhygrzd3hkx6eqcqzpgxqzjcsp5ljee7p2gufjtda6jj5d3cxh977ew3npjx5ajhav68k3hf5xhd48q9qyyssqvjcg29x5jnas9lc5tmkstamgf8kghjqk2l0v326qgzq3s6xqftu9nmzkjt7t7607da9n44n0a8svtfuya0s4rtsr94tmtf7k8ng6tlsq2qdh2k

qr-bip21_longer

URI with label and message - alternate invoice (uppercase)

Build command

npm run qr -- --amt=0.00001000 --name='sbddesign' --description='For lunch Tuesday' --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3FF0WXPP5P3VCHN8EHVPK2DRLL24X222CRHX4AUQJ2ADUXPUAXW9GJ2JFPRXSD8QFA3XUMMCD9HH2UMV0YSXCMMWVUSX6ETDDUSZ6GZZD96XXMMFDCSXJURNW4KJQER0D3HHYGRND96ZQCTDV46ZUGZYDA6KYMR994EHQETWVSS8QUN0VFKX2MFQWA5XJAR9WPSHQETJYPF5SSFDXG6NVTPQV3HH2CNVV5KHXUR9DEJZQURJDA3XCETDYPXK2UNTD3JJQ4RJV4JJQMTFDEJHYGRZD3HKX6EQCQZPGXQZJCSP5LJEE7P2GUFJTDA6JJ5D3CXH977EW3NPJX5AJHAV68K3HF5XHD48Q9QYYSSQVJCG29X5JNAS9LC5TMKSTAMGF8KGHJQK2L0V326QGZQ3S6XQFTU9NMZKJT7T7607DA9N44N0A8SVTFUYA0S4RTSR94TMTF7K8NG6TLSQ2QDH2K' --file qr_bip21-longer_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&label=sbddesign&message=For%20lunch%20Tuesday&lightning=LNBC10U1P3FF0WXPP5P3VCHN8EHVPK2DRLL24X222CRHX4AUQJ2ADUXPUAXW9GJ2JFPRXSD8QFA3XUMMCD9HH2UMV0YSXCMMWVUSX6ETDDUSZ6GZZD96XXMMFDCSXJURNW4KJQER0D3HHYGRND96ZQCTDV46ZUGZYDA6KYMR994EHQETWVSS8QUN0VFKX2MFQWA5XJAR9WPSHQETJYPF5SSFDXG6NVTPQV3HH2CNVV5KHXUR9DEJZQURJDA3XCETDYPXK2UNTD3JJQ4RJV4JJQMTFDEJHYGRZD3HKX6EQCQZPGXQZJCSP5LJEE7P2GUFJTDA6JJ5D3CXH977EW3NPJX5AJHAV68K3HF5XHD48Q9QYYSSQVJCG29X5JNAS9LC5TMKSTAMGF8KGHJQK2L0V326QGZQ3S6XQFTU9NMZKJT7T7607DA9N44N0A8SVTFUYA0S4RTSR94TMTF7K8NG6TLSQ2QDH2K

qr_bip21-longer_uppercase

URI with amount

Build Command

npm run qr -- --amt=0.00001000 --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file=qr_bip21_non-memo.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?amount=0.00001&lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6

qr_bip21_non-memo

URI with amount (uppercase)

Build Command

npm run qr -- --amt=0.00001000 --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file=qr_bip21_non-memo_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?amount=0.00001&lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_non-memo_uppercase

URI with lightning param only

Build Command

npm run qr -- --btc='bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u' --ln='lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6' --file=qr_bip21_1-param.png

URI

bitcoin:bc1qylh3u67j673h6y6alv70m0pl2yz53tzhvxgg7u?lightning=lnbc10u1p3pj257pp5yztkwjcz5ftl5laxkav23zmzekaw37zk6kmv80pk4xaev5qhtz7qdpdwd3xger9wd5kwm36yprx7u3qd36kucmgyp282etnv3shjcqzpgxqyz5vqsp5usyc4lk9chsfp53kvcnvq456ganh60d89reykdngsmtj6yw3nhvq9qyyssqjcewm5cjwz4a6rfjx77c490yced6pemk0upkxhy89cmm7sct66k8gneanwykzgdrwrfje69h9u5u0w57rrcsysas7gadwmzxc8c6t0spjazup6

qr_bip21_1-param

URI with lightning param only (uppercase)

Build Command

npm run qr -- --btc='BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U' --ln='LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6' --file=qr_bip21_1-param_uppercase.png

URI

bitcoin:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?lightning=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

qr_bip21_1-param_uppercase

@robtex I'll make a PR to change the QR codes on the site as well as add some text to explain the value of uppercasing.

nice research and awesome examples!
just some last minute comments and ideas:
there seems to be good support for BITCOIN: maybe should throw in that as well?

also i see no point in doing lightning= in lowercase since it is a brand new parameter. make that one uppercase and we might save another pixel. or why not just LN= ?

it is truly annoying that '?' and = breaks the flow of alphanumerics, but the : is supported so BITCOIN:BC1... part would become one single alphanumeric sequence. so your last example would be

1 BITCOIN:BC1... in alphanumeric
2 ? in text
3 LN (or LIGHTNING) in alphanumeric
4 = in text
5 LNBC1... in alphanumeric

probably 2,3,4 will be short enough to be optimizied into one text-mode sequence ?LN= without having to shift modes

1 BITCOIN:BC1... in alphanumeric
2 ?LN= in text
3 LNBC1... in alphanumeric

default:
image

error correction L (my favorite since bech has enough error correction):
image

BITCOIN:BC1QYLH3U67J673H6Y6ALV70M0PL2YZ53TZHVXGG7U?LN=LNBC10U1P3PJ257PP5YZTKWJCZ5FTL5LAXKAV23ZMZEKAW37ZK6KMV80PK4XAEV5QHTZ7QDPDWD3XGER9WD5KWM36YPRX7U3QD36KUCMGYP282ETNV3SHJCQZPGXQYZ5VQSP5USYC4LK9CHSFP53KVCNVQ456GANH60D89REYKDNGSMTJ6YW3NHVQ9QYYSSQJCEWM5CJWZ4A6RFJX77C490YCED6PEMK0UPKXHY89CMM7SCT66K8GNEANWYKZGDRWRFJE69H9U5U0W57RRCSYSAS7GADWMZXC8C6T0SPJAZUP6

I decided to do some investigation regarding the capitalizing the scheme and parameter, as well as changing from lightning to LN. While this is far from exhaustive, I have managed to collect a lot of data on this. What I have observed is that (with my example data) the bitcoin address and lightning invoice contribute the most "weight" to the QR code. Through almost all these variations, simply using bitcoin:BECH32 ... lightning=BECH32 is equally effective as BITCOIN:BECH32 ... LN=BECH32. The only exception to this is row 4 of my data. I even ran the tests again without lightning invoices out of curiosity. Same deal: upper-casing the scheme has no noticeable effect on QR size.

See data here. For each row, the green outlines indicate the smallest QR dimension (there are many ties per row). Orange outlines indicate the second smallest QR dimension (also many ties).

My conclusion:

  • Upper-casing scheme and protocol usually has no noticeable effect.
  • Switching to LN= may have a very small effect in some situations.
    • LN= does not seem to have good support. (I tested 6 lightning wallets and none recognized LN=).
  • Upper-casing the address and invoice have an outsized effect in all situations.
  • bitcoin:BECH32 ... lightning=BECH32 is the format we are within closest reach to in the industry.
  • Therefore, we should promote bitcoin:BECH32 ... lightning=BECH32.

Personally, I'd rather spend time discussing BOLT12 than trying to save 16 pixels in some situations.

GBKS commented

Wow, thorough analysis there. Your recommendation makes sense to me. ACK.

definitely exhaustive enough and also uppercase enough for me. very nice!
wasn't aware there were already wallets supporting this lightning= part, so let's not break them.
ACK

Nice research, makes sense to me!

A shame these iQR codes are proprietary: https://qrcode.meetheed.com/question40.php

"You could take an iQR Code and a QR Code of exactly the same size, and encode a lot more data within the iQR Code (up to 80% more)."

Thanks for pushing for this @robtex and others! Merged.