Skip to main content

px_native/cipher/
b64.rs

1//! `hP / hQ` — standard base64 encode over the alphabet `hI`
2//! captured at line 583 of the eT15wiaE init.js:
3//!
4//! `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=`
5//!
6//! Encoder matches `=` padding length per JS reference. We do not pull
7//! the `base64` crate so the cipher core stays dependency-free.
8
9const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
10
11pub fn h_p(input: &[u8]) -> String {
12    if input.is_empty() {
13        return String::new();
14    }
15    let mut out = String::with_capacity(input.len().div_ceil(3) * 4);
16    let mut i = 0;
17    while i + 3 <= input.len() {
18        let o =
19            (u32::from(input[i]) << 16) | (u32::from(input[i + 1]) << 8) | u32::from(input[i + 2]);
20        out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
21        out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
22        out.push(ALPHABET[((o >> 6) & 63) as usize] as char);
23        out.push(ALPHABET[(o & 63) as usize] as char);
24        i += 3;
25    }
26    let rem = input.len() - i;
27    if rem == 1 {
28        let o = u32::from(input[i]) << 16;
29        out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
30        out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
31        out.push('=');
32        out.push('=');
33    } else if rem == 2 {
34        let o = (u32::from(input[i]) << 16) | (u32::from(input[i + 1]) << 8);
35        out.push(ALPHABET[((o >> 18) & 63) as usize] as char);
36        out.push(ALPHABET[((o >> 12) & 63) as usize] as char);
37        out.push(ALPHABET[((o >> 6) & 63) as usize] as char);
38        out.push('=');
39    }
40    out
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn rfc4648_vectors() {
49        assert_eq!(h_p(b""), "");
50        assert_eq!(h_p(b"f"), "Zg==");
51        assert_eq!(h_p(b"fo"), "Zm8=");
52        assert_eq!(h_p(b"foo"), "Zm9v");
53        assert_eq!(h_p(b"foob"), "Zm9vYg==");
54        assert_eq!(h_p(b"fooba"), "Zm9vYmE=");
55        assert_eq!(h_p(b"foobar"), "Zm9vYmFy");
56    }
57}