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.is_empty() {
132 return Err(DecodingError::InvalidLength(0));
133 }
134
135 let payload_chars = payload_str.chars();
137 let payload_5_bits: Result<Vec<u8>, DecodingError> = payload_chars
138 .map(|c| {
139 let i = c as usize;
140 if let Some(Some(d)) = CHAR_INDEX.get(i) {
141 Ok(*d)
142 } else {
143 Err(DecodingError::InvalidChar(c))
144 }
145 })
146 .collect();
147 let payload_5_bits = payload_5_bits?;
148
149 let checksum =
151 polymod(&[&expand_prefix(prefix), &payload_5_bits[..]].concat());
152 if checksum != 0 {
153 return Err(DecodingError::ChecksumFailed(checksum));
157 }
158
159 let len_5_bit = payload_5_bits.len();
162 if len_5_bit <= 8 {
163 return Err(DecodingError::InvalidLength(len_5_bit));
164 }
165 let payload =
167 convert_bits(&payload_5_bits[..(len_5_bit - 8)], 5, 8, false)?;
168 if payload.is_empty() {
169 return Err(DecodingError::InvalidLength(0));
170 }
171
172 let version = payload[0];
174
175 let body = &payload[1..];
177 let body_len = body.len();
178 let version_size = version & consts::SIZE_MASK;
179 if (version_size == consts::SIZE_160 && body_len != 20)
180 || (version_size == consts::SIZE_192 && body_len != 24)
183 || (version_size == consts::SIZE_224 && body_len != 28)
184 || (version_size == consts::SIZE_256 && body_len != 32)
185 || (version_size == consts::SIZE_320 && body_len != 40)
186 || (version_size == consts::SIZE_384 && body_len != 48)
187 || (version_size == consts::SIZE_448 && body_len != 56)
188 || (version_size == consts::SIZE_512 && body_len != 64)
189 {
190 return Err(DecodingError::InvalidLength(body_len));
191 }
192 if version & consts::RESERVED_BITS_MASK != 0 {
194 return Err(DecodingError::VersionNotRecognized(version));
195 }
196
197 let hex_address;
198 if version_size == consts::SIZE_160 {
200 hex_address = Some(Address::from_slice(body));
201 if let Some(expected) = address_type {
202 let got = AddressType::from_address(hex_address.as_ref().unwrap())
203 .or(Err(()));
204 if got.as_ref() != Ok(&expected) {
205 return Err(DecodingError::InvalidOption(
206 OptionError::AddressTypeMismatch { expected, got },
207 ));
208 }
209 }
210 } else {
211 hex_address = None;
212 }
213
214 Ok(DecodedRawAddress {
215 input_base32_address: addr_str.into(),
216 parsed_address_bytes: body.to_vec(),
217 hex_address,
218 network,
219 })
220}