bs58/lib.rs
1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![warn(missing_copy_implementations)]
4#![warn(missing_debug_implementations)]
5#![warn(missing_docs)]
6#![warn(trivial_casts)]
7#![warn(trivial_numeric_casts)]
8#![warn(unused_extern_crates)]
9#![warn(unused_import_braces)]
10#![warn(variant_size_differences)]
11// This would be forbid, except unsafe is necessary to work with `&mut str`,
12// nowhere else should use it
13#![deny(unsafe_code)]
14#![doc(test(attr(deny(warnings))))]
15
16//! Another [Base58][] codec implementation.
17//!
18//! Compared to [`base58`][] this is significantly faster at decoding (about
19//! 2.4x as fast when decoding 32 bytes), almost the same speed for encoding
20//! (about 3% slower when encoding 32 bytes) and doesn't have the 128 byte
21//! limitation.
22//!
23//! Compared to [`rust-base58`][] this is massively faster (over ten times as
24//! fast when decoding 32 bytes, almost 40 times as fast when encoding 32
25//! bytes) and has no external dependencies.
26//!
27//! Compared to both this supports a configurable alphabet and user provided
28//! buffers for zero-allocation {en,de}coding.
29//!
30//! [Base58]: https://en.wikipedia.org/wiki/Base58
31//! [`base58`]: https://github.com/debris/base58
32//! [`rust-base58`]: https://github.com/nham/rust-base58
33//!
34//! # Features
35//!
36//! Feature | Activation | Effect
37//! ---------|--------------------|--------
38//! `std` | **on**-by-default | Implement [`Error`](std::error::Error) for error types
39//! `alloc` | implied by `std` | Support encoding/decoding to [`Vec`](alloc::vec::Vec) and [`String`](alloc::string::String) as appropriate
40//! `check` | **off**-by-default | Integrated support for [Base58Check][]
41//! `cb58` | **off**-by-default | Integrated support for [CB58][]
42//!
43//! [Base58Check]: https://en.bitcoin.it/wiki/Base58Check_encoding
44//! [CB58]: https://support.avax.network/en/articles/4587395-what-is-cb58
45//!
46//! # Examples
47//!
48//! ## Basic example
49//!
50//! ```rust
51//! let decoded = bs58::decode("he11owor1d").into_vec()?;
52//! let encoded = bs58::encode(decoded).into_string();
53//! assert_eq!("he11owor1d", encoded);
54//! # Ok::<(), bs58::decode::Error>(())
55//! ```
56//!
57//! ## Changing the alphabet
58//!
59//! ```rust
60//! let decoded = bs58::decode("he11owor1d")
61//! .with_alphabet(bs58::Alphabet::RIPPLE)
62//! .into_vec()?;
63//! let encoded = bs58::encode(decoded)
64//! .with_alphabet(bs58::Alphabet::FLICKR)
65//! .into_string();
66//! assert_eq!("4DSSNaN1SC", encoded);
67//! # Ok::<(), bs58::decode::Error>(())
68//! ```
69//!
70//! ## Decoding into an existing buffer
71//!
72//! ```rust
73//! let (mut decoded, mut encoded) = ([0xFF; 8], String::with_capacity(10));
74//! bs58::decode("he11owor1d").onto(&mut decoded)?;
75//! bs58::encode(decoded).onto(&mut encoded)?;
76//! assert_eq!("he11owor1d", encoded);
77//! # Ok::<(), Box<dyn std::error::Error>>(())
78//! ```
79
80#[cfg(feature = "std")]
81extern crate std;
82
83#[cfg(feature = "alloc")]
84extern crate alloc;
85
86pub mod alphabet;
87#[doc(inline)]
88pub use alphabet::Alphabet;
89
90pub mod decode;
91pub mod encode;
92
93#[cfg(any(feature = "check", feature = "cb58"))]
94const CHECKSUM_LEN: usize = 4;
95
96/// Possible check variants.
97enum Check {
98 Disabled,
99 #[cfg(feature = "check")]
100 Enabled(Option<u8>),
101 #[cfg(feature = "cb58")]
102 CB58(Option<u8>),
103}
104
105/// Setup decoder for the given string using the [default alphabet][Alphabet::DEFAULT].
106///
107/// # Examples
108///
109/// ## Basic example
110///
111/// ```rust
112/// assert_eq!(
113/// vec![0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58],
114/// bs58::decode("he11owor1d").into_vec()?);
115/// # Ok::<(), bs58::decode::Error>(())
116/// ```
117///
118/// ## Changing the alphabet
119///
120/// ```rust
121/// assert_eq!(
122/// vec![0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78],
123/// bs58::decode("he11owor1d")
124/// .with_alphabet(bs58::Alphabet::RIPPLE)
125/// .into_vec()?);
126/// # Ok::<(), bs58::decode::Error>(())
127/// ```
128///
129/// ## Decoding into an existing buffer
130///
131/// ```rust
132/// let mut output = [0xFF; 10];
133/// assert_eq!(8, bs58::decode("he11owor1d").onto(&mut output)?);
134/// assert_eq!(
135/// [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58, 0xFF, 0xFF],
136/// output);
137/// # Ok::<(), bs58::decode::Error>(())
138/// ```
139///
140/// ## Errors
141///
142/// ### Invalid Character
143///
144/// ```rust
145/// assert_eq!(
146/// bs58::decode::Error::InvalidCharacter { character: 'l', index: 2 },
147/// bs58::decode("hello world").into_vec().unwrap_err());
148/// ```
149///
150/// ### Non-ASCII Character
151///
152/// ```rust
153/// assert_eq!(
154/// bs58::decode::Error::NonAsciiCharacter { index: 5 },
155/// bs58::decode("he11o🇳🇿").into_vec().unwrap_err());
156/// ```
157///
158/// ### Too Small Buffer
159///
160/// This error can only occur when reading into a provided buffer, when using
161/// [`into_vec()`][decode::DecodeBuilder::into_vec] a vector large enough is guaranteed to be
162/// used.
163///
164/// ```rust
165/// let mut output = [0; 7];
166/// assert_eq!(
167/// bs58::decode::Error::BufferTooSmall,
168/// bs58::decode("he11owor1d").onto(&mut output).unwrap_err());
169/// ```
170pub const fn decode<I: AsRef<[u8]>>(input: I) -> decode::DecodeBuilder<'static, I> {
171 decode::DecodeBuilder::from_input(input)
172}
173
174/// Setup encoder for the given bytes using the [default alphabet][Alphabet::DEFAULT].
175///
176/// # Examples
177///
178/// ## Basic example
179///
180/// ```rust
181/// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58];
182/// assert_eq!("he11owor1d", bs58::encode(input).into_string());
183/// ```
184///
185/// ## Changing the alphabet
186///
187/// ```rust
188/// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78];
189/// assert_eq!(
190/// "he11owor1d",
191/// bs58::encode(input)
192/// .with_alphabet(bs58::Alphabet::RIPPLE)
193/// .into_string());
194/// ```
195///
196/// ## Encoding into an existing string
197///
198/// ```rust
199/// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58];
200/// let mut output = "goodbye world ".to_owned();
201/// bs58::encode(input).onto(&mut output)?;
202/// assert_eq!("goodbye world he11owor1d", output);
203/// # Ok::<(), bs58::encode::Error>(())
204/// ```
205///
206/// ## Errors
207///
208/// ### Too Small Buffer
209///
210/// This error can only occur when reading into an unresizeable buffer.
211///
212/// ```rust
213/// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58];
214/// let mut output = [0; 7];
215/// assert_eq!(
216/// bs58::encode::Error::BufferTooSmall,
217/// bs58::encode(input).onto(&mut output[..]).unwrap_err());
218/// ```
219pub fn encode<I: AsRef<[u8]>>(input: I) -> encode::EncodeBuilder<'static, I> {
220 encode::EncodeBuilder::from_input(input)
221}