From 2791f0bf54e88f23f782514799284363c7195764 Mon Sep 17 00:00:00 2001 From: Ian Goldberg Date: Wed, 28 Apr 2021 23:02:45 -0400 Subject: [PATCH] Handle the response of the open invitation protocol to produce the Lox credential --- crates/lox-library/src/cred.rs | 2 + crates/lox-library/src/lib.rs | 5 +- crates/lox-library/src/open_invite.rs | 87 ++++++++++++++++++++++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/crates/lox-library/src/cred.rs b/crates/lox-library/src/cred.rs index 97eb09d..46a6ab9 100644 --- a/crates/lox-library/src/cred.rs +++ b/crates/lox-library/src/cred.rs @@ -9,6 +9,7 @@ use curve25519_dalek::scalar::Scalar; /// A migration credential. This credential authorizes the holder of /// the Lox credential with the given id to switch from bucket /// from_bucket to bucket to_bucket. +#[derive(Debug)] pub struct Migration { pub P: RistrettoPoint, pub Q: RistrettoPoint, @@ -26,6 +27,7 @@ pub struct Migration { /// authorizes the user to switch from its current bucket to the same /// bucket (i.e., a no-op). This can be useful for hiding from the BA /// whether or not the user is performing a bucket migration. +#[derive(Debug)] pub struct Lox { pub P: RistrettoPoint, pub Q: RistrettoPoint, diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 88d1fb2..a81bcee 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -274,6 +274,9 @@ mod tests { // Use it to get a Lox credential let (req, state) = open_invite::request(&inv); - let resp = ba.handle_open_invite(req); + let resp = ba.handle_open_invite(req).unwrap(); + let cred = + open_invite::handle_response(state, resp, &ba.lox_pub, &ba.migration_pub).unwrap(); + println!("cred = {:?}", cred); } } diff --git a/crates/lox-library/src/open_invite.rs b/crates/lox-library/src/open_invite.rs index 128f2b3..d55e077 100644 --- a/crates/lox-library/src/open_invite.rs +++ b/crates/lox-library/src/open_invite.rs @@ -14,12 +14,14 @@ credential. The credential will have attributes: 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::bridge_table; +use super::cred; use super::dup_filter::SeenType; use super::{BridgeAuth, IssuerPubKey}; use super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE}; @@ -74,7 +76,8 @@ define_proof! { (x0, x0tilde, xid, xbucket, xsince, s, b, tid, x0_nm, x0tilde_nm, xid_nm, xfrom_nm, xto_nm, s_nm, b_nm, tid_nm), (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xsince, Pbucket, Psince, TId, - P_nm, EncQ0_nm, EncQ1_nm, X0_nm, Xid_nm, Xfrom_nm, Xto_nm, TId_nm, + P_nm, EncQ0_nm, EncQ1_nm, X0_nm, Xid_nm, Xfrom_nm, Xto_nm, + Pbucket_nm, TId_nm, D, EncId0, EncId1), (A, B) : Xid = (xid*A), @@ -94,7 +97,7 @@ define_proof! { TId_nm = (b_nm*Xid_nm), TId_nm = (tid_nm*A), EncQ0_nm = (s_nm*B + tid_nm*EncId0), - EncQ1_nm = (s_nm*D + tid_nm*EncId1 + x0_nm*P_nm + xfrom_nm*Pbucket + xto_nm*Pbucket) + EncQ1_nm = (s_nm*D + tid_nm*EncId1 + x0_nm*P_nm + xfrom_nm*Pbucket_nm + xto_nm*Pbucket_nm) } /// Submit an open invitation issued by the BridgeDb to receive your @@ -231,7 +234,7 @@ impl BridgeAuth { let QHc_noopmigration = (self.migration_priv.x[0] + self.migration_priv.x[2] * bucket + self.migration_priv.x[3] * bucket) - * P; + * P_noopmigration; // El Gamal encrypt it to the public key req.D let s_noopmigration = Scalar::random(&mut rng); @@ -274,6 +277,7 @@ impl BridgeAuth { Xid_nm: &self.migration_pub.X[1], Xfrom_nm: &self.migration_pub.X[2], Xto_nm: &self.migration_pub.X[3], + Pbucket_nm: &(bucket * P_noopmigration), TId_nm: &TId_noopmigration, D: &req.D, EncId0: &EncId.0, @@ -312,3 +316,80 @@ impl BridgeAuth { }) } } + +/// Handle the reponse to the request, producing the desired Lox +/// credential if successful. +pub fn handle_response( + state: State, + resp: Response, + lox_pub: &IssuerPubKey, + migration_pub: &IssuerPubKey, +) -> Result { + let A: &RistrettoPoint = &CMZ_A; + let B: &RistrettoPoint = &CMZ_B; + let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE; + + if resp.P.is_identity() || resp.P_noopmigration.is_identity() { + return Err(ProofError::VerificationFailure); + } + + // Add the server's contribution to the id to our own, both in plain + // and encrypted form + let id = state.id_client + resp.id_server; + let EncId = ( + state.EncIdClient.0, + state.EncIdClient.1 + &resp.id_server * Btable, + ); + + // Verify the proof + let mut transcript = Transcript::new(b"open invite issuing"); + blindissue::verify_compact( + &resp.piBlindIssue, + &mut transcript, + blindissue::VerifyAssignments { + A: &A.compress(), + B: &B.compress(), + P: &resp.P.compress(), + EncQ0: &resp.EncQ.0.compress(), + EncQ1: &resp.EncQ.1.compress(), + X0: &lox_pub.X[0].compress(), + Xid: &lox_pub.X[1].compress(), + Xbucket: &lox_pub.X[2].compress(), + Xsince: &lox_pub.X[4].compress(), + Pbucket: &(resp.bucket * resp.P).compress(), + Psince: &(resp.level_since * resp.P).compress(), + TId: &resp.TId.compress(), + P_nm: &resp.P_noopmigration.compress(), + EncQ0_nm: &resp.EncQ_noopmigration.0.compress(), + EncQ1_nm: &resp.EncQ_noopmigration.1.compress(), + X0_nm: &migration_pub.X[0].compress(), + Xid_nm: &migration_pub.X[1].compress(), + Xfrom_nm: &migration_pub.X[2].compress(), + Xto_nm: &migration_pub.X[3].compress(), + Pbucket_nm: &(resp.bucket * resp.P_noopmigration).compress(), + TId_nm: &resp.TId_noopmigration.compress(), + D: &state.D.compress(), + EncId0: &EncId.0.compress(), + EncId1: &EncId.1.compress(), + }, + )?; + + // Decrypt EncQ + let Q = resp.EncQ.1 - (state.d * resp.EncQ.0); + + // Decrypt EncQ_noopmigration + let Q_noopmigration = resp.EncQ_noopmigration.1 - (state.d * resp.EncQ_noopmigration.0); + + Ok(cred::Lox { + P: resp.P, + Q, + id, + bucket: resp.bucket, + trust_level: Scalar::zero(), + level_since: resp.level_since, + invites_remaining: Scalar::zero(), + invites_issued: Scalar::zero(), + P_noopmigration: resp.P_noopmigration, + Q_noopmigration, + }) +}