The complete blockage migration protocol

This commit is contained in:
Ian Goldberg 2021-05-05 18:21:09 -04:00
parent 4bb77d16e4
commit 596cf10ea5
4 changed files with 703 additions and 7 deletions

View File

@ -536,6 +536,7 @@ pub fn pt_dbl(P: &RistrettoPoint) -> RistrettoPoint {
/// Response. It also adds a handle_* function to the BridgeAuth struct /// Response. It also adds a handle_* function to the BridgeAuth struct
/// that consumes a Request and produces a Result<Response, ProofError>. /// that consumes a Request and produces a Result<Response, ProofError>.
pub mod proto { pub mod proto {
pub mod blockage_migration;
pub mod check_blockage; pub mod check_blockage;
pub mod issue_invite; pub mod issue_invite;
pub mod level_up; pub mod level_up;

View File

@ -0,0 +1,682 @@
/*! A module for the protocol for the user of trust level 3 or higher to
migrate from one bucket to another because their current bucket has been
blocked. Their trust level will go down by 2.
The user presents their current Lox credential:
- id: revealed
- bucket: blinded
- trust_level: revealed to be 3 or higher
- level_since: blinded
- invites_remaining: blinded
- blockages: blinded
and a Migration credential:
- id: revealed as the same as the Lox credential id above
- from_bucket: blinded, but proved in ZK that it's the same as the
bucket in the Lox credential above
- to_bucket: blinded
and a new Lox credential to be issued:
- id: jointly chosen by the user and BA
- bucket: blinded, but proved in ZK that it's the same as the to_bucket
in the Migration credential above
- trust_level: revealed to be 2 less than the trust_level above
- level_since: today
- invites_remaining: revealed to be LEVEL_INVITATIONS for the new trust
level [Actually, there's a bug in the zkp crate that's triggered when
a public value is 0 (the identity element of the Ristretto group), so
we treat this field as blinded, but the _server_ encrypts the value.]
- blockages: blinded, but proved in ZK that it's one more than the
blockages above
*/
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::super::cred;
use super::super::dup_filter::SeenType;
use super::super::migration_table::MigrationType;
use super::super::scalar_u32;
use super::super::{BridgeAuth, IssuerPubKey};
use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
use super::check_blockage::MIN_TRUST_LEVEL;
use super::level_up::LEVEL_INVITATIONS;
pub struct Request {
// Fields for blind showing the Lox credential
P_lox: RistrettoPoint,
id: Scalar,
CBucket: RistrettoPoint,
trust_level: Scalar,
CSince: RistrettoPoint,
CInvRemain: RistrettoPoint,
CBlockages: RistrettoPoint,
CQ_lox: RistrettoPoint,
// Fields for blind showing the Migration credential
P_mig: RistrettoPoint,
CFromBucket: RistrettoPoint,
CToBucket: RistrettoPoint,
CQ_mig: RistrettoPoint,
// Fields for user blinding of the Lox credential to be issued
D: RistrettoPoint,
EncIdClient: (RistrettoPoint, RistrettoPoint),
EncBucket: (RistrettoPoint, RistrettoPoint),
EncBlockages: (RistrettoPoint, RistrettoPoint),
// The combined ZKP
piUser: CompactProof,
}
#[derive(Debug)]
pub struct State {
d: Scalar,
D: RistrettoPoint,
EncIdClient: (RistrettoPoint, RistrettoPoint),
EncBucket: (RistrettoPoint, RistrettoPoint),
EncBlockages: (RistrettoPoint, RistrettoPoint),
id_client: Scalar,
to_bucket: Scalar,
trust_level: Scalar,
blockages: Scalar,
}
pub struct Response {
// The new attributes; the trust_level and invites_remaining are
// implicit
level_since: Scalar,
// The fields for the new Lox credential
P: RistrettoPoint,
EncQ: (RistrettoPoint, RistrettoPoint),
EncInvRemain: (RistrettoPoint, RistrettoPoint),
id_server: Scalar,
TId: RistrettoPoint,
TBucket: RistrettoPoint,
TInvRemain: RistrettoPoint,
TBlockages: RistrettoPoint,
// The ZKP
piBlindIssue: CompactProof,
}
define_proof! {
requestproof,
"Blockage Migration Request",
(bucket, since, invremain, blockages, zbucket, zsince, zinvremain,
zblockages, negzQ_lox,
tobucket, zfrombucket, ztobucket, negzQ_mig,
d, eid_client, ebucket, eblockages, id_client),
(P_lox, CBucket, CSince, CInvRemain, CBlockages, V_lox, Xbucket,
Xsince, Xinvremain, Xblockages,
P_mig, CFromBucket, CToBucket, V_mig, Xfrombucket, Xtobucket,
D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
EncBlockages0, EncBlockages1_minus_B),
(A, B):
// Blind showing of the Lox credential
CBucket = (bucket*P_lox + zbucket*A),
CSince = (since*P_lox + zsince*A),
CInvRemain = (invremain*P_lox + zinvremain*A),
CBlockages = (blockages*P_lox + zblockages*A),
V_lox = (zbucket*Xbucket + zsince*Xsince + zinvremain*Xinvremain
+ zblockages*Xblockages + negzQ_lox*A),
// Blind showing of the Migration credential; note the use of the
// same "bucket" secret variable
CFromBucket = (bucket*P_mig + zfrombucket*A),
CToBucket = (tobucket*P_mig + ztobucket*A),
V_mig = (zfrombucket*Xfrombucket + ztobucket*Xtobucket + negzQ_mig*A),
// User blinding of the Lox credential to be issued; note the use of
// the same "tobucket" secret variable
D = (d*B),
EncIdClient0 = (eid_client*B),
EncIdClient1 = (id_client*B + eid_client*D),
EncBucket0 = (ebucket*B),
EncBucket1 = (tobucket*B + ebucket*D),
EncBlockages0 = (eblockages*B),
EncBlockages1_minus_B = (blockages*B + eblockages*D)
}
define_proof! {
blindissue,
"Blockage Migration Blind Issuing",
(x0, x0tilde, xid, xbucket, xlevel, xsince, xinvremain, xblockages,
s, b, tid, tbucket, tinvremain, tblockages),
(P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Xinvremain,
Xblockages, Plevel, Psince, TId, TBucket, TInvRemain, TBlockages,
D, EncId0, EncId1, EncBucket0, EncBucket1, EncInvRemain0,
EncInvRemain1, EncBlockages0, EncBlockages1),
(A, B):
Xid = (xid*A),
Xlevel = (xlevel*A),
Xbucket = (xbucket*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),
TInvRemain = (b*Xinvremain),
TInvRemain = (tinvremain*A),
TBlockages = (b*Xblockages),
TBlockages = (tblockages*A),
EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0
+ tinvremain*EncInvRemain0 + tblockages*EncBlockages0),
EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1
+ tinvremain*EncInvRemain1 + tblockages*EncBlockages1
+ x0*P + xlevel*Plevel + xsince*Psince)
}
pub fn request(
lox_cred: &cred::Lox,
migration_cred: &cred::Migration,
lox_pub: &IssuerPubKey,
migration_pub: &IssuerPubKey,
) -> Result<(Request, State), ProofError> {
let A: &RistrettoPoint = &CMZ_A;
let B: &RistrettoPoint = &CMZ_B;
let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
// Ensure that the credenials can be correctly shown; that is, the
// ids match and the Lox credential bucket matches the Migration
// credential from_bucket
if lox_cred.id != migration_cred.lox_id || lox_cred.bucket != migration_cred.from_bucket {
return Err(ProofError::VerificationFailure);
}
// The trust level must be at least MIN_TRUST_LEVEL
let level: u32 = match scalar_u32(&lox_cred.trust_level) {
Some(v) => v,
None => return Err(ProofError::VerificationFailure),
};
if level < MIN_TRUST_LEVEL {
return Err(ProofError::VerificationFailure);
}
// Blind showing the Lox credential
// Reblind P and Q
let mut rng = rand::thread_rng();
let t_lox = Scalar::random(&mut rng);
let P_lox = t_lox * lox_cred.P;
let Q_lox = t_lox * lox_cred.Q;
// Form Pedersen commitments to the blinded attributes
let zbucket = Scalar::random(&mut rng);
let zsince = Scalar::random(&mut rng);
let zinvremain = Scalar::random(&mut rng);
let zblockages = Scalar::random(&mut rng);
let CBucket = lox_cred.bucket * P_lox + &zbucket * Atable;
let CSince = lox_cred.level_since * P_lox + &zsince * Atable;
let CInvRemain = lox_cred.invites_remaining * P_lox + &zinvremain * Atable;
let CBlockages = lox_cred.blockages * P_lox + &zblockages * Atable;
// Form a Pedersen commitment to the MAC Q
// We flip the sign of zQ from that of the Hyphae paper so that
// the ZKP has a "+" instead of a "-", as that's what the zkp
// macro supports.
let negzQ_lox = Scalar::random(&mut rng);
let CQ_lox = Q_lox - &negzQ_lox * Atable;
// Compute the "error factor"
let V_lox = zbucket * lox_pub.X[2]
+ zsince * lox_pub.X[4]
+ zinvremain * lox_pub.X[5]
+ zblockages * lox_pub.X[6]
+ &negzQ_lox * Atable;
// Blind showing the Migration credential
// Reblind P and Q
let t_mig = Scalar::random(&mut rng);
let P_mig = t_mig * migration_cred.P;
let Q_mig = t_mig * migration_cred.Q;
// Form Pedersen commitments to the blinded attributes
let zfrombucket = Scalar::random(&mut rng);
let ztobucket = Scalar::random(&mut rng);
let CFromBucket = migration_cred.from_bucket * P_mig + &zfrombucket * Atable;
let CToBucket = migration_cred.to_bucket * P_mig + &ztobucket * Atable;
// Form a Pedersen commitment to the MAC Q
// We flip the sign of zQ from that of the Hyphae paper so that
// the ZKP has a "+" instead of a "-", as that's what the zkp
// macro supports.
let negzQ_mig = Scalar::random(&mut rng);
let CQ_mig = Q_mig - &negzQ_mig * Atable;
// Compute the "error factor"
let V_mig =
zfrombucket * migration_pub.X[2] + ztobucket * migration_pub.X[3] + &negzQ_mig * Atable;
// User blinding for the Lox certificate to be issued
// Pick an ElGamal keypair
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);
// Encrypt the other blinded attributes (times B) to D as well
let ebucket = Scalar::random(&mut rng);
let EncBucket = (
&ebucket * Btable,
&migration_cred.to_bucket * Btable + ebucket * D,
);
let eblockages = Scalar::random(&mut rng);
let new_blockages = lox_cred.blockages + Scalar::one();
let EncBlockages = (
&eblockages * Btable,
&new_blockages * Btable + eblockages * D,
);
// Construct the proof
let mut transcript = Transcript::new(b"blockage migration request");
let piUser = requestproof::prove_compact(
&mut transcript,
requestproof::ProveAssignments {
A: &A,
B: &B,
P_lox: &P_lox,
CBucket: &CBucket,
CSince: &CSince,
CInvRemain: &CInvRemain,
CBlockages: &CBlockages,
V_lox: &V_lox,
Xbucket: &lox_pub.X[2],
Xsince: &lox_pub.X[4],
Xinvremain: &lox_pub.X[5],
Xblockages: &lox_pub.X[6],
P_mig: &P_mig,
CFromBucket: &CFromBucket,
CToBucket: &CToBucket,
V_mig: &V_mig,
Xfrombucket: &migration_pub.X[2],
Xtobucket: &migration_pub.X[3],
D: &D,
EncIdClient0: &EncIdClient.0,
EncIdClient1: &EncIdClient.1,
EncBucket0: &EncBucket.0,
EncBucket1: &EncBucket.1,
EncBlockages0: &EncBlockages.0,
EncBlockages1_minus_B: &(EncBlockages.1 - B),
bucket: &lox_cred.bucket,
since: &lox_cred.level_since,
invremain: &lox_cred.invites_remaining,
blockages: &lox_cred.blockages,
zbucket: &zbucket,
zsince: &zsince,
zinvremain: &zinvremain,
zblockages: &zblockages,
negzQ_lox: &negzQ_lox,
tobucket: &migration_cred.to_bucket,
zfrombucket: &zfrombucket,
ztobucket: &ztobucket,
negzQ_mig: &negzQ_mig,
d: &d,
eid_client: &eid_client,
ebucket: &ebucket,
eblockages: &eblockages,
id_client: &id_client,
},
)
.0;
Ok((
Request {
P_lox,
id: lox_cred.id,
CBucket,
trust_level: lox_cred.trust_level,
CSince,
CInvRemain,
CBlockages,
CQ_lox,
P_mig,
CFromBucket,
CToBucket,
CQ_mig,
D,
EncIdClient,
EncBucket,
EncBlockages,
piUser,
},
State {
d,
D,
EncIdClient,
EncBucket,
EncBlockages,
id_client,
to_bucket: migration_cred.to_bucket,
trust_level: (level - 2).into(),
blockages: new_blockages,
},
))
}
impl BridgeAuth {
/// Receive a blockage migration request
pub fn handle_blockage_migration(&mut self, req: Request) -> Result<Response, ProofError> {
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_lox.is_identity() || req.P_mig.is_identity() {
return Err(ProofError::VerificationFailure);
}
// The trust level must be at least MIN_TRUST_LEVEL
let level: u32 = match scalar_u32(&req.trust_level) {
Some(v) => v,
None => return Err(ProofError::VerificationFailure),
};
if level < MIN_TRUST_LEVEL {
return Err(ProofError::VerificationFailure);
}
// Recompute the "error factors" using knowledge of our own
// (the issuer's) private key instead of knowledge of the
// hidden attributes
let Vprime_lox = (self.lox_priv.x[0]
+ self.lox_priv.x[1] * req.id
+ self.lox_priv.x[3] * req.trust_level)
* req.P_lox
+ self.lox_priv.x[2] * req.CBucket
+ self.lox_priv.x[4] * req.CSince
+ self.lox_priv.x[5] * req.CInvRemain
+ self.lox_priv.x[6] * req.CBlockages
- req.CQ_lox;
let migration_type: Scalar = MigrationType::Blockage.into();
let Vprime_mig = (self.migration_priv.x[0]
+ self.migration_priv.x[1] * req.id
+ self.migration_priv.x[4] * migration_type)
* req.P_mig
+ self.migration_priv.x[2] * req.CFromBucket
+ self.migration_priv.x[3] * req.CToBucket
- req.CQ_mig;
// Verify the ZKP
let mut transcript = Transcript::new(b"blockage migration request");
requestproof::verify_compact(
&req.piUser,
&mut transcript,
requestproof::VerifyAssignments {
A: &A.compress(),
B: &B.compress(),
P_lox: &req.P_lox.compress(),
CBucket: &req.CBucket.compress(),
CSince: &req.CSince.compress(),
CInvRemain: &req.CInvRemain.compress(),
CBlockages: &req.CBlockages.compress(),
V_lox: &Vprime_lox.compress(),
Xbucket: &self.lox_pub.X[2].compress(),
Xsince: &self.lox_pub.X[4].compress(),
Xinvremain: &self.lox_pub.X[5].compress(),
Xblockages: &self.lox_pub.X[6].compress(),
P_mig: &req.P_mig.compress(),
CFromBucket: &req.CFromBucket.compress(),
CToBucket: &req.CToBucket.compress(),
V_mig: &Vprime_mig.compress(),
Xfrombucket: &self.migration_pub.X[2].compress(),
Xtobucket: &self.migration_pub.X[3].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(),
EncBlockages0: &req.EncBlockages.0.compress(),
EncBlockages1_minus_B: &(req.EncBlockages.1 - B).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);
// Create the trust_level attrubute (Scalar), which will be
// 2 levels down from the one in the provided credential
let trust_level: Scalar = (level - 2).into();
// Create the level_since attribute (Scalar), which is today's
// Julian date
let level_since: Scalar = self.today().into();
// The invites remaining is the appropriate number for the new
// level (note that LEVEL_INVITATIONS[i] is the number of
// invitations for moving from level i to level i+1)
let invremain: Scalar = LEVEL_INVITATIONS[(level - 3) as usize].into();
// Because of the bug in the zkp crate, encrypt the invites
// remaining instead of sending it in the clear
let sinvremain = Scalar::random(&mut rng);
let EncInvRemain = (
&sinvremain * Btable,
&invremain * Btable + sinvremain * req.D,
);
// Compute the MAC on the visible attributes
let b = Scalar::random(&mut rng);
let P = &b * Btable;
let QHc = (self.lox_priv.x[0]
+ self.lox_priv.x[3] * trust_level
+ self.lox_priv.x[4] * level_since)
* 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 tinvremain = self.lox_priv.x[5] * b;
let TInvRemain = &tinvremain * Atable;
let EncQInvRemain = (tinvremain * EncInvRemain.0, tinvremain * 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 + EncQInvRemain.0 + EncQBlockages.0,
EncQHc.1 + EncQId.1 + EncQBucket.1 + EncQInvRemain.1 + EncQBlockages.1,
);
let mut transcript = Transcript::new(b"blockage migration 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],
Plevel: &(trust_level * P),
Psince: &(level_since * P),
TId: &TId,
TBucket: &TBucket,
TInvRemain: &TInvRemain,
TBlockages: &TBlockages,
D: &req.D,
EncId0: &EncId.0,
EncId1: &EncId.1,
EncBucket0: &req.EncBucket.0,
EncBucket1: &req.EncBucket.1,
EncInvRemain0: &EncInvRemain.0,
EncInvRemain1: &EncInvRemain.1,
EncBlockages0: &req.EncBlockages.0,
EncBlockages1: &req.EncBlockages.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,
tinvremain: &tinvremain,
tblockages: &tblockages,
},
)
.0;
Ok(Response {
level_since,
P,
EncQ,
EncInvRemain,
id_server,
TId,
TBucket,
TInvRemain,
TBlockages,
piBlindIssue,
})
}
}
/// Handle the response to the request, producing the new Lox credential
/// if successful.
pub fn handle_response(
state: State,
resp: Response,
lox_pub: &IssuerPubKey,
) -> Result<cred::Lox, ProofError> {
let A: &RistrettoPoint = &CMZ_A;
let B: &RistrettoPoint = &CMZ_B;
let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
if resp.P.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,
);
let new_level: u32 = match scalar_u32(&state.trust_level) {
Some(v) => v,
None => return Err(ProofError::VerificationFailure),
};
if new_level < 1 {
return Err(ProofError::VerificationFailure);
}
// The invites remaining is the appropriate number for the new level
// (note that LEVEL_INVITATIONS[i] is the number of invitations for
// moving from level i to level i+1)
let invremain: Scalar = LEVEL_INVITATIONS[(new_level - 1) as usize].into();
// Decrypt EncInvRemain
let recv_invremain = resp.EncInvRemain.1 - (state.d * resp.EncInvRemain.0);
if recv_invremain != &invremain * Btable {
return Err(ProofError::VerificationFailure);
}
// Verify the proof
let mut transcript = Transcript::new(b"blockage migration 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(),
Plevel: &(state.trust_level * resp.P).compress(),
Psince: &(resp.level_since * resp.P).compress(),
TId: &resp.TId.compress(),
TBucket: &resp.TBucket.compress(),
TInvRemain: &resp.TInvRemain.compress(),
TBlockages: &resp.TBlockages.compress(),
D: &state.D.compress(),
EncId0: &EncId.0.compress(),
EncId1: &EncId.1.compress(),
EncBucket0: &state.EncBucket.0.compress(),
EncBucket1: &state.EncBucket.1.compress(),
EncInvRemain0: &resp.EncInvRemain.0.compress(),
EncInvRemain1: &resp.EncInvRemain.1.compress(),
EncBlockages0: &state.EncBlockages.0.compress(),
EncBlockages1: &state.EncBlockages.1.compress(),
},
)?;
// Decrypt EncQ
let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
Ok(cred::Lox {
P: resp.P,
Q,
id,
bucket: state.to_bucket,
trust_level: new_level.into(),
level_since: resp.level_since,
invites_remaining: invremain,
blockages: state.blockages,
})
}

