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"HIVE";
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)
262 }
263
264 pub fn load(storage: &dyn SecureStorage) -> Result<Self, PersistenceError> {
268 let data = storage
269 .retrieve("hive_persisted_state")?
270 .ok_or(PersistenceError::NotFound)?;
271
272 Self::decode(&data)
273 }
274
275 pub fn delete(storage: &dyn SecureStorage) -> Result<(), PersistenceError> {
279 storage.delete("hive_persisted_state")
280 }
281
282 pub fn encode(&self) -> Vec<u8> {
296 let genesis_len = self.genesis_data.as_ref().map(|d| d.len()).unwrap_or(0);
297 let capacity = 4
298 + 4
299 + 32
300 + 8
301 + 4
302 + genesis_len
303 + 4
304 + self.registry_data.len()
305 + 4
306 + self.revoked_keys.len() * 32;
307
308 let mut buf = Vec::with_capacity(capacity);
309
310 buf.extend_from_slice(&MAGIC);
312
313 buf.extend_from_slice(&self.version.to_le_bytes());
315
316 buf.extend_from_slice(&self.device_private_key);
318
319 buf.extend_from_slice(&self.persisted_at_ms.to_le_bytes());
321
322 buf.extend_from_slice(&(genesis_len as u32).to_le_bytes());
324 if let Some(ref data) = self.genesis_data {
325 buf.extend_from_slice(data);
326 }
327
328 buf.extend_from_slice(&(self.registry_data.len() as u32).to_le_bytes());
330 buf.extend_from_slice(&self.registry_data);
331
332 buf.extend_from_slice(&(self.revoked_keys.len() as u32).to_le_bytes());
334 for key in &self.revoked_keys {
335 buf.extend_from_slice(key);
336 }
337
338 buf
339 }
340
341 pub fn decode(data: &[u8]) -> Result<Self, PersistenceError> {
343 if data.len() < 60 {
345 return Err(PersistenceError::InvalidFormat);
346 }
347
348 let mut offset = 0;
349
350 if data[offset..offset + 4] != MAGIC {
352 return Err(PersistenceError::InvalidFormat);
353 }
354 offset += 4;
355
356 let version = u32::from_le_bytes([
358 data[offset],
359 data[offset + 1],
360 data[offset + 2],
361 data[offset + 3],
362 ]);
363 offset += 4;
364
365 if version > PERSISTED_STATE_VERSION {
366 return Err(PersistenceError::UnsupportedVersion {
367 stored: version,
368 supported: PERSISTED_STATE_VERSION,
369 });
370 }
371
372 let mut device_private_key = [0u8; 32];
374 device_private_key.copy_from_slice(&data[offset..offset + 32]);
375 offset += 32;
376
377 let persisted_at_ms = u64::from_le_bytes([
379 data[offset],
380 data[offset + 1],
381 data[offset + 2],
382 data[offset + 3],
383 data[offset + 4],
384 data[offset + 5],
385 data[offset + 6],
386 data[offset + 7],
387 ]);
388 offset += 8;
389
390 let genesis_len = u32::from_le_bytes([
392 data[offset],
393 data[offset + 1],
394 data[offset + 2],
395 data[offset + 3],
396 ]) as usize;
397 offset += 4;
398
399 if data.len() < offset + genesis_len {
400 return Err(PersistenceError::InvalidFormat);
401 }
402
403 let genesis_data = if genesis_len > 0 {
404 Some(data[offset..offset + genesis_len].to_vec())
405 } else {
406 None
407 };
408 offset += genesis_len;
409
410 if data.len() < offset + 4 {
412 return Err(PersistenceError::InvalidFormat);
413 }
414
415 let registry_len = u32::from_le_bytes([
416 data[offset],
417 data[offset + 1],
418 data[offset + 2],
419 data[offset + 3],
420 ]) as usize;
421 offset += 4;
422
423 if data.len() < offset + registry_len {
424 return Err(PersistenceError::InvalidFormat);
425 }
426
427 let registry_data = data[offset..offset + registry_len].to_vec();
428 offset += registry_len;
429
430 if data.len() < offset + 4 {
432 return Err(PersistenceError::InvalidFormat);
433 }
434
435 let revoked_count = u32::from_le_bytes([
436 data[offset],
437 data[offset + 1],
438 data[offset + 2],
439 data[offset + 3],
440 ]) as usize;
441 offset += 4;
442
443 if data.len() < offset + revoked_count * 32 {
444 return Err(PersistenceError::InvalidFormat);
445 }
446
447 let mut revoked_keys = Vec::with_capacity(revoked_count);
448 for _ in 0..revoked_count {
449 let mut key = [0u8; 32];
450 key.copy_from_slice(&data[offset..offset + 32]);
451 revoked_keys.push(key);
452 offset += 32;
453 }
454
455 Ok(Self {
456 version,
457 device_private_key,
458 genesis_data,
459 registry_data,
460 revoked_keys,
461 persisted_at_ms,
462 })
463 }
464
465 pub fn set_persisted_at(&mut self, timestamp_ms: u64) {
467 self.persisted_at_ms = timestamp_ms;
468 }
469}
470
471#[cfg(any(test, feature = "std"))]
475pub struct MemoryStorage {
476 data: std::sync::Mutex<std::collections::HashMap<String, Vec<u8>>>,
477}
478
479#[cfg(any(test, feature = "std"))]
480impl MemoryStorage {
481 pub fn new() -> Self {
483 Self {
484 data: std::sync::Mutex::new(std::collections::HashMap::new()),
485 }
486 }
487}
488
489#[cfg(any(test, feature = "std"))]
490impl Default for MemoryStorage {
491 fn default() -> Self {
492 Self::new()
493 }
494}
495
496#[cfg(any(test, feature = "std"))]
497impl SecureStorage for MemoryStorage {
498 fn store(&self, key: &str, value: &[u8]) -> Result<(), PersistenceError> {
499 let mut data = self
500 .data
501 .lock()
502 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
503 data.insert(key.to_string(), value.to_vec());
504 Ok(())
505 }
506
507 fn retrieve(&self, key: &str) -> Result<Option<Vec<u8>>, PersistenceError> {
508 let data = self
509 .data
510 .lock()
511 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
512 Ok(data.get(key).cloned())
513 }
514
515 fn delete(&self, key: &str) -> Result<(), PersistenceError> {
516 let mut data = self
517 .data
518 .lock()
519 .map_err(|e| PersistenceError::StorageError(e.to_string()))?;
520 data.remove(key);
521 Ok(())
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528 use crate::security::{DeviceIdentity, MembershipPolicy, MeshGenesis};
529
530 #[test]
531 fn test_persisted_state_roundtrip() {
532 let identity = DeviceIdentity::generate();
533 let genesis = MeshGenesis::create("TEST-MESH", &identity, MembershipPolicy::Controlled);
534
535 let mut state = PersistedState::new(&identity, Some(&genesis));
536 state.set_persisted_at(1234567890);
537 state.add_revoked_key([0xAA; 32]);
538 state.add_revoked_key([0xBB; 32]);
539
540 let encoded = state.encode();
541 let decoded = PersistedState::decode(&encoded).unwrap();
542
543 assert_eq!(decoded.version, PERSISTED_STATE_VERSION);
544 assert_eq!(decoded.persisted_at_ms, 1234567890);
545 assert_eq!(decoded.revoked_keys.len(), 2);
546
547 let restored_identity = decoded.restore_identity().unwrap();
549 assert_eq!(restored_identity.node_id(), identity.node_id());
550 assert_eq!(restored_identity.public_key(), identity.public_key());
551
552 let restored_genesis = decoded.restore_genesis().unwrap();
554 assert_eq!(restored_genesis.mesh_id(), genesis.mesh_id());
555 }
556
557 #[test]
558 fn test_persisted_state_without_genesis() {
559 let identity = DeviceIdentity::generate();
560 let state = PersistedState::new(&identity, None);
561
562 let encoded = state.encode();
563 let decoded = PersistedState::decode(&encoded).unwrap();
564
565 assert!(decoded.restore_genesis().is_none());
566
567 let restored_identity = decoded.restore_identity().unwrap();
568 assert_eq!(restored_identity.node_id(), identity.node_id());
569 }
570
571 #[test]
572 fn test_persisted_state_with_registry() {
573 let identity1 = DeviceIdentity::generate();
574 let identity2 = DeviceIdentity::generate();
575 let identity3 = DeviceIdentity::generate();
576
577 let mut registry = IdentityRegistry::new();
578 registry.verify_or_register(&identity2.create_attestation(1000));
579 registry.verify_or_register(&identity3.create_attestation(2000));
580
581 let state = PersistedState::with_registry(&identity1, None, ®istry);
582
583 let encoded = state.encode();
584 let decoded = PersistedState::decode(&encoded).unwrap();
585
586 let restored_registry = decoded.restore_registry();
587 assert_eq!(restored_registry.len(), 2);
588 assert!(restored_registry.is_known(identity2.node_id()));
589 assert!(restored_registry.is_known(identity3.node_id()));
590 }
591
592 #[test]
593 fn test_memory_storage() {
594 let storage = MemoryStorage::new();
595 let identity = DeviceIdentity::generate();
596 let state = PersistedState::new(&identity, None);
597
598 state.save(&storage).unwrap();
600
601 let loaded = PersistedState::load(&storage).unwrap();
603 let restored = loaded.restore_identity().unwrap();
604 assert_eq!(restored.node_id(), identity.node_id());
605
606 PersistedState::delete(&storage).unwrap();
608 assert!(matches!(
609 PersistedState::load(&storage),
610 Err(PersistenceError::NotFound)
611 ));
612 }
613
614 #[test]
615 fn test_invalid_magic() {
616 let mut data = vec![0u8; 100];
617 data[0..4].copy_from_slice(b"NOPE");
618
619 assert!(matches!(
620 PersistedState::decode(&data),
621 Err(PersistenceError::InvalidFormat)
622 ));
623 }
624
625 #[test]
626 fn test_unsupported_version() {
627 let identity = DeviceIdentity::generate();
628 let state = PersistedState::new(&identity, None);
629 let mut encoded = state.encode();
630
631 encoded[4..8].copy_from_slice(&999u32.to_le_bytes());
633
634 assert!(matches!(
635 PersistedState::decode(&encoded),
636 Err(PersistenceError::UnsupportedVersion { .. })
637 ));
638 }
639
640 #[test]
641 fn test_revoked_keys_deduplication() {
642 let identity = DeviceIdentity::generate();
643 let mut state = PersistedState::new(&identity, None);
644
645 state.add_revoked_key([0xAA; 32]);
646 state.add_revoked_key([0xAA; 32]); state.add_revoked_key([0xBB; 32]);
648
649 assert_eq!(state.revoked_keys().len(), 2);
650 }
651}