1use std::{fmt, str};
2
3use super::Id;
4use crate::finite::Empty;
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
7#[error("invalid base58")]
8pub struct Error;
9
10pub type Result<T, E = Error> = std::result::Result<T, E>;
11
12#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
13#[cfg_attr(feature = "serde", derive(DeserializeFromStr, SerializeDisplay))]
14pub struct Base58 {
15 bytes: Vec<u8>,
16 string: String,
17}
18
19impl Empty for Id {
20 const EMPTY: Self = Id(0);
21
22 fn is_empty(&self) -> bool {
23 *self == Self::EMPTY
24 }
25}
26
27impl fmt::Display for Id {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 Base58::encode(&self.0.to_be_bytes()).fmt(f)
30 }
31}
32
33impl str::FromStr for Id {
34 type Err = Error;
35
36 fn from_str(s: &str) -> Result<Self, Self::Err> {
37 let bytes = Base58::decode(s)?;
38 let bytes: [u8; 16] = bytes.try_into().map_err(|_| Error)?;
39 Ok(Self(u128::from_be_bytes(bytes)))
40 }
41}
42
43#[cfg(feature = "serde")]
44impl serde::Serialize for Id {
45 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
46 where
47 S: serde::Serializer,
48 {
49 if serializer.is_human_readable() {
50 serializer.serialize_str(&self.to_string())
51 } else {
52 serializer.serialize_bytes(&self.0.to_be_bytes())
53 }
54 }
55}
56
57#[cfg(feature = "serde")]
58impl<'de> serde::Deserialize<'de> for Id {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: serde::Deserializer<'de>,
62 {
63 use serde::de::Visitor;
64
65 struct IdVisitor;
66
67 impl<'de> Visitor<'de> for IdVisitor {
68 type Value = Id;
69
70 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
71 formatter.write_str("a base58 string or 16 bytes")
72 }
73
74 fn visit_str<E>(self, value: &str) -> Result<Id, E>
75 where
76 E: serde::de::Error,
77 {
78 value.parse().map_err(E::custom)
79 }
80
81 fn visit_bytes<E>(self, value: &[u8]) -> Result<Id, E>
82 where
83 E: serde::de::Error,
84 {
85 let bytes: [u8; 16] = value.try_into().map_err(|_| E::custom("invalid id"))?;
86 Ok(Id(u128::from_be_bytes(bytes)))
87 }
88
89 fn visit_seq<A>(self, mut seq: A) -> Result<Id, A::Error>
90 where
91 A: serde::de::SeqAccess<'de>,
92 {
93 let mut bytes = [0u8; 16];
94 for (index, byte) in bytes.iter_mut().enumerate() {
95 *byte = seq
96 .next_element()?
97 .ok_or_else(|| serde::de::Error::invalid_length(index, &self))?;
98 }
99 if seq.next_element::<u8>()?.is_some() {
100 return Err(serde::de::Error::invalid_length(17, &self));
101 }
102 Ok(Id(u128::from_be_bytes(bytes)))
103 }
104 }
105
106 if deserializer.is_human_readable() {
107 deserializer.deserialize_str(IdVisitor)
108 } else {
109 deserializer.deserialize_bytes(IdVisitor)
110 }
111 }
112}
113
114impl Base58 {
115 pub const LETTERS: [u8; 58] = *b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
116
117 pub const OCTETS: [u8; 128] = {
118 let mut octets = [0xff; 128];
119 let mut index = 0;
120 while index < Self::LETTERS.len() {
121 octets[Self::LETTERS[index] as usize] = index as u8;
122 index += 1;
123 }
124 octets
125 };
126
127 pub fn new(bytes: &[u8]) -> Self {
128 Self { bytes: bytes.to_vec(), string: Self::encode(bytes) }
129 }
130
131 pub fn parse(s: &str) -> Result<Self> {
132 s.parse()
133 }
134
135 pub fn random_bytes(len: usize) -> Self {
136 use rand::RngExt as _;
137
138 let mut vec = vec![0u8; len];
139 rand::rng().fill(vec.as_mut_slice());
140 Self::new(&vec)
141 }
142
143 pub fn random_str(len: usize) -> Self {
144 use rand::RngExt as _;
145
146 let mut rng = rand::rng();
147 let string = (0..len)
148 .map(|_| Self::LETTERS[rng.random_range(0..Self::LETTERS.len())])
149 .collect::<Vec<_>>();
150 str::from_utf8(&string).unwrap().parse().unwrap()
151 }
152
153 pub fn encode(bytes: &[u8]) -> String {
154 let zeros = bytes.iter().take_while(|&&byte| byte == 0).count();
155 let mut digits = Vec::<u8>::new();
156 for &byte in bytes {
157 let mut carry = byte as u32;
158 for digit in &mut digits {
159 carry += (*digit as u32) << 8;
160 *digit = (carry % 58) as u8;
161 carry /= 58;
162 }
163 while carry > 0 {
164 digits.push((carry % 58) as u8);
165 carry /= 58;
166 }
167 }
168
169 let mut string = String::with_capacity(zeros + digits.len());
170 string.extend(core::iter::repeat_n('1', zeros));
171 string.extend(digits.iter().rev().map(|digit| Self::LETTERS[*digit as usize] as char));
172 string
173 }
174
175 pub fn decode(s: &str) -> Result<Vec<u8>> {
176 let zeros = s.bytes().take_while(|&byte| byte == b'1').count();
177 let mut bytes = Vec::<u8>::new();
178 for byte in s.bytes() {
179 if byte as usize >= Self::OCTETS.len() {
180 return Err(Error);
181 }
182 let digit = Self::OCTETS[byte as usize];
183 if digit == 0xff {
184 return Err(Error);
185 }
186 let mut carry = digit as u32;
187 for decoded in &mut bytes {
188 carry += (*decoded as u32) * 58;
189 *decoded = (carry & 0xff) as u8;
190 carry >>= 8;
191 }
192 while carry > 0 {
193 bytes.push((carry & 0xff) as u8);
194 carry >>= 8;
195 }
196 }
197
198 let mut decoded = vec![0; zeros];
199 decoded.extend(bytes.iter().rev());
200 Ok(decoded)
201 }
202
203 pub const fn as_bytes(&self) -> &[u8] {
204 self.bytes.as_slice()
205 }
206
207 pub const fn as_str(&self) -> &str {
208 self.string.as_str()
209 }
210}
211
212impl str::FromStr for Base58 {
213 type Err = Error;
214
215 fn from_str(s: &str) -> Result<Self> {
216 Ok(Self { bytes: Self::decode(s)?, string: s.to_string() })
217 }
218}
219
220impl fmt::Display for Base58 {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 self.string.fmt(f)
223 }
224}
225
226impl From<Base58> for String {
227 fn from(base58: Base58) -> Self {
228 base58.string
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::{Base58, Id};
235
236 #[test]
237 fn id_display_roundtrips() {
238 for id in [Id(0), Id(1), Id(u128::MAX), Id(0x0123_4567_89ab_cdef_fedc_ba98_7654_3210)] {
239 assert_eq!(id.to_string().parse::<Id>().unwrap(), id);
240 }
241 }
242
243 #[cfg(feature = "serde")]
244 #[test]
245 fn json_serializes_id_as_base58_string() {
246 let id = Id(0x0123_4567_89ab_cdef_fedc_ba98_7654_3210);
247 let json = serde_json::to_string(&id).unwrap();
248 assert!(json.starts_with('"'));
249 assert_eq!(serde_json::from_str::<Id>(&json).unwrap(), id);
250 }
251
252 #[test]
253 fn known_vectors() {
254 let vectors: &[(&[u8], &str)] = &[
255 (&[], ""),
256 (&[0], "1"),
257 (&[0, 0, 0, 1], "1112"),
258 (&[0x61], "2g"),
259 (&[0x62, 0x62, 0x62], "a3gV"),
260 (&[0x63, 0x63, 0x63], "aPEr"),
261 (
262 &[
263 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x6e, 0x67,
264 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
265 ],
266 "2cFupjhnEsSn59qHXstmK2ffpLv2",
267 ),
268 ];
269
270 for (bytes, encoded) in vectors {
271 assert_eq!(Base58::encode(bytes), *encoded);
272 assert_eq!(Base58::decode(encoded).unwrap(), *bytes);
273 let base58 = Base58::new(bytes);
274 assert_eq!(base58.as_str(), *encoded);
275 assert_eq!(base58.as_bytes(), *bytes);
276 }
277 }
278
279 #[test]
280 fn rejects_invalid_characters() {
281 for invalid in ["0", "O", "I", "l", "+", "/", "abc0"] {
282 assert!(Base58::decode(invalid).is_err());
283 assert!(Base58::parse(invalid).is_err());
284 }
285 }
286}