use std::fmt::Debug;
use blowfish_rs::Blowfish;
use const_decoder::Decoder;
use crate::error::ArmourError;
use crate::zbase::ZBASE32;
use crate::{IdStr, Result};
#[inline(always)]
pub fn encode(id: &[u8; 8]) -> IdStr {
let mut buf = IdStr::zero_filled();
ZBASE32.encode_mut(id, unsafe { buf.as_bytes_mut() });
buf
}
#[inline(always)]
pub fn decode(id: &str) -> Result<[u8; 8]> {
let mut buf = [0u8; 8];
ZBASE32
.decode_mut(id.as_bytes(), &mut buf)
.map_err(|_| ArmourError::ZBaseDecodeError)?;
Ok(buf)
}
#[derive(Debug)]
pub struct Cipher(Blowfish);
impl Cipher {
pub const fn new(key: &str) -> Self {
let bytes: [u8; 56] = Decoder::Base64Url.decode(key.as_bytes());
Self(Blowfish::new(&bytes))
}
pub const fn raw(blowfish: Blowfish) -> Self {
Self(blowfish)
}
}
pub trait IdHasher: Copy + Ord + Eq + Sized + Send + Sync + Debug {
const HASHER: Cipher;
#[cfg(feature = "std")]
#[inline]
fn ser(id: u64) -> IdStr {
let enc = Self::HASHER.0.encrypt_u64(id);
encode(&enc.to_le_bytes())
}
#[cfg(feature = "std")]
#[inline]
fn deser(id: &str) -> Result<u64> {
if id.len() != 13 {
return Err(ArmourError::ZBaseDecodeError);
}
let buf = decode(id)?;
let de = u64::from_le_bytes(buf);
let id = Self::HASHER.0.decrypt_u64(de);
Ok(id)
}
}