Skip to main content

secure_gate/traits/
mod.rs

1//! Traits for polymorphic secret handling.
2//!
3//! > **Note:** All traits in this module are re-exported at the crate root
4//! > (`secure_gate::RevealSecret`, not `secure_gate::traits::RevealSecret`).
5//! > You should never need to import from `secure_gate::traits::*` directly.
6//!
7//! This module defines the core traits that enable generic, zero-cost, and secure
8//! operations across different secret wrapper types (`Fixed<T>`, `Dynamic<T>`, etc.).
9//! These traits allow writing polymorphic code that preserves strong security invariants:
10//! explicit access, controlled mutability, timing safety, and opt-in risk features.
11//!
12//! # Core Traits
13//!
14//! | Trait                  | Purpose                                      | Requires Feature         | Notes                                                                 |
15//! |------------------------|----------------------------------------------|--------------------------|-----------------------------------------------------------------------|
16//! | [`RevealSecret`]       | Read-only scoped / direct access             | Always available         | Preferred: `with_secret` (scoped); escape hatch: `expose_secret`      |
17//! | [`SecretLen`]          | Length metadata (`len`, `byte_len`, …)       | Always available         | Only for `[T; N]`, `String`, `Vec<T>`; does not expose contents, but length can itself be sensitive — see trait docs |
18//! | [`RevealSecretMut`]    | Mutable scoped / direct access               | Always available         | Same preference: `with_secret_mut` over `expose_secret_mut`           |
19//! | [`SentinelValue`]      | Inert placeholder left by `into_inner`       | Always available         | Implemented for `[T; N]` (any `N`), `String`, `Vec<T>`                |
20//! | [`FixedStorage`]       | Asserts the inner type cannot reallocate     | Always available         | Required by `Fixed::new`. Implemented for primitives, `[T; N]`, small tuples and `Box<T>`; a custom inner type writes one line. `Vec`/`String` deliberately excluded |
21//! | [`ConstantTimeEq`]     | Deterministic constant-time equality         | `ct-eq`                  | Timing-attack resistant byte comparison                               |
22//! | [`CloneableSecret`]    | Opt-in marker for safe cloning               | `cloneable`              | Requires explicit impl on inner type; zeroize preserved. See [`SECURITY.md`](https://github.com/Slurp9187/secure-gate/blob/release/0.8/SECURITY.md) for opt-in risk details. |
23//! | [`SerializableSecret`] | Opt-in marker for Serde serialization        | `serde-serialize`        | Serialization exposes secret — use with extreme caution. See [`SECURITY.md`](https://github.com/Slurp9187/secure-gate/blob/release/0.8/SECURITY.md) for opt-in risk details. |
24//! | [`EncodableBytes`]     | Gates the encoder blanket impls              | Any `encoding-*`         | Load-bearing: every `To*` blanket is `T: AsRef<[u8]> + EncodableBytes`, which is what keeps `str`, `String` and [`EncodedSecret`] out |
25//! | [`SecureEncoding`]     | Vestigial marker for byte-shaped types       | Any `encoding-*`         | Auto-implemented for `T: AsRef<[u8]>`. Nothing in the crate bounds on it; the `To*` traits are gated by [`EncodableBytes`] |
26//! | [`SecureDecoding`]     | Vestigial marker for string-shaped types     | Any `encoding-*`         | Auto-implemented for `T: AsRef<str>`. Nothing in the crate bounds on it; the `From*Str` blankets are plain `AsRef<str>` |
27//!
28//! # Security Guarantees
29//!
30//! - **No implicit access while held** — Reaching a secret inside `Fixed`/`Dynamic`
31//!   requires an explicit trait method. `into_inner` ends that protection and hands
32//!   back the plain value; the encoders return [`EncodedSecret`], which derefs by design
33//! - **Scoped preference** — `with_secret` / `with_secret_mut` limit borrow lifetime
34//! - **Zero-cost** — All methods use `#[inline(always)]` where possible
35//! - **Timing safety** — `ConstantTimeEq` provides constant-time equality
36//! - **Opt-in risk** — Cloning and serialization require deliberate marker impls
37//! - **Read-only output** — [`EncodedSecret`] exposes its buffer only through `Deref`
38//!   and its two named consumers; there is no mutable access to encoded output
39//!
40//! # Feature Gates
41//!
42//! Some traits are only available when their corresponding Cargo features are enabled:
43//!
44//! - `ct-eq`          → [`ConstantTimeEq`]
45//! - `cloneable`      → [`CloneableSecret`]
46//! - `serde-serialize`→ [`SerializableSecret`]
47//! - `encoding-*`     → [`SecureEncoding`], [`SecureDecoding`], and per-format traits
48//!
49//! The encoding traits (`ToHex`, `FromHexStr`, etc.) are re-exported from submodules for convenience.
50//!
51//! See individual trait docs for detailed usage and examples.
52
53pub mod revealed_secrets;
54
55#[cfg(feature = "alloc")]
56pub use revealed_secrets::EncodedSecret;
57
58pub mod reveal_secret;
59pub use reveal_secret::{RevealSecret, SecretLen};
60
61pub mod reveal_secret_mut;
62pub use reveal_secret_mut::RevealSecretMut;
63
64pub mod fixed_storage;
65pub use fixed_storage::FixedStorage;
66
67pub mod sentinel_value;
68pub use sentinel_value::SentinelValue;
69
70#[cfg(feature = "ct-eq")]
71pub mod constant_time_eq;
72#[cfg(feature = "ct-eq")]
73pub use constant_time_eq::ConstantTimeEq;
74
75pub mod decoding;
76pub mod encoding;
77
78// Re-export per-format decoding traits (feature-gated; blanket impls return Vec<u8> — alloc required)
79#[cfg(all(feature = "encoding-base32", feature = "alloc"))]
80pub use decoding::FromBase32Str;
81
82#[cfg(all(feature = "encoding-base64", feature = "alloc"))]
83pub use decoding::FromBase64UrlStr;
84
85#[cfg(all(feature = "encoding-bech32", feature = "alloc"))]
86pub use decoding::FromBech32Str;
87
88#[cfg(all(feature = "encoding-bech32", feature = "alloc"))]
89pub use decoding::FromBech32mStr;
90
91#[cfg(all(feature = "encoding-hex", feature = "alloc"))]
92pub use decoding::FromHexStr;
93
94// Re-export per-format encoding traits (feature-gated)
95// Note: blanket impls of ToBase32, ToBase64Url, ToBech32, ToBech32m require alloc (String output).
96// Each trait is exported only with its own encoding feature *and* alloc, because every
97// encoder returns EncodedSecret and that type requires alloc.
98#[cfg(all(feature = "encoding-base32", feature = "alloc"))]
99pub use encoding::ToBase32;
100
101#[cfg(all(feature = "encoding-base64", feature = "alloc"))]
102pub use encoding::ToBase64Url;
103
104#[cfg(feature = "encoding-bech32")]
105pub use encoding::Case;
106
107#[cfg(all(feature = "encoding-bech32", feature = "alloc"))]
108pub use encoding::ToBech32;
109
110#[cfg(any(
111    feature = "encoding-hex",
112    feature = "encoding-base32",
113    feature = "encoding-base64",
114    feature = "encoding-bech32",
115))]
116pub use encoding::EncodableBytes;
117
118#[cfg(feature = "encoding-bech32")]
119pub use encoding::{Bech32Sized, Bech32Standard};
120
121#[cfg(feature = "encoding-bech32")]
122pub use encoding::{Bech32mSized, Bech32mStandard};
123
124#[cfg(feature = "encoding-bech32")]
125pub use encoding::{bech32_code_length, BECH32_CODE_LENGTH};
126
127#[cfg(all(feature = "encoding-bech32", feature = "alloc"))]
128pub use encoding::ToBech32m;
129
130#[cfg(all(feature = "encoding-hex", feature = "alloc"))]
131pub use encoding::ToHex;
132
133/// Marker trait for types that support secure encoding operations.
134///
135/// Automatically implemented for any type that implements `AsRef<[u8]>`,
136/// such as `&[u8]`, `Vec<u8>`, `[u8; N]`, etc.
137///
138/// It does **not** gate the encoding traits. Every `To*` blanket is bounded on
139/// `AsRef<[u8]> + `[`EncodableBytes`], and this marker is
140/// implemented for `str` and `String` too — precisely the types `EncodableBytes`
141/// exists to reject. Nothing in the crate bounds on this trait; the 0.9 line removed
142/// it. It is retained here for backwards compatibility.
143///
144/// Since this is a marker trait (no methods), it exists only to allow trait
145/// bounds and extension methods to be available where appropriate.
146///
147/// Requires at least one `encoding-*` feature to be enabled.
148#[cfg(any(
149    feature = "encoding-hex",
150    feature = "encoding-base32",
151    feature = "encoding-base64",
152    feature = "encoding-bech32",
153))]
154pub trait SecureEncoding {}
155
156#[cfg(any(
157    feature = "encoding-hex",
158    feature = "encoding-base32",
159    feature = "encoding-base64",
160    feature = "encoding-bech32",
161))]
162impl<T: AsRef<[u8]> + ?Sized> SecureEncoding for T {}
163
164/// Marker trait for types that support secure decoding operations.
165///
166/// Automatically implemented for any type that implements `AsRef<str>`,
167/// such as `&str`, `String`, etc.
168///
169/// It does **not** gate the decoding traits: each `From*Str` blanket is bounded on
170/// plain `AsRef<str>` and does not mention this marker. Nothing in the crate bounds
171/// on it; the 0.9 line removed it. Retained here for backwards compatibility.
172///
173/// Like `SecureEncoding`, this is a marker trait with no methods — it exists
174/// to allow trait bounds and extension methods where relevant.
175///
176/// Requires at least one `encoding-*` feature to be enabled.
177#[cfg(any(
178    feature = "encoding-hex",
179    feature = "encoding-base32",
180    feature = "encoding-base64",
181    feature = "encoding-bech32",
182))]
183pub trait SecureDecoding {}
184
185#[cfg(any(
186    feature = "encoding-hex",
187    feature = "encoding-base32",
188    feature = "encoding-base64",
189    feature = "encoding-bech32",
190))]
191impl<T: AsRef<str> + ?Sized> SecureDecoding for T {}
192
193#[cfg(feature = "cloneable")]
194pub mod cloneable_secret;
195#[cfg(feature = "cloneable")]
196pub use cloneable_secret::CloneableSecret;
197
198#[cfg(feature = "serde-serialize")]
199pub mod serializable_secret;
200#[cfg(feature = "serde-serialize")]
201pub use serializable_secret::SerializableSecret;