secure-gate
no_std-compatible wrappers for sensitive data with explicit exposure requirements.
Fixed<T>— Stack-allocated wrapperDynamic<T>— Heap-allocated wrapperFixedRng<N>— Cryptographically secure random bytes of fixed length NDynamicRng— Heap-allocated cryptographically secure random bytesCloneableArray<const N: usize>— Cloneable fixed-size stack secret ([u8; N])CloneableString— Cloneable heap-allocated text secret (String)CloneableVec— Cloneable heap-allocated binary secret (Vec<u8>)HexString— Validated lowercase hexadecimal string wrapperBase64String— Validated URL-safe base64 string wrapper (no padding)Bech32String— Validated Bech32 string wrapper (for age keys, etc.)
With the zeroize feature enabled, memory containing secrets is zeroed on drop, including spare capacity where applicable.
Access to secret data requires an explicit .expose_secret() call. There are no Deref implementations or other implicit access paths.
Cloning is opt-in and only available under the zeroize feature.
Installation
[]
= "0.7.0-rc.2"
Recommended configuration:
= { = "0.7.0-rc.2", = ["full"] }
Features
| Feature | Description |
|---|---|
zeroize |
Memory zeroing on drop and opt-in cloning via pre-baked cloneable types |
rand |
Random generation (FixedRng<N>::generate(), DynamicRng::generate()) |
ct-eq |
Constant-time equality comparison |
encoding |
All encoding support (encoding-hex, encoding-base64, encoding-bech32) |
encoding-hex |
Hex encoding, HexString, FixedRng hex methods |
encoding-base64 |
Base64String |
encoding-bech32 |
Bech32String (age-compatible Bech32 keys) |
full |
All optional features |
The crate is no_std-compatible with alloc. Features are optional and add no overhead when unused.
Security Model & Design Philosophy
secure-gate prioritizes auditability and explicitness over implicit convenience.
Every access to secret material — even inside the crate itself — goes through a method named .expose_secret() (or .expose_secret_mut()). This is deliberate:
- Makes every exposure site grep-able and obvious in code reviews
- Prevents accidental silent leaks or hidden bypasses
- Ensures consistent reasoning about secret lifetimes and memory handling
These calls are #[inline(always)] const fn reborrows — the optimizer elides them completely. There is zero runtime cost.
It's intentional "theatre" for humans and auditors, but free for the machine. Clarity of purpose wins over micro-optimizations.
Quick Start
use ;
fixed_alias!;
dynamic_alias!;
let pw: Password = "hunter2".into;
assert_eq!;
Opt-In Cloning
Cloning is available only when the zeroize feature is enabled.
The crate provides three ready-to-use cloneable primitives (zero boilerplate):
| Type | Allocation | Inner Data | Typical Use Case |
|---|---|---|---|
CloneableArray<const N: usize> |
Stack | [u8; N] |
Fixed-size keys/nonces |
CloneableString |
Heap | String |
Passwords, tokens, API keys |
CloneableVec |
Heap | Vec<u8> |
Seeds, variable-length binary |
Semantic Aliases (Recommended)
For better readability, create type aliases:
These are zero-cost and make intent crystal clear.
Minimizing Stack Exposure
When reading secrets from user input (e.g., passwords), use init_with/try_init_with to reduce temporary stack exposure:
The temporary is cloned to the heap and zeroized immediately.
Randomness
FixedRng<N> can only be constructed via cryptographically secure RNG.
Direct generation is also available:
Encoding
Encoding functions require explicit .expose_secret(). Invalid inputs to the .new() constructors are zeroed when the zeroize feature is enabled.
Constant-Time Equality
Available on Fixed<[u8; N]> and Dynamic<T> where T: AsRef<[u8]>.
Macros
use ;
fixed_alias!;
dynamic_alias!;
Memory Guarantees (zeroize enabled)
| Type | Allocation | Auto-zero | Full wipe | Slack eliminated | Notes |
|---|---|---|---|---|---|
Fixed<T> |
Stack | Yes | Yes | Yes (no heap) | |
Dynamic<T> |
Heap | Yes | Yes | No (until drop) | Use shrink_to_fit() |
FixedRng<N> |
Stack | Yes | Yes | Yes | |
HexString |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated hex |
Base64String |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated base64 |
Bech32String |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated Bech32 |
Performance
The wrappers add no runtime overhead compared to raw types in benchmarks.
Changelog
License
MIT OR Apache-2.0