1use crate::bases::BaseConversionError;
19
20pub trait ToBase58 {
22 fn to_base58(&self) -> String;
24}
25
26pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], u8), BaseConversionError> {
28 let mut source = base58_data;
29 let mut count_leading_1 = 0;
30 while !source.is_empty() && &source[0..1] == "1" {
31 source = &source[1..];
32 count_leading_1 += 1;
33 }
34
35 let mut u8_array = [0; 32];
36 match bs58::decode(source).into(&mut u8_array) {
37 Ok(written_len) => {
38 if written_len == 32 {
39 Ok((u8_array, count_leading_1))
40 } else {
41 let delta = 32 - written_len;
42 for i in (0..written_len).rev() {
43 u8_array[i + delta] = u8_array[i];
44 }
45 #[allow(clippy::needless_range_loop)]
46 for i in 0..delta {
47 u8_array[i] = 0;
48 }
49 Ok((u8_array, count_leading_1))
50 }
51 }
52 Err(bs58::decode::Error::InvalidCharacter { character, index }) => {
53 Err(BaseConversionError::InvalidCharacter {
54 character,
55 offset: index,
56 })
57 }
58 Err(bs58::decode::Error::BufferTooSmall) => str_base58_to_32bytes_vec(base58_data),
59 _ => Err(BaseConversionError::UnknownError),
60 }
61}
62
63fn str_base58_to_32bytes_vec(base58_data: &str) -> Result<([u8; 32], u8), BaseConversionError> {
65 let mut source = base58_data;
66 let mut count_leading_1 = 0;
67 while !source.is_empty() && &source[0..1] == "1" {
68 source = &source[1..];
69 count_leading_1 += 1;
70 }
71
72 let mut u8_array = [0; 32];
73 match bs58::decode(source).into_vec() {
74 Ok(bytes) => {
75 let len = std::cmp::min(bytes.len(), 32);
76 u8_array[(32 - len)..].copy_from_slice(&bytes[..len]);
77 Ok((u8_array, count_leading_1))
78 }
79 Err(bs58::decode::Error::InvalidCharacter { character, index }) => {
80 Err(BaseConversionError::InvalidCharacter {
81 character,
82 offset: index,
83 })
84 }
85 Err(bs58::decode::Error::BufferTooSmall) => {
86 Err(BaseConversionError::InvalidBaseConverterLength)
87 }
88 _ => Err(BaseConversionError::UnknownError),
89 }
90}
91
92pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: u8) -> String {
94 let mut str_base58 = String::new();
95 let mut remaining_leading_1 = count_leading_1;
96 while remaining_leading_1 > 0 {
97 remaining_leading_1 -= 1;
98 str_base58.push('1');
99 }
100 if count_leading_1 >= 32 {
101 return str_base58;
102 }
103
104 let bytes_len = bytes.len();
105 let mut i = 0;
106 while i < bytes_len && bytes[i] == 0 {
107 i += 1;
108 }
109 str_base58.push_str(&bs58::encode(&bytes[i..]).into_string());
110 str_base58
111}
112
113#[cfg(test)]
114mod tests {
115
116 use super::*;
117
118 #[test]
119 fn test_base_58_str_with_only_1() -> Result<(), BaseConversionError> {
120 let base58str = "11111111111111111111111111111111111111111111";
121
122 let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?;
123
124 assert_eq!(count_leading_1, 44);
125
126 println!("{:?}", bytes);
127
128 assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),);
129
130 Ok(())
131 }
132
133 #[test]
134 fn test_base_58_str_with_leading_1() -> Result<(), BaseConversionError> {
135 let base58str = "13fn6X3XWVgshHTgS8beZMo9XiyScx6MB6yPsBB5ZBia";
136
137 let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?;
138
139 println!("{:?}", bytes);
140
141 assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),);
142
143 Ok(())
144 }
145
146 #[test]
147 fn test_other_base_58_str_with_leading_1() -> Result<(), BaseConversionError> {
148 let base58str = "1V27SH9TiVEDs8TWFPydpRKxhvZari7wjGwQnPxMnkr";
149
150 let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?;
151
152 println!("{:?}", bytes);
153
154 assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),);
155
156 Ok(())
157 }
158
159 #[test]
160 fn test_third_base_58_str_with_leading_1() -> Result<(), BaseConversionError> {
161 let base58str = "1XoFs76G4yidvVY3FZBwYyLXTMjabryhFD8mNQPkQKHk";
162
163 let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?;
164
165 println!("{:?}", bytes);
166
167 assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),);
168
169 Ok(())
170 }
171
172 #[test]
173 fn test_base_58_str_with_43_char() -> Result<(), BaseConversionError> {
174 let base58str = "2nV7Dv4nhTJ9dZUvRJpL34vFP9b2BkDjKWv9iBW2JaR";
175
176 let (bytes, count_leading_1) = str_base58_to_32bytes(base58str)?;
177
178 println!("{}", count_leading_1);
179 println!("{:?}", bytes);
180
181 assert_eq!(base58str, &bytes_to_str_base58(&bytes[..], count_leading_1),);
182
183 Ok(())
184 }
185
186 #[test]
187 fn test_invalid_pubkey_of_33_bytes() -> Result<(), BaseConversionError> {
188 str_base58_to_32bytes("jUPLL2BgY2QpheWEY3R13edV2Y4tvQMCXjJVM8PGDvyd")?;
189 Ok(())
190 }
191}
192
193