Rust’s Secrets Management crate with

  1. type level and compile-time guarantees and
  2. each references corresponding to each secrets can only be exposed or revealed under a lexical scope with an invariant lifetime.

It is like the secrecy crate but with type level and compile-time guarantees that the Secret<T, MEC, EC> value is not ’exposed’ more than MEC number of times.

Invariant Lifetimes

Exposure of Secrets (i.e. getting references to them) are only allowed under certain lexical scope and each of the references only exist with an invariant lifetime.

Example:

// Define a wrapper struct `UseSecret` that holds a value of type `T`.
#[derive(Debug)]
pub struct UseSecret<T> {
    pub inner: T,
}

impl<T> UseSecret<T> {
    // Implement a constructor method `new` for `UseSecret` to create a new instance.
    pub fn new(value: T) -> Self {
        Self { inner: value }
    }
}

fn main {
    // Create a secret string.
    let secret = "MySecret".to_owned();

    // Create a new secret using the `Secret` type from your library.
    // `U5` indicates the maximum exposure count (5 times),
    // and the underscore in the last position allows Rust to infer the type.
    let new_secret: Secret<_, U5, _> = Secret::new(secret);

    // Expose the secret safely within a closure. This pattern is identical to
    // `[std:๐Ÿงต:scoped](https://doc.rust-lang.org/std/thread/fn.scope.html)`
    let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
        // `exposed_secret` is of type `&T` and it only exists from HERE to below --- #####
        // Create a new `UseSecret` instance by cloning the exposed secret.               ^
        // You cannot bring `exposed_secret` out of this scope, never.                    |
        // However, because `String` is `Clone`, so you can 'copy' `exposed_secret`       |
        // out of this scope.                                                             |
        let returned_value = UseSecret::new((*exposed_secret).to_owned()); //             |
        // Return the new `UseSecret` instance.                                           |
        returned_value //                                                                 v
        // `exposed_secret` is of type `&T` and it only exists from above to HERE --- #####
    });

    // Assert that the inner value of `returned_value` matches the original secret.
    assert_eq!(returned_value.inner, "MySecret".to_owned());
}

Compile-time Guarantees ๐Ÿš€๐Ÿš€๐Ÿš€

Of course, another cool part of this is the compile time guarantees.

Limited Secret Exposures

Secret<T, MEC, EC>’s cannot be ’exposed’ more than MEC times

Example:

This program will fail to compile.

// The following code is a demonstration of using the `sosecrets_rs` crate in a `no_std` environment.
#![no_std]

// Entry point of the program
fn main() {
    // Importing necessary items from the `sosecrets_rs` crate and other dependencies
    use common::UseSecret; // `UseSecret` is a utility struct for testing
    use sosecrets_rs::prelude::*;
    use sosecrets_rs::traits::ExposeSecret;
    use typenum::consts::U2;

    // Conditionally importing the `std` crate if the "alloc" feature is enabled
    #[cfg(feature = "alloc")]
    extern crate std;

    // Conditionally using items from the `std` crate if the "alloc" feature is enabled
    #[cfg(feature = "alloc")]
    use std::{borrow::ToOwned, vec};

    // Creating a vector containing a secret value ("MySecret")
    let secret_vec = vec!["MySecret".to_owned()];

    // Creating a new secret of type `Secret<_, U2, _>` using the vector
    let new_secret: Secret<_, U2, _> = Secret::new(secret_vec);

    // Exposing the secret and capturing the returned value; `EC` = 1, `MEC` = 2
    let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
        // Creating a new `UseSecret` instance from the exposed secret
        let returned_value = UseSecret::new((*exposed_secret).to_owned());
        returned_value
    });

    // Asserting that the returned value contains the original secret
    assert_eq!(returned_value.inner, vec!["MySecret".to_owned()]);

    // Performing another exposure of the secret and capturing the returned value; `EC` = 2, `MEC` = 2
    let (new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
        let returned_value = UseSecret::new((*exposed_secret).to_owned());
        returned_value
    });

    // Asserting again that the returned value contains the original secret
    assert_eq!(returned_value.inner, vec!["MySecret".to_owned()]);

    // Performing one final exposure; `EC` = 3, `MEC` = 2 => COMPILE TIME ERROR ๐Ÿ˜ฅ
    let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
        let returned_value = UseSecret::new((*exposed_secret).to_owned());
        returned_value
    });
    assert_eq!(returned_value.inner, vec![]);
}

Compilation fails with this obscene error message.

error[E0271]: type mismatch resolving `<UInt<UInt<UTerm, B1>, B1> as IsLessOrEqual<UInt<UInt<UTerm, B1>, B0>>>::Output == B1`
  --> trybuild_tests/test_compile_fail_eight.rs:32:52
   |
32 |     let (_new_secret, returned_value) = new_secret.expose_secret(|exposed_secret| {
   |                                                    ^^^^^^^^^^^^^ expected `B1`, found `B0`
   |
note: required by a bound in `sosecrets_rs::traits::ExposeSecret::Next`
  --> src/traits.rs
   |
   |     type Next: ExposeSecret<'max, T, MEC, Sum<EC, U1>>
   |          ---- required by a bound in this associated type
...
   |         Sum<EC, U1>: Unsigned + IsLessOrEqual<MEC, Output = True> + Add<U1>;
   |                                                    ^^^^^^^^^^^^^ required by this bound in `ExposeSecret::Next`

Invariants Always Maintained

Secret<T, MEC, EC> cannot be constructed with EC strictly larger than MEC

They can be equal but you cannot do anything with it, lol ๐Ÿ˜Ž

Example:

use sosecrets_rs::prelude::Secret;
use typenum::consts::{U5, U67};

fn main() {
    let secret = "MySecret".to_owned();
    // Simple, creating a type with `EC` = 67 and `MEC` = 5; compile error
    let new_secret: Secret<String, U5, U67> = Secret::new(secret);
}

Compilation fails with another yet obscene error message.

error[E0271]: type mismatch resolving `<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, B0>, B0>, ...>, ...>, ...>, ...> as IsLessOrEqual<...>>::Output == B1`
 --> trybuild_tests/test_compile_fail_three.rs:7:21
  |
7 |     let new_secret: Secret<String, U5, U67> = Secret::new(secret);
  |                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `B1`, found `B0`
  |
note: required by a bound in `Secret`
 --> src/secret.rs
  |
  | pub struct Secret<
  |            ------ required by a bound in this struct
...
  |     EC: Add<U1> + IsLessOrEqual<MEC, Output = True> + Unsigned = U0,
  |                                      ^^^^^^^^^^^^^ required by this bound in `Secret`
  1. GitHub - https://github.com/jymchng/sosecrets-rs/tree/master/src