qsfs_core/
header.rs

1use serde::{Serialize, Deserialize};
2use crate::suite::SuiteId;
3use crate::pae::pae_v2_compat;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct RecipientEntry {
7    /// Human-readable label
8    pub label: String,
9    /// ML-KEM ciphertext
10    #[serde(with="serde_bytes")]
11    pub mlkem_ct: Vec<u8>,
12    /// Legacy wrapped CEK (pre-GCM, 32 bytes) — kept for backward-compat
13    #[serde(with="serde_bytes")]
14    pub wrap: Vec<u8>,
15    /// AES-GCM-wrapped DEK (must be 48 bytes)
16    #[serde(default, with="serde_bytes")]
17    pub wrapped_dek: Vec<u8>,
18    /// Nonce for wrapped_dek (12 bytes)
19    #[serde(default)]
20    pub wrap_nonce: [u8; 12],
21    /// X25519 recipient PK fingerprint (first 8 of BLAKE3)
22    #[serde(default)]
23    pub x25519_pk_fpr: [u8; 8],
24    /// X25519 recipient PK (legacy/debug; presence indicates hybrid used)
25    #[serde(default, with="serde_bytes")]
26    pub x25519_pub: Vec<u8>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct Header {
31    /// Magic bytes for format identification
32    pub magic: [u8; 6],
33    /// Chunk size for streaming
34    pub chunk_size: u32,
35    /// File identifier for nonce derivation
36    pub file_id: [u8; 8],
37    /// Reserved (previously plaintext hash). Kept for compatibility; zeroed.
38    #[serde(default)]
39    pub blake3_of_plain: [u8; 32],
40    /// AEAD suite identifier
41    pub suite: SuiteId,
42    /// Optional per-file public KDF salt (v2.1). None for v2.0 files.
43    #[serde(default)]
44    pub kdf_salt: Option<[u8; 32]>,
45    /// Recipients with KEM ciphertexts and wrapped CEKs
46    pub recipients: Vec<RecipientEntry>,
47    /// Ephemeral X25519 public key (hybrid)
48    #[serde(default)]
49    pub eph_x25519_pk: [u8; 32],
50    /// ML-DSA-87 signature (FIPS 204)
51    #[serde(default, with="serde_bytes")]
52    pub mldsa_sig: Vec<u8>,
53    /// Ed25519 signature (legacy/hybrid)
54    #[serde(default, with="serde_bytes")]
55    pub ed25519_sig: Vec<u8>,
56    /// Signature metadata
57    #[serde(default)]
58    pub signature_metadata: Option<SignatureMetadata>,
59    /// FIN marker
60    pub fin: u8,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct SignatureMetadata {
65    pub signer_id: String,
66    pub algorithm: String,
67    pub public_key: String, // base64 encoded
68}
69
70impl Header {
71    pub fn aead_aad(&self) -> Vec<u8> {
72        // Spec-accurate PAE/AAD with backward-compat
73        pae_v2_compat(self)
74    }
75}