secure-gate
no_std-compatible wrappers for sensitive data with explicit, auditable exposure.
🔒 Security Notice: This crate has not undergone independent audit. Review the code and SECURITY.md before production use. Memory safety is guaranteed — no unsafe code (
#![forbid(unsafe_code)]).
secure-gate provides Dynamic<T> (heap-allocated) and Fixed<T> (stack-allocated) wrappers that force explicit access to secrets via .expose_secret() or scoped .with_secret() — preventing accidental leaks while remaining zero-cost and no_std + alloc compatible.
For zero-cost performance justification, see ZERO_COST_WRAPPERS.md.
Why secure-gate?
-
Orthogonal encoding/decoding — per-format traits (e.g.,
ToHex/FromHexStr) with symmetric APIs and umbrella traits for aggregation -
Extensible — adding new formats (e.g., base58) requires only one new trait pair + impls
-
Explicit exposure — no silent
Deref/AsRefleaks -
Zeroize on drop (
zeroizefeature) -
Timing-safe equality (
ct-eqfeature) -
Fast probabilistic equality for large secrets (
ct-eq-hash→ BLAKE3 + fixed digest compare) -
Secure random generation (
randfeature) -
Encoding (symmetric per-format traits: hex, base64url, bech32/BIP-173, bech32m/BIP-350) + serde direct deserialization (binary-safe)
-
Macros for ergonomic aliases (
dynamic_alias!,fixed_alias!) -
Auditable — every exposure and encoding call is grep-able
Installation
[]
= "0.7.0-rc.12" # or latest stable version
Recommended secure defaults:
= { = "0.7.0-rc.12", = ["secure"] } # zeroize + alloc
Batteries-included (most features):
= { = "0.7.0-rc.12", = ["full"] }
Minimal (no zeroize/ct-eq — discouraged for production):
= { = "0.7.0-rc.12", = false }
Features
| Feature | Description |
|---|---|
secure (default) |
Meta: zeroize + alloc (wiping + heap support) |
zeroize |
Zero memory on drop |
ct-eq |
ConstantTimeEq trait (prevents timing attacks) |
ct-eq-hash |
ConstantTimeEqExt trait: BLAKE3-based equality (fast for large/variable secrets) |
rand |
Secure random via OsRng (from_random()) |
serde |
Meta: serde-deserialize + serde-serialize |
serde-deserialize |
Direct deserialization to inner types (binary-safe) |
serde-serialize |
Export secrets (requires SerializableType marker on inner type) |
encoding |
Meta: symmetric per-format encoding/decoding (hex, base64url, bech32/bech32m) — granular sub-features available |
encoding-hex |
ToHex (.to_hex(), .to_hex_upper()) + FromHexStr (.try_from_hex()) |
encoding-base64 |
ToBase64Url (.to_base64url()) + FromBase64UrlStr (.try_from_base64url()) |
encoding-bech32 |
Enables Bech32 (BIP-173) encoding/decoding support via the bech32 crate. Also includes Bech32m compatibility. |
encoding-bech32m |
Enables strict Bech32m (BIP-350) support. Currently identical to encoding-bech32 (same dependency), but reserved for future strict variant separation or stricter validation. |
cloneable |
Opt-in cloning via CloneableType marker |
insecure |
Disables zeroize + ct-eq (testing/low-resource only — strongly discouraged) |
alloc |
Enables heap-dependent code (Dynamic<T>, Vec<String> support). Required for most real-world usage. Included in default. |
| no-alloc | Explicitly disables heap support (Dynamic<T>, Vec/String zeroize, encodings). Use for true no-heap/embedded builds. Conflicts with alloc (both can be enabled, but alloc takes precedence). |
std |
Enables std-specific enhancements (currently minimal; future-proof). Depends on alloc. |
full |
All of the above (convenient for development) |
no_std + alloc compatible. Disabled features have zero overhead.
Quick Feature Guide
| Goal | Features | Result |
|---|---|---|
| Default secure (heap + stack) | secure (default) |
Fixed<T> + Dynamic<T>, zeroize, alloc |
| Secure with no-heap | secure + no-alloc |
Fixed<T> only, zeroize |
| Minimal (discouraged) | no-alloc |
Fixed<T> only, no zeroize |
| Full featured | full |
All features enabled |
Heap vs No-Heap Builds
secure-gate defaults to heap-enabled (via secure pulling alloc):
= "0.7" # Fixed<T> + Dynamic<T> + zeroize/alloc
For no-heap / embedded (only Fixed<T>):
= { = "0.7", = false, = ["no-alloc"] } # Minimal, no-heap
# or with secure (zeroize on Fixed<T>):
= { = "0.7", = ["secure", "no-alloc"] }
Note: The "pass-through wrapper" principle holds for Fixed<T> in all builds (zero-cost explicit exposure + optional zeroize). Dynamic<T> requires heap and is unavailable in no-alloc mode.
Warning: Enabling both alloc and no-alloc features allows alloc to take precedence (e.g., with --all-features for docs generation or CI). Prefer enabling only one feature for predictable builds.
Quick Start
Note: Encoding API updated in 0.7.0 — old
SecureEncodingremoved in favor of per-format traits (e.g.,ToHex,FromHexStr). Existing code likedata.to_hex()still works via blanket impls. For new symmetric encoding/decoding, use individual traits or umbrellas (SecureEncoding/SecureDecoding). Prefer fallibletry_variants for encoding to avoid panics.
Security Model
- Explicit access only —
.with_secret()/.expose_secret()required - No implicit leaks — no
Deref/AsRef/Copyby default - Zeroize on drop (
zeroizefeature) - Timing-safe equality (optional
ct-eqfeature) - Probabilistic fast equality for big data (
hash-eq) - No unsafe code — enforced with
#![forbid(unsafe_code)]
Read SECURITY.md for threat model and mitigations.
Recommended Equality
Use ct_eq_auto — it automatically chooses the best method:
- Small inputs (≤32 bytes default): fast deterministic
ct_eq - Large/variable inputs: fast BLAKE3 hashing + digest compare
Performance Tuning: If benchmarks show a different optimal crossover point on your hardware (e.g., ct_eq remains faster up to 64 or 1024 bytes), customize with ct_eq_auto(&sig_b, Some(n)).
Plain ct_eq_hash is still available for uniform probabilistic behavior.
For detailed justification, benchmarks, and tuning guidance, see CT_EQ_AUTO.md.
Advanced Usage
Using Fixed and Dynamic Directly
For macro-averse users, use the types directly:
use ;
let key: = new;
key.with_secret;
Polymorphic / Generic Code
Write functions that work with any secure wrapper (Fixed<T> or Dynamic<T>) via the ExposeSecret trait:
use ExposeSecret;
Macros for Aliases
Dynamic Alias
Dynamic Generic Alias
Fixed Alias
use fixed_alias;
fixed_alias!;
Fixed Generic Alias
use fixed_generic_alias;
fixed_generic_alias!;
let buf: = .into;
Random Generation
Encoding (symmetric per-format traits)
secure-gate provides orthogonal, symmetric encoding/decoding traits for extensibility:
ToHex/FromHexStr: Hex encoding/decodingToBase64Url/FromBase64UrlStr: Base64url encoding/decodingToBech32/FromBech32Str: BIP-173 Bech32 encoding/decodingToBech32m/FromBech32mStr: BIP-350 Bech32m encoding/decoding
Umbrellas (SecureEncoding / SecureDecoding) aggregate all enabled traits for convenience. Each format is independent—adding base58 later requires only one new pair.
All methods are blanket-implemented over AsRef<[u8]> (encoding) or AsRef<str> (decoding) for zero-overhead ergonomics.
Serde (direct deserialization to inner types; serialization requires SerializableType)
See docs for full API.
License
MIT OR Apache-2.0