From a6d98dde735b301b90c06f34b23d06f5f0630a3c Mon Sep 17 00:00:00 2001 From: Ian Goldberg Date: Tue, 4 May 2021 12:02:43 -0400 Subject: [PATCH] The response message of the issue invitation protocol --- crates/lox-library/src/proto/issue_invite.rs | 358 ++++++++++++++++++- crates/lox-library/src/proto/level_up.rs | 5 +- crates/lox-library/src/tests.rs | 1 + 3 files changed, 357 insertions(+), 7 deletions(-) diff --git a/crates/lox-library/src/proto/issue_invite.rs b/crates/lox-library/src/proto/issue_invite.rs index bee4bc9..faee7e4 100644 --- a/crates/lox-library/src/proto/issue_invite.rs +++ b/crates/lox-library/src/proto/issue_invite.rs @@ -56,7 +56,7 @@ use zkp::Transcript; use super::super::cred; use super::super::dup_filter::SeenType; -use super::super::{pt_dbl, scalar_dbl, scalar_u32}; +use super::super::scalar_u32; use super::super::{BridgeAuth, IssuerPubKey}; use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE}; @@ -129,8 +129,15 @@ pub struct Response { TSince: RistrettoPoint, TInvRemain: RistrettoPoint, TBlockages: RistrettoPoint, + + // The fields for the new Invitation credential + P_inv: RistrettoPoint, + EncQ_inv: (RistrettoPoint, RistrettoPoint), inv_id_server: Scalar, - TInvId: RistrettoPoint, + TId_inv: RistrettoPoint, + date_inv: Scalar, + TBucket_inv: RistrettoPoint, + TBlockages_inv: RistrettoPoint, // The ZKP piBlindIssue: CompactProof, @@ -183,6 +190,67 @@ define_proof! { EncInvIdClient1 = (inv_id_client*B + einv_id_client*D) } +define_proof! { + blindissue, + "Issue Invite Issuing", + (x0, x0tilde, xid, xbucket, xlevel, xsince, xinvremain, xblockages, + s, b, tid, tbucket, tlevel, tsince, tinvremain, tblockages, + x0_inv, x0tilde_inv, xid_inv, xdate_inv, xbucket_inv, + xblockages_inv, + s_inv, b_inv, tid_inv, tbucket_inv, tblockages_inv), + (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Xinvremain, + Xblockages, TId, TBucket, TLevel, TSince, TInvRemain, TBlockages, + P_inv, EncQ_inv0, EncQ_inv1, X0_inv, Xid_inv, Xdate_inv, + Xbucket_inv, Xblockages_inv, Pdate_inv, TId_inv, TBucket_inv, + TBlockages_inv, + D, EncId0, EncId1, EncBucket0, EncBucket1, EncLevel0, EncLevel1, + EncSince0, EncSince1, EncInvRemain0, EncInvRemain1, + EncBlockages0, EncBlockages1, + EncInvId0, EncInvId1), + (A, B): + Xid = (xid*A), + Xbucket = (xbucket*A), + Xlevel = (xlevel*A), + Xsince = (xsince*A), + Xinvremain = (xinvremain*A), + Xblockages = (xblockages*A), + X0 = (x0*B + x0tilde*A), + P = (b*B), + TId = (b*Xid), + TId = (tid*A), + TBucket = (b*Xbucket), + TBucket = (tbucket*A), + TLevel = (b*Xlevel), + TLevel = (tlevel*A), + TSince = (b*Xsince), + TSince = (tsince*A), + TInvRemain = (b*Xinvremain), + TInvRemain = (tinvremain*A), + TBlockages = (b*Xblockages), + TBlockages = (tblockages*A), + EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0 + tlevel*EncLevel0 + + tsince*EncSince0 + tinvremain*EncInvRemain0 + tblockages*EncBlockages0), + EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1 + tlevel*EncLevel1 + + tsince*EncSince1 + tinvremain*EncInvRemain1 + tblockages*EncBlockages1 + + x0*P), + Xid_inv = (xid_inv*A), + Xdate_inv = (xdate_inv*A), + Xbucket_inv = (xbucket_inv*A), + Xblockages_inv = (xblockages_inv*A), + X0_inv = (x0_inv*B + x0tilde_inv*A), + P_inv = (b_inv*B), + TId_inv = (b_inv*Xid_inv), + TId_inv = (tid_inv*A), + TBucket_inv = (b_inv*Xbucket_inv), + TBucket_inv = (tbucket_inv*A), + TBlockages_inv = (b_inv*Xblockages_inv), + TBlockages_inv = (tblockages_inv*A), + EncQ_inv0 = (s_inv*B + tid_inv*EncInvId0 + tbucket_inv*EncBucket0 + + tblockages_inv*EncBlockages0), + EncQ_inv1 = (s_inv*D + tid_inv*EncInvId1 + tbucket_inv*EncBucket1 + + tblockages_inv*EncBlockages1 + x0_inv*P_inv + xdate_inv*Pdate_inv) +} + pub fn request( lox_cred: &cred::Lox, reach_cred: &cred::BucketReachability, @@ -231,7 +299,7 @@ pub fn request( let zinvremain = Scalar::random(&mut rng); let zblockages = Scalar::random(&mut rng); let CBucket = lox_cred.bucket * P + &zbucket * Atable; - let CLevel = lox_cred.bucket * P + &zlevel * Atable; + let CLevel = lox_cred.trust_level * P + &zlevel * Atable; let CSince = lox_cred.level_since * P + &zsince * Atable; let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable; let CBlockages = lox_cred.blockages * P + &zblockages * Atable; @@ -320,7 +388,7 @@ pub fn request( let einv_id_client = Scalar::random(&mut rng); let EncInvIdClient = ( &einv_id_client * Btable, - &id_client * Btable + einv_id_client * D, + &inv_id_client * Btable + einv_id_client * D, ); // The proof that invites_remaining is not zero. We prove this by @@ -441,3 +509,285 @@ pub fn request( }, )) } + +impl BridgeAuth { + /// Receive an issue invite request + pub fn handle_issue_invite(&mut self, req: Request) -> Result { + let A: &RistrettoPoint = &CMZ_A; + let B: &RistrettoPoint = &CMZ_B; + let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE; + let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE; + + if req.P.is_identity() || req.P_reach.is_identity() { + return Err(ProofError::VerificationFailure); + } + + let today: Scalar = self.today().into(); + + // Recompute the "error factors" using knowledge of our own + // (the issuer's) private key instead of knowledge of the + // hidden attributes + let Vprime = (self.lox_priv.x[0] + self.lox_priv.x[1] * req.id) * req.P + + self.lox_priv.x[2] * req.CBucket + + self.lox_priv.x[3] * req.CLevel + + self.lox_priv.x[4] * req.CSince + + self.lox_priv.x[5] * req.CInvRemain + + self.lox_priv.x[6] * req.CBlockages + - req.CQ; + + let Vprime_reach = (self.reachability_priv.x[0] + self.reachability_priv.x[1] * today) + * req.P_reach + + self.reachability_priv.x[2] * req.CBucket_reach + - req.CQ_reach; + + // Verify the ZKP + let mut transcript = Transcript::new(b"issue invite request"); + requestproof::verify_compact( + &req.piUser, + &mut transcript, + requestproof::VerifyAssignments { + A: &A.compress(), + B: &B.compress(), + P: &req.P.compress(), + CBucket: &req.CBucket.compress(), + CLevel: &req.CLevel.compress(), + CSince: &req.CSince.compress(), + CInvRemain: &req.CInvRemain.compress(), + CBlockages: &req.CBlockages.compress(), + V: &Vprime.compress(), + Xbucket: &self.lox_pub.X[2].compress(), + Xlevel: &self.lox_pub.X[3].compress(), + Xsince: &self.lox_pub.X[4].compress(), + Xinvremain: &self.lox_pub.X[5].compress(), + Xblockages: &self.lox_pub.X[6].compress(), + P_reach: &req.P_reach.compress(), + CBucket_reach: &req.CBucket_reach.compress(), + V_reach: &Vprime_reach.compress(), + Xbucket_reach: &self.reachability_pub.X[2].compress(), + D: &req.D.compress(), + EncIdClient0: &req.EncIdClient.0.compress(), + EncIdClient1: &req.EncIdClient.1.compress(), + EncBucket0: &req.EncBucket.0.compress(), + EncBucket1: &req.EncBucket.1.compress(), + EncLevel0: &req.EncLevel.0.compress(), + EncLevel1: &req.EncLevel.1.compress(), + EncSince0: &req.EncSince.0.compress(), + EncSince1: &req.EncSince.1.compress(), + EncInvRemain0: &req.EncInvRemain.0.compress(), + EncInvRemain1_plus_B: &(req.EncInvRemain.1 + B).compress(), + EncBlockages0: &req.EncBlockages.0.compress(), + EncBlockages1: &req.EncBlockages.1.compress(), + EncInvIdClient0: &req.EncInvIdClient.0.compress(), + EncInvIdClient1: &req.EncInvIdClient.1.compress(), + }, + )?; + + // Ensure the id has not been seen before, and add it to the + // seen list. + if self.id_filter.filter(&req.id) == SeenType::Seen { + return Err(ProofError::VerificationFailure); + } + + // Blind issuing of the new Lox credential + + // Choose a random server id component to add to the client's + // (blinded) id component + let mut rng = rand::thread_rng(); + let id_server = Scalar::random(&mut rng); + let EncId = (req.EncIdClient.0, req.EncIdClient.1 + &id_server * Btable); + + // Compute the MAC on the visible attributes (none here) + let b = Scalar::random(&mut rng); + let P = &b * Btable; + let QHc = self.lox_priv.x[0] * P; + + // El Gamal encrypt it to the public key req.D + let s = Scalar::random(&mut rng); + let EncQHc = (&s * Btable, QHc + s * req.D); + + // Homomorphically compute the part of the MAC corresponding to + // the blinded attributes + let tid = self.lox_priv.x[1] * b; + let TId = &tid * Atable; + let EncQId = (tid * EncId.0, tid * EncId.1); + let tbucket = self.lox_priv.x[2] * b; + let TBucket = &tbucket * Atable; + let EncQBucket = (tbucket * req.EncBucket.0, tbucket * req.EncBucket.1); + let tlevel = self.lox_priv.x[3] * b; + let TLevel = &tlevel * Atable; + let EncQLevel = (tlevel * req.EncLevel.0, tlevel * req.EncLevel.1); + let tsince = self.lox_priv.x[4] * b; + let TSince = &tsince * Atable; + let EncQSince = (tsince * req.EncSince.0, tsince * req.EncSince.1); + let tinvremain = self.lox_priv.x[5] * b; + let TInvRemain = &tinvremain * Atable; + let EncQInvRemain = ( + tinvremain * req.EncInvRemain.0, + tinvremain * req.EncInvRemain.1, + ); + let tblockages = self.lox_priv.x[6] * b; + let TBlockages = &tblockages * Atable; + let EncQBlockages = ( + tblockages * req.EncBlockages.0, + tblockages * req.EncBlockages.1, + ); + + let EncQ = ( + EncQHc.0 + + EncQId.0 + + EncQBucket.0 + + EncQLevel.0 + + EncQSince.0 + + EncQInvRemain.0 + + EncQBlockages.0, + EncQHc.1 + + EncQId.1 + + EncQBucket.1 + + EncQLevel.1 + + EncQSince.1 + + EncQInvRemain.1 + + EncQBlockages.1, + ); + + // Blind issuing of the new Invitation credential + + // Choose a random server id component to add to the client's + // (blinded) id component + let inv_id_server = Scalar::random(&mut rng); + let EncInvId = ( + req.EncInvIdClient.0, + req.EncInvIdClient.1 + &inv_id_server * Btable, + ); + + // Compute the MAC on the visible attributes + let b_inv = Scalar::random(&mut rng); + let P_inv = &b_inv * Btable; + let QHc_inv = (self.invitation_priv.x[0] + self.invitation_priv.x[2] * today) * P; + + // El Gamal encrypt it to the public key req.D + let s_inv = Scalar::random(&mut rng); + let EncQHc_inv = (&s_inv * Btable, QHc_inv + s_inv * req.D); + + // Homomorphically compute the part of the MAC corresponding to + // the blinded attributes + let tinvid = self.invitation_priv.x[1] * b_inv; + let TId_inv = &tinvid * Atable; + let EncQInvId = (tinvid * EncInvId.0, tinvid * EncInvId.1); + let tinvbucket = self.invitation_priv.x[3] * b_inv; + let TBucket_inv = &tinvbucket * Atable; + // The bucket and blockages encrypted attributes are reused from + // the Lox credential + let EncQInvBucket = (tinvbucket * req.EncBucket.0, tinvbucket * req.EncBucket.1); + let tinvblockages = self.invitation_priv.x[4] * b_inv; + let TBlockages_inv = &tinvblockages * Atable; + let EncQInvBlockages = ( + tinvblockages * req.EncBlockages.0, + tinvblockages * req.EncBlockages.1, + ); + + let EncQ_inv = ( + EncQHc_inv.0 + EncQInvId.0 + EncQInvBucket.0 + EncQInvBlockages.0, + EncQHc_inv.1 + EncQInvId.1 + EncQInvBucket.1 + EncQInvBlockages.1, + ); + + let mut transcript = Transcript::new(b"issue invite issuing"); + let piBlindIssue = blindissue::prove_compact( + &mut transcript, + blindissue::ProveAssignments { + A: &A, + B: &B, + P: &P, + EncQ0: &EncQ.0, + EncQ1: &EncQ.1, + X0: &self.lox_pub.X[0], + Xid: &self.lox_pub.X[1], + Xbucket: &self.lox_pub.X[2], + Xlevel: &self.lox_pub.X[3], + Xsince: &self.lox_pub.X[4], + Xinvremain: &self.lox_pub.X[5], + Xblockages: &self.lox_pub.X[6], + TId: &TId, + TBucket: &TBucket, + TLevel: &TLevel, + TSince: &TSince, + TInvRemain: &TInvRemain, + TBlockages: &TBlockages, + P_inv: &P_inv, + EncQ_inv0: &EncQ_inv.0, + EncQ_inv1: &EncQ_inv.1, + X0_inv: &self.invitation_pub.X[0], + Xid_inv: &self.invitation_pub.X[1], + Xdate_inv: &self.invitation_pub.X[2], + Xbucket_inv: &self.invitation_pub.X[3], + Xblockages_inv: &self.invitation_pub.X[4], + Pdate_inv: &(today * P_inv), + TId_inv: &TId_inv, + TBucket_inv: &TBucket_inv, + TBlockages_inv: &TBlockages_inv, + D: &req.D, + EncId0: &EncId.0, + EncId1: &EncId.1, + EncBucket0: &req.EncBucket.0, + EncBucket1: &req.EncBucket.1, + EncLevel0: &req.EncLevel.0, + EncLevel1: &req.EncLevel.1, + EncSince0: &req.EncSince.0, + EncSince1: &req.EncSince.1, + EncInvRemain0: &req.EncInvRemain.0, + EncInvRemain1: &req.EncInvRemain.1, + EncBlockages0: &req.EncBlockages.0, + EncBlockages1: &req.EncBlockages.1, + EncInvId0: &EncInvId.0, + EncInvId1: &EncInvId.1, + x0: &self.lox_priv.x[0], + x0tilde: &self.lox_priv.x0tilde, + xid: &self.lox_priv.x[1], + xbucket: &self.lox_priv.x[2], + xlevel: &self.lox_priv.x[3], + xsince: &self.lox_priv.x[4], + xinvremain: &self.lox_priv.x[5], + xblockages: &self.lox_priv.x[6], + s: &s, + b: &b, + tid: &tid, + tbucket: &tbucket, + tlevel: &tlevel, + tsince: &tsince, + tinvremain: &tinvremain, + tblockages: &tblockages, + x0_inv: &self.invitation_priv.x[0], + x0tilde_inv: &self.invitation_priv.x0tilde, + xid_inv: &self.invitation_priv.x[1], + xdate_inv: &self.invitation_priv.x[2], + xbucket_inv: &self.invitation_priv.x[3], + xblockages_inv: &self.invitation_priv.x[4], + s_inv: &s_inv, + b_inv: &b_inv, + tid_inv: &tinvid, + tbucket_inv: &tinvbucket, + tblockages_inv: &tinvblockages, + }, + ) + .0; + + Ok(Response { + P, + EncQ, + id_server, + TId, + TBucket, + TLevel, + TSince, + TInvRemain, + TBlockages, + P_inv, + EncQ_inv, + inv_id_server, + TId_inv, + date_inv: today, + TBucket_inv, + TBlockages_inv, + piBlindIssue, + }) + } +} diff --git a/crates/lox-library/src/proto/level_up.rs b/crates/lox-library/src/proto/level_up.rs index 7a1c1bf..ee64b80 100644 --- a/crates/lox-library/src/proto/level_up.rs +++ b/crates/lox-library/src/proto/level_up.rs @@ -243,9 +243,8 @@ define_proof! { D, EncId0, EncId1, EncBucket0, EncBucket1, EncBlockages0, EncBlockages1), (A, B): Xid = (xid*A), - Xid = (xid*A), - Xlevel = (xlevel*A), Xbucket = (xbucket*A), + Xlevel = (xlevel*A), Xsince = (xsince*A), Xinvremain = (xinvremain*A), Xblockages = (xblockages*A), @@ -700,7 +699,7 @@ impl BridgeAuth { let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE; let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE; - if req.P.is_identity() { + if req.P.is_identity() || req.P_reach.is_identity() { return Err(ProofError::VerificationFailure); } diff --git a/crates/lox-library/src/tests.rs b/crates/lox-library/src/tests.rs index 38d23cc..6bd1b79 100644 --- a/crates/lox-library/src/tests.rs +++ b/crates/lox-library/src/tests.rs @@ -231,4 +231,5 @@ fn test_issue_inv() { ba.today(), ) .unwrap(); + let resp = ba.handle_issue_invite(req).unwrap(); }