diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 109ac54..b6fd8c5 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -225,3 +225,5 @@ impl BridgeAuth { (time::OffsetDateTime::now_utc().date() + self.time_offset).julian_day() } } + +pub mod open_invite; diff --git a/crates/lox-library/src/open_invite.rs b/crates/lox-library/src/open_invite.rs new file mode 100644 index 0000000..01a81d7 --- /dev/null +++ b/crates/lox-library/src/open_invite.rs @@ -0,0 +1,116 @@ +/*! A module for the protocol for the user to redeem an open invitation +with the BA (bridge authority) to receive their initial Lox +credential. The credential will have attributes: + +- id: jointly chosen by the user and BA +- bucket: set by the BA +- trust_level: 0 +- level_since: today +- invites_remaining: 0 +- invites_issued: 0 + +*/ + +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; + +use super::{BridgeAuth, IssuerPubKey}; +use super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE}; + +/// The request message for this protocol +pub struct Request { + invite: [u8; super::OPENINV_LENGTH], + D: RistrettoPoint, + EncIdClient: (RistrettoPoint, RistrettoPoint), + piUserBlinding: CompactProof, +} + +#[derive(Debug)] +/// The client state for this protocol +pub struct State { + d: Scalar, + D: RistrettoPoint, + EncIdClient: (RistrettoPoint, RistrettoPoint), + id_client: Scalar, +} + +/// The response message for this protocol +pub struct Response { + P: RistrettoPoint, + EncQ: (RistrettoPoint, RistrettoPoint), + id_server: Scalar, + TId: RistrettoPoint, + bucket: Scalar, + level_since: Scalar, + P_noopmigration: RistrettoPoint, + EncQ_noopmigration: (RistrettoPoint, RistrettoPoint), + TId_noopmigration: RistrettoPoint, +} + +// The userblinding ZKP +define_proof! { + userblinding, + "Open Invitation User Blinding", + (d, eid_client, id_client), + (EncIdClient0, EncIdClient1, D), + (B) : + EncIdClient0 = (eid_client*B), + EncIdClient1 = (id_client*B + eid_client*D), + D = (d*B) +} + +/// Submit an open invitation issued by the BridgeDb to receive your +/// first Lox credential +pub fn request(invite: &[u8; super::OPENINV_LENGTH]) -> (Request, State) { + let B: &RistrettoPoint = &CMZ_B; + let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE; + + // Pick an ElGamal keypair + let mut rng = rand::thread_rng(); + let d = Scalar::random(&mut rng); + let D = &d * Btable; + + // Pick a random client component of the id + let id_client = Scalar::random(&mut rng); + + // Encrypt it (times the basepoint B) to the ElGamal public key D we + // just created + let eid_client = Scalar::random(&mut rng); + let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D); + + // Construct the proof of correct user blinding + let mut transcript = Transcript::new(b"open invite user blinding"); + let piUserBlinding = userblinding::prove_compact( + &mut transcript, + userblinding::ProveAssignments { + B: &B, + EncIdClient0: &EncIdClient.0, + EncIdClient1: &EncIdClient.1, + D: &D, + d: &d, + eid_client: &eid_client, + id_client: &id_client, + }, + ) + .0; + ( + Request { + invite: *invite, + D, + EncIdClient, + piUserBlinding, + }, + State { + d, + D, + EncIdClient, + id_client, + }, + ) +}