use std::fmt::Debug;
#[cfg(feature = "cipher")]
use blowfish_rs::Blowfish;
#[cfg(feature = "cipher")]
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)
}
#[cfg(feature = "cipher")]
#[derive(Debug)]
pub struct Cipher(Blowfish);
#[cfg(not(feature = "cipher"))]
#[derive(Debug)]
pub struct Cipher;
#[cfg(feature = "cipher")]
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)
}
}
#[cfg(not(feature = "cipher"))]
impl Cipher {
pub const fn new(_key: &str) -> Self {
Self
}
}
pub trait IdHasher: Copy + Ord + Eq + Sized + Send + Sync + Debug {
const HASHER: Cipher;
#[inline]
fn encrypt(id: u64) -> u64 {
#[cfg(feature = "cipher")]
{
Self::HASHER.0.encrypt_u64(id)
}
#[cfg(not(feature = "cipher"))]
{
id
}
}
#[inline]
fn decrypt(id: u64) -> u64 {
#[cfg(feature = "cipher")]
{
Self::HASHER.0.decrypt_u64(id)
}
#[cfg(not(feature = "cipher"))]
{
id
}
}
#[cfg(feature = "std")]
#[inline]
fn ser(id: u64) -> IdStr {
#[cfg(feature = "cipher")]
let id = Self::HASHER.0.encrypt_u64(id);
encode(&id.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);
#[cfg(feature = "cipher")]
let de = Self::HASHER.0.decrypt_u64(de);
Ok(de)
}
}