1extern crate cfx_types;
9#[macro_use]
10extern crate lazy_static;
11extern crate rustc_hex;
12
13#[allow(dead_code)]
14pub mod checksum;
15pub mod consts;
16pub mod errors;
17#[cfg(test)]
18mod tests;
19
20use cfx_types::Address;
21use checksum::polymod;
22pub use consts::{AddressType, Network};
23pub use errors::DecodingError;
24use errors::*;
25
26const BASE32_CHARS: &str = "abcdefghijklmnopqrstuvwxyz0123456789";
27const EXCLUDE_CHARS: [char; 4] = ['o', 'i', 'l', 'q'];
28lazy_static! {
29 static ref REGEXP: String = format!{"(?i)[:=_-{}]*", BASE32_CHARS};
33
34 static ref CHARSET: Vec<u8> =
36 BASE32_CHARS.replace(&EXCLUDE_CHARS[..], "").into_bytes();
38
39 static ref CHAR_INDEX: [Option<u8>; 128] = (|| {
41 let mut index = [None; 128];
42 assert_eq!(CHARSET.len(), consts::CHARSET_SIZE);
43 for i in 0..consts::CHARSET_SIZE {
44 let c = CHARSET[i] as usize;
45 index[c] = Some(i as u8);
46 let u = (c as u8 as char).to_ascii_uppercase() as u8 as usize;
48 if u != c {
49 index[u] = Some(i as u8);
50 }
51 }
52 return index;
53 }) ();
54}
55
56#[derive(PartialEq, Eq, Clone, Debug, Hash)]
58pub struct DecodedRawAddress {
59 pub input_base32_address: String,
61 pub parsed_address_bytes: Vec<u8>,
63 pub hex_address: Option<Address>,
65 pub network: Network,
67}
68
69#[derive(Copy, Clone)]
70pub enum EncodingOptions {
71 Simple,
72 QrCode,
73}
74
75pub fn cfx_addr_encode(
77 raw: &[u8], network: Network, encoding_options: EncodingOptions,
78) -> Result<String, EncodingError> {
79 let length = raw.len();
81 let version_byte = match length {
82 20 => consts::SIZE_160,
83 24 => consts::SIZE_192,
86 28 => consts::SIZE_224,
87 32 => consts::SIZE_256,
88 40 => consts::SIZE_320,
89 48 => consts::SIZE_384,
90 56 => consts::SIZE_448,
91 64 => consts::SIZE_512,
92 _ => return Err(EncodingError::InvalidLength(length)),
93 };
94
95 let prefix = network.to_prefix()?;
97
98 let mut payload = Vec::with_capacity(1 + raw.len());
100 payload.push(version_byte);
101 payload.extend(raw);
102 let payload_5_bits = convert_bits(&payload, 8, 5, true)
103 .expect("no error is possible for encoding");
104
105 let payload_str: String = payload_5_bits
107 .iter()
108 .map(|b| CHARSET[*b as usize] as char)
109 .collect();
110
111 let expanded_prefix = expand_prefix(&prefix);
113 let checksum_input =
114 [&expanded_prefix[..], &payload_5_bits, &[0; 8][..]].concat();
115 let checksum = polymod(&checksum_input);
116
117 let checksum_str: String = (0..8)
119 .rev()
120 .map(|i| CHARSET[((checksum >> (i * 5)) & 31) as usize] as char)
121 .collect();
122
123 let cfx_base32_addr = match encoding_options {
125 EncodingOptions::Simple => {
126 [&prefix, ":", &payload_str, &checksum_str].concat()
127 }
128 EncodingOptions::QrCode => {
129 let addr_type_str = AddressType::from_address(&raw)?.to_str();
130 [
131 &prefix,
132 ":type.",
133 addr_type_str,
134 ":",
135 &payload_str,
136 &checksum_str,
137 ]
138 .concat()
139 .to_uppercase()
140 }
141 };
142 Ok(cfx_base32_addr)
143}
144
145pub fn cfx_addr_decode(
146 addr_str: &str,
147) -> Result<DecodedRawAddress, DecodingError> {
148 let has_lowercase = addr_str.chars().any(|c| c.is_lowercase());
150 let has_uppercase = addr_str.chars().any(|c| c.is_uppercase());
151 if has_lowercase && has_uppercase {
152 return Err(DecodingError::MixedCase);
153 }
154 let lowercase = addr_str.to_lowercase();
155
156 let parts: Vec<&str> = lowercase.split(':').collect();
158 if parts.len() < 2 {
159 return Err(DecodingError::NoPrefix);
160 }
161 let prefix = parts[0];
162 let network = Network::from_prefix(prefix)?;
164
165 let mut address_type = None;
166 for option_str in &parts[1..parts.len() - 1] {
168 let key_value: Vec<&str> = option_str.split('.').collect();
169 if key_value.len() != 2 {
170 return Err(DecodingError::InvalidOption(OptionError::ParseError(
171 (*option_str).into(),
172 )));
173 }
174 if key_value[0] == "type" {
176 address_type = Some(AddressType::parse(key_value[1])?);
177 }
178 }
179
180 let payload_str = parts[parts.len() - 1];
182 if payload_str.len() == 0 {
183 return Err(DecodingError::InvalidLength(0));
184 }
185 let has_lowercase = payload_str.chars().any(|c| c.is_lowercase());
186 let has_uppercase = payload_str.chars().any(|c| c.is_uppercase());
187 if has_lowercase && has_uppercase {
188 return Err(DecodingError::MixedCase);
189 }
190
191 let payload_chars = payload_str.chars();
193 let payload_5_bits: Result<Vec<u8>, DecodingError> = payload_chars
194 .map(|c| {
195 let i = c as usize;
196 if let Some(Some(d)) = CHAR_INDEX.get(i) {
197 Ok(*d as u8)
198 } else {
199 Err(DecodingError::InvalidChar(c))
200 }
201 })
202 .collect();
203 let payload_5_bits = payload_5_bits?;
204
205 let checksum =
207 polymod(&[&expand_prefix(prefix), &payload_5_bits[..]].concat());
208 if checksum != 0 {
209 return Err(DecodingError::ChecksumFailed(checksum));
213 }
214
215 let len_5_bit = payload_5_bits.len();
217 let payload =
218 convert_bits(&payload_5_bits[..(len_5_bit - 8)], 5, 8, false)?;
219
220 let version = payload[0];
222
223 let body = &payload[1..];
225 let body_len = body.len();
226 let version_size = version & consts::SIZE_MASK;
227 if (version_size == consts::SIZE_160 && body_len != 20)
228 || (version_size == consts::SIZE_192 && body_len != 24)
231 || (version_size == consts::SIZE_224 && body_len != 28)
232 || (version_size == consts::SIZE_256 && body_len != 32)
233 || (version_size == consts::SIZE_320 && body_len != 40)
234 || (version_size == consts::SIZE_384 && body_len != 48)
235 || (version_size == consts::SIZE_448 && body_len != 56)
236 || (version_size == consts::SIZE_512 && body_len != 64)
237 {
238 return Err(DecodingError::InvalidLength(body_len));
239 }
240 if version & consts::RESERVED_BITS_MASK != 0 {
242 return Err(DecodingError::VersionNotRecognized(version));
243 }
244
245 let hex_address;
246 if version_size == consts::SIZE_160 {
248 hex_address = Some(Address::from_slice(body));
249 match address_type {
250 Some(expected) => {
251 let got =
252 AddressType::from_address(hex_address.as_ref().unwrap())
253 .or(Err(()));
254 if got.as_ref() != Ok(&expected) {
255 return Err(DecodingError::InvalidOption(
256 OptionError::AddressTypeMismatch { expected, got },
257 ));
258 }
259 }
260 None => {}
261 }
262 } else {
263 hex_address = None;
264 }
265
266 Ok(DecodedRawAddress {
267 input_base32_address: addr_str.into(),
268 parsed_address_bytes: body.to_vec(),
269 hex_address,
270 network,
271 })
272}
273
274fn expand_prefix(prefix: &str) -> Vec<u8> {
279 let mut ret: Vec<u8> = prefix.chars().map(|c| (c as u8) & 0x1f).collect();
280 ret.push(0);
281 ret
282}
283
284fn convert_bits(
288 data: &[u8], inbits: u8, outbits: u8, pad: bool,
289) -> Result<Vec<u8>, DecodingError> {
290 assert!(inbits <= 8 && outbits <= 8);
291 let num_bytes = (data.len() * inbits as usize + outbits as usize - 1)
292 / outbits as usize;
293 let mut ret = Vec::with_capacity(num_bytes);
294 let mut acc: u16 = 0; let mut num: u8 = 0; let groupmask = (1 << outbits) - 1;
297 for d in data.iter() {
298 acc = (acc << inbits) | u16::from(*d);
300 num += inbits;
301 while num >= outbits {
303 ret.push((acc >> (num - outbits)) as u8);
305 acc &= !(groupmask << (num - outbits));
307 num -= outbits;
308 }
309 }
310 if pad {
311 if num > 0 {
313 ret.push((acc << (outbits - num)) as u8);
314 }
315 } else {
316 let padding = ((data.len() * inbits as usize) % outbits as usize) as u8;
320 if num >= inbits || acc != 0 {
321 return Err(DecodingError::InvalidPadding {
322 from_bits: inbits,
323 padding_bits: padding,
324 padding: acc,
325 });
326 }
327 }
328 Ok(ret)
329}
330
331#[test]
332fn test_expand_prefix() {
333 assert_eq!(expand_prefix("cfx"), vec![0x03, 0x06, 0x18, 0x00]);
334
335 assert_eq!(
336 expand_prefix("cfxtest"),
337 vec![0x03, 0x06, 0x18, 0x14, 0x05, 0x13, 0x14, 0x00]
338 );
339
340 assert_eq!(
341 expand_prefix("net17"),
342 vec![0x0e, 0x05, 0x14, 0x11, 0x17, 0x00]
343 );
344}
345
346#[test]
347fn test_convert_bits() {
348 assert_eq!(convert_bits(&[0], 8, 1, false), Ok(vec![0; 8]));
350
351 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]));
364
365 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!(
375 convert_bits(&[0, 1, 2, 3, 4], 8, 5, false),
376 Ok(vec![0, 0, 0, 16, 4, 0, 24, 4])
377 );
378
379 assert!(convert_bits(&[0, 1, 2], 8, 5, false).is_err()); assert_eq!(
384 convert_bits(&[0, 1, 2], 8, 5, true),
385 Ok(vec![0, 0, 0, 16, 4])
386 ); assert_eq!(
391 convert_bits(&[0, 0, 0, 16, 4, 0, 24, 4], 5, 8, false),
392 Ok(vec![0, 1, 2, 3, 4])
393 );
394
395 assert_eq!(
398 convert_bits(&[0, 0, 0, 16, 4], 5, 8, false),
399 Ok(vec![0, 1, 2])
400 ); assert_eq!(
403 convert_bits(&[0, 0, 0, 16, 4], 5, 8, true),
404 Ok(vec![0, 1, 2, 0])
405 ); }