Kaynağa Gözat

Modify existing protocols to handle credential changes

Vecna 6 ay önce
ebeveyn
işleme
ea5f7ce9b1

+ 12 - 2
crates/lox-extensions/src/proto/blockage_migration.rs

@@ -10,6 +10,8 @@ The user presents their current Lox credential:
 - level_since: hidden
 - invites_remaining: hidden
 - blockages: hidden
+- false_reports: hidden
+- pending: hidden
 
 and a Migration credential:
 
@@ -28,6 +30,10 @@ and a new Lox credential to be issued:
 - invites_remaining: implicit to both the client and server as LEVEL_INVITATIONS for the new trust level
 - blockages: hidden, but proved in ZK that it's one more than the
   blockages above
+- false_reports: hidden, but proved in ZK that it's the same as in the
+  Lox credential above
+- pending: hidden, but proved in ZK that it's the same as in the Lox
+  credential above
 
 */
 
@@ -54,13 +60,15 @@ use sha2::Sha512;
 const SESSION_ID: &[u8] = b"blockage_migration";
 
 muCMZProtocol! { blockage_migration,
-    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
+    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: H },
     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: H },
+    N: Lox {id: J, bucket: H, trust_level: I, level_since: S, invites_remaining: I, blockages: H, false_reports: H, pending: H },
     L.id = M.lox_id,
     L.bucket = M.from_bucket,
     N.bucket = M.to_bucket,
     N.blockages = L.blockages + 1,
