multibase implementation in Rust.
A multibase encoding/decoding library with error handling, type safety, and
no_std support.
- Features
- Install
- Usage
- Supported Bases
- Performance
- Security
- Concurrency
- CLI Tool
- Testing
- Maintainers
- Contribute
- License
β¨ Stable
- 142 tests (unit, integration, property-based, security, concurrency)
- Zero clippy warnings
- Thread safety verification
#![deny(unsafe_code)]
π Performance
- Zero-copy buffer reuse APIs
#[inline]on hot encode/decode paths- Pre-allocated exact-capacity encoding
π Type Safety
- Validated
EncodedStringnewtype - "Parse, don't validate" pattern
- Compile-time guarantees
π‘οΈ Security
- No panics on untrusted input
#![deny(unsafe_code)]enforced- Fuzzing infrastructure
- Input validation at all boundaries
π§΅ Thread Safe
- All types are Send + Sync
- No interior mutability
- Verified with concurrent stress tests
π Documented
- API documentation with examples
- Security and concurrency guides
- CHANGELOG.md with migration notes
π Flexible
- 24 supported base encodings
- Strict and permissive decoding modes
no_stdsupport withalloc- WebAssembly compatible
Add this to your Cargo.toml:
[dependencies]
multi-base = "1.0"For no_std environments:
[dependencies]
multi-base = { version = "1.0", default-features = false }Note: the crate is published as
multi-baseon crates.io and imported asmulti_basein Rust. The current published version is1.0.1.
MSRV: Rust 1.85 (Edition 2024)
use multi_base::{Base, encode, decode};
// Encode data
let encoded = encode(Base::Base64, b"hello world");
println!("{}", encoded); // "maGVsbG8gd29ybGQ"
// Decode data
let (base, data) = decode(&encoded, true)?;
assert_eq!(base, Base::Base64);
assert_eq!(data, b"hello world");When encoding/decoding multiple values, reuse buffers to avoid allocations:
use multi_base::{Base, encode_into, decode_into};
let mut encode_buffer = String::new();
let mut decode_buffer = Vec::new();
for data in dataset {
// Encode into existing buffer (no allocation)
encode_into(Base::Base64, data, &mut encode_buffer);
// Decode into existing buffer (no allocation)
let base = decode_into(&encode_buffer, true, &mut decode_buffer)?;
// Process decoded data...
}Use EncodedString for validated multibase strings:
use multi_base::{EncodedString, Base};
// Parse and validate at construction
let encoded = EncodedString::new("zCn8eVZg")?;
// Base is known at compile time
assert_eq!(encoded.base(), Base::Base58Btc);
// Decode directly
let data = encoded.decode()?;
assert_eq!(data, b"hello");
// Or use FromStr
let encoded: EncodedString = "md29ybGQ".parse()?;The library provides comprehensive error types with context:
use multi_base::{decode, Error};
match decode(input, true) {
Ok((base, data)) => {
println!("Decoded with {:?}: {:?}", base, data);
}
Err(Error::UnknownBase { code }) => {
eprintln!("Unknown base code: {}", code);
}
Err(Error::EmptyInput) => {
eprintln!("Input string is empty");
}
Err(Error::DataEncodingDecode { message }) => {
eprintln!("Decoding failed: {}", message);
}
Err(e) => {
eprintln!("Error: {}", e);
}
}The library supports 24 base encodings:
| Base | Code | Alphabet |
|---|---|---|
| Identity | \0 |
8-bit binary (no encoding) |
| Base2 | 0 |
01 |
| Base8 | 7 |
01234567 |
| Base10 | 9 |
0123456789 |
| Base16 (Lower) | f |
0123456789abcdef |
| Base16 (Upper) | F |
0123456789ABCDEF |
| Base32 (Lower) | b |
RFC 4648 (no padding) |
| Base32 (Upper) | B |
RFC 4648 (no padding) |
| Base32Pad (Lower) | c |
RFC 4648 (with padding) |
| Base32Pad (Upper) | C |
RFC 4648 (with padding) |
| Base32Hex (Lower) | v |
RFC 4648 hex (no padding) |
| Base32Hex (Upper) | V |
RFC 4648 hex (no padding) |
| Base32HexPad (Lower) | t |
RFC 4648 hex (with padding) |
| Base32HexPad (Upper) | T |
RFC 4648 hex (with padding) |
| Base32Z | h |
z-base-32 (Tahoe-LAFS) |
| Base36 (Lower) | k |
0123456789abcdefghijklmnopqrstuvwxyz |
| Base36 (Upper) | K |
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ |
| Base58 Flickr | Z |
Flickr alphabet |
| Base58 Bitcoin | z |
Bitcoin alphabet |
| Base64 | m |
RFC 4648 (no padding) |
| Base64Pad | M |
RFC 4648 (with padding) |
| Base64Url | u |
RFC 4648 URL-safe (no padding) |
| Base64UrlPad | U |
RFC 4648 URL-safe (with padding) |
| Base256Emoji | π |
Emoji alphabet |
Encoding Performance: Base32 and Base64 are orders of magnitude faster than other bases due to byte alignment.
Optimization Tips:
- Use
encode_into()anddecode_into()for buffer reuse in loops - Prefer Base32 or Base64 for performance-critical applications
- Use Base58 or Base16 when human readability is important
Benchmarks: Run cargo bench to see performance on your system.
- β No panics on arbitrary untrusted input
- β
#![deny(unsafe_code)]enforced at compile time - β Input validation at all boundaries
- β 17 dedicated security tests
- β Fuzzing infrastructure with 4 targets (3 functional + 1 placeholder)
Best Practices:
- For untrusted input, always use strict mode:
decode(input, true) - Implement application-level size limits (see SECURITY.md)
- For binary data preservation, avoid Identity encoding (use Base64 instead)
See SECURITY.md for detailed security information.
All public types are fully thread-safe:
- β
All types implement
Send+Sync - β No interior mutability
- β No data races possible
- β Verified with 20 thread safety tests
Concurrent Usage:
use std::sync::Arc;
use std::thread;
let data = Arc::new(b"data".to_vec());
let handles: Vec<_> = (0..10)
.map(|_| {
let d = Arc::clone(&data);
thread::spawn(move || {
multi_base::encode(Base::Base64, &*d)
})
})
.collect();
for handle in handles {
let encoded = handle.join().unwrap();
// All threads produce identical results
}See CONCURRENCY.md for detailed concurrency information.
The crate includes a command-line tool for encoding/decoding, located in the
cli/ directory.
Build the CLI:
cd cli
cargo build --releaseExample usage:
# Encode data
echo "hello world" | multibase encode --base base64
# Decode data
echo "maGVsbG8gd29ybGQ" | multibase decode
# Specify input directly
multibase encode --base base58btc --input "hello world"The crate has 142 tests:
- 142 tests total (excluding ignored tests)
- 12 unit tests
- 63 integration tests
- 16 property-based tests (using proptest)
- 17 security tests
- 20 thread safety tests
- 14 documentation tests
Run all tests:
cargo test --allRun specific test suites:
cargo test --test lib # Integration tests
cargo test --test properties # Property-based tests
cargo test --test security # Security tests
cargo test --test thread_safety # Concurrency testsRun benchmarks:
cargo benchRun fuzzing (requires cargo-fuzz):
cargo install cargo-fuzz
cargo fuzz run fuzz_decode
cargo fuzz run fuzz_encode
cargo fuzz run fuzz_roundtripGenerate and view the documentation:
cargo doc --openAdditional documentation:
- SECURITY.md - Security review and best practices
- CONCURRENCY.md - Thread safety analysis
- CHANGELOG.md - Version history and migration notes
This Repo: @dhuseby.
Captain: @dignifiedquire.
Contributors: @koushiro, and others.
Contributions welcome! Please check out the issues.
Check out our contributing document for more information on how we work, and about contributing in general.
Please be aware that all interactions related to multiformats are subject to the IPFS Code of Conduct.
- Run
cargo fmtbefore committing - Run
cargo clippy -- -D warningsto check for issues - Add tests for new features
- Update documentation for API changes
- Run full test suite:
cargo test --all
Small note: If editing the README, please conform to the standard-readme specification.
MIT Β© Friedel Ziegelmayer