Skip to content

Repository files navigation

multi-base

Build StatusLicenseCrates.ioDocumentationCoverage Status

A multibase implementation in Rust. The crate gives encoding and decoding with error handling, type safety, and no_std support.

The crate is published as multi-base on crates.io. Import it as multi_base in Rust.

Table of Contents

Features

  • 24 base encodings.
  • Zero-copy buffer reuse APIs: encode_into and decode_into.
  • #[inline] on hot encode and decode paths.
  • Pre-allocated exact-capacity encoding.
  • Validated EncodedString newtype. Parse, do not validate.
  • #![deny(unsafe_code)] set at the crate root.
  • No panics on untrusted input.
  • Fuzzing infrastructure with cargo-fuzz.
  • All types are Send + Sync. No interior mutability.
  • no_std support with alloc.
  • WebAssembly compatible.
  • 142 tests: unit, integration, property-based, security, concurrency, and documentation tests.

Install

Add this to your Cargo.toml:

[dependencies]
multi-base = "1.1"

For no_std environments:

[dependencies]
multi-base = { version = "1.1", default-features = false }

MSRV: Rust 1.85 (Edition 2024).

Usage

Basic Usage

use multi_base::{Base, encode, decode};// Encode datalet encoded = encode(Base::Base64,b"hello world");println!("{}", encoded);// "maGVsbG8gd29ybGQ"// Decode datalet(base, data) = decode(&encoded,true)?;assert_eq!(base,Base::Base64);assert_eq!(data,b"hello world");

Buffer Reuse for Performance

When you encode or decode multiple values, reuse buffers to avoid allocations:

use multi_base::{Base, encode_into, decode_into};letmut encode_buffer = String::new();letmut decode_buffer = Vec::new();for data in dataset {// Encode into the existing buffer. No allocation.encode_into(Base::Base64, data,&mut encode_buffer);// Decode into the existing buffer. No allocation.let base = decode_into(&encode_buffer,true,&mut decode_buffer)?;// Process the decoded data.}

Type Safety with EncodedString

Use EncodedString for validated multibase strings:

use multi_base::{EncodedString,Base};// Parse and validate at constructionlet encoded = EncodedString::new("zCn8eVZg")?;// The base is known at compile timeassert_eq!(encoded.base(),Base::Base58Btc);// Decode directlylet data = encoded.decode()?;assert_eq!(data,b"hello");// Or use FromStrlet encoded:EncodedString = "md29ybGQ".parse()?;

Error Handling

The crate gives error types with context:

use multi_base::{decode,Error};matchdecode(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);}}

Supported Bases

The crate supports 24 base encodings:

BaseCodeAlphabet
Identity\08-bit binary (no encoding)
Base2001
Base8701234567
Base1090123456789
Base16 (Lower)f0123456789abcdef
Base16 (Upper)F0123456789ABCDEF
Base32 (Lower)bRFC 4648 (no padding)
Base32 (Upper)BRFC 4648 (no padding)
Base32Pad (Lower)cRFC 4648 (with padding)
Base32Pad (Upper)CRFC 4648 (with padding)
Base32Hex (Lower)vRFC 4648 hex (no padding)
Base32Hex (Upper)VRFC 4648 hex (no padding)
Base32HexPad (Lower)tRFC 4648 hex (with padding)
Base32HexPad (Upper)TRFC 4648 hex (with padding)
Base32Zhz-base-32 (Tahoe-LAFS)
Base36 (Lower)k0123456789abcdefghijklmnopqrstuvwxyz
Base36 (Upper)K0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
Base58 FlickrZFlickr alphabet
Base58 BitcoinzBitcoin alphabet
Base64mRFC 4648 (no padding)
Base64PadMRFC 4648 (with padding)
Base64UrluRFC 4648 URL-safe (no padding)
Base64UrlPadURFC 4648 URL-safe (with padding)
Base256Emoji🚀Emoji alphabet

Performance

Base32 and Base64 are faster than other bases. This is because of byte alignment.

Optimization tips:

  1. Use encode_into() and decode_into() for buffer reuse in loops.
  2. Prefer Base32 or Base64 for performance-critical code.
  3. Use Base58 or Base16 when human readability is important.

Run cargo bench to see performance on your system.

Security

  • No panics on untrusted input.
  • #![deny(unsafe_code)] set at the crate root.
  • Input validation at all boundaries.
  • 17 security tests.
  • Fuzzing infrastructure with 3 targets: fuzz_decode, fuzz_encode, and fuzz_roundtrip.

Best practices:

  • For untrusted input, use strict mode: decode(input, true).
  • Set application-level size limits. See SECURITY.md.
  • For binary data preservation, do not use Identity encoding. Use Base64.

See SECURITY.md for the full security policy.

Concurrency

All public types are thread-safe:

  • All types implement Send + Sync.
  • No interior mutability.
  • No data races.
  • 20 thread safety tests verify these properties.

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 give the same result.}

See CONCURRENCY.md for detailed concurrency information.

CLI Tool

The crate includes a command-line tool in the cli/ directory.

Build the CLI:

cd cli
cargo build --release

Example usage:

# Encode dataecho"hello world"| multibase encode --base base64
# Decode dataecho"maGVsbG8gd29ybGQ"| multibase decode
# Specify input directly
multibase encode --base base58btc --input "hello world"

Testing

The crate has 142 tests:

  • 12 unit tests.
  • 63 integration tests.
  • 16 property-based tests with proptest.
  • 17 security tests.
  • 20 thread safety tests.
  • 14 documentation tests.

Run all tests:

cargo test --all

Run 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 tests

Run benchmarks:

cargo bench

Run fuzzing (requires cargo-fuzz):

cargo install cargo-fuzz
cargo fuzz run fuzz_decode
cargo fuzz run fuzz_encode
cargo fuzz run fuzz_roundtrip

Documentation

Generate and view the documentation:

cargo doc --open

Additional documentation:

Maintainers

This repo: @dhuseby.

Original author: @dignifiedquire.

Contribute

Contributions are welcome. Please check out the issues.

Development Guidelines

  • Run cargo fmt before you commit.
  • Run cargo clippy -- -D warnings to check for issues.
  • Add tests for new features.
  • Update documentation for API changes.
  • Run the full test suite: cargo test --all.

License

MIT © Friedel Ziegelmayer

About

Multibase in rust

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages