veridian_kernel/pkg/format/
mod.rs1#![allow(clippy::no_effect, clippy::identity_op)]
26
27mod compression;
28mod signature;
29
30pub use compression::{compress, decompress};
32pub use signature::{PackageSignatures, SignaturePolicy, TrustLevel, TrustedKey, TrustedKeyRing};
33
34pub const VPKG_MAGIC: [u8; 4] = *b"VPKG";
36
37pub const VPKG_VERSION: u32 = 1;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42#[repr(u8)]
43pub enum PackageType {
44 Binary = 0,
46 Library = 1,
48 KernelModule = 2,
50 Data = 3,
52 Meta = 4,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58#[repr(u8)]
59pub enum Compression {
60 None = 0,
62 Zstd = 1,
64 Lz4 = 2,
66 Brotli = 3,
68}
69
70impl Compression {
71 pub fn from_u8(value: u8) -> Option<Self> {
73 match value {
74 0 => Some(Compression::None),
75 1 => Some(Compression::Zstd),
76 2 => Some(Compression::Lz4),
77 3 => Some(Compression::Brotli),
78 _ => None,
79 }
80 }
81
82 pub fn ratio_estimate(&self) -> f32 {
84 match self {
85 Compression::None => 1.0,
86 Compression::Zstd => 0.3, Compression::Lz4 => 0.5, Compression::Brotli => 0.25, }
90 }
91}
92
93#[repr(C, packed)]
95#[derive(Debug, Clone, Copy)]
96pub struct PackageHeader {
97 pub magic: [u8; 4],
99 pub version: u32,
101 pub pkg_type: u8,
103 pub compression: u8,
105 pub _reserved: [u8; 6],
107 pub metadata_offset: u64,
109 pub metadata_size: u64,
111 pub content_offset: u64,
113 pub content_size: u64,
115 pub signature_offset: u64,
117 pub signature_size: u64,
119}
120
121impl PackageHeader {
122 pub fn new(
124 pkg_type: PackageType,
125 compression: Compression,
126 metadata_size: u64,
127 content_size: u64,
128 signature_size: u64,
129 ) -> Self {
130 let mut offset = 64u64; let metadata_offset = offset;
133 offset += metadata_size;
134
135 let content_offset = offset;
136 offset += content_size;
137
138 let signature_offset = offset;
139
140 Self {
141 magic: VPKG_MAGIC,
142 version: VPKG_VERSION,
143 pkg_type: pkg_type as u8,
144 compression: compression as u8,
145 _reserved: [0; 6],
146 metadata_offset,
147 metadata_size,
148 content_offset,
149 content_size,
150 signature_offset,
151 signature_size,
152 }
153 }
154
155 pub fn validate(&self) -> bool {
157 self.magic == VPKG_MAGIC && self.version == VPKG_VERSION
158 }
159
160 pub fn get_type(&self) -> Option<PackageType> {
162 match self.pkg_type {
163 0 => Some(PackageType::Binary),
164 1 => Some(PackageType::Library),
165 2 => Some(PackageType::KernelModule),
166 3 => Some(PackageType::Data),
167 4 => Some(PackageType::Meta),
168 _ => None,
169 }
170 }
171
172 pub fn get_compression(&self) -> Option<Compression> {
174 Compression::from_u8(self.compression)
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use alloc::{vec, vec::Vec};
181
182 use super::*;
183
184 #[test]
185 fn test_header_creation() {
186 let header = PackageHeader::new(PackageType::Binary, Compression::Zstd, 1024, 4096, 128);
187
188 assert!(header.validate());
189 assert_eq!(header.get_type(), Some(PackageType::Binary));
190 assert_eq!(header.get_compression(), Some(Compression::Zstd));
191 }
192
193 #[test]
194 fn test_compression_enum() {
195 assert_eq!(Compression::from_u8(0), Some(Compression::None));
196 assert_eq!(Compression::from_u8(1), Some(Compression::Zstd));
197 assert_eq!(Compression::from_u8(99), None);
198 }
199
200 #[test]
201 fn test_signature_serialization() {
202 let sigs = PackageSignatures {
203 ed25519_sig: [0x42; 64],
204 dilithium_sig: vec![0xAA; 100],
205 };
206
207 let bytes = sigs.to_bytes();
208 let restored = PackageSignatures::from_bytes(&bytes).unwrap();
209
210 assert_eq!(restored.ed25519_sig, sigs.ed25519_sig);
211 assert_eq!(restored.dilithium_sig, sigs.dilithium_sig);
212 }
213
214 #[test]
215 fn test_lz4_compression_roundtrip() {
216 let original = b"Hello, World! This is a test of LZ4 compression. \
217 It should compress and decompress correctly.";
218
219 let compressed = compress(original, Compression::Lz4).unwrap();
220 let decompressed = decompress(&compressed, Compression::Lz4).unwrap();
221
222 assert_eq!(decompressed, original);
223 }
224
225 #[test]
226 fn test_zstd_compression_roundtrip() {
227 let original = b"Test data for Zstd compression. \
228 AAAAAAAAAA BBBBBBBBBB CCCCCCCCCC repetitive data.";
229
230 let compressed = compress(original, Compression::Zstd).unwrap();
231 let decompressed = decompress(&compressed, Compression::Zstd).unwrap();
232
233 assert_eq!(decompressed, original);
234 }
235
236 #[test]
237 fn test_brotli_compression_roundtrip() {
238 let original = b"Brotli compression test with some repeated patterns \
239 and varied content for better compression testing.";
240
241 let compressed = compress(original, Compression::Brotli).unwrap();
242 let decompressed = decompress(&compressed, Compression::Brotli).unwrap();
243
244 assert_eq!(decompressed, original);
245 }
246
247 #[test]
248 fn test_no_compression() {
249 let original = b"Uncompressed data";
250
251 let compressed = compress(original, Compression::None).unwrap();
252 let decompressed = decompress(&compressed, Compression::None).unwrap();
253
254 assert_eq!(compressed, original);
255 assert_eq!(decompressed, original);
256 }
257
258 #[test]
259 fn test_empty_input() {
260 let empty: &[u8] = &[];
261
262 let lz4_result = compress(empty, Compression::Lz4).unwrap();
264 assert!(lz4_result.is_empty());
265
266 let brotli_result = compress(empty, Compression::Brotli).unwrap();
268 assert!(!brotli_result.is_empty()); let none_result = compress(empty, Compression::None).unwrap();
272 assert!(none_result.is_empty());
273 }
274
275 #[test]
276 fn test_highly_compressible_data() {
277 let mut original = Vec::with_capacity(10000);
279 for _ in 0..1000 {
280 original.extend_from_slice(b"AAAAAAAAAA");
281 }
282
283 let compressed = compress(&original, Compression::Lz4).unwrap();
285 assert!(compressed.len() < original.len() / 2);
286
287 let decompressed = decompress(&compressed, Compression::Lz4).unwrap();
288 assert_eq!(decompressed, original);
289 }
290}