diff --git a/crates/lox-library/src/bridge_table.rs b/crates/lox-library/src/bridge_table.rs index 9fea23a..f2c6f0f 100644 --- a/crates/lox-library/src/bridge_table.rs +++ b/crates/lox-library/src/bridge_table.rs @@ -213,8 +213,10 @@ impl BridgeLine { #[serde_as] #[derive(Debug, Default, Serialize, Deserialize)] pub struct BridgeTable { - pub keys: Vec<[u8; 16]>, - pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>, +// All structures in the bridgetable are indexed by counter + pub counter: u32, + pub keys: HashMap, + pub buckets: HashMap, #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>, /// Individual bridges that are reachable @@ -249,20 +251,21 @@ impl BridgeTable { self.buckets.len() } +// TODO Don't need with hashmaps, but remove unused buckets pub fn recycle_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET], index: u32) { // Pick a random key to encrypt this bucket let mut rng = rand::thread_rng(); let mut key: [u8; 16] = [0; 16]; rng.fill_bytes(&mut key); - self.keys[index as usize] = key; - self.buckets[index as usize] = *bucket; - for (i, b) in bucket.iter().enumerate() { - if b.port > 0 { - if let Some(v) = self.reachable.get_mut(b) { + let key = self.keys.get(&index).unwrap(); + let bucket = *self.buckets.get(&index).unwrap(); + for (i, bridgeline) in bucket.iter().enumerate() { + if bridgeline.port > 0 { + if let Some(v) = self.reachable.get_mut(bridgeline) { v.push((index, i)); } else { let v = vec![(index, i)]; - self.reachable.insert(*b, v); + self.reachable.insert(*bridgeline, v); } } } @@ -274,21 +277,23 @@ impl BridgeTable { let mut rng = rand::thread_rng(); let mut key: [u8; 16] = [0; 16]; rng.fill_bytes(&mut key); - self.keys.push(key); - self.buckets.push(*bucket); - let bucketnum: u32 = (self.buckets.len() - 1).try_into().unwrap(); + // Increase the counter to identify the bucket, wrap value if beyond u32::MAX + self.counter = self.counter.wrapping_add(1); + self.keys.insert(self.counter, key); + self.buckets.insert(self.counter, *bucket); + // TODO: maybe we don't need this if the hashtable can keep track of available bridges // Mark the new bridges as available for (i, b) in bucket.iter().enumerate() { if b.port > 0 { if let Some(v) = self.reachable.get_mut(b) { - v.push((bucketnum, i)); + v.push((self.counter, i)); } else { - let v = vec![(bucketnum, i)]; + let v = vec![(self.counter, i)]; self.reachable.insert(*b, v); } } } - bucketnum + self.counter } /// Create the vector of encrypted buckets from the keys and buckets @@ -303,13 +308,14 @@ impl BridgeTable { self.encbuckets.clear(); // We want id to be a u32, so we use .zip(0u32..) instead of // enumerate() - for ((key, bucket), id) in self.keys.iter().zip(self.buckets.iter()).zip(0u32..) { + for (uid, key) in self.keys.iter(){ + let bucket = self.buckets.get(uid).unwrap(); let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES]; let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode( bucket, &self.reachable, today, - &to_scalar(id, key), + &to_scalar(*uid, key), reachability_priv, ); // Set the AES key @@ -390,15 +396,15 @@ mod tests { // Create the encrypted bridge table btable.encrypt_table(today, &reachability_priv); // Try to decrypt a 1-bridge bucket - let key7 = btable.keys[7]; + let key7 = btable.keys[&7u32]; let bucket7 = btable.decrypt_bucket_id(7, &key7)?; println!("bucket 7 = {:?}", bucket7); // Try to decrypt a 3-bridge bucket - let key24 = btable.keys[24]; + let key24 = btable.keys[&24u32]; let bucket24 = btable.decrypt_bucket_id(24, &key24)?; println!("bucket 24 = {:?}", bucket24); // Try to decrypt a bucket with the wrong key - let key12 = btable.keys[12]; + let key12 = btable.keys[&12u32]; let res = btable.decrypt_bucket_id(15, &key12).unwrap_err(); println!("bucket key mismatch = {:?}", res); Ok(()) diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 39f52dc..d0b14fa 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -380,14 +380,22 @@ impl BridgeAuth { if let Some(v) = positions { for (bucketnum, offset) in v.iter() { println!("Bucket num: {:?} and offset: {:?}", bucketnum, offset); + let bridgelines = match self.bridge_table.buckets.get(bucketnum) { + Some(bridgelines) => *bridgelines, + None => return res + }; assert!( - self.bridge_table.buckets[*bucketnum as usize][*offset] + bridgelines[*offset] == reachable_bridge.0 ); - self.bridge_table.buckets[*bucketnum as usize][*offset] = *bridge; - assert!(self.bridge_table.buckets[*bucketnum as usize][*offset] == *bridge); + bridgelines[*offset] = *bridge; + self.bridge_table.buckets.insert(*bucketnum, bridgelines); + let bridgelines = match self.bridge_table.buckets.get(bucketnum) { + Some(bridgelines) => *bridgelines, + None => return res + }; assert!( - self.bridge_table.buckets[*bucketnum as usize][*offset] + bridgelines[*offset] != reachable_bridge.0 ); } @@ -418,23 +426,33 @@ impl BridgeAuth { let reachable_bridges = &self.bridge_table.reachable.clone(); match reachable_bridges.get(bridge) { Some(positions) => { - println!("Should not get here"); if let Some(replacement) = available_bridge { for (bucketnum, offset) in positions.iter() { - assert!(self.bridge_table.buckets[*bucketnum as usize][*offset] == *bridge); - self.bridge_table.buckets[*bucketnum as usize][*offset] = *replacement; + let bridgelines = match self.bridge_table.buckets.get(bucketnum) { + Some(bridgelines) => *bridgelines, + None => return ReplaceSuccess::NotFound, + }; + assert!(bridgelines[*offset] == *bridge); + bridgelines[*offset] = *replacement; + self.bridge_table.buckets.insert(*bucketnum, bridgelines); // Remove the bridge from the reachable bridges and add new bridge self.bridge_table .reachable .insert(*replacement, positions.clone()); // Remove the bridge from the bucket self.bridge_table.reachable.remove(bridge); - res = ReplaceSuccess::Replaced } + res = ReplaceSuccess::Replaced } else if !self.bridge_table.unallocated_bridges.is_empty() { let replacement = &self.bridge_table.unallocated_bridges.pop().unwrap(); for (bucketnum, offset) in positions.iter() { - self.bridge_table.buckets[*bucketnum as usize][*offset] = *replacement; + let bridgelines = match self.bridge_table.buckets.get(bucketnum) { + Some(bridgelines) => *bridgelines, + None => return ReplaceSuccess::NotFound, + }; + assert!(bridgelines[*offset] == *bridge); + bridgelines[*offset] = *replacement; + self.bridge_table.buckets.insert(*bucketnum, bridgelines); self.bridge_table .reachable .insert(*replacement, positions.clone()); @@ -446,10 +464,8 @@ impl BridgeAuth { // Get the first spare and remove it from the spares set. let spare = *self.bridge_table.spares.iter().next().unwrap(); self.bridge_table.spares.remove(&spare); - // Indicate the removed bucket as a recyclable bucket - self.bridge_table.recyclable.insert(spare); // Get the actual bridges from the spare bucket - let spare_bucket = self.bridge_table.buckets[spare as usize]; + let spare_bucket = self.bridge_table.buckets[&spare]; let mut replacement: &BridgeLine = &BridgeLine::default(); // Make the first spare the replacement bridge, add the others to the set of // unallocated_bridges diff --git a/crates/lox-library/src/proto/open_invite.rs b/crates/lox-library/src/proto/open_invite.rs index 461ccbc..6f4bd48 100644 --- a/crates/lox-library/src/proto/open_invite.rs +++ b/crates/lox-library/src/proto/open_invite.rs @@ -196,10 +196,11 @@ impl BridgeAuth { // Create the bucket attribute (Scalar), which is a combination // of the bucket id (u32) and the bucket's decryption key ([u8; 16]) - let bucket_key = self.bridge_table.keys[bucket_id]; + let bucket_key = self.bridge_table.keys.get(&bucket_id_u32).unwrap(); let bucket: Scalar = bridge_table::to_scalar(bucket_id_u32, &bucket_key); - let bridge_line = self.bridge_table.buckets[bucket_id][0]; - + let bridge_lines = self.bridge_table.buckets.get(&bucket_id_u32).unwrap(); + let bridge_line = bridge_lines[0]; + // Create the level_since attribute (Scalar), which is today's // Julian date let level_since: Scalar = self.today().into();