Просмотр исходного кода

Start on trust promotion

This is the protocol for the user to get promoted from untrusted (trust
level 0) to trusted (trust level 1).
Ian Goldberg 3 лет назад
Родитель
Сommit
361e9f20a2
5 измененных файлов с 146 добавлено и 1 удалено
  1. 1 1
      src/bridge_table.rs
  2. 16 0
      src/cred.rs
  3. 64 0
      src/lib.rs
  4. 15 0
      src/migration_table.rs
  5. 50 0
      src/trust_promotion.rs

+ 1 - 1
src/bridge_table.rs

@@ -29,7 +29,7 @@ pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET;
 pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
 
 /// A bridge information line
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug)]
 pub struct BridgeLine {
     /// IPv4 or IPv6 address
     pub addr: [u8; 16],

+ 16 - 0
src/cred.rs

@@ -41,3 +41,19 @@ pub struct Lox {
     pub P_noopmigration: RistrettoPoint,
     pub Q_noopmigration: RistrettoPoint,
 }
+
+// The migration key credential is never actually instantiated.  It is
+// an implicit credential with the following attributes:
+// - lox_id: Scalar,
+// - from_bucket: Scalar
+// Plus the usual (P,Q) MAC.  This credential type does have an
+// associated private and public key, however.  The idea is that if a
+// user proves (in zero knowledge) that their Lox credential entitles
+// them to migrate from one bucket to another, the BA will issue a
+// (blinded, so the BA will not know the values of the attributes or of
+// Q) MAC on this implicit credential.  The Q value will then be used
+// (actually, a hash of lox_id, from_bucket, and Q) to encrypt the
+// to_bucket, P, and Q fields of a Migration credential.  That way,
+// people entitled to migrate buckets can receive a Migration credential
+// with their new bucket, without the BA learning either their old or
+// new buckets.

+ 64 - 0
src/lib.rs

@@ -20,6 +20,8 @@ extern crate zkp;
 pub mod bridge_table;
 pub mod cred;
 pub mod dup_filter;
+pub mod migration_table;
+pub mod trust_promotion;
 
 use sha2::Sha512;
 
@@ -178,6 +180,10 @@ pub struct BridgeAuth {
     migration_priv: IssuerPrivKey,
     /// The public key for migration credentials
     pub migration_pub: IssuerPubKey,
+    /// The private key for migration key credentials
+    migrationkey_priv: IssuerPrivKey,
+    /// The public key for migration key credentials
+    pub migrationkey_pub: IssuerPubKey,
 
     /// The public key of the BridgeDb issuing open invitations
     pub bridgedb_pub: PublicKey,
@@ -185,10 +191,16 @@ pub struct BridgeAuth {
     /// The bridge table
     bridge_table: bridge_table::BridgeTable,
 
+    /// The migration table
+    migration_table: migration_table::MigrationTable,
+
     /// Duplicate filter for open invitations
     openinv_filter: dup_filter::DupFilter<Scalar>,
     /// Duplicate filter for credential ids
     id_filter: dup_filter::DupFilter<Scalar>,
+    /// Duplicate filter for trust promotions (from untrusted level 0 to
+    /// trusted level 1)
+    trust_promotion_filter: dup_filter::DupFilter<Scalar>,
 
     /// For testing only: offset of the true time to the simulated time
     time_offset: time::Duration,
@@ -196,19 +208,27 @@ pub struct BridgeAuth {
 
 impl BridgeAuth {
     pub fn new(bridgedb_pub: PublicKey) -> Self {
+        // Create the private and public keys for each of the types of
+        // credential, each with the appropriate number of attributes
         let lox_priv = IssuerPrivKey::new(6);
         let lox_pub = IssuerPubKey::new(&lox_priv);
         let migration_priv = IssuerPrivKey::new(3);
         let migration_pub = IssuerPubKey::new(&migration_priv);
+        let migrationkey_priv = IssuerPrivKey::new(2);
+        let migrationkey_pub = IssuerPubKey::new(&migrationkey_priv);
         Self {
             lox_priv,
             lox_pub,
             migration_priv,
             migration_pub,
+            migrationkey_priv,
+            migrationkey_pub,
             bridgedb_pub,
             bridge_table: Default::default(),
+            migration_table: Default::default(),
             openinv_filter: Default::default(),
             id_filter: Default::default(),
+            trust_promotion_filter: Default::default(),
             time_offset: time::Duration::zero(),
         }
     }
@@ -284,4 +304,48 @@ mod tests {
         println!("cred = {:?}", cred);
         println!("bucket = {:?}", bucket);
     }
+
+    #[test]
+    fn test_trust_promotion() {
+        // Create a BridegDb
+        let bdb = BridgeDb::new(15);
+        // Create a BridgeAuth
+        let mut ba = BridgeAuth::new(bdb.pubkey);
+
+        // Make 15 buckets with one random bridge each
+        for _ in 0..15 {
+            let bucket: [BridgeLine; 3] =
+                [BridgeLine::random(), Default::default(), Default::default()];
+            ba.bridge_table.new_bucket(bucket);
+        }
+        // Make 5 more buckets, each containing 3 of the previously
+        // created bridges
+        for i in 0u32..5 {
+            let iusize = i as usize;
+            let bucket: [BridgeLine; 3] = [
+                ba.bridge_table.buckets[3 * iusize][0],
+                ba.bridge_table.buckets[3 * iusize + 1][0],
+                ba.bridge_table.buckets[3 * iusize + 2][0],
+            ];
+            ba.bridge_table.new_bucket(bucket);
+            // Add the allowed migrations to the migration table
+            ba.migration_table.table.push((3 * i, 15 + i));
+            ba.migration_table.table.push((3 * i + 1, 15 + i));
+            ba.migration_table.table.push((3 * i + 2, 15 + i));
+        }
+        // Create the encrypted bridge table
+        ba.bridge_table.encrypt_table();
+
+        // Issue an open invitation
+        let inv = bdb.invite();
+
+        // Use it to get a Lox credential
+        let (req, state) = open_invite::request(&inv);
+        let resp = ba.handle_open_invite(req).unwrap();
+        let cred =
+            open_invite::handle_response(state, resp, &ba.lox_pub, &ba.migration_pub).unwrap();
+
+        // Time passes
+        ba.advance_days(40);
+    }
 }

+ 15 - 0
src/migration_table.rs

@@ -0,0 +1,15 @@
+/*! The migration table.
+
+This is a table listing pairs of (from_bucket_id, to_bucket_id).  A pair
+in this table indicates that a user with a Lox credential containing
+from_bucket_id (and possibly meeting other conditions as well) is
+entitled to exchange their credential for one with to_bucket_id.  (Note
+that the credentials contain the bucket attributes, which include both
+the id and the bucket decrytpion key, but the table just contains the
+bucket ids.) */
+
+/// The migration table
+#[derive(Default, Debug)]
+pub struct MigrationTable {
+    pub table: Vec<(u32, u32)>,
+}

+ 50 - 0
src/trust_promotion.rs

@@ -0,0 +1,50 @@
+/*! A module for the protocol for the user to get promoted from
+untrusted (trust level 0) to trusted (trust level 1).
+
+They are allowed to do this as long as UNTRUSTED_INTERVAL days have
+passed since they obtained their level 0 Lox credential, and their
+bridge (level 0 users get put in a one-bridge bucket) has not been
+blocked.  (Blocked bridges in one-bridge buckets will have their entries
+removed from the bridge authority's migration table.)
+
+The user presents their current Lox credential:
+- id: revealed
+- bucket: blinded
+- trust_level: revealed to be 0
+- level_since: blinded, but proved in ZK that it's at least
+  UNTRUSTED_INTERVAL days ago
+- invites_remaining: revealed to be 0
+- invites_issued: revealed to be 0
+
+They will receive in return the encrypted MAC (Pk, EncQk) for their
+implicit Migration Key credential with attributes id and bucket,
+along with a HashMap of encrypted Migration credentials.  For each
+(from_i, to_i) in the BA's migration list, there will be an entry in
+the HashMap with key H1(id, from_attr_i, Qk_i) and value
+Enc_{H2(id, from_attr_i, Qk_i)}(to_attr_i, P_i, Q_i).  Here H1 and H2
+are the first 16 bytes and the second 16 bytes respectively of the
+SHA256 hash of the input, P_i and Q_i are a MAC on the Migration
+credential with attributes id, from_attr_i, and to_attr_i. Qk_i is the
+value EncQk would decrypt to if bucket were equal to from_attr_i. */
+
+use curve25519_dalek::ristretto::RistrettoBasepointTable;
+use curve25519_dalek::ristretto::RistrettoPoint;
+use curve25519_dalek::scalar::Scalar;
+use curve25519_dalek::traits::IsIdentity;
+
+use zkp::CompactProof;
+use zkp::ProofError;
+use zkp::Transcript;
+
+/// The minimum number of days a user has to be at trust level 0
+/// (untrusted) with their (single) bridge unblocked before they can
+/// move to level 1.
+///
+/// The implementation also puts an upper bound of UNTRUSTED_INTERVAL +
+/// 511 days, which is not unreasonable; we want users to be engaging
+/// with the system in order to move up trust levels.
+pub const UNTRUSTED_INTERVAL: u64 = 30;
+
+pub struct Request {
+    id: Scalar,
+}