View File

@ -1,9 +1,8 @@
/*! A module for the protocol for the user to migrate from one bucket to /*! A module for the protocol for the user to migrate from one bucket to
another (and possibly also change trust level). another and change trust level from untrusted (trust level 0) to trusted
(trust level 1).
For the case of migrating from trust level 0 (a one-bridge bucket) to The user presents their current Lox credential:
trust level 1 (a three-bridge bucket), the user presents their current
Lox credential:
- id: revealed - id: revealed
- bucket: blinded - bucket: blinded
@ -163,8 +162,8 @@ pub fn request(
return Err(ProofError::VerificationFailure); return Err(ProofError::VerificationFailure);
} }
// We only support migrating from trust level 0 to trust level 1 // This protocol only allows migrating from trust level 0 to trust
// right now // level 1
if lox_cred.trust_level != Scalar::zero() { if lox_cred.trust_level != Scalar::zero() {
return Err(ProofError::VerificationFailure); return Err(ProofError::VerificationFailure);
} }

View File

@ -126,6 +126,14 @@ impl TestHarness {
let resp = self.ba.handle_check_blockage(req).unwrap(); let resp = self.ba.handle_check_blockage(req).unwrap();
check_blockage::handle_response(state, resp).unwrap() check_blockage::handle_response(state, resp).unwrap()
} }
fn blockage_migration(&mut self, cred: &cred::Lox, mig: &cred::Migration) -> cred::Lox {
let (req, state) =
blockage_migration::request(&cred, &mig, &self.ba.lox_pub, &self.ba.migration_pub)
.unwrap();
let resp = self.ba.handle_blockage_migration(req).unwrap();
blockage_migration::handle_response(state, resp, &self.ba.lox_pub).unwrap()
}
} }
#[test] #[test]
@ -358,7 +366,7 @@ fn test_mark_unreachable() {
} }
#[test] #[test]
fn test_check_blockage() { fn test_blockage_migration() {
let mut th = TestHarness::new(); let mut th = TestHarness::new();
// Join an untrusted user // Join an untrusted user
@ -420,4 +428,10 @@ fn test_check_blockage() {
let migration = th.check_blockage(&cred3); let migration = th.check_blockage(&cred3);
println!("migration = {:?}", migration); println!("migration = {:?}", migration);
// Migrate
let cred4 = th.blockage_migration(&cred3, &migration);
println!("cred4 = {:?}", cred4);
assert!(th.ba.verify_lox(&cred4));
} }