1use core::fmt::Write;
9
10use crate::error::AddressParseError;
11
12const ALPHABET: &[u8; 58] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
14
15pub const ENCODED_LEN: usize = 44;
17
18pub fn encode(bytes: &[u8; 32]) -> [u8; ENCODED_LEN] {
20 let mut out = [ALPHABET[0]; ENCODED_LEN];
21 let mut num = *bytes;
22 for slot in out.iter_mut().rev() {
23 let mut rem = 0u32;
24 for byte in num.iter_mut() {
25 let acc = (rem << 8) | u32::from(*byte);
26 *byte = (acc / 58) as u8;
27 rem = acc % 58;
28 }
29 *slot = ALPHABET[rem as usize];
30 }
31 out
32}
33
34pub fn decode(digits: &[u8]) -> Result<[u8; 32], AddressParseError> {
36 if digits.len() != ENCODED_LEN {
37 return Err(AddressParseError::InvalidLength);
38 }
39 let mut out = [0u8; 32];
40 for &digit in digits {
41 let mut carry = u32::from(digit_value(digit)?);
42 for byte in out.iter_mut().rev() {
43 let acc = u32::from(*byte) * 58 + carry;
44 *byte = acc as u8;
45 carry = acc >> 8;
46 }
47 if carry != 0 {
48 return Err(AddressParseError::Overflow);
49 }
50 }
51 Ok(out)
52}
53
54fn digit_value(digit: u8) -> Result<u8, AddressParseError> {
55 ALPHABET
56 .iter()
57 .position(|&c| c == digit)
58 .map(|index| index as u8)
59 .ok_or(AddressParseError::InvalidCharacter)
60}
61
62pub(crate) fn fmt_hint(
70 f: &mut core::fmt::Formatter<'_>,
71 hint: &[u8],
72 budget: usize,
73) -> core::fmt::Result {
74 let mut lo = [0x00u8; 32];
75 let mut hi = [0xFFu8; 32];
76 lo[..hint.len()].copy_from_slice(hint);
77 hi[..hint.len()].copy_from_slice(hint);
78 let lo = encode(&lo);
79 let hi = encode(&hi);
80 for (&a, &b) in lo.iter().zip(hi.iter()).take(budget) {
81 if a != b {
82 return f.write_char('*');
83 }
84 f.write_char(char::from(a))?;
85 }
86 Ok(())
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 const ZERO: [u8; 32] = [0u8; 32];
94 const MAX: [u8; 32] = [0xFFu8; 32];
95
96 fn leading_zero_key() -> [u8; 32] {
97 let mut key = [0u8; 32];
98 for (i, byte) in key.iter_mut().enumerate() {
99 *byte = i as u8;
100 }
101 key
102 }
103
104 #[test]
105 fn encode_matches_reference_vectors() {
106 assert_eq!(
107 &encode(&ZERO),
108 b"11111111111111111111111111111111111111111111"
109 );
110 assert_eq!(
111 &encode(&MAX),
112 b"JEKNVnkbo3jma5nREBBJCDoXFVeKkD56V3xKrvRmWxFG"
113 );
114
115 let mut one = ZERO;
116 one[31] = 1;
117 assert_eq!(
118 &encode(&one),
119 b"11111111111111111111111111111111111111111112"
120 );
121
122 assert_eq!(
123 &encode(&leading_zero_key()),
124 b"111thX6LZfHDZZKUs92febYZhYRcXddmzfzF2NvTkPNE"
125 );
126 }
127
128 #[test]
129 fn decode_round_trips() {
130 for key in [ZERO, MAX, leading_zero_key()] {
131 assert_eq!(decode(&encode(&key)).unwrap(), key);
132 }
133 }
134
135 #[test]
136 fn decode_rejects_bad_input() {
137 assert_eq!(decode(b"7NeD"), Err(AddressParseError::InvalidLength));
138 for bad in [b'0', b'O', b'I', b'l'] {
140 let mut digits = *b"11111111111111111111111111111111111111111111";
141 digits[10] = bad;
142 assert_eq!(decode(&digits), Err(AddressParseError::InvalidCharacter));
143 }
144 assert_eq!(
145 decode(&[b'z'; ENCODED_LEN]),
146 Err(AddressParseError::Overflow)
147 );
148 }
149}