- Rust 100%
|
Some checks failed
CI / build, lint, test (stable) (push) Successful in 51s
CI / build, lint, test (nightly) (push) Successful in 1m10s
CI / lint markdown (push) Successful in 24s
CI / audit (push) Successful in 27s
CI / build, lint, test (beta) (push) Successful in 1m52s
CI / doc (push) Successful in 1m58s
CI / coverage (push) Failing after 1m29s
|
||
|---|---|---|
| .forgejo/workflows | ||
| .github/workflows | ||
| examples | ||
| src | ||
| .gitignore | ||
| .markdownlint.yaml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE.txt | ||
| README.md | ||
pbech32
Bech32 encoding and decoding library.
Links:
What is Bech32?
Bech32 is a fast and user-friendly base 32 encoding format that includes a namespace and checksum. Bech32m is an update to Bech32 with an improved checksum algorithm.
A Bech32 string contains a human-readable part (HRP), an encoded data part, and a 6 character checksum. The data part and checksum are base 32-encoded with a user-friendly alphabet that only contains lowercase ASCII alphanumeric characters.
Here is an example Bech32m string:
hello1vehkc6mn27xpct
Bech32 and Bech32m are specified in BIP173 and BIP350, respectively.
Library Features
- Bech32 (BIP173) and Bech32m (BIP350) support.
- Idiomatic encoding and decoding via the
DisplayandFromStrtraits. - Decode arbitrarily long strings.
- Streamed, allocation-free encoding to any writer.
- No external dependencies.
Examples
Decode from string:
use pbech32::Bech32;
let s = "a1qypqxpq9mqr2hj"; // bech32m-encoded string
let got: Bech32 = s.parse()?; // decode string
assert_eq!(got.hrp.to_string(), "a"); // check human-readable part
assert_eq!(got.data, vec![1, 2, 3, 4, 5]); // check data
Encode to string:
use pbech32::{Bech32, Hrp, Scheme};
let scheme = Scheme::Bech32m; // checksum scheme
let hrp: Hrp = "a".parse()?; // human-readable part
let data = vec![1, 2, 3, 4, 5]; // data
let got = Bech32 { scheme, hrp, data }.to_string(); // encode as string
assert_eq!(got, "a1qypqxpq9mqr2hj"); // check result
Decoding a string verifies the checksum to catch mistakes:
use pbech32::{Bech32, Err};
let s = "a1wypqxpq9mqr2hj"; // string with error ("q" changed to "w")
let got = s.parse::<Bech32>(); // try to decode string
assert_eq!(got, Err(Err::InvalidChecksum)); // check result
Encode to a writer:
use std::io::Write;
use pbech32::{Encoder, Hrp, Scheme};
let mut vec: Vec<u8> = Vec::new(); // output vector
let hrp: Hrp = "hello".parse()?; // human readable part
{
let mut encoder = Encoder::new(&mut vec, Scheme::Bech32m, hrp)?; // create encoder
encoder.write_all(b"folks")?; // write data
encoder.flush()?; // flush encoder (RECOMMENDED)
}
let got = str::from_utf8(vec.as_ref())?; // convert output vector to string
assert_eq!(got, "hello1vehkc6mn27xpct"); // check result
Many error variants have a context field which provides additional information about the error. Try to decode a string which has an invalid character at position 1:
use pbech32::{Bech32, Err};
let s = "a 1xxxxxx"; // string with invalid character at position 1
assert_eq!(s.parse::<Bech32>(), Err(Err::InvalidChar(1))); // check result
More examples are available in examples/.
Install
pbech32 package page on crates.io
Run cargo add pbech32 to add pbech32 as a dependency to an
exiting Rust project:
$ cargo add pbech32
...
Run cargo install pbech32 to install the bech32 tool:
# install bech32 tool in cargo bin dir (e.g. `~/.cargo/bin`)
$ cargo install pbech32
Build
Run cargo build to create a debug build of the bech32 tool in
target/debug/:
$ cargo build
...
$ echo -n hello | target/debug/bech32 encode; echo
example1dpjkcmr0qp8pe8
Run cargo build --release to create a release build of the bech32
tool in target/release/:
$ cargo build --release
...
$ echo -n 'hi there' | target/release/bech32 encode; echo
example1dp5jqargv4ex2at7pqx
You can also build the bech32 tool in a container using
Podman or Docker like this:
$ podman run --rm -t -v "$PWD":/src -w /src docker.io/rust cargo build --release
...
$ echo -n foobarbaz | target/release/bech32 encode; echo
example1vehk7cnpwf3xz7sfaj6vp
To build a static binary of the example bech32 tool in a container:
$ podman run --rm -it -v "$PWD":/src -w /src rust sh -c "
rustup target add $(arch)-unknown-linux-musl &&
cargo build --release --target $(arch)-unknown-linux-musl
"
...
$ ldd target/x86_64-unknown-linux-musl/release/bech32
statically linked
$ du -sh target/x86_64-unknown-linux-musl/release/bech32
580K target/x86_64-unknown-linux-musl/release/bech32
$ echo -n hello | target/x86_64-unknown-linux-musl/release/bech32 encode; echo
example1dpjkcmr0qp8pe8
Documentation
pbech32 API documentation on docs.rs
Run cargo doc to build the API documentation locally in
target/doc/pbech32/:
$ cargo doc
...
$ ls target/doc/pbech32/index.html
target/doc/pbech32/index.html
Run cargo doc --lib build the library documentation and exclude the
bech32 tool documentation:
# remove generated docs
# (needed to clean up stale artifacts)
$ cargo clean --doc
# generate library-only docs
$ cargo doc --lib
Tests
Use cargo test to run the test suite:
$ cargo test
...
test result: ok. 46 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
all doctests ran in 0.23s; merged doctests compilation took 0.22s
Use cargo clippy to run the linter:
$ cargo clippy
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
Install cargo-tarpaulin and use cargo tarpaulin to check code
coverage:
$ cargo tarpaulin --engine llvm
...
2026-03-27T03:46:05.799963Z INFO cargo_tarpaulin::report: Coverage Results:
|| Uncovered Lines:
|| src/bin/bech32.rs: 113-116, 119, 124, 126, 161, 206-209
|| src/lib.rs: 811
|| Tested/Total Lines:
|| src/bin/bech32.rs: 28/40 +0.00%
|| src/lib.rs: 196/197 +0.00%
||
94.51% coverage, 224/237 lines covered, +0.00% change in coverage
Note: Some of the tests in src/bin/bech32.rs are ignored by
default because the tests set environment variables which will cause
tests in other threads to fail sporadically.
You can run the tests in a single thread and enable the ignored tests like this:
$ cargo tarpaulin --engine llvm -j1 -i
2026-03-27T03:46:30.385793Z INFO cargo_tarpaulin::report: Coverage Results:
|| Uncovered Lines:
|| src/bin/bech32.rs: 119, 126, 161, 206-209
|| src/lib.rs: 811
|| Tested/Total Lines:
|| src/bin/bech32.rs: 33/40 +12.50%
|| src/lib.rs: 196/197 +0.00%
||
96.62% coverage, 229/237 lines covered, +2.11% change in coverage