use bitvec::prelude::*;
use std::iter::repeat;
use thiserror::Error;
const ALPHABET: [u8; 32] = [
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
b'g', b'h', b'j', b'k', b'm', b'n', b'p', b'q', b'r', b's', b't', b'v', b'w', b'x', b'y', b'z',
];
#[rustfmt::skip]
const ALPHABET_DECODE_MAP: [u8; 256] = [
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14,
0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C,
0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
];
pub const fn encodable_bits<T>() -> usize {
let byte_len = core::mem::size_of::<T>();
let len = byte_len * 8;
(len + 5) - ((len + 5) % 5)
}
pub const fn encoded_len<T>() -> usize {
encodable_bits::<T>() / 5
}
const fn pad_bits_len(bytes: &[u8]) -> usize {
let bits = bytes.len() * 8;
((bits + 5) - (bits + 5) % 5) - bits
}
pub fn encode(src: &[u8], dst: &mut [u8]) {
let mut bv = bitvec![u8, Msb0;];
bv.extend(repeat(false).take(pad_bits_len(src)));
bv.extend_from_bitslice(src.view_bits::<Msb0>());
assert_eq!(
dst.len(),
bv.chunks(5).count(),
"out slice is incorrect size"
);
for (i, byte) in bv.chunks(5).enumerate() {
let o = ALPHABET[byte.load_be::<u8>() as usize];
dst[i] = o;
}
}
#[derive(Error, Debug, Eq, PartialEq)]
pub enum Base32Error {
#[error("empty source bytes")]
Empty,
#[error("invalid source byte")]
InvalidByte,
#[error("invalid first source byte")]
InvalidFirstByte,
#[error("out bytes slice is the wrong size. expected {0}, found {1}")]
InvalidOutBytesSize(usize, usize),
}
pub fn decode(src: &[u8], dst: &mut [u8]) -> Result<(), Base32Error> {
if src.is_empty() {
return Err(Base32Error::Empty);
}
let mut bv = bitvec![u8, Msb0;];
let pad_bits_len = pad_bits_len(dst);
for (i, byte) in src.iter().enumerate() {
let decoded = ALPHABET_DECODE_MAP[*byte as usize];
if i == 0 {
let max_first_byte: u8 = 0x1F >> pad_bits_len;
if decoded > max_first_byte {
return Err(Base32Error::InvalidFirstByte);
}
}
if decoded == 0xFF {
return Err(Base32Error::InvalidByte);
}
let bits = decoded.view_bits::<Msb0>();
bv.extend(&bits[3..]);
}
let bv = &bv[pad_bits_len..];
let chunks_len = bv.chunks(8).count();
if dst.len() != chunks_len {
return Err(Base32Error::InvalidOutBytesSize(chunks_len, dst.len()));
}
for (i, byte) in bv.chunks(8).enumerate() {
dst[i] = byte.load_be::<u8>();
}
Ok(())
}