lib.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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 CMZ14 credentials (GGM version, which is more efficient, but
  5. makes a stronger security assumption): "Algebraic MACs and
  6. Keyed-Verification Anonymous Credentials" (Chase, Meiklejohn, and
  7. Zaverucha, CCS 2014)
  8. The notation follows that of the paper "Hyphae: Social Secret Sharing"
  9. (Lovecruft and de Valence, 2017), Section 4. */
  10. // We really want points to be capital letters and scalars to be
  11. // lowercase letters
  12. #![allow(non_snake_case)]
  13. #[macro_use]
  14. extern crate zkp;
  15. pub mod bridge_table;
  16. pub mod cred;
  17. pub mod dup_filter;
  18. pub mod migration_table;
  19. use sha2::Sha512;
  20. use rand::rngs::OsRng;
  21. use rand::Rng;
  22. use std::convert::{TryFrom, TryInto};
  23. use curve25519_dalek::constants as dalek_constants;
  24. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  25. use curve25519_dalek::ristretto::RistrettoPoint;
  26. use curve25519_dalek::scalar::Scalar;
  27. #[cfg(test)]
  28. use curve25519_dalek::traits::IsIdentity;
  29. use ed25519_dalek::{Keypair, PublicKey, Signature, SignatureError, Signer, Verifier};
  30. use subtle::ConstantTimeEq;
  31. use std::collections::HashSet;
  32. use bridge_table::{
  33. BridgeLine, BridgeTable, ENC_BUCKET_BYTES, MAX_BRIDGES_PER_BUCKET, MIN_BUCKET_REACHABILITY,
  34. };
  35. use migration_table::{MigrationTable, MigrationType};
  36. use lazy_static::lazy_static;
  37. lazy_static! {
  38. pub static ref CMZ_A: RistrettoPoint =
  39. RistrettoPoint::hash_from_bytes::<Sha512>(b"CMZ Generator A");
  40. pub static ref CMZ_B: RistrettoPoint = dalek_constants::RISTRETTO_BASEPOINT_POINT;
  41. pub static ref CMZ_A_TABLE: RistrettoBasepointTable = RistrettoBasepointTable::create(&CMZ_A);
  42. pub static ref CMZ_B_TABLE: RistrettoBasepointTable =
  43. dalek_constants::RISTRETTO_BASEPOINT_TABLE;
  44. }
  45. #[derive(Clone, Debug)]
  46. pub struct IssuerPrivKey {
  47. x0tilde: Scalar,
  48. x: Vec<Scalar>,
  49. }
  50. impl IssuerPrivKey {
  51. /// Create an IssuerPrivKey for credentials with the given number of
  52. /// attributes.
  53. pub fn new(n: u16) -> IssuerPrivKey {
  54. let mut rng = rand::thread_rng();
  55. let x0tilde = Scalar::random(&mut rng);
  56. let mut x: Vec<Scalar> = Vec::with_capacity((n + 1) as usize);
  57. // Set x to a vector of n+1 random Scalars
  58. x.resize_with((n + 1) as usize, || Scalar::random(&mut rng));
  59. IssuerPrivKey { x0tilde, x }
  60. }
  61. }
  62. #[derive(Clone, Debug)]
  63. pub struct IssuerPubKey {
  64. X: Vec<RistrettoPoint>,
  65. }
  66. impl IssuerPubKey {
  67. /// Create an IssuerPubKey from the corresponding IssuerPrivKey
  68. pub fn new(privkey: &IssuerPrivKey) -> IssuerPubKey {
  69. let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
  70. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  71. let n_plus_one = privkey.x.len();
  72. let mut X: Vec<RistrettoPoint> = Vec::with_capacity(n_plus_one);
  73. // The first element is a special case; it is
  74. // X[0] = x0tilde*A + x[0]*B
  75. X.push(&privkey.x0tilde * Atable + &privkey.x[0] * Btable);
  76. // The other elements (1 through n) are X[i] = x[i]*A
  77. for i in 1..n_plus_one {
  78. X.push(&privkey.x[i] * Atable);
  79. }
  80. IssuerPubKey { X }
  81. }
  82. }
  83. /// The BridgeDb. This will typically be a singleton object. The
  84. /// BridgeDb's role is simply to issue signed "open invitations" to
  85. /// people who are not yet part of the system.
  86. #[derive(Debug)]
  87. pub struct BridgeDb {
  88. /// The keypair for signing open invitations
  89. keypair: Keypair,
  90. /// The public key for verifying open invitations
  91. pub pubkey: PublicKey,
  92. /// The set of open-invitation buckets
  93. openinv_buckets: HashSet<u32>,
  94. }
  95. /// An open invitation is a [u8; OPENINV_LENGTH] where the first 32
  96. /// bytes are the serialization of a random Scalar (the invitation id),
  97. /// the next 4 bytes are a little-endian bucket number, and the last
  98. /// SIGNATURE_LENGTH bytes are the signature on the first 36 bytes.
  99. pub const OPENINV_LENGTH: usize = 32 // the length of the random
  100. // invitation id (a Scalar)
  101. + 4 // the length of the u32 for the bucket number
  102. + ed25519_dalek::SIGNATURE_LENGTH; // the length of the signature
  103. impl BridgeDb {
  104. /// Create the BridgeDb.
  105. pub fn new() -> Self {
  106. let mut csprng = OsRng {};
  107. let keypair = Keypair::generate(&mut csprng);
  108. let pubkey = keypair.public;
  109. Self {
  110. keypair,
  111. pubkey,
  112. openinv_buckets: Default::default(),
  113. }
  114. }
  115. /// Insert an open-invitation bucket into the set
  116. pub fn insert_openinv(&mut self, bucket: u32) {
  117. self.openinv_buckets.insert(bucket);
  118. }
  119. /// Remove an open-invitation bucket from the set
  120. pub fn remove_openinv(&mut self, bucket: u32) {
  121. self.openinv_buckets.remove(&bucket);
  122. }
  123. /// Produce an open invitation. In this example code, we just
  124. /// choose a random open-invitation bucket.
  125. pub fn invite(&self) -> [u8; OPENINV_LENGTH] {
  126. let mut res: [u8; OPENINV_LENGTH] = [0; OPENINV_LENGTH];
  127. let mut rng = rand::thread_rng();
  128. // Choose a random invitation id (a Scalar) and serialize it
  129. let id = Scalar::random(&mut rng);
  130. res[0..32].copy_from_slice(&id.to_bytes());
  131. // Choose a random bucket number (from the set of open
  132. // invitation buckets) and serialize it
  133. let openinv_vec: Vec<&u32> = self.openinv_buckets.iter().collect();
  134. let bucket_num = *openinv_vec[rng.gen_range(0, openinv_vec.len())];
  135. res[32..(32 + 4)].copy_from_slice(&bucket_num.to_le_bytes());
  136. // Sign the first 36 bytes and serialize it
  137. let sig = self.keypair.sign(&res[0..(32 + 4)]);
  138. res[(32 + 4)..].copy_from_slice(&sig.to_bytes());
  139. res
  140. }
  141. /// Verify an open invitation. Returns the invitation id and the
  142. /// bucket number if the signature checked out. It is up to the
  143. /// caller to then check that the invitation id has not been used
  144. /// before.
  145. pub fn verify(
  146. invitation: [u8; OPENINV_LENGTH],
  147. pubkey: PublicKey,
  148. ) -> Result<(Scalar, u32), SignatureError> {
  149. // Pull out the signature and verify it
  150. let sig = Signature::try_from(&invitation[(32 + 4)..])?;
  151. pubkey.verify(&invitation[0..(32 + 4)], &sig)?;
  152. // The signature passed. Pull out the bucket number and then
  153. // the invitation id
  154. let bucket = u32::from_le_bytes(invitation[32..(32 + 4)].try_into().unwrap());
  155. match Scalar::from_canonical_bytes(invitation[0..32].try_into().unwrap()) {
  156. // It should never happen that there's a valid signature on
  157. // an invalid serialization of a Scalar, but check anyway.
  158. None => Err(SignatureError::new()),
  159. Some(s) => Ok((s, bucket)),
  160. }
  161. }
  162. }
  163. impl Default for BridgeDb {
  164. fn default() -> Self {
  165. Self::new()
  166. }
  167. }
  168. /// The bridge authority. This will typically be a singleton object.
  169. #[derive(Debug)]
  170. pub struct BridgeAuth {
  171. /// The private key for the main Lox credential
  172. lox_priv: IssuerPrivKey,
  173. /// The public key for the main Lox credential
  174. pub lox_pub: IssuerPubKey,
  175. /// The private key for migration credentials
  176. migration_priv: IssuerPrivKey,
  177. /// The public key for migration credentials
  178. pub migration_pub: IssuerPubKey,
  179. /// The private key for migration key credentials
  180. migrationkey_priv: IssuerPrivKey,
  181. /// The public key for migration key credentials
  182. pub migrationkey_pub: IssuerPubKey,
  183. /// The private key for bucket reachability credentials
  184. reachability_priv: IssuerPrivKey,
  185. /// The public key for bucket reachability credentials
  186. pub reachability_pub: IssuerPubKey,
  187. /// The private key for invitation credentials
  188. invitation_priv: IssuerPrivKey,
  189. /// The public key for invitation credentials
  190. pub invitation_pub: IssuerPubKey,
  191. /// The public key of the BridgeDb issuing open invitations
  192. pub bridgedb_pub: PublicKey,
  193. /// The bridge table
  194. bridge_table: BridgeTable,
  195. /// The migration tables
  196. trustup_migration_table: MigrationTable,
  197. blockage_migration_table: MigrationTable,
  198. /// Duplicate filter for open invitations
  199. openinv_filter: dup_filter::DupFilter<Scalar>,
  200. /// Duplicate filter for Lox credential ids
  201. id_filter: dup_filter::DupFilter<Scalar>,
  202. /// Duplicate filter for Invitation credential ids
  203. inv_id_filter: dup_filter::DupFilter<Scalar>,
  204. /// Duplicate filter for trust promotions (from untrusted level 0 to
  205. /// trusted level 1)
  206. trust_promotion_filter: dup_filter::DupFilter<Scalar>,
  207. /// For testing only: offset of the true time to the simulated time
  208. time_offset: time::Duration,
  209. }
  210. impl BridgeAuth {
  211. pub fn new(bridgedb_pub: PublicKey) -> Self {
  212. // Create the private and public keys for each of the types of
  213. // credential, each with the appropriate number of attributes
  214. let lox_priv = IssuerPrivKey::new(6);
  215. let lox_pub = IssuerPubKey::new(&lox_priv);
  216. let migration_priv = IssuerPrivKey::new(3);
  217. let migration_pub = IssuerPubKey::new(&migration_priv);
  218. let migrationkey_priv = IssuerPrivKey::new(2);
  219. let migrationkey_pub = IssuerPubKey::new(&migrationkey_priv);
  220. let reachability_priv = IssuerPrivKey::new(2);
  221. let reachability_pub = IssuerPubKey::new(&reachability_priv);
  222. let invitation_priv = IssuerPrivKey::new(4);
  223. let invitation_pub = IssuerPubKey::new(&invitation_priv);
  224. Self {
  225. lox_priv,
  226. lox_pub,
  227. migration_priv,
  228. migration_pub,
  229. migrationkey_priv,
  230. migrationkey_pub,
  231. reachability_priv,
  232. reachability_pub,
  233. invitation_priv,
  234. invitation_pub,
  235. bridgedb_pub,
  236. bridge_table: Default::default(),
  237. trustup_migration_table: MigrationTable::new(MigrationType::TrustUpgrade),
  238. blockage_migration_table: MigrationTable::new(MigrationType::Blockage),
  239. openinv_filter: Default::default(),
  240. id_filter: Default::default(),
  241. inv_id_filter: Default::default(),
  242. trust_promotion_filter: Default::default(),
  243. time_offset: time::Duration::zero(),
  244. }
  245. }
  246. /// Insert a set of open invitation bridges.
  247. ///
  248. /// Each of the bridges will be given its own open invitation
  249. /// bucket, and the BridgeDb will be informed. A single bucket
  250. /// containing all of the bridges will also be created, with a trust
  251. /// upgrade migration from each of the single-bridge buckets.
  252. pub fn add_openinv_bridges(
  253. &mut self,
  254. bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET],
  255. bdb: &mut BridgeDb,
  256. ) {
  257. let bnum = self.bridge_table.new_bucket(&bridges);
  258. let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
  259. for b in bridges.iter() {
  260. single[0] = *b;
  261. let snum = self.bridge_table.new_bucket(&single);
  262. bdb.insert_openinv(snum);
  263. println!("Adding {} -> {}", snum, bnum);
  264. self.trustup_migration_table.table.insert(snum, bnum);
  265. }
  266. }
  267. /// Insert a hot spare bucket of bridges
  268. pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
  269. let bnum = self.bridge_table.new_bucket(&bucket);
  270. self.bridge_table.spares.insert(bnum);
  271. }
  272. /// Mark a bridge as unreachable
  273. ///
  274. /// This bridge will be removed from each of the buckets that
  275. /// contains it. If any of those are open-invitation buckets, the
  276. /// trust upgrade migration for that bucket will be removed and the
  277. /// BridgeDb will be informed to stop handing out that bridge. If
  278. /// any of those are trusted buckets where the number of reachable
  279. /// bridges has fallen below the threshold, a blockage migration
  280. /// from that bucket to a spare bucket will be added, and the spare
  281. /// bucket will be removed from the list of hot spares. In
  282. /// addition, if the blocked bucket was the _target_ of a blockage
  283. /// migration, change the target to the new (formerly spare) bucket.
  284. /// Returns true if sucessful, or false if it needed a hot spare but
  285. /// there was none available.
  286. pub fn bridge_unreachable(&mut self, bridge: &BridgeLine, bdb: &mut BridgeDb) -> bool {
  287. let mut res: bool = true;
  288. let positions = self.bridge_table.reachable.get(bridge);
  289. if let Some(v) = positions {
  290. for (bucketnum, offset) in v.iter() {
  291. // Count how many bridges in this bucket are reachable
  292. let numreachable = self.bridge_table.buckets[*bucketnum as usize]
  293. .iter()
  294. .filter(|br| self.bridge_table.reachable.get(br).is_some())
  295. .count();
  296. // Remove the bridge from the bucket
  297. assert!(self.bridge_table.buckets[*bucketnum as usize][*offset] == *bridge);
  298. self.bridge_table.buckets[*bucketnum as usize][*offset] = BridgeLine::default();
  299. // Is this bucket an open-invitation bucket?
  300. if bdb.openinv_buckets.contains(bucketnum) {
  301. bdb.openinv_buckets.remove(bucketnum);
  302. self.trustup_migration_table.table.remove(bucketnum);
  303. continue;
  304. }
  305. // Does this removal cause the bucket to go below the
  306. // threshold?
  307. if numreachable != MIN_BUCKET_REACHABILITY {
  308. // No
  309. continue;
  310. }
  311. // This bucket is now unreachable. Get a spare bucket
  312. if self.bridge_table.spares.is_empty() {
  313. // Uh, oh. No spares available. Just delete any
  314. // migrations leading to this bucket.
  315. res = false;
  316. self.trustup_migration_table
  317. .table
  318. .retain(|_, &mut v| v != *bucketnum);
  319. self.blockage_migration_table
  320. .table
  321. .retain(|_, &mut v| v != *bucketnum);
  322. } else {
  323. // Get the first spare and remove it from the spares
  324. // set.
  325. let spare = *self.bridge_table.spares.iter().next().unwrap();
  326. self.bridge_table.spares.remove(&spare);
  327. // Add a blockage migration from this bucket to the spare
  328. self.blockage_migration_table
  329. .table
  330. .insert(*bucketnum, spare);
  331. // Remove any trust upgrade migrations to this
  332. // bucket
  333. self.trustup_migration_table
  334. .table
  335. .retain(|_, &mut v| v != *bucketnum);
  336. // Change any blockage migrations with this bucket
  337. // as the destination to the spare
  338. for (_, v) in self.blockage_migration_table.table.iter_mut() {
  339. if *v == *bucketnum {
  340. *v = spare;
  341. }
  342. }
  343. }
  344. }
  345. }
  346. self.bridge_table.reachable.remove(bridge);
  347. res
  348. }
  349. #[cfg(test)]
  350. /// For testing only: manually advance the day by 1 day
  351. pub fn advance_day(&mut self) {
  352. self.time_offset += time::Duration::days(1);
  353. }
  354. #[cfg(test)]
  355. /// For testing only: manually advance the day by the given number
  356. /// of days
  357. pub fn advance_days(&mut self, days: u16) {
  358. self.time_offset += time::Duration::days(days.into());
  359. }
  360. /// Get today's (real or simulated) date
  361. fn today(&self) -> u32 {
  362. // We will not encounter negative Julian dates (~6700 years ago)
  363. // or ones larger than 32 bits
  364. (time::OffsetDateTime::now_utc().date() + self.time_offset)
  365. .julian_day()
  366. .try_into()
  367. .unwrap()
  368. }
  369. /// Get a reference to the encrypted bridge table.
  370. ///
  371. /// Be sure to call this function when you want the latest version
  372. /// of the table, since it will put fresh Bucket Reachability
  373. /// credentials in the buckets each day.
  374. pub fn enc_bridge_table(&mut self) -> &Vec<[u8; ENC_BUCKET_BYTES]> {
  375. let today = self.today();
  376. if self.bridge_table.date_last_enc != today {
  377. self.bridge_table
  378. .encrypt_table(today, &self.reachability_priv);
  379. }
  380. &self.bridge_table.encbuckets
  381. }
  382. #[cfg(test)]
  383. /// Verify the two MACs on a Lox credential
  384. pub fn verify_lox(&self, cred: &cred::Lox) -> bool {
  385. if cred.P.is_identity() {
  386. return false;
  387. }
  388. let Q = (self.lox_priv.x[0]
  389. + cred.id * self.lox_priv.x[1]
  390. + cred.bucket * self.lox_priv.x[2]
  391. + cred.trust_level * self.lox_priv.x[3]
  392. + cred.level_since * self.lox_priv.x[4]
  393. + cred.invites_remaining * self.lox_priv.x[5]
  394. + cred.blockages * self.lox_priv.x[6])
  395. * cred.P;
  396. Q == cred.Q
  397. }
  398. #[cfg(test)]
  399. /// Verify the MAC on a Migration credential
  400. pub fn verify_migration(&self, cred: &cred::Migration) -> bool {
  401. if cred.P.is_identity() {
  402. return false;
  403. }
  404. let Q = (self.migration_priv.x[0]
  405. + cred.lox_id * self.migration_priv.x[1]
  406. + cred.from_bucket * self.migration_priv.x[2]
  407. + cred.to_bucket * self.migration_priv.x[3])
  408. * cred.P;
  409. Q == cred.Q
  410. }
  411. #[cfg(test)]
  412. /// Verify the MAC on a Bucket Reachability credential
  413. pub fn verify_reachability(&self, cred: &cred::BucketReachability) -> bool {
  414. if cred.P.is_identity() {
  415. return false;
  416. }
  417. let Q = (self.reachability_priv.x[0]
  418. + cred.date * self.reachability_priv.x[1]
  419. + cred.bucket * self.reachability_priv.x[2])
  420. * cred.P;
  421. Q == cred.Q
  422. }
  423. #[cfg(test)]
  424. /// Verify the MAC on a Invitation credential
  425. pub fn verify_invitation(&self, cred: &cred::Invitation) -> bool {
  426. if cred.P.is_identity() {
  427. return false;
  428. }
  429. let Q = (self.invitation_priv.x[0]
  430. + cred.inv_id * self.invitation_priv.x[1]
  431. + cred.date * self.invitation_priv.x[2]
  432. + cred.bucket * self.invitation_priv.x[3]
  433. + cred.blockages * self.invitation_priv.x[4])
  434. * cred.P;
  435. Q == cred.Q
  436. }
  437. }
  438. /// Try to extract a u64 from a Scalar
  439. pub fn scalar_u64(s: &Scalar) -> Option<u64> {
  440. // Check that the top 24 bytes of the Scalar are 0
  441. let sbytes = s.as_bytes();
  442. if sbytes[8..].ct_eq(&[0u8; 24]).unwrap_u8() == 0 {
  443. return None;
  444. }
  445. Some(u64::from_le_bytes(sbytes[..8].try_into().unwrap()))
  446. }
  447. /// Try to extract a u32 from a Scalar
  448. pub fn scalar_u32(s: &Scalar) -> Option<u32> {
  449. // Check that the top 28 bytes of the Scalar are 0
  450. let sbytes = s.as_bytes();
  451. if sbytes[4..].ct_eq(&[0u8; 28]).unwrap_u8() == 0 {
  452. return None;
  453. }
  454. Some(u32::from_le_bytes(sbytes[..4].try_into().unwrap()))
  455. }
  456. /// Double a Scalar
  457. pub fn scalar_dbl(s: &Scalar) -> Scalar {
  458. s + s
  459. }
  460. /// Double a RistrettoPoint
  461. pub fn pt_dbl(P: &RistrettoPoint) -> RistrettoPoint {
  462. P + P
  463. }
  464. /// The protocol modules.
  465. ///
  466. /// Each protocol lives in a submodule. Each submodule defines structs
  467. /// for Request (the message from the client to the bridge authority),
  468. /// State (the state held by the client while waiting for the reply),
  469. /// and Response (the message from the bridge authority to the client).
  470. /// Each submodule defines functions request, which produces a (Request,
  471. /// State) pair, and handle_response, which consumes a State and a
  472. /// Response. It also adds a handle_* function to the BridgeAuth struct
  473. /// that consumes a Request and produces a Result<Response, ProofError>.
  474. pub mod proto {
  475. pub mod issue_invite;
  476. pub mod level_up;
  477. pub mod migration;
  478. pub mod open_invite;
  479. pub mod redeem_invite;
  480. pub mod trust_promotion;
  481. }
  482. // Unit tests
  483. #[cfg(test)]
  484. mod tests;