The implementation of the Bech32/Bech32m encoder and decoder for Ruby.
Bech32 is checksummed base32 format that is used in following Bitcoin address format.
https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
Bech32m is checksummed base32m format that is used in following Bitcoin address format.
https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
Add this line to your application's Gemfile:
gem 'bech32'
And then execute:
$ bundle
Or install it yourself as:
$ gem install bech32
Require the Gem:
require 'bech32'
Decode Bech32-encoded data into hrp part and data part.
hrp, data, spec = Bech32.decode('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4')
# hrp is human-readable part of Bech32 format
'bc'
# data is data part of Bech32 format
[0, 14, 20, 15, 7, 13, 26, 0, 25, 18, 6, 11, 13, 8, 21, 4, 20, 3, 17, 2, 29, 3, 12, 29, 3, 4, 15, 24, 20, 6, 14, 30, 22]
# spec is whether Bech32::Encoding::BECH32 or Bech32::Encoding::BECH32M
The maximum number of characters of Bech32 defined in BIP-173 is limited to 90 characters. However, LN specification BOLT#11 has no limitation.
To decode data of more than 90 characters, specify max_length
at decode as below. (The default value of max_length
is 90.)
MAX_INTEGER = 2**31 - 1
Bech32.decode(bechString, MAX_INTEGER)
Note that between length of the addresses and the error-detection capabilities are trade-off.
Encode Bech32 human-readable part and data part into Bech32 string.
hrp = 'bc'
data = [0, 14, 20, 15, 7, 13, 26, 0, 25, 18, 6, 11, 13, 8, 21, 4, 20, 3, 17, 2, 29, 3, 12, 29, 3, 4, 15, 24, 20, 6, 14, 30, 22]
bech = Bech32.encode(hrp, data, Bech32::Encoding::BECH32)
=> 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
Decode Bech32-encoded Segwit address into Bech32::SegwitAddr
instance.
addr = 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4'
segwit_addr = Bech32::SegwitAddr.new(addr)
# generate script pubkey
segwit_addr.to_script_pubkey
=> '0014751e76e8199196d454941c45d1b3a323f1433bd6'
Encode Segwit script into Bech32 Segwit address.
segwit_addr = Bech32::SegwitAddr.new
segwit_addr.script_pubkey = '0014751e76e8199196d454941c45d1b3a323f1433bd6'
# generate addr
segwit_addr.addr
=> 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
Supports encoding/decoding of Nostr's NIP-19 entities.
# Decode bare entity
bech32 = 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg'
entity = Bech32::Nostr::NIP19.parse(bech32)
entity.hrp
=> 'npub'
entity.data
=> '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e'
# Decode tlv entity
bech32 = 'nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p'
entity = Bech32::Nostr::NIP19.parse(bech32)
entity.hrp
=> 'nprofile'
entity.entries[0].value
=> '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
entity.entries[1].value
=> 'wss://r.x.com'
# Encode bare entity
entity = Bech32::Nostr::BareEntity.new('npub', '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e')
entity.encode
=> 'npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg'
# Encode tlv entity
entry_relay = Bech32::Nostr::TLVEntry.new(Bech32::Nostr::TLVEntity::TYPE_RELAY, 'wss://relay.nostr.example')
entry_author = Bech32::Nostr::TLVEntry.new(Bech32::Nostr::TLVEntity::TYPE_AUTHOR, '97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322')
entity = Bech32::Nostr::TLVEntity.new(Bech32::Nostr::NIP19::HRP_EVENT, [entry_relay, entry_author])
entity.encode
=> 'nevent1qyvhwumn8ghj7un9d3shjtnwdaehgu3wv4uxzmtsd3jsygyhcu9ygdn2v56uz3dnx0uh865xmlwz675emfsccsxxguz6mx8rygstv78u'
After installing the gem, the bech32
command will be available. Encoding and decoding features are also available in the cli.
The encode
command takes HRP
, data
, and type (bech32
or bech32m
) as arguments and outputs a bech32/bech32m string.
$ bech32 encode genesis 000409190707111719041a120308120a060c161408110d091b090009021b1e1d150e190215010d0a1603091e1f0b100609090d1a1c1a13030c120c0c0f1c020d1d1a0e170b1c17021018121e0a021c121a1c0d161b16131d1609130f1d13180f1e081d041d0a110f110d1313081c11100600180b000c08140c1e130e0f090c160e0018191e1d1c0016060c11101214121e19070d1a0c1c15020414001f10100c09090600181806001809080e180507021913031100030216141b100908160c1213120f1912011f07021c13190d1900170c1d1203040f071c1908050504130e080d0a100d130b03000a0a08191310090918120f11031104120c15180c15120a0f1919070c1c12060c1911091010120a0d191b040c1613020e1911081f000b1a0b0514150c1613010d0c1c030b17011805090119061e0b051e130c00030419000112030110181d011a000f020c0901080c1113060201041a0e1b060a15160506181c11140c1c1d0b1b14020c131e0b0f071519181e0b1f0e0a08170f1d0c05060e1c1b0e160c0f0a171d0b101a1a1f1417160e0d1414030e161b0a000709100d15020c000e010c00000000 bech32
genesis1qyfe883hey6jrgj2xvk5g3dfmfqfzm7a4wez4pd2krf7ltsxffd6u6nrvjvv0uzda6whtuhzscj72zuj6udkmknakfn0anc07gaya2303dnngu3sxqctqvg5v7nw0fvkwqce7auqkxv3sj5j7e8d6vu4zy5qlssvffxqccxqcfgwc98zenr3qrzk5msfgkvjnj0ejpl8zunedeqhvajry08ueg99ynwgd2sdntrq22gensffcj03r3yjv4cv4j20ee8vujxve3fssj2demyvknzwe3glqt6t954vknpdvurthpc9fpex7t97nvqryeqpjrpscap6q0zvfpgv3nxzpy6wmx24k9xcu35vuatm5zvn7t084ec7tlw2gh0av9xwumwkv02hats66l5hkwd55rwkm2q8fsd4zvqwpvqqqqtdc6rp
Note: data
must be converted from 8-bit to 5-bit units.
The decode
command takes bech32/bech32m string as arguments and outputs HRP
, data
, and type.
$ bech32 decode genesis1qyfe883hey6jrgj2xvk5g3dfmfqfzm7a4wez4pd2krf7ltsxffd6u6nrvjvv0uzda6whtuhzscj72zuj6udkmknakfn0anc07gaya2303dnngu3sxqctqvg5v7nw0fvkwqce7auqkxv3sj5j7e8d6vu4zy5qlssvffxqccxqcfgwc98zenr3qrzk5msfgkvjnj0ejpl8zunedeqhvajry08ueg99ynwgd2sdntrq22gensffcj03r3yjv4cv4j20ee8vujxve3fssj2demyvknzwe3glqt6t954vknpdvurthpc9fpex7t97nvqryeqpjrpscap6q0zvfpgv3nxzpy6wmx24k9xcu35vuatm5zvn7t084ec7tlw2gh0av9xwumwkv02hats66l5hkwd55rwkm2q8fsd4zvqwpvqqqqtdc6rp
HRP: genesis
DATA: 000409190707111719041a120308120a060c161408110d091b090009021b1e1d150e190215010d0a1603091e1f0b100609090d1a1c1a13030c120c0c0f1c020d1d1a0e170b1c17021018121e0a021c121a1c0d161b16131d1609130f1d13180f1e081d041d0a110f110d1313081c11100600180b000c08140c1e130e0f090c160e0018191e1d1c0016060c11101214121e19070d1a0c1c15020414001f10100c09090600181806001809080e180507021913031100030216141b100908160c1213120f1912011f07021c13190d1900170c1d1203040f071c1908050504130e080d0a100d130b03000a0a08191310090918120f11031104120c15180c15120a0f1919070c1c12060c1911091010120a0d191b040c1613020e1911081f000b1a0b0514150c1613010d0c1c030b17011805090119061e0b051e130c00030419000112030110181d011a000f020c0901080c1113060201041a0e1b060a15160506181c11140c1c1d0b1b14020c131e0b0f071519181e0b1f0e0a08170f1d0c05060e1c1b0e160c0f0a171d0b101a1a1f1417160e0d1414030e161b0a000709100d15020c000e010c00000000
TYPE: bech32
If bech32 string has segwit hrp, it will also output witness version and witness program:
$ bech32 decode bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y
HRP: bc
DATA: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
TYPE: bech32m
WITNESS VERSION: 1
WITNESS PROGRAM: 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
If bech32 string has NIP-19 hrp, it will also output NIP-19 entry:
$ bech32 decode nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p
HRP: nprofile
DATA: 00001003171c0606071f051906111114001e17190f090f051d19120f1502011d02011f0f13190a18081c16041d0e0d0a151b1d040b07080101151b17061c191a051c1717040b1318051911161e1b080102151b17061c191a051c1716081a13020c0519121c1c1b010c111516040b13030d1d1610
TYPE: bech32
NIP19 Entities:
special: 3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
relay: wss://r.x.com
relay: wss://djbas.sadkb.com
Note: DATA
is data without bit conversion. When used, the DATA
must be converted from 5-bit to 8-bit and padded as necessary.
The gem is available as open source under the terms of the MIT License.