Skip to main content

quantum_shield/
constants.rs

1//! Sizes, labels, and limits for the quantum-shield v2 wire format.
2//!
3//! All sizes are fixed by the algorithm suite (suite id 1): X25519 +
4//! ML-KEM-1024 for key establishment, AES-256-GCM for payload encryption,
5//! and Ed25519 + ML-DSA-87 for signatures.
6
7/// Wire format version produced and accepted by this crate.
8pub const WIRE_VERSION: u8 = 2;
9
10/// Cipher suite id 1: X25519 + ML-KEM-1024, AES-256-GCM, Ed25519 + ML-DSA-87.
11pub const SUITE_ID: u8 = 1;
12
13/// Length of the common wire header: magic (4) + version (1) + suite (1).
14pub const HEADER_LEN: usize = 6;
15
16/// Magic prefix of a serialized [`Envelope`](crate::Envelope).
17pub const MAGIC_ENVELOPE: [u8; 4] = *b"QSE2";
18
19/// Magic prefix of a serialized [`HybridSignature`](crate::HybridSignature).
20pub const MAGIC_SIGNATURE: [u8; 4] = *b"QSS2";
21
22/// Magic prefix of a serialized [`PublicKeyBundle`](crate::PublicKeyBundle).
23pub const MAGIC_PUBLIC_BUNDLE: [u8; 4] = *b"QSP2";
24
25/// Magic prefix of a serialized secret-key bundle.
26pub const MAGIC_SECRET_BUNDLE: [u8; 4] = *b"QSK2";
27
28/// Magic prefix of a serialized multi-recipient envelope.
29pub const MAGIC_MULTI: [u8; 4] = *b"QSM2";
30
31/// Magic prefix of a serialized streaming header.
32pub const MAGIC_STREAM: [u8; 4] = *b"QST2";
33
34/// Magic prefix of a serialized rotation attestation.
35pub const MAGIC_ROTATION: [u8; 4] = *b"QSR2";
36
37/// X25519 public key length in bytes.
38pub const X25519_PK_LEN: usize = 32;
39
40/// X25519 secret key length in bytes.
41pub const X25519_SK_LEN: usize = 32;
42
43/// ML-KEM-1024 encapsulation (public) key length in bytes.
44pub const MLKEM1024_EK_LEN: usize = 1568;
45
46/// ML-KEM-1024 ciphertext length in bytes.
47pub const MLKEM1024_CT_LEN: usize = 1568;
48
49/// ML-KEM (d,z) seed length in bytes (FIPS 203 private key seed form).
50pub const MLKEM_SEED_LEN: usize = 64;
51
52/// Ed25519 public key length in bytes.
53pub const ED25519_PK_LEN: usize = 32;
54
55/// Ed25519 private key seed length in bytes.
56pub const ED25519_SEED_LEN: usize = 32;
57
58/// Ed25519 signature length in bytes.
59pub const ED25519_SIG_LEN: usize = 64;
60
61/// ML-DSA-87 verifying (public) key length in bytes.
62pub const MLDSA87_VK_LEN: usize = 2592;
63
64/// ML-DSA-87 signature length in bytes.
65pub const MLDSA87_SIG_LEN: usize = 4627;
66
67/// ML-DSA private key seed (xi) length in bytes (FIPS 204 Algorithm 6).
68pub const MLDSA_SEED_LEN: usize = 32;
69
70/// AES-256-GCM nonce length in bytes.
71pub const NONCE_LEN: usize = 12;
72
73/// AES-256-GCM authentication tag length in bytes.
74pub const TAG_LEN: usize = 16;
75
76/// Length of the authenticated envelope header (everything before the AEAD
77/// ciphertext): header + ephemeral X25519 key + ML-KEM ciphertext + nonce.
78/// This entire prefix is bound into the AEAD tag as associated data.
79pub const ENVELOPE_AAD_LEN: usize = HEADER_LEN + X25519_PK_LEN + MLKEM1024_CT_LEN + NONCE_LEN;
80
81/// Total envelope overhead on top of the plaintext length.
82pub const ENVELOPE_OVERHEAD: usize = ENVELOPE_AAD_LEN + TAG_LEN;
83
84/// Serialized [`HybridSignature`](crate::HybridSignature) length in bytes.
85pub const SIGNATURE_LEN: usize = HEADER_LEN + ED25519_SIG_LEN + MLDSA87_SIG_LEN;
86
87/// Serialized [`PublicKeyBundle`](crate::PublicKeyBundle) length in bytes.
88pub const PUBLIC_BUNDLE_LEN: usize =
89    HEADER_LEN + X25519_PK_LEN + MLKEM1024_EK_LEN + ED25519_PK_LEN + MLDSA87_VK_LEN;
90
91/// Serialized secret-key bundle length in bytes (seeds only).
92pub const SECRET_BUNDLE_LEN: usize =
93    HEADER_LEN + X25519_SK_LEN + MLKEM_SEED_LEN + ED25519_SEED_LEN + MLDSA_SEED_LEN;
94
95/// Maximum plaintext length accepted by [`seal`](crate::seal) (64 MiB).
96pub const MAX_PLAINTEXT_LEN: usize = 64 * 1024 * 1024;
97
98/// Content-encryption key length for multi-recipient envelopes (bytes).
99pub const CEK_LEN: usize = 32;
100
101/// Length of the CEK commitment in a multi-recipient envelope (bytes).
102pub const CEK_COMMIT_LEN: usize = 32;
103
104/// Per-recipient wrap length in a multi-recipient envelope: ephemeral X25519
105/// key + ML-KEM ciphertext + wrap nonce + wrapped CEK (CEK + AEAD tag).
106pub const WRAP_LEN: usize = X25519_PK_LEN + MLKEM1024_CT_LEN + NONCE_LEN + CEK_LEN + TAG_LEN;
107
108/// Maximum recipients per multi-recipient envelope (DoS bound; enforced at
109/// both seal and parse time, since `open` trial-decrypts every wrap).
110pub const MAX_RECIPIENTS: usize = 1024;
111
112/// Plaintext bytes per chunk in a streaming envelope (64 KiB).
113pub const STREAM_CHUNK_SIZE: usize = 64 * 1024;
114
115/// Length of the random nonce prefix in a streaming envelope. The 12-byte
116/// AES-GCM nonce is `prefix (7) || u32 chunk counter (4) || last-flag (1)`.
117pub const STREAM_NONCE_PREFIX_LEN: usize = 7;
118
119/// Length of a streaming header: header + ephemeral X25519 key + ML-KEM
120/// ciphertext + nonce prefix.
121pub const STREAM_HEADER_LEN: usize =
122    HEADER_LEN + X25519_PK_LEN + MLKEM1024_CT_LEN + STREAM_NONCE_PREFIX_LEN;
123
124/// Length of a truncated key identifier (`SHA3-256(QSP2)[..16]`).
125pub const KEY_ID_LEN: usize = 16;
126
127/// Maximum signing/verification context length in bytes (mirrors the FIPS 204
128/// context-string limit).
129pub const MAX_CONTEXT_LEN: usize = 255;
130
131/// Domain-separation label for the hybrid KEM shared-secret combiner.
132pub(crate) const KEM_COMBINER_LABEL: &[u8] = b"quantum-shield/v2/kem:X25519+ML-KEM-1024\0";
133
134/// Domain-separation label prepended to every signed message.
135pub(crate) const SIG_DOMAIN_LABEL: &[u8] = b"quantum-shield/v2/sig:Ed25519+ML-DSA-87\0";
136
137/// Signing context for rotation attestations.
138pub const ROTATION_CONTEXT: &[u8] = b"quantum-shield/v2/rotate\0";
139
140/// Domain label for the multi-recipient CEK commitment.
141pub(crate) const MULTI_CEK_COMMIT_LABEL: &[u8] = b"quantum-shield/v2/multi:cek-commit\0";