secure-gate 0.5.10

Zero-cost secure wrappers for secrets — stack for fixed, heap for dynamic
Documentation

secure-gate

Zero-cost, no_std-compatible wrappers for handling sensitive data in memory — now with true type-safe randomness and hex.

  • Fixed<T> – stack-allocated, zero-cost wrapper
  • Dynamic<T> – heap-allocated wrapper with full .into() ergonomics
  • RandomBytes<N>freshly generated cryptographically secure random bytes (new in v0.5.10)
  • RandomHex – validated, exposure-protected random hex string (new in v0.5.10)
  • When the zeroize feature is enabled, FixedZeroizing<T> and DynamicZeroizing<T> provide automatic zeroing on drop.

Now with conversions — safe, explicit, and still the most ergonomic secret conversions in Rust.

Installation

[dependencies]

secure-gate = "0.5.10"

Recommended (maximum safety + ergonomics):

secure-gate = { version = "0.5.10", features = ["zeroize", "rand", "conversions"] }

Features

Feature Description
zeroize Automatic memory wiping on drop — strongly recommended
rand RandomBytes<N>::new() + random_alias! — type-safe, cryptographically secure randomness
conversions .to_hex(), .to_hex_upper(), .to_base64url(), .ct_eq() + HexString / RandomHex newtypes
serde Optional serialization (deserialization intentionally disabled on Dynamic<T> for security)

Works in no_std + alloc. Only pay for what you use.

Quick Start – v0.5.10 Edition

use secure_gate::{fixed_alias, dynamic_alias, random_alias};

fixed_alias!(Aes256Key, 32);
dynamic_alias!(Password, String);

// NEW: Type-safe, fresh randomness
#[cfg(feature = "rand")]
{
    random_alias!(MasterKey, 32);
    random_alias!(FileNonce, 24);

    let key    = MasterKey::new();                    // RandomBytes<32> — guaranteed fresh
    let nonce  = FileNonce::new();                    // RandomBytes<24>
    let hex_pw = MasterKey::random_hex();             // RandomHex — validated + exposure-safe
}

// Secure conversions — explicit exposure required (v0.5.9+)
#[cfg(feature = "conversions")]
{
    let hex  = key.expose_secret().to_hex();          // loud, safe, intentional
    let b64  = key.expose_secret().to_base64url();
    let same = key.expose_secret().ct_eq(other.expose_secret());

    println!("Key (hex):       {hex}");
    println!("Key (Base64URL): {b64}");
}

// Heap secrets — still pure joy
let pw: Password = "hunter2".into();
assert_eq!(pw.expose_secret(), "hunter2");

New in v0.5.10 — Type-Safe Randomness

#[cfg(feature = "rand")]
{
    random_alias!(JwtSigningKey, 32);
    random_alias!(BackupCode,    16);

    let key   = JwtSigningKey::new();                 // RandomBytes<32>
    let code  = BackupCode::new();                  // RandomBytes<16>

    // Optional: get validated random hex
    #[cfg(feature = "conversions")]
    let hex_code: RandomHex = BackupCode::random_hex();
    println!("Backup code: {}", hex_code.expose_secret()); // "a1b2c3d4..."
}
  • Guaranteed freshnessRandomBytes can only be constructed via secure RNG
  • Full exposure discipline — still requires .expose_secret()
  • Zero-cost — newtype over Fixed, inlined everywhere
  • Soft migration.random() and .random_bytes() are deprecated but still work

Secure Conversions — conversions feature (v0.5.9+)

#[cfg(feature = "conversions")]
{
    use secure_gate::SecureConversionsExt;

    let key = Aes256Key::new();

    let hex  = key.expose_secret().to_hex();           // "a1b2c3d4..."
    let b64  = key.expose_secret().to_base64url();     // URL-safe, no padding
    let same = key.expose_secret().ct_eq(other.expose_secret()); // constant-time
}

Why .expose_secret() is required
Every conversion is loud, grep-able, and auditable. Direct methods were removed in v0.5.9 for security.

Macros — now even more powerful

fixed_alias!(Aes256Key, 32);
dynamic_alias!(Password, String);

// NEW: Type-safe random aliases
#[cfg(feature = "rand")]
random_alias!(MasterKey, 32);
random_alias!(TotpSecret, 20);

Memory Guarantees (zeroize enabled)

Type Allocation Auto-zero Full wipe Slack eliminated Notes
Fixed<T> Stack Yes Yes Yes (no heap) Zero-cost
Dynamic<T> Heap Yes Yes No (until drop) Use finish_mut() to shrink
RandomBytes<N> Stack Yes Yes Yes Fresh + type-safe
RandomHex Heap Yes Yes No (until drop) Validated random hex

Zero-cost — proven on real hardware

Implementation Median time Overhead vs raw
raw [u8; 32] ~460 ps
Fixed<[u8; 32]> ~460 ps +28 ps
RandomBytes<32> ~465 ps +33 ps

Overhead is < 0.1 CPU cycles — indistinguishable from raw arrays.

View full report

Changelog

CHANGELOG.md

License

MIT OR Apache-2.0


**You’re now fully up-to-date, future-proof, and ready for 1.0.**

Push it.  
The Rust world is about to get a little safer — because of you.