Browse Source

Accommodate cmz and sigma-compiler crate updates

onyinyang 2 months ago
parent
commit
03937496c2

+ 10 - 9
Cargo.lock

@@ -113,9 +113,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.18.1"
+version = "3.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
 
 [[package]]
 name = "byteorder"
@@ -171,7 +171,7 @@ dependencies = [
  "group",
  "hex",
  "lazy_static",
- "rand_core",
+ "rand",
  "serde",
  "serde_bytes",
  "serde_with",
@@ -206,9 +206,9 @@ dependencies = [
 
 [[package]]
 name = "crunchy"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
 
 [[package]]
 name = "crypto-common"
@@ -511,9 +511,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown 0.15.4",
@@ -586,12 +586,12 @@ dependencies = [
  "ff",
  "group",
  "rand",
- "rand_core",
  "serde",
  "serde_bytes",
  "serde_with",
  "sha1",
  "sha2",
+ "sigma_compiler",
  "subtle",
  "thiserror 2.0.12",
  "time",
@@ -851,7 +851,7 @@ dependencies = [
  "chrono",
  "hex",
  "indexmap 1.9.3",
- "indexmap 2.9.0",
+ "indexmap 2.10.0",
  "schemars",
  "serde",
  "serde_derive",
@@ -929,6 +929,7 @@ name = "sigma_compiler"
 version = "0.1.0"
 dependencies = [
  "group",
+ "rand",
  "sigma-rs",
  "sigma_compiler_derive",
 ]

+ 2 - 2
Cargo.toml

@@ -9,7 +9,7 @@ base64 = "0.21.0"
 chrono = { version = "0.4.38", default-features = false, features = ["now"], optional = true }
 curve25519-dalek = {version = "4.1.3", default-features = false, features = ["serde", "group", "rand_core", "digest", "precomputed-tables"] }
 ed25519-dalek = { version = "2.1.1", default-features = false, features = ["serde", "rand_core"] }
-rand = {version = "0.8.0", features = ["std_rng"] }
+rand = {version = "0.8.5", features = ["std_rng"] }
 serde = "1.0.217"
 serde_with = { version = "3.0.0", features = ["json"] }
 sha1 = "0.10"
@@ -17,10 +17,10 @@ sha2 = "0.10.9"
 subtle = "2.5"
 time = "0.3.36"
 cmz = {path = "../cmz"}
+sigma_compiler = {path = "../sigma_compiler"}
 group = "0.13"
 ff = "0.13.1"
 bincode = "1"
-rand_core = "0.6"
 thiserror = "2.0.12"
 serde_bytes = "0.11.17"
 

+ 1 - 1
src/bridge_table.rs

@@ -18,7 +18,7 @@ use base64::{engine::general_purpose, Engine as _};
 use cmz::{CMZCredential, CMZPrivkey, CMZPubkey};
 use curve25519_dalek::ristretto::CompressedRistretto;
 #[allow(unused_imports)]
-use rand::RngCore;
+use rand::{CryptoRng, RngCore};
 use serde::{Deserialize, Serialize};
 use serde_with::{serde_as, DisplayFromStr};
 use sha1::{Digest, Sha1};

+ 7 - 8
src/lib.rs

@@ -26,7 +26,7 @@ use cmz::*;
 use curve25519_dalek::ristretto::RistrettoPoint as G;
 use group::Group;
 #[cfg(feature = "bridgeauth")]
-use rand::{rngs::OsRng, Rng};
+use rand::{rngs::OsRng, CryptoRng, Rng, RngCore};
 #[cfg(feature = "bridgeauth")]
 use std::collections::HashMap;
 type Scalar = <G as Group>::Scalar;
@@ -363,17 +363,16 @@ pub struct BridgeAuth {
 
 #[cfg(feature = "bridgeauth")]
 impl BridgeAuth {
-    pub fn new(bridgedb_pub: VerifyingKey) -> Self {
+    pub fn new(bridgedb_pub: VerifyingKey, rng: &mut (impl CryptoRng + RngCore)) -> Self {
         // Initialization
-        let mut rng = rand::thread_rng();
         cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
         // Create the private and public keys for each of the types of
         // credential with 'true' to indicate uCMZ
-        let (lox_priv, lox_pub) = Lox::gen_keys(&mut rng, true);
-        let (migration_priv, migration_pub) = Migration::gen_keys(&mut rng, true);
-        let (migrationkey_priv, migrationkey_pub) = MigrationKey::gen_keys(&mut rng, true);
-        let (reachability_priv, reachability_pub) = BucketReachability::gen_keys(&mut rng, true);
-        let (invitation_priv, invitation_pub) = Invitation::gen_keys(&mut rng, true);
+        let (lox_priv, lox_pub) = Lox::gen_keys(rng, true);
+        let (migration_priv, migration_pub) = Migration::gen_keys(rng, true);
+        let (migrationkey_priv, migrationkey_pub) = MigrationKey::gen_keys(rng, true);
+        let (reachability_priv, reachability_pub) = BucketReachability::gen_keys(rng, true);
+        let (invitation_priv, invitation_pub) = Invitation::gen_keys(rng, true);
         Self {
             lox_priv,
             lox_pub,

+ 64 - 1
src/mock_auth.rs

@@ -27,8 +27,9 @@ impl TestHarness {
     pub fn new_buckets(num_buckets: u16, hot_spare: u16) -> Self {
         // Create a BridegDb
         let mut bdb = BridgeDb::new();
+        let mut rng = rand::thread_rng();
         // Create a BridgeAuth
-        let mut ba = BridgeAuth::new(bdb.pubkey.clone());
+        let mut ba = BridgeAuth::new(bdb.pubkey.clone(), &mut rng);
 
         // Make 3 x num_buckets open invitation bridges, in sets of 3
         for _ in 0..num_buckets {
@@ -49,6 +50,68 @@ impl TestHarness {
     // pub fn advance_days(&mut self, days: u16) {
     //     self.ba.advance_days(days);
     // }
+
+    /// Verify the two MACs on a Lox credential
+    pub fn verify_lox(&self, cred: &lox_creds::Lox) {
+        assert!(
+            !bool::from(cred.MAC.P.is_identity()),
+            "Lox cred MAC P should not be identity"
+        );
+
+        let Q = (self.ba.lox_priv.x[0]
+            + cred.id.unwrap() * self.ba.lox_priv.x[1]
+            + cred.bucket.unwrap() * self.ba.lox_priv.x[2]
+            + cred.trust_level.unwrap() * self.ba.lox_priv.x[3]
+            + cred.level_since.unwrap() * self.ba.lox_priv.x[4]
+            + cred.invites_remaining.unwrap() * self.ba.lox_priv.x[5]
+            + cred.blockages.unwrap() * self.ba.lox_priv.x[6])
+            * cred.MAC.P;
+
+        assert_eq!(Q, cred.MAC.Q, "Lox MAC Q should match computation");
+    }
+
+    /// Verify the MAC on a Migration credential
+    /*    pub fn verify_migration(&self, cred: &lox_creds::Migration) {
+            if cred.P.is_identity() {
+            }
+
+            let Q = (self.migration_priv.x[0]
+                + cred.lox_id * self.migration_priv.x[1]
+                + cred.from_bucket * self.migration_priv.x[2]
+                + cred.to_bucket * self.migration_priv.x[3])
+                * cred.P;
+
+            Q == cred.Q
+        }
+
+        /// Verify the MAC on a Bucket Reachability credential
+        pub fn verify_reachability(&self, cred: &lox_creds::BucketReachability) {
+            if cred.MAC.P.is_identity() {
+                return false;
+            }
+
+            let Q = (self.reachability_priv.x[0]
+                + cred.date * self.reachability_priv.x[1]
+                + cred.bucket * self.reachability_priv.x[2])
+                * cred.P;
+
+            Q == cred.Q
+        }
+    */
+    /// Verify the MAC on a Invitation credential
+    pub fn verify_invitation(&mut self, cred: &lox_creds::Invitation) {
+        assert!(
+            !bool::from(cred.MAC.P.is_identity()),
+            "Invitation MAC P should not be identity"
+        );
+        let Q = (self.ba.invitation_priv.x[0]
+            + cred.inv_id.unwrap() * self.ba.invitation_priv.x[1]
+            + cred.date.unwrap() * self.ba.invitation_priv.x[2]
+            + cred.bucket.unwrap() * self.ba.invitation_priv.x[3]
+            + cred.blockages.unwrap() * self.ba.invitation_priv.x[4])
+            * cred.MAC.P;
+        assert_eq!(Q, cred.MAC.Q, "Invitation MAC Q should match");
+    }
 }
 
 /// Create a random BridgeLine for testing

+ 18 - 16
src/proto/blockage_migration.rs

@@ -5,29 +5,28 @@ blocked.  Their trust level will go down by 2.
 The user presents their current Lox credential:
 
 - id: revealed
-- bucket: blinded
+- bucket: hidden
 - trust_level: revealed to be 3 or higher
-- level_since: blinded
-- invites_remaining: blinded
-- blockages: blinded
+- level_since: hidden
+- invites_remaining: hidden
+- blockages: hidden
 
 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
+- from_bucket: hidden, but proved in ZK that it's the same as the
   bucket in the Lox credential above
-- to_bucket: blinded
+- to_bucket: hidden
 
 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
+- bucket: hidden, 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
+- level_since: set by the server to today
+- 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
 
 */
@@ -45,18 +44,16 @@ use super::level_up::MAX_LEVEL;
 pub use crate::lox_creds::{Lox, Migration};
 use cmz::*;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, 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,
+    N.blockages = L.blockages + 1,
 }
 
 pub fn request(
@@ -140,7 +137,12 @@ impl BridgeAuth {
                     }
                 };
                 if L.id.is_some_and(|b| b != M.lox_id.unwrap()) {
-                    return Err(CMZError::RevealAttrMissing("id", "mismatch"));
+                    return Err(CMZError::IssProofFailed);
+                }
+                if L.trust_level
+                    .is_some_and(|b| scalar_u32(&b).unwrap() < MIN_TRUST_LEVEL)
+                {
+                    return Err(CMZError::IssProofFailed);
                 }
                 L.set_privkey(&self.lox_priv);
                 M.set_privkey(&self.migration_priv);

+ 12 - 5
src/proto/check_blockage.rs

@@ -34,6 +34,7 @@ use super::super::dup_filter::SeenType;
 use super::super::BridgeAuth;
 use super::super::{scalar_u32, G};
 use super::errors::CredentialError;
+use super::level_up::MAX_LEVEL;
 use crate::lox_creds::{Lox, Migration, MigrationKey};
 use crate::migration_table;
 use crate::migration_table::ENC_MIGRATION_BYTES;
@@ -43,7 +44,7 @@ use cmz::*;
 use group::Group;
 #[cfg(feature = "bridgeauth")]
 use group::WnafBase;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 use std::collections::HashMap;
 
@@ -51,11 +52,11 @@ use std::collections::HashMap;
 /// perform this protocol.
 pub const MIN_TRUST_LEVEL: u32 = 3;
 
-muCMZProtocol! { check_blockage<min_trust_level>,
+muCMZProtocol! { check_blockage<min_trust_level, max_trust_level>,
     L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R },
     M: MigrationKey { lox_id: J, from_bucket: H} ,
     L.bucket = M.from_bucket,
-    // L.trust_level > min_trust_level,
+    [min_trust_level..max_trust_leve].contains(L.trust_level),
 }
 
 pub fn request(
@@ -91,12 +92,17 @@ pub fn request(
         }
     }
 
-    let M = MigrationKey::using_pubkey(&mig_pubkeys);
     let params = check_blockage::Params {
         min_trust_level: MIN_TRUST_LEVEL.into(),
+        max_trust_level: (MAX_LEVEL as u32).into(),
     };
 
-    match check_blockage::prepare(&mut rng, &L, M, &params) {
+    match check_blockage::prepare(
+        &mut rng,
+        &L,
+        MigrationKey::using_pubkey(&mig_pubkeys),
+        &params,
+    ) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }
@@ -128,6 +134,7 @@ impl BridgeAuth {
                 M.from_bucket = L.bucket;
                 Ok(check_blockage::Params {
                     min_trust_level: MIN_TRUST_LEVEL.into(),
+                    max_trust_level: (MAX_LEVEL as u32).into(),
                 })
             },
             |L: &Lox, _M: &MigrationKey| {

+ 24 - 29
src/proto/issue_invite.rs

@@ -9,38 +9,38 @@ encrypted bridge table.)
 
 The user presents their current Lox credential:
 - id: revealed
-- bucket: blinded
-- trust_level: blinded
-- level_since: blinded
-- invites_remaining: blinded, but proved in ZK that it's not zero
-- blockages: blinded
+- bucket: hidden
+- trust_level: hidden
+- level_since: hidden
+- invites_remaining: hidden, but proved in ZK that it's not zero
+- blockages: hidden
 
 and a Bucket Reachability credential:
 - date: revealed to be today
-- bucket: blinded, but proved in ZK that it's the same as in the Lox
+- bucket: hidden, but proved in ZK that it's the same as in the Lox
   credential above
 
 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 in the Lox
+- bucket: hidden, but proved in ZK that it's the same as in the Lox
   credential above
-- trust_level: blinded, but proved in ZK that it's the same as in the
+- trust_level: hidden, but proved in ZK that it's the same as in the
   Lox credential above
-- level_since: blinded, but proved in ZK that it's the same as in the
+- level_since: hidden, but proved in ZK that it's the same as in the
   Lox credential above
-- invites_remaining: blinded, but proved in ZK that it's one less than
+- invites_remaining: hidden, but proved in ZK that it's one less than
   the number in the Lox credential above
-- blockages: blinded, but proved in ZK that it's the same as in the
+- blockages: hidden, but proved in ZK that it's the same as in the
   Lox credential above
 
 and a new Invitation credential to be issued:
 
 - inv_id: jointly chosen by the user and BA
-- date: revealed to be today
-- bucket: blinded, but proved in ZK that it's the same as in the Lox
+- date: selected by the server to be today's date
+- bucket: hidden, 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
+- blockages: hidden, but proved in ZK that it's the same as in the Lox
   credential above
 
 */
@@ -54,7 +54,7 @@ use super::errors::CredentialError;
 use crate::lox_creds::{BucketReachability, Invitation, Lox};
 use cmz::*;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 /// Invitations must be used within this many days of being issued.
@@ -66,11 +66,11 @@ 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.bucket = B.bucket,
-    //L.invites_remaining > 0,
+    L.invites_remaining != 0,
     N.bucket = L.bucket,
     N.trust_level = L.trust_level,
     N.level_since = L.level_since,
-    N.invites_remaining = L.invites_remaining - Scalar::ONE,
+    N.invites_remaining = L.invites_remaining - 1,
     N.blockages = L.blockages,
     I. bucket = L.bucket,
     I.blockages = L.blockages
@@ -121,18 +121,13 @@ pub fn request(
         ));
     }
 
-    //TODO check all values are not None
-    let mut I = Invitation::using_pubkey(&inv_pub);
-    let mut N = Lox::using_pubkey(&lox_pubkeys);
-    N.bucket = L.bucket;
-    N.trust_level = L.trust_level;
-    N.level_since = L.level_since;
-    N.invites_remaining = Some(L.invites_remaining.unwrap() - Scalar::ONE);
-    N.blockages = L.blockages;
-    I.bucket = L.bucket;
-    I.blockages = L.blockages;
-
-    match issue_invite::prepare(&mut rng, &L, &B, I, N) {
+    match issue_invite::prepare(
+        &mut rng,
+        &L,
+        &B,
+        Invitation::using_pubkey(&inv_pub),
+        Lox::using_pubkey(&lox_pubkeys),
+    ) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }

+ 6 - 11
src/proto/level_up.rs

@@ -46,7 +46,7 @@ use super::errors::CredentialError;
 use crate::lox_creds::{BucketReachability, Lox};
 use cmz::*;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 /// The maximum trust level in the system.  A user can run this level
@@ -80,25 +80,22 @@ muCMZProtocol! { level_up<credential_expiry, eligibility_max_age, max_blockage>,
     [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
     B: BucketReachability { date: R, bucket: H } ],
     N: Lox {id: J, bucket: H, trust_level: R, level_since: S, invites_remaining: I, blockages: H },
-   // credential_expiry <= L.level_since,
-   // L.level_since <= eligibility_max_age,
-   // 0 <= L.blockages,
-   // L.blockages <= max_blockage,
+    [credential_expiry.. eligibility_max_age].contains(L.level_since),
+    [0..max_blockage].contains(L.blockages),
     B.bucket = L.bucket,
     N.bucket = L.bucket,
-    N.trust_level = L.trust_level + Scalar::ONE,
+    N.trust_level = L.trust_level + 1,
     N.blockages = L.blockages,
 }
 
 pub fn request(
+    rng: &mut (impl CryptoRng + RngCore),
     L: Lox,
     B: BucketReachability,
     pubkeys: CMZPubkey<G>,
     today: u32,
 ) -> Result<(level_up::Request, level_up::ClientState), CredentialError> {
-    let mut rng = rand::thread_rng();
     cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
-
     // Ensure the credential can be correctly shown: it must be the case
     // that level_since + LEVEL_INTERVAL[level] <= today.
     let level_since: u32 = match scalar_u32(&L.level_since.unwrap()) {
@@ -189,15 +186,13 @@ pub fn request(
 
     let eligibility_max_age = today - (LEVEL_INTERVAL[trust_level as usize]);
 
-    let mut N = Lox::using_pubkey(&pubkeys);
-    N.invites_remaining = Some(LEVEL_INVITATIONS[new_level as usize].into());
     let params = level_up::Params {
         credential_expiry: (eligibility_max_age - 511).into(),
         eligibility_max_age: eligibility_max_age.into(),
         max_blockage: MAX_BLOCKAGES[new_level as usize].into(),
     };
 
-    match level_up::prepare(&mut rng, &L, &B, N, &params) {
+    match level_up::prepare(rng, &L, &B, Lox::using_pubkey(&pubkeys), &params) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }

+ 1 - 1
src/proto/migration.rs

@@ -42,7 +42,7 @@ use cmz::*;
 use curve25519_dalek::ristretto::RistrettoPoint as G;
 use curve25519_dalek::scalar::Scalar;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 muCMZProtocol! { migration,

+ 9 - 7
src/proto/open_invite.rs

@@ -23,7 +23,7 @@ use super::super::{Scalar, G};
 use super::errors::CredentialError;
 use crate::lox_creds::Lox;
 use cmz::*;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 muCMZProtocol! { open_invitation,
@@ -35,19 +35,19 @@ muCMZProtocol! { open_invitation,
 /// Note that preparing the request does not require an open invitation, but an invitation
 /// must be sent along with the prepared open_inivtation::Request to the Lox authority
 pub fn request(
+    rng: &mut (impl CryptoRng + RngCore),
     pubkeys: CMZPubkey<G>,
 ) -> Result<(open_invitation::Request, open_invitation::ClientState), CredentialError> {
-    let mut rng = rand::thread_rng();
     cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
 
     let mut L = Lox::using_pubkey(&pubkeys);
-    L.id = Some(Scalar::random(&mut rng));
+    L.id = Some(Scalar::ZERO);
     L.bucket = Some(Scalar::ZERO);
     L.trust_level = Some(Scalar::ZERO);
     L.level_since = Some(Scalar::ZERO);
     L.invites_remaining = Some(Scalar::ZERO);
     L.blockages = Some(Scalar::ZERO);
-    match open_invitation::prepare(&mut rng, L) {
+    match open_invitation::prepare(&mut *rng, L) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }
@@ -63,6 +63,7 @@ impl BridgeAuth {
         // Check the signature on the open_invite, first with the old key, then with the new key.
         // We manually match here because we're changing the Err type from SignatureError
         // to ProofError
+        let mut rng = rand::thread_rng();
         let mut old_token: Option<((Scalar, u32), usize)> = Default::default();
         let invite_id: Scalar;
         let bucket_id: u32;
@@ -114,7 +115,6 @@ impl BridgeAuth {
             ));
         }
 
-        let mut rng = rand::thread_rng();
         let reqbytes = req.as_bytes();
         // Create the bucket attribute (Scalar), which is a combination
         // of the bucket id (u32) and the bucket's decryption key ([u8; 16])
@@ -161,7 +161,8 @@ mod tests {
     #[test]
     fn test_open_invitation() {
         let mut th = TestHarness::new();
-        let open_invitation_request = request(th.ba.lox_pub.clone());
+        let mut rng = rand::thread_rng();
+        let open_invitation_request = request(&mut rng, th.ba.lox_pub.clone());
         assert!(
             open_invitation_request.is_ok(),
             "Open invitation request should succeed"
@@ -173,8 +174,9 @@ mod tests {
             open_invitation_response.is_ok(),
             "Open invitation response from server should succeed"
         );
-        let (response, bridgeline) = open_invitation_response.unwrap();
+        let (response, _) = open_invitation_response.unwrap();
         let creds = handle_response(client_state, response);
         assert!(creds.is_ok(), "Handle response should succeed");
+        th.verify_lox(&creds.unwrap());
     }
 }

+ 4 - 7
src/proto/redeem_invite.rs

@@ -27,11 +27,12 @@ use super::super::dup_filter::SeenType;
 use super::super::BridgeAuth;
 use super::super::{scalar_u32, Scalar, G};
 use super::errors::CredentialError;
+#[cfg(feature = "bridgeauth")]
 use super::level_up::LEVEL_INVITATIONS;
 use crate::lox_creds::{Invitation, Lox};
 use cmz::*;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 /// Invitations must be used within this many days of being issued.
@@ -42,8 +43,7 @@ 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 },
-    //credential_expiry <= I.date,
-    //I.date <= today,
+    [credential_expiry..today].contains(I.date),
     N.bucket = I.bucket,
     N.blockages = I.blockages,
 }
@@ -79,15 +79,12 @@ pub fn request(
         ));
     }
 
-    let mut N = Lox::using_pubkey(&lox_pubkeys);
-    N.trust_level = Some(Scalar::ONE);
-    N.invites_remaining = Some(LEVEL_INVITATIONS[1].into());
     let params = redeem_invite::Params {
         credential_expiry: (today - INVITATION_EXPIRY).into(),
         today: today.into(),
     };
 
-    match redeem_invite::prepare(&mut rng, &I, N, &params) {
+    match redeem_invite::prepare(&mut rng, &I, Lox::using_pubkey(&lox_pubkeys), &params) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }

+ 4 - 7
src/proto/trust_promotion.rs

@@ -42,7 +42,7 @@ use cmz::*;
 use group::Group;
 #[cfg(feature = "bridgeauth")]
 use group::WnafBase;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 use std::collections::HashMap;
 
@@ -59,16 +59,15 @@ 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 },
     M: MigrationKey { lox_id: J, from_bucket: H} ,
     L.bucket = M.from_bucket,
-   // credential_expiry <= L.level_since,
-   // L.level_since <= eligibility_max_age,
+    [credential_expiry..eligibility_max_age].contains(L.level_since),
 }
 
 pub fn request(
+    rng: &mut (impl CryptoRng + RngCore),
     L: Lox,
     mig_pubkeys: CMZPubkey<G>,
     today: u32,
 ) -> Result<(trust_promotion::Request, trust_promotion::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
@@ -102,13 +101,12 @@ pub fn request(
     }
     let eligibility_max_age = today - UNTRUSTED_INTERVAL;
 
-    let M = MigrationKey::using_pubkey(&mig_pubkeys);
     let params = trust_promotion::Params {
         credential_expiry: (eligibility_max_age - 511).into(),
         eligibility_max_age: eligibility_max_age.into(),
     };
 
-    match trust_promotion::prepare(&mut rng, &L, M, &params) {
+    match trust_promotion::prepare(rng, &L, MigrationKey::using_pubkey(&mig_pubkeys), &params) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }
@@ -129,7 +127,6 @@ impl BridgeAuth {
         let mut rng = rand::thread_rng();
         let reqbytes = req.as_bytes();
         let recvreq = trust_promotion::Request::try_from(&reqbytes[..]).unwrap();
-
         let today = self.today();
         match trust_promotion::handle(
             &mut rng,

+ 5 - 7
src/proto/update_cred.rs

@@ -34,7 +34,7 @@ use crate::lox_creds::Lox;
 use cmz::*;
 use curve25519_dalek::ristretto::RistrettoPoint as G;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 muCMZProtocol! { update_cred,
@@ -48,14 +48,13 @@ muCMZProtocol! { update_cred,
 }
 
 pub fn request(
+    rng: &mut (impl CryptoRng + RngCore),
     L: Lox,
     pubkeys: CMZPubkey<G>,
 ) -> Result<(update_cred::Request, update_cred::ClientState), CredentialError> {
-    let mut rng = rand::thread_rng();
     cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
 
-    let N = Lox::using_pubkey(&pubkeys);
-    match update_cred::prepare(&mut rng, &L, N) {
+    match update_cred::prepare(&mut *rng, &L, Lox::using_pubkey(&pubkeys)) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }
@@ -65,10 +64,9 @@ pub fn request(
 impl BridgeAuth {
     pub fn handle_update_cred(
         &mut self,
+        rng: &mut (impl CryptoRng + RngCore),
         req: update_cred::Request,
     ) -> Result<update_cred::Reply, CredentialError> {
-        let mut rng = rand::thread_rng();
-
         // Both of these must be true and should be true after rotate_lox_keys is called
         if self.old_keys.lox_keys.is_empty() || self.old_filters.lox_filter.is_empty() {
             return Err(CredentialError::CredentialMismatch);
@@ -77,7 +75,7 @@ impl BridgeAuth {
         let reqbytes = req.as_bytes();
         let recvreq = update_cred::Request::try_from(&reqbytes[..]).unwrap();
         match update_cred::handle(
-            &mut rng,
+            &mut *rng,
             recvreq,
             |L: &mut Lox, N: &mut Lox| {
                 // calling this function will automatically use the most recent old private key for

+ 5 - 6
src/proto/update_invite.rs

@@ -28,7 +28,7 @@ use crate::lox_creds::Invitation;
 use cmz::*;
 use curve25519_dalek::ristretto::RistrettoPoint as G;
 use group::Group;
-use rand_core::RngCore;
+use rand::{CryptoRng, RngCore};
 use sha2::Sha512;
 
 muCMZProtocol! { update_invite,
@@ -40,14 +40,13 @@ muCMZProtocol! { update_invite,
 }
 
 pub fn request(
+    rng: &mut (impl CryptoRng + RngCore),
     I: Invitation,
     new_pubkeys: CMZPubkey<G>,
 ) -> Result<(update_invite::Request, update_invite::ClientState), CredentialError> {
-    let mut rng = rand::thread_rng();
     cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
 
-    let N = Invitation::using_pubkey(&new_pubkeys);
-    match update_invite::prepare(&mut rng, &I, N) {
+    match update_invite::prepare(&mut *rng, &I, Invitation::using_pubkey(&new_pubkeys)) {
         Ok(req_state) => Ok(req_state),
         Err(e) => Err(CredentialError::CMZError(e)),
     }
@@ -57,9 +56,9 @@ pub fn request(
 impl BridgeAuth {
     pub fn handle_update_invite(
         &mut self,
+        rng: &mut (impl CryptoRng + RngCore),
         req: update_invite::Request,
     ) -> Result<update_invite::Reply, CredentialError> {
-        let mut rng = rand::thread_rng();
         // Both of these must be true and should be true after rotate_lox_keys is called
         if self.old_keys.invitation_keys.is_empty() || self.old_filters.invitation_filter.is_empty()
         {
@@ -69,7 +68,7 @@ impl BridgeAuth {
         let reqbytes = req.as_bytes();
         let recvreq = update_invite::Request::try_from(&reqbytes[..]).unwrap();
         match update_invite::handle(
-            &mut rng,
+            &mut *rng,
             recvreq,
             |I: &mut Invitation, N: &mut Invitation| {
                 // calling this function will automatically use the most recent old private key for