+    N.false_reports = L.false_reports,
+    N.pending = L.pending,
 }
 
 pub fn request(
@@ -106,6 +114,8 @@ pub fn request(
     // invitations for moving from level i to level i+1)
     N.invites_remaining = Some(LEVEL_INVITATIONS[(level - 3) as usize].into());
     N.blockages = Some(L.blockages.unwrap() + Scalar::ONE);
+    N.false_reports = L.false_reports;
+    N.pending = L.pending;
 
     match blockage_migration::prepare(rng, SESSION_ID, &L, &M, N) {
         Ok(req_state) => Ok(req_state),

+ 3 - 1
crates/lox-extensions/src/proto/check_blockage.rs

@@ -9,6 +9,8 @@ The user presents their current Lox credential:
 - level_since: blinded
 - invites_remaining: blinded
 - blockages: blinded
+- false_reports: blinded
+- pending: blinded
 
 They are allowed to to this as long as they are level 3 or above.  If
 they have too many blockages (but are level 3 or above), they will be
@@ -53,7 +55,7 @@ pub const MIN_TRUST_LEVEL: u32 = 3;
 const SESSION_ID: &[u8] = b"check_blockage";
 
 muCMZProtocol! { check_blockage,
-    L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
+    L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: H },
     M: MigrationKey { lox_id: R, from_bucket: H},
     M.lox_id = L.id,
     M.from_bucket = L.bucket,

+ 4 - 0
crates/lox-extensions/src/proto/errors.rs

@@ -16,6 +16,10 @@ pub enum CredentialError {
     NoInvitationsRemaining,
     #[error("supplied credentials do not match")]
     CredentialMismatch,
+    #[error("credential is in pending state")]
+    CredentialPending,
+    #[error("credential is not in pending state")]
+    CredentialNotPending,
     #[error("CMZ Error")]
     CMZError(cmz::CMZError),
 }

+ 26 - 3
crates/lox-extensions/src/proto/issue_invite.rs

@@ -14,6 +14,8 @@ The user presents their current Lox credential:
 - level_since: hidden
 - invites_remaining: hidden, but proved in ZK that it's not zero
 - blockages: hidden
+- false_reports: hidden
+- pending: revealed to be 0
 
 and a Bucket Reachability credential:
 - date: revealed to be today
@@ -33,6 +35,9 @@ and a new Lox credential to be issued:
   the number in the Lox credential above
 - blockages: hidden, but proved in ZK that it's the same as in the
   Lox credential above
+- false_reports: hidden, but proved in ZK that it's the same as in the
+  Lox credential above
+- pending: 0
 
 and a new Invitation credential to be issued:
 
@@ -42,6 +47,8 @@ and a new Invitation credential to be issued:
   credential above
 - blockages: hidden, but proved in ZK that it's the same as in the Lox
   credential above
+- false_reports: hidden, but proved in ZK that it's the same as in the
+  Lox credential above
 
 */
 
@@ -65,8 +72,8 @@ const SESSION_ID: &[u8] = b"issue_invite";
 pub const INVITATION_EXPIRY: u32 = 15;
 
 muCMZProtocol! { issue_invite,
-    [L: Lox {id: R, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H}, B: BucketReachability { date: R, bucket: H } ],
-    [ I: Invitation { inv_id: J, date: S, bucket: H, blockages: H }, N: Lox {id: J, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H }],
+    [L: Lox {id: R, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: R }, B: BucketReachability { date: R, bucket: H } ],
+    [ I: Invitation { inv_id: J, date: S, bucket: H, blockages: H, false_reports: H }, N: Lox {id: J, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: I }],
     L.bucket = B.bucket,
     L.invites_remaining != 0,
     N.bucket = L.bucket,
@@ -74,8 +81,10 @@ muCMZProtocol! { issue_invite,
     N.level_since = L.level_since,
     N.invites_remaining = L.invites_remaining - 1,
     N.blockages = L.blockages,
+    N.false_reports = L.false_reports,
     I.bucket = L.bucket,
-    I.blockages = L.blockages
+    I.blockages = L.blockages,
+    I.false_reports = L.false_reports,
 }
 
 pub fn request(
@@ -121,12 +130,17 @@ pub fn request(
             String::from("reachability credential must be generated today"),
         ));
     }
+    // The credential must not have pending reports
+    if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+        return Err(CredentialError::CredentialPending);
+    }
 
     let mut I: Invitation = Invitation::using_pubkey(&inv_pub);
     I.inv_id = Some(Scalar::random(rng));
     I.date = Some(today.into());
     I.bucket = L.bucket;
     I.blockages = L.blockages;
+    I.false_reports = L.false_reports;
 
     let mut N: Lox = Lox::using_pubkey(L.get_pubkey());
     N.bucket = L.bucket;
@@ -134,6 +148,8 @@ pub fn request(
     N.level_since = L.level_since;
     N.invites_remaining = Some(L.invites_remaining.unwrap() - Scalar::ONE);
     N.blockages = L.blockages;
+    N.false_reports = L.false_reports;
+    N.pending = Some(Scalar::ZERO);
 
     match issue_invite::prepare(rng, SESSION_ID, &L, &B, I, N) {
         Ok(req_state) => Ok(req_state),
@@ -156,6 +172,13 @@ impl BridgeAuth {
             SESSION_ID,
             recvreq,
             |L: &mut Lox, B: &mut BucketReachability, I: &mut Invitation, N: &mut Lox| {
+                if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+                    // This error should be improved (InvalidAttr)
+                    return Err(CMZError::RevealAttrMissing(
+                        "trust_promotion",
+                        "Credential must not be pending",
+                    ));
+                }
                 L.set_privkey(&self.lox_priv);
                 B.set_privkey(&self.reachability_priv);
                 I.set_privkey(&self.invitation_priv);

+ 12 - 2
crates/lox-extensions/src/proto/level_up.rs

@@ -17,6 +17,8 @@ The user presents their current Lox credential:
 - invites_remaining: blinded
 - blockages: blinded, but proved in ZK that it's at most the appropriate
   blockage limit for the target trust level
+- false_reports: blinded
+- pending: blinded
 
 and a Bucket Reachability credential:
 - date: revealed to be today
@@ -35,6 +37,10 @@ and a new Lox credential to be issued:
   are _not_ carried over)
 - blockages: blinded, but proved in ZK that it's the same as in the
   Lox credential above
+- false_reports: blinded, but proved in ZK that it's the same as in the
+  Lox credential above
+- pending: blinded, but proved in ZK that it's the same as in the Lox
+  credential above
 
 */
 #[cfg(feature = "bridgeauth")]
@@ -79,9 +85,9 @@ pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6, 8];
 pub const MAX_BLOCKAGES: [u32; MAX_LEVEL + 1] = [0, 4, 3, 2, 2];
 
 muCMZProtocol! { level_up<credential_expiry, eligibility_max_age, max_blockage, today>,
-    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
+    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: H },
     B: BucketReachability { date: R, bucket: H } ],
-    N: Lox {id: J, bucket: H, trust_level: R, level_since: S, invites_remaining: I, blockages: H },
+    N: Lox {id: J, bucket: H, trust_level: R, level_since: S, invites_remaining: I, blockages: H, false_reports: H, pending: H },
     (credential_expiry..=eligibility_max_age).contains(L.level_since),
     (0..=max_blockage).contains(L.blockages),
     B.date = today,
@@ -89,6 +95,8 @@ muCMZProtocol! { level_up<credential_expiry, eligibility_max_age, max_blockage,
     N.bucket = L.bucket,
     N.trust_level = L.trust_level + 1,
     N.blockages = L.blockages,
+    N.false_reports = L.false_reports,
+    N.pending = L.pending,
 }
 
 pub fn request(
@@ -190,6 +198,8 @@ pub fn request(
     N.trust_level = Some(new_level.into());
     N.invites_remaining = Some(LEVEL_INVITATIONS[trust_level as usize].into());
     N.blockages = L.blockages;
+    N.false_reports = L.false_reports;
+    N.pending = L.pending;
     let eligibility_max_age = today - (LEVEL_INTERVAL[trust_level as usize]);
 
     let params = level_up::Params {

+ 23 - 2
crates/lox-extensions/src/proto/migration.rs

@@ -10,6 +10,8 @@ The user presents their current Lox credential:
 - level_since: blinded
 - invites_remaining: revealed to be 0
 - blockages: revealed to be 0
+- false_reports: blinded
+- pending: revealed to be 0
 
 and a Migration credential:
 
@@ -27,6 +29,9 @@ and a new Lox credential to be issued:
 - level_since: today
 - invites_remaining: 0
 - blockages: 0
+- false_reports: blinded, but proved in ZK that it's the same as in the
+  Lox credential above
+- pending: 0
 
 */
 
@@ -51,12 +56,13 @@ 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 },
+    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R, false_reports: H, pending: 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 },
+    N: Lox {id: J, bucket: H, trust_level: I, level_since: S, invites_remaining: I, blockages: I, false_reports: H, pending: I },
     L.id = M.lox_id,
     L.bucket = M.from_bucket,
     N.bucket = M.to_bucket,
+    N.false_reports = L.false_reports,
 }
 
 pub fn request(
@@ -86,11 +92,18 @@ pub fn request(
         return Err(CredentialError::CredentialMismatch);
     }
 
+    // The user's credential must not be pending
+    if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+        return Err(CredentialError::CredentialPending);
+    }
+
     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);
+    N.false_reports = L.false_reports;
+    N.pending = Some(Scalar::ZERO);
 
     match migration::prepare(rng, SESSION_ID, &L, &M, N) {
         Ok(req_state) => Ok(req_state),
@@ -125,6 +138,13 @@ impl BridgeAuth {
                         ));
                     }
                 };
