pub const MAGIC: u32 = 0xC17A_D3E1;
pub const FORMAT_VERSION: u32 = 1;
pub const KEY_FILE_MAGIC: u32 = 0x4B45_5953;
pub const KEY_FILE_VERSION: u32 = 1;
pub const PAGE_SIZE: usize = 8208; pub const BODY_SIZE: usize = 8160; pub const IV_SIZE: usize = 16;
pub const MAC_SIZE: usize = 32;
pub const PAGE_HEADER_SIZE: usize = 64;
pub const USABLE_SIZE: usize = BODY_SIZE - PAGE_HEADER_SIZE; pub const CHECKSUM_SIZE: usize = 8;
pub const FILE_HEADER_SIZE: usize = 512;
pub const GOD_BYTE_OFFSET: usize = 20;
pub const FILE_ID_OFFSET: usize = 24;
pub const COMMIT_SLOT_OFFSET: usize = 32;
pub const COMMIT_SLOT_SIZE: usize = 240;
pub const GOD_BIT_ACTIVE_SLOT: u8 = 0x01; pub const GOD_BIT_RECOVERY: u8 = 0x02;
pub const KEY_SIZE: usize = 32; pub const REK_SIZE: usize = 32; pub const DEK_SIZE: usize = 32; pub const MAC_KEY_SIZE: usize = 32; pub const WRAPPED_KEY_SIZE: usize = 40; pub const ARGON2_SALT_SIZE: usize = 16;
pub const KEY_FILE_SIZE: usize = 172;
pub const HKDF_INFO_DEK: &[u8] = b"citadel-dek-v1";
pub const HKDF_INFO_MAC_KEY: &[u8] = b"citadel-mac-key-v1";
pub const HKDF_INFO_KEYFILE_MAC: &[u8] = b"citadel-keyfile-mac";
pub const HKDF_INFO_KMS_MASTER: &[u8] = b"citadel-master-key";
pub const HKDF_KMS_SALT: &[u8] = b"citadel-v1";
pub const PBKDF2_MIN_ITERATIONS: u32 = 600_000;
pub const KEY_BACKUP_MAGIC: u32 = 0x4B45_5942; pub const KEY_BACKUP_VERSION: u32 = 1;
pub const KEY_BACKUP_SIZE: usize = 124;
pub const HKDF_INFO_BACKUP_MAC: &[u8] = b"citadel-backup-mac";
pub const MAX_KEY_SIZE: usize = 2048;
pub const MAX_INLINE_VALUE_SIZE: usize = 1920;
pub const OVERFLOW_THRESHOLD: usize = MAX_INLINE_VALUE_SIZE;
pub const PENDING_FREE_ENTRY_SIZE: usize = 12; pub const PENDING_FREE_ENTRIES_PER_PAGE: usize = USABLE_SIZE / PENDING_FREE_ENTRY_SIZE;
pub const MERKLE_HASH_SIZE: usize = 28;
pub const MERKLE_HASH_OFFSET: usize = 36; pub const SLOT_MERKLE_ROOT: usize = 84;
pub const AUDIT_LOG_MAGIC: u32 = 0x4155_4454; pub const AUDIT_LOG_VERSION: u32 = 1;
pub const AUDIT_HEADER_SIZE: usize = 64;
pub const AUDIT_ENTRY_MAGIC: u32 = 0x454E_5452; pub const HKDF_INFO_AUDIT_KEY: &[u8] = b"citadel-audit-key-v1";
pub const DEFAULT_BUFFER_POOL_SIZE: usize = 256;
pub const SLOT_TXN_ID: usize = 0;
pub const SLOT_TREE_ROOT: usize = 8;
pub const SLOT_TREE_DEPTH: usize = 12;
pub const SLOT_TREE_ENTRIES: usize = 16;
pub const SLOT_CATALOG_ROOT: usize = 24;
pub const SLOT_TOTAL_PAGES: usize = 28;
pub const SLOT_HIGH_WATER_MARK: usize = 32;
pub const SLOT_PENDING_FREE_ROOT: usize = 36;
pub const SLOT_ENCRYPTION_EPOCH: usize = 40;
pub const SLOT_DEK_ID: usize = 44;
pub const SLOT_CHECKSUM: usize = 76;
pub const SLOT_NAMED_ENTRIES: usize = 112;
pub const SLOT_NAMED_ENTRY_SIZE: usize = 18;
pub const SLOT_NAMED_MAX_ENTRIES: usize =
(COMMIT_SLOT_SIZE - SLOT_NAMED_ENTRIES - 2) / SLOT_NAMED_ENTRY_SIZE;
pub const GROWTH_CHUNK_1MB: u64 = 1024 * 1024;
pub const GROWTH_CHUNK_4MB: u64 = 4 * 1024 * 1024;
pub const GROWTH_CHUNK_16MB: u64 = 16 * 1024 * 1024;
pub const GROWTH_THRESHOLD_4MB: u64 = 4 * 1024 * 1024;
pub const GROWTH_THRESHOLD_64MB: u64 = 64 * 1024 * 1024;
pub const GROWTH_THRESHOLD_1GB: u64 = 1024 * 1024 * 1024;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn page_size_consistency() {
assert_eq!(PAGE_SIZE, IV_SIZE + BODY_SIZE + MAC_SIZE);
}
#[test]
fn usable_size_consistency() {
assert_eq!(USABLE_SIZE, BODY_SIZE - PAGE_HEADER_SIZE);
assert_eq!(USABLE_SIZE, 8096);
}
#[test]
fn two_cells_per_page_invariant() {
let max_branch_cell = 4 + 2 + MAX_KEY_SIZE;
let max_leaf_cell = 2 + 4 + MAX_KEY_SIZE + 1 + MAX_INLINE_VALUE_SIZE;
let max_cell = max_branch_cell.max(max_leaf_cell);
assert!(2 * max_cell <= USABLE_SIZE, "2 cells must fit in one page");
}
#[test]
fn file_header_fits() {
let needed = COMMIT_SLOT_OFFSET + 2 * COMMIT_SLOT_SIZE;
assert!(
needed <= FILE_HEADER_SIZE,
"commit slots must fit in header"
);
}
#[test]
fn pending_free_entries_per_page() {
assert_eq!(PENDING_FREE_ENTRIES_PER_PAGE, 674);
}
}