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/Bech32m string wrapper With thezeroizefeature 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 noDerefimplementations or other implicit access paths. Cloning is opt-in and only available under thezeroizefeature.
Installation
[]
= "0.7.0-rc.4"
Recommended configuration:
= { = "0.7.0-rc.4", = ["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 (Bech32 and Bech32m variants; supports mixed-case input, stores lowercase) |
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 fnreborrows - 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/Bech32m |
Performance
The wrappers add no runtime overhead compared to raw types in benchmarks.
Changelog
License
MIT OR Apache-2.0