Skip to content

Instantly share code, notes, and snippets.

@tommilligan
Created February 16, 2021 15:58
Show Gist options
  • Select an option

  • Save tommilligan/ba2d591dc6a0d494c409311a2b6f7c60 to your computer and use it in GitHub Desktop.

Select an option

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.
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