keyhog_core/hyperscan_cache.rs
1//! Shared Hyperscan serialized-database cache header contract.
2
3/// Filename prefix of every KeyHog Hyperscan shard cache file (`hs-<sha256>.db`).
4/// Single owner shared by the hardening lockdown gate (which strips it to
5/// recognise a trusted compiled-pattern cache) and the scanner shard writer
6/// (which builds the name), so the two can never disagree.
7pub const HYPERSCAN_CACHE_PREFIX: &str = "hs-";
8
9/// Filename suffix of every KeyHog Hyperscan shard cache file. See
10/// [`HYPERSCAN_CACHE_PREFIX`].
11pub const HYPERSCAN_CACHE_SUFFIX: &str = ".db";
12
13/// Magic bytes at the front of every KeyHog Hyperscan shard cache file.
14pub const HYPERSCAN_CACHE_MAGIC: &[u8; 4] = b"KHHS";
15
16/// KeyHog-owned cache header version for serialized Hyperscan shard files.
17pub const HYPERSCAN_CACHE_VERSION: u32 = 2;
18
19/// Byte length of the KeyHog Hyperscan cache header: magic plus little-endian version.
20pub const HYPERSCAN_CACHE_HEADER_LEN: usize = 8;
21
22/// Hard cap for one serialized Hyperscan shard cache file, including the KeyHog header.
23///
24/// This is a performance-cache bound, not a detector correctness bound. Files above
25/// this cap are not loaded or persisted; the scanner compiles from detector patterns
26/// instead. The cap is intentionally owned in core so read-side validation and
27/// write-side persistence cannot drift.
28pub const HYPERSCAN_CACHE_FILE_BYTES: u64 = 128 * 1024 * 1024;
29
30/// Return true when `header` is exactly the current KeyHog Hyperscan cache header.
31pub fn hyperscan_cache_header_is_valid(header: &[u8]) -> bool {
32 if header.len() != HYPERSCAN_CACHE_HEADER_LEN {
33 return false;
34 }
35 let version = u32::from_le_bytes([header[4], header[5], header[6], header[7]]);
36 &header[..4] == HYPERSCAN_CACHE_MAGIC && version == HYPERSCAN_CACHE_VERSION
37}
38
39/// Append the current KeyHog Hyperscan cache header to a serialized-cache buffer.
40pub fn write_hyperscan_cache_header(output: &mut Vec<u8>) {
41 output.extend_from_slice(HYPERSCAN_CACHE_MAGIC);
42 output.extend_from_slice(&HYPERSCAN_CACHE_VERSION.to_le_bytes());
43}
44
45/// Build the on-disk filename of a KeyHog Hyperscan shard cache file from its
46/// content `shard_key`: `hs-<shard_key>.db`. Single owner of the name FORMAT,
47/// shared by the scanner shard writer (which persists the file) and the
48/// hardening lockdown gate (which recognises/strips it via
49/// [`HYPERSCAN_CACHE_PREFIX`]/[`HYPERSCAN_CACHE_SUFFIX`]), so writer and reader
50/// can never disagree on the shard filename. Previously the writer re-inlined
51/// the `hs-`/`.db` affixes in a `format!`, a latent drift from this owner.
52#[must_use]
53pub fn hyperscan_cache_filename(shard_key: &str) -> String {
54 format!("{HYPERSCAN_CACHE_PREFIX}{shard_key}{HYPERSCAN_CACHE_SUFFIX}")
55}