darkfi/util/encoding/
base32.rs1use core::cmp::min;
23
24const ENCODE_STD: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
26
27pub fn encode(padding: bool, data: &[u8]) -> String {
29 let mut ret = Vec::with_capacity(data.len().div_ceil(4) * 5);
30
31 for chunk in data.chunks(5) {
32 let buf = {
33 let mut buf = [0u8; 5];
34 for (i, &b) in chunk.iter().enumerate() {
35 buf[i] = b;
36 }
37 buf
38 };
39
40 ret.push(ENCODE_STD[((buf[0] & 0xf8) >> 3) as usize]);
41 ret.push(ENCODE_STD[(((buf[0] & 0x07) << 2) | ((buf[1] & 0xc0) >> 6)) as usize]);
42 ret.push(ENCODE_STD[((buf[1] & 0x3e) >> 1) as usize]);
43 ret.push(ENCODE_STD[(((buf[1] & 0x01) << 4) | ((buf[2] & 0xf0) >> 4)) as usize]);
44 ret.push(ENCODE_STD[(((buf[2] & 0x0f) << 1) | (buf[3] >> 7)) as usize]);
45 ret.push(ENCODE_STD[((buf[3] & 0x7c) >> 2) as usize]);
46 ret.push(ENCODE_STD[(((buf[3] & 0x03) << 3) | ((buf[4] & 0xe0) >> 5)) as usize]);
47 ret.push(ENCODE_STD[(buf[4] & 0x1f) as usize]);
48 }
49
50 if !data.len().is_multiple_of(5) {
51 let len = ret.len();
52 let num_extra = 8 - (data.len() % 5 * 8).div_ceil(5);
53 if padding {
54 for i in 1..num_extra + 1 {
55 ret[len - i] = b'=';
56 }
57 } else {
58 ret.truncate(len - num_extra);
59 }
60 }
61
62 String::from_utf8(ret).unwrap()
63}
64
65const STD_INV_ALPHABET: [i8; 43] = [
66 -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
67 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
68];
69
70pub fn decode(data: &str) -> Option<Vec<u8>> {
73 if !data.is_ascii() {
74 return None
75 }
76
77 let data = data.as_bytes();
78 let mut unpadded_data_len = data.len();
79
80 for i in 1..min(6, data.len()) + 1 {
81 if data[data.len() - i] != b'=' {
82 break
83 }
84 unpadded_data_len -= 1;
85 }
86
87 let output_length = unpadded_data_len * 5 / 8;
88 let mut ret = Vec::with_capacity(output_length.div_ceil(5) * 5);
89
90 for chunk in data.chunks(8) {
91 let buf = {
92 let mut buf = [0u8; 8];
93 for (i, &c) in chunk.iter().enumerate() {
94 match STD_INV_ALPHABET.get(c.to_ascii_uppercase().wrapping_sub(b'0') as usize) {
95 Some(&-1) | None => return None,
96 Some(&value) => buf[i] = value as u8,
97 };
98 }
99
100 buf
101 };
102
103 ret.push((buf[0] << 3) | (buf[1] >> 2));
104 ret.push((buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4));
105 ret.push((buf[3] << 4) | (buf[4] >> 1));
106 ret.push((buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3));
107 ret.push((buf[6] << 5) | buf[7]);
108 }
109
110 ret.truncate(output_length);
111 Some(ret)
112}
113
114#[cfg(test)]
115mod tests {
116 #[test]
117 fn base32_encoding_decoding() {
118 let s = b"b32Test"; let encoded = super::encode(true, &s[..]);
120 assert_eq!(&encoded, "MIZTEVDFON2A====");
121 assert_eq!(super::decode(&encoded).unwrap(), s);
122
123 let s = b"b32Testoor"; let encoded = super::encode(true, &s[..]);
125 assert_eq!(&encoded, "MIZTEVDFON2G633S");
126 assert_eq!(super::decode(&encoded).unwrap(), s);
127 }
128}