|
@@ -282,7 +282,7 @@ pub fn request(
|
|
|
return Err(ProofError::VerificationFailure);
|
|
|
}
|
|
|
// The new invites_remaining
|
|
|
- let new_invites_remaining = &lox_cred.invites_remaining - Scalar::one();
|
|
|
+ let new_invites_remaining = lox_cred.invites_remaining - Scalar::one();
|
|
|
|
|
|
// Blind showing the Lox credential
|
|
|
|
|
@@ -662,7 +662,7 @@ impl BridgeAuth {
|
|
|
// 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;
|
|
|
+ let QHc_inv = (self.invitation_priv.x[0] + self.invitation_priv.x[2] * today) * P_inv;
|
|
|
|
|
|
// El Gamal encrypt it to the public key req.D
|
|
|
let s_inv = Scalar::random(&mut rng);
|
|
@@ -791,3 +791,114 @@ impl BridgeAuth {
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/// Handle the response to the request, producing the new Lox credential
|
|
|
+/// and Invitation credential if successful.
|
|
|
+pub fn handle_response(
|
|
|
+ state: State,
|
|
|
+ resp: Response,
|
|
|
+ lox_pub: &IssuerPubKey,
|
|
|
+ invitation_pub: &IssuerPubKey,
|
|
|
+) -> Result<(cred::Lox, cred::Invitation), ProofError> {
|
|
|
+ let A: &RistrettoPoint = &CMZ_A;
|
|
|
+ let B: &RistrettoPoint = &CMZ_B;
|
|
|
+ let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
|
|
|
+
|
|
|
+ if resp.P.is_identity() || resp.P_inv.is_identity() {
|
|
|
+ return Err(ProofError::VerificationFailure);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add the server's contribution to the id to our own, both in plain
|
|
|
+ // and encrypted form and for both the Lox credential id and the
|
|
|
+ // Invitation credential id
|
|
|
+ let id = state.id_client + resp.id_server;
|
|
|
+ let EncId = (
|
|
|
+ state.EncIdClient.0,
|
|
|
+ state.EncIdClient.1 + &resp.id_server * Btable,
|
|
|
+ );
|
|
|
+
|
|
|
+ let inv_id = state.inv_id_client + resp.inv_id_server;
|
|
|
+ let EncInvId = (
|
|
|
+ state.EncInvIdClient.0,
|
|
|
+ state.EncInvIdClient.1 + &resp.inv_id_server * Btable,
|
|
|
+ );
|
|
|
+
|
|
|
+ // Verify the proof
|
|
|
+ let mut transcript = Transcript::new(b"issue 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(),
|
|
|
+ Xlevel: &lox_pub.X[3].compress(),
|
|
|
+ Xsince: &lox_pub.X[4].compress(),
|
|
|
+ Xinvremain: &lox_pub.X[5].compress(),
|
|
|
+ Xblockages: &lox_pub.X[6].compress(),
|
|
|
+ TId: &resp.TId.compress(),
|
|
|
+ TBucket: &resp.TBucket.compress(),
|
|
|
+ TLevel: &resp.TLevel.compress(),
|
|
|
+ TSince: &resp.TSince.compress(),
|
|
|
+ TInvRemain: &resp.TInvRemain.compress(),
|
|
|
+ TBlockages: &resp.TBlockages.compress(),
|
|
|
+ P_inv: &resp.P_inv.compress(),
|
|
|
+ EncQ_inv0: &resp.EncQ_inv.0.compress(),
|
|
|
+ EncQ_inv1: &resp.EncQ_inv.1.compress(),
|
|
|
+ X0_inv: &invitation_pub.X[0].compress(),
|
|
|
+ Xid_inv: &invitation_pub.X[1].compress(),
|
|
|
+ Xdate_inv: &invitation_pub.X[2].compress(),
|
|
|
+ Xbucket_inv: &invitation_pub.X[3].compress(),
|
|
|
+ Xblockages_inv: &invitation_pub.X[4].compress(),
|
|
|
+ Pdate_inv: &(resp.date_inv * resp.P_inv).compress(),
|
|
|
+ TId_inv: &resp.TId_inv.compress(),
|
|
|
+ TBucket_inv: &resp.TBucket_inv.compress(),
|
|
|
+ TBlockages_inv: &resp.TBlockages_inv.compress(),
|
|
|
+ D: &state.D.compress(),
|
|
|
+ EncId0: &EncId.0.compress(),
|
|
|
+ EncId1: &EncId.1.compress(),
|
|
|
+ EncBucket0: &state.EncBucket.0.compress(),
|
|
|
+ EncBucket1: &state.EncBucket.1.compress(),
|
|
|
+ EncLevel0: &state.EncLevel.0.compress(),
|
|
|
+ EncLevel1: &state.EncLevel.1.compress(),
|
|
|
+ EncSince0: &state.EncSince.0.compress(),
|
|
|
+ EncSince1: &state.EncSince.1.compress(),
|
|
|
+ EncInvRemain0: &state.EncInvRemain.0.compress(),
|
|
|
+ EncInvRemain1: &state.EncInvRemain.1.compress(),
|
|
|
+ EncBlockages0: &state.EncBlockages.0.compress(),
|
|
|
+ EncBlockages1: &state.EncBlockages.1.compress(),
|
|
|
+ EncInvId0: &EncInvId.0.compress(),
|
|
|
+ EncInvId1: &EncInvId.1.compress(),
|
|
|
+ },
|
|
|
+ )?;
|
|
|
+
|
|
|
+ // Decrypt EncQ and EncQ_inv
|
|
|
+ let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
|
|
|
+ let Q_inv = resp.EncQ_inv.1 - (state.d * resp.EncQ_inv.0);
|
|
|
+
|
|
|
+ Ok((
|
|
|
+ cred::Lox {
|
|
|
+ P: resp.P,
|
|
|
+ Q,
|
|
|
+ id,
|
|
|
+ bucket: state.bucket,
|
|
|
+ trust_level: state.level,
|
|
|
+ level_since: state.since,
|
|
|
+ invites_remaining: state.invremain,
|
|
|
+ blockages: state.blockages,
|
|
|
+ },
|
|
|
+ cred::Invitation {
|
|
|
+ P: resp.P_inv,
|
|
|
+ Q: Q_inv,
|
|
|
+ inv_id,
|
|
|
+ date: resp.date_inv,
|
|
|
+ bucket: state.bucket,
|
|
|
+ blockages: state.blockages,
|
|
|
+ },
|
|
|
+ ))
|
|
|
+}
|