API for adding bridges and marking them as unreachable
This commit is contained in:
parent
cf19bf80ee
commit
0664dd7b45
|
@ -18,7 +18,7 @@ use curve25519_dalek::ristretto::CompressedRistretto;
|
||||||
use curve25519_dalek::ristretto::RistrettoBasepointTable;
|
use curve25519_dalek::ristretto::RistrettoBasepointTable;
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ impl BridgeLine {
|
||||||
/// credential if appropriate
|
/// credential if appropriate
|
||||||
pub fn bucket_encode(
|
pub fn bucket_encode(
|
||||||
bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
||||||
reachable: &HashSet<BridgeLine>,
|
reachable: &HashMap<BridgeLine, Vec<(u32, usize)>>,
|
||||||
today: u32,
|
today: u32,
|
||||||
bucket_attr: &Scalar,
|
bucket_attr: &Scalar,
|
||||||
reachability_priv: &IssuerPrivKey,
|
reachability_priv: &IssuerPrivKey,
|
||||||
|
@ -102,7 +102,7 @@ impl BridgeLine {
|
||||||
let mut num_reachable: usize = 0;
|
let mut num_reachable: usize = 0;
|
||||||
for bridge in bucket {
|
for bridge in bucket {
|
||||||
res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
|
res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
|
||||||
if reachable.contains(bridge) {
|
if reachable.contains_key(bridge) {
|
||||||
num_reachable += 1;
|
num_reachable += 1;
|
||||||
}
|
}
|
||||||
pos += BRIDGE_BYTES;
|
pos += BRIDGE_BYTES;
|
||||||
|
@ -208,7 +208,13 @@ pub struct BridgeTable {
|
||||||
pub keys: Vec<[u8; 16]>,
|
pub keys: Vec<[u8; 16]>,
|
||||||
pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
|
pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
|
||||||
pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
|
pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
|
||||||
pub reachable: HashSet<BridgeLine>,
|
/// Individual bridges that are reachable
|
||||||
|
pub reachable: HashMap<BridgeLine, Vec<(u32, usize)>>,
|
||||||
|
/// bucket ids of "hot spare" buckets. These buckets are not handed
|
||||||
|
/// to users, nor do they have any Migration credentials pointing to
|
||||||
|
/// them. When a new Migration credential is needed, a bucket is
|
||||||
|
/// removed from this set and used for that purpose.
|
||||||
|
pub spares: HashSet<u32>,
|
||||||
/// The date the buckets were last encrypted to make the encbucket.
|
/// The date the buckets were last encrypted to make the encbucket.
|
||||||
///
|
///
|
||||||
/// The encbucket must be rebuilt each day so that the Bucket
|
/// The encbucket must be rebuilt each day so that the Bucket
|
||||||
|
@ -225,21 +231,28 @@ impl BridgeTable {
|
||||||
self.buckets.len()
|
self.buckets.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a new bucket to the bridge table
|
/// Append a new bucket to the bridge table, returning its index
|
||||||
pub fn new_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
|
pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 {
|
||||||
// Pick a random key to encrypt this bucket
|
// Pick a random key to encrypt this bucket
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let mut key: [u8; 16] = [0; 16];
|
let mut key: [u8; 16] = [0; 16];
|
||||||
rng.fill_bytes(&mut key);
|
rng.fill_bytes(&mut key);
|
||||||
self.keys.push(key);
|
self.keys.push(key);
|
||||||
self.buckets.push(bucket);
|
self.buckets.push(*bucket);
|
||||||
|
let bucketnum: u32 = (self.buckets.len() - 1).try_into().unwrap();
|
||||||
// Mark the new bridges as available
|
// Mark the new bridges as available
|
||||||
for b in bucket.iter() {
|
for (i, b) in bucket.iter().enumerate() {
|
||||||
if b.port > 0 {
|
if b.port > 0 {
|
||||||
self.reachable.insert(*b);
|
if let Some(v) = self.reachable.get_mut(b) {
|
||||||
|
v.push((bucketnum, i));
|
||||||
|
} else {
|
||||||
|
let v = vec![(bucketnum, i)];
|
||||||
|
self.reachable.insert(*b, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bucketnum
|
||||||
|
}
|
||||||
|
|
||||||
/// Create the vector of encrypted buckets from the keys and buckets
|
/// Create the vector of encrypted buckets from the keys and buckets
|
||||||
/// in the BridgeTable. All of the entries will be (randomly)
|
/// in the BridgeTable. All of the entries will be (randomly)
|
||||||
|
@ -321,7 +334,7 @@ mod tests {
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
let bucket: [BridgeLine; 3] =
|
let bucket: [BridgeLine; 3] =
|
||||||
[BridgeLine::random(), Default::default(), Default::default()];
|
[BridgeLine::random(), Default::default(), Default::default()];
|
||||||
btable.new_bucket(bucket);
|
btable.new_bucket(&bucket);
|
||||||
}
|
}
|
||||||
// And 20 more with three random bridges each
|
// And 20 more with three random bridges each
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
|
@ -330,7 +343,7 @@ mod tests {
|
||||||
BridgeLine::random(),
|
BridgeLine::random(),
|
||||||
BridgeLine::random(),
|
BridgeLine::random(),
|
||||||
];
|
];
|
||||||
btable.new_bucket(bucket);
|
btable.new_bucket(&bucket);
|
||||||
}
|
}
|
||||||
let today: u32 = time::OffsetDateTime::now_utc()
|
let today: u32 = time::OffsetDateTime::now_utc()
|
||||||
.date()
|
.date()
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub mod migration_table;
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
|
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::RngCore;
|
use rand::Rng;
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
use curve25519_dalek::constants as dalek_constants;
|
use curve25519_dalek::constants as dalek_constants;
|
||||||
|
@ -38,6 +38,13 @@ use curve25519_dalek::traits::IsIdentity;
|
||||||
use ed25519_dalek::{Keypair, PublicKey, Signature, SignatureError, Signer, Verifier};
|
use ed25519_dalek::{Keypair, PublicKey, Signature, SignatureError, Signer, Verifier};
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use bridge_table::{
|
||||||
|
BridgeLine, BridgeTable, ENC_BUCKET_BYTES, MAX_BRIDGES_PER_BUCKET, MIN_BUCKET_REACHABILITY,
|
||||||
|
};
|
||||||
|
use migration_table::{MigrationTable, MigrationType};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -104,8 +111,8 @@ pub struct BridgeDb {
|
||||||
keypair: Keypair,
|
keypair: Keypair,
|
||||||
/// The public key for verifying open invitations
|
/// The public key for verifying open invitations
|
||||||
pub pubkey: PublicKey,
|
pub pubkey: PublicKey,
|
||||||
/// The number of open-invitation buckets
|
/// The set of open-invitation buckets
|
||||||
num_openinv_buckets: u32,
|
openinv_buckets: HashSet<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An open invitation is a [u8; OPENINV_LENGTH] where the first 32
|
/// An open invitation is a [u8; OPENINV_LENGTH] where the first 32
|
||||||
|
@ -119,17 +126,27 @@ pub const OPENINV_LENGTH: usize = 32 // the length of the random
|
||||||
|
|
||||||
impl BridgeDb {
|
impl BridgeDb {
|
||||||
/// Create the BridgeDb.
|
/// Create the BridgeDb.
|
||||||
pub fn new(num_openinv_buckets: u32) -> Self {
|
pub fn new() -> Self {
|
||||||
let mut csprng = OsRng {};
|
let mut csprng = OsRng {};
|
||||||
let keypair = Keypair::generate(&mut csprng);
|
let keypair = Keypair::generate(&mut csprng);
|
||||||
let pubkey = keypair.public;
|
let pubkey = keypair.public;
|
||||||
Self {
|
Self {
|
||||||
keypair,
|
keypair,
|
||||||
pubkey,
|
pubkey,
|
||||||
num_openinv_buckets,
|
openinv_buckets: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert an open-invitation bucket into the set
|
||||||
|
pub fn insert_openinv(&mut self, bucket: u32) {
|
||||||
|
self.openinv_buckets.insert(bucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an open-invitation bucket from the set
|
||||||
|
pub fn remove_openinv(&mut self, bucket: u32) {
|
||||||
|
self.openinv_buckets.remove(&bucket);
|
||||||
|
}
|
||||||
|
|
||||||
/// Produce an open invitation. In this example code, we just
|
/// Produce an open invitation. In this example code, we just
|
||||||
/// choose a random open-invitation bucket.
|
/// choose a random open-invitation bucket.
|
||||||
pub fn invite(&self) -> [u8; OPENINV_LENGTH] {
|
pub fn invite(&self) -> [u8; OPENINV_LENGTH] {
|
||||||
|
@ -138,9 +155,10 @@ impl BridgeDb {
|
||||||
// Choose a random invitation id (a Scalar) and serialize it
|
// Choose a random invitation id (a Scalar) and serialize it
|
||||||
let id = Scalar::random(&mut rng);
|
let id = Scalar::random(&mut rng);
|
||||||
res[0..32].copy_from_slice(&id.to_bytes());
|
res[0..32].copy_from_slice(&id.to_bytes());
|
||||||
// Choose a random bucket number (mod num_openinv_buckets) and
|
// Choose a random bucket number (from the set of open
|
||||||
// serialize it
|
// invitation buckets) and serialize it
|
||||||
let bucket_num = rng.next_u32() % self.num_openinv_buckets;
|
let openinv_vec: Vec<&u32> = self.openinv_buckets.iter().collect();
|
||||||
|
let bucket_num = *openinv_vec[rng.gen_range(0, openinv_vec.len())];
|
||||||
res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
|
res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
|
||||||
// Sign the first 36 bytes and serialize it
|
// Sign the first 36 bytes and serialize it
|
||||||
let sig = self.keypair.sign(&res[0..(32 + 4)]);
|
let sig = self.keypair.sign(&res[0..(32 + 4)]);
|
||||||
|
@ -171,6 +189,12 @@ impl BridgeDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BridgeDb {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The bridge authority. This will typically be a singleton object.
|
/// The bridge authority. This will typically be a singleton object.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BridgeAuth {
|
pub struct BridgeAuth {
|
||||||
|
@ -199,10 +223,11 @@ pub struct BridgeAuth {
|
||||||
pub bridgedb_pub: PublicKey,
|
pub bridgedb_pub: PublicKey,
|
||||||
|
|
||||||
/// The bridge table
|
/// The bridge table
|
||||||
bridge_table: bridge_table::BridgeTable,
|
bridge_table: BridgeTable,
|
||||||
|
|
||||||
/// The migration table
|
/// The migration tables
|
||||||
migration_table: migration_table::MigrationTable,
|
trustup_migration_table: MigrationTable,
|
||||||
|
blockage_migration_table: MigrationTable,
|
||||||
|
|
||||||
/// Duplicate filter for open invitations
|
/// Duplicate filter for open invitations
|
||||||
openinv_filter: dup_filter::DupFilter<Scalar>,
|
openinv_filter: dup_filter::DupFilter<Scalar>,
|
||||||
|
@ -245,7 +270,8 @@ impl BridgeAuth {
|
||||||
invitation_pub,
|
invitation_pub,
|
||||||
bridgedb_pub,
|
bridgedb_pub,
|
||||||
bridge_table: Default::default(),
|
bridge_table: Default::default(),
|
||||||
migration_table: Default::default(),
|
trustup_migration_table: MigrationTable::new(MigrationType::TrustUpgrade),
|
||||||
|
blockage_migration_table: MigrationTable::new(MigrationType::Blockage),
|
||||||
openinv_filter: Default::default(),
|
openinv_filter: Default::default(),
|
||||||
id_filter: Default::default(),
|
id_filter: Default::default(),
|
||||||
inv_id_filter: Default::default(),
|
inv_id_filter: Default::default(),
|
||||||
|
@ -254,6 +280,117 @@ impl BridgeAuth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a set of open invitation bridges.
|
||||||
|
///
|
||||||
|
/// Each of the bridges will be given its own open invitation
|
||||||
|
/// bucket, and the BridgeDb will be informed. A single bucket
|
||||||
|
/// containing all of the bridges will also be created, with a trust
|
||||||
|
/// upgrade migration from each of the single-bridge buckets.
|
||||||
|
pub fn add_openinv_bridges(
|
||||||
|
&mut self,
|
||||||
|
bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
|
||||||
|
bdb: &mut BridgeDb,
|
||||||
|
) {
|
||||||
|
let bnum = self.bridge_table.new_bucket(&bridges);
|
||||||
|
let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
|
||||||
|
for b in bridges.iter() {
|
||||||
|
single[0] = *b;
|
||||||
|
let snum = self.bridge_table.new_bucket(&single);
|
||||||
|
bdb.insert_openinv(snum);
|
||||||
|
println!("Adding {} -> {}", snum, bnum);
|
||||||
|
self.trustup_migration_table.table.insert(snum, bnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert a hot spare bucket of bridges
|
||||||
|
pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
|
||||||
|
let bnum = self.bridge_table.new_bucket(&bucket);
|
||||||
|
self.bridge_table.spares.insert(bnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark a bridge as unreachable
|
||||||
|
///
|
||||||
|
/// This bridge will be removed from each of the buckets that
|
||||||
|
/// contains it. If any of those are open-invitation buckets, the
|
||||||
|
/// trust upgrade migration for that bucket will be removed and the
|
||||||
|
/// BridgeDb will be informed to stop handing out that bridge. If
|
||||||
|
/// any of those are trusted buckets where the number of reachable
|
||||||
|
/// bridges has fallen below the threshold, a blockage migration
|
||||||
|
/// from that bucket to a spare bucket will be added, and the spare
|
||||||
|
/// bucket will be removed from the list of hot spares. In
|
||||||
|
/// addition, if the blocked bucket was the _target_ of a blockage
|
||||||
|
/// migration, change the target to the new (formerly spare) bucket.
|
||||||
|
/// Returns true if sucessful, or false if it needed a hot spare but
|
||||||
|
/// there was none available.
|
||||||
|
pub fn bridge_unreachable(&mut self, bridge: &BridgeLine, bdb: &mut BridgeDb) -> bool {
|
||||||
|
let mut res: bool = true;
|
||||||
|
let positions = self.bridge_table.reachable.get(bridge);
|
||||||
|
if let Some(v) = positions {
|
||||||
|
for (bucketnum, offset) in v.iter() {
|
||||||
|
// Count how many bridges in this bucket are reachable
|
||||||
|
let numreachable = self.bridge_table.buckets[*bucketnum as usize]
|
||||||
|
.iter()
|
||||||
|
.filter(|br| self.bridge_table.reachable.get(br).is_some())
|
||||||
|
.count();
|
||||||
|
|
||||||
|
// Remove the bridge from the bucket
|
||||||
|
assert!(self.bridge_table.buckets[*bucketnum as usize][*offset] == *bridge);
|
||||||
|
self.bridge_table.buckets[*bucketnum as usize][*offset] = BridgeLine::default();
|
||||||
|
|
||||||
|
// Is this bucket an open-invitation bucket?
|
||||||
|
if bdb.openinv_buckets.contains(bucketnum) {
|
||||||
|
bdb.openinv_buckets.remove(bucketnum);
|
||||||
|
self.trustup_migration_table.table.remove(bucketnum);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does this removal cause the bucket to go below the
|
||||||
|
// threshold?
|
||||||
|
if numreachable != MIN_BUCKET_REACHABILITY {
|
||||||
|
// No
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This bucket is now unreachable. Get a spare bucket
|
||||||
|
if self.bridge_table.spares.is_empty() {
|
||||||
|
// Uh, oh. No spares available. Just delete any
|
||||||
|
// migrations leading to this bucket.
|
||||||
|
res = false;
|
||||||
|
self.trustup_migration_table
|
||||||
|
.table
|
||||||
|
.retain(|_, &mut v| v != *bucketnum);
|
||||||
|
self.blockage_migration_table
|
||||||
|
.table
|
||||||
|
.retain(|_, &mut v| v != *bucketnum);
|
||||||
|
} else {
|
||||||
|
// 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);
|
||||||
|
// Add a blockage migration from this bucket to the spare
|
||||||
|
self.blockage_migration_table
|
||||||
|
.table
|
||||||
|
.insert(*bucketnum, spare);
|
||||||
|
// Remove any trust upgrade migrations to this
|
||||||
|
// bucket
|
||||||
|
self.trustup_migration_table
|
||||||
|
.table
|
||||||
|
.retain(|_, &mut v| v != *bucketnum);
|
||||||
|
// Change any blockage migrations with this bucket
|
||||||
|
// as the destination to the spare
|
||||||
|
for (_, v) in self.blockage_migration_table.table.iter_mut() {
|
||||||
|
if *v == *bucketnum {
|
||||||
|
*v = spare;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.bridge_table.reachable.remove(bridge);
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// For testing only: manually advance the day by 1 day
|
/// For testing only: manually advance the day by 1 day
|
||||||
pub fn advance_day(&mut self) {
|
pub fn advance_day(&mut self) {
|
||||||
|
@ -282,7 +419,7 @@ impl BridgeAuth {
|
||||||
/// Be sure to call this function when you want the latest version
|
/// Be sure to call this function when you want the latest version
|
||||||
/// of the table, since it will put fresh Bucket Reachability
|
/// of the table, since it will put fresh Bucket Reachability
|
||||||
/// credentials in the buckets each day.
|
/// credentials in the buckets each day.
|
||||||
pub fn enc_bridge_table(&mut self) -> &Vec<[u8; bridge_table::ENC_BUCKET_BYTES]> {
|
pub fn enc_bridge_table(&mut self) -> &Vec<[u8; ENC_BUCKET_BYTES]> {
|
||||||
let today = self.today();
|
let today = self.today();
|
||||||
if self.bridge_table.date_last_enc != today {
|
if self.bridge_table.date_last_enc != today {
|
||||||
self.bridge_table
|
self.bridge_table
|
||||||
|
|
|
@ -34,10 +34,33 @@ pub const MIGRATION_BYTES: usize = 96;
|
||||||
/// The size of an encrypted entry in the returned migration table
|
/// The size of an encrypted entry in the returned migration table
|
||||||
pub const ENC_MIGRATION_BYTES: usize = MIGRATION_BYTES + 12 + 16;
|
pub const ENC_MIGRATION_BYTES: usize = MIGRATION_BYTES + 12 + 16;
|
||||||
|
|
||||||
|
/// The type of migration table: TrustUpgrade is for migrations from
|
||||||
|
/// untrusted (level 0) 1-bridge buckets to trusted (level 1) 3-bridge
|
||||||
|
/// buckets. Blockage is for migrations that drop you down two levels
|
||||||
|
/// (level 3 to 1, level 4 to 2) because the bridges in your current
|
||||||
|
/// bucket were blocked.
|
||||||
|
pub enum MigrationType {
|
||||||
|
TrustUpgrade,
|
||||||
|
Blockage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MigrationType> for Scalar {
|
||||||
|
/// Convert a MigrationType into the Scalar value that represents
|
||||||
|
/// it in the Migration credential
|
||||||
|
fn from(m: MigrationType) -> Self {
|
||||||
|
match m {
|
||||||
|
MigrationType::TrustUpgrade => 0u32,
|
||||||
|
MigrationType::Blockage => 1u32,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The migration table
|
/// The migration table
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct MigrationTable {
|
pub struct MigrationTable {
|
||||||
pub table: HashMap<u32, u32>,
|
pub table: HashMap<u32, u32>,
|
||||||
|
pub migration_type: Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an encrypted Migration credential for returning to the user
|
/// Create an encrypted Migration credential for returning to the user
|
||||||
|
@ -143,6 +166,14 @@ pub fn encrypt_cred_ids(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MigrationTable {
|
impl MigrationTable {
|
||||||
|
/// Create a MigrationTable of the given MigrationType
|
||||||
|
pub fn new(table_type: MigrationType) -> Self {
|
||||||
|
Self {
|
||||||
|
table: Default::default(),
|
||||||
|
migration_type: table_type.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// For each entry in the MigrationTable, use encrypt_cred_ids to
|
/// For each entry in the MigrationTable, use encrypt_cred_ids to
|
||||||
/// produce an entry in an output HashMap (from labels to encrypted
|
/// produce an entry in an output HashMap (from labels to encrypted
|
||||||
/// Migration credentials).
|
/// Migration credentials).
|
||||||
|
|
|
@ -517,7 +517,7 @@ impl BridgeAuth {
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
Pk,
|
Pk,
|
||||||
EncQk,
|
EncQk,
|
||||||
enc_migration_table: self.migration_table.encrypt_table(
|
enc_migration_table: self.trustup_migration_table.encrypt_table(
|
||||||
&req.id,
|
&req.id,
|
||||||
&self.bridge_table,
|
&self.bridge_table,
|
||||||
&Pktable,
|
&Pktable,
|
||||||
|
|
|
@ -13,30 +13,27 @@ struct TestHarness {
|
||||||
impl TestHarness {
|
impl TestHarness {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
// Create a BridegDb
|
// Create a BridegDb
|
||||||
let bdb = BridgeDb::new(15);
|
let mut bdb = BridgeDb::new();
|
||||||
// Create a BridgeAuth
|
// Create a BridgeAuth
|
||||||
let mut ba = BridgeAuth::new(bdb.pubkey);
|
let mut ba = BridgeAuth::new(bdb.pubkey);
|
||||||
|
|
||||||
// Make 15 buckets with one random bridge each
|
// Make 15 open invitation bridges, in 5 sets of 3
|
||||||
for _ in 0..15 {
|
for _ in 0..5 {
|
||||||
let bucket: [BridgeLine; 3] =
|
let bucket = [
|
||||||
[BridgeLine::random(), Default::default(), Default::default()];
|
BridgeLine::random(),
|
||||||
ba.bridge_table.new_bucket(bucket);
|
BridgeLine::random(),
|
||||||
}
|
BridgeLine::random(),
|
||||||
// Make 5 more buckets, each containing 3 of the previously
|
|
||||||
// created bridges
|
|
||||||
for i in 0u32..5 {
|
|
||||||
let iusize = i as usize;
|
|
||||||
let bucket: [BridgeLine; 3] = [
|
|
||||||
ba.bridge_table.buckets[3 * iusize][0],
|
|
||||||
ba.bridge_table.buckets[3 * iusize + 1][0],
|
|
||||||
ba.bridge_table.buckets[3 * iusize + 2][0],
|
|
||||||
];
|
];
|
||||||
ba.bridge_table.new_bucket(bucket);
|
ba.add_openinv_bridges(bucket, &mut bdb);
|
||||||
// Add the allowed migrations to the migration table
|
}
|
||||||
ba.migration_table.table.insert(3 * i, 15 + i);
|
// Add 5 more hot spare buckets
|
||||||
ba.migration_table.table.insert(3 * i + 1, 15 + i);
|
for _ in 0..5 {
|
||||||
ba.migration_table.table.insert(3 * i + 2, 15 + i);
|
let bucket = [
|
||||||
|
BridgeLine::random(),
|
||||||
|
BridgeLine::random(),
|
||||||
|
BridgeLine::random(),
|
||||||
|
];
|
||||||
|
ba.add_spare_bucket(bucket);
|
||||||
}
|
}
|
||||||
// Create the encrypted bridge table
|
// Create the encrypted bridge table
|
||||||
ba.enc_bridge_table();
|
ba.enc_bridge_table();
|
||||||
|
@ -303,3 +300,53 @@ fn test_redeem_invite() {
|
||||||
assert!(th.ba.verify_lox(&bob_cred));
|
assert!(th.ba.verify_lox(&bob_cred));
|
||||||
println!("bob_cred = {:?}", bob_cred);
|
println!("bob_cred = {:?}", bob_cred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mark_unreachable() {
|
||||||
|
let mut th = TestHarness::new();
|
||||||
|
|
||||||
|
println!("spares = {:?}", th.ba.bridge_table.spares);
|
||||||
|
println!("tmig = {:?}", th.ba.trustup_migration_table.table);
|
||||||
|
println!("bmig = {:?}", th.ba.blockage_migration_table.table);
|
||||||
|
println!("openinv = {:?}\n", th.bdb.openinv_buckets);
|
||||||
|
|
||||||
|
// Mark a bridge in an untrusted bucket as unreachable
|
||||||
|
let b6 = th.ba.bridge_table.buckets[6][0];
|
||||||
|
th.ba.bridge_unreachable(&b6, &mut th.bdb);
|
||||||
|
|
||||||
|
println!("spares = {:?}", th.ba.bridge_table.spares);
|
||||||
|
println!("tmig = {:?}", th.ba.trustup_migration_table.table);
|
||||||
|
println!("bmig = {:?}", th.ba.blockage_migration_table.table);
|
||||||
|
println!("openinv = {:?}\n", th.bdb.openinv_buckets);
|
||||||
|
|
||||||
|
// Mark another bridge grouped to the same trusted bucket as
|
||||||
|
// unreachable
|
||||||
|
let b7 = th.ba.bridge_table.buckets[7][0];
|
||||||
|
th.ba.bridge_unreachable(&b7, &mut th.bdb);
|
||||||
|
|
||||||
|
println!("spares = {:?}", th.ba.bridge_table.spares);
|
||||||
|
println!("tmig = {:?}", th.ba.trustup_migration_table.table);
|
||||||
|
println!("bmig = {:?}", th.ba.blockage_migration_table.table);
|
||||||
|
println!("openinv = {:?}\n", th.bdb.openinv_buckets);
|
||||||
|
|
||||||
|
// That will have introduced a blockage migration. Get the target
|
||||||
|
let target: u32 = *th
|
||||||
|
.ba
|
||||||
|
.blockage_migration_table
|
||||||
|
.table
|
||||||
|
.iter()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.1;
|
||||||
|
|
||||||
|
// Block two of the bridges in that target bucket
|
||||||
|
let bt1 = th.ba.bridge_table.buckets[target as usize][1];
|
||||||
|
let bt2 = th.ba.bridge_table.buckets[target as usize][2];
|
||||||
|
th.ba.bridge_unreachable(&bt1, &mut th.bdb);
|
||||||
|
th.ba.bridge_unreachable(&bt2, &mut th.bdb);
|
||||||
|
|
||||||
|
println!("spares = {:?}", th.ba.bridge_table.spares);
|
||||||
|
println!("tmig = {:?}", th.ba.trustup_migration_table.table);
|
||||||
|
println!("bmig = {:?}", th.ba.blockage_migration_table.table);
|
||||||
|
println!("openinv = {:?}\n", th.bdb.openinv_buckets);
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@ use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bridgedb() {
|
fn test_bridgedb() {
|
||||||
let bdb = BridgeDb::new(20);
|
let mut bdb = BridgeDb::new();
|
||||||
|
for i in &[1u32, 5, 7, 12, 19, 20, 22] {
|
||||||
|
bdb.insert_openinv(*i);
|
||||||
|
}
|
||||||
let inv = bdb.invite();
|
let inv = bdb.invite();
|
||||||
println!("{:?}", inv);
|
println!("{:?}", inv);
|
||||||
let res = BridgeDb::verify(inv, bdb.pubkey);
|
let res = BridgeDb::verify(inv, bdb.pubkey);
|
||||||
|
|
Loading…
Reference in New Issue