Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

/p/g1magld5ptgzaktqcexxq0pgq5lmdf0kz6re8hlv/x/daily/bech32/v0

Directory · 4 Files
README.md Open

gno.land/p/moul/x/daily/bech32/v0

Bech32 and Bech32m, BIP-173 and BIP-350: Encode, EncodeVariant, Decode, ConvertBits, EncodeBytes, DecodeBytes.

1import "gno.land/p/moul/x/daily/bech32/v0"
2
3hrp, payload, v, err := bech32.DecodeBytes("g1manfred47kzduec920z88wfr64ylksmdcedlf5")
4// hrp == "g", payload is the 20-byte address, v.String() == "bech32"
5
6bech32.EncodeBytes("g", payload)              // back to the same string
7bech32.EncodeVariant("a", nil, bech32.Bech32m) // "a1lqfn3a"

What the format buys. A human-readable part, the separator 1, and a data part in a 32-character alphabet that ends in a six-character BCH checksum. The checksum is the point: it detects every error of up to four characters, and the alphabet leaves out 1, b, i and o, the four that are easiest to misread. That is why a gno.land address, a Bitcoin segwit address and a Cosmos account address all look the way they do.

Two variants, one constant apart. Bech32 xors its checksum with 1, Bech32m with 0x2bc830a3. Decode accepts either and reports which one verified, so a caller that cares can check instead of assuming.

Why the second one exists, reproduced as a test rather than quoted: a Bech32 string ending in p keeps a valid checksum when q characters are inserted in front of that final p. a1q3g6mnsp and a1q3g6mnsqp both verify, and decode to different data. The same insertion on a Bech32m string is refused.

Verified against the BIP-173 and BIP-350 vectors, and against a live mainnet address, which is the externally anchored check: it decodes to 20 bytes and re-encodes to the same 40 characters.

Strict where it matters: mixed case is rejected rather than folded, the 90 character cap of BIP-173 is enforced (it is what keeps a wrong character locatable, and a decode bounded in gas), and ConvertBits going back to 8 bits refuses leftover bits rather than inventing a trailing zero byte. A Variant that is neither constant is refused rather than quietly encoded as Bech32, and EncodeBytes checks MaxPayloadLen(hrp) before it regroups anything, so an oversized payload costs a comparison and not a full scan.

Live demo: r/moul/x/daily/bech32demo · render it at /r/moul/x/daily/bech32demo/v0.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.