28 Commits 81cbdea305 ... 02c19b6865

Author SHA1 Message Date
  onyinyang 02c19b6865 Fixed testing instructions and another substring issue 2 years ago
  onyinyang 367476fe3f Moved README and fixed substring issue 2 years ago
  onyinyang 9c41819b69 Added Updated tests file and readme 2 years ago
  onyinyang 634f8c9b35 Added timing 2 years ago
  onyinyang 9ddc7469cf Changed printout statements and reverted to multithreaded testing 2 years ago
  onyinyang a7592247c8 Added tests for different sized bridges 2 years ago
  onyinyang 6f55624667 Added perfstat time outputs for each test 2 years ago
  onyinyang 6ba706d49f Remove open invitation buckets from blockages, add test for 75% 2 years ago
  ltulloch 4525d50b54 Fixed bug that still blocked spares 2 years ago
  onyinyang f78c121f6f Changed blockage test to only block non-spare buckets 2 years ago
  ltulloch 177039a123 Add more bridges for consistency, printout units 2 years ago
  onyinyang aea4dc800f Corrected error causing response handling stdev anomaly, adjusted test size for blockages 2 years ago
  onyinyang 19c8f06e93 Add tests for varying percentages of blocked bridge 2 years ago
  onyinyang 19af8fc13b Updated print statements and number of users 2 years ago
  onyinyang d3752adc4b Add blockage migration stats test 2 years ago
  onyinyang 07ebf38e40 Added all tests but details of blockage migration 2 years ago
  onyinyang 8b2d4ab202 Modularized duplicate code and added more tests 2 years ago
  onyinyang 6223b6235b Fixed issues identified during live code review 2 years ago
  onyinyang 7a69f7ff5d Added statistics for open invite 1000 users 2 years ago
  onyinyang 8d3be9748c Added timing and measurements to all methods, TODO printout tests 2 years ago
  onyinyang b1a09eaca1 Removed types for deserialized objects 2 years ago
  onyinyang 4aaf7860cc Added timing and perfstat struct for open invite 2 years ago
  onyinyang 701a047454 Added serialized sizes for request and response in open invite 2 years ago
  onyinyang 56911752c0 Replace big_array with serde_as, cargo fmt likes things to be alphabetical 2 years ago
  onyinyang 67f2a708d4 Added serialization/deserialization for check_blockage and trust_promotion 2 years ago
  onyinyang f257280c6e Added serialization and deserialization for all but check blockage and trust promotion 2 years ago
  onyinyang cca1f7e009 Fixed comments from code review 3 years ago
  onyinyang 83d7162b7a Added Bridgeline to open-entry 3 years ago

+ 3 - 0
Cargo.toml

@@ -10,9 +10,12 @@ ed25519-dalek = "1"
 # zkp = { version = "0.8", features = ["debug-transcript"] }
 zkp = "0.8"
 bincode = "1"
+chrono = "0.4"
 rand = "0.7"
 serde = "1"
+serde_with = "1.9.1"
 sha2 = "0.9"
+statistical = "1.0.0"
 lazy_static = "1"
 hex_fmt = "0.3"
 aes-gcm = "0.8"

+ 40 - 0
README.md

