/*! Unit tests that require access to the testing-only function BridgeLine::random() or private fields */ use super::bridge_table::BridgeLine; use super::proto::*; use super::*; struct TestHarness { bdb: BridgeDb, pub ba: BridgeAuth, } impl TestHarness { fn new() -> 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 { let bucket = [ BridgeLine::random(), BridgeLine::random(), BridgeLine::random(), ]; ba.add_openinv_bridges(bucket, &mut bdb); } // Add 5 more hot spare buckets for _ in 0..5 { let bucket = [ BridgeLine::random(), BridgeLine::random(), BridgeLine::random(), ]; ba.add_spare_bucket(bucket); } // Create the encrypted bridge table ba.enc_bridge_table(); Self { bdb, ba } } fn advance_days(&mut self, days: u16) { self.ba.advance_days(days); } fn open_invite(&mut self) -> cred::Lox { // Issue an open invitation let inv = self.bdb.invite(); // 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() } fn trust_promotion(&mut self, cred: &cred::Lox) -> cred::Migration { 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() } fn level0_migration(&mut self, loxcred: &cred::Lox, migcred: &cred::Migration) -> cred::Lox { 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() } fn level_up(&mut self, cred: &cred::Lox) -> 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 = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); let reachcred = bucket.1.unwrap(); // Use the Bucket Reachability credential to advance to the next // level let (req, state) = level_up::request( &cred, &reachcred, &self.ba.lox_pub, &self.ba.reachability_pub, self.ba.today(), ) .unwrap(); let resp = self.ba.handle_level_up(req).unwrap(); level_up::handle_response(state, resp, &self.ba.lox_pub).unwrap() } fn issue_invite(&mut self, cred: &cred::Lox) -> (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(); let encbuckets = self.ba.enc_bridge_table(); let bucket = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); let reachcred = bucket.1.unwrap(); let (req, state) = issue_invite::request( &cred, &reachcred, &self.ba.lox_pub, &self.ba.reachability_pub, 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() } fn redeem_invite(&mut self, inv: &cred::Invitation) -> cred::Lox { 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() } fn check_blockage(&mut self, cred: &cred::Lox) -> cred::Migration { 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() } fn blockage_migration(&mut self, cred: &cred::Lox, mig: &cred::Migration) -> cred::Lox { 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() } } #[test] fn test_open_invite() { let mut th = TestHarness::new(); // Join an untrusted user let cred = 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(); println!("cred = {:?}", cred); println!("bucket = {:?}", bucket); assert!(bucket.1.is_none()); assert!(th.ba.verify_lox(&cred)); } #[test] fn test_trust_promotion() { let mut th = TestHarness::new(); let cred = th.open_invite(); assert!(th.ba.verify_lox(&cred)); // Time passes th.advance_days(47); let migcred = th.trust_promotion(&cred); assert!(th.ba.verify_migration(&migcred)); // Check that we can use the to_bucket in the Migration credenital // to read a bucket let (id, key) = bridge_table::from_scalar(migcred.to_bucket).unwrap(); let encbuckets = th.ba.enc_bridge_table(); let bucket = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); println!("bucket = {:?}", bucket); assert!(th.ba.verify_reachability(&bucket.1.unwrap())); } #[test] fn test_level0_migration() { let mut th = TestHarness::new(); let cred = th.open_invite(); assert!(th.ba.verify_lox(&cred)); // Time passes th.advance_days(47); let migcred = th.trust_promotion(&cred); assert!(th.ba.verify_migration(&migcred)); let newloxcred = th.level0_migration(&cred, &migcred); assert!(th.ba.verify_lox(&newloxcred)); println!("newloxcred = {:?}", newloxcred); // Check that we can use the credenital to read a bucket let (id, key) = bridge_table::from_scalar(newloxcred.bucket).unwrap(); let encbuckets = th.ba.enc_bridge_table(); let bucket = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); println!("bucket = {:?}", bucket); assert!(th.ba.verify_reachability(&bucket.1.unwrap())); } #[test] fn test_level_up() { let mut th = TestHarness::new(); // Join an untrusted user let cred = th.open_invite(); // Time passes th.advance_days(47); // Go up to level 1 let migcred = th.trust_promotion(&cred); let cred1 = th.level0_migration(&cred, &migcred); assert!(scalar_u32(&cred1.trust_level).unwrap() == 1); // Time passes th.advance_days(20); let cred2 = th.level_up(&cred1); assert!(scalar_u32(&cred2.trust_level).unwrap() == 2); println!("cred2 = {:?}", cred2); assert!(th.ba.verify_lox(&cred2)); // Time passes th.advance_days(30); let cred3 = th.level_up(&cred2); assert!(scalar_u32(&cred3.trust_level).unwrap() == 3); println!("cred3 = {:?}", cred3); assert!(th.ba.verify_lox(&cred3)); // Time passes th.advance_days(60); let cred4 = th.level_up(&cred3); assert!(scalar_u32(&cred3.trust_level).unwrap() == 3); println!("cred4 = {:?}", cred4); assert!(th.ba.verify_lox(&cred4)); } #[test] fn test_issue_invite() { let mut th = TestHarness::new(); // Join an untrusted user let cred = th.open_invite(); // Time passes th.advance_days(47); // Go up to level 1 let migcred = th.trust_promotion(&cred); let 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); 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); assert!(th.ba.verify_lox(&cred2a)); assert!(th.ba.verify_invitation(&invite)); println!("cred2a = {:?}", cred2a); println!("invite = {:?}", invite); } #[test] fn test_redeem_invite() { let mut th = TestHarness::new(); // Join an untrusted user let cred = th.open_invite(); // Time passes th.advance_days(47); // Go up to level 1 let migcred = th.trust_promotion(&cred); let 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); 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); assert!(th.ba.verify_lox(&cred2a)); assert!(th.ba.verify_invitation(&bob_invite)); println!("cred2a = {:?}", cred2a); println!("bob_invite = {:?}", bob_invite); // Time passes th.advance_days(12); // Bob joins the system let bob_cred = th.redeem_invite(&bob_invite); assert!(th.ba.verify_lox(&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); } #[test] fn test_blockage_migration() { let mut th = TestHarness::new(); // Join an untrusted user let cred = th.open_invite(); // Time passes th.advance_days(47); // Go up to level 1 let migcred = th.trust_promotion(&cred); let 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); assert!(scalar_u32(&cred2.trust_level).unwrap() == 2); println!("cred2 = {:?}", cred2); assert!(th.ba.verify_lox(&cred2)); // Time passes th.advance_days(29); // Go up to level 3 let cred3 = th.level_up(&cred2); assert!(scalar_u32(&cred3.trust_level).unwrap() == 3); println!("cred3 = {:?}", cred3); assert!(th.ba.verify_lox(&cred3)); // Get our bridges let (id, key) = bridge_table::from_scalar(cred3.bucket).unwrap(); let encbuckets = th.ba.enc_bridge_table(); let bucket = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); // We should have a Bridge Reachability credential assert!(bucket.1.is_some()); // Oh, no! Two of our bridges are blocked! th.ba.bridge_unreachable(&bucket.0[0], &mut th.bdb); th.ba.bridge_unreachable(&bucket.0[2], &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); // Time passes th.advance_days(1); let encbuckets2 = th.ba.enc_bridge_table(); let bucket2 = bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets2[id as usize]).unwrap(); // We should no longer have a Bridge Reachability credential assert!(bucket2.1.is_none()); // See about getting a Migration credential for the blockage let migration = th.check_blockage(&cred3); println!("migration = {:?}", migration); // Migrate let cred4 = th.blockage_migration(&cred3, &migration); println!("cred4 = {:?}", cred4); assert!(th.ba.verify_lox(&cred4)); }