keyper/app/
db_key.rs

1use sha3::TurboShake256;
2use sha3::digest::{ExtendableOutput, Update, XofReader};
3use zeroize::Zeroize;
4
5const DB_KEY_LEN: usize = 16;
6
7/// Represents a key used for database entries.
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)]
9pub struct DbKey([u8; DB_KEY_LEN]);
10
11impl DbKey {
12    /// Represents the byte length.
13    pub const LEN: usize = DB_KEY_LEN;
14
15    /// Creates a new [DbKey].
16    pub const fn new() -> Self {
17        Self([0u8; Self::LEN])
18    }
19
20    /// Hashes input [`u64`] for use as a database key.
21    pub fn from_u64(val: u64) -> Self {
22        Self::from_slice(val.to_le_bytes().as_ref())
23    }
24
25    /// Hashes input slice for use as a database key.
26    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    /// Directly copies input database key.
36    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    /// Gets a reference to the inner slice.
46    pub const fn as_slice(&self) -> &[u8] {
47        &self.0
48    }
49
50    /// Gets the [DbKey] length.
51    pub const fn len(&self) -> usize {
52        Self::LEN
53    }
54
55    /// Gets whether the [DbKey] is all zeroes.
56    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}