From 596cf10ea58b9adbfa181e77b7f1d5a9b8c26ea3 Mon Sep 17 00:00:00 2001 From: Ian Goldberg Date: Wed, 5 May 2021 18:21:09 -0400 Subject: [PATCH] The complete blockage migration protocol --- crates/lox-library/src/lib.rs | 1 + .../src/proto/blockage_migration.rs | 682 ++++++++++++++++++ crates/lox-library/src/proto/migration.rs | 11 +- crates/lox-library/src/tests.rs | 16 +- 4 files changed, 703 insertions(+), 7 deletions(-) create mode 100644 crates/lox-library/src/proto/blockage_migration.rs diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index ee6d182..253313a 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -536,6 +536,7 @@ pub fn pt_dbl(P: &RistrettoPoint) -> RistrettoPoint { /// Response. It also adds a handle_* function to the BridgeAuth struct /// that consumes a Request and produces a Result. pub mod proto { + pub mod blockage_migration; pub mod check_blockage; pub mod issue_invite; pub mod level_up; diff --git a/crates/lox-library/src/proto/blockage_migration.rs b/crates/lox-library/src/proto/blockage_migration.rs new file mode 100644 index 0000000..694ad4e --- /dev/null +++ b/crates/lox-library/src/proto/blockage_migration.rs @@ -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 { + 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 { + 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, + }) +} diff --git a/crates/lox-library/src/proto/migration.rs b/crates/lox-library/src/proto/migration.rs index 8af5672..27cb622 100644 --- a/crates/lox-library/src/proto/migration.rs +++ b/crates/lox-library/src/proto/migration.rs @@ -1,9 +1,8 @@ /*! 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 -trust level 1 (a three-bridge bucket), the user presents their current -Lox credential: +The user presents their current Lox credential: - id: revealed - bucket: blinded @@ -163,8 +162,8 @@ pub fn request( return Err(ProofError::VerificationFailure); } - // We only support migrating from trust level 0 to trust level 1 - // right now + // This protocol only allows migrating from trust level 0 to trust + // level 1 if lox_cred.trust_level != Scalar::zero() { return Err(ProofError::VerificationFailure); } diff --git a/crates/lox-library/src/tests.rs b/crates/lox-library/src/tests.rs index 00e1987..af7ddcd 100644 --- a/crates/lox-library/src/tests.rs +++ b/crates/lox-library/src/tests.rs @@ -126,6 +126,14 @@ impl TestHarness { let resp = self.ba.handle_check_blockage(req).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] @@ -358,7 +366,7 @@ fn test_mark_unreachable() { } #[test] -fn test_check_blockage() { +fn test_blockage_migration() { let mut th = TestHarness::new(); // Join an untrusted user @@ -420,4 +428,10 @@ fn test_check_blockage() { let migration = th.check_blockage(&cred3); println!("migration = {:?}", migration); + + // Migrate + let cred4 = th.blockage_migration(&cred3, &migration); + + println!("cred4 = {:?}", cred4); + assert!(th.ba.verify_lox(&cred4)); }