Skip to main content

chess/key/
base58.rs

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