1#[cfg(not(feature = "std"))]
48use alloc::vec::Vec;
49use hashbrown::HashMap;
50
51use super::identity::IdentityAttestation;
52use crate::NodeId;
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum RegistryResult {
57 Registered,
59
60 Verified,
62
63 InvalidSignature,
65
66 KeyMismatch {
68 node_id: NodeId,
70 },
71}
72
73impl RegistryResult {
74 pub fn is_trusted(&self) -> bool {
76 matches!(self, Self::Registered | Self::Verified)
77 }
78
79 pub fn is_violation(&self) -> bool {
81 matches!(self, Self::InvalidSignature | Self::KeyMismatch { .. })
82 }
83}
84
85#[derive(Debug, Clone)]
87pub struct IdentityRecord {
88 pub public_key: [u8; 32],
90
91 pub first_seen_ms: u64,
93
94 pub last_seen_ms: u64,
96
97 pub verification_count: u32,
99}
100
101#[derive(Debug, Clone)]
106pub struct IdentityRegistry {
107 known: HashMap<NodeId, IdentityRecord>,
109
110 max_identities: usize,
112}
113
114impl Default for IdentityRegistry {
115 fn default() -> Self {
116 Self::new()
117 }
118}
119
120impl IdentityRegistry {
121 pub const DEFAULT_MAX_IDENTITIES: usize = 256;
123
124 pub fn new() -> Self {
126 Self {
127 known: HashMap::new(),
128 max_identities: Self::DEFAULT_MAX_IDENTITIES,
129 }
130 }
131
132 pub fn with_capacity(max_identities: usize) -> Self {
134 Self {
135 known: HashMap::with_capacity(max_identities.min(64)),
136 max_identities,
137 }
138 }
139
140 pub fn verify_or_register(&mut self, attestation: &IdentityAttestation) -> RegistryResult {
147 self.verify_or_register_at(attestation, attestation.timestamp_ms)
148 }
149
150 pub fn verify_or_register_at(
152 &mut self,
153 attestation: &IdentityAttestation,
154 now_ms: u64,
155 ) -> RegistryResult {
156 if !attestation.verify() {
158 return RegistryResult::InvalidSignature;
159 }
160
161 let node_id = attestation.node_id;
162
163 if let Some(record) = self.known.get_mut(&node_id) {
165 if record.public_key == attestation.public_key {
167 record.last_seen_ms = now_ms;
169 record.verification_count = record.verification_count.saturating_add(1);
170 RegistryResult::Verified
171 } else {
172 RegistryResult::KeyMismatch { node_id }
174 }
175 } else {
176 if self.known.len() >= self.max_identities {
178 }
182
183 self.known.insert(
184 node_id,
185 IdentityRecord {
186 public_key: attestation.public_key,
187 first_seen_ms: now_ms,
188 last_seen_ms: now_ms,
189 verification_count: 1,
190 },
191 );
192 RegistryResult::Registered
193 }
194 }
195
196 pub fn is_known(&self, node_id: NodeId) -> bool {
198 self.known.contains_key(&node_id)
199 }
200
201 pub fn get_public_key(&self, node_id: NodeId) -> Option<&[u8; 32]> {
203 self.known.get(&node_id).map(|r| &r.public_key)
204 }
205
206 pub fn get_record(&self, node_id: NodeId) -> Option<&IdentityRecord> {
208 self.known.get(&node_id)
209 }
210
211 pub fn len(&self) -> usize {
213 self.known.len()
214 }
215
216 pub fn is_empty(&self) -> bool {
218 self.known.is_empty()
219 }
220
221 pub fn remove(&mut self, node_id: NodeId) -> Option<IdentityRecord> {
225 self.known.remove(&node_id)
226 }
227
228 pub fn clear(&mut self) {
232 self.known.clear();
233 }
234
235 pub fn known_nodes(&self) -> Vec<NodeId> {
237 self.known.keys().copied().collect()
238 }
239
240 pub fn pre_register(&mut self, node_id: NodeId, public_key: [u8; 32], now_ms: u64) {
245 self.known.insert(
246 node_id,
247 IdentityRecord {
248 public_key,
249 first_seen_ms: now_ms,
250 last_seen_ms: now_ms,
251 verification_count: 0,
252 },
253 );
254 }
255
256 pub fn encode(&self) -> Vec<u8> {
267 let mut buf = Vec::with_capacity(4 + self.known.len() * 56);
268
269 buf.extend_from_slice(&(self.known.len() as u32).to_le_bytes());
271
272 for (node_id, record) in &self.known {
273 buf.extend_from_slice(&node_id.as_u32().to_le_bytes());
274 buf.extend_from_slice(&record.public_key);
275 buf.extend_from_slice(&record.first_seen_ms.to_le_bytes());
276 buf.extend_from_slice(&record.last_seen_ms.to_le_bytes());
277 buf.extend_from_slice(&record.verification_count.to_le_bytes());
278 }
279
280 buf
281 }
282
283 pub fn decode(data: &[u8]) -> Option<Self> {
285 if data.len() < 4 {
286 return None;
287 }
288
289 let count = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize;
290
291 if data.len() < 4 + count * 56 {
292 return None;
293 }
294
295 let mut registry = Self::new();
296 let mut offset = 4;
297
298 for _ in 0..count {
299 let node_id = NodeId::new(u32::from_le_bytes([
300 data[offset],
301 data[offset + 1],
302 data[offset + 2],
303 data[offset + 3],
304 ]));
305 offset += 4;
306
307 let mut public_key = [0u8; 32];
308 public_key.copy_from_slice(&data[offset..offset + 32]);
309 offset += 32;
310
311 let first_seen_ms = u64::from_le_bytes([
312 data[offset],
313 data[offset + 1],
314 data[offset + 2],
315 data[offset + 3],
316 data[offset + 4],
317 data[offset + 5],
318 data[offset + 6],
319 data[offset + 7],
320 ]);
321 offset += 8;
322
323 let last_seen_ms = u64::from_le_bytes([
324 data[offset],
325 data[offset + 1],
326 data[offset + 2],
327 data[offset + 3],
328 data[offset + 4],
329 data[offset + 5],
330 data[offset + 6],
331 data[offset + 7],
332 ]);
333 offset += 8;
334
335 let verification_count = u32::from_le_bytes([
336 data[offset],
337 data[offset + 1],
338 data[offset + 2],
339 data[offset + 3],
340 ]);
341 offset += 4;
342
343 registry.known.insert(
344 node_id,
345 IdentityRecord {
346 public_key,
347 first_seen_ms,
348 last_seen_ms,
349 verification_count,
350 },
351 );
352 }
353
354 Some(registry)
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361 use crate::security::DeviceIdentity;
362
363 #[test]
364 fn test_register_new_identity() {
365 let mut registry = IdentityRegistry::new();
366 let identity = DeviceIdentity::generate();
367 let attestation = identity.create_attestation(0);
368
369 let result = registry.verify_or_register(&attestation);
370 assert_eq!(result, RegistryResult::Registered);
371 assert!(result.is_trusted());
372 assert!(!result.is_violation());
373 assert_eq!(registry.len(), 1);
374 }
375
376 #[test]
377 fn test_verify_known_identity() {
378 let mut registry = IdentityRegistry::new();
379 let identity = DeviceIdentity::generate();
380 let attestation = identity.create_attestation(0);
381
382 registry.verify_or_register(&attestation);
384
385 let result = registry.verify_or_register(&attestation);
387 assert_eq!(result, RegistryResult::Verified);
388 assert!(result.is_trusted());
389 }
390
391 #[test]
392 fn test_key_mismatch_detection() {
393 let mut registry = IdentityRegistry::new();
394
395 let identity1 = DeviceIdentity::generate();
397 let attestation1 = identity1.create_attestation(0);
398 registry.verify_or_register(&attestation1);
399
400 let identity2 = DeviceIdentity::generate();
406 let node_id = identity1.node_id();
407
408 registry.known.insert(
410 node_id,
411 IdentityRecord {
412 public_key: [0xAA; 32], first_seen_ms: 0,
414 last_seen_ms: 0,
415 verification_count: 1,
416 },
417 );
418
419 let result = registry.verify_or_register(&attestation1);
421 assert!(matches!(result, RegistryResult::KeyMismatch { .. }));
422 assert!(result.is_violation());
423 }
424
425 #[test]
426 fn test_invalid_signature_detection() {
427 let mut registry = IdentityRegistry::new();
428
429 let identity = DeviceIdentity::generate();
431 let mut attestation = identity.create_attestation(0);
432 attestation.signature[0] ^= 0xFF; let result = registry.verify_or_register(&attestation);
435 assert_eq!(result, RegistryResult::InvalidSignature);
436 assert!(result.is_violation());
437 }
438
439 #[test]
440 fn test_verification_count_increment() {
441 let mut registry = IdentityRegistry::new();
442 let identity = DeviceIdentity::generate();
443 let attestation = identity.create_attestation(0);
444 let node_id = identity.node_id();
445
446 registry.verify_or_register(&attestation);
448 registry.verify_or_register(&attestation);
449 registry.verify_or_register(&attestation);
450
451 let record = registry.get_record(node_id).unwrap();
452 assert_eq!(record.verification_count, 3);
453 }
454
455 #[test]
456 fn test_pre_register() {
457 let mut registry = IdentityRegistry::new();
458 let identity = DeviceIdentity::generate();
459 let node_id = identity.node_id();
460 let public_key = identity.public_key();
461
462 registry.pre_register(node_id, public_key, 1000);
464
465 assert!(registry.is_known(node_id));
466 assert_eq!(registry.get_public_key(node_id), Some(&public_key));
467
468 let attestation = identity.create_attestation(0);
470 let result = registry.verify_or_register(&attestation);
471 assert_eq!(result, RegistryResult::Verified);
472 }
473
474 #[test]
475 fn test_encode_decode_roundtrip() {
476 let mut registry = IdentityRegistry::new();
477
478 for _ in 0..5 {
480 let identity = DeviceIdentity::generate();
481 let attestation = identity.create_attestation(0);
482 registry.verify_or_register(&attestation);
483 }
484
485 let encoded = registry.encode();
486 let decoded = IdentityRegistry::decode(&encoded).unwrap();
487
488 assert_eq!(decoded.len(), registry.len());
489 for node_id in registry.known_nodes() {
490 assert!(decoded.is_known(node_id));
491 assert_eq!(
492 decoded.get_public_key(node_id),
493 registry.get_public_key(node_id)
494 );
495 }
496 }
497
498 #[test]
499 fn test_remove_identity() {
500 let mut registry = IdentityRegistry::new();
501 let identity = DeviceIdentity::generate();
502 let attestation = identity.create_attestation(0);
503 let node_id = identity.node_id();
504
505 registry.verify_or_register(&attestation);
506 assert!(registry.is_known(node_id));
507
508 registry.remove(node_id);
509 assert!(!registry.is_known(node_id));
510
511 let result = registry.verify_or_register(&attestation);
513 assert_eq!(result, RegistryResult::Registered);
514 }
515
516 #[test]
517 fn test_known_nodes() {
518 let mut registry = IdentityRegistry::new();
519 let mut expected_nodes = Vec::new();
520
521 for _ in 0..3 {
522 let identity = DeviceIdentity::generate();
523 let attestation = identity.create_attestation(0);
524 expected_nodes.push(identity.node_id());
525 registry.verify_or_register(&attestation);
526 }
527
528 let known = registry.known_nodes();
529 assert_eq!(known.len(), 3);
530 for node_id in expected_nodes {
531 assert!(known.contains(&node_id));
532 }
533 }
534}