1use sha3::TurboShake256;
2use sha3::digest::{ExtendableOutput, Update, XofReader};
3use zeroize::Zeroize;
4
5const DB_KEY_LEN: usize = 16;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)]
9pub struct DbKey([u8; DB_KEY_LEN]);
10
11impl DbKey {
12 pub const LEN: usize = DB_KEY_LEN;
14
15 pub const fn new() -> Self {
17 Self([0u8; Self::LEN])
18 }
19
20 pub fn from_u64(val: u64) -> Self {
22 Self::from_slice(val.to_le_bytes().as_ref())
23 }
24
25 pub fn from_slice(key: &[u8]) -> Self {
27 let mut out = Self::new();
28 let mut hasher = TurboShake256::from_core(sha3::TurboShake256Core::new(1));
29 hasher.update(key);
30 let mut reader = hasher.finalize_xof();
31 reader.read(out.as_mut());
32 out
33 }
34
35 pub fn from_db(key: &[u8]) -> Self {
37 let mut inner = [0u8; Self::LEN];
38 let len = inner.len().min(key.len());
39
40 inner[..len].copy_from_slice(&key[..len]);
41
42 Self(inner)
43 }
44
45 pub const fn as_slice(&self) -> &[u8] {
47 &self.0
48 }
49
50 pub const fn len(&self) -> usize {
52 Self::LEN
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.0 == [0u8; Self::LEN]
58 }
59}
60
61impl Default for DbKey {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl From<&[u8]> for DbKey {
68 fn from(val: &[u8]) -> Self {
69 Self::from_slice(val)
70 }
71}
72
73impl<'d> From<&'d DbKey> for &'d [u8] {
74 fn from(val: &'d DbKey) -> Self {
75 val.as_slice()
76 }
77}
78
79impl AsRef<[u8]> for DbKey {
80 fn as_ref(&self) -> &[u8] {
81 self.as_slice()
82 }
83}
84
85impl AsMut<[u8]> for DbKey {
86 fn as_mut(&mut self) -> &mut [u8] {
87 &mut self.0
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_db_key() {
97 let key_u64: u64 = 0xfeed_deaf;
98 let key_bytes = key_u64.to_le_bytes();
99
100 let db_key = DbKey::from_u64(key_u64);
101
102 assert_eq!(DbKey::from_slice(key_bytes.as_ref()), db_key);
103
104 assert!(db_key != DbKey::new());
105 assert_eq!(db_key.len(), DbKey::LEN);
106 assert!(!db_key.is_empty());
107 }
108}