mixnet/core/
surb_keystore.rs1use super::{
24 fragment::MessageId,
25 sphinx::{SurbId, SurbPayloadEncryptionKeys, SURB_ID_SIZE},
26};
27use hashlink::{linked_hash_map, LinkedHashMap};
28use log::debug;
29use rand::{CryptoRng, Rng};
30
31struct Value {
32 keys: SurbPayloadEncryptionKeys,
33 message_id: MessageId,
34}
35
36pub struct Entry<'a>(linked_hash_map::OccupiedEntry<'a, SurbId, Value>);
37
38impl<'a> Entry<'a> {
39 pub fn keys(&self) -> &SurbPayloadEncryptionKeys {
40 &self.0.get().keys
41 }
42
43 pub fn message_id(&self) -> &MessageId {
44 &self.0.get().message_id
45 }
46
47 pub fn remove(self) {
48 self.0.remove();
49 }
50}
51
52pub struct SurbKeystore {
53 capacity: usize,
55 surbs: LinkedHashMap<SurbId, Value>,
57}
58
59impl SurbKeystore {
60 pub fn new(capacity: usize) -> Self {
61 debug_assert_ne!(capacity, 0);
62 Self { capacity, surbs: LinkedHashMap::with_capacity(capacity) }
63 }
64
65 pub fn insert(
68 &mut self,
69 rng: &mut (impl Rng + CryptoRng),
70 message_id: &MessageId,
71 log_target: &str,
72 ) -> (SurbId, &mut SurbPayloadEncryptionKeys) {
73 debug_assert!(self.surbs.len() <= self.capacity);
75 if self.surbs.len() == self.capacity {
76 debug!(target: log_target, "Too many entries in SURB keystore; evicting oldest");
77 self.surbs.pop_front();
78 }
79
80 let mut id = [0; SURB_ID_SIZE];
81 rng.fill_bytes(&mut id);
82 match self.surbs.entry(id) {
83 linked_hash_map::Entry::Occupied(_) => panic!(
84 "Randomly generated SURB ID matches an existing SURB ID; something wrong with RNG?"
85 ),
86 linked_hash_map::Entry::Vacant(entry) => {
87 let value = entry.insert(Value {
88 keys: SurbPayloadEncryptionKeys::new(),
89 message_id: *message_id,
90 });
91 (id, &mut value.keys)
92 },
93 }
94 }
95
96 pub fn entry(&mut self, id: &SurbId) -> Option<Entry> {
98 match self.surbs.entry(*id) {
99 linked_hash_map::Entry::Occupied(entry) => Some(Entry(entry)),
100 linked_hash_map::Entry::Vacant(_) => None,
101 }
102 }
103}