#[cfg(feature = "bridgeauth")]
use super::super::dup_filter::SeenType;
#[cfg(feature = "bridgeauth")]
use super::super::BridgeAuth;
use super::super::{Scalar, G};
use super::errors::CredentialError;
use crate::lox_creds::{Lox, Migration};
#[cfg(feature = "bridgeauth")]
use crate::migration_table::MigrationType;
#[cfg(feature = "bridgeauth")]
use crate::scalar_u32;
use cmz::*;
#[cfg(feature = "bridgeauth")]
use ff::PrimeField;
use group::Group;
use rand::{CryptoRng, RngCore};
use sha2::Sha512;
const SESSION_ID: &[u8] = b"migration";
muCMZProtocol! { migration,
[ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R },
M: Migration { lox_id: R, from_bucket: H, to_bucket: H, migration_type: I} ],
N: Lox {id: J, bucket: H, trust_level: I, level_since: S, invites_remaining: I, blockages: I },
L.id = M.lox_id,
L.bucket = M.from_bucket,
N.bucket = M.to_bucket,
}
pub fn request(
rng: &mut (impl CryptoRng + RngCore),
L: Lox,
M: Migration,
) -> Result<(migration::Request, migration::ClientState), CredentialError> {
cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
if L.id.is_some_and(|i| i != M.lox_id.unwrap()) {
return Err(CredentialError::CredentialMismatch);
}
if L.trust_level.is_some_and(|t| t != Scalar::ZERO) {
return Err(CredentialError::InvalidField(
String::from("trust_level"),
String::from("must be zero"),
));
}
if L.bucket.is_some_and(|b| b != M.from_bucket.unwrap()) {
return Err(CredentialError::CredentialMismatch);
}
let mut N = Lox::using_pubkey(L.get_pubkey());
N.bucket = M.to_bucket;
N.trust_level = Some(Scalar::ONE);
N.invites_remaining = Some(Scalar::ZERO);
N.blockages = Some(Scalar::ZERO);
match migration::prepare(rng, SESSION_ID, &L, &M, N) {
Ok(req_state) => Ok(req_state),
Err(e) => Err(CredentialError::CMZError(e)),
}
}
#[cfg(feature = "bridgeauth")]
impl BridgeAuth {
pub fn handle_migration(
&mut self,
req: migration::Request,
) -> Result<migration::Reply, CredentialError> {
let mut rng = rand::thread_rng();
let reqbytes = req.as_bytes();
let recvreq = migration::Request::try_from(&reqbytes[..]).unwrap();
let today = self.today();
match migration::handle(
&mut rng,
SESSION_ID,
recvreq,
|L: &mut Lox, M: &mut Migration, N: &mut Lox| {
match scalar_u32(&L.trust_level.unwrap()) {
Some(v) if v as usize == 0 => v,
_ => {
return Err(CMZError::RevealAttrMissing(
"migration",
"Could not be converted to u32 or trust_level not 0",
));
}
};
L.set_privkey(&self.lox_priv);
M.set_privkey(&self.migration_priv);
N.set_privkey(&self.lox_priv);
M.migration_type = Some(Scalar::from_u128(MigrationType::TrustUpgrade.into()));
N.trust_level = Some(Scalar::ONE);
N.level_since = Some(today.into());
N.invites_remaining = Some(Scalar::ZERO);
N.blockages = Some(Scalar::ZERO);
Ok(())
},
|L: &Lox, _M: &Migration, _N: &Lox| {
if self.id_filter.filter(&L.id.unwrap()) == SeenType::Seen {
return Err(CMZError::RevealAttrMissing("id", "Credential Expired"));
}
Ok(())
},
) {
Ok((response, (_L_issuer, _M_isser, _N_issuer))) => Ok(response),
Err(e) => Err(CredentialError::CMZError(e)),
}
}
}
pub fn handle_response(
state: migration::ClientState,
rep: migration::Reply,
) -> Result<Lox, CMZError> {
let replybytes = rep.as_bytes();
let recvreply = migration::Reply::try_from(&replybytes[..]).unwrap();
match state.finalize(recvreply) {
Ok(cred) => Ok(cred),
Err(_e) => Err(CMZError::Unknown),
}
}
#[cfg(all(test, feature = "bridgeauth"))]
mod tests {
use crate::mock_auth::TestHarness;
#[test]
fn test_trust_migration() {
let mut th = TestHarness::new();
let rng = &mut rand::thread_rng();
let invite = th.bdb.invite().unwrap();
let mut lox_cred = th.open_invite(rng, &invite);
let mig_cred = th.trust_promotion(rng, lox_cred.clone());
lox_cred = th.migration(rng, lox_cred.clone(), mig_cred.clone());
th.verify_lox(&lox_cred);
}
}