|
|
@@ -0,0 +1,179 @@
|
|
|
+/*! 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
|
|
|
+- blockages: blinded, but proved in ZK that it's one more than the
|
|
|
+ blockages above
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+use super::super::dup_filter::SeenType;
|
|
|
+use super::super::scalar_u32;
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+use super::super::BridgeAuth;
|
|
|
+use super::check_blockage::MIN_TRUST_LEVEL;
|
|
|
+use super::errors::CredentialError;
|
|
|
+use super::level_up::LEVEL_INVITATIONS;
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+use super::level_up::MAX_LEVEL;
|
|
|
+pub use crate::lox_creds::{Lox, Migration};
|
|
|
+use cmz::*;
|
|
|
+use curve25519_dalek::ristretto::RistrettoPoint as G;
|
|
|
+use group::Group;
|
|
|
+use rand_core::RngCore;
|
|
|
+use sha2::Sha512;
|
|
|
+
|
|
|
+muCMZProtocol! { blockage_migration<min_trust_level>,
|
|
|
+ [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
|
|
|
+ M: Migration { lox_id: R, from_bucket: H, to_bucket: H } ],
|
|
|
+ N: Lox {id: J, bucket: H, trust_level: R, level_since: S, invites_remaining: I, blockages: H },
|
|
|
+ //L.trust_level > min_trust_level,
|
|
|
+ L.bucket = M.from_bucket,
|
|
|
+ N.bucket = M.to_bucket,
|
|
|
+ N.trust_level = L.trust_level - (Scalar::ONE + Scalar::ONE),
|
|
|
+ N.blockages = L.blockages + Scalar::ONE
|
|
|
+}
|
|
|
+
|
|
|
+pub fn request(
|
|
|
+ L: Lox,
|
|
|
+ M: Migration,
|
|
|
+ pubkeys: CMZPubkey<G>,
|
|
|
+) -> Result<(blockage_migration::Request, blockage_migration::ClientState), CredentialError> {
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
+ cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
|
|
|
+
|
|
|
+ // 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 L.id.is_some_and(|i| i != M.lox_id.unwrap()) {
|
|
|
+ return Err(CredentialError::CredentialMismatch);
|
|
|
+ }
|
|
|
+
|
|
|
+ if L.bucket.is_some_and(|b| b != M.from_bucket.unwrap()) {
|
|
|
+ return Err(CredentialError::CredentialMismatch);
|
|
|
+ }
|
|
|
+
|
|
|
+ // The trust level must be at least MIN_TRUST_LEVEL
|
|
|
+ let level: u32 = match scalar_u32(&L.trust_level.unwrap()) {
|
|
|
+ Some(v) => v,
|
|
|
+ None => {
|
|
|
+ return Err(CredentialError::InvalidField(
|
|
|
+ String::from("trust_level"),
|
|
|
+ String::from("could not be converted to u32"),
|
|
|
+ ))
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if level < MIN_TRUST_LEVEL {
|
|
|
+ return Err(CredentialError::InvalidField(
|
|
|
+ String::from("trust_level"),
|
|
|
+ format!("level {:?} not in range", level),
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut N = Lox::using_pubkey(&pubkeys);
|
|
|
+ N.trust_level = Some((level - 2).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)
|
|
|
+ N.invites_remaining = Some(LEVEL_INVITATIONS[(level - 3) as usize].into());
|
|
|
+ let params = blockage_migration::Params {
|
|
|
+ // Since we do not yet (and may not?) have PartialOrd for
|
|
|
+ // protocols, we will subtract and extra value and check strictly gt
|
|
|
+ min_trust_level: (MIN_TRUST_LEVEL - 1).into(),
|
|
|
+ };
|
|
|
+
|
|
|
+ match blockage_migration::prepare(&mut rng, &L, &M, N, ¶ms) {
|
|
|
+ Ok(req_state) => Ok(req_state),
|
|
|
+ Err(e) => Err(CredentialError::CMZError(e)),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+impl BridgeAuth {
|
|
|
+ pub fn handle_blockage_migration(
|
|
|
+ &mut self,
|
|
|
+ req: blockage_migration::Request,
|
|
|
+ ) -> Result<blockage_migration::Reply, CredentialError> {
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
+ let reqbytes = req.as_bytes();
|
|
|
+ let recvreq = blockage_migration::Request::try_from(&reqbytes[..]).unwrap();
|
|
|
+
|
|
|
+ let today = self.today();
|
|
|
+ match blockage_migration::handle(
|
|
|
+ &mut rng,
|
|
|
+ recvreq,
|
|
|
+ |L: &mut Lox, M: &mut Migration, N: &mut Lox| {
|
|
|
+ let level: u32 = match scalar_u32(&L.trust_level.unwrap()) {
|
|
|
+ Some(v) if v >= MIN_TRUST_LEVEL && v as usize <= MAX_LEVEL => v,
|
|
|
+ _ => {
|
|
|
+ // This error should be improved i.e., InvalidAttr and the type
|
|
|
+ // with a description
|
|
|
+ return Err(CMZError::RevealAttrMissing(
|
|
|
+ "blockage_migration",
|
|
|
+ "Could not be converted to u32 or value not in range",
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if L.id.is_some_and(|b| b != M.lox_id.unwrap()) {
|
|
|
+ return Err(CMZError::RevealAttrMissing("id", "mismatch"));
|
|
|
+ }
|
|
|
+ L.set_privkey(&self.lox_priv);
|
|
|
+ M.set_privkey(&self.migration_priv);
|
|
|
+ N.set_privkey(&self.lox_priv);
|
|
|
+ N.trust_level = Some((level - 2).into());
|
|
|
+ N.level_since = Some(today.into());
|
|
|
+ N.invites_remaining = Some(LEVEL_INVITATIONS[(level - 3) as usize].into());
|
|
|
+ Ok(blockage_migration::Params {
|
|
|
+ min_trust_level: (MIN_TRUST_LEVEL - 1).into(),
|
|
|
+ })
|
|
|
+ },
|
|
|
+ |L: &Lox, _M: &Migration, _N: &Lox| {
|
|
|
+ if self.id_filter.filter(&L.id.unwrap()) == SeenType::Seen {
|
|
|
+ return Err(CMZError::RevealAttrMissing("id", ""));
|
|
|
+ }
|
|
|
+ Ok(())
|
|
|
+ },
|
|
|
+ ) {
|
|
|
+ Ok((response, (_L_issuer, _M_isser, _N_issuer))) => Ok(response),
|
|
|
+ Err(e) => Err(CredentialError::CMZError(e)),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn handle_response(
|
|
|
+ state: blockage_migration::ClientState,
|
|
|
+ rep: blockage_migration::Reply,
|
|
|
+) -> Result<Lox, CMZError> {
|
|
|
+ let replybytes = rep.as_bytes();
|
|
|
+ let recvreply = blockage_migration::Reply::try_from(&replybytes[..]).unwrap();
|
|
|
+ match state.finalize(recvreply) {
|
|
|
+ Ok(cred) => Ok(cred),
|
|
|
+ Err(_e) => Err(CMZError::Unknown),
|
|
|
+ }
|
|
|
+}
|