lib.rs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. /*! Implementation of a new style of bridge authority for Tor that
  2. allows users to invite other users, while protecting the social graph
  3. from the bridge authority itself.
  4. We use uCMZ credentials (Orr`u, 2024 https://eprint.iacr.org/2024/1552.pdf) which improves issuer efficiency
  5. over our original CMZ14 credential (GGM version, which is more efficient, but
  6. makes a stronger security assumption) implementation: "Algebraic MACs and
  7. Keyed-Verification Anonymous Credentials" (Chase, Meiklejohn, and
  8. Zaverucha, CCS 2014)
  9. The notation follows that of the paper "Hyphae: Social Secret Sharing"
  10. (Lovecruft and de Valence, 2017), Section 4. */
  11. // We want Scalars to be lowercase letters, and Points and credentials
  12. // to be capital letters
  13. #![allow(non_snake_case)]
  14. #[cfg(feature = "bridgeauth")]
  15. use ed25519_dalek::{Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey};
  16. use subtle::ConstantTimeEq;
  17. #[cfg(feature = "bridgeauth")]
  18. use chrono::{DateTime, Duration, Utc};
  19. #[cfg(feature = "bridgeauth")]
  20. use cmz::*;
  21. use curve25519_dalek::ristretto::RistrettoPoint as G;
  22. use group::Group;
  23. #[cfg(feature = "bridgeauth")]
  24. use rand::{rngs::OsRng, CryptoRng, Rng, RngCore};
  25. #[cfg(feature = "bridgeauth")]
  26. use std::collections::HashMap;
  27. type Scalar = <G as Group>::Scalar;
  28. #[cfg(feature = "bridgeauth")]
  29. use sha2::Sha512;
  30. pub mod bridge_table;
  31. pub mod dup_filter;
  32. pub mod lox_creds;
  33. pub mod migration_table;
  34. pub mod mock_auth;
  35. pub mod proto {
  36. pub mod blockage_migration;
  37. pub mod check_blockage;
  38. pub mod errors;
  39. pub mod issue_invite;
  40. pub mod level_up;
  41. pub mod migration;
  42. pub mod open_invite;
  43. pub mod redeem_invite;
  44. pub mod trust_promotion;
  45. pub mod update_cred;
  46. pub mod update_invite;
  47. }
  48. #[cfg(feature = "bridgeauth")]
  49. use bridge_table::{
  50. BridgeLine, BridgeTable, EncryptedBucket, MAX_BRIDGES_PER_BUCKET, MIN_BUCKET_REACHABILITY,
  51. };
  52. #[cfg(feature = "bridgeauth")]
  53. use lox_creds::*;
  54. #[cfg(feature = "bridgeauth")]
  55. use migration_table::{MigrationTable, MigrationType};
  56. #[cfg(feature = "bridgeauth")]
  57. use serde::{Deserialize, Serialize};
  58. #[cfg(feature = "bridgeauth")]
  59. use std::collections::HashSet;
  60. #[cfg(any(feature = "bridgeauth", test))]
  61. use thiserror::Error;
  62. // EXPIRY_DATE is set to EXPIRY_DATE days for open-entry and blocked buckets in order to match
  63. // the expiry date for Lox credentials.This particular value (EXPIRY_DATE) is chosen because
  64. // values that are 2^k − 1 make range proofs more efficient, but this can be changed to any value
  65. pub const EXPIRY_DATE: u32 = 511;
  66. /// ReplaceSuccess sends a signal to the lox-distributor to inform
  67. /// whether or not a bridge was successfully replaced
  68. #[derive(PartialEq, Eq)]
  69. #[cfg(feature = "bridgeauth")]
  70. pub enum ReplaceSuccess {
  71. NotFound = 0,
  72. NotReplaced = 1,
  73. Replaced = 2,
  74. Removed = 3,
  75. }
  76. /// This error is thrown if the number of buckets/keys in the bridge table
  77. /// exceeds u32 MAX.It is unlikely this error will ever occur.
  78. #[derive(Error, Debug)]
  79. #[cfg(feature = "bridgeauth")]
  80. pub enum NoAvailableIDError {
  81. #[error("Find key exhausted with no available index found!")]
  82. ExhaustedIndexer,
  83. }
  84. /// This error is thrown after the MAX_DAILY_BRIDGES threshold for bridges
  85. /// distributed in a day has been reached
  86. #[derive(Error, Debug)]
  87. #[cfg(any(feature = "bridgeauth", test))]
  88. pub enum OpenInvitationError {
  89. #[error("The maximum number of bridges has already been distributed today, please try again tomorrow!")]
  90. ExceededMaxBridges,
  91. #[error("There are no bridges available for open invitations.")]
  92. NoBridgesAvailable,
  93. }
  94. #[derive(Error, Debug)]
  95. #[cfg(feature = "bridgeauth")]
  96. pub enum BridgeTableError {
  97. #[error("The bucket corresponding to key {0} was not in the bridge table")]
  98. MissingBucket(u32),
  99. }
  100. /// Number of times a given invitation is ditributed
  101. pub const OPENINV_K: u32 = 10;
  102. /// TODO: Decide on maximum daily number of invitations to be distributed
  103. pub const MAX_DAILY_BRIDGES: u32 = 100;
  104. /// The BridgeDb. This will typically be a singleton object. The
  105. /// BridgeDb's role is simply to issue signed "open invitations" to
  106. /// people who are not yet part of the system.
  107. #[derive(Debug, Serialize, Deserialize)]
  108. #[cfg(feature = "bridgeauth")]
  109. pub struct BridgeDb {
  110. /// The keypair for signing open invitations
  111. keypair: SigningKey,
  112. /// The public key for verifying open invitations
  113. pub pubkey: VerifyingKey,
  114. /// The set of open-invitation buckets
  115. openinv_buckets: HashSet<u32>,
  116. /// The set of open invitation buckets that have been distributed
  117. distributed_buckets: Vec<u32>,
  118. #[serde(skip)]
  119. today: DateTime<Utc>,
  120. pub current_k: u32,
  121. pub daily_bridges_distributed: u32,
  122. }
  123. #[derive(Debug, Clone, Serialize, Deserialize)]
  124. #[cfg(feature = "bridgeauth")]
  125. pub struct OldKeyStore {
  126. // /// Most recently outdated lox secret and private keys for verifying update_cred credentials
  127. priv_key: CMZPrivkey<G>,
  128. // /// The public key for verifying update_cred credentials
  129. pub pub_key: CMZPubkey<G>,
  130. }
  131. #[derive(Debug, Default, Clone, Serialize, Deserialize)]
  132. #[cfg(feature = "bridgeauth")]
  133. pub struct OldKeys {
  134. /// Most recently outdated lox secret and private keys for verifying update_cred credentials
  135. lox_keys: Vec<OldKeyStore>,
  136. /// Most recently outdated open_invitation VerifyingKey for verifying update_openinv tokens
  137. bridgedb_key: Vec<VerifyingKey>,
  138. /// Most recently outdated invitation secret and private keys for verifying update_inv credentials
  139. invitation_keys: Vec<OldKeyStore>,
  140. }
  141. #[derive(Debug, Default, Clone, Serialize, Deserialize)]
  142. #[cfg(feature = "bridgeauth")]
  143. pub struct OldFilters {
  144. /// Most recently outdated lox id filter
  145. lox_filter: Vec<dup_filter::DupFilter<Scalar>>,
  146. /// Most recently outdated open invitation filter
  147. openinv_filter: Vec<dup_filter::DupFilter<Scalar>>,
  148. /// Most recently outdated invitation filter
  149. invitation_filter: Vec<dup_filter::DupFilter<Scalar>>,
  150. }
  151. /// An open invitation is a [u8; OPENINV_LENGTH] where the first 32
  152. /// bytes are the serialization of a random Scalar (the invitation id),
  153. /// the next 4 bytes are a little-endian bucket number, and the last
  154. /// SIGNATURE_LENGTH bytes are the signature on the first 36 bytes.
  155. pub const OPENINV_LENGTH: usize = 32 // the length of the random
  156. // invitation id (a Scalar)
  157. + 4 // the length of the u32 for the bucket number
  158. + ed25519_dalek::SIGNATURE_LENGTH; // the length of the signature
  159. #[cfg(feature = "bridgeauth")]
  160. impl Default for BridgeDb {
  161. fn default() -> Self {
  162. Self::new()
  163. }
  164. }
  165. #[cfg(feature = "bridgeauth")]
  166. impl BridgeDb {
  167. /// Create the BridgeDb.
  168. pub fn new() -> Self {
  169. let mut csprng = OsRng {};
  170. let keypair = SigningKey::generate(&mut csprng);
  171. let pubkey = keypair.verifying_key();
  172. Self {
  173. keypair,
  174. pubkey,
  175. openinv_buckets: Default::default(),
  176. distributed_buckets: Default::default(),
  177. today: Utc::now(),
  178. current_k: 0,
  179. daily_bridges_distributed: 0,
  180. }
  181. }
  182. pub fn openinv_length(&mut self) -> usize {
  183. self.openinv_buckets.len()
  184. }
  185. /// Rotate Open Invitation keys
  186. pub fn rotate_open_inv_keys(&mut self) -> VerifyingKey {
  187. let mut csprng = OsRng {};
  188. self.keypair = SigningKey::generate(&mut csprng);
  189. self.pubkey = self.keypair.verifying_key();
  190. self.pubkey
  191. }
  192. /// Insert an open-invitation bucket into the set
  193. pub fn insert_openinv(&mut self, bucket: u32) {
  194. self.openinv_buckets.insert(bucket);
  195. }
  196. /// Remove an open-invitation bucket from the set
  197. pub fn remove_openinv(&mut self, bucket: &u32) {
  198. self.openinv_buckets.remove(bucket);
  199. }
  200. /// Remove open invitation and/or otherwise distributed buckets that have
  201. /// become blocked or are expired to free up the index for a new bucket
  202. pub fn remove_blocked_or_expired_buckets(&mut self, bucket: &u32) {
  203. if self.openinv_buckets.contains(bucket) {
  204. println!("Removing a bucket that has not been distributed yet!");
  205. self.openinv_buckets.remove(bucket);
  206. } else if self.distributed_buckets.contains(bucket) {
  207. self.distributed_buckets.retain(|&x| x != *bucket);
  208. }
  209. }
  210. /// Mark a bucket as distributed
  211. pub fn mark_distributed(&mut self, bucket: u32) {
  212. self.distributed_buckets.push(bucket);
  213. }
  214. /// Produce an open invitation such that the next k users, where k is <
  215. /// OPENINV_K, will receive the same open invitation bucket
  216. /// chosen randomly from the set of open-invitation buckets.
  217. pub fn invite(&mut self) -> Result<[u8; OPENINV_LENGTH], OpenInvitationError> {
  218. let mut res: [u8; OPENINV_LENGTH] = [0; OPENINV_LENGTH];
  219. let mut rng = rand::rngs::OsRng;
  220. // Choose a random invitation id (a Scalar) and serialize it
  221. let id = Scalar::random(&mut rng);
  222. res[0..32].copy_from_slice(&id.to_bytes());
  223. let bucket_num: u32;
  224. if Utc::now() >= (self.today + Duration::days(1)) {
  225. self.today = Utc::now();
  226. self.daily_bridges_distributed = 0;
  227. }
  228. if self.daily_bridges_distributed < MAX_DAILY_BRIDGES {
  229. if self.current_k < OPENINV_K && !self.distributed_buckets.is_empty() {
  230. bucket_num = *self.distributed_buckets.last().unwrap();
  231. self.current_k += 1;
  232. } else {
  233. if self.openinv_buckets.is_empty() {
  234. return Err(OpenInvitationError::NoBridgesAvailable);
  235. }
  236. // Choose a random bucket number (from the set of open
  237. // invitation buckets) and serialize it
  238. let openinv_vec: Vec<&u32> = self.openinv_buckets.iter().collect();
  239. bucket_num = *openinv_vec[rng.gen_range(0..openinv_vec.len())];
  240. self.mark_distributed(bucket_num);
  241. self.remove_openinv(&bucket_num);
  242. self.current_k = 1;
  243. self.daily_bridges_distributed += 1;
  244. }
  245. res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
  246. // Sign the first 36 bytes and serialize it
  247. let sig = self.keypair.sign(&res[0..(32 + 4)]);
  248. res[(32 + 4)..].copy_from_slice(&sig.to_bytes());
  249. Ok(res)
  250. } else {
  251. Err(OpenInvitationError::ExceededMaxBridges)
  252. }
  253. }
  254. /// Verify an open invitation. Returns the invitation id and the
  255. /// bucket number if the signature checked out. It is up to the
  256. /// caller to then check that the invitation id has not been used
  257. /// before.
  258. pub fn verify(
  259. invitation: [u8; OPENINV_LENGTH],
  260. pubkey: VerifyingKey,
  261. ) -> Result<(Scalar, u32), SignatureError> {
  262. // Pull out the signature and verify it
  263. let sig = Signature::try_from(&invitation[(32 + 4)..])?;
  264. pubkey.verify(&invitation[0..(32 + 4)], &sig)?;
  265. // The signature passed. Pull out the bucket number and then
  266. // the invitation id
  267. let bucket = u32::from_le_bytes(invitation[32..(32 + 4)].try_into().unwrap());
  268. let s = Scalar::from_canonical_bytes(invitation[0..32].try_into().unwrap());
  269. if s.is_some().into() {
  270. Ok((s.unwrap(), bucket))
  271. } else {
  272. // It should never happen that there's a valid signature on
  273. // an invalid serialization of a Scalar, but check anyway.
  274. Err(SignatureError::new())
  275. }
  276. }
  277. }
  278. /// The bridge authority. This will typically be a singleton object.
  279. #[cfg(feature = "bridgeauth")]
  280. #[derive(Default, Debug, Serialize, Deserialize)]
  281. pub struct BridgeAuth {
  282. /// The private key for the main Lox credential
  283. lox_priv: CMZPrivkey<G>,
  284. /// The public key for the main Lox credential
  285. pub lox_pub: CMZPubkey<G>,
  286. /// The private key for migration credentials
  287. migration_priv: CMZPrivkey<G>,
  288. /// The public key for migration credentials
  289. pub migration_pub: CMZPubkey<G>,
  290. /// The private key for migration key credentials
  291. migrationkey_priv: CMZPrivkey<G>,
  292. /// The public key for migration key credentials
  293. pub migrationkey_pub: CMZPubkey<G>,
  294. /// The private key for bucket reachability credentials
  295. reachability_priv: CMZPrivkey<G>,
  296. /// The public key for bucket reachability credentials
  297. pub reachability_pub: CMZPubkey<G>,
  298. /// The private key for invitation credentials
  299. invitation_priv: CMZPrivkey<G>,
  300. /// The public key for invitation credentials
  301. pub invitation_pub: CMZPubkey<G>,
  302. /// The public key of the BridgeDb issuing open invitations
  303. pub bridgedb_pub: VerifyingKey,
  304. /// The bridge table
  305. bridge_table: BridgeTable,
  306. // Map of bridge fingerprint to values needed to verify TP reports
  307. //pub tp_bridge_infos: HashMap<String, BridgeVerificationInfo>,
  308. /// The migration tables
  309. trustup_migration_table: MigrationTable,
  310. blockage_migration_table: MigrationTable,
  311. /// Duplicate filter for open invitations
  312. bridgedb_pub_filter: dup_filter::DupFilter<Scalar>,
  313. /// Duplicate filter for Lox credential ids
  314. id_filter: dup_filter::DupFilter<Scalar>,
  315. /// Duplicate filter for Invitation credential ids
  316. inv_id_filter: dup_filter::DupFilter<Scalar>,
  317. /// Duplicate filter for trust promotions (from untrusted level 0 to
  318. /// trusted level 1)
  319. trust_promotion_filter: dup_filter::DupFilter<Scalar>,
  320. // Outdated Lox Keys to be populated with the old Lox private and public keys
  321. // after a key rotation
  322. old_keys: OldKeys,
  323. old_filters: OldFilters,
  324. /// For testing only: offset of the true time to the simulated time
  325. #[serde(skip)]
  326. time_offset: time::Duration,
  327. }
  328. #[cfg(feature = "bridgeauth")]
  329. impl BridgeAuth {
  330. pub fn new(bridgedb_pub: VerifyingKey, rng: &mut (impl CryptoRng + RngCore)) -> Self {
  331. // Initialization
  332. cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
  333. // Create the private and public keys for each of the types of
  334. // credential with 'true' to indicate uCMZ
  335. let (lox_priv, lox_pub) = Lox::gen_keys(rng, true);
  336. let (migration_priv, migration_pub) = Migration::gen_keys(rng, true);
  337. let (migrationkey_priv, migrationkey_pub) = MigrationKey::gen_keys(rng, true);
  338. let (reachability_priv, reachability_pub) = BucketReachability::gen_keys(rng, true);
  339. let (invitation_priv, invitation_pub) = Invitation::gen_keys(rng, true);
  340. Self {
  341. lox_priv,
  342. lox_pub,
  343. migration_priv,
  344. migration_pub,
  345. migrationkey_priv,
  346. migrationkey_pub,
  347. reachability_priv,
  348. reachability_pub,
  349. invitation_priv,
  350. invitation_pub,
  351. bridgedb_pub,
  352. bridge_table: Default::default(),
  353. // tp_bridge_infos: HashMap::<String, BridgeVerificationInfo>::new(),
  354. trustup_migration_table: MigrationTable::new(MigrationType::TrustUpgrade),
  355. blockage_migration_table: MigrationTable::new(MigrationType::Blockage),
  356. bridgedb_pub_filter: Default::default(),
  357. id_filter: Default::default(),
  358. inv_id_filter: Default::default(),
  359. trust_promotion_filter: Default::default(),
  360. time_offset: time::Duration::ZERO,
  361. old_keys: Default::default(),
  362. old_filters: Default::default(),
  363. }
  364. }
  365. pub fn rotate_lox_keys(&mut self, rng: &mut (impl CryptoRng + RngCore)) {
  366. let (updated_lox_priv, updated_lox_pub) = Lox::gen_keys(rng, true);
  367. // Store the old keys until the next key rotation (this should happen no more than 511 days after the
  368. // last rotation to ensure that all credentials issued with the old key can be updated
  369. self.old_keys.lox_keys.push(OldKeyStore {
  370. priv_key: self.lox_priv.clone(),
  371. pub_key: self.lox_pub.clone(),
  372. });
  373. // Move the old lox id filter to the old_lox_id_filter
  374. self.old_filters.lox_filter.push(self.id_filter.clone());
  375. // TODO: Commit to the new keys and post the commitment somewhere public that can be verified
  376. // by users, ideally
  377. self.lox_priv = updated_lox_priv;
  378. self.lox_pub = updated_lox_pub;
  379. self.id_filter = Default::default();
  380. }
  381. pub fn rotate_invitation_keys(&mut self, rng: &mut (impl CryptoRng + RngCore)) {
  382. let (updated_invitation_priv, updated_invitation_pub) = Invitation::gen_keys(rng, true);
  383. // Store the old keys until the next key rotation (this should happen no more than 511 days after the
  384. // last rotation to ensure that all credentials issued with the old key can be updated
  385. self.old_keys.invitation_keys.push(OldKeyStore {
  386. priv_key: self.invitation_priv.clone(),
  387. pub_key: self.invitation_pub.clone(),
  388. });
  389. // Move the old invitation id filter to the old_invitation_id_filter
  390. self.old_filters
  391. .invitation_filter
  392. .push(self.inv_id_filter.clone());
  393. // TODO: Commit to the new keys and post the commitment somewhere public that can be verified
  394. // by users, ideally
  395. self.invitation_priv = updated_invitation_priv;
  396. self.invitation_pub = updated_invitation_pub;
  397. self.inv_id_filter = Default::default();
  398. }
  399. pub fn rotate_bridgedb_keys(&mut self, new_bridgedb_pub: VerifyingKey) {
  400. // Store the old verifying key until the next key rotation (this should happen no more often than the
  401. // we would reasonably expect a user to redeem an open invitation token to ensure that all invitations
  402. // issued with the old key can be updated)
  403. self.old_keys.bridgedb_key.push(self.bridgedb_pub);
  404. // Move the old lox id filter to the old_lox_id_filter
  405. self.old_filters
  406. .openinv_filter
  407. .push(self.bridgedb_pub_filter.clone());
  408. // TODO: Commit to the new keys and post the commitment somewhere public that can be verified
  409. // by users, ideally
  410. self.bridgedb_pub = new_bridgedb_pub;
  411. self.bridgedb_pub_filter = Default::default();
  412. }
  413. /// Insert a set of open invitation bridges.
  414. ///
  415. /// Each of the bridges will be given its own open invitation
  416. /// bucket, and the BridgeDb will be informed. A single bucket
  417. /// containing all of the bridges will also be created, with a trust
  418. /// upgrade migration from each of the single-bridge buckets.
  419. pub fn add_openinv_bridges(
  420. &mut self,
  421. bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
  422. bdb: &mut BridgeDb,
  423. ) -> Result<(), NoAvailableIDError> {
  424. let bindex = self.find_next_available_key(bdb)?;
  425. self.bridge_table.new_bucket(bindex, &bridges);
  426. let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
  427. for b in bridges.iter() {
  428. let sindex = self.find_next_available_key(bdb)?;
  429. single[0] = *b;
  430. self.bridge_table.new_bucket(sindex, &single);
  431. self.bridge_table.open_inv_keys.push((sindex, self.today()));
  432. bdb.insert_openinv(sindex);
  433. self.trustup_migration_table.table.insert(sindex, bindex);
  434. }
  435. Ok(())
  436. }
  437. pub fn is_empty(&self) -> bool {
  438. self.bridge_table.buckets.is_empty()
  439. }
  440. pub fn reachable_length(&self) -> usize {
  441. self.bridge_table.reachable.len()
  442. }
  443. pub fn unallocated_length(&self) -> usize {
  444. self.bridge_table.unallocated_bridges.len()
  445. }
  446. pub fn spares_length(&self) -> usize {
  447. self.bridge_table.spares.len()
  448. }
  449. pub fn openinv_length(&self, bdb: &mut BridgeDb) -> usize {
  450. bdb.openinv_length()
  451. }
  452. /// Insert a hot spare bucket of bridges
  453. pub fn add_spare_bucket(
  454. &mut self,
  455. bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
  456. bdb: &mut BridgeDb,
  457. ) -> Result<(), NoAvailableIDError> {
  458. let index = self.find_next_available_key(bdb)?;
  459. self.bridge_table.new_bucket(index, &bucket);
  460. self.bridge_table.spares.insert(index);
  461. Ok(())
  462. }
  463. /// When syncing the Lox bridge table with rdsys, this function returns any bridges
  464. /// that are found in the Lox bridge table that are not found in the Vector
  465. /// of bridges received from rdsys through the Lox distributor.
  466. pub fn find_and_remove_unaccounted_for_bridges(
  467. &mut self,
  468. accounted_for_bridges: Vec<u64>,
  469. ) -> Vec<BridgeLine> {
  470. let mut unaccounted_for: Vec<BridgeLine> = Vec::new();
  471. for (k, _v) in self.bridge_table.reachable.clone() {
  472. if !accounted_for_bridges.contains(&k.uid_fingerprint) {
  473. unaccounted_for.push(k);
  474. }
  475. }
  476. unaccounted_for
  477. }
  478. /// Allocate single left over bridges to an open invitation bucket
  479. pub fn allocate_bridges(
  480. &mut self,
  481. distributor_bridges: &mut Vec<BridgeLine>,
  482. bdb: &mut BridgeDb,
  483. ) {
  484. while let Some(bridge) = distributor_bridges.pop() {
  485. self.bridge_table.unallocated_bridges.push(bridge);
  486. }
  487. while self.bridge_table.unallocated_bridges.len() >= MAX_BRIDGES_PER_BUCKET {
  488. let mut bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
  489. for bridge in bucket.iter_mut() {
  490. *bridge = self.bridge_table.unallocated_bridges.pop().unwrap();
  491. }
  492. match self.add_openinv_bridges(bucket, bdb) {
  493. Ok(_) => continue,
  494. Err(e) => {
  495. println!("Error: {:?}", e);
  496. for bridge in bucket {
  497. self.bridge_table.unallocated_bridges.push(bridge);
  498. }
  499. }
  500. }
  501. }
  502. }
  503. // Update the details of a bridge in the bridge table. This assumes that the IP and Port
  504. // of a given bridge remains the same and thus can be updated.
  505. // First we must retrieve the list of reachable bridges, then we must search for any matching our partial key
  506. // which will include the IP and Port. Finally we can replace the original bridge with the updated bridge.
  507. // Returns true if the bridge has successfully updated
  508. pub fn bridge_update(&mut self, bridge: &BridgeLine) -> bool {
  509. let mut res: bool = false; //default False to assume that update failed
  510. let reachable_bridges = self.bridge_table.reachable.clone();
  511. for reachable_bridge in reachable_bridges {
  512. if reachable_bridge.0.uid_fingerprint == bridge.uid_fingerprint {
  513. // Now we must remove the old bridge from the table and insert the new bridge in its place
  514. // i.e., in the same bucket and with the same permissions.
  515. let positions = self.bridge_table.reachable.get(&reachable_bridge.0);
  516. if let Some(v) = positions {
  517. for (bucketnum, offset) in v.iter() {
  518. let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) {
  519. Some(bridgelines) => *bridgelines,
  520. None => return res,
  521. };
  522. assert!(bridgelines[*offset] == reachable_bridge.0);
  523. bridgelines[*offset] = *bridge;
  524. self.bridge_table.buckets.insert(*bucketnum, bridgelines);
  525. /* #[cfg(feature = "blockage-detection")]
  526. let (fingerprint_str, bucket) =
  527. self.get_tp_bucket_and_fingerprint(bridge, bucketnum);
  528. // Add bucket to existing entry or add new entry
  529. #[cfg(feature = "blockage-detection")]
  530. match self.tp_bridge_infos.get_mut(&fingerprint_str) {
  531. Some(info) => {
  532. info.buckets.insert(bucket);
  533. }
  534. None => {
  535. let mut buckets = HashSet::<Scalar>::new();
  536. buckets.insert(bucket);
  537. self.tp_bridge_infos.insert(
  538. fingerprint_str,
  539. BridgeVerificationInfo {
  540. bridge_line: *bridge,
  541. buckets,
  542. },
  543. );
  544. }
  545. }; */
  546. if !self.bridge_table.buckets.contains_key(bucketnum) {
  547. return res;
  548. }
  549. }
  550. res = true;
  551. } else {
  552. return res;
  553. }
  554. // We must also remove the old bridge from the reachable bridges table
  555. // and add the new bridge
  556. self.bridge_table.reachable.remove(&reachable_bridge.0);
  557. self.bridge_table
  558. .reachable
  559. .insert(*bridge, reachable_bridge.1);
  560. return res;
  561. }
  562. }
  563. // Also check the unallocated bridges just in case there is a bridge that should be updated there
  564. let unallocated_bridges = self.bridge_table.unallocated_bridges.clone();
  565. for (i, unallocated_bridge) in unallocated_bridges.iter().enumerate() {
  566. if unallocated_bridge.uid_fingerprint == bridge.uid_fingerprint {
  567. // Now we must remove the old bridge from the unallocated bridges and insert the new bridge
  568. // in its place
  569. self.bridge_table.unallocated_bridges.remove(i);
  570. self.bridge_table.unallocated_bridges.push(*bridge);
  571. res = true;
  572. }
  573. }
  574. // If this is returned, we assume that the bridge wasn't found in the bridge table
  575. // and therefore should be treated as a "new bridge"
  576. res
  577. }
  578. // Repurpose a bucket of spares into unallocated bridges
  579. pub fn dissolve_spare_bucket(&mut self, key: u32) -> Result<(), BridgeTableError> {
  580. self.bridge_table.spares.remove(&key);
  581. // Get the actual bridges from the spare bucket
  582. let spare_bucket = self
  583. .bridge_table
  584. .buckets
  585. .remove(&key)
  586. .ok_or(BridgeTableError::MissingBucket(key))?;
  587. for bridge in spare_bucket.iter() {
  588. self.bridge_table.unallocated_bridges.push(*bridge);
  589. // Mark bucket as unreachable while it is unallocated
  590. self.bridge_table.reachable.remove(bridge);
  591. }
  592. self.bridge_table.keys.remove(&key);
  593. self.bridge_table.recycleable_keys.push(key);
  594. Ok(())
  595. }
  596. // Removes an unallocated bridge and returns it if it was present
  597. pub fn remove_unallocated(&mut self, bridge: &BridgeLine) -> Option<BridgeLine> {
  598. // #[cfg(feature = "blockage-detection")]
  599. // let fingerprint_str = self.fingerprint_hasher(bridge.unhashed_fingerprint);
  600. match self
  601. .bridge_table
  602. .unallocated_bridges
  603. .iter()
  604. .position(|x| x == bridge)
  605. {
  606. Some(index) => Some({
  607. // #[cfg(feature = "blockage-detection")]
  608. // self.tp_bridge_infos.remove_entry(&fingerprint_str);
  609. self.bridge_table.unallocated_bridges.swap_remove(index)
  610. }),
  611. None => None,
  612. }
  613. }
  614. /// Attempt to remove a bridge that is failing tests and replace it with a bridge from
  615. /// available_bridge or from a spare bucket
  616. pub fn bridge_replace(
  617. &mut self,
  618. bridge: &BridgeLine,
  619. available_bridge: Option<BridgeLine>,
  620. ) -> ReplaceSuccess {
  621. let reachable_bridges = &self.bridge_table.reachable.clone();
  622. let Some(positions) = reachable_bridges.get(bridge) else {
  623. match self.remove_unallocated(bridge) {
  624. Some(_) => {
  625. return ReplaceSuccess::Removed;
  626. }
  627. None => {
  628. return ReplaceSuccess::NotFound;
  629. }
  630. }
  631. };
  632. // Check if the bridge is in a spare bucket first, if it is, dissolve the bucket
  633. if let Some(spare) = self
  634. .bridge_table
  635. .spares
  636. .iter()
  637. .find(|x| positions.iter().any(|(bucketnum, _)| &bucketnum == x))
  638. .cloned()
  639. {
  640. let Ok(_) = self.dissolve_spare_bucket(spare) else {
  641. return ReplaceSuccess::NotReplaced;
  642. };
  643. // Next Check if the bridge is in the unallocated bridges and remove the bridge if so
  644. // Bridges in spare buckets should have been moved to the unallocated bridges
  645. match self.remove_unallocated(bridge) {
  646. Some(_) => {
  647. return ReplaceSuccess::Removed;
  648. }
  649. None => {
  650. return ReplaceSuccess::NotFound;
  651. }
  652. }
  653. }
  654. // select replacement:
  655. // - first try the given bridge
  656. // - second try to pick one from the set of available bridges
  657. // - third dissolve a spare bucket to create more available bridges
  658. let Some(replacement) = available_bridge.or_else(|| {
  659. self.bridge_table.unallocated_bridges.pop().or_else(|| {
  660. let spare = self
  661. .bridge_table
  662. .spares
  663. .iter()
  664. // in case bridge is a spare, avoid replacing it with itself
  665. .find(|x| !positions.iter().any(|(bucketnum, _)| &bucketnum == x))
  666. .cloned()?;
  667. let Ok(_) = self.dissolve_spare_bucket(spare) else {
  668. return None;
  669. };
  670. self.bridge_table.unallocated_bridges.pop()
  671. })
  672. }) else {
  673. // If there are no available bridges that can be assigned here, the only thing
  674. // that can be done is return an indication that updating the gone bridge
  675. // didn't work.
  676. // In this case, we do not mark the bridge as unreachable or remove it from the
  677. // reachable bridges so that we can still find it when a new bridge does become available
  678. println!("No available bridges");
  679. return ReplaceSuccess::NotReplaced;
  680. };
  681. for (bucketnum, offset) in positions.iter() {
  682. let mut bridgelines = match self.bridge_table.buckets.get(bucketnum) {
  683. Some(bridgelines) => *bridgelines,
  684. None => return ReplaceSuccess::NotFound,
  685. };
  686. assert!(bridgelines[*offset] == *bridge);
  687. bridgelines[*offset] = replacement;
  688. self.bridge_table.buckets.insert(*bucketnum, bridgelines);
  689. // Remove the bridge from the reachable bridges and add new bridge
  690. self.bridge_table
  691. .reachable
  692. .insert(replacement, positions.clone());
  693. // Remove the bridge from the bucket
  694. self.bridge_table.reachable.remove(bridge);
  695. }
  696. ReplaceSuccess::Replaced
  697. }
  698. /* pub fn get_bridge_verification_info(
  699. &mut self,
  700. bridge_str: &String,
  701. ) -> Option<&BridgeVerificationInfo> {
  702. self.tp_bridge_infos.get(bridge_str)
  703. }
  704. // Remove Bridge Info for blocked bridge and return the bridgeline with the given fingerprint
  705. pub fn block_by_string(&mut self, bridge_str: &String) -> Option<BridgeLine> {
  706. if let Some(bridge_verification_info) = self.tp_bridge_infos.remove(bridge_str) {
  707. return Some(bridge_verification_info.bridge_line);
  708. }
  709. None
  710. }
  711. */
  712. /// Mark a bridge as blocked
  713. ///
  714. /// This bridge will be removed from each of the buckets that
  715. /// contains it. If any of those are open-invitation buckets, the
  716. /// trust upgrade migration for that bucket will be removed and the
  717. /// BridgeDb will be informed to stop handing out that bridge. If
  718. /// any of those are trusted buckets where the number of reachable
  719. /// bridges has fallen below the threshold, a blockage migration
  720. /// from that bucket to a spare bucket will be added, and the spare
  721. /// bucket will be removed from the list of hot spares. In
  722. /// addition, if the blocked bucket was the _target_ of a blockage
  723. /// migration, change the target to the new (formerly spare) bucket.
  724. /// Returns true if sucessful, or false if it needed a hot spare but
  725. /// there was none available.
  726. pub fn bridge_blocked(&mut self, bridge: &BridgeLine, bdb: &mut BridgeDb) -> bool {
  727. let mut res: bool = true;
  728. if self.remove_unallocated(bridge).is_some() {
  729. return true;
  730. }
  731. if let Some(positions) = self.bridge_table.reachable.get(bridge) {
  732. for (bucketnum, offset) in positions.iter() {
  733. // Count how many bridges in this bucket are reachable
  734. let mut bucket = match self.bridge_table.buckets.get(bucketnum) {
  735. Some(bridgelines) => *bridgelines,
  736. None => return false, // This should not happen
  737. };
  738. // Remove the bridge from the bucket
  739. assert!(bucket[*offset] == *bridge);
  740. bucket[*offset] = BridgeLine::default();
  741. // If this is an open invitation bucket, there is only one bridge, remove bucket
  742. if bdb.openinv_buckets.contains(bucketnum)
  743. || bdb.distributed_buckets.contains(bucketnum)
  744. {
  745. bdb.remove_blocked_or_expired_buckets(bucketnum);
  746. self.trustup_migration_table.table.remove(bucketnum);
  747. continue;
  748. }
  749. // If this bucket still has an acceptable number of bridges, continue
  750. let numreachable = bucket
  751. .iter()
  752. .filter(|br| self.bridge_table.reachable.contains_key(br))
  753. .count();
  754. if numreachable != MIN_BUCKET_REACHABILITY {
  755. // No
  756. continue;
  757. }
  758. // Remove any trust upgrade migrations to this bucket
  759. self.trustup_migration_table
  760. .table
  761. .retain(|_, &mut v| v != *bucketnum);
  762. // If there are no spares, delete blockage migrations leading to this bucket
  763. if self.bridge_table.spares.is_empty() {
  764. res = false;
  765. self.blockage_migration_table
  766. .table
  767. .retain(|_, &mut v| v != *bucketnum);
  768. continue;
  769. }
  770. // Get the first spare and remove it from the spares
  771. // set.
  772. let spare = *self.bridge_table.spares.iter().next().unwrap();
  773. self.bridge_table.spares.remove(&spare);
  774. self.bridge_table
  775. .blocked_keys
  776. .push((*bucketnum, self.today()));
  777. // Add a blockage migration from this bucket to the spare
  778. self.blockage_migration_table
  779. .table
  780. .insert(*bucketnum, spare);
  781. // Change any blockage migrations with this bucket
  782. // as the destination to the spare
  783. for (_, v) in self.blockage_migration_table.table.iter_mut() {
  784. if *v == *bucketnum {
  785. *v = spare;
  786. }
  787. }
  788. }
  789. }
  790. self.bridge_table.reachable.remove(bridge);
  791. res
  792. }
  793. // Since buckets are moved around in the bridge_table, finding a lookup key that
  794. // does not overwrite existing bridges could become an issue.We keep a list
  795. // of recycleable lookup keys from buckets that have been removed and prioritize
  796. // this list before increasing the counter
  797. fn find_next_available_key(&mut self, bdb: &mut BridgeDb) -> Result<u32, NoAvailableIDError> {
  798. self.clean_up_expired_buckets(bdb);
  799. if self.bridge_table.recycleable_keys.is_empty() {
  800. let mut test_index = 1;
  801. let mut test_counter = self.bridge_table.counter.wrapping_add(test_index);
  802. let mut i = 0;
  803. while self.bridge_table.buckets.contains_key(&test_counter) && i < 5000 {
  804. test_index += 1;
  805. test_counter = self.bridge_table.counter.wrapping_add(test_index);
  806. i += 1;
  807. if i == 5000 {
  808. return Err(NoAvailableIDError::ExhaustedIndexer);
  809. }
  810. }
  811. self.bridge_table.counter = self.bridge_table.counter.wrapping_add(test_index);
  812. Ok(self.bridge_table.counter)
  813. } else {
  814. Ok(self.bridge_table.recycleable_keys.pop().unwrap())
  815. }
  816. }
  817. // This function looks for and removes buckets so their indexes can be reused
  818. // This should include buckets that have been blocked for a sufficiently long period
  819. // that we no longer want to allow migration to, or else, open-entry buckets that
  820. // have been unblocked long enough to become trusted and who's users' credentials
  821. // would have expired (after EXPIRY_DATE)
  822. pub fn clean_up_expired_buckets(&mut self, bdb: &mut BridgeDb) {
  823. // First check if there are any blocked indexes that are old enough to be replaced
  824. self.clean_up_blocked();
  825. // Next do the same for open_invitations buckets
  826. self.clean_up_open_entry(bdb);
  827. }
  828. /// Cleans up exipred blocked buckets
  829. fn clean_up_blocked(&mut self) {
  830. // If there are expired blockages, separate them from the fresh blockages
  831. #[allow(clippy::type_complexity)]
  832. let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = self
  833. .bridge_table
  834. .blocked_keys
  835. .iter()
  836. .partition(|&x| x.1 + EXPIRY_DATE < self.today());
  837. for item in expired {
  838. let key = item.0;
  839. // check each single bridge line and ensure none are still marked as reachable.
  840. // if any are still reachable, remove from reachable bridges.
  841. // When syncing resources, we will likely have to reallocate this bridge but if it hasn't already been
  842. // blocked, this might be fine?
  843. let bridgelines = self.bridge_table.buckets.get(&key).unwrap();
  844. for bridgeline in bridgelines {
  845. // If the bridge hasn't been set to default, assume it's still reachable
  846. if bridgeline.port > 0 {
  847. // Move to unallocated bridges
  848. self.bridge_table.unallocated_bridges.push(*bridgeline);
  849. // Make sure bridge is removed from reachable bridges
  850. self.bridge_table.reachable.remove(bridgeline);
  851. }
  852. }
  853. // Then remove the bucket and keys at the specified index
  854. self.bridge_table.buckets.remove(&key);
  855. self.bridge_table.keys.remove(&key);
  856. //and add them to the recyclable keys
  857. self.bridge_table.recycleable_keys.push(key);
  858. // Remove the expired blocked bucket from the blockage migration table,
  859. // assuming that anyone that has still not attempted to migrate from their
  860. // blocked bridge after the EXPIRY_DATE probably doesn't still need to migrate.
  861. self.blockage_migration_table.table.retain(|&k, _| k != key);
  862. }
  863. // Finally, update the blocked_keys vector to only include the fresh keys
  864. self.bridge_table.blocked_keys = fresh
  865. }
  866. /// Cleans up expired open invitation buckets
  867. fn clean_up_open_entry(&mut self, bdb: &mut BridgeDb) {
  868. // Separate exipred from fresh open invitation indexes
  869. #[allow(clippy::type_complexity)]
  870. let (expired, fresh): (Vec<(u32, u32)>, Vec<(u32, u32)>) = self
  871. .bridge_table
  872. .open_inv_keys
  873. .iter()
  874. .partition(|&x| x.1 + EXPIRY_DATE < self.today());
  875. for item in expired {
  876. let key = item.0;
  877. // We should check that the items were actually distributed before they are removed
  878. if !bdb.distributed_buckets.contains(&key) {
  879. // TODO: Add prometheus metric for this?
  880. println!("This bucket was not actually distributed!");
  881. }
  882. bdb.remove_blocked_or_expired_buckets(&key);
  883. // Remove any trust upgrade migrations from this
  884. // bucket
  885. self.trustup_migration_table.table.retain(|&k, _| k != key);
  886. self.bridge_table.buckets.remove(&key);
  887. self.bridge_table.keys.remove(&key);
  888. //and add them to the recyclable keys
  889. self.bridge_table.recycleable_keys.push(key);
  890. }
  891. // update the open_inv_keys vector to only include the fresh keys
  892. self.bridge_table.open_inv_keys = fresh
  893. }
  894. /// Get today's (real or simulated) date as u32
  895. pub fn today(&self) -> u32 {
  896. // We will not encounter negative Julian dates (~6700 years ago)
  897. // or ones larger than 32 bits
  898. (time::OffsetDateTime::now_utc().date() + self.time_offset)
  899. .to_julian_day()
  900. .try_into()
  901. .unwrap()
  902. }
  903. /// Get today's (real or simulated) date as a DateTime<Utc> value
  904. pub fn today_date(&self) -> DateTime<Utc> {
  905. Utc::now()
  906. }
  907. /// Get a reference to the encrypted bridge table.
  908. ///
  909. /// Be sure to call this function when you want the latest version
  910. /// of the table, since it will put fresh Bucket Reachability
  911. /// credentials in the buckets each day.
  912. pub fn enc_bridge_table(&mut self) -> &HashMap<u32, EncryptedBucket> {
  913. let today = self.today();
  914. if self.bridge_table.date_last_enc != today {
  915. self.bridge_table
  916. .encrypt_table(today, &self.reachability_priv);
  917. }
  918. &self.bridge_table.encbuckets
  919. }
  920. }
  921. pub fn scalar_u32(s: &Scalar) -> Option<u32> {
  922. // Check that the top 28 bytes of the Scalar are 0
  923. let sbytes: &[u8; 32] = s.as_bytes();
  924. if sbytes[4..].ct_eq(&[0u8; 28]).unwrap_u8() == 0 {
  925. return None;
  926. }
  927. Some(u32::from_le_bytes(sbytes[..4].try_into().unwrap()))
  928. }