1
2extern crate mazze_types;
7#[macro_use]
8extern crate lazy_static;
9extern crate rustc_hex;
10
11#[allow(dead_code)]
12pub mod checksum;
13pub mod consts;
14pub mod errors;
15#[cfg(test)]
16mod tests;
17
18use mazze_types::Address;
19use checksum::polymod;
20pub use consts::{AddressType, Network};
21pub use errors::DecodingError;
22use errors::*;
23
24const BASE32_CHARS: &str = "abcdefghijklmnopqrstuvwxyz0123456789";
25const EXCLUDE_CHARS: [char; 4] = ['o', 'i', 'l', 'q'];
26lazy_static! {
27 static ref REGEXP: String = format!{"(?i)[:=_-{}]*", BASE32_CHARS};
31
32 static ref CHARSET: Vec<u8> =
34 BASE32_CHARS.replace(&EXCLUDE_CHARS[..], "").into_bytes();
36
37 static ref CHAR_INDEX: [Option<u8>; 128] = (|| {
39 let mut index = [None; 128];
40 assert_eq!(CHARSET.len(), consts::CHARSET_SIZE);
41 for i in 0..consts::CHARSET_SIZE {
42 let c = CHARSET[i] as usize;
43 index[c] = Some(i as u8);
44 let u = (c as u8 as char).to_ascii_uppercase() as u8 as usize;
46 if u != c {
47 index[u] = Some(i as u8);
48 }
49 }
50 return index;
51 }) ();
52}
53
54#[derive(PartialEq, Eq, Clone, Debug, Hash)]
56pub struct DecodedRawAddress {
57 pub input_base32_address: String,
59 pub parsed_address_bytes: Vec<u8>,
61 pub hex_address: Option<Address>,
63 pub network: Network,
65}
66
67#[derive(Copy, Clone)]
68pub enum EncodingOptions {
69 Simple,
70 QrCode,
71}
72
73pub fn mazze_addr_encode(
75 raw: &[u8], network: Network, encoding_options: EncodingOptions,
76) -> Result<String, EncodingError> {
77 let length = raw.len();
79 let version_byte = match length {
80 20 => consts::SIZE_160,
81 24 => consts::SIZE_192,
84 28 => consts::SIZE_224,
85 32 => consts::SIZE_256,
86 40 => consts::SIZE_320,
87 48 => consts::SIZE_384,
88 56 => consts::SIZE_448,
89 64 => consts::SIZE_512,
90 _ => return Err(EncodingError::InvalidLength(length)),
91 };
92
93 let prefix = network.to_prefix()?;
95
96 let mut payload = Vec::with_capacity(1 + raw.len());
98 payload.push(version_byte);
99 payload.extend(raw);
100 let payload_5_bits = convert_bits(&payload, 8, 5, true)
101 .expect("no error is possible for encoding");
102
103 let payload_str: String = payload_5_bits
105 .iter()
106 .map(|b| CHARSET[*b as usize] as char)
107 .collect();
108
109 let expanded_prefix = expand_prefix(&prefix);
111 let checksum_input =
112 [&expanded_prefix[..], &payload_5_bits, &[0; 8][..]].concat();
113 let checksum = polymod(&checksum_input);
114
115 let checksum_str: String = (0..8)
117 .rev()
118 .map(|i| CHARSET[((checksum >> (i * 5)) & 31) as usize] as char)
119 .collect();
120
121 let mazze_base32_addr = match encoding_options {
123 EncodingOptions::Simple => {
124 [&prefix, ":", &payload_str, &checksum_str].concat()
125 }
126 EncodingOptions::QrCode => {
127 let addr_type_str = AddressType::from_address(&raw)?.to_str();
128 [
129 &prefix,
130 ":type.",
131 addr_type_str,
132 ":",
133 &payload_str,
134 &checksum_str,
135 ]
136 .concat()
137 .to_uppercase()
138 }
139 };
140 Ok(mazze_base32_addr)
141}
142
143pub fn mazze_addr_decode(
144 addr_str: &str,
145) -> Result<DecodedRawAddress, DecodingError> {
146 let has_lowercase = addr_str.chars().any(|c| c.is_lowercase());
148 let has_uppercase = addr_str.chars().any(|c| c.is_uppercase());
149 if has_lowercase && has_uppercase {
150 return Err(DecodingError::MixedCase);
151 }
152 let lowercase = addr_str.to_lowercase();
153
154 let parts: Vec<&str> = lowercase.split(':').collect();
156 if parts.len() < 2 {
157 return Err(DecodingError::NoPrefix);
158 }
159 let prefix = parts[0];
160 let network = Network::from_prefix(prefix)?;
162
163 let mut address_type = None;
164 for option_str in &parts[1..parts.len() - 1] {
166 let key_value: Vec<&str> = option_str.split('.').collect();
167 if key_value.len() != 2 {
168 return Err(DecodingError::InvalidOption(OptionError::ParseError(
169 (*option_str).into(),
170 )));
171 }
172 if key_value[0] == "type" {
174 address_type = Some(AddressType::parse(key_value[1])?);
175 }
176 }
177
178 let payload_str = parts[parts.len() - 1];
180 if payload_str.len() == 0 {
181 return Err(DecodingError::InvalidLength(0));
182 }
183 let has_lowercase = payload_str.chars().any(|c| c.is_lowercase());
184 let has_uppercase = payload_str.chars().any(|c| c.is_uppercase());
185 if has_lowercase && has_uppercase {
186 return Err(DecodingError::MixedCase);
187 }
188
189 let payload_chars = payload_str.chars();
191 let payload_5_bits: Result<Vec<u8>, DecodingError> = payload_chars
192 .map(|c| {
193 let i = c as usize;
194 if let Some(Some(d)) = CHAR_INDEX.get(i) {
195 Ok(*d as u8)
196 } else {
197 Err(DecodingError::InvalidChar(c))
198 }
199 })
200 .collect();
201 let payload_5_bits = payload_5_bits?;
202
203 let checksum =
205 polymod(&[&expand_prefix(prefix), &payload_5_bits[..]].concat());
206 if checksum != 0 {
207 return Err(DecodingError::ChecksumFailed(checksum));
211 }
212
213 let len_5_bit = payload_5_bits.len();
215 let payload =
216 convert_bits(&payload_5_bits[..(len_5_bit - 8)], 5, 8, false)?;
217
218 let version = payload[0];
220
221 let body = &payload[1..];
223 let body_len = body.len();
224 let version_size = version & consts::SIZE_MASK;
225 if (version_size == consts::SIZE_160 && body_len != 20)
226 || (version_size == consts::SIZE_192 && body_len != 24)
229 || (version_size == consts::SIZE_224 && body_len != 28)
230 || (version_size == consts::SIZE_256 && body_len != 32)
231 || (version_size == consts::SIZE_320 && body_len != 40)
232 || (version_size == consts::SIZE_384 && body_len != 48)
233 || (version_size == consts::SIZE_448 && body_len != 56)
234 || (version_size == consts::SIZE_512 && body_len != 64)
235 {
236 return Err(DecodingError::InvalidLength(body_len));
237 }
238 if version & consts::RESERVED_BITS_MASK != 0 {
240 return Err(DecodingError::VersionNotRecognized(version));
241 }
242
243 let hex_address;
244 if version_size == consts::SIZE_160 {
246 hex_address = Some(Address::from_slice(body));
247 match address_type {
248 Some(expected) => {
249 let got =
250 AddressType::from_address(hex_address.as_ref().unwrap())
251 .or(Err(()));
252 if got.as_ref() != Ok(&expected) {
253 return Err(DecodingError::InvalidOption(
254 OptionError::AddressTypeMismatch { expected, got },
255 ));
256 }
257 }
258 None => {}
259 }
260 } else {
261 hex_address = None;
262 }
263
264 Ok(DecodedRawAddress {
265 input_base32_address: addr_str.into(),
266 parsed_address_bytes: body.to_vec(),
267 hex_address,
268 network,
269 })
270}
271
272fn expand_prefix(prefix: &str) -> Vec<u8> {
277 let mut ret: Vec<u8> = prefix.chars().map(|c| (c as u8) & 0x1f).collect();
278 ret.push(0);
279 ret
280}
281
282fn convert_bits(
286 data: &[u8], inbits: u8, outbits: u8, pad: bool,
287) -> Result<Vec<u8>, DecodingError> {
288 assert!(inbits <= 8 && outbits <= 8);
289 let num_bytes = (data.len() * inbits as usize + outbits as usize - 1)
290 / outbits as usize;
291 let mut ret = Vec::with_capacity(num_bytes);
292 let mut acc: u16 = 0; let mut num: u8 = 0; let groupmask = (1 << outbits) - 1;
295 for d in data.iter() {
296 acc = (acc << inbits) | u16::from(*d);
298 num += inbits;
299 while num >= outbits {
301 ret.push((acc >> (num - outbits)) as u8);
303 acc &= !(groupmask << (num - outbits));
305 num -= outbits;
306 }
307 }
308 if pad {
309 if num > 0 {
311 ret.push((acc << (outbits - num)) as u8);
312 }
313 } else {
314 let padding = ((data.len() * inbits as usize) % outbits as usize) as u8;
318 if num >= inbits || acc != 0 {
319 return Err(DecodingError::InvalidPadding {
320 from_bits: inbits,
321 padding_bits: padding,
322 padding: acc,
323 });
324 }
325 }
326 Ok(ret)
327}
328
329#[test]
330fn test_expand_prefix() {
331 assert_eq!(expand_prefix("mazze"), vec![0x03, 0x06, 0x18, 0x00]);
332
333 assert_eq!(
334 expand_prefix("mazzetest"),
335 vec![0x03, 0x06, 0x18, 0x14, 0x05, 0x13, 0x14, 0x00]
336 );
337
338 assert_eq!(
339 expand_prefix("net17"),
340 vec![0x0e, 0x05, 0x14, 0x11, 0x17, 0x00]
341 );
342}
343
344#[test]
345fn test_convert_bits() {
346 assert_eq!(convert_bits(&[0], 8, 1, false), Ok(vec![0; 8]));
348
349 assert_eq!(convert_bits(&[0], 8, 3, false), Ok(vec![0, 0])); assert_eq!(convert_bits(&[0], 8, 3, true), Ok(vec![0, 0, 0])); assert!(convert_bits(&[1], 8, 3, false).is_err()); assert_eq!(convert_bits(&[1], 8, 3, true), Ok(vec![0, 0, 2])); assert_eq!(convert_bits(&[1], 8, 7, true), Ok(vec![0, 64])); assert_eq!(convert_bits(&[0; 8], 1, 8, false), Ok(vec![0]));
362
363 assert_eq!(convert_bits(&[0, 0, 2], 3, 8, false), Ok(vec![1])); assert_eq!(convert_bits(&[0, 0, 2], 3, 8, true), Ok(vec![1, 0])); assert!(convert_bits(&[0, 0, 3], 3, 8, false).is_err()); assert_eq!(
373 convert_bits(&[0, 1, 2, 3, 4], 8, 5, false),
374 Ok(vec![0, 0, 0, 16, 4, 0, 24, 4])
375 );
376
377 assert!(convert_bits(&[0, 1, 2], 8, 5, false).is_err()); assert_eq!(
382 convert_bits(&[0, 1, 2], 8, 5, true),
383 Ok(vec![0, 0, 0, 16, 4])
384 ); assert_eq!(
389 convert_bits(&[0, 0, 0, 16, 4, 0, 24, 4], 5, 8, false),
390 Ok(vec![0, 1, 2, 3, 4])
391 );
392
393 assert_eq!(
396 convert_bits(&[0, 0, 0, 16, 4], 5, 8, false),
397 Ok(vec![0, 1, 2])
398 ); assert_eq!(
401 convert_bits(&[0, 0, 0, 16, 4], 5, 8, true),
402 Ok(vec![0, 1, 2, 0])
403 ); }