Created
February 16, 2021 15:58
-
-
Save tommilligan/ba2d591dc6a0d494c409311a2b6f7c60 to your computer and use it in GitHub Desktop.
Bare-bones base85 encoding function in Rust - ended up unused for other reasons.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::convert::TryInto; | |
| const RADIX: u32 = 85; | |
| const INPUT_BLOCK_SIZE: u32 = 4; | |
| const OUTPUT_BLOCK_SIZE: u32 = 5; | |
| #[inline] | |
| /// Read a block of four `u8`s in as a single big-endian u32. | |
| fn read_u32(s: &[u8]) -> u32 { | |
| u32::from_be_bytes(s[..4].try_into().unwrap()) | |
| } | |
| /// Given an input of bytes, output it as base85 encoded string (in byte slice format). | |
| fn encode_to_slice(input: &[u8; 32], output: &mut [u8]) { | |
| for block_index in 0..8 { | |
| let input_index = block_index * INPUT_BLOCK_SIZE as usize; | |
| let input_block = &input[input_index..input_index + INPUT_BLOCK_SIZE as usize]; | |
| let output_index = block_index * OUTPUT_BLOCK_SIZE as usize; | |
| let output_block = &mut output[output_index..output_index + OUTPUT_BLOCK_SIZE as usize]; | |
| let mut remainder = read_u32(&input_block[0..]); | |
| for output_index in 0..OUTPUT_BLOCK_SIZE { | |
| let divisor = RADIX.pow((OUTPUT_BLOCK_SIZE - 1) - output_index); | |
| let quotient = remainder / divisor; | |
| remainder = remainder % divisor; | |
| output_block[output_index as usize] = ALPHABET[quotient as usize]; | |
| } | |
| } | |
| } | |
| /// Encode the given byte array in base85. | |
| pub fn b85_encode(input: &[u8; 32]) -> String { | |
| let mut buffer = [0u8; 40]; | |
| encode_to_slice(input, &mut buffer[..]); | |
| String::from_utf8_lossy(&buffer).to_string() | |
| } | |
| /// The base85 alphabet. Sampled from the Python implementation with: | |
| /// | |
| /// ```python | |
| /// import base64 | |
| /// | |
| /// print(list(base64._b85alphabet)) | |
| /// ``` | |
| pub const ALPHABET: &[u8; 85] = &[ | |
| 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, | |
| 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, | |
| 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 33, 35, 36, 37, | |
| 38, 40, 41, 42, 43, 45, 59, 60, 61, 62, 63, 64, 94, 95, 96, 123, 124, 125, 126, | |
| ]; | |
| #[cfg(test)] | |
| mod test { | |
| use super::*; | |
| use proptest::prelude::*; | |
| #[test] | |
| fn quote() { | |
| let input: &[u8; 32] = b"The trouble with having an open "; | |
| let expected = "RA^-&baHQXVr*p~cWHEJAZTHBX>MmAVQwIAaAj^F"; | |
| assert_eq!(b85_encode(input), expected); | |
| } | |
| proptest! { | |
| #[test] | |
| fn encode_any_slice( | |
| array in proptest::array::uniform32(proptest::num::u8::ANY), | |
| ) { | |
| b85_encode(&array); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment