1#![allow(non_snake_case)]
16
17#[macro_use]
18extern crate lox_zkp;
19
20pub mod bridge_table;
21pub mod bridge_verification_info;
22pub mod cred;
23pub mod dup_filter;
24pub mod migration_table;
25
26use bridge_verification_info::BridgeVerificationInfo;
27#[cfg(feature = "bridgeauth")]
28use chrono::{DateTime, Duration, Utc};
29#[cfg(feature = "blockage-detection")]
30use sha1::{Digest, Sha1};
31use sha2::Sha512;
32
33use curve25519_dalek::constants as dalek_constants;
34use curve25519_dalek::ristretto::RistrettoBasepointTable;
35use curve25519_dalek::ristretto::RistrettoPoint;
36use curve25519_dalek::scalar::Scalar;
37#[cfg(test)]
38use curve25519_dalek::traits::IsIdentity;
39#[allow(unused_imports)]
40use rand::rngs::OsRng;
41#[allow(unused_imports)]
42use rand::Rng;
43#[cfg(feature = "bridgeauth")]
44use std::collections::HashMap;
45#[cfg(feature = "bridgeauth")]
46use std::convert::TryFrom;
47use std::convert::TryInto;
48
49#[cfg(feature = "bridgeauth")]
50use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
51use subtle::ConstantTimeEq;
52
53#[cfg(feature = "bridgeauth")]
54use std::collections::HashSet;
55
56#[cfg(feature = "bridgeauth")]
57use bridge_table::{
58 BridgeLine, BridgeTable, EncryptedBucket, MAX_BRIDGES_PER_BUCKET, MIN_BUCKET_REACHABILITY,
59};
60#[cfg(feature = "bridgeauth")]
61use migration_table::{MigrationTable, MigrationType};
62
63use lazy_static::lazy_static;
64
65use serde::{Deserialize, Serialize};
66#[cfg(feature = "bridgeauth")]
67use thiserror::Error;
68
69lazy_static! {
70 pub static ref CMZ_A: RistrettoPoint =
71 RistrettoPoint::hash_from_bytes::<Sha512>(b"CMZ Generator A");
72 pub static ref CMZ_B: RistrettoPoint = dalek_constants::RISTRETTO_BASEPOINT_POINT;
73 pub static ref CMZ_A_TABLE: RistrettoBasepointTable = RistrettoBasepointTable::create(&CMZ_A);
74 pub static ref CMZ_B_TABLE: RistrettoBasepointTable =
75 dalek_constants::RISTRETTO_BASEPOINT_TABLE.clone();
76}
77
78pub const EXPIRY_DATE: u32 = 511;
82
83#[derive(PartialEq, Eq)]
86#[cfg(feature = "bridgeauth")]
87pub enum ReplaceSuccess {
88 NotFound = 0,
89 NotReplaced = 1,
90 Replaced = 2,
91 Removed = 3,
92}
93
94#[derive(Error, Debug)]
97#[cfg(feature = "bridgeauth")]
98pub enum NoAvailableIDError {
99 #[error("Find key exhausted with no available index found!")]
100 ExhaustedIndexer,
101}
102
103#[derive(Error, Debug)]
106#[cfg(feature = "bridgeauth")]
107pub enum OpenInvitationError {
108 #[error("The maximum number of bridges has already been distributed today, please try again tomorrow!")]
109 ExceededMaxBridges,
110
111 #[error("There are no bridges available for open invitations.")]
112 NoBridgesAvailable,
113}
114
115#[derive(Error, Debug)]
116#[cfg(feature = "bridgeauth")]
117pub enum BridgeTableError {
118 #[error("The bucket corresponding to key {0} was not in the bridge table")]
119 MissingBucket(u32),
120}
121
122#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
124pub struct IssuerPrivKey {
125 x0tilde: Scalar,
126 x: Vec<Scalar>,
127}
128
129impl IssuerPrivKey {
130 pub fn new(n: u16) -> IssuerPrivKey {
133 let mut rng = rand::thread_rng();
134 let x0tilde = Scalar::random(&mut rng);
135 let mut x: Vec<Scalar> = Vec::with_capacity((n + 1) as usize);
136
137 x.resize_with((n + 1) as usize, || Scalar::random(&mut rng));
139
140 IssuerPrivKey { x0tilde, x }
141 }
142}
143
144#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
145pub struct IssuerPubKey {
146 X: Vec<RistrettoPoint>,
147}
148
149impl IssuerPubKey {
151 pub fn new(privkey: &IssuerPrivKey) -> IssuerPubKey {
153 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
154 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
155 let n_plus_one = privkey.x.len();
156 let mut X: Vec<RistrettoPoint> = Vec::with_capacity(n_plus_one);
157
158 X.push(&privkey.x0tilde * Atable + &privkey.x[0] * Btable);
161
162 X.extend(privkey.x.iter().skip(1).map(|xi| xi * Atable));
164
165 IssuerPubKey { X }
166 }
167}
168
169pub const OPENINV_K: u32 = 10;
171pub const MAX_DAILY_BRIDGES: u32 = 100;
173#[derive(Debug, Serialize, Deserialize)]
177#[cfg(feature = "bridgeauth")]
178pub struct BridgeDb {
179 keypair: SigningKey,
181 pub pubkey: VerifyingKey,
183 openinv_buckets: HashSet<u32>,
185 distributed_buckets: Vec<u32>,
187 #[serde(skip)]
188 today: DateTime<Utc>,
189 pub current_k: u32,
190 pub daily_bridges_distributed: u32,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
194#[cfg(feature = "bridgeauth")]
195pub struct OldKeyStore {
196 priv_key: IssuerPrivKey,
198 pub pub_key: IssuerPubKey,
200}
201
202#[derive(Debug, Default, Clone, Serialize, Deserialize)]
203#[cfg(feature = "bridgeauth")]
204pub struct OldKeys {
205 lox_keys: Vec<OldKeyStore>,
207 bridgedb_key: Vec<VerifyingKey>,
209 invitation_keys: Vec<OldKeyStore>,
211}
212
213#[derive(Debug, Default, Clone, Serialize, Deserialize)]
214#[cfg(feature = "bridgeauth")]
215pub struct OldFilters {
216 lox_filter: Vec<dup_filter::DupFilter<Scalar>>,
218 openinv_filter: Vec<dup_filter::DupFilter<Scalar>>,
220 invitation_filter: Vec<dup_filter::DupFilter<Scalar>>,
222}
223
224pub const OPENINV_LENGTH: usize = 32 + 4 + ed25519_dalek::SIGNATURE_LENGTH; #[cfg(feature = "bridgeauth")]
234impl BridgeDb {
235 pub fn new() -> Self {
237 let mut csprng = OsRng {};
238 let keypair = SigningKey::generate(&mut csprng);
239 let pubkey = keypair.verifying_key();
240 Self {
241 keypair,
242 pubkey,
243 openinv_buckets: Default::default(),
244 distributed_buckets: Default::default(),
245 today: Utc::now(),
246 current_k: 0,
247 daily_bridges_distributed: 0,
248 }
249 }
250
251 pub fn openinv_length(&mut self) -> usize {
252 self.openinv_buckets.len()
253 }
254
255 pub fn rotate_open_inv_keys(&mut self) -> VerifyingKey {
257 let mut csprng = OsRng {};
258 self.keypair = SigningKey::generate(&mut csprng);
259 self.pubkey = self.keypair.verifying_key();
260 self.pubkey
261 }
262
263 pub fn insert_openinv(&mut self, bucket: u32) {
265 self.openinv_buckets.insert(bucket);
266 }
267
268 pub fn remove_openinv(&mut self, bucket: &u32) {
270 self.openinv_buckets.remove(bucket);
271 }
272
273 pub fn remove_blocked_or_expired_buckets(&mut self, bucket: &u32) {
276 if self.openinv_buckets.contains(bucket) {
277 println!("Removing a bucket that has not been distributed yet!");
278 self.openinv_buckets.remove(bucket);
279 } else if self.distributed_buckets.contains(bucket) {
280 self.distributed_buckets.retain(|&x| x != *bucket);
281 }
282 }
283
284 pub fn mark_distributed(&mut self, bucket: u32) {
286 self.distributed_buckets.push(bucket);
287 }
288
289 pub fn invite(&mut self) -> Result<[u8; OPENINV_LENGTH], OpenInvitationError> {
293 let mut res: [u8; OPENINV_LENGTH] = [0; OPENINV_LENGTH];
294 let mut rng = rand::thread_rng();
295 let id = Scalar::random(&mut rng);
297 res[0..32].copy_from_slice(&id.to_bytes());
298 let bucket_num: u32;
299 if Utc::now() >= (self.today + Duration::days(1)) {
300 self.today = Utc::now();
301 self.daily_bridges_distributed = 0;
302 }
303 if self.daily_bridges_distributed < MAX_DAILY_BRIDGES {
304 if self.current_k < OPENINV_K && !self.distributed_buckets.is_empty() {
305 bucket_num = *self.distributed_buckets.last().unwrap();
306 self.current_k += 1;
307 } else {
308 if self.openinv_buckets.is_empty() {
309 return Err(OpenInvitationError::NoBridgesAvailable);
310 }
311 let openinv_vec: Vec<&u32> = self.openinv_buckets.iter().collect();
314 bucket_num = *openinv_vec[rng.gen_range(0..openinv_vec.len())];
315 self.mark_distributed(bucket_num);
316 self.remove_openinv(&bucket_num);
317 self.current_k = 1;
318 self.daily_bridges_distributed += 1;
319 }
320 res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
321 let sig = self.keypair.sign(&res[0..(32 + 4)]);
323 res[(32 + 4)..].copy_from_slice(&sig.to_bytes());
324 Ok(res)
325 } else {
326 Err(OpenInvitationError::ExceededMaxBridges)
327 }
328 }
329
330 pub fn verify(
335 invitation: [u8; OPENINV_LENGTH],
336 pubkey: VerifyingKey,
337 ) -> Result<(Scalar, u32), SignatureError> {
338 let sig = Signature::try_from(&invitation[(32 + 4)..])?;
340 pubkey.verify(&invitation[0..(32 + 4)], &sig)?;
341 let bucket = u32::from_le_bytes(invitation[32..(32 + 4)].try_into().unwrap());
344 let s = Scalar::from_canonical_bytes(invitation[0..32].try_into().unwrap());
345 if s.is_some().into() {
346 Ok((s.unwrap(), bucket))
347 } else {
348 Err(SignatureError::new())
351 }
352 }
353
354 pub fn advance_days(&mut self, days: u16) {
358 if days > 0 {
359 self.today += Duration::days(days.into());
360 self.daily_bridges_distributed = 0;
362 }
363 }
364}
365
366#[cfg(feature = "bridgeauth")]
367impl Default for BridgeDb {
368 fn default() -> Self {
369 Self::new()
370 }
371}
372
373#[cfg(feature = "bridgeauth")]
375#[derive(Debug, Serialize, Deserialize)]
376pub struct BridgeAuth {
377 lox_priv: IssuerPrivKey,
379 pub lox_pub: IssuerPubKey,
381 migration_priv: IssuerPrivKey,
383 pub migration_pub: IssuerPubKey,
385 migrationkey_priv: IssuerPrivKey,
387 pub migrationkey_pub: IssuerPubKey,
389 reachability_priv: IssuerPrivKey,
391 pub reachability_pub: IssuerPubKey,
393 invitation_priv: IssuerPrivKey,
395 pub invitation_pub: IssuerPubKey,
397
398 pub bridgedb_pub: VerifyingKey,
400
401 bridge_table: BridgeTable,
403
404 pub tp_bridge_infos: HashMap<String, BridgeVerificationInfo>,
406
407 trustup_migration_table: MigrationTable,
409 blockage_migration_table: MigrationTable,
410
411 bridgedb_pub_filter: dup_filter::DupFilter<Scalar>,
413 id_filter: dup_filter::DupFilter<Scalar>,
415 inv_id_filter: dup_filter::DupFilter<Scalar>,
417 trust_promotion_filter: dup_filter::DupFilter<Scalar>,
420 old_keys: OldKeys,
423 old_filters: OldFilters,
424
425 #[serde(skip)]
427 time_offset: time::Duration,
428}
429
430#[cfg(feature = "bridgeauth")]
431impl BridgeAuth {
432 pub fn new(bridgedb_pub: VerifyingKey) -> Self {
433 let lox_priv = IssuerPrivKey::new(6);
436 let lox_pub = IssuerPubKey::new(&lox_priv);
437 let migration_priv = IssuerPrivKey::new(4);
438 let migration_pub = IssuerPubKey::new(&migration_priv);
439 let migrationkey_priv = IssuerPrivKey::new(2);
440 let migrationkey_pub = IssuerPubKey::new(&migrationkey_priv);
441 let reachability_priv = IssuerPrivKey::new(2);
442 let reachability_pub = IssuerPubKey::new(&reachability_priv);
443 let invitation_priv = IssuerPrivKey::new(4);
444 let invitation_pub = IssuerPubKey::new(&invitation_priv);
445 Self {
446 lox_priv,
447 lox_pub,
448 migration_priv,
449 migration_pub,
450 migrationkey_priv,
451 migrationkey_pub,
452 reachability_priv,
453 reachability_pub,
454 invitation_priv,
455 invitation_pub,
456 bridgedb_pub,
457 bridge_table: Default::default(),
458 tp_bridge_infos: HashMap::<String, BridgeVerificationInfo>::new(),
459 trustup_migration_table: MigrationTable::new(MigrationType::TrustUpgrade),
460 blockage_migration_table: MigrationTable::new(MigrationType::Blockage),
461 bridgedb_pub_filter: Default::default(),
462 id_filter: Default::default(),
463 inv_id_filter: Default::default(),
464 trust_promotion_filter: Default::default(),
465 time_offset: time::Duration::ZERO,
466 old_keys: Default::default(),
467 old_filters: Default::default(),
468 }
469 }
470
471 pub fn rotate_lox_keys(&mut self) {
472 let updated_lox_priv = IssuerPrivKey::new(6);
473 let updated_lox_pub = IssuerPubKey::new(&updated_lox_priv);
474 self.old_keys.lox_keys.push(OldKeyStore {
477 priv_key: self.lox_priv.clone(),
478 pub_key: self.lox_pub.clone(),
479 });
480 self.old_filters.lox_filter.push(self.id_filter.clone());
482 self.lox_priv = updated_lox_priv;
485 self.lox_pub = updated_lox_pub;
486 self.id_filter = Default::default();
487 }
488
489 pub fn rotate_invitation_keys(&mut self) {
490 let updated_invitation_priv = IssuerPrivKey::new(4);
491 let updated_invitation_pub = IssuerPubKey::new(&updated_invitation_priv);
492 self.old_keys.invitation_keys.push(OldKeyStore {
495 priv_key: self.invitation_priv.clone(),
496 pub_key: self.invitation_pub.clone(),
497 });
498 self.old_filters
500 .invitation_filter
501 .push(self.inv_id_filter.clone());
502 self.invitation_priv = updated_invitation_priv;
505 self.invitation_pub = updated_invitation_pub;
506 self.inv_id_filter = Default::default();
507 }
508
509 pub fn rotate_bridgedb_keys(&mut self, new_bridgedb_pub: VerifyingKey) {
510 self.old_keys.bridgedb_key.push(self.bridgedb_pub);
514 self.old_filters
516 .openinv_filter
517 .push(self.bridgedb_pub_filter.clone());
518 self.bridgedb_pub = new_bridgedb_pub;
521 self.bridgedb_pub_filter = Default::default();
522 }
523
524 pub fn is_empty(&self) -> bool {
525 self.bridge_table.buckets.is_empty()
526 }
527
528 pub fn reachable_length(&self) -> usize {
529 self.bridge_table.reachable.len()
530 }
531
532 pub fn unallocated_length(&self) -> usize {
533 self.bridge_table.unallocated_bridges.len()
534 }
535
536 pub fn spares_length(&self) -> usize {
537 self.bridge_table.spares.len()
538 }
539
540 pub fn openinv_length(&self, bdb: &mut BridgeDb) -> usize {
541 bdb.openinv_length()
542 }
543
544 #[cfg(feature = "blockage-detection")]
545 pub fn fingerprint_hasher(&self, unhashed_fingerprint: [u8; 20]) -> String {
546 let mut hasher = Sha1::new();
547 hasher.update(unhashed_fingerprint);
548 let fingerprint: [u8; 20] = hasher.finalize().into();
549 array_bytes::bytes2hex("", fingerprint)
550 }
551
552 #[cfg(feature = "blockage-detection")]
553 pub fn get_tp_bucket_and_fingerprint(&self, bridge: &BridgeLine, id: &u32) -> (String, Scalar) {
554 let key = self.bridge_table.keys.get(id).unwrap();
556 let bucket = bridge_table::to_scalar(*id, key);
557 let fingerprint_str = self.fingerprint_hasher(bridge.unhashed_fingerprint);
558 (fingerprint_str, bucket)
559 }
560
561 #[cfg(feature = "blockage-detection")]
562 pub fn generate_bridge_infos(&mut self) {
563 let buckets = &self.bridge_table.buckets;
567 for id in buckets.keys() {
568 let bridges = buckets.get(id).unwrap();
569 let key = self.bridge_table.keys.get(id).unwrap();
570 let bucket = bridge_table::to_scalar(*id, key);
571 for bridge in bridges {
572 if bridge.unhashed_fingerprint == [0; 20] {
573 continue;
574 }
575 let fingerprint_str = self.fingerprint_hasher(bridge.unhashed_fingerprint);
576
577 match self.tp_bridge_infos.get_mut(&fingerprint_str) {
579 Some(info) => {
580 info.buckets.insert(bucket);
581 }
582 None => {
583 let mut buckets = HashSet::<Scalar>::new();
584 buckets.insert(bucket);
585 self.tp_bridge_infos.insert(
586 fingerprint_str,
587 BridgeVerificationInfo {
588 bridge_line: *bridge,
589 buckets,
590 },
591 );
592 }
593 };
594 }
595 }
596 }
597
598 pub fn add_openinv_bridges(
605 &mut self,
606 bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
607 bdb: &mut BridgeDb,
608 ) -> Result<(), NoAvailableIDError> {
609 let bindex = self.find_next_available_key(bdb)?;
610 self.bridge_table.new_bucket(bindex, &bridges);
611 let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
612 for b in bridges.iter() {
613 let sindex = self.find_next_available_key(bdb)?;
614 single[0] = *b;
615 self.bridge_table.new_bucket(sindex, &single);
616 self.bridge_table.open_inv_keys.push((sindex, self.today()));
617 bdb.insert_openinv(sindex);
618 self.trustup_migration_table.table.insert(sindex, bindex);
619 }
620 Ok(())
621 }
622
623 pub fn add_spare_bucket(
625 &mut self,
626 bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
627 bdb: &mut BridgeDb,
628 ) -> Result<(), NoAvailableIDError> {
629 let index = self.find_next_available_key(bdb)?;
630 self.bridge_table.new_bucket(index, &bucket);
631 self.bridge_table.spares.insert(index);
632 Ok(())
633 }
634
635 pub fn find_and_remove_unaccounted_for_bridges(
639 &mut self,
640 accounted_for_bridges: Vec<u64>,
641 ) -> Vec<BridgeLine> {
642 let mut unaccounted_for: Vec<BridgeLine> = Vec::new();
643 for (k, _v) in self.bridge_table.reachable.clone() {
644 if !accounted_for_bridges.contains(&k.uid_fingerprint) {
645 unaccounted_for.push(k);
646 }
647 }
648 unaccounted_for
649 }
650
651 pub fn allocate_bridges(
653 &mut self,
654 distributor_bridges: &mut Vec<BridgeLine>,
655 bdb: &mut BridgeDb,
656 ) {
657 while let Some(bridge) = distributor_bridges.pop() {
658 self.bridge_table.unallocated_bridges.push(bridge);
659 }
660 while self.bridge_table.unallocated_bridges.len() >= MAX_BRIDGES_PER_BUCKET {
661 let mut bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
662 for bridge in bucket.iter_mut() {
663 *bridge = self.bridge_table.unallocated_bridges.pop().unwrap();
664 }
665 match self.add_openinv_bridges(bucket, bdb) {
666 Ok(_) => continue,
667 Err(e) => {
668 println!("Error: {:?}", e);
669 for bridge in bucket {
670 self.bridge_table.unallocated_bridges.push(bridge);
671 }
672 }
673 }
674 }
675 }
676
677 pub fn bridge_update(&mut self, bridge: &BridgeLine) -> bool {
683 let mut res: bool = false; let reachable_bridges = self.bridge_table.reachable.clone();
685 for reachable_bridge in reachable_bridges {
686 if reachable_bridge.0.uid_fingerprint == bridge.uid_fingerprint {
687 let positions = self.bridge_table.reachable.get(&reachable_bridge.0);
690 if let Some(v) = positions {
691 for (bucketnum, offset) in v.iter() {
692 let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) {
693 Some(bridgelines) => *bridgelines,
694 None => return res,
695 };
696 assert!(bridgelines[*offset] == reachable_bridge.0);
697 bridgelines[*offset] = *bridge;
698 self.bridge_table.buckets.insert(*bucketnum, bridgelines);
699 #[cfg(feature = "blockage-detection")]
700 let (fingerprint_str, bucket) =
701 self.get_tp_bucket_and_fingerprint(bridge, bucketnum);
702 #[cfg(feature = "blockage-detection")]
704 match self.tp_bridge_infos.get_mut(&fingerprint_str) {
705 Some(info) => {
706 info.buckets.insert(bucket);
707 }
708 None => {
709 let mut buckets = HashSet::<Scalar>::new();
710 buckets.insert(bucket);
711 self.tp_bridge_infos.insert(
712 fingerprint_str,
713 BridgeVerificationInfo {
714 bridge_line: *bridge,
715 buckets,
716 },
717 );
718 }
719 };
720 if !self.bridge_table.buckets.contains_key(bucketnum) {
721 return res;
722 }
723 }
724 res = true;
725 } else {
726 return res;
727 }
728 self.bridge_table.reachable.remove(&reachable_bridge.0);
731 self.bridge_table
732 .reachable
733 .insert(*bridge, reachable_bridge.1);
734 return res;
735 }
736 }
737 let unallocated_bridges = self.bridge_table.unallocated_bridges.clone();
739 for (i, unallocated_bridge) in unallocated_bridges.iter().enumerate() {
740 if unallocated_bridge.uid_fingerprint == bridge.uid_fingerprint {
741 self.bridge_table.unallocated_bridges.remove(i);
744 self.bridge_table.unallocated_bridges.push(*bridge);
745 res = true;
746 }
747 }
748 res
751 }
752
753 pub fn dissolve_spare_bucket(&mut self, key: u32) -> Result<(), BridgeTableError> {
755 self.bridge_table.spares.remove(&key);
756 let spare_bucket = self
758 .bridge_table
759 .buckets
760 .remove(&key)
761 .ok_or(BridgeTableError::MissingBucket(key))?;
762 for bridge in spare_bucket.iter() {
763 self.bridge_table.unallocated_bridges.push(*bridge);
764 self.bridge_table.reachable.remove(bridge);
766 }
767 self.bridge_table.keys.remove(&key);
768 self.bridge_table.recycleable_keys.push(key);
769 Ok(())
770 }
771
772 pub fn remove_unallocated(&mut self, bridge: &BridgeLine) -> Option<BridgeLine> {
774 #[cfg(feature = "blockage-detection")]
775 let fingerprint_str = self.fingerprint_hasher(bridge.unhashed_fingerprint);
776 match self
777 .bridge_table
778 .unallocated_bridges
779 .iter()
780 .position(|x| x == bridge)
781 {
782 Some(index) => Some({
783 #[cfg(feature = "blockage-detection")]
784 self.tp_bridge_infos.remove_entry(&fingerprint_str);
785 self.bridge_table.unallocated_bridges.swap_remove(index)
786 }),
787 None => None,
788 }
789 }
790
791 pub fn bridge_replace(
794 &mut self,
795 bridge: &BridgeLine,
796 available_bridge: Option<BridgeLine>,
797 ) -> ReplaceSuccess {
798 let reachable_bridges = &self.bridge_table.reachable.clone();
799 let Some(positions) = reachable_bridges.get(bridge) else {
800 match self.remove_unallocated(bridge) {
801 Some(_) => {
802 return ReplaceSuccess::Removed;
803 }
804 None => {
805 return ReplaceSuccess::NotFound;
806 }
807 }
808 };
809 if let Some(spare) = self
811 .bridge_table
812 .spares
813 .iter()
814 .find(|x| positions.iter().any(|(bucketnum, _)| &bucketnum == x))
815 .cloned()
816 {
817 let Ok(_) = self.dissolve_spare_bucket(spare) else {
818 return ReplaceSuccess::NotReplaced;
819 };
820 match self.remove_unallocated(bridge) {
823 Some(_) => {
824 return ReplaceSuccess::Removed;
825 }
826 None => {
827 return ReplaceSuccess::NotFound;
828 }
829 }
830 }
831 let Some(replacement) = available_bridge.or_else(|| {
836 self.bridge_table.unallocated_bridges.pop().or_else(|| {
837 let spare = self
838 .bridge_table
839 .spares
840 .iter()
841 .find(|x| !positions.iter().any(|(bucketnum, _)| &bucketnum == x))
843 .cloned()?;
844 let Ok(_) = self.dissolve_spare_bucket(spare) else {
845 return None;
846 };
847 self.bridge_table.unallocated_bridges.pop()
848 })
849 }) else {
850 println!("No available bridges");
856 return ReplaceSuccess::NotReplaced;
857 };
858 for (bucketnum, offset) in positions.iter() {
859 let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) {
860 Some(bridgelines) => *bridgelines,
861 None => return ReplaceSuccess::NotFound,
862 };
863 assert!(bridgelines[*offset] == *bridge);
864 bridgelines[*offset] = replacement;
865 self.bridge_table.buckets.insert(*bucketnum, bridgelines);
866 self.bridge_table
868 .reachable
869 .insert(replacement, positions.clone());
870 self.bridge_table.reachable.remove(bridge);
872 }
873 ReplaceSuccess::Replaced
874 }
875
876 pub fn get_bridge_verification_info(
877 &mut self,
878 bridge_str: &String,
879 ) -> Option<&BridgeVerificationInfo> {
880 self.tp_bridge_infos.get(bridge_str)
881 }
882
883 pub fn block_by_string(&mut self, bridge_str: &String) -> Option<BridgeLine> {
885 if let Some(bridge_verification_info) = self.tp_bridge_infos.remove(bridge_str) {
886 return Some(bridge_verification_info.bridge_line);
887 }
888 None
889 }
890
891 pub fn bridge_blocked(&mut self, bridge: &BridgeLine, bdb: &mut BridgeDb) -> bool {
906 let mut res: bool = true;
907 if self.remove_unallocated(bridge).is_some() {
908 return true;
909 }
910 if let Some(positions) = self.bridge_table.reachable.get(bridge) {
911 for (bucketnum, offset) in positions.iter() {
912 let mut bucket = match self.bridge_table.buckets.get(bucketnum) {
914 Some(bridgelines) => *bridgelines,
915 None => return false, };
917 assert!(bucket[*offset] == *bridge);
919 bucket[*offset] = BridgeLine::default();
920
921 if bdb.openinv_buckets.contains(bucketnum)
923 || bdb.distributed_buckets.contains(bucketnum)
924 {
925 bdb.remove_blocked_or_expired_buckets(bucketnum);
926 self.trustup_migration_table.table.remove(bucketnum);
927 continue;
928 }
929
930 let numreachable = bucket
932 .iter()
933 .filter(|br| self.bridge_table.reachable.contains_key(br))
934 .count();
935 if numreachable != MIN_BUCKET_REACHABILITY {
936 continue;
938 }
939
940 self.trustup_migration_table
942 .table
943 .retain(|_, &mut v| v != *bucketnum);
944
945 if self.bridge_table.spares.is_empty() {
947 res = false;
948 self.blockage_migration_table
949 .table
950 .retain(|_, &mut v| v != *bucketnum);
951 continue;
952 }
953 let spare = *self.bridge_table.spares.iter().next().unwrap();
956 self.bridge_table.spares.remove(&spare);
957 self.bridge_table
958 .blocked_keys
959 .push((*bucketnum, self.today()));
960 self.blockage_migration_table
962 .table
963 .insert(*bucketnum, spare);
964 for (_, v) in self.blockage_migration_table.table.iter_mut() {
967 if *v == *bucketnum {
968 *v = spare;
969 }
970 }
971 }
972 }
973 self.bridge_table.reachable.remove(bridge);
974
975 res
976 }
977
978 fn find_next_available_key(&mut self, bdb: &mut BridgeDb) -> Result<u32, NoAvailableIDError> {
983 self.clean_up_expired_buckets(bdb);
984 if self.bridge_table.recycleable_keys.is_empty() {
985 let mut test_index = 1;
986 let mut test_counter = self.bridge_table.counter.wrapping_add(test_index);
987 let mut i = 0;
988 while self.bridge_table.buckets.contains_key(&test_counter) && i < 5000 {
989 test_index += 1;
990 test_counter = self.bridge_table.counter.wrapping_add(test_index);
991 i += 1;
992 if i == 5000 {
993 return Err(NoAvailableIDError::ExhaustedIndexer);
994 }
995 }
996 self.bridge_table.counter = self.bridge_table.counter.wrapping_add(test_index);
997 Ok(self.bridge_table.counter)
998 } else {
999 Ok(self.bridge_table.recycleable_keys.pop().unwrap())
1000 }
1001 }
1002
1003 pub fn clean_up_expired_buckets(&mut self, bdb: &mut BridgeDb) {
1009 self.clean_up_blocked();
1011 self.clean_up_open_entry(bdb);
1013 }
1014
1015 fn clean_up_blocked(&mut self) {
1017 #[allow(clippy::type_complexity)]
1019 let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = self
1020 .bridge_table
1021 .blocked_keys
1022 .iter()
1023 .partition(|&x| x.1 + EXPIRY_DATE < self.today());
1024 for item in expired {
1025 let key = item.0;
1026 let bridgelines = self.bridge_table.buckets.get(&key).unwrap();
1031 for bridgeline in bridgelines {
1032 if bridgeline.port > 0 {
1034 self.bridge_table.unallocated_bridges.push(*bridgeline);
1036 self.bridge_table.reachable.remove(bridgeline);
1038 }
1039 }
1040 self.bridge_table.buckets.remove(&key);
1042 self.bridge_table.keys.remove(&key);
1043 self.bridge_table.recycleable_keys.push(key);
1045 self.blockage_migration_table.table.retain(|&k, _| k != key);
1049 }
1050 self.bridge_table.blocked_keys = fresh
1052 }
1053
1054 fn clean_up_open_entry(&mut self, bdb: &mut BridgeDb) {
1056 #[allow(clippy::type_complexity)]
1058 let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = self
1059 .bridge_table
1060 .open_inv_keys
1061 .iter()
1062 .partition(|&x| x.1 + EXPIRY_DATE < self.today());
1063 for item in expired {
1064 let key = item.0;
1065 if !bdb.distributed_buckets.contains(&key) {
1067 println!("This bucket was not actually distributed!");
1069 }
1070 bdb.remove_blocked_or_expired_buckets(&key);
1071 self.trustup_migration_table.table.retain(|&k, _| k != key);
1074 self.bridge_table.buckets.remove(&key);
1075 self.bridge_table.keys.remove(&key);
1076 self.bridge_table.recycleable_keys.push(key);
1078 }
1079 self.bridge_table.open_inv_keys = fresh
1081 }
1082
1083 #[cfg(test)]
1084 pub fn advance_day(&mut self) {
1086 self.time_offset += time::Duration::days(1);
1087 }
1088
1089 pub fn advance_days(&mut self, days: u16) {
1093 self.time_offset += time::Duration::days(days.into());
1094 }
1095
1096 pub fn today(&self) -> u32 {
1098 (time::OffsetDateTime::now_utc().date() + self.time_offset)
1101 .to_julian_day()
1102 .try_into()
1103 .unwrap()
1104 }
1105
1106 pub fn today_date(&self) -> DateTime<Utc> {
1108 Utc::now()
1109 }
1110
1111 pub fn enc_bridge_table(&mut self) -> &HashMap<u32, EncryptedBucket> {
1117 let today = self.today();
1118 if self.bridge_table.date_last_enc != today {
1119 self.bridge_table
1120 .encrypt_table(today, &self.reachability_priv);
1121 }
1122 &self.bridge_table.encbuckets
1123 }
1124
1125 #[cfg(test)]
1126 pub fn verify_lox(&self, cred: &cred::Lox) -> bool {
1128 if cred.P.is_identity() {
1129 return false;
1130 }
1131
1132 let Q = (self.lox_priv.x[0]
1133 + cred.id * self.lox_priv.x[1]
1134 + cred.bucket * self.lox_priv.x[2]
1135 + cred.trust_level * self.lox_priv.x[3]
1136 + cred.level_since * self.lox_priv.x[4]
1137 + cred.invites_remaining * self.lox_priv.x[5]
1138 + cred.blockages * self.lox_priv.x[6])
1139 * cred.P;
1140
1141 Q == cred.Q
1142 }
1143
1144 #[cfg(test)]
1145 pub fn verify_migration(&self, cred: &cred::Migration) -> bool {
1147 if cred.P.is_identity() {
1148 return false;
1149 }
1150
1151 let Q = (self.migration_priv.x[0]
1152 + cred.lox_id * self.migration_priv.x[1]
1153 + cred.from_bucket * self.migration_priv.x[2]
1154 + cred.to_bucket * self.migration_priv.x[3])
1155 * cred.P;
1156
1157 Q == cred.Q
1158 }
1159
1160 #[cfg(test)]
1161 pub fn verify_reachability(&self, cred: &cred::BucketReachability) -> bool {
1163 if cred.P.is_identity() {
1164 return false;
1165 }
1166
1167 let Q = (self.reachability_priv.x[0]
1168 + cred.date * self.reachability_priv.x[1]
1169 + cred.bucket * self.reachability_priv.x[2])
1170 * cred.P;
1171
1172 Q == cred.Q
1173 }
1174
1175 #[cfg(test)]
1176 pub fn verify_invitation(&self, cred: &cred::Invitation) -> bool {
1178 if cred.P.is_identity() {
1179 return false;
1180 }
1181
1182 let Q = (self.invitation_priv.x[0]
1183 + cred.inv_id * self.invitation_priv.x[1]
1184 + cred.date * self.invitation_priv.x[2]
1185 + cred.bucket * self.invitation_priv.x[3]
1186 + cred.blockages * self.invitation_priv.x[4])
1187 * cred.P;
1188
1189 Q == cred.Q
1190 }
1191}
1192
1193pub fn scalar_u64(s: &Scalar) -> Option<u64> {
1195 let sbytes = s.as_bytes();
1197 if sbytes[8..].ct_eq(&[0u8; 24]).unwrap_u8() == 0 {
1198 return None;
1199 }
1200 Some(u64::from_le_bytes(sbytes[..8].try_into().unwrap()))
1201}
1202
1203pub fn scalar_u32(s: &Scalar) -> Option<u32> {
1205 let sbytes = s.as_bytes();
1207 if sbytes[4..].ct_eq(&[0u8; 28]).unwrap_u8() == 0 {
1208 return None;
1209 }
1210 Some(u32::from_le_bytes(sbytes[..4].try_into().unwrap()))
1211}
1212
1213pub fn scalar_dbl(s: &Scalar) -> Scalar {
1215 s + s
1216}
1217
1218pub fn pt_dbl(P: &RistrettoPoint) -> RistrettoPoint {
1220 P + P
1221}
1222
1223pub mod proto {
1234 pub mod blockage_migration;
1235 pub mod check_blockage;
1236 pub mod errors;
1237 pub mod issue_invite;
1238 pub mod level_up;
1239 pub mod migration;
1240 pub mod open_invite;
1241 pub mod redeem_invite;
1242 pub mod trust_promotion;
1243 pub mod update_cred;
1244 pub mod update_invite;
1245}
1246
1247#[cfg(test)]
1249mod tests;