Start on trust promotion

This is the protocol for the user to get promoted from untrusted (trust
level 0) to trusted (trust level 1).
This commit is contained in:
Ian Goldberg 2021-04-29 15:18:54 -04:00
parent b86973174a
commit e7bb50ab2b
5 changed files with 146 additions and 1 deletions

View File

@ -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],

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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)>,
}

View File

@ -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,
}