1use std::fmt::Debug;
2
3#[cfg(feature = "cipher")]
4use blowfish_rs::Blowfish;
5#[cfg(feature = "cipher")]
6use const_decoder::Decoder;
7
8use crate::error::ArmourError;
9use crate::zbase::ZBASE32;
10use crate::{IdStr, Result};
11
12#[inline(always)]
13pub fn encode(id: &[u8; 8]) -> IdStr {
14 let mut buf = IdStr::zero_filled();
15 ZBASE32.encode_mut(id, unsafe { buf.as_bytes_mut() });
16 buf
17}
18
19#[inline(always)]
20pub fn decode(id: &str) -> Result<[u8; 8]> {
21 let mut buf = [0u8; 8];
22 ZBASE32
23 .decode_mut(id.as_bytes(), &mut buf)
24 .map_err(|_| ArmourError::ZBaseDecodeError)?;
25 Ok(buf)
26}
27
28#[cfg(feature = "cipher")]
29#[derive(Debug)]
30pub struct Cipher(Blowfish);
31
32#[cfg(not(feature = "cipher"))]
33#[derive(Debug)]
34pub struct Cipher;
35
36#[cfg(feature = "cipher")]
37impl Cipher {
38 pub const fn new(key: &str) -> Self {
40 let bytes: [u8; 56] = Decoder::Base64Url.decode(key.as_bytes());
41 Self(Blowfish::new(&bytes))
42 }
43
44 pub const fn raw(blowfish: Blowfish) -> Self {
45 Self(blowfish)
46 }
47}
48
49#[cfg(not(feature = "cipher"))]
50impl Cipher {
51 pub const fn new(_key: &str) -> Self {
52 Self
53 }
54}
55
56pub trait IdHasher: Copy + Ord + Eq + Sized + Send + Sync + Debug {
58 const HASHER: Cipher;
59
60 #[inline]
61 fn encrypt(id: u64) -> u64 {
62 #[cfg(feature = "cipher")]
63 {
64 Self::HASHER.0.encrypt_u64(id)
65 }
66 #[cfg(not(feature = "cipher"))]
67 {
68 id
69 }
70 }
71
72 #[inline]
73 fn decrypt(id: u64) -> u64 {
74 #[cfg(feature = "cipher")]
75 {
76 Self::HASHER.0.decrypt_u64(id)
77 }
78 #[cfg(not(feature = "cipher"))]
79 {
80 id
81 }
82 }
83
84 #[cfg(feature = "std")]
85 #[inline]
86 fn ser(id: u64) -> IdStr {
87 #[cfg(feature = "cipher")]
88 let id = Self::HASHER.0.encrypt_u64(id);
89 encode(&id.to_le_bytes())
90 }
91
92 #[cfg(feature = "std")]
93 #[inline]
94 fn deser(id: &str) -> Result<u64> {
95 if id.len() != 13 {
96 return Err(ArmourError::ZBaseDecodeError);
97 }
98 let buf = decode(id)?;
99 let de = u64::from_le_bytes(buf);
100 #[cfg(feature = "cipher")]
101 let de = Self::HASHER.0.decrypt_u64(de);
102 Ok(de)
103 }
104}