diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 934a159..ae2fcd7 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -21,7 +21,6 @@ pub mod bridge_table; pub mod cred; pub mod dup_filter; pub mod migration_table; -pub mod trust_promotion; use sha2::Sha512; @@ -33,6 +32,8 @@ use curve25519_dalek::constants as dalek_constants; use curve25519_dalek::ristretto::RistrettoBasepointTable; use curve25519_dalek::ristretto::RistrettoPoint; use curve25519_dalek::scalar::Scalar; +#[cfg(test)] +use curve25519_dalek::traits::IsIdentity; use ed25519_dalek::{Keypair, PublicKey, Signature, SignatureError, Signer, Verifier}; use subtle::ConstantTimeEq; @@ -257,8 +258,12 @@ impl BridgeAuth { } #[cfg(test)] - /// Verify the MAC on a Lox credential + /// Verify the two MACs on a Lox credential pub fn verify_lox(&self, cred: &cred::Lox) -> bool { + if cred.P.is_identity() || cred.P_noopmigration.is_identity() { + return false; + } + let Q = (self.lox_priv.x[0] + cred.id * self.lox_priv.x[1] + cred.bucket * self.lox_priv.x[2] @@ -267,12 +272,23 @@ impl BridgeAuth { + cred.invites_remaining * self.lox_priv.x[5] + cred.invites_issued * self.lox_priv.x[6]) * cred.P; - return Q == cred.Q; + + let Q_noopmigration = (self.migration_priv.x[0] + + cred.id * self.migration_priv.x[1] + + cred.bucket * self.migration_priv.x[2] + + cred.bucket * self.migration_priv.x[3]) + * cred.P_noopmigration; + + return Q == cred.Q && Q_noopmigration == cred.Q_noopmigration; } #[cfg(test)] /// Verify the MAC on a Migration credential pub fn verify_migration(&self, cred: &cred::Migration) -> bool { + if cred.P.is_identity() { + return false; + } + let Q = (self.migration_priv.x[0] + cred.lox_id * self.migration_priv.x[1] + cred.from_bucket * self.migration_priv.x[2] @@ -303,7 +319,9 @@ pub fn pt_dbl(P: &RistrettoPoint) -> RistrettoPoint { } // The protocol modules +pub mod migration; pub mod open_invite; +pub mod trust_promotion; // Unit tests #[cfg(test)] diff --git a/crates/lox-library/src/migration.rs b/crates/lox-library/src/migration.rs new file mode 100644 index 0000000..4450fdc --- /dev/null +++ b/crates/lox-library/src/migration.rs @@ -0,0 +1,612 @@ +/*! A module for the protocol for the user to migrate from one bucket to +another (and possibly also change trust level). + +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: + +- id: revealed +- bucket: blinded +- trust_level: revealed to be 0 +- level_since: blinded +- invites_remaining: revealed to be 0 +- invites_issued: revealed to be 0 + +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: 1 +- level_since: today +- invites_remaining: 0 +- invites_issued: 0 + +*/ + +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::cred; +use super::{BridgeAuth, IssuerPubKey}; +use super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE}; + +pub struct Request { + // Fields for blind showing the Lox credential + // We don't need to include invites_remaining or invites_issued, + // since they must be 0 + P_lox: RistrettoPoint, + id: Scalar, + CBucket: RistrettoPoint, + trust_level: Scalar, + CSince: 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), + + // The combined ZKP + piUser: CompactProof, +} + +#[derive(Debug)] +pub struct State { + d: Scalar, + D: RistrettoPoint, + EncIdClient: (RistrettoPoint, RistrettoPoint), + EncBucket: (RistrettoPoint, RistrettoPoint), + id_client: Scalar, + to_bucket: Scalar, +} + +pub struct Response { + // The new attributes; trust_level = 1 is implicit + level_since: Scalar, + + // The fields for the new Lox credential + P: RistrettoPoint, + EncQ: (RistrettoPoint, RistrettoPoint), + id_server: Scalar, + TId: RistrettoPoint, + TBucket: RistrettoPoint, + + // The fields for the implicit noop migration ("nm") credential + P_nm: RistrettoPoint, + EncQ_nm: (RistrettoPoint, RistrettoPoint), + TId_nm: RistrettoPoint, + TBucket_nm: RistrettoPoint, + + // The ZKP + piBlindIssue: CompactProof, +} + +define_proof! { + requestproof, + "Migration Request", + (bucket, since, zbucket, zsince, negzQ_lox, + tobucket, zfrombucket, ztobucket, negzQ_mig, + d, eid_client, ebucket, id_client), + (P_lox, CBucket, CSince, V_lox, Xbucket, Xsince, + P_mig, CFromBucket, CToBucket, V_mig, Xfrombucket, Xtobucket, + D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1), + (A, B): + // Blind showing of the Lox credential + CBucket = (bucket*P_lox + zbucket*A), + CSince = (since*P_lox + zsince*A), + V_lox = (zbucket*Xbucket + zsince*Xsince + 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 + EncIdClient0 = (eid_client*B), + EncIdClient1 = (id_client*B + eid_client*D), + EncBucket0 = (ebucket*B), + EncBucket1 = (tobucket*B + ebucket*D), + D = (d*B) +} + +define_proof! { + blindissue, + "Migration Blind Issuing", + (x0, x0tilde, xid, xbucket, xlevel, xsince, s, b, tid, tbucket, + x0_nm, x0tilde_nm, xid_nm, xfrom_nm, xto_nm, s_nm, b_nm, tid_nm, tbucket_nm), + (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Plevel, Psince, TId, TBucket, + P_nm, EncQ0_nm, EncQ1_nm, X0_nm, Xid_nm, Xfrom_nm, Xto_nm, + TId_nm, TBucket_nm, + D, EncId0, EncId1, EncBucket0, EncBucket1), + (A, B): + Xid = (xid*A), + Xlevel = (xlevel*A), + Xbucket = (xbucket*A), + Xsince = (xsince*A), + X0 = (x0*B + x0tilde*A), + P = (b*B), + TId = (b*Xid), + TId = (tid*A), + TBucket = (b*Xbucket), + TBucket = (tbucket*A), + EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0), + EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1 + x0*P + xlevel*Plevel + xsince*Psince), + Xid_nm = (xid_nm*A), + Xfrom_nm = (xfrom_nm*A), + Xto_nm = (xto_nm*A), + X0_nm = (x0_nm*B + x0tilde_nm*A), + P_nm = (b_nm*B), + TId_nm = (b_nm*Xid_nm), + TId_nm = (tid_nm*A), + TBucket_nm = (b_nm*Xfrom_nm + b_nm*Xto_nm), + TBucket_nm = (tbucket_nm*A), + EncQ0_nm = (s_nm*B + tid_nm*EncId0 + tbucket_nm*EncBucket0), + EncQ1_nm = (s_nm*D + tid_nm*EncId1 + tbucket_nm*EncBucket1 + x0_nm*P_nm) +} + +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); + } + + // We only support migrating from trust level 0 to trust level 1 + // right now + if lox_cred.trust_level != Scalar::zero() { + 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 CBucket = lox_cred.bucket * P_lox + &zbucket * Atable; + let CSince = lox_cred.level_since * P_lox + &zsince * 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] + &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 bucket field (times B) to D as well + let ebucket = Scalar::random(&mut rng); + let EncBucket = ( + &ebucket * Btable, + &migration_cred.to_bucket * Btable + ebucket * D, + ); + + // Construct the proof + let mut transcript = Transcript::new(b"migration request"); + let piUser = requestproof::prove_compact( + &mut transcript, + requestproof::ProveAssignments { + A: &A, + B: &B, + P_lox: &P_lox, + CBucket: &CBucket, + CSince: &CSince, + V_lox: &V_lox, + Xbucket: &lox_pub.X[2], + Xsince: &lox_pub.X[4], + 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, + bucket: &lox_cred.bucket, + since: &lox_cred.level_since, + zbucket: &zbucket, + zsince: &zsince, + 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, + id_client: &id_client, + }, + ) + .0; + + Ok(( + Request { + P_lox, + id: lox_cred.id, + CBucket, + trust_level: lox_cred.trust_level, + CSince, + CQ_lox, + P_mig, + CFromBucket, + CToBucket, + CQ_mig, + D, + EncIdClient, + EncBucket, + piUser, + }, + State { + d, + D, + EncIdClient, + EncBucket, + id_client, + to_bucket: migration_cred.to_bucket, + }, + )) +} + +impl BridgeAuth { + /// Receive a migration request + pub fn handle_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); + } + + // We only currently support migrating from trust level 0 + if req.trust_level != Scalar::zero() { + 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 + - req.CQ_lox; + + let Vprime_mig = (self.migration_priv.x[0] + self.migration_priv.x[1] * req.id) * 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"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(), + V_lox: &Vprime_lox.compress(), + Xbucket: &self.lox_pub.X[2].compress(), + Xsince: &self.lox_pub.X[4].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(), + }, + )?; + + // 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 + // level 1 + let trust_level: Scalar = Scalar::one(); + + // Create the level_since attribute (Scalar), which is today's + // Julian date + let level_since: Scalar = self.today().into(); + + // The invitations_remaining and invitations_issued attributes + // are 0 for level 0 and level 1 Lox credentials, so we don't + // need to explicitly create them. + + // Compute the MAC on the visible attributes + let b = Scalar::random(&mut rng); + let P = &b * Btable; + // invites_remaining = invites_issued = 0 + 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 id attribute + 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 EncQ = ( + EncQHc.0 + EncQId.0 + EncQBucket.0, + EncQHc.1 + EncQId.1 + EncQBucket.1, + ); + + // Now the no-op migration credential + // Compute the MAC on the visible attributes (none here) + let b_nm = Scalar::random(&mut rng); + let P_nm = &b_nm * Btable; + let QHc_nm = (self.migration_priv.x[0]) * P_nm; + + // El Gamal encrypt it to the public key req.D + let s_nm = Scalar::random(&mut rng); + let EncQHc_nm = (&s_nm * Btable, QHc_nm + s_nm * req.D); + + // Homomorphically compute the part of the MAC corresponding to + // the blinded attributes + let tid_nm = self.migration_priv.x[1] * b_nm; + let TId_nm = &tid_nm * Atable; + let EncQId_nm = (tid_nm * EncId.0, tid_nm * EncId.1); + let tbucket_nm = (self.migration_priv.x[2] + self.migration_priv.x[3]) * b_nm; + let TBucket_nm = &tbucket_nm * Atable; + let EncQBucket_nm = (tbucket_nm * req.EncBucket.0, tbucket_nm * req.EncBucket.1); + + let EncQ_nm = ( + EncQHc_nm.0 + EncQId_nm.0 + EncQBucket_nm.0, + EncQHc_nm.1 + EncQId_nm.1 + EncQBucket_nm.1, + ); + + let mut transcript = Transcript::new(b"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], + Plevel: &(trust_level * P), + Psince: &(level_since * P), + TId: &TId, + TBucket: &TBucket, + P_nm: &P_nm, + EncQ0_nm: &EncQ_nm.0, + EncQ1_nm: &EncQ_nm.1, + X0_nm: &self.migration_pub.X[0], + Xid_nm: &self.migration_pub.X[1], + Xfrom_nm: &self.migration_pub.X[2], + Xto_nm: &self.migration_pub.X[3], + TId_nm: &TId_nm, + TBucket_nm: &TBucket_nm, + D: &req.D, + EncId0: &EncId.0, + EncId1: &EncId.1, + EncBucket0: &req.EncBucket.0, + EncBucket1: &req.EncBucket.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], + s: &s, + b: &b, + tid: &tid, + tbucket: &tbucket, + x0_nm: &self.migration_priv.x[0], + x0tilde_nm: &self.migration_priv.x0tilde, + xid_nm: &self.migration_priv.x[1], + xfrom_nm: &self.migration_priv.x[2], + xto_nm: &self.migration_priv.x[3], + s_nm: &s_nm, + b_nm: &b_nm, + tid_nm: &tid_nm, + tbucket_nm: &tbucket_nm, + }, + ) + .0; + + Ok(Response { + level_since, + P, + EncQ, + id_server, + TId, + TBucket, + P_nm, + EncQ_nm, + TId_nm, + TBucket_nm, + 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, + 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_nm.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"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(), + // The new trust level is 1 + Plevel: &(Scalar::one() * resp.P).compress(), + Psince: &(resp.level_since * resp.P).compress(), + TId: &resp.TId.compress(), + TBucket: &resp.TBucket.compress(), + P_nm: &resp.P_nm.compress(), + EncQ0_nm: &resp.EncQ_nm.0.compress(), + EncQ1_nm: &resp.EncQ_nm.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(), + TId_nm: &resp.TId_nm.compress(), + TBucket_nm: &resp.TBucket_nm.compress(), + D: &state.D.compress(), + EncId0: &EncId.0.compress(), + EncId1: &EncId.1.compress(), + EncBucket0: &state.EncBucket.0.compress(), + EncBucket1: &state.EncBucket.1.compress(), + }, + )?; + + // Decrypt EncQ + let Q = resp.EncQ.1 - (state.d * resp.EncQ.0); + + // Decrypt EncQ_nm + let Q_nm = resp.EncQ_nm.1 - (state.d * resp.EncQ_nm.0); + + Ok(cred::Lox { + P: resp.P, + Q, + id, + bucket: state.to_bucket, + trust_level: Scalar::one(), + level_since: resp.level_since, + invites_remaining: Scalar::zero(), + invites_issued: Scalar::zero(), + P_noopmigration: resp.P_nm, + Q_noopmigration: Q_nm, + }) +} diff --git a/crates/lox-library/src/tests.rs b/crates/lox-library/src/tests.rs index c7d31cb..3d2db6e 100644 --- a/crates/lox-library/src/tests.rs +++ b/crates/lox-library/src/tests.rs @@ -45,8 +45,7 @@ fn test_open_invite() { assert!(ba.verify_lox(&cred)); } -#[test] -fn test_trust_promotion() { +fn setup() -> (BridgeDb, BridgeAuth) { // Create a BridegDb let bdb = BridgeDb::new(15); // Create a BridgeAuth @@ -76,6 +75,10 @@ fn test_trust_promotion() { // Create the encrypted bridge table ba.bridge_table.encrypt_table(); + (bdb, ba) +} + +fn trust_promotion(bdb: &BridgeDb, ba: &mut BridgeAuth) -> (cred::Lox, cred::Migration) { // Issue an open invitation let inv = bdb.invite(); @@ -91,7 +94,16 @@ fn test_trust_promotion() { let (promreq, promstate) = trust_promotion::request(&cred, &ba.lox_pub, ba.today()).unwrap(); let promresp = ba.handle_trust_promotion(promreq).unwrap(); let migcred = trust_promotion::handle_response(promstate, promresp).unwrap(); - println!("resp = {:?}", migcred); + + (cred, migcred) +} + +#[test] +fn test_trust_promotion() { + let (bdb, mut ba) = setup(); + + let (_loxcred, migcred) = trust_promotion(&bdb, &mut ba); + assert!(ba.verify_migration(&migcred)); // Check that we can use the to_bucket in the Migration credenital // to read a bucket @@ -99,3 +111,22 @@ fn test_trust_promotion() { let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap(); println!("bucket = {:?}", bucket); } + +#[test] +fn test_level0_migration() { + let (bdb, mut ba) = setup(); + + let (loxcred, migcred) = trust_promotion(&bdb, &mut ba); + + let (migreq, migstate) = + migration::request(&loxcred, &migcred, &ba.lox_pub, &ba.migration_pub).unwrap(); + let migresp = ba.handle_migration(migreq).unwrap(); + let newloxcred = + migration::handle_response(migstate, migresp, &ba.lox_pub, &ba.migration_pub).unwrap(); + assert!(ba.verify_lox(&newloxcred)); + println!("newloxcred = {:?}", newloxcred); + // Check that we can use the credenital to read a bucket + let (id, key) = bridge_table::from_scalar(newloxcred.bucket).unwrap(); + let bucket = ba.bridge_table.decrypt_bucket_id(id, &key).unwrap(); + println!("bucket = {:?}", bucket); +}