@@ -0,0 +1,40 @@
+# Lox
+
+Lox is a reputation-based bridge distribution system that provides privacy protection to users and their social graph and is open to all users.
+Lox is written in rust and requires `cargo` to test. [Install Rust](https://www.rust-lang.org/tools/install)
+
+### To run the tests used for our experimental results run:
+
+```
+cargo test --release -- --nocapture TESTNAME
+```
+
+Where TESTNAME is one of:
+
+```
+stats_test_trust_levels
+stats_test_invitations
+stats_test_percent_blockage_migration_05
+stats_test_percent_blockage_migration_010
+stats_test_percent_blockage_migration_15
+stats_test_percent_blockage_migration_20
+stats_test_percent_blockage_migration_25
+stats_test_percent_blockage_migration_30
+stats_test_percent_blockage_migration_35
+stats_test_percent_blockage_migration_40
+stats_test_percent_blockage_migration_45
+stats_test_percent_blockage_migration_50
+stats_test_percent_blockage_migration_55
+stats_test_percent_blockage_migration_60
+stats_test_percent_blockage_migration_65
+stats_test_percent_blockage_migration_70
+stats_test_percent_blockage_migration_75
+stats_test_percent_blockage_migration_80
+stats_test_percent_blockage_migration_85
+stats_test_percent_blockage_migration_90
+stats_test_percent_blockage_migration_95
+stats_test_percent_blockage_migration_100
+```
+
+Note that: our implementation is coded such that the reachability certificate expires at 00:00 UTC. A workaround has been included in each test to pause if it is too close to this time so the request won't fail. In reality, if the bucket is still reachable, a user could simply request a new reachability token if their request fails for this reason (a new certificate should be available prior to the outdated certificate expiring).
+

+ 5 - 1
src/bridge_table.rs

@@ -18,6 +18,8 @@ use curve25519_dalek::ristretto::CompressedRistretto;
 use curve25519_dalek::ristretto::RistrettoBasepointTable;
 use curve25519_dalek::scalar::Scalar;
 use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
 use std::collections::{HashMap, HashSet};
 use std::convert::TryInto;
 use subtle::ConstantTimeEq;
@@ -35,7 +37,8 @@ pub const MAX_BRIDGES_PER_BUCKET: usize = 3;
 pub const MIN_BUCKET_REACHABILITY: usize = 2;
 
 /// A bridge information line
-#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
+#[serde_as]
+#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
 pub struct BridgeLine {
     /// IPv4 or IPv6 address
     pub addr: [u8; 16],
@@ -43,6 +46,7 @@ pub struct BridgeLine {
     pub port: u16,
     /// other protocol information, including pluggable transport,
     /// public key, etc.
+    #[serde_as(as = "[_; BRIDGE_BYTES - 18]")]
     pub info: [u8; BRIDGE_BYTES - 18],
 }
 

+ 4 - 0
src/proto/blockage_migration.rs

@@ -43,6 +43,8 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::migration_table::MigrationType;
@@ -52,6 +54,7 @@ use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 use super::check_blockage::MIN_TRUST_LEVEL;
 use super::level_up::LEVEL_INVITATIONS;
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     P_lox: RistrettoPoint,
@@ -92,6 +95,7 @@ pub struct State {
     blockages: Scalar,
 }
 
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     // The new attributes; the trust_level and invites_remaining are
     // implicit

+ 7 - 1
src/proto/check_blockage.rs

@@ -37,6 +37,9 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
 use std::collections::HashMap;
 
 use super::super::cred;
@@ -50,6 +53,7 @@ use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 /// perform this protocol.
 pub const MIN_TRUST_LEVEL: u32 = 3;
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     P: RistrettoPoint,
@@ -78,7 +82,8 @@ pub struct State {
     bucket: Scalar,
 }
 
-#[derive(Debug)]
+#[serde_as]
+#[derive(Serialize, Deserialize, Debug)]
 pub struct Response {
     // The encrypted MAC for the Migration Key credential
     Pk: RistrettoPoint,
@@ -87,6 +92,7 @@ pub struct Response {
     // A table of encrypted Migration credentials; the encryption keys
     // are formed from the possible values of Qk (the decrypted form of
     // EncQk)
+    #[serde_as(as = "Vec<(_,[_; migration_table::ENC_MIGRATION_BYTES])>")]
     enc_migration_table: HashMap<[u8; 16], [u8; migration_table::ENC_MIGRATION_BYTES]>,
 }
 

+ 4 - 0
src/proto/issue_invite.rs

@@ -54,12 +54,15 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::scalar_u32;
 use super::super::{BridgeAuth, IssuerPubKey};
 use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     P: RistrettoPoint,
@@ -116,6 +119,7 @@ pub struct State {
     inv_id_client: Scalar,
 }
 
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     // The fields for the new Lox credential; the new invites_remaining
     // is one less than the old value, so we don't have to include it

+ 4 - 0
src/proto/level_up.rs

@@ -47,6 +47,8 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::{pt_dbl, scalar_dbl, scalar_u32};
@@ -80,6 +82,7 @@ pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6, 8];
 // one or more bits to the ZKP.
 pub const MAX_BLOCKAGES: [u32; MAX_LEVEL + 1] = [0, 4, 3, 2, 2];
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     P: RistrettoPoint,
@@ -148,6 +151,7 @@ pub struct State {
     blockages: Scalar,
 }
 
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     // The fields for the new Lox credential; the new trust level is one
     // more than the old trust level, so we don't have to include it

+ 4 - 0
src/proto/migration.rs

@@ -39,11 +39,14 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::{BridgeAuth, IssuerPubKey};
 use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     // We don't need to include invites_remaining or blockages,
@@ -80,6 +83,7 @@ pub struct State {
     to_bucket: Scalar,
 }
 
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     // The new attributes; trust_level = 1 is implicit
     level_since: Scalar,

+ 26 - 12
src/proto/open_invite.rs

@@ -22,7 +22,11 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
 use super::super::bridge_table;
+use super::super::bridge_table::BridgeLine;
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::OPENINV_LENGTH;
@@ -30,15 +34,18 @@ use super::super::{BridgeAuth, BridgeDb, IssuerPubKey};
 use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 
 /// The request message for this protocol
+#[serde_as]
+#[derive(Serialize, Deserialize)]
 pub struct Request {
+    #[serde_as(as = "[_; OPENINV_LENGTH]")]
     invite: [u8; OPENINV_LENGTH],
     D: RistrettoPoint,
     EncIdClient: (RistrettoPoint, RistrettoPoint),
     piUserBlinding: CompactProof,
 }
 
-#[derive(Debug)]
 /// The client state for this protocol
+#[derive(Debug)]
 pub struct State {
     d: Scalar,
     D: RistrettoPoint,
@@ -47,6 +54,7 @@ pub struct State {
 }
 
 /// The response message for this protocol
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     P: RistrettoPoint,
     EncQ: (RistrettoPoint, RistrettoPoint),
@@ -55,6 +63,7 @@ pub struct Response {
     bucket: Scalar,
     level_since: Scalar,
     piBlindIssue: CompactProof,
+    bridge_line: BridgeLine,
 }
 
 // The userblinding ZKP
@@ -189,6 +198,7 @@ impl BridgeAuth {
         // of the bucket id (u32) and the bucket's decryption key ([u8; 16])
         let bucket_key = self.bridge_table.keys[bucket_id];
         let bucket: Scalar = bridge_table::to_scalar(bucket_id_u32, &bucket_key);
+        let bridge_line = self.bridge_table.buckets[bucket_id][0];
 
         // Create the level_since attribute (Scalar), which is today's
         // Julian date
@@ -253,6 +263,7 @@ impl BridgeAuth {
             bucket,
             level_since,
             piBlindIssue,
+            bridge_line,
         })
     }
 }
@@ -263,7 +274,7 @@ pub fn handle_response(
     state: State,
     resp: Response,
     lox_pub: &IssuerPubKey,
-) -> Result<cred::Lox, ProofError> {
+) -> Result<(cred::Lox, BridgeLine), ProofError> {
     let A: &RistrettoPoint = &CMZ_A;
     let B: &RistrettoPoint = &CMZ_B;
     let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
@@ -307,14 +318,17 @@ pub fn handle_response(
     // Decrypt EncQ
     let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
 
-    Ok(cred::Lox {
-        P: resp.P,
-        Q,
-        id,
-        bucket: resp.bucket,
-        trust_level: Scalar::zero(),
-        level_since: resp.level_since,
-        invites_remaining: Scalar::zero(),
-        blockages: Scalar::zero(),
-    })
+    Ok((
+        cred::Lox {
+            P: resp.P,
+            Q,
+            id,
+            bucket: resp.bucket,
+            trust_level: Scalar::zero(),
+            level_since: resp.level_since,
+            invites_remaining: Scalar::zero(),
+            blockages: Scalar::zero(),
+        },
+        resp.bridge_line,
+    ))
 }

+ 4 - 0
src/proto/redeem_invite.rs

@@ -30,6 +30,8 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+
 use super::super::cred;
 use super::super::dup_filter::SeenType;
 use super::super::{pt_dbl, scalar_dbl, scalar_u32};
@@ -41,6 +43,7 @@ use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 /// also add bits to the zero knowledge proof.
 pub const INVITATION_EXPIRY: u32 = 15;
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for showing the Invitation credential
     P: RistrettoPoint,
@@ -82,6 +85,7 @@ pub struct State {
     blockages: Scalar,
 }
 
+#[derive(Serialize, Deserialize)]
 pub struct Response {
     // The fields for the new Lox credential; the new trust level is 1
     // and the new invites_remaining is 0, so we don't have to include

+ 7 - 1
src/proto/trust_promotion.rs

@@ -36,6 +36,9 @@ use zkp::CompactProof;
 use zkp::ProofError;
 use zkp::Transcript;
 
+use serde::{Deserialize, Serialize};
+use serde_with::serde_as;
+
 use std::collections::HashMap;
 
 use super::super::cred;
@@ -54,6 +57,7 @@ use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
 /// with the system in order to move up trust levels.
 pub const UNTRUSTED_INTERVAL: u32 = 30;
 
+#[derive(Serialize, Deserialize)]
 pub struct Request {
     // Fields for blind showing the Lox credential
     // We don't need to include trust_level, invites_remaining, or
@@ -101,7 +105,8 @@ pub struct State {
     bucket: Scalar,
 }
 
-#[derive(Debug)]
+#[serde_as]
+#[derive(Serialize, Deserialize, Debug)]
 pub struct Response {
     // The encrypted MAC for the Migration Key credential
     Pk: RistrettoPoint,
@@ -110,6 +115,7 @@ pub struct Response {
     // A table of encrypted Migration credentials; the encryption keys
     // are formed from the possible values of Qk (the decrypted form of
     // EncQk)
+    #[serde_as(as = "Vec<(_,[_; migration_table::ENC_MIGRATION_BYTES])>")]
     enc_migration_table: HashMap<[u8; 16], [u8; migration_table::ENC_MIGRATION_BYTES]>,
 }
 

+ 1345 - 59
src/tests.rs

@@ -4,6 +4,21 @@ BridgeLine::random() or private fields */
 use super::bridge_table::BridgeLine;
 use super::proto::*;
 use super::*;
+use chrono::{Utc, DateTime, NaiveTime, Timelike};
+use rand::Rng;
+use statistical::{mean, standard_deviation};
+use std::collections::HashSet;
+use std::thread;
+use std::time::{Duration, Instant};
+
+struct PerfStat {
+    // Report performance metrics for each test
+    req_len: usize,
+    resp_len: usize,
+    req_t: Duration,
+    resp_t: Duration,
+    resp_handle_t: Duration,
+}
 
 struct TestHarness {
     bdb: BridgeDb,
@@ -12,13 +27,17 @@ struct TestHarness {
 
 impl TestHarness {
     fn new() -> Self {
+        TestHarness::new_buckets(5, 5)
+    }
+
+    fn new_buckets(num_buckets: u16, hot_spare: u16) -> Self {
         // Create a BridegDb
         let mut bdb = BridgeDb::new();
         // Create a BridgeAuth
         let mut ba = BridgeAuth::new(bdb.pubkey);
 
-        // Make 15 open invitation bridges, in 5 sets of 3
-        for _ in 0..5 {
+        // Make 3 x num_buckets open invitation bridges, in sets of 3
+        for _ in 0..num_buckets {
             let bucket = [
                 BridgeLine::random(),
                 BridgeLine::random(),
@@ -26,8 +45,8 @@ impl TestHarness {
             ];
             ba.add_openinv_bridges(bucket, &mut bdb);
         }
-        // Add 5 more hot spare buckets
-        for _ in 0..5 {
+        // Add hot_spare more hot spare buckets
+        for _ in 0..hot_spare {
             let bucket = [
                 BridgeLine::random(),
                 BridgeLine::random(),
@@ -45,33 +64,114 @@ impl TestHarness {
         self.ba.advance_days(days);
     }
 
-    fn open_invite(&mut self) -> cred::Lox {
+    fn open_invite(&mut self) -> (PerfStat, (cred::Lox, bridge_table::BridgeLine)) {
         // Issue an open invitation
         let inv = self.bdb.invite();
 
+        let req_start = Instant::now();
         // Use it to get a Lox credential
         let (req, state) = open_invite::request(&inv);
-        let resp = self.ba.handle_open_invite(req).unwrap();
-        open_invite::handle_response(state, resp, &self.ba.lox_pub).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_open_invite(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let (cred, bridgeline) =
+            open_invite::handle_response(state, decode_resp, &self.ba.lox_pub).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            (cred, bridgeline),
+        )
     }
 
-    fn trust_promotion(&mut self, cred: &cred::Lox) -> cred::Migration {
+    fn trust_promotion(&mut self, cred: &cred::Lox) -> (PerfStat, cred::Migration) {
+        let req_start = Instant::now();
         let (promreq, promstate) =
             trust_promotion::request(&cred, &self.ba.lox_pub, self.ba.today()).unwrap();
-        let promresp = self.ba.handle_trust_promotion(promreq).unwrap();
-        trust_promotion::handle_response(promstate, promresp).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&promreq).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let promresp = self.ba.handle_trust_promotion(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&promresp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let migcred = trust_promotion::handle_response(promstate, decode_resp).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            migcred,
+        )
     }
 
-    fn level0_migration(&mut self, loxcred: &cred::Lox, migcred: &cred::Migration) -> cred::Lox {
+    fn level0_migration(
+        &mut self,
+        loxcred: &cred::Lox,
+        migcred: &cred::Migration,
+    ) -> (PerfStat, cred::Lox) {
+        let req_start = Instant::now();
         let (migreq, migstate) =
             migration::request(loxcred, migcred, &self.ba.lox_pub, &self.ba.migration_pub).unwrap();
-        let migresp = self.ba.handle_migration(migreq).unwrap();
-        migration::handle_response(migstate, migresp, &self.ba.lox_pub).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&migreq).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let migresp = self.ba.handle_migration(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&migresp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp: migration::Response = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let cred = migration::handle_response(migstate, decode_resp, &self.ba.lox_pub).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            cred,
+        )
     }
 
-    fn level_up(&mut self, cred: &cred::Lox) -> cred::Lox {
+    fn level_up(&mut self, cred: &cred::Lox) -> (PerfStat, cred::Lox) {
         // Read the bucket in the credential to get today's Bucket
         // Reachability credential
+
         let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
         let encbuckets = self.ba.enc_bridge_table();
         let bucket =
@@ -80,6 +180,7 @@ impl TestHarness {
 
         // Use the Bucket Reachability credential to advance to the next
         // level
+        let req_start = Instant::now();
         let (req, state) = level_up::request(
             &cred,
             &reachcred,
@@ -88,11 +189,35 @@ impl TestHarness {
             self.ba.today(),
         )
         .unwrap();
-        let resp = self.ba.handle_level_up(req).unwrap();
-        level_up::handle_response(state, resp, &self.ba.lox_pub).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_level_up(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let cred = level_up::handle_response(state, decode_resp, &self.ba.lox_pub).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            cred,
+        )
     }
 
-    fn issue_invite(&mut self, cred: &cred::Lox) -> (cred::Lox, cred::Invitation) {
+    fn issue_invite(&mut self, cred: &cred::Lox) -> (PerfStat, (cred::Lox, cred::Invitation)) {
         // Read the bucket in the credential to get today's Bucket
         // Reachability credential
         let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
@@ -101,6 +226,7 @@ impl TestHarness {
             bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
         let reachcred = bucket.1.unwrap();
 
+        let req_start = Instant::now();
         let (req, state) = issue_invite::request(
             &cred,
             &reachcred,
@@ -109,30 +235,140 @@ impl TestHarness {
             self.ba.today(),
         )
         .unwrap();
-        let resp = self.ba.handle_issue_invite(req).unwrap();
-        issue_invite::handle_response(state, resp, &self.ba.lox_pub, &self.ba.invitation_pub)
-            .unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_issue_invite(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let (cred, invite) = issue_invite::handle_response(
+            state,
+            decode_resp,
+            &self.ba.lox_pub,
+            &self.ba.invitation_pub,
+        )
+        .unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            (cred, invite),
+        )
     }
 
-    fn redeem_invite(&mut self, inv: &cred::Invitation) -> cred::Lox {
+    fn redeem_invite(&mut self, inv: &cred::Invitation) -> (PerfStat, cred::Lox) {
+        let req_start = Instant::now();
         let (req, state) =
             redeem_invite::request(&inv, &self.ba.invitation_pub, self.ba.today()).unwrap();
-        let resp = self.ba.handle_redeem_invite(req).unwrap();
-        redeem_invite::handle_response(state, resp, &self.ba.lox_pub).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_redeem_invite(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let cred = redeem_invite::handle_response(state, decode_resp, &self.ba.lox_pub).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            cred,
+        )
     }
 
-    fn check_blockage(&mut self, cred: &cred::Lox) -> cred::Migration {
+    fn check_blockage(&mut self, cred: &cred::Lox) -> (PerfStat, cred::Migration) {
+        let req_start = Instant::now();
         let (req, state) = check_blockage::request(&cred, &self.ba.lox_pub).unwrap();
-        let resp = self.ba.handle_check_blockage(req).unwrap();
-        check_blockage::handle_response(state, resp).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_check_blockage(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
+        let migcred = check_blockage::handle_response(state, decode_resp).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            migcred,
+        )
     }
 
-    fn blockage_migration(&mut self, cred: &cred::Lox, mig: &cred::Migration) -> cred::Lox {
+    fn blockage_migration(
+        &mut self,
+        cred: &cred::Lox,
+        mig: &cred::Migration,
+    ) -> (PerfStat, cred::Lox) {
+        let req_start = Instant::now();
         let (req, state) =
             blockage_migration::request(&cred, &mig, &self.ba.lox_pub, &self.ba.migration_pub)
                 .unwrap();
-        let resp = self.ba.handle_blockage_migration(req).unwrap();
-        blockage_migration::handle_response(state, resp, &self.ba.lox_pub).unwrap()
+        let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
+        let req_t = req_start.elapsed();
+        let req_len = encoded.len();
+
+        let resp_start = Instant::now();
+        let decoded = bincode::deserialize(&encoded[..]).unwrap();
+        let resp = self.ba.handle_blockage_migration(decoded).unwrap();
+        let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
+        let resp_t = resp_start.elapsed();
+        let resp_len = encoded_resp.len();
+
+        let resp_handle_start = Instant::now();
+        let decode_resp: blockage_migration::Response =
+            bincode::deserialize(&encoded_resp[..]).unwrap();
+        let cred =
+            blockage_migration::handle_response(state, decode_resp, &self.ba.lox_pub).unwrap();
+        let resp_handle_t = resp_handle_start.elapsed();
+
+        (
+            PerfStat {
+                req_len,
+                resp_len,
+                req_t,
+                resp_t,
+                resp_handle_t,
+            },
+            cred,
+        )
     }
 }
 
@@ -141,30 +377,33 @@ fn test_open_invite() {
     let mut th = TestHarness::new();
 
     // Join an untrusted user
-    let cred = th.open_invite();
+    let (perf_stat, (cred, bridgeline)) = th.open_invite();
 
     // Check that we can use the credential to read a bucket
     let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
     let encbuckets = th.ba.enc_bridge_table();
     let bucket =
         bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
+    print_test_results(perf_stat);
     println!("cred = {:?}", cred);
     println!("bucket = {:?}", bucket);
+    println!("bridgeline = {:?}", bridgeline);
     assert!(bucket.1.is_none());
     assert!(th.ba.verify_lox(&cred));
+    assert!(bridgeline == bucket.0[0]);
 }
 
 #[test]
 fn test_trust_promotion() {
     let mut th = TestHarness::new();
 
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
     assert!(th.ba.verify_lox(&cred));
 
     // Time passes
     th.advance_days(47);
 
-    let migcred = th.trust_promotion(&cred);
+    let (perf_stat, migcred) = th.trust_promotion(&cred);
     assert!(th.ba.verify_migration(&migcred));
 
     // Check that we can use the to_bucket in the Migration credenital
@@ -173,6 +412,7 @@ fn test_trust_promotion() {
     let encbuckets = th.ba.enc_bridge_table();
     let bucket =
         bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
+    print_test_results(perf_stat);
     println!("bucket = {:?}", bucket);
     assert!(th.ba.verify_reachability(&bucket.1.unwrap()));
 }
@@ -181,16 +421,21 @@ fn test_trust_promotion() {
 fn test_level0_migration() {
     let mut th = TestHarness::new();
 
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
     assert!(th.ba.verify_lox(&cred));
 
     // Time passes
     th.advance_days(47);
 
-    let migcred = th.trust_promotion(&cred);
+    let (perf_stat, migcred) = th.trust_promotion(&cred);
     assert!(th.ba.verify_migration(&migcred));
+    println!("--Trust Promotion to 1--\n");
+    print_test_results(perf_stat);
+
+    let (mperf_stat, newloxcred) = th.level0_migration(&cred, &migcred);
 
-    let newloxcred = th.level0_migration(&cred, &migcred);
+    println!("--Level 0 migration--\n");
+    print_test_results(mperf_stat);
 
     assert!(th.ba.verify_lox(&newloxcred));
     println!("newloxcred = {:?}", newloxcred);
@@ -208,37 +453,52 @@ fn test_level_up() {
     let mut th = TestHarness::new();
 
     // Join an untrusted user
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
 
     // Time passes
     th.advance_days(47);
 
     // Go up to level 1
-    let migcred = th.trust_promotion(&cred);
-    let cred1 = th.level0_migration(&cred, &migcred);
+    let (perf_stat, migcred) = th.trust_promotion(&cred);
+
+    println!("--Trust Promotion to 1--\n");
+    print_test_results(perf_stat);
+
+    let (mperf_stat, cred1) = th.level0_migration(&cred, &migcred);
+
+    println!("--New Level 1 Credential--\n");
+    print_test_results(mperf_stat);
+
     assert!(scalar_u32(&cred1.trust_level).unwrap() == 1);
 
     // Time passes
     th.advance_days(20);
 
-    let cred2 = th.level_up(&cred1);
+    let (two_perf_stat, cred2) = th.level_up(&cred1);
     assert!(scalar_u32(&cred2.trust_level).unwrap() == 2);
+
+    println!("--Upgrade to Level 2--\n");
+    print_test_results(two_perf_stat);
     println!("cred2 = {:?}", cred2);
     assert!(th.ba.verify_lox(&cred2));
 
     // Time passes
     th.advance_days(30);
 
-    let cred3 = th.level_up(&cred2);
+    let (three_perf_stat, cred3) = th.level_up(&cred2);
     assert!(scalar_u32(&cred3.trust_level).unwrap() == 3);
+    println!("--Upgrade to Level 3--\n");
+    print_test_results(three_perf_stat);
     println!("cred3 = {:?}", cred3);
     assert!(th.ba.verify_lox(&cred3));
 
     // Time passes
     th.advance_days(60);
 
-    let cred4 = th.level_up(&cred3);
+    let (four_perf_stat, cred4) = th.level_up(&cred3);
     assert!(scalar_u32(&cred3.trust_level).unwrap() == 3);
+    println!("--Upgrade to Level 4--\n");
+    print_test_results(four_perf_stat);
     println!("cred4 = {:?}", cred4);
     assert!(th.ba.verify_lox(&cred4));
 }
@@ -248,27 +508,35 @@ fn test_issue_invite() {
     let mut th = TestHarness::new();
 
     // Join an untrusted user
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
 
     // Time passes
     th.advance_days(47);
 
     // Go up to level 1
-    let migcred = th.trust_promotion(&cred);
-    let cred1 = th.level0_migration(&cred, &migcred);
+    let (perf_stat, migcred) = th.trust_promotion(&cred);
+    println!("--Trust Promotion to 1--\n");
+    print_test_results(perf_stat);
+    let (mperf_stat, cred1) = th.level0_migration(&cred, &migcred);
+    println!("--New Level 1 Credential--\n");
+    print_test_results(mperf_stat);
     assert!(scalar_u32(&cred1.trust_level).unwrap() == 1);
 
     // Time passes
     th.advance_days(20);
 
     // Go up to level 2
-    let cred2 = th.level_up(&cred1);
+    let (two_perf_stat, cred2) = th.level_up(&cred1);
+    println!("--Upgrade to Level 2--\n");
+    print_test_results(two_perf_stat);
     assert!(scalar_u32(&cred2.trust_level).unwrap() == 2);
     println!("cred2 = {:?}", cred2);
     assert!(th.ba.verify_lox(&cred2));
 
     // Issue an invitation
-    let (cred2a, invite) = th.issue_invite(&cred2);
+    let (invite_perf_stat, (cred2a, invite)) = th.issue_invite(&cred2);
+    println!("--Issue Invitation--\n");
+    print_test_results(invite_perf_stat);
     assert!(th.ba.verify_lox(&cred2a));
     assert!(th.ba.verify_invitation(&invite));
     println!("cred2a = {:?}", cred2a);
@@ -280,27 +548,35 @@ fn test_redeem_invite() {
     let mut th = TestHarness::new();
 
     // Join an untrusted user
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
 
     // Time passes
     th.advance_days(47);
 
     // Go up to level 1
-    let migcred = th.trust_promotion(&cred);
-    let cred1 = th.level0_migration(&cred, &migcred);
+    let (perf_stat, migcred) = th.trust_promotion(&cred);
+    println!("--Trust Promotion to 1--\n");
+    print_test_results(perf_stat);
+    let (mperf_stat, cred1) = th.level0_migration(&cred, &migcred);
+    println!("--New Level 1 Credential--\n");
+    print_test_results(mperf_stat);
     assert!(scalar_u32(&cred1.trust_level).unwrap() == 1);
 
     // Time passes
     th.advance_days(20);
 
     // Go up to level 2
-    let cred2 = th.level_up(&cred1);
+    let (two_perf_stat, cred2) = th.level_up(&cred1);
+    println!("--Upgrade to Level 2--\n");
+    print_test_results(two_perf_stat);
     assert!(scalar_u32(&cred2.trust_level).unwrap() == 2);
     println!("cred2 = {:?}", cred2);
     assert!(th.ba.verify_lox(&cred2));
 
     // Issue an invitation to Bob
-    let (cred2a, bob_invite) = th.issue_invite(&cred2);
+    let (invite_perf_stat, (cred2a, bob_invite)) = th.issue_invite(&cred2);
+    println!("--Issue Invitation--\n");
+    print_test_results(invite_perf_stat);
     assert!(th.ba.verify_lox(&cred2a));
     assert!(th.ba.verify_invitation(&bob_invite));
     println!("cred2a = {:?}", cred2a);
@@ -310,7 +586,9 @@ fn test_redeem_invite() {
     th.advance_days(12);
 
     // Bob joins the system
-    let bob_cred = th.redeem_invite(&bob_invite);
+    let (bob_perf_stat, bob_cred) = th.redeem_invite(&bob_invite);
+    println!("--Bob joins the system--\n");
+    print_test_results(bob_perf_stat);
     assert!(th.ba.verify_lox(&bob_cred));
     println!("bob_cred = {:?}", bob_cred);
 }
@@ -370,21 +648,21 @@ fn test_blockage_migration() {
     let mut th = TestHarness::new();
 
     // Join an untrusted user
-    let cred = th.open_invite();
+    let cred = th.open_invite().1 .0;
 
     // Time passes
     th.advance_days(47);
 
     // Go up to level 1
-    let migcred = th.trust_promotion(&cred);
-    let cred1 = th.level0_migration(&cred, &migcred);
+    let (_mperf_stat, migcred) = th.trust_promotion(&cred);
+    let (_perf_stat, cred1) = th.level0_migration(&cred, &migcred);
     assert!(scalar_u32(&cred1.trust_level).unwrap() == 1);
 
     // Time passes
     th.advance_days(20);
 
     // Go up to level 2
-    let cred2 = th.level_up(&cred1);
+    let (_two_perf_stat, cred2) = th.level_up(&cred1);
     assert!(scalar_u32(&cred2.trust_level).unwrap() == 2);
     println!("cred2 = {:?}", cred2);
     assert!(th.ba.verify_lox(&cred2));
@@ -393,7 +671,7 @@ fn test_blockage_migration() {
     th.advance_days(29);
 
     // Go up to level 3
-    let cred3 = th.level_up(&cred2);
+    let (_three_perf_stat, cred3) = th.level_up(&cred2);
     assert!(scalar_u32(&cred3.trust_level).unwrap() == 3);
     println!("cred3 = {:?}", cred3);
     assert!(th.ba.verify_lox(&cred3));
@@ -425,13 +703,1021 @@ fn test_blockage_migration() {
     assert!(bucket2.1.is_none());
 
     // See about getting a Migration credential for the blockage
-    let migration = th.check_blockage(&cred3);
+    let (_block_perf_stat, migration) = th.check_blockage(&cred3);
 
     println!("migration = {:?}", migration);
 
     // Migrate
-    let cred4 = th.blockage_migration(&cred3, &migration);
+    let (_four_perf_stat, cred4) = th.blockage_migration(&cred3, &migration);
 
     println!("cred4 = {:?}", cred4);
     assert!(th.ba.verify_lox(&cred4));
 }
+
+#[test]
+fn stats_test_trust_levels() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+
+        let mut promo_req_size: Vec<f64> = Vec::new();
+        let mut promo_resp_size: Vec<f64> = Vec::new();
+        let mut promo_req_time: Vec<f64> = Vec::new();
+        let mut promo_resp_time: Vec<f64> = Vec::new();
+        let mut promo_resp_handle_time: Vec<f64> = Vec::new();
+        let mut mig_req_size: Vec<f64> = Vec::new();
+        let mut mig_resp_size: Vec<f64> = Vec::new();
+        let mut mig_req_time: Vec<f64> = Vec::new();
+        let mut mig_resp_time: Vec<f64> = Vec::new();
+        let mut mig_resp_handle_time: Vec<f64> = Vec::new();
+        let mut sec_req_size: Vec<f64> = Vec::new();
+        let mut sec_resp_size: Vec<f64> = Vec::new();
+        let mut sec_req_time: Vec<f64> = Vec::new();
+        let mut sec_resp_time: Vec<f64> = Vec::new();
+        let mut sec_resp_handle_time: Vec<f64> = Vec::new();
+        let mut three_req_size: Vec<f64> = Vec::new();
+        let mut three_resp_size: Vec<f64> = Vec::new();
+        let mut three_req_time: Vec<f64> = Vec::new();
+        let mut three_resp_time: Vec<f64> = Vec::new();
+        let mut three_resp_handle_time: Vec<f64> = Vec::new();
+        let mut four_req_size: Vec<f64> = Vec::new();
+        let mut four_resp_size: Vec<f64> = Vec::new();
+        let mut four_req_time: Vec<f64> = Vec::new();
+        let mut four_resp_time: Vec<f64> = Vec::new();
+        let mut four_resp_handle_time: Vec<f64> = Vec::new();
+        let mut open_req_size: Vec<f64> = Vec::new();
+        let mut open_resp_size: Vec<f64> = Vec::new();
+        let mut open_req_time: Vec<f64> = Vec::new();
+        let mut open_resp_time: Vec<f64> = Vec::new();
+        let mut open_resp_handle_time: Vec<f64> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let (open_perf_stat, cred) = th.open_invite();
+            th.advance_days(30);
+            let (tp_perf_stat, migcred) = th.trust_promotion(&cred.0);
+            let (mig_perf_stat, cred1) = th.level0_migration(&cred.0, &migcred);
+            th.advance_days(14);
+            let (sec_perf_stat, cred2) = th.level_up(&cred1);
+            th.advance_days(28);
+            let (three_perf_stat, cred3) = th.level_up(&cred2);
+            th.advance_days(56);
+            let (four_perf_stat, _) = th.level_up(&cred3);
+            open_req_size.push(open_perf_stat.req_len as f64);
+            open_req_time.push(open_perf_stat.req_t.as_secs_f64());
+            open_resp_size.push(open_perf_stat.resp_len as f64);
+            open_resp_time.push(open_perf_stat.resp_t.as_secs_f64());
+            open_resp_handle_time.push(open_perf_stat.resp_handle_t.as_secs_f64());
+            promo_req_size.push(tp_perf_stat.req_len as f64);
+            promo_req_time.push(tp_perf_stat.req_t.as_secs_f64());
+            promo_resp_size.push(tp_perf_stat.resp_len as f64);
+            promo_resp_time.push(tp_perf_stat.resp_t.as_secs_f64());
+            promo_resp_handle_time.push(tp_perf_stat.resp_handle_t.as_secs_f64());
+            mig_req_size.push(mig_perf_stat.req_len as f64);
+            mig_req_time.push(mig_perf_stat.req_t.as_secs_f64());
+            mig_resp_size.push(mig_perf_stat.resp_len as f64);
+            mig_resp_time.push(mig_perf_stat.resp_t.as_secs_f64());
+            mig_resp_handle_time.push(mig_perf_stat.resp_handle_t.as_secs_f64());
+            sec_req_size.push(sec_perf_stat.req_len as f64);
+            sec_req_time.push(sec_perf_stat.req_t.as_secs_f64());
+            sec_resp_size.push(sec_perf_stat.resp_len as f64);
+            sec_resp_time.push(sec_perf_stat.resp_t.as_secs_f64());
+            sec_resp_handle_time.push(sec_perf_stat.resp_handle_t.as_secs_f64());
+            three_req_size.push(three_perf_stat.req_len as f64);
+            three_req_time.push(three_perf_stat.req_t.as_secs_f64());
+            three_resp_size.push(three_perf_stat.resp_len as f64);
+            three_resp_time.push(three_perf_stat.resp_t.as_secs_f64());
+            three_resp_handle_time.push(three_perf_stat.resp_handle_t.as_secs_f64());
+            four_req_size.push(four_perf_stat.req_len as f64);
+            four_req_time.push(four_perf_stat.req_t.as_secs_f64());
+            four_resp_size.push(four_perf_stat.resp_len as f64);
+            four_resp_time.push(four_perf_stat.resp_t.as_secs_f64());
+            four_resp_handle_time.push(four_perf_stat.resp_handle_t.as_secs_f64());
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS LEVELS***\n", x);
+        println!("\n----OPEN-INVITATION-{}---\n", x);
+        print_stats_test_results(
+            open_req_size,
+            open_req_time,
+            open_resp_size,
+            open_resp_time,
+            open_resp_handle_time,
+        );
+
+        println!("\n----TRUST-PROMOTION-1: 30 days-{}---\n", x);
+        print_stats_test_results(
+            promo_req_size,
+            promo_req_time,
+            promo_resp_size,
+            promo_resp_time,
+            promo_resp_handle_time,
+        );
+
+        println!("\n----TRUST-MIGRATION-0: 30 days-{}---\n", x);
+        print_stats_test_results(
+            mig_req_size,
+            mig_req_time,
+            mig_resp_size,
+            mig_resp_time,
+            mig_resp_handle_time,
+        );
+
+        println!("\n----LEVEL-UP-2: 44 days-{}---\n", x);
+        print_stats_test_results(
+            sec_req_size,
+            sec_req_time,
+            sec_resp_size,
+            sec_resp_time,
+            sec_resp_handle_time,
+        );
+
+        println!("\n----LEVEL-UP-3: 72 days---{}---\n", x);
+        print_stats_test_results(
+            three_req_size,
+            three_req_time,
+            three_resp_size,
+            three_resp_time,
+            three_resp_handle_time,
+        );
+
+        println!("\n----LEVEL-UP-4: 128 days---{}---\n", x);
+        print_stats_test_results(
+            four_req_size,
+            four_req_time,
+            four_resp_size,
+            four_resp_time,
+            four_resp_handle_time,
+        );
+    }
+}
+
+#[test]
+fn stats_test_invitations() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+
+        let mut req_size: Vec<f64> = Vec::new();
+        let mut resp_size: Vec<f64> = Vec::new();
+        let mut req_time: Vec<f64> = Vec::new();
+        let mut resp_time: Vec<f64> = Vec::new();
+        let mut resp_handle_time: Vec<f64> = Vec::new();
+        let mut red_req_size: Vec<f64> = Vec::new();
+        let mut red_resp_size: Vec<f64> = Vec::new();
+        let mut red_req_time: Vec<f64> = Vec::new();
+        let mut red_resp_time: Vec<f64> = Vec::new();
+        let mut red_resp_handle_time: Vec<f64> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            th.advance_days(28);
+            let (perf_stat, (_, invite)) = th.issue_invite(&cred2);
+            let (bob_perf_stat, _) = th.redeem_invite(&invite);
+            req_size.push(perf_stat.req_len as f64);
+            req_time.push(perf_stat.req_t.as_secs_f64());
+            resp_size.push(perf_stat.resp_len as f64);
+            resp_time.push(perf_stat.resp_t.as_secs_f64());
+            resp_handle_time.push(perf_stat.resp_handle_t.as_secs_f64());
+            red_req_size.push(bob_perf_stat.req_len as f64);
+            red_req_time.push(bob_perf_stat.req_t.as_secs_f64());
+            red_resp_size.push(bob_perf_stat.resp_len as f64);
+            red_resp_time.push(bob_perf_stat.resp_t.as_secs_f64());
+            red_resp_handle_time.push(bob_perf_stat.resp_handle_t.as_secs_f64());
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS INVITATIONS***\n", x);
+        println!("\n----ISSUE-INVITATION-{}---\n", x);
+        print_stats_test_results(req_size, req_time, resp_size, resp_time, resp_handle_time);
+
+        println!("\n----REDEEM-INVITATION-{}---\n", x);
+        print_stats_test_results(
+            red_req_size,
+            red_req_time,
+            red_resp_size,
+            red_resp_time,
+            red_resp_handle_time,
+        );
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_05() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 5***\n", x);
+        block_bridges(&mut th, 5, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_010() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 10***\n", x);
+        block_bridges(&mut th, 10, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_15() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 15***\n", x);
+        block_bridges(&mut th, 15, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_20() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 20***\n", x);
+        block_bridges(&mut th, 20, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_25() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 25***\n", x);
+        block_bridges(&mut th, 25, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_30() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 30***\n", x);
+        block_bridges(&mut th, 30, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_35() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 35***\n", x);
+        block_bridges(&mut th, 35, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_40() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 40***\n", x);
+        block_bridges(&mut th, 40, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_45() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 45***\n", x);
+        block_bridges(&mut th, 45, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_50() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 50***\n", x);
+        block_bridges(&mut th, 50, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_55() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 55***\n", x);
+        block_bridges(&mut th, 55, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_60() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 60***\n", x);
+        block_bridges(&mut th, 60, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_65() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 65***\n", x);
+        block_bridges(&mut th, 65, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_70() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 70***\n", x);
+        block_bridges(&mut th, 70, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_75() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 75***\n", x);
+        block_bridges(&mut th, 75, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_80() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 80***\n", x);
+        block_bridges(&mut th, 80, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_85() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 85***\n", x);
+        block_bridges(&mut th, 85, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_90() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 90***\n", x);
+        block_bridges(&mut th, 90, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_95() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+
+        println!("\n***START: {}*3*2 BUCKETS 95***\n", x);
+        block_bridges(&mut th, 95, credentials);
+    }
+}
+
+#[test]
+fn stats_test_percent_blockage_migration_100() {
+    let buckets: Vec<u16> = vec![150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500];
+
+    for x in buckets {
+        let mut th = TestHarness::new_buckets(x, x);
+        let mut credentials: Vec<cred::Lox> = Vec::new();
+        for _ in 0..10000 {
+	    let h: NaiveTime = DateTime::time(&Utc::now());
+            if h.hour() == 23 && h.minute() == 59 {
+                println!("Wait for UTC 00:00");
+		thread::sleep(Duration::new(60,0));
+                println!("Ready to work again");
+            }
+            let cred = th.open_invite().1 .0;
+            th.advance_days(30);
+            let (_, migcred) = th.trust_promotion(&cred);
+            let (_, cred1) = th.level0_migration(&cred, &migcred);
+            th.advance_days(14);
+            let (_, cred2) = th.level_up(&cred1);
+            let (_, (cred2a, invite)) = th.issue_invite(&cred2);
+            let (_, bob_cred) = th.redeem_invite(&invite);
+            th.advance_days(28);
+            let (_, _) = th.level_up(&bob_cred);
+            let (_, cred3) = th.level_up(&cred2a);
+            credentials.push(cred3);
+        }
+        println!("\n***START: {}*3*2 BUCKETS 100***\n", x);
+        block_bridges(&mut th, 100, credentials);
+    }
+}
+
+/// Blocks a percentage of the bridges for the passed Test Harness
+/// excluding the hot spare buckets as they will not have been handed out.
+/// The logic assumes hot spare buckets are appended to the end of the bridge_table
+/// bucket list.
+
+fn block_bridges(th: &mut TestHarness, percentage: usize, credentials: Vec<cred::Lox>) {
+    let blockable_num = th.ba.bridge_table.buckets.len()
+        - th.ba.bridge_table.spares.len()
+        - th.bdb.openinv_buckets.len();
+    let blockable_range = th.ba.bridge_table.buckets.len() - th.ba.bridge_table.spares.len();
+    let to_block: usize = (blockable_num * percentage / 100).into();
+    let mut block_index: HashSet<usize> = HashSet::new();
+    let mut rng = rand::thread_rng();
+
+    while block_index.len() <= to_block - 1 {
+        let rand_num = rng.gen_range(0, blockable_range);
+        if !th.bdb.openinv_buckets.contains(&(rand_num as u32)) {
+            block_index.insert(rand_num);
+        }
+    }
+
+    for index in block_index {
+        let b0 = th.ba.bridge_table.buckets[index][0];
+        let b1 = th.ba.bridge_table.buckets[index][1];
+        let b2 = th.ba.bridge_table.buckets[index][2];
+        th.ba.bridge_unreachable(&b0, &mut th.bdb);
+        th.ba.bridge_unreachable(&b1, &mut th.bdb);
+        th.ba.bridge_unreachable(&b2, &mut th.bdb);
+    }
+
+    let mut req_size: Vec<f64> = Vec::new();
+    let mut resp_size: Vec<f64> = Vec::new();
+    let mut req_time: Vec<f64> = Vec::new();
+    let mut resp_time: Vec<f64> = Vec::new();
+    let mut resp_handle_time: Vec<f64> = Vec::new();
+    let mut red_req_size: Vec<f64> = Vec::new();
+    let mut red_resp_size: Vec<f64> = Vec::new();
+    let mut red_req_time: Vec<f64> = Vec::new();
+    let mut red_resp_time: Vec<f64> = Vec::new();
+    let mut red_resp_handle_time: Vec<f64> = Vec::new();
+    for cred in credentials {
+        let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
+        let encbuckets = th.ba.enc_bridge_table();
+        let bucket =
+            bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
+
+        let mut count = 0;
+        for bridge_line in &bucket.0 {
+            if th.ba.bridge_table.reachable.contains_key(bridge_line) {
+                count = count + 1;
+            }
+        }
+
+        if count < 2 {
+            let (perf_stat, migration) = th.check_blockage(&cred);
+            let (block_perf_stat, _) = th.blockage_migration(&cred, &migration);
+            req_size.push(perf_stat.req_len as f64);
+            req_time.push(perf_stat.req_t.as_secs_f64());
+            resp_size.push(perf_stat.resp_len as f64);
+            resp_time.push(perf_stat.resp_t.as_secs_f64());
+            resp_handle_time.push(perf_stat.resp_handle_t.as_secs_f64());
+            red_req_size.push(block_perf_stat.req_len as f64);
+            red_req_time.push(block_perf_stat.req_t.as_secs_f64());
+            red_resp_size.push(block_perf_stat.resp_len as f64);
+            red_resp_time.push(block_perf_stat.resp_t.as_secs_f64());
+            red_resp_handle_time.push(block_perf_stat.resp_handle_t.as_secs_f64());
+        }
+    }
+
+    println!("\n----CHECK-BLOCKAGE-{}----\n", percentage);
+    print_stats_test_results(req_size, req_time, resp_size, resp_time, resp_handle_time);
+
+    println!("\n----BLOCKAGE-MIGRATION-{}----\n", percentage);
+    print_stats_test_results(
+        red_req_size,
+        red_req_time,
+        red_resp_size,
+        red_resp_time,
+        red_resp_handle_time,
+    );
+}
+
+fn print_test_results(perf_stat: PerfStat) {
+    println!("Request size = {:?} bytes", perf_stat.req_len);
+    println!("Request time = {:?}", perf_stat.req_t);
+    println!("Response size = {:?} bytes", perf_stat.resp_len);
+    println!("Response time = {:?}", perf_stat.resp_t);
+    println!("Response handle time = {:?}", perf_stat.resp_handle_t);
+}
+
+//fn print_time_test_results(perf_stat: PerfStat) {
+//    println!("Request time = {:?}", perf_stat.req_t);
+//    println!("Response time = {:?}", perf_stat.resp_t);
+//    println!("Response handle time = {:?}", perf_stat.resp_handle_t);
+//}
+
+fn print_stats_test_results(
+    req_size: Vec<f64>,
+    req_time: Vec<f64>,
+    resp_size: Vec<f64>,
+    resp_time: Vec<f64>,
+    resp_handle_time: Vec<f64>,
+) {
+    let mean_req_size = mean(&req_size);
+    let req_std_dev = standard_deviation(&req_size, Some(mean_req_size));
+    let mean_req_time = mean(&req_time);
+    let req_time_std_dev = standard_deviation(&req_time, Some(mean_req_time));
+    let mean_resp_size = mean(&resp_size);
+    let resp_std_dev = standard_deviation(&resp_size, Some(mean_resp_size));
+    let mean_resp_time = mean(&resp_time);
+    let resp_time_std_dev = standard_deviation(&resp_time, Some(mean_resp_time));
+    let mean_resp_handle_time = mean(&resp_handle_time);
+    let resp_handle_time_std_dev =
+        standard_deviation(&resp_handle_time, Some(mean_resp_handle_time));
+
+    println!("Average request size = {} bytes", mean_req_size);
+    println!("Request size standard deviation = {} bytes", req_std_dev);
+    println!(
+        "Average request time = {:?}",
+        Duration::from_secs_f64(mean_req_time)
+    );
+    println!(
+        "Request time standard deviation = {:?}",
+        Duration::from_secs_f64(req_time_std_dev)
+    );
+    println!("Average response size = {} bytes", mean_resp_size);
+    println!("Response standard deviation = {} bytes", resp_std_dev);
+    println!(
+        "Average response time = {:?}",
+        Duration::from_secs_f64(mean_resp_time)
+    );
+    println!(
+        "Response time standard deviation = {:?}",
+        Duration::from_secs_f64(resp_time_std_dev)
+    );
+    println!(
+        "Average response handling time = {:?}",
+        Duration::from_secs_f64(mean_resp_handle_time)
+    );
+    println!(
+        "Response handling time standard deviation = {:?}",
+        Duration::from_secs_f64(resp_handle_time_std_dev)
+    );
+}