+                if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+                    // As above, this error should be InvalidAttr
+                    return Err(CMZError::RevealAttrMissing(
+                        "migration",
+                        "Credential must not be pending",
+                    ));
+                }
                 L.set_privkey(&self.lox_priv);
                 M.set_privkey(&self.migration_priv);
                 N.set_privkey(&self.lox_priv);
@@ -133,6 +153,7 @@ impl BridgeAuth {
                 N.level_since = Some(today.into());
                 N.invites_remaining = Some(Scalar::ZERO);
                 N.blockages = Some(Scalar::ZERO);
+                N.pending = Some(Scalar::ZERO);
                 Ok(())
             },
             |L: &Lox, _M: &Migration, _N: &Lox| {

+ 7 - 1
crates/lox-extensions/src/proto/open_invite.rs

@@ -10,6 +10,8 @@ The credential will have attributes:
 - level_since: today
 - invites_remaining: 0
 - blockages: 0
+- false_reports: 0
+- pending: 0
 
 */
 
@@ -29,7 +31,7 @@ use sha2::Sha512;
 const SESSION_ID: &[u8] = b"open_invite";
 muCMZProtocol! { open_invitation,
     ,
-    L: Lox {id: J, bucket: S, trust_level: I, level_since: S, invites_remaining: I, blockages: I },
+    L: Lox {id: J, bucket: S, trust_level: I, level_since: S, invites_remaining: I, blockages: I, false_reports: I, pending: I },
 }
 
 /// Prepare the open invitation request to send to the Lox Authority
@@ -45,6 +47,8 @@ pub fn request(
     L.trust_level = Some(Scalar::ZERO);
     L.invites_remaining = Some(Scalar::ZERO);
     L.blockages = Some(Scalar::ZERO);
+    L.false_reports = Some(Scalar::ZERO);
+    L.pending = Some(Scalar::ZERO);
     match open_invitation::prepare(rng, SESSION_ID, L) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
@@ -132,6 +136,8 @@ impl BridgeAuth {
                 L.level_since = Some(self.today().into());
                 L.invites_remaining = Some(Scalar::ZERO);
                 L.blockages = Some(Scalar::ZERO);
+                L.false_reports = Some(Scalar::ZERO);
+                L.pending = Some(Scalar::ZERO);
                 Ok(())
             },
             |_L: &Lox| Ok(()),

+ 10 - 2
crates/lox-extensions/src/proto/redeem_invite.rs

@@ -7,6 +7,7 @@ The user presents the Invitation credential:
 - date: blinded, but proved in ZK to be at most INVITATION_EXPIRY days ago
 - bucket: blinded
 - blockages: blinded
+- false_reports: blinded
 
 and a new Lox credential to be issued:
 
@@ -18,6 +19,9 @@ and a new Lox credential to be issued:
 - invites_remaining: revealed to be 0
 - blockages: blinded, but proved in ZK that it's the same as in the
   Invitations credential above
+- false_reports: blinded, but proved in ZK that it's the same as in the
+  Invitation credential above
+- pending: revealed to be 0
 
 */
 
@@ -42,11 +46,12 @@ const SESSION_ID: &[u8] = b"redeem_invite";
 pub const INVITATION_EXPIRY: u32 = 15;
 
 muCMZProtocol! { redeem_invite<credential_expiry, today>,
-    [ I: Invitation { inv_id: R, date: H, bucket: H, blockages: H } ],
-    N: Lox {id: J, bucket: H, trust_level: I, level_since: S, invites_remaining: I, blockages: H },
+    [ I: Invitation { inv_id: R, date: H, bucket: H, blockages: H, false_reports: H } ],
+    N: Lox {id: J, bucket: H, trust_level: I, level_since: S, invites_remaining: I, blockages: H, false_reports: H, pending: I },
     (credential_expiry..=today).contains(I.date),
     N.bucket = I.bucket,
     N.blockages = I.blockages,
+    N.false_reports = I.false_reports,
 }
 
 pub fn request(
@@ -90,6 +95,8 @@ pub fn request(
     N.trust_level = Some(Scalar::ONE);
     N.invites_remaining = Some(LEVEL_INVITATIONS[1].into());
     N.blockages = I.blockages;
+    N.false_reports = I.false_reports;
+    N.pending = Some(Scalar::ZERO);
 
     match redeem_invite::prepare(rng, SESSION_ID, &I, N, &params) {
         Ok(req_state) => Ok(req_state),
@@ -118,6 +125,7 @@ impl BridgeAuth {
                 N.trust_level = Some(Scalar::ONE);
                 N.level_since = Some(today.into());
                 N.invites_remaining = Some(LEVEL_INVITATIONS[1].into());
+                N.pending = Some(Scalar::ZERO);
                 Ok(redeem_invite::Params {
                     credential_expiry: eligibility_max_age.into(),
                     today: today.into(),

+ 15 - 2
crates/lox-extensions/src/proto/trust_promotion.rs

@@ -15,6 +15,8 @@ The user presents their current Lox credential:
   UNTRUSTED_INTERVAL days ago
 - invites_remaining: revealed to be 0
 - blockages: revealed to be 0
+- false_reports: blinded
+- pending: revealed to be 0
 
 They will receive in return the encrypted MAC (Pk, EncQk) for their
 implicit Migration Key credential with attributes id and bucket,
@@ -31,7 +33,7 @@ value EncQk would decrypt to if bucket were equal to from_attr_i. */
 use super::super::dup_filter::SeenType;
 #[cfg(feature = "bridgeauth")]
 use super::super::BridgeAuth;
-use super::super::{scalar_u32, G};
+use super::super::{scalar_u32, Scalar, G};
 use super::errors::CredentialError;
 use crate::lox_creds::{Lox, Migration, MigrationKey};
 #[cfg(feature = "bridgeauth")]
@@ -56,7 +58,7 @@ const SESSION_ID: &[u8] = b"trust_promo";
 pub const UNTRUSTED_INTERVAL: u32 = 30;
 
 muCMZProtocol! { trust_promotion<credential_expiry, eligibility_max_age>,
-    L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R },
+    L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R, false_reports: H, pending: R },
     M: MigrationKey { lox_id: R, from_bucket: H} ,
     M.lox_id = L.id,
     M.from_bucket = L.bucket,
@@ -102,6 +104,10 @@ pub fn request(
     }
     let eligibility_max_age = today - UNTRUSTED_INTERVAL;
 
+    if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+        return Err(CredentialError::CredentialPending);
+    }
+
     let params = trust_promotion::Params {
         credential_expiry: (eligibility_max_age - 511).into(),
         eligibility_max_age: eligibility_max_age.into(),
@@ -131,6 +137,13 @@ impl BridgeAuth {
             SESSION_ID,
             recvreq,
             |L: &mut Lox, M: &mut MigrationKey| {
+                if L.pending.is_some_and(|p| p != Scalar::ZERO) {
+                    // This error should be improved (InvalidAttr)
+                    return Err(CMZError::RevealAttrMissing(
+                        "trust_promotion",
+                        "Credential must not be pending",
+                    ));
+                }
                 L.set_privkey(&self.lox_priv);
                 M.set_privkey(&self.migrationkey_priv);
                 let eligibility_max_age = today - UNTRUSTED_INTERVAL;

+ 12 - 2
crates/lox-extensions/src/proto/update_cred.rs

@@ -10,6 +10,8 @@ The user presents their current Lox credential:
 - level_since: blinded
 - invites_remaining: blinded
 - blockages: blinded
+- false_reports: blinded
+- pending: blinded
 
 and a new Lox credential to be issued:
 - id: jointly chosen by the user and BA
@@ -22,6 +24,10 @@ and a new Lox credential to be issued:
 - invites_remaining: blinded, but proved in ZK that it's the same as in the Lox credential above
 - blockages: blinded, but proved in ZK that it's the same as in the
   Lox credential above
+- false_reports: blinded, but proved in ZK that it's the same as in the
+  Lox credential above
+- pending: blinded, but proved in ZK that it's the same as in the Lox
+  credential above
 
 */
 
@@ -40,13 +46,15 @@ use sha2::Sha512;
 const SESSION_ID: &[u8] = b"update_cred";
 
 muCMZProtocol! { update_cred,
-    L: Lox { id: R, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H },
-    N: Lox {id: J, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H },
+    L: Lox { id: R, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: H },
+    N: Lox {id: J, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H, false_reports: H, pending: H },
     N.bucket = L.bucket,
     N.trust_level = L.trust_level,
     N.level_since = L.level_since,
     N.invites_remaining = L.invites_remaining,
     N.blockages = L.blockages,
+    N.false_reports = L.false_reports,
+    N.pending = L.pending,
 }
 
 pub fn request(
@@ -61,6 +69,8 @@ pub fn request(
     N.level_since = L.level_since;
     N.invites_remaining = L.invites_remaining;
     N.blockages = L.blockages;
+    N.false_reports = L.false_reports;
+    N.pending = L.pending;
 
     match update_cred::prepare(&mut *rng, SESSION_ID, &L, N) {
         Ok(req_state) => Ok(req_state),

+ 7 - 2
crates/lox-extensions/src/proto/update_invite.rs

@@ -7,6 +7,7 @@ The user presents their current Invitation credential:
 - date: blinded
 - bucket: blinded
 - blockages: blinded
+- false_reports: blinded
 
 and a new Invitation credential to be issued:
 - id: jointly chosen by the user and BA
@@ -16,6 +17,8 @@ and a new Invitation credential to be issued:
   credential above
 - blockages: blinded, but proved in ZK that it's the same as in the
   Invitation credential above
+- false_reports: blinded, but proved in ZK that it's the same as in the
+  invitation credential above
 
 */
 
@@ -34,11 +37,12 @@ use sha2::Sha512;
 const SESSION_ID: &[u8] = b"update_invite";
 
 muCMZProtocol! { update_invite,
-    I: Invitation { inv_id: R, date: H, bucket: H, blockages: H },
-    N: Invitation { inv_id: J, date: H, bucket: H, blockages: H },
+    I: Invitation { inv_id: R, date: H, bucket: H, blockages: H, false_reports: H },
+    N: Invitation { inv_id: J, date: H, bucket: H, blockages: H, false_reports: H },
     I.date = N.date,
     I.bucket = N.bucket,
     I.blockages = N.blockages,
+    I.false_reports = N.false_reports,
 }
 
 pub fn request(
@@ -52,6 +56,7 @@ pub fn request(
     N.date = I.date;
     N.bucket = I.bucket;
     N.blockages = I.blockages;
+    N.false_reports = I.false_reports;
 
     match update_invite::prepare(&mut *rng, SESSION_ID, &I, N) {
         Ok(req_state) => Ok(req_state),