1#![cfg_attr(not(feature = "std"), no_std)]
9
10mod consts;
11mod types;
12mod utils;
13
14pub use consts::*;
15pub use types::*;
16pub use utils::*;
17
18#[cfg(not(feature = "std"))]
19extern crate alloc;
20
21#[cfg(not(feature = "std"))]
22use alloc::{string::String, vec::Vec};
23
24use cfx_types::Address;
25
26pub fn cfx_addr_encode(
27 raw: &[u8], network: Network, encoding_options: EncodingOptions,
28) -> Result<String, EncodingError> {
29 let length = raw.len();
31 let version_byte = match length {
32 20 => consts::SIZE_160,
33 24 => consts::SIZE_192,
36 28 => consts::SIZE_224,
37 32 => consts::SIZE_256,
38 40 => consts::SIZE_320,
39 48 => consts::SIZE_384,
40 56 => consts::SIZE_448,
41 64 => consts::SIZE_512,
42 _ => return Err(EncodingError::InvalidLength(length)),
43 };
44
45 let prefix = network.to_prefix()?;
47
48 let mut payload = Vec::with_capacity(1 + raw.len());
50 payload.push(version_byte);
51 payload.extend(raw);
52 let payload_5_bits = convert_bits(&payload, 8, 5, true)
53 .expect("no error is possible for encoding");
54
55 let payload_str: String = payload_5_bits
57 .iter()
58 .map(|b| CHARSET[*b as usize] as char)
59 .collect();
60
61 let expanded_prefix = expand_prefix(&prefix);
63 let checksum_input =
64 [&expanded_prefix[..], &payload_5_bits, &[0; 8][..]].concat();
65 let checksum = polymod(&checksum_input);
66
67 let checksum_str: String = (0..8)
69 .rev()
70 .map(|i| CHARSET[((checksum >> (i * 5)) & 31) as usize] as char)
71 .collect();
72
73 let cfx_base32_addr = match encoding_options {
75 EncodingOptions::Simple => {
76 [&prefix, ":", &payload_str, &checksum_str].concat()
77 }
78 EncodingOptions::QrCode => {
79 let addr_type_str = AddressType::from_address(&raw)?.to_str();
80 [
81 &prefix,
82 ":type.",
83 addr_type_str,
84 ":",
85 &payload_str,
86 &checksum_str,
87 ]
88 .concat()
89 .to_uppercase()
90 }
91 };
92 Ok(cfx_base32_addr)
93}
94
95pub fn cfx_addr_decode(
96 addr_str: &str,
97) -> Result<DecodedRawAddress, DecodingError> {
98 let has_lowercase = addr_str.chars().any(|c| c.is_lowercase());
99 let has_uppercase = addr_str.chars().any(|c| c.is_uppercase());
100 if has_lowercase && has_uppercase {
101 return Err(DecodingError::MixedCase);
102 }
103 let lowercase = addr_str.to_lowercase();
104
105 let parts: Vec<&str> = lowercase.split(':').collect();
107 if parts.len() < 2 {
108 return Err(DecodingError::NoPrefix);
109 }
110 let prefix = parts[0];
111 let network = Network::from_prefix(prefix)?;
113
114 let mut address_type = None;
115 for option_str in &parts[1..parts.len() - 1] {
117 let key_value: Vec<&str> = option_str.split('.').collect();
118 if key_value.len() != 2 {
119 return Err(DecodingError::InvalidOption(OptionError::ParseError(
120 (*option_str).into(),
121 )));
122 }
123 if key_value[0] == "type" {
125 address_type = Some(AddressType::parse(key_value[1])?);
126 }
127 }
128
129 let payload_str = parts[parts.len() - 1];
131 if payload_str.len() == 0 {
132 return Err(DecodingError::InvalidLength(0));
133 }
134 let has_lowercase = payload_str.chars().any(|c| c.is_lowercase());
135 let has_uppercase = payload_str.chars().any(|c| c.is_uppercase());
136 if has_lowercase && has_uppercase {
137 return Err(DecodingError::MixedCase);
138 }
139
140 let payload_chars = payload_str.chars();
142 let payload_5_bits: Result<Vec<u8>, DecodingError> = payload_chars
143 .map(|c| {
144 let i = c as usize;
145 if let Some(Some(d)) = CHAR_INDEX.get(i) {
146 Ok(*d as u8)
147 } else {
148 Err(DecodingError::InvalidChar(c))
149 }
150 })
151 .collect();
152 let payload_5_bits = payload_5_bits?;
153
154 let checksum =
156 polymod(&[&expand_prefix(prefix), &payload_5_bits[..]].concat());
157 if checksum != 0 {
158 return Err(DecodingError::ChecksumFailed(checksum));
162 }
163
164 let len_5_bit = payload_5_bits.len();
166 let payload =
167 convert_bits(&payload_5_bits[..(len_5_bit - 8)], 5, 8, false)?;
168
169 let version = payload[0];
171
172 let body = &payload[1..];
174 let body_len = body.len();
175 let version_size = version & consts::SIZE_MASK;
176 if (version_size == consts::SIZE_160 && body_len != 20)
177 || (version_size == consts::SIZE_192 && body_len != 24)
180 || (version_size == consts::SIZE_224 && body_len != 28)
181 || (version_size == consts::SIZE_256 && body_len != 32)
182 || (version_size == consts::SIZE_320 && body_len != 40)
183 || (version_size == consts::SIZE_384 && body_len != 48)
184 || (version_size == consts::SIZE_448 && body_len != 56)
185 || (version_size == consts::SIZE_512 && body_len != 64)
186 {
187 return Err(DecodingError::InvalidLength(body_len));
188 }
189 if version & consts::RESERVED_BITS_MASK != 0 {
191 return Err(DecodingError::VersionNotRecognized(version));
192 }
193
194 let hex_address;
195 if version_size == consts::SIZE_160 {
197 hex_address = Some(Address::from_slice(body));
198 match address_type {
199 Some(expected) => {
200 let got =
201 AddressType::from_address(hex_address.as_ref().unwrap())
202 .or(Err(()));
203 if got.as_ref() != Ok(&expected) {
204 return Err(DecodingError::InvalidOption(
205 OptionError::AddressTypeMismatch { expected, got },
206 ));
207 }
208 }
209 None => {}
210 }
211 } else {
212 hex_address = None;
213 }
214
215 Ok(DecodedRawAddress {
216 input_base32_address: addr_str.into(),
217 parsed_address_bytes: body.to_vec(),
218 hex_address,
219 network,
220 })
221}