1#[cfg(not(feature = "std"))]
62use alloc::string::String;
63#[cfg(not(feature = "std"))]
64use alloc::vec::Vec;
65
66use super::{DeviceIdentity, IdentityRegistry, MeshGenesis};
67
68pub const PERSISTED_STATE_VERSION: u32 = 1;
72
73const MAGIC: [u8; 4] = *b"PEAT";
75
76#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum PersistenceError {
79 StorageError(String),
81
82 InvalidFormat,
84
85 UnsupportedVersion {
87 stored: u32,
89 supported: u32,
91 },
92
93 NotFound,
95
96 CryptoError(String),
98}
99
100#[cfg(feature = "std")]
101impl std::fmt::Display for PersistenceError {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 match self {
104 Self::StorageError(msg) => write!(f, "storage error: {}", msg),
105 Self::InvalidFormat => write!(f, "invalid format or corrupted data"),
106 Self::UnsupportedVersion { stored, supported } => {
107 write!(
108 f,
109 "unsupported version: stored={}, supported={}",
110 stored, supported
111 )
112 }
113 Self::NotFound => write!(f, "persisted state not found"),
114 Self::CryptoError(msg) => write!(f, "crypto error: {}", msg),
115 }
116 }
117}
118
119#[cfg(feature = "std")]
120impl std::error::Error for PersistenceError {}
121
122pub trait SecureStorage {
131 fn store(&self, key: &str, value: &[u8]) -> Result<(), PersistenceError>;
136
137 fn retrieve(&self, key: &str) -> Result<Option<Vec<u8>>, PersistenceError>;
142
143 fn delete(&self, key: &str) -> Result<(), PersistenceError>;
147
148 fn exists(&self, key: &str) -> Result<bool, PersistenceError> {
150 Ok(self.retrieve(key)?.is_some())
151 }
152}
153
154#[derive(Debug, Clone)]
159pub struct PersistedState {
160 pub version: u32,
162
163 device_private_key: [u8; 32],
168
169 genesis_data: Option<Vec<u8>>,
173
174 registry_data: Vec<u8>,
178
179 revoked_keys: Vec<[u8; 32]>,
183
184 pub persisted_at_ms: u64,
186}
187
188impl PersistedState {
189 pub fn new(identity: &DeviceIdentity, genesis: Option<&MeshGenesis>) -> Self {
191 Self {
192 version: PERSISTED_STATE_VERSION,
193 device_private_key: identity.private_key_bytes(),
194 genesis_data: genesis.map(|g| g.encode()),
195 registry_data: Vec::new(),
196 revoked_keys: Vec::new(),
197 persisted_at_ms: 0,
198 }
199 }
200
201 pub fn with_registry(
203 identity: &DeviceIdentity,
204 genesis: Option<&MeshGenesis>,
205 registry: &IdentityRegistry,
206 ) -> Self {
207 Self {
208 version: PERSISTED_STATE_VERSION,
209 device_private_key: identity.private_key_bytes(),
210 genesis_data: genesis.map(|g| g.encode()),
211 registry_data: registry.encode(),
212 revoked_keys: Vec::new(),
213 persisted_at_ms: 0,
214 }
215 }
216
217 pub fn restore_identity(&self) -> Result<DeviceIdentity, PersistenceError> {
219 DeviceIdentity::from_private_key(&self.device_private_key)
220 .map_err(|e| PersistenceError::CryptoError(format!("{:?}", e)))
221 }
222
223 pub fn restore_genesis(&self) -> Option<MeshGenesis> {
225 self.genesis_data
226 .as_ref()
227 .and_then(|data| MeshGenesis::decode(data))
228 }
229
230 pub fn restore_registry(&self) -> IdentityRegistry {
232 if self.registry_data.is_empty() {
233 IdentityRegistry::new()
234 } else {
235 IdentityRegistry::decode(&self.registry_data).unwrap_or_default()
236 }
237 }
238
239 pub fn revoked_keys(&self) -> &[[u8; 32]] {
241 &self.revoked_keys
242 }
243
244 pub fn add_revoked_key(&mut self, public_key: [u8; 32]) {
246 if !self.revoked_keys.contains(&public_key) {
247 self.revoked_keys.push(public_key);
248 }
249 }
250
251 pub fn update_registry(&mut self, registry: &IdentityRegistry) {
253 self.registry_data = registry.encode();
254 }
255
256 pub fn save(&self, storage: &dyn SecureStorage) -> Result<(), PersistenceError> {
260 let encoded = self.encode();
261 storage.store("hive_persisted_state", &encoded)
263 }
264
265 pub fn load(storage: &dyn SecureStorage) -> Result<Self, PersistenceError> {
269 let data = storage
270 .retrieve("hive_persisted_state")?
271 .ok_or(PersistenceError::NotFound)?;
272
273 Self::decode(&data)
274 }
275
276 pub fn delete(storage: &dyn SecureStorage) -> Result<(), PersistenceError> {
280 storage.delete("hive_persisted_state")
281 }
282
283 pub fn encode(&self) -> Vec<u8> {
297 let genesis_len = self.genesis_data.as_ref().map(|d| d.len()).unwrap_or(0);
298 let capacity = 4
299 + 4
300 + 32
301 + 8
302 + 4
303 + genesis_len
304 + 4
305 + self.registry_data.len()
306 + 4
307 + self.revoked_keys.len() * 32;
308
309 let mut buf = Vec::with_capacity(capacity);
310
311 buf.extend_from_slice(&MAGIC);
313
314 buf.extend_from_slice(&self.version.to_le_bytes());
316
317 buf.extend_from_slice(&self.device_private_key);
319
320 buf.extend_from_slice(&self.persisted_at_ms.to_le_bytes());
322
323 buf.extend_from_slice(&(genesis_len as u32).to_le_bytes());
325 if let Some(ref data) = self.genesis_data {
326 buf.extend_from_slice(data);
327 }
328
329 buf.extend_from_slice(&(self.registry_data.len() as u32).to_le_bytes());
331 buf.extend_from_slice(&self.registry_data);
332
333 buf.extend_from_slice(&(self.revoked_keys.len() as u32).to_le_bytes());
335 for key in &self.revoked_keys {
336 buf.extend_from_slice(key);
337 }
338
339 buf
340 }
341
342 pub fn decode(data: &[u8]) -> Result<Self, PersistenceError> {
344 if data.len() < 60 {
346 return Err(PersistenceError::InvalidFormat);
347 }
348
349 let mut offset = 0;
350
351 if data[offset..offset + 4] != MAGIC {
353 return Err(PersistenceError::InvalidFormat);
354 }
355 offset += 4;
356
357 let version = u32::from_le_bytes([
359 data[offset],
360 data[offset + 1],
361 data[offset + 2],
362 data[offset + 3],
363 ]);
364 offset += 4;
365
366 if version > PERSISTED_STATE_VERSION {
367 return Err(PersistenceError::UnsupportedVersion {
368 stored: version,
369 supported: PERSISTED_STATE_VERSION,
370 });
371 }
372
373 let mut device_private_key = [0u8; 32];
375 device_private_key.copy_from_slice(&data[offset..offset + 32]);
376 offset += 32;
377
378 let persisted_at_ms = u64::from_le_bytes([
380 data[offset],
381 data[offset + 1],
382 data[offset + 2],
383 data[offset + 3],
384 data[offset + 4],
385 data[offset + 5],
386 data[offset + 6],
387 data[offset + 7],
388 ]);
389 offset += 8;
390
391 let genesis_len = u32::from_le_bytes([
393 data[offset],
394 data[offset + 1],
395 data[offset + 2],
396 data[offset + 3],
397 ]) as usize;
398 offset += 4;
399
400 if data.len() < offset + genesis_len {
401 return Err(PersistenceError::InvalidFormat);
402 }
403
404 let genesis_data = if genesis_len > 0 {
405 Some(data[offset..offset + genesis_len].to_vec())
406 } else {
407 None
408 };
409 offset += genesis_len;
410
411 if data.len() < offset + 4 {
413 return Err(PersistenceError::InvalidFormat);
414 }
415
416 let registry_len = u32::from_le_bytes([
417 data[offset],
418 data[offset + 1],
419 data[offset + 2],
420 data[offset + 3],
421 ]) as usize;
422 offset += 4;
423
424 if data.len() < offset + registry_len {
425 return Err(PersistenceError::InvalidFormat);
426 }
427
428 let registry_data = data[offset..offset + registry_len].to_vec();
429 offset += registry_len;
430
431 if data.len() < offset + 4 {
433 return Err(PersistenceError::InvalidFormat);
434 }
435
436 let revoked_count = u32::from_le_bytes([
437 data[offset],
438 data[offset + 1],
439 data[offset + 2],
440 data[offset + 3],
441 ]) as usize;
442 offset += 4;
443
444 if data.len() < offset + revoked_count * 32 {
445 return Err(PersistenceError::InvalidFormat);
446 }
447
448 let mut revoked_keys = Vec::with_capacity(revoked_count);
449 for _ in 0..revoked_count {
450 let mut key = [0u8; 32];
451 key.copy_from_slice(&data[offset..offset + 32]);
452 revoked_keys.push(key);
453 offset += 32;
454 }
455
456 Ok(Self {
457 version,
458 device_private_key,
459 genesis_data,
460 registry_data,
461 revoked_keys,
462 persisted_at_ms,
463 })
464 }
465
466 pub fn set_persisted_at(&mut self, timestamp_ms: u64) {
468 self.persisted_at_ms = timestamp_ms;
469 }
470}
471
472#[cfg(any(test, feature = "std"))]
476pub struct MemoryStorage {
477 data: std::sync::Mutex<std::collections::HashMap<String, Vec<u8>>>,
478}
479
480#[cfg(any(test, feature = "std"))]
481impl MemoryStorage {
482 pub fn new() -> Self {
484 Self {
485 data: std::sync::Mutex::new(std::collections::HashMap::new()),
486 }
487 }
488}
489
490#[cfg(any(test, feature = "std"))]
491impl Default for MemoryStorage {
492 fn default() -> Self {
493 Self::new()
494 }
495}
496
497#[cfg(any(test, feature = "std"))]
498impl SecureStorage for MemoryStorage {
499 fn store(&self, key: &str, value: &[u8]) -> Result<(), PersistenceError> {
500 let mut data = self
501 .data
502 .lock()
503 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
504 data.insert(key.to_string(), value.to_vec());
505 Ok(())
506 }
507
508 fn retrieve(&self, key: &str) -> Result<Option<Vec<u8>>, PersistenceError> {
509 let data = self
510 .data
511 .lock()
512 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
513 Ok(data.get(key).cloned())
514 }
515
516 fn delete(&self, key: &str) -> Result<(), PersistenceError> {
517 let mut data = self
518 .data
519 .lock()
520 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
521 data.remove(key);
522 Ok(())
523 }
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529 use crate::security::{DeviceIdentity, MembershipPolicy, MeshGenesis};
530
531 #[test]
532 fn test_persisted_state_roundtrip() {
533 let identity = DeviceIdentity::generate();
534 let genesis = MeshGenesis::create("TEST-MESH", &identity, MembershipPolicy::Controlled);
535
536 let mut state = PersistedState::new(&identity, Some(&genesis));
537 state.set_persisted_at(1234567890);
538 state.add_revoked_key([0xAA; 32]);
539 state.add_revoked_key([0xBB; 32]);
540
541 let encoded = state.encode();
542 let decoded = PersistedState::decode(&encoded).unwrap();
543
544 assert_eq!(decoded.version, PERSISTED_STATE_VERSION);
545 assert_eq!(decoded.persisted_at_ms, 1234567890);
546 assert_eq!(decoded.revoked_keys.len(), 2);
547
548 let restored_identity = decoded.restore_identity().unwrap();
550 assert_eq!(restored_identity.node_id(), identity.node_id());
551 assert_eq!(restored_identity.public_key(), identity.public_key());
552
553 let restored_genesis = decoded.restore_genesis().unwrap();
555 assert_eq!(restored_genesis.mesh_id(), genesis.mesh_id());
556 }
557
558 #[test]
559 fn test_persisted_state_without_genesis() {
560 let identity = DeviceIdentity::generate();
561 let state = PersistedState::new(&identity, None);
562
563 let encoded = state.encode();
564 let decoded = PersistedState::decode(&encoded).unwrap();
565
566 assert!(decoded.restore_genesis().is_none());
567
568 let restored_identity = decoded.restore_identity().unwrap();
569 assert_eq!(restored_identity.node_id(), identity.node_id());
570 }
571
572 #[test]
573 fn test_persisted_state_with_registry() {
574 let identity1 = DeviceIdentity::generate();
575 let identity2 = DeviceIdentity::generate();
576 let identity3 = DeviceIdentity::generate();
577
578 let mut registry = IdentityRegistry::new();
579 registry.verify_or_register(&identity2.create_attestation(1000));
580 registry.verify_or_register(&identity3.create_attestation(2000));
581
582 let state = PersistedState::with_registry(&identity1, None, ®istry);
583
584 let encoded = state.encode();
585 let decoded = PersistedState::decode(&encoded).unwrap();
586
587 let restored_registry = decoded.restore_registry();
588 assert_eq!(restored_registry.len(), 2);
589 assert!(restored_registry.is_known(identity2.node_id()));
590 assert!(restored_registry.is_known(identity3.node_id()));
591 }
592
593 #[test]
594 fn test_memory_storage() {
595 let storage = MemoryStorage::new();
596 let identity = DeviceIdentity::generate();
597 let state = PersistedState::new(&identity, None);
598
599 state.save(&storage).unwrap();
601
602 let loaded = PersistedState::load(&storage).unwrap();
604 let restored = loaded.restore_identity().unwrap();
605 assert_eq!(restored.node_id(), identity.node_id());
606
607 PersistedState::delete(&storage).unwrap();
609 assert!(matches!(
610 PersistedState::load(&storage),
611 Err(PersistenceError::NotFound)
612 ));
613 }
614
615 #[test]
616 fn test_invalid_magic() {
617 let mut data = vec![0u8; 100];
618 data[0..4].copy_from_slice(b"NOPE");
619
620 assert!(matches!(
621 PersistedState::decode(&data),
622 Err(PersistenceError::InvalidFormat)
623 ));
624 }
625
626 #[test]
627 fn test_unsupported_version() {
628 let identity = DeviceIdentity::generate();
629 let state = PersistedState::new(&identity, None);
630 let mut encoded = state.encode();
631
632 encoded[4..8].copy_from_slice(&999u32.to_le_bytes());
634
635 assert!(matches!(
636 PersistedState::decode(&encoded),
637 Err(PersistenceError::UnsupportedVersion { .. })
638 ));
639 }
640
641 #[test]
642 fn test_revoked_keys_deduplication() {
643 let identity = DeviceIdentity::generate();
644 let mut state = PersistedState::new(&identity, None);
645
646 state.add_revoked_key([0xAA; 32]);
647 state.add_revoked_key([0xAA; 32]); state.add_revoked_key([0xBB; 32]);
649
650 assert_eq!(state.revoked_keys().len(), 2);
651 }
652}