// ============================================================================
// secure-gate – Full library source + Cargo.toml
// Generated by: package_it.py
// Generated at: 2026-01-23 09:34:47.054
// ============================================================================

// ============================================================================
// TABLE OF CONTENTS
// ============================================================================
// 001. Cargo.toml
// 002. CHANGELOG.md
// 003. README.md
// 004. SECURITY.md
// 005. src/dynamic.rs
// 006. src/error.rs
// 007. src/fixed.rs
// 008. src/lib.rs
// 009. src/macros/dynamic_alias.rs
// 010. src/macros/dynamic_generic_alias.rs
// 011. src/macros/fixed_alias.rs
// 012. src/macros/fixed_generic_alias.rs
// 013. src/macros/mod.rs
// 014. src/traits/cloneable_type.rs
// 015. src/traits/constant_time_eq.rs
// 016. src/traits/expose_secret.rs
// 017. src/traits/expose_secret_mut.rs
// 018. src/traits/hash_eq.rs
// 019. src/traits/mod.rs
// 020. src/traits/secure_encoding.rs
// 021. src/traits/serializable_type.rs
// ============================================================================




================================================================================
// SECTION 001: Cargo.toml
// Created:  2026-01-06 16:42:07.300
// Modified: 2026-01-23 08:49:51.763
================================================================================
[package]
name = "secure-gate"
version = "0.7.0-rc.10"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Zero-cost secure wrappers for secrets — heap for dynamic, stack for fixed"
repository = "https://github.com/Slurp9187/secure-gate/tree/main"
documentation = "https://docs.rs/secure-gate"
keywords = ["crypto", "no-std", "security", "zeroize"]
categories = ["cryptography", "no-std", "data-structures"]

[dependencies]
base64 = { version = "0.22", optional = true }
bech32 = { version = "0.11", default-features = false, optional = true, features = ["alloc"] }
blake3 = { version = "1.8", optional = true, default-features = false }
hex = { version = "0.4", optional = true, features = ["alloc"] }
once_cell = { version = "1.19", optional = true, features = ["alloc"] }
rand = { version = "0.9", optional = true }
serde = { version = "1.0", optional = true, default-features = false, features = ["alloc", "derive"] }
subtle = { version = "2.5", optional = true }
thiserror = "2.0"
zeroize = { version = "1.7", default-features = false, optional = true, features = [
  "alloc",
  "zeroize_derive",
] }

[dev-dependencies]
criterion = { version = "0.8", features = ["html_reports"] }
proptest = "1.0"
serde_json = "1.0"
trybuild = "1.0"

# ──────────────────────────────────────────────────────────────
# Docs.rs metadata (enable features for online docs)
# ──────────────────────────────────────────────────────────────
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

# ──────────────────────────────────────────────────────────────
# Features
# ──────────────────────────────────────────────────────────────
[features]
# Default feature: Enforces secure handling with zeroization and constant-time operations
default = ["secure"]

# Secure: Essential for secure secret handling (includes zeroize and ct-eq)
secure = ["zeroize", "ct-eq"]

# Zeroize: Secure zeroing of secrets on drop or explicit calls (uses 'zeroize' crate with alloc and derives)
zeroize = ["dep:zeroize", "blake3/zeroize"]

# ct-eq: Constant-time equality checks (prevents timing attacks in comparisons; uses 'subtle' crate)
ct-eq = ["dep:subtle"]

# Hash-based equality (uses blake3 for fast, secure hashing without caching overhead)
hash-eq = ["ct-eq", "dep:blake3", "dep:once_cell"]

# Full: Meta-feature enabling all optional features for a complete, batteries-included setup
full = ["secure", "encoding", "hash-eq", "cloneable"]

# Insecure: Opt-out feature for no-default-features builds (disables zeroize, ct-eq; use only for testing/low-resource scenarios—strongly discouraged for production)
insecure = []

# Encoding: Secure conversions (hex/base64) for displaying or serializing secrets without leaks
encoding = ["encoding-hex", "encoding-base64", "encoding-bech32"]
# Hex encoding support (uses the 'hex' crate)
encoding-hex = ["dep:hex"]
# Base64 encoding support (uses the 'base64' crate)
encoding-base64 = ["dep:base64"]
# Bech32 encoding support (uses the 'bech32' crate)
encoding-bech32 = ["dep:bech32"]

# Rand: Random number generation for securely creating secrets (uses rand with getrandom for seeding; rand_core is transitive)
rand = ["dep:rand"]

# Cloneable: Opt-in safe cloning for secrets
cloneable = []

# Serde: Meta-feature enabling both deserialize and serialize
serde = ["serde-deserialize", "serde-serialize"]
# Serde deserialize: Enables serde Deserialize only (safe loading)
serde-deserialize = ["dep:serde"]
# Serde serialize: Enables serde Serialize only (requires SerializableSecret marker)
serde-serialize = ["dep:serde"]

[[bench]]
name = "fixed_vs_raw"
harness = false

[[bench]]
name = "hash_eq_vs_ct_eq"
harness = false

[[bench]]
name = "serde"
harness = false



================================================================================
// SECTION 002: CHANGELOG.md
// Created:  2026-01-20 06:27:19.452
// Modified: 2026-01-23 06:35:31.820
================================================================================
# Changelog

All changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),  
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0] - 2026-01-22

### Added
- **Security Hardening for Secret Wrappers**: Complete overhaul of `Dynamic<T>` and `Fixed<T>` with explicit exposure model. Added private `inner` fields, requiring all access through controlled methods. Introduced dual exposure API: scoped `with_secret` (recommended for safety) and direct `expose_secret` (auditable escape hatch). Prevents accidental leaks via long-lived borrows.
- **Opt-In Cloning**: New `CloneableType` marker trait for deliberate secret duplication. Independent of `zeroize` for embedded compatibility. Replaced implicit cloning with explicit marker implementation on inner types.
- **Opt-In Serialization**: Split `serde` into `serde-deserialize` and `serde-serialize` features. `Deserialize` for all wrappers with secure construction; `Serialize` gated behind `SerializableType` marker trait for user-opt-in export.
- **Polymorphic Traits**: Added `ExposeSecret` and `ExposeSecretMut` traits in `src/traits/` for generic secret access with metadata (length, emptiness) without exposing contents. Implemented for `Dynamic<T>` and `Fixed<T>` with zero-cost abstractions.
- **Enhanced Encoding System**: Replaced old conversions with `SecureEncoding` trait. Added `to_hex`, `to_hex_upper`, `to_base64url`, `to_bech32`, `to_bech32m` methods on any `AsRef<[u8]>` (including consuming `into_*` variants). Granular features: `encoding-hex`, `encoding-base64`, `encoding-bech32`, meta `encoding`.
- **Constant-Time Equality**: `ConstantTimeEq` trait in `src/traits/constant_time_eq` with `.ct_eq()` methods on `Fixed<[u8; N]>` and `Dynamic<T: AsRef<[u8]>>` for timing-attack resistance.
- **Random Generation**: `from_random()` on `Fixed<[u8; N]>` and `Dynamic<Vec<u8>>` for cryptographically secure initialization (panics on RNG failure, requires `rand`).
- **Error Handling Overhaul**: Centralized errors in `error.rs` with `thiserror`. Added `Bech32Error` (renamed from `Bech32EncodingError`) and `DecodingError` for unified failures. `SecureEncoding` now returns proper errors instead of panics.
- **Fallible Construction**: `impl TryFrom<&[u8]> for Fixed<[u8; N]>` with `FromSliceError` for safe slicing.
- **Testing Infrastructure**: Compile-fail tests with `trybuild` for invariant verification. Serde fuzz target (`fuzz_targets/serde.rs`) for deserialization security. CI matrix expanded to 8 feature combinations.
- **Documentation**: `SECURITY.md` with considerations and mitigations. Enhanced README with Security Checklist. Custom rustdoc support for all alias macros.
- **Conversions and Helpers**: `From<&str>` for `Dynamic<String>`, `From<&[u8]>` for `Dynamic<Vec<u8>>`. Zeroize integration with `Zeroize` and `ZeroizeOnDrop`.
- **No Unsafe Code Guarantee**: Unconditional `#![forbid(unsafe_code)]` across all builds, strengthening memory safety.

### Changed (Breaking)
- **Default Features**: Switched to `secure` meta-feature (`zeroize` + `ct-eq`) for secure-by-default. `insecure` for opt-out. `full` now `["secure", "encoding"]`.
- **Cloning Model**: Opt-in via `CloneableType` on inner types. No more implicit `Clone` on wrappers.
- **Serialization**: Opt-in via `SerializableType` marker. No automatic `Serialize` impls.
- **Exposure Model**: All access now explicit. No `Deref`, `AsRef`, or implicit borrowing. Direct `inner` access removed from public API.
- **Error Types**: Renamed and unified error enums. `from_slice` removed in favor of `try_from`.
- **Bech32**: Now fallible with `try_to_bech32`/`try_to_bech32m`, returning errors instead of panicking.

### Fixed
- **Doc-Tests**: Compatibility across all feature configurations.
- **Bech32 Robustness**: Improved variant detection and HRP handling.
- **Error Display**: Manual `Display`/`Error` impls for `FromSliceError` to replace deprecated traits.

### Removed
- **NoClone Wrappers**: `NoClone` types and `no_clone()` methods (replaced by opt-in model).
- **Redundant Methods**: `Dynamic::new_boxed()` (superseded by `From<Box<T>>`). `from_slice` on `Fixed<[u8; N]>` (panicking, use `try_from`).
- **Unsafe Code**: Conditional forbids removed; now forbidden unconditionally.
- **Old Encoding**: `RandomHex` type and conversions module replaced by `SecureEncoding`.
- **Implicit Behaviors**: Automatic `Clone`/`Serialize` on wrappers; replaced with markers.

## [0.6.1] - 2025-12-07

### Security

- **Removed `into_inner()` from `Fixed<T>`, `Dynamic<T>`, `FixedNoClone<T>`, and `DynamicNoClone<T>`**: This closes a security bypass that allowed extracting raw values without going through `expose_secret()` or `expose_secret_mut()`. All access to secret data must now be explicit and auditable through the security gate. When the `zeroize` feature is enabled, this also prevents bypassing `ZeroizeOnDrop` guarantees.
  - **Migration**: Replace `value.into_inner()` with `value.expose_secret()` or `value.expose_secret_mut()` as appropriate.
  - **Note**: `into_inner()` remains available on `FixedRng<N>` and `DynamicRng` as they return secure wrapper types (`Fixed`/`Dynamic`), not raw values. This is a type conversion, not a security escape.
- **Removed `finish_mut()` from `Dynamic<String>`, `Dynamic<Vec<T>>`, `DynamicNoClone<String>`, and `DynamicNoClone<Vec<T>>`**: These methods returned `&mut T` directly, bypassing the `expose_secret_mut()` security gate. This violates the core security principle that all secret access must be explicit and auditable.
  - **Migration**: Replace `secret.finish_mut()` with `secret.expose_secret_mut().shrink_to_fit()` to achieve the same functionality while maintaining security guarantees.

### Added

- **Ergonomic RNG conversions**: `FixedRng<N>` and `DynamicRng` can now be converted to `Fixed` and `Dynamic` via `.into()` or `.into_inner()`
  ```rust
  let key: Fixed<[u8; 32]> = FixedRng::<32>::generate().into();
  let random: Dynamic<Vec<u8>> = DynamicRng::generate(64).into();
  ```
- **Convenience random generation methods**: Direct generation methods on `Fixed` and `Dynamic` for ergonomic random secret creation
  ```rust
  let key: Fixed<[u8; 32]> = Fixed::generate_random();
  let random: Dynamic<Vec<u8>> = Dynamic::generate_random(64);
  ```

### Changed

- **Macro visibility syntax**: All type alias macros (`fixed_alias!`, `fixed_alias_rng!`, `dynamic_alias!`, etc.) now require explicit visibility specification in line with standard Rust semantics. The automatic `pub` fallback has been removed.

### Before

```rust
fixed_alias!(MyKey, 32);  // Automatically public (implicit behavior)
```

### After

```rust
fixed_alias!(pub MyKey, 32);          // Public type (explicit)
fixed_alias!(MyPrivateKey, 32);       // Private type (no visibility modifier)
fixed_alias!(pub(crate) Internal, 64); // Crate-visible type
```

### Fixed

- **Macro recursion**: Removed unnecessary recursive call in `dynamic_generic_alias!` macro, making it consistent with `fixed_generic_alias!` pattern

### Why

- Improves consistency with Rust's explicit visibility philosophy
- Eliminates surprising automatic behavior in macros
- Makes type visibility intentions clear and auditable
- Removes redundant macro branches, simplifying implementation
- Provides ergonomic conversion paths while preserving type-level security guarantees
- **Enforces the core security principle**: All secret access must be explicit, grep-able, and auditable through `expose_secret()` or `expose_secret_mut()`

### Migration

- Update macro invocations to explicitly specify visibility where needed. Add `pub` for types that should be publicly accessible.
- Replace any `into_inner()` calls on `Fixed<T>`, `Dynamic<T>`, `FixedNoClone<T>`, or `DynamicNoClone<T>` with `expose_secret()` or `expose_secret_mut()`.
- Replace any `finish_mut()` calls on `Dynamic<String>`, `Dynamic<Vec<T>>`, `DynamicNoClone<String>`, or `DynamicNoClone<Vec<T>>` with `expose_secret_mut().shrink_to_fit()`.

## [0.6.0] - 2025-12-06

### Breaking Changes

- Removed `Deref`/`DerefMut` from `Fixed<T>`.
- Made the inner field of `Fixed<T>` private.
- Removed inherent conversion methods (`.to_hex()`, `.to_hex_upper()`, `.to_base64url()`, `.ct_eq()`) from `Fixed<[u8; N]>` and aliases.
- Implemented `SecureConversionsExt` only on raw `[u8]` and `[u8; N]`, requiring explicit `.expose_secret()` for conversions.
- Removed deprecated direct-conversion shims from 0.5.x.
- Replaced `RandomBytes<N>` with `FixedRng<N>`, a newtype over `Fixed<[u8; N]>`.
- Removed `serde` feature; serialization requires user implementation.
- Switched RNG to direct `rand::rngs::OsRng` usage, removing `thread_local!` and `RefCell`.
- Removed all dependancies on `secrecy` as they were no longer necessary.

### Added

- `len()` and `is_empty()` on `Fixed<[u8; N]>`.

- Compile-time negative impl guard for `SecureConversionsExt` on wrapper types.
- `rand_core = { version = "0.9", optional = true }` dependency for `rand` feature.
- Direct `OsRng` calls in `FixedRng<N>::generate()` and `DynamicRng::generate()`.

### Fixed

- Lifetime issue in `FixedRng::<N>::random_hex()`.
- `ct_eq` bounds on fixed-size arrays, using `.as_slice()`.
- Updated tests and benchmarks to explicit `.expose_secret()`.
- Internal cleanups and dead code removal.

### Performance

- Benchmarks show `Fixed<[u8; 32]> + .expose_secret()` indistinguishable from raw `[u8; 32]` access on Intel i7-10510U (2019).
- Direct `OsRng` usage increases key generation throughput by 8–10% over prior `thread_local!` implementation.

## [0.5.10] - 2025-12-02

### Added

- `HexString` newtype in `conversions.rs` for type-safe, validated hex strings (requires "conversions" feature). Includes `.new()` with validation (even length, ascii hex digits, lowercase normalization), `.to_bytes()` for safe decoding, and `.byte_len()` property. Enforces `.expose_secret()` for access, aligning with safety rules.
- `RandomHex` newtype in `conversions.rs` for random hex strings (requires "rand + conversions"). Wraps `HexString`, inherits methods like `.to_bytes()` via Deref, enforces `.expose_secret()`. Constructor only via RNG for freshness.
- `PartialEq` and `Eq` impls for `Dynamic<T>` (bounded on T: PartialEq/Eq) in `dynamic.rs`—enables comparisons on dynamic secrets like `Dynamic<String>`.
- `RandomBytes<const N: usize>` newtype in `rng.rs` for semantically fresh random bytes (requires "rand" feature). Wraps `Fixed<[u8; N]>`, inherits methods via Deref, enforces `.expose_secret()`/`.expose_secret_mut()`.
- `random_alias!` macro in `macros.rs` for aliases on `RandomBytes<N>` (requires "rand" feature). Syntax: `random_alias!(Name, size);`—inherits `.new()` and deprecated shims; supports `.random_hex()` if "conversions" enabled.
- Comprehensive paranoia tests: `macros_paranoia_tests.rs` (all macros + edges) and `random_bytes_paranoia_tests.rs` (RandomBytes safety, deprecations, type distinctions).

### Changed

- Renamed randomness method to `.new()` in `rng.rs` for idiomatic constructors (Clippy-compliant). Added soft deprecations for `.random_bytes()` and `.random()` with friendly notes and doc aliases.
- Updated doc examples in `lib.rs` and `rng.rs` to use `random_alias!` and `.new()`.

### Fixed

- Privacy/import issues in tests (e.g., `use secure_gate::rng::{RandomBytes, SecureRandomExt};`).
- Doc-test failures by adding trait imports in examples.
- Test assertions in paranoia suites (e.g., expect different random values, not equal).
- Macro expansion/orphan rules by moving trait impls to `rng.rs` generics.
- Zeroize access in tests via `secrecy::ExposeSecret`.

## [0.5.9] - 2025-11-30

### Security & API Improvement — `conversions` feature

- **All conversion methods now require explicit `.expose_secret()`**  
  This is a deliberate breaking change to restore the crate’s core security invariant:  
  every access to secret bytes must be loud, visible, and grep-able.

  ```rust
  // v0.5.8 (deprecated)
  let hex = key.to_hex();

  // v0.5.9+ (required)
  let hex = key.expose_secret().to_hex();
  ```

  The same applies to `.to_hex_upper()`, `.to_base64url()`, and `.ct_eq()`.

- Direct methods on `Fixed<[u8; N]>` are **deprecated** and will be removed in v0.6.0.
- Old syntax continues to work with clear deprecation warnings.
- Compile-time test added: removing any `#[deprecated]` attribute now **fails CI**.
- Documentation and examples fully updated to teach the safe pattern.

This change eliminates a subtle but serious footgun while preserving ergonomics and backward compatibility during the 0.5.x series.

## [0.5.8] - 2025-11-29

### Added

- **New optional `conversions` feature** — the most requested ergonomics upgrade yet!
  - Adds `.to_hex()`, `.to_hex_upper()`, `.to_base64url()`, and `.ct_eq()` to **all** `Fixed<[u8; N]>` types and `fixed_alias!` types
  - Enabled with `features = ["conversions"]`
  - **Zero impact** on minimal or `no_std` builds — only compiled when requested
  - Perfect for:
    - Exporting keys to JSON (`to_base64url()`)
    - Logging/debugging (`to_hex()` with redacted `Debug`)
    - Secure equality checks (`ct_eq()` — timing-attack resistant)
  - Fully tested with real vectors and constant-time verification
  - Named consistently with `SecureRandomExt` → `SecureConversionsExt`

````rust
fixed_alias!(FileKey, 32);
let key = FileKey::random();
let password = Password::new(key.to_hex());        // beautiful
let export = key.to_base64url();                   // safe for JSON
assert!(key.ct_eq(&other_key));                    // secure

## [0.5.7] - 2025-11-27

### Added
- **New `rand` feature**: `SecureRandomExt::random()` for all `Fixed<[u8; N]>` and `fixed_alias!` types (#18)
  ```rust
  fixed_alias!(Aes256Key, 32);
  fixed_alias!(XChaCha20Nonce, 24);

  let key = Aes256Key::random();       // zero-cost, cryptographically secure
  let nonce = XChaCha20Nonce::random();
````

- Powered by thread-local `rand::rngs::OsRng` (lazy initialization)
- Uses modern `TryRngCore::try_fill_bytes` (rand 0.9+)
- No heap allocation, fully safe, `no_std`-compatible
- Panics on RNG failure (standard for high-assurance crypto code)
- Fully tested and Clippy-clean

### Documentation

- **Complete rustdoc overhaul** (#14)
  - Every public item now has clear, consistent, and fully-tested documentation
  - All examples compile under `--all-features` and `--no-default-features`
  - Added comprehensive module overviews, tables, security rationales, and idiomatic usage patterns
  - 100% passing `cargo test --doc`
  - Fixed all Clippy doc lint warnings

## [0.5.6] - 2025-04-05

### Added

- **Major ergonomics upgrade** – `Dynamic<T>` and `DynamicZeroizing<T>` now implement idiomatic `.into()` conversions:

  ```rust
  dynamic_alias!(Password, String);
  dynamic_alias!(JwtKey, Vec<u8>);

  // The dream syntax – just works!
  let pw: Password = "hunter2".into();                     // From<&str>
  let pw: Password = "hunter2".to_string().into();         // From<String>
  let key: JwtKey = secret_bytes.into();                   // From<Vec<u8>>

  // Zeroizing variants too!
  let pw: DynamicZeroizing<String> = "temp secret".into();
  let key: DynamicZeroizing<Vec<u8>> = vec![0u8; 32].into();
  ```

## [0.5.5] - 2025-08-10

### Changed

- **API: `view()` / `view_mut()` → `expose_secret()` / `expose_secret_mut()`**  
  The old `.view()` and `.view_mut()` methods are now **deprecated** and forward directly to the new canonical API:

  ```rust
  // Old (deprecated in 0.5.5, removed in 0.6.0)
  key.view()           // → &T
  key.view_mut()       // → &mut T

  // New — recommended
  key.expose_secret()      // → &T
  key.expose_secret_mut()  // → &mut T
  ```

## [0.5.4] - 2025-11-23

### Added

- `AsRef<[u8]>` and `AsMut<[u8]>` implementations for `Fixed<[u8; N]>`, enabling seamless integration with crates expecting slice references (e.g., cryptographic libraries like `aes` or `chacha20poly1305`). (Closes #13)

## [0.5.3] - 2025-11-24

### Changed

- Documentation polish & real-world proof
  - Added live Criterion benchmark report showing **zero overhead** on real hardware
  - Updated all examples and links to reflect final v0.5.x API
  - Changelog link now absolute (fixes broken link on docs.rs)

### Fixed

- Relative `CHANGELOG.md` link in README now points to the correct file on GitHub

## [0.5.2] - 2025-11-24

### Added

- `fixed_alias!` types now support idiomatic construction via `From` and `.into()`

  ```rust
  fixed_alias!(Aes256Key, 32);

  let key1 = Aes256Key::from(rng.gen());
  let key2: Aes256Key = rng.gen().into();  // natural, zero-cost, idiomatic
  ```

- All `fixed_alias!` types automatically inherit `from_slice` and `From<[u8; N]>` from generic impls on `Fixed`

### Changed

- Removed inherent impls from `fixed_alias!` macro (now uses crate-level generic impls)
  - Fixes orphan rule violations
  - Cleaner, more maintainable code
  - No behavior change for users

This release completes the ergonomics vision: `fixed_alias!` types now feel like first-class, built-in secret types.

## [0.5.1] - 2025-11-23

### Added

- New `secure!`, `secure_zeroizing!`, `fixed_alias!`, and `dynamic_alias!` macros for ergonomic secret creation
- Support for heap-based secrets via `secure!(String, ...)` and `secure!(Vec<u8>, ...)`
- `from_slice()` method and `From<[u8; N]>` impl on all `fixed_alias!` types
- `finish_mut()` helper emphasized for eliminating spare capacity in heap secrets
- Comprehensive macro test suite (`tests/macros_tests.rs`) with full feature-gate support

### Changed

- `fixed_alias!` now only emits the type alias; methods are provided via generic impls on `Fixed<[u8; N]>`
- Improved documentation of memory guarantees under the `zeroize` feature
- Macro tests now correctly gated behind `#[cfg(feature = "zeroize")]` to support `--no-default-features`

### Fixed

- README now accurately reflects that `zeroize` performs full-capacity wiping, but does not force deallocation or shrink capacity
- Resolved orphan rule violations in `fixed_alias!` macro
- Fixed privacy and feature-gating issues in test suite and re-exports

## [0.5.0] - 2025-11-22

### Breaking Changes

- Replaced `SecureGate<T>` with two honest types: `Fixed<T>` (stack/fixed-size) and `Dynamic<T>` (heap/dynamic).
- Removed `ZeroizeMode` and manual wiping — `zeroize` ≥1.8 handles spare capacity by default.
- Removed password specializations (`SecurePassword`, `SecurePasswordBuilder`) — use `Dynamic<String>`.
- Removed `unsafe-wipe` — safe by default.
- Migration guide in README.

### Added

- True zero-cost for fixed-size secrets when `zeroize` off (no heap allocation).
- `Deref` / `DerefMut` ergonomics — secrets borrow like normal types.
- `secure!` and `fixed_alias!` macros for constructors and aliases.
- `into_inner()` for extraction.
- `finish_mut()` with `shrink_to_fit` for `Dynamic<String>` / `Vec<u8>`.
- `Clone` for `Dynamic<T>`.

### Fixed

- No `unsafe` when `zeroize` off (`forbid(unsafe_code)`).
- Full spare-capacity wipe via `zeroize`.
- Consistent API across modes.

### Improved

- Modular structure (`fixed.rs`, `dynamic.rs`, `macros.rs`, `zeroize.rs`, `serde.rs`).
- 9 unit tests covering zero-cost, wiping, ergonomics, serde, macros.

## [0.4.3] - 2025-11-20

### Fixed

- Documentation mismatch: `CHANGELOG.md` and `README.md` now correctly reflect the changes shipped in 0.4.2
- No code changes — binary identical to 0.4.2

### Changes in 0.4.2 (now correctly documented)

- Fixed #27: Restored `.expose_secret()` and `.expose_secret_mut()` on `SecurePassword` and `SecurePasswordBuilder`
- `SecurePasswordBuilder` now supports full mutation (`push_str`, `push`, etc.) and `.build()`
- `SecureStackPassword` is now truly zero-heap using `zeroize::Zeroizing<[u8; 128]>`
- All password-specific accessors work correctly under `--no-default-features`
- Added `expose_secret_bytes()` / `expose_secret_bytes_mut()` (gated behind `unsafe-wipe`)
- Added comprehensive regression test suite (`tests/password_tests.rs`) with 8+ guards
- Zero warnings under `cargo clippy --all-features -- -D warnings`

## [0.4.1] - 2025-11-20

### Added

- Configurable zeroization modes via `ZeroizeMode` enum:
  - `Safe` (default) – wipes only used bytes (no unsafe code)
  - `Full` (opt-in via `unsafe-wipe` feature) – wipes entire allocation including spare capacity
  - `Passthrough` – relies solely on inner type's `Zeroize` impl
- New constructors:
  - `SecureGate::new_full_wipe(value)`
  - `SecureGate::new_passthrough(value)`
  - `SecureGate::with_mode(value, mode)`
- Full-capacity wiping now works correctly for `Vec<u8>` and `String` under `unsafe-wipe`

### Changed

- `SecureGate<T>` now stores zeroization mode (zero-cost for non-`Vec<u8>`/`String`)
- All zeroization logic unified through `Wipable` trait

### Fixed

- Empty but allocated vectors are now properly wiped in `Full` mode
- Clone preserves zeroization mode correctly

## [0.4.0] - 2025-11-20

### Breaking Changes (semver-minor)

- Unified all secure wrapper types under a single generic type: `SecureGate<T>`
- `SecureGate<T>` is now the canonical public name

### Added

- New short alias `SG<T>` for `SecureGate<T>`
- Fixed-size secrets use `zeroize::Zeroizing` directly when `stack` feature is enabled

### Deprecated

- Old names `Secure<T>` and `HeapSecure<T>` are now deprecated aliases

## [0.3.4] - 2025-11-18

### Documentation

- Updated README with correct `.expose_secret()` usage

## [0.3.3] - 2025-11-18

### Added

- Direct `.expose_secret()` and `.expose_secret_mut()` on password types

## [0.3.1] - 2025-11-17

### Changed

- Renamed `SecurePasswordMut` → `SecurePasswordBuilder`

## [0.3.0] - 2025-11-13

- Initial public release



================================================================================
// SECTION 003: README.md
// Created:  2026-01-20 06:27:20.495
// Modified: 2026-01-23 06:35:31.822
================================================================================
# 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](SECURITY.md) before production use. Memory safety is guaranteed—no unsafe code (`#![forbid(unsafe_code)]`).

- `Dynamic<T>` – Heap-allocated variable-size secrets (e.g., passwords, tokens).
- `Fixed<T>` – Stack-allocated fixed-size secrets (e.g., keys, hashes).

Zeroizes memory on drop (when `zeroize` enabled). All access requires explicit `.expose_secret()` or scoped `.with_secret()` – no implicit leaks.

## Installation

```toml
[dependencies]
secure-gate = "0.7.0-rc.10"
```

**Secure defaults** (recommended):
```toml
secure-gate = "0.7.0-rc.10"  # Enables "secure" meta-feature (zeroize + ct-eq)
```

**Batteries-included**:
```toml
secure-gate = { version = "0.7.0-rc.10", features = ["full"] }
```

**Minimal** (no zeroization/ct-eq – **discouraged for production**):
```toml
secure-gate = { version = "0.7.0-rc.10", default-features = false }
```

## Features

| Feature              | Description                                                                                          |
|----------------------|------------------------------------------------------------------------------------------------------|
| `secure` (default)   | Meta-feature: `zeroize` + `ct-eq` (secure wiping + timing-safe equality)                              |
| `zeroize`            | Zeroizes memory on drop; enables safe cloning via `CloneableType`                                    |
| `ct-eq`              | `ConstantTimeEq` trait for timing-attack-resistant comparisons                                       |
| `hash-eq`            | `HashEq` trait: BLAKE3 hashing for large secrets (probabilistic safety)                               |
| `rand`               | Random generation (`from_random()`) via `OsRng`                                                       |
| `serde`              | Meta-feature: `serde-deserialize` + `serde-serialize`                                                 |
| `serde-deserialize`  | Load secrets via serde (auto-detects hex/base64/bech32)                                               |
| `serde-serialize`    | Export secrets via serde (gated by `SerializableType` marker)                                         |
| `encoding`           | Meta-feature: `encoding-hex` + `encoding-base64` + `encoding-bech32`                                  |
| `encoding-hex`       | Hex encoding/decoding (`to_hex()`, `to_hex_upper()`)                                                  |
| `encoding-base64`    | Base64 URL-safe encoding (`to_base64url()`)                                                           |
| `encoding-bech32`    | Bech32/Bech32m with HRP validation (`to_bech32()`, `try_to_bech32()`)                                  |
| `cloneable`          | `CloneableType` marker for opt-in cloning                                                              |
| `full`               | Meta-feature: `secure` + `encoding` + `hash-eq` + `cloneable`                                          |

`no_std` + `alloc` compatible. Features are zero-overhead when disabled.

## Security Model

Prioritizes **explicitness** and **auditability**:
- **No implicit access**: Requires `.expose_secret()`, `.expose_secret_mut()`, or scoped `.with_secret()`/`.with_secret_mut()`.
- **Dual exposure**: Scoped closures prevent long-lived leaks; direct refs are grep-able escape hatches.
- **Opt-in risks**: Cloning/serialization via markers (`CloneableType`, `SerializableType`).
- **Zero overhead**: Explicit calls are inlined/elided; no runtime cost for security.
- **No unsafe code**: Forbidden unconditionally.

See [SECURITY.md](SECURITY.md) for details.

## Quick Start

```rust
use secure_gate::{fixed_alias, dynamic_alias, ExposeSecret, ExposeSecretMut};
extern crate alloc;

dynamic_alias!(pub Password, String);   // Dynamic<String>
fixed_alias!(pub Aes256Key, 32);       // Fixed<[u8; 32]>

let mut pw: Password = "secret".into();
let key: Aes256Key = [42u8; 32].into();

// Scoped access (preferred, prevents leaks)
let len = pw.with_secret(|s| s.len());

// Direct access (auditable)
assert_eq!(pw.expose_secret(), "secret");
let key_bytes = key.expose_secret();  // &[u8; 32]

// Mutable access
pw.with_secret_mut(|s| s.push('!'));
pw.expose_secret_mut().clear();
```

## Polymorphic Traits

Generic code across wrappers:

- **`ExposeSecret`/`ExposeSecretMut`**: Controlled access with length/is_empty metadata.
- **`ConstantTimeEq`**: Timing-safe byte equality.
- **`HashEq`**: Probabilistic BLAKE3-based equality for large data.
- **`SecureEncoding`**: String encoding/decoding.

```rust
use secure_gate::{Dynamic, Fixed, ExposeSecret};
extern crate alloc;

fn check_len<T: ExposeSecret>(secret: &T) -> usize {
    secret.len()  // Generic over Dynamic/Fixed
}
```

```rust
#[cfg(feature = "ct-eq")]
{
    use secure_gate::{Fixed, ConstantTimeEq};

    let a: Fixed<[u8; 32]> = [0; 32].into();
    let b: Fixed<[u8; 32]> = [1; 32].into();
    assert!(!a.ct_eq(&b));  // Timing-safe
}
```

## Random Generation (`rand`)

Secure random bytes via system entropy.

```rust
#[cfg(feature = "rand")]
{
    use secure_gate::{Fixed, Dynamic};
    extern crate alloc;

    let data: Dynamic<Vec<u8>> = Dynamic::from_random(64);
    let key: Fixed<[u8; 32]> = Fixed::from_random();

    // Panics on RNG failure
}
```

## Encoding (`encoding-*`)

Explicit string conversions via `SecureEncoding` trait.

**Outbound** (to strings):
```rust
#[cfg(feature = "encoding-hex")]
{
    use secure_gate::SecureEncoding;
    let hex = [0u8; 16].to_hex();  // "0000000000000000"
}

#[cfg(feature = "encoding-base64")]
{
    use secure_gate::SecureEncoding;
    let b64 = b"hello".to_base64url();  // "aGVsbG8"
}

#[cfg(feature = "encoding-bech32")]
{
    use secure_gate::SecureEncoding;
    let bech32 = b"test".to_bech32("bc");  // "bc1qtest..."
}
```

**Inbound** (from strings via serde auto-detection):
```rust
#[cfg(all(feature = "serde-deserialize", feature = "encoding-hex"))]
{
    use secure_gate::Dynamic;
    extern crate alloc;

    let key: Dynamic<Vec<u8>> = serde_json::from_str(r#""deadbeef""#).expect("Failed to decode hex string");
}

#[cfg(all(feature = "serde-deserialize", feature = "encoding-bech32"))]
{
    use secure_gate::Dynamic;
    let result: Result<Dynamic<Vec<u8>>, _> = serde_json::from_str(r#""bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4""#);
}
```

Bech32 includes fallible `try_to_bech32()` for error handling.

## Equality

**Constant-Time (`ct-eq`)**: Direct byte comparison via `subtle`.
```rust
#[cfg(feature = "ct-eq")]
{
    use secure_gate::Fixed;
    let a: Fixed<[u8; 32]> = [0; 32].into();
    let b: Fixed<[u8; 32]> = [1; 32].into();
    assert!(!a.ct_eq(&b));  // Timing-safe
}
```

**Hash-Based (`hash-eq`)**: BLAKE3 + ct-eq on digest (better for large secrets).
```rust
#[cfg(feature = "hash-eq")]
{
    use secure_gate::{Fixed, HashEq};
    let a: Fixed<[u8; 32]> = [1; 32].into();
    let b: Fixed<[u8; 32]> = [1; 32].into();
    let c: Fixed<[u8; 32]> = [2; 32].into();
    assert!(a.hash_eq(&b));
    assert!(!a.hash_eq(&c));
}
```

`==` is not implemented—use these for security.

## Opt-In Cloning (`cloneable`)

Mark types for cloning with `CloneableType`.
```rust
#[cfg(feature = "cloneable")]
{
    use secure_gate::CloneableType;

    #[derive(Clone)]
    struct MyKey([u8; 32]);

    impl CloneableType for MyKey {}  // Opt-in

    let key = MyKey([0; 32]);
    let copy = key.clone();  // Now allowed
}
```

## Opt-In Serialization (`serde-serialize`)

Mark types for serde export with `SerializableType`.
```rust
#[cfg(feature = "serde-serialize")]
{
    use secure_gate::{Dynamic, SerializableType};
    use serde::Serialize;
    extern crate alloc;

    #[derive(Serialize)]
    struct RawKey(Vec<u8>);

    impl SerializableType for RawKey {}

    let key = RawKey(vec![1, 2, 3]);
    let wrapped: Dynamic<RawKey> = key.into();
    let json = serde_json::to_string(&wrapped).unwrap();  // Allowed
}
```

## Construction

**Dynamic** (flexible):
```rust
use secure_gate::Dynamic;
extern crate alloc;

let dyn_vec: Dynamic<Vec<u8>> = [1, 2, 3].as_slice().into();  // Infallible copy
let dyn_str: Dynamic<String> = "hello".into();  // Infallible
```

**Fixed** (exact sizes):
```rust
use secure_gate::Fixed;

let fixed: Fixed<[u8; 4]> = [1, 2, 3, 4].into();  // Infallible
let tried: Result<Fixed<[u8; 4]>, _> = [1, 2, 3, 4].try_into();  // Fallible alternative
```

## Macros

Require explicit visibility (`pub`, `pub(crate)`, etc.).

### Basic Aliases
```rust
use secure_gate::{fixed_alias, dynamic_alias};

fixed_alias!(pub AesKey, 32);
dynamic_alias!(pub Password, String);
```

### With Custom Docs
```rust
use secure_gate::{fixed_alias, dynamic_alias};

dynamic_alias!(pub Token, Vec<u8>, "OAuth token");
fixed_alias!(pub ApiKey, 32, "Service API key");
```

### Generic Aliases

```rust
use secure_gate::{dynamic_generic_alias, fixed_generic_alias};
extern crate alloc;

dynamic_generic_alias!(Secret);
fixed_generic_alias!(Buffer);
```

### With Custom Docs (Generic)

```rust
use secure_gate::{dynamic_generic_alias, fixed_generic_alias};

dynamic_generic_alias!(pub Token, "OAuth token");
fixed_generic_alias!(pub ApiKey, "Service API key");
```

## Memory & Performance

**Zeroization** (`zeroize`):
- Heap: `Dynamic<T>` wipes full allocation, including slack (best-effort, not guaranteed in all environments).
- Stack: `Fixed<T>` wipes on drop.

**Performance**: Zero overhead—wrappers inline to raw types. Explicit exposure elided by optimizer.

## License

MIT OR Apache-2.0



================================================================================
// SECTION 004: SECURITY.md
// Created:  2026-01-20 06:27:20.560
// Modified: 2026-01-23 06:35:31.822
================================================================================
# Security Considerations for secure-gate

## TL;DR
- **No independent security audit** — review the code yourself before production use.
- **Default feature set**: `secure` meta-feature (`zeroize` + `ct-eq` enabled for secure-by-default).
- **Explicit exposure required**: Scoped `with_secret()`/`with_secret_mut()` (recommended) or direct `expose_secret()`/`expose_secret_mut()` calls for all access — zero-cost, fully elided by optimizer.
- **Memory zeroization**: On drop (including spare capacity in `Vec`/`String`) when `zeroize` feature is enabled.
- **Opt-in behaviors**: Cloning/serialization require marker traits (`CloneableType`/`SerializableType`) — no implicit risks.
- **No unsafe code**: Unconditionally forbidden (`#![forbid(unsafe_code)]`).
- **Vulnerability reporting**: Use GitHub Security tab (private preferred, public acceptable).

This document summarizes security-relevant design choices, strengths, potential weaknesses, and review points for the `secure-gate` crate. It is intended for developers performing threat modeling or security reviews.

## Audit Status
`secure-gate` has **not** undergone independent security audit.  
The implementation relies on vetted dependencies (`zeroize`, `subtle`, `blake3`, `rand`, encoding crates like `bech32`, `hex`, `base64`).  
**Review source code, tests, and dependencies** before using in security-critical applications.

## Core Security Model
- **Explicit exposure only** — Scoped `with_secret()`/`with_secret_mut()` (prevents leaks via closures) or direct `expose_secret()`/`expose_secret_mut()` (auditable escape hatches); no `Deref`, `AsRef`, or implicit borrowing paths.
- **Zeroization on drop** — Enabled via `zeroize` feature; wipes full backing buffer (including slack capacity in `Vec`/`String`).
- **No unsafe code** — `#![forbid(unsafe_code)]` enforced unconditionally across all builds.
- **Redacted Debug** — Prevents accidental secret leakage via `{:?}` formatting.
- **Timing-safe equality** — `ConstantTimeEq` trait (via `ct-eq` feature) for byte-level comparisons; `HashEq` for large/variable secrets; `==` not supported (use timing-safe alternatives).
- **Opt-in risky behaviors** — Cloning/serialization require marker traits (`CloneableType`/`SerializableType`); no automatic exposure.
- **Marker-based security** — Traits like `CloneableType` ensure deliberate opt-in, reducing accidental risks.
- **Encoding with validation** — Explicit methods; zeroizes invalid inputs; fallible Bech32 with HRP checks.

## Feature Security Implications

| Feature             | Security Impact                                                                 | Recommendation                                      |
|---------------------|---------------------------------------------------------------------------------|-----------------------------------------------------|
| `secure` (default)  | Meta-feature enabling `zeroize` + `ct-eq` — baseline for safety                 | Always enable unless extreme constraints            |
| `zeroize`           | Zeroes memory on drop; enables safe opt-in behaviors                           | Strongly recommended                                |
| `ct-eq`             | `ConstantTimeEq` trait for timing-safe comparisons                              | Strongly recommended; avoid `==`                    |
| `hash-eq`           | `HashEq` trait: BLAKE3 hashing + ct-eq on digest; probabilistic safety for large data | Use for performance on large secrets; prefer `ct-eq` for small |
| `rand`              | `OsRng` for secure randomness; `from_random()` methods                          | Ensure OS entropy is secure; panics handled         |
| `serde`             | Meta-feature enabling both `serde-deserialize` and `serde-serialize`           | Enable only when serializing secrets is necessary   |
| `serde-deserialize` | Load secrets from strings; temporary buffers zeroized on failure               | Enable only for trusted sources                     |
| `serde-serialize`   | Opt-in export via `SerializableType` marker; audit all impls                   | Enable sparingly; monitor for exfiltration          |
| `encoding`          | Meta-feature enabling all `encoding-*` features                                | Validate inputs upstream                            |
| `encoding-hex`      | Hex encoding/decoding; fallible; zeroizes invalids                             | Validate inputs upstream                            |
| `encoding-base64`   | Base64 encoding/decoding; fallible; zeroizes invalids                          | Validate inputs upstream                            |
| `encoding-bech32`   | Bech32/Bech32m with HRP validation; fallible                                    | Use for BIP173-compliant strings                    |
| `cloneable`         | `CloneableType` marker for duplication; increases exposure                      | Use minimally; prefer move semantics               |
| `full`              | Meta-feature enabling all features for complete functionality                   | Use for development; audit for production           |
| `insecure`          | Disables `zeroize` and `ct-eq` for testing/low-resource; strongly discouraged   | Never use in production                             |

## Module-by-Module Security Notes

### Core Wrappers (`dynamic.rs`, `fixed.rs`)
- **Strengths**
  - Private `inner` fields prevent direct access; all exposure via audited methods.
  - Dual exposure: Scoped `with_secret()` closures limit borrow lifetimes; direct `expose_secret()` is grep-able.
  - No `Deref`/`AsRef` prevents silent conversions or implicit borrowing.
  - Zeroization (via `zeroize`) wipes full capacity on drop.
- **Weaknesses**
  - User code can call `expose_secret()` and hold long-lived refs (defeating scoping).
  - Macro-generated aliases lack runtime checks—audit generated types.
  - Errors may leak length metadata (e.g., expected vs. actual sizes).
- **Mitigations**
  - Audit all `expose_secret()` calls; prefer `with_secret()`.
  - Use compile-time assertions in macros.
  - Contextualize error handling to avoid side-channel leaks.

### Polymorphic Traits (`traits/`)
- **Strengths**
  - `ExposeSecret`/`ExposeSecretMut`: Generic, zero-cost access with metadata.
  - Marker traits (`CloneableType`, `SerializableType`): Force opt-in for risky ops.
  - `ConstantTimeEq`/`HashEq`: Safe equality options.
- **Weaknesses**
  - Generic impls assume input trustworthiness.
- **Mitigations**
  - Audit custom marker impls; validate inputs.

### Encoding & Errors (`traits/secure_encoding.rs`, `error.rs`)
- **Strengths**
  - `SecureEncoding`: Explicit, type-safe encoding/decoding.
  - Errors (`Bech32Error`, `DecodingError`): Typed, minimal metadata; fallible ops prevent panics.
  - Bech32 with HRP validation prevents injection attacks.
- **Weaknesses**
  - Decoding allocates temps; invalid inputs zeroized but may reveal format attempts.
  - Lengths in errors could be sensitive.
- **Mitigations**
  - Upstream input validation; fuzz tests.
  - Wrap errors in sensitive contexts.

### Other Modules
- **Dependencies**: Rely on audited crates (`zeroize`, `subtle`, etc.); monitor for CVEs.
- **Random Generation**: `OsRng` panics on failure—mitigate with trusted environments.
- **Serde**: Opt-in deserialize from trusted sources; audit serialize impls.

## Best Practices
- **Enable defaults**: Use `secure` meta-feature unless constraints prohibit it.
- **Audit exposure**: Grep all `with_secret()`, `expose_secret()`, `expose_secret_mut()` calls—prefer scoped access.
- **Use aliases**: Leverage `dynamic_alias!`, `fixed_alias!` for semantic types.
- **Limit risky ops**: Avoid cloning/serialization unless necessary; audit all marker impls.
- **Input validation**: Check upstream before encoding/decoding; trust no inputs.
- **Monitor deps**: Keep dependencies updated; review CVE reports.
- **Code review**: Treat secrets like radioactive—explicit, minimal exposure.
- **Testing**: Run with all features; use fuzzing for parsers.

## Vulnerability Reporting
- **Preferred**: GitHub private vulnerability reporting (Security tab → Report a vulnerability).
- **Alternative**: Draft or public issue.
- **Response target**: 48 hours.
- **Disclosure**: Public after coordinated fix.

## Disclaimer
This document reflects design intent and observed properties as of January 2026.  
**No warranties provided**. Users are responsible for their own security evaluation and audit.



================================================================================
// SECTION 005: src/dynamic.rs
// Created:  2026-01-20 06:27:03.727
// Modified: 2026-01-23 09:27:52.516
================================================================================
extern crate alloc;

use alloc::boxed::Box;
#[cfg(all(feature = "serde-deserialize", feature = "encoding-base64"))]
use base64::{engine::general_purpose, Engine};

#[cfg(feature = "rand")]
use rand::TryRngCore;

/// Local implementation of bit conversion for Bech32, since bech32 crate doesn't expose it in v0.11.
#[cfg(all(feature = "serde-deserialize", feature = "encoding-bech32"))]
fn convert_bits(
    from: u8,
    to: u8,
    pad: bool,
    data: &[u8],
) -> Result<(alloc::vec::Vec<u8>, usize), ()> {
    if !(1..=8).contains(&from) || !(1..=8).contains(&to) {
        return Err(());
    }
    let mut acc = 0u64;
    let mut bits = 0u8;
    let mut ret = alloc::vec::Vec::new();
    let maxv = (1u64 << to) - 1;
    let _max_acc = (1u64 << (from + to - 1)) - 1;
    for &v in data {
        if ((v as u32) >> from) != 0 {
            return Err(());
        }
        acc = (acc << from) | (v as u64);
        bits += from;
        while bits >= to {
            bits -= to;
            ret.push(((acc >> bits) & maxv) as u8);
        }
    }
    if pad {
        if bits > 0 {
            ret.push(((acc << (to - bits)) & maxv) as u8);
        }
    } else if bits >= from || ((acc << (to - bits)) & maxv) != 0 {
        return Err(());
    }
    Ok((ret, bits as usize))
}

/// Helper function to try decoding a string as bech32, hex, or base64 in priority order.
#[cfg(feature = "serde-deserialize")]
fn try_decode(_s: &str) -> Result<alloc::vec::Vec<u8>, crate::DecodingError> {
    #[cfg(feature = "encoding-bech32")]
    if let Ok((_, data)) = ::bech32::decode(_s) {
        let (converted, _) =
            convert_bits(5, 8, false, &data).map_err(|_| crate::DecodingError::InvalidBech32)?;
        return Ok(converted);
    }
    #[cfg(feature = "encoding-hex")]
    if let Ok(data) = ::hex::decode(_s) {
        return Ok(data);
    }

    #[cfg(feature = "encoding-base64")]
    if let Ok(data) = general_purpose::URL_SAFE_NO_PAD.decode(_s) {
        return Ok(data);
    }

    Err(crate::DecodingError::InvalidEncoding)
}

/// Dynamic-sized heap-allocated secure secret wrapper.
///
/// This is a thin wrapper around `Box<T>` with enforced explicit exposure.
/// Suitable for dynamic-sized secrets like `String` or `Vec<u8>`.
/// The inner field is private, forcing all access through explicit methods.
///
/// Security invariants:
/// - No `Deref` or `AsRef` — prevents silent access.
/// - `Debug` is always redacted.
/// - With `zeroize`, wipes the entire allocation on drop (including spare capacity).
///
/// # Examples
///
/// Basic usage:
/// ```
/// use secure_gate::{Dynamic, ExposeSecret};
/// let secret: Dynamic<String> = "hunter2".into();
/// assert_eq!(secret.expose_secret(), "hunter2");
/// ```
///
/// With already-boxed values:
/// ```
/// use secure_gate::{Dynamic, ExposeSecret};
/// let boxed_secret = Box::new("hunter2".to_string());
/// let secret: Dynamic<String> = boxed_secret.into(); // or Dynamic::from(boxed_secret)
/// assert_eq!(secret.expose_secret(), "hunter2");
/// ```
///
/// Mutable access:
/// ```
/// use secure_gate::{Dynamic, ExposeSecret, ExposeSecretMut};
/// let mut secret = Dynamic::<String>::new("pass".to_string());
/// secret.expose_secret_mut().push('!');
/// assert_eq!(secret.expose_secret(), "pass!");
/// ```
///
/// With `zeroize` (automatic wipe):
/// With `zeroize` feature (automatic wipe on drop):
/// ```
/// # #[cfg(feature = "zeroize")]
/// # {
/// use secure_gate::Dynamic;
/// let secret = Dynamic::<Vec<u8>>::new(vec![1u8; 32]);
/// drop(secret); // heap allocation wiped automatically
/// # }
/// ```
pub struct Dynamic<T: ?Sized> {
    inner: Box<T>,
}

impl<T: ?Sized> Dynamic<T> {
    /// Wrap a value by boxing it.
    ///
    /// Uses `Into<Box<T>>` for flexibility.
    #[inline(always)]
    pub fn new<U>(value: U) -> Self
    where
        U: Into<Box<T>>,
    {
        let inner = value.into();
        Self { inner }
    }
}

#[cfg(feature = "cloneable")]
impl<T: crate::CloneableType> Clone for Dynamic<T> {
    fn clone(&self) -> Self {
        Self::new(self.inner.clone())
    }
}

#[cfg(feature = "serde-serialize")]
impl<T: crate::SerializableType> serde::Serialize for Dynamic<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.inner.serialize(serializer)
    }
}

impl crate::ExposeSecret for Dynamic<String> {
    type Inner = String;

    #[inline(always)]
    fn with_secret<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&String) -> R,
    {
        f(&self.inner)
    }

    #[inline(always)]
    fn expose_secret(&self) -> &String {
        &self.inner
    }

    #[inline(always)]
    fn len(&self) -> usize {
        self.inner.len()
    }
}

impl<T> crate::ExposeSecret for Dynamic<Vec<T>> {
    type Inner = Vec<T>;

    #[inline(always)]
    fn with_secret<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&Vec<T>) -> R,
    {
        f(&self.inner)
    }

    #[inline(always)]
    fn expose_secret(&self) -> &Vec<T> {
        &self.inner
    }

    #[inline(always)]
    fn len(&self) -> usize {
        self.inner.len() * core::mem::size_of::<T>()
    }
}

impl crate::ExposeSecretMut for Dynamic<String> {
    #[inline(always)]
    fn with_secret_mut<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut String) -> R,
    {
        f(&mut self.inner)
    }

    #[inline(always)]
    fn expose_secret_mut(&mut self) -> &mut String {
        &mut self.inner
    }
}

impl<T> crate::ExposeSecretMut for Dynamic<Vec<T>> {
    #[inline(always)]
    fn with_secret_mut<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Vec<T>) -> R,
    {
        f(&mut self.inner)
    }

    #[inline(always)]
    fn expose_secret_mut(&mut self) -> &mut Vec<T> {
        &mut self.inner
    }
}

#[cfg(feature = "ct-eq")]
impl<T> crate::ConstantTimeEq for Dynamic<T>
where
    T: crate::ConstantTimeEq,
{
    fn ct_eq(&self, other: &Self) -> bool {
        (*self.inner).ct_eq(&*other.inner)
    }
}

#[cfg(feature = "hash-eq")]
impl<T> crate::HashEq for Dynamic<T>
where
    T: AsRef<[u8]>,
{
    fn hash_eq(&self, other: &Self) -> bool {
        #[cfg(feature = "rand")]
        {
            use once_cell::sync::Lazy;
            use rand::{rngs::OsRng, TryRngCore};
            static HASH_EQ_KEY: Lazy<[u8; 32]> = Lazy::new(|| {
                let mut key = [0u8; 32];
                let mut rng = OsRng;
                rng.try_fill_bytes(&mut key).unwrap();
                key
            });
            let mut self_hasher = blake3::Hasher::new_keyed(&HASH_EQ_KEY);
            let mut other_hasher = blake3::Hasher::new_keyed(&HASH_EQ_KEY);
            self_hasher.update((*self.inner).as_ref());
            other_hasher.update((*other.inner).as_ref());
            use crate::ConstantTimeEq;
            self_hasher
                .finalize()
                .as_bytes()
                .ct_eq(other_hasher.finalize().as_bytes())
        }
        #[cfg(not(feature = "rand"))]
        {
            let self_hash = blake3::hash((*self.inner).as_ref());
            let other_hash = blake3::hash((*other.inner).as_ref());
            use crate::ConstantTimeEq;
            self_hash.as_bytes().ct_eq(other_hash.as_bytes())
        }
    }
}

/// # Ergonomic helpers for common heap types
impl Dynamic<String> {}
impl<T> Dynamic<Vec<T>> {}

// From impls for Dynamic types
impl<T: ?Sized> From<Box<T>> for Dynamic<T> {
    /// Wrap a boxed value in a [`Dynamic`] secret.
    #[inline(always)]
    fn from(boxed: Box<T>) -> Self {
        Self { inner: boxed }
    }
}

impl From<&[u8]> for Dynamic<Vec<u8>> {
    /// Wrap a byte slice in a [`Dynamic`] [`Vec<u8>`].
    #[inline(always)]
    fn from(slice: &[u8]) -> Self {
        Self::new(slice.to_vec())
    }
}

impl From<&str> for Dynamic<String> {
    /// Wrap a string slice in a [`Dynamic`] [`String`].
    #[inline(always)]
    fn from(input: &str) -> Self {
        Self::new(input.to_string())
    }
}

impl<T: 'static> From<T> for Dynamic<T> {
    /// Wrap a value in a [`Dynamic`] secret by boxing it.
    #[inline(always)]
    fn from(value: T) -> Self {
        Self {
            inner: Box::new(value),
        }
    }
}

// Optional Hash impls for collections (use HashEq for explicit equality checks)
#[cfg(feature = "hash-eq")]
impl core::hash::Hash for Dynamic<alloc::vec::Vec<u8>> {
    /// WARNING: Using Dynamic in HashMap/HashSet enables implicit equality via hash collisions.
    /// This is probabilistic and NOT cryptographically secure. Prefer HashEq::hash_eq() for secrets.
    /// Rate-limit or avoid in untrusted contexts due to DoS potential.
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        use blake3::hash;
        let hash_bytes = *hash(self.inner.as_slice()).as_bytes();
        hash_bytes.hash(state);
    }
}

#[cfg(feature = "hash-eq")]
impl core::hash::Hash for Dynamic<alloc::string::String> {
    /// WARNING: Using Dynamic in HashMap/HashSet enables implicit equality via hash collisions.
    /// This is probabilistic and NOT cryptographically secure. Prefer HashEq::hash_eq() for secrets.
    /// Rate-limit or avoid in untrusted contexts due to DoS potential.
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        use blake3::hash;
        let hash_bytes = *hash(self.inner.as_bytes()).as_bytes();
        hash_bytes.hash(state);
    }
}

// Macro-generated implementations
// Constant-time equality for Dynamic types
#[cfg(feature = "ct-eq")]
impl Dynamic<String> {
    /// Constant-time equality comparison.
    ///
    /// Compares the byte contents of two instances in constant time
    /// to prevent timing attacks.
    #[inline]
    pub fn ct_eq(&self, other: &Self) -> bool {
        use crate::traits::ConstantTimeEq;
        self.inner.as_bytes().ct_eq(other.inner.as_bytes())
    }
}

#[cfg(feature = "ct-eq")]
impl Dynamic<Vec<u8>> {
    /// Constant-time equality comparison.
    ///
    /// Compares the byte contents of two instances in constant time
    /// to prevent timing attacks.
    #[inline]
    pub fn ct_eq(&self, other: &Self) -> bool {
        use crate::traits::ConstantTimeEq;
        self.inner.as_slice().ct_eq(other.inner.as_slice())
    }
}

// Redacted Debug implementation
impl<T: ?Sized> core::fmt::Debug for Dynamic<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str("[REDACTED]")
    }
}

// Macro-generated constructor implementations
// Random generation — only available with `rand` feature.
#[cfg(feature = "rand")]
impl Dynamic<alloc::vec::Vec<u8>> {
    /// Fill with fresh random bytes of the specified length using the System RNG.
    ///
    /// Panics on RNG failure for fail-fast crypto code. Guarantees secure entropy
    /// from system sources.
    ///
    /// # Example
    ///
    /// ```
    /// # #[cfg(feature = "rand")]
    /// # {
    /// use secure_gate::{Dynamic, ExposeSecret};
    /// let random: Dynamic<Vec<u8>> = Dynamic::from_random(64);
    /// assert_eq!(random.len(), 64);
    /// # }
    /// ```
    #[inline]
    pub fn from_random(len: usize) -> Self {
        let mut bytes = vec![0u8; len];
        rand::rngs::OsRng
            .try_fill_bytes(&mut bytes)
            .expect("OsRng failure is a program error");
        Self::from(bytes)
    }
}

// Serde deserialization for Dynamic<Vec<u8>> with auto-decoding, and simple delegation for others
#[cfg(feature = "serde-deserialize")]
impl<'de> serde::Deserialize<'de> for Dynamic<alloc::vec::Vec<u8>> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use alloc::fmt;
        use serde::de::{self, Visitor};

        struct DynamicVecVisitor;

        impl<'de> Visitor<'de> for DynamicVecVisitor {
            type Value = Dynamic<alloc::vec::Vec<u8>>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a hex/base64/bech32 string or byte vector")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                let bytes = try_decode(v).map_err(E::custom)?;
                Ok(Dynamic::new(bytes))
            }
        }

        if deserializer.is_human_readable() {
            deserializer.deserialize_str(DynamicVecVisitor)
        } else {
            let vec: alloc::vec::Vec<u8> = serde::Deserialize::deserialize(deserializer)?;
            Ok(Dynamic::new(vec))
        }
    }
}

// Serde deserialization for Dynamic<String>
#[cfg(feature = "serde-deserialize")]
impl<'de> serde::Deserialize<'de> for Dynamic<String> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s: String = serde::Deserialize::deserialize(deserializer)?;
        Ok(Dynamic::new(s))
    }
}

// Zeroize integration
#[cfg(feature = "zeroize")]
impl<T: ?Sized + zeroize::Zeroize> zeroize::Zeroize for Dynamic<T> {
    fn zeroize(&mut self) {
        self.inner.zeroize();
    }
}

/// Zeroize on drop integration
#[cfg(feature = "zeroize")]
impl<T: ?Sized + zeroize::Zeroize> zeroize::ZeroizeOnDrop for Dynamic<T> {}



================================================================================
// SECTION 006: src/error.rs
// Created:  2026-01-20 06:27:03.781
// Modified: 2026-01-23 06:35:31.834
================================================================================
// secure-gate\src\error.rs

//! Centralized error types for the secure-gate crate.

/// Error type for slice conversion operations.
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
pub enum FromSliceError {
    #[error("slice length mismatch: expected {expected}, got {got}")]
    LengthMismatch { expected: usize, got: usize },
}

#[cfg(feature = "encoding-bech32")]
/// Error type for Bech32 operations (encoding and decoding).
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum Bech32Error {
    #[error("invalid Human-Readable Part (HRP)")]
    InvalidHrp,
    #[error("bit conversion failed")]
    ConversionFailed,
    #[error("bech32 operation failed")]
    OperationFailed,
    #[error("unexpected HRP: expected {expected}, got {got}")]
    UnexpectedHrp { expected: String, got: String },
}

#[cfg(feature = "encoding-base64")]
/// Error type for Base64 decoding operations.
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
pub enum Base64Error {
    #[error("invalid base64 string")]
    InvalidBase64,
}

#[cfg(feature = "encoding-hex")]
/// Error type for Hex decoding operations.
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
pub enum HexError {
    #[error("invalid hex string")]
    InvalidHex,
}

/// Unified error type for decoding operations across formats.
#[derive(Clone, Debug, thiserror::Error)]
pub enum DecodingError {
    #[cfg(feature = "encoding-bech32")]
    #[error("invalid bech32 string")]
    InvalidBech32,
    #[cfg(feature = "encoding-base64")]
    #[error("invalid base64 string")]
    InvalidBase64,
    #[cfg(feature = "encoding-hex")]
    #[error("invalid hex string")]
    InvalidHex,
    #[error(
        "invalid encoding: string does not match any supported format (bech32, hex, or base64)"
    )]
    InvalidEncoding,
}



================================================================================
// SECTION 007: src/fixed.rs
// Created:  2026-01-20 06:27:03.964
// Modified: 2026-01-23 09:28:05.635
================================================================================
#[cfg(feature = "rand")]
use rand::TryRngCore;

/// Local implementation of bit conversion for Bech32, since bech32 crate doesn't expose it in v0.11.
#[cfg(all(feature = "serde-deserialize", feature = "encoding-bech32"))]
fn convert_bits(
    from: u8,
    to: u8,
    pad: bool,
    data: &[u8],
) -> Result<(alloc::vec::Vec<u8>, usize), ()> {
    if !(1..=8).contains(&from) || !(1..=8).contains(&to) {
        return Err(());
    }
    let mut acc = 0u64;
    let mut bits = 0u8;
    let mut ret = alloc::vec::Vec::new();
    let maxv = (1u64 << to) - 1;
    let _max_acc = (1u64 << (from + to - 1)) - 1;
    for &v in data {
        if ((v as u32) >> from) != 0 {
            return Err(());
        }
        acc = (acc << from) | (v as u64);
        bits += from;
        while bits >= to {
            bits -= to;
            ret.push(((acc >> bits) & maxv) as u8);
        }
    }
    if pad {
        if bits > 0 {
            ret.push(((acc << (to - bits)) & maxv) as u8);
        }
    } else if bits >= from || ((acc << (to - bits)) & maxv) != 0 {
        return Err(());
    }
    Ok((ret, bits as usize))
}

#[cfg(all(feature = "serde-deserialize", feature = "encoding-base64"))]
use base64::{engine::general_purpose, Engine};

/// Helper function to try decoding a string as bech32, hex, or base64 in priority order.
#[cfg(feature = "serde-deserialize")]
fn try_decode(_s: &str) -> Result<alloc::vec::Vec<u8>, crate::DecodingError> {
    #[cfg(feature = "encoding-bech32")]
    if let Ok((_, data)) = ::bech32::decode(_s) {
        let (converted, _) =
            convert_bits(5, 8, false, &data).map_err(|_| crate::DecodingError::InvalidBech32)?;
        return Ok(converted);
    }
    #[cfg(feature = "encoding-hex")]
    if let Ok(data) = ::hex::decode(_s) {
        return Ok(data);
    }

    #[cfg(feature = "encoding-base64")]
    if let Ok(data) = Engine::decode(&general_purpose::URL_SAFE_NO_PAD, _s) {
        return Ok(data);
    }

    Err(crate::DecodingError::InvalidEncoding)
}

/// Fixed-size stack-allocated secure secret wrapper.
///
/// This is a zero-cost wrapper for fixed-size secrets like byte arrays or primitives.
/// The inner field is private, forcing all access through explicit methods.
///
/// Security invariants:
/// - No `Deref` or `AsRef` — prevents silent access or borrowing.
/// - No implicit `Copy` — even for `[u8; N]`, duplication must be explicit via `.clone()`.
/// - `Debug` is always redacted.
///
/// # Examples
///
/// Basic usage:
/// ```
/// use secure_gate::{Fixed, ExposeSecret};
/// let secret = Fixed::new([42u8; 1]);
/// assert_eq!(secret.expose_secret()[0], 42);
/// ```
///
/// For byte arrays (most common):
/// ```
/// use secure_gate::{fixed_alias, Fixed, ExposeSecret};
/// fixed_alias!(Aes256Key, 32);
/// let key_bytes = [0x42u8; 32];
/// let key: Aes256Key = Fixed::from(key_bytes);
/// assert_eq!(key.len(), 32);
/// assert_eq!(key.expose_secret()[0], 0x42);
/// ```
///
/// With `zeroize` feature (automatic wipe on drop):
/// ```
/// # #[cfg(feature = "zeroize")]
/// # {
/// use secure_gate::Fixed;
/// let mut secret = Fixed::new([1u8, 2, 3]);
/// drop(secret); // stack memory wiped automatically
/// # }
/// ```
pub struct Fixed<T> {
    inner: T,
}

impl<T> Fixed<T> {
    /// Wrap a value in a `Fixed` secret.
    ///
    /// This is zero-cost and const-friendly.
    ///
    /// Wrap a value in a Fixed secret.
    ///
    /// This is zero-cost and const-friendly.
    ///
    /// # Example
    ///
    /// ```
    /// use secure_gate::Fixed;
    /// const SECRET: Fixed<u32> = Fixed::new(42);
    /// ```
    #[inline(always)]
    pub const fn new(value: T) -> Self {
        Fixed { inner: value }
    }
}

#[cfg(feature = "cloneable")]
impl<T: crate::CloneableType> Clone for Fixed<T> {
    fn clone(&self) -> Self {
        Self::new(self.inner.clone())
    }
}

#[cfg(feature = "serde-serialize")]
impl<T: crate::SerializableType> serde::Serialize for Fixed<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.inner.serialize(serializer)
    }
}

impl<const N: usize, T> crate::ExposeSecret for Fixed<[T; N]> {
    type Inner = [T; N];

    #[inline(always)]
    fn with_secret<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&[T; N]) -> R,
    {
        f(&self.inner)
    }

    #[inline(always)]
    fn expose_secret(&self) -> &[T; N] {
        &self.inner
    }

    #[inline(always)]
    fn len(&self) -> usize {
        N * core::mem::size_of::<T>()
    }
}

impl<const N: usize, T> crate::ExposeSecretMut for Fixed<[T; N]> {
    #[inline(always)]
    fn with_secret_mut<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut [T; N]) -> R,
    {
        f(&mut self.inner)
    }

    #[inline(always)]
    fn expose_secret_mut(&mut self) -> &mut [T; N] {
        &mut self.inner
    }
}

#[cfg(feature = "ct-eq")]
impl<T> crate::ConstantTimeEq for Fixed<T>
where
    T: crate::ConstantTimeEq,
{
    fn ct_eq(&self, other: &Self) -> bool {
        self.inner.ct_eq(&other.inner)
    }
}

#[cfg(feature = "hash-eq")]
impl<T> crate::HashEq for Fixed<T>
where
    T: AsRef<[u8]>,
{
    fn hash_eq(&self, other: &Self) -> bool {
        #[cfg(feature = "rand")]
        {
            use once_cell::sync::Lazy;
            use rand::{rngs::OsRng, TryRngCore};
            static HASH_EQ_KEY: Lazy<[u8; 32]> = Lazy::new(|| {
                let mut key = [0u8; 32];
                let mut rng = OsRng;
                rng.try_fill_bytes(&mut key).unwrap();
                key
            });
            let mut self_hasher = blake3::Hasher::new_keyed(&HASH_EQ_KEY);
            let mut other_hasher = blake3::Hasher::new_keyed(&HASH_EQ_KEY);
            self_hasher.update(self.inner.as_ref());
            other_hasher.update(other.inner.as_ref());
            use crate::ConstantTimeEq;
            self_hasher
                .finalize()
                .as_bytes()
                .ct_eq(other_hasher.finalize().as_bytes())
        }
        #[cfg(not(feature = "rand"))]
        {
            let self_hash = blake3::hash(self.inner.as_ref());
            let other_hash = blake3::hash(other.inner.as_ref());
            use crate::ConstantTimeEq;
            self_hash.as_bytes().ct_eq(other_hash.as_bytes())
        }
    }
}

/// # Byte-array specific helpers
impl<const N: usize> Fixed<[u8; N]> {}

// Fallible conversion from byte slice.
impl<const N: usize> core::convert::TryFrom<&[u8]> for Fixed<[u8; N]> {
    type Error = crate::error::FromSliceError;

    /// Attempt to create a `Fixed` from a byte slice, returning an error on length mismatch.
    ///
    /// This is the safe alternative to panicking conversions.
    ///
    /// # Example
    ///
    /// ```
    /// use secure_gate::Fixed;
    /// let slice: &[u8] = &[1u8, 2, 3, 4];
    /// let key: Result<Fixed<[u8; 4]>, _> = slice.try_into();
    /// assert!(key.is_ok());
    ///
    /// let short_slice: &[u8] = &[1u8, 2];
    /// let fail: Result<Fixed<[u8; 4]>, _> = short_slice.try_into();
    /// assert!(fail.is_err());
    /// ```
    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
        if slice.len() != N {
            return Err(crate::error::FromSliceError::LengthMismatch {
                expected: N,
                got: slice.len(),
            });
        }
        let mut arr = [0u8; N];
        arr.copy_from_slice(slice);
        Ok(Self::new(arr))
    }
}

impl<const N: usize> From<[u8; N]> for Fixed<[u8; N]> {
    /// Wrap a raw byte array in a `Fixed` secret.
    ///
    /// Zero-cost conversion.
    ///
    /// # Example
    ///
    /// ```
    /// use secure_gate::Fixed;
    /// let key: Fixed<[u8; 4]> = [1, 2, 3, 4].into();
    /// ```
    #[inline(always)]
    fn from(arr: [u8; N]) -> Self {
        Self::new(arr)
    }
}

// Fallible conversion from byte slice.

/// Custom serde deserialization for byte arrays with auto-detection of hex/base64/bech32 strings.
#[cfg(feature = "serde-deserialize")]
impl<'de, const N: usize> serde::Deserialize<'de> for Fixed<[u8; N]> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use serde::de::{self, Visitor};
        use std::fmt;

        struct FixedVisitor<const M: usize>;

        impl<'de, const M: usize> Visitor<'de> for FixedVisitor<M> {
            type Value = Fixed<[u8; M]>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(
                    formatter,
                    "a hex/base64/bech32 string or byte array of length {}",
                    M
                )
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                let bytes = try_decode(v).map_err(E::custom)?;
                if bytes.len() != M {
                    return Err(E::invalid_length(bytes.len(), &M.to_string().as_str()));
                }
                let mut arr = [0u8; M];
                arr.copy_from_slice(&bytes);
                Ok(Fixed::new(arr))
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::SeqAccess<'de>,
            {
                let mut vec = alloc::vec::Vec::with_capacity(M);
                while let Some(value) = seq.next_element()? {
                    vec.push(value);
                }
                if vec.len() != M {
                    return Err(serde::de::Error::invalid_length(
                        vec.len(),
                        &M.to_string().as_str(),
                    ));
                }
                let mut arr = [0u8; M];
                arr.copy_from_slice(&vec);
                Ok(Fixed::new(arr))
            }
        }

        deserializer.deserialize_any(FixedVisitor::<N>)
    }
}

// Random generation — only available with `rand` feature.
#[cfg(feature = "rand")]
impl<const N: usize> Fixed<[u8; N]> {
    /// Generate a secure random instance (panics on failure).
    ///
    /// Fill with fresh random bytes using the System RNG.
    /// Panics on RNG failure for fail-fast crypto code. Guarantees secure entropy
    /// from system sources.
    ///
    /// # Example
    ///
    /// ```
    /// # #[cfg(feature = "rand")]
    /// # {
    /// use secure_gate::{Fixed, ExposeSecret};
    /// let random: Fixed<[u8; 32]> = Fixed::from_random();
    /// assert_eq!(random.len(), 32);
    /// # }
    /// ```
    #[inline]
    pub fn from_random() -> Self {
        let mut bytes = [0u8; N];
        rand::rngs::OsRng
            .try_fill_bytes(&mut bytes)
            .expect("OsRng failure is a program error");
        Self::from(bytes)
    }
}

// Constant-time equality
#[cfg(feature = "ct-eq")]
impl<const N: usize> Fixed<[u8; N]> {
    /// Constant-time equality comparison.
    ///
    /// This is the **only safe way** to compare two fixed-size secrets.
    /// Available only when the `ct-eq` feature is enabled.
    ///
    /// # Example
    ///
    /// ```
    /// # #[cfg(feature = "ct-eq")]
    /// # {
    /// use secure_gate::Fixed;
    /// let a = Fixed::new([1u8; 32]);
    /// let b = Fixed::new([1u8; 32]);
    /// assert!(a.ct_eq(&b));
    /// # }
    /// ```
    #[inline]
    pub fn ct_eq(&self, other: &Self) -> bool {
        use crate::traits::ConstantTimeEq;
        self.inner.ct_eq(&other.inner)
    }
}

// Optional Hash impl for collections (use HashEq for explicit equality checks)
#[cfg(feature = "hash-eq")]
impl<T: AsRef<[u8]>> core::hash::Hash for Fixed<T> {
    /// WARNING: Using Fixed in HashMap/HashSet enables implicit equality via hash collisions.
    /// This is probabilistic and NOT cryptographically secure. Prefer HashEq::hash_eq() for secrets.
    /// Rate-limit or avoid in untrusted contexts due to DoS potential.
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        use blake3::hash;
        let hash_bytes = *hash(self.inner.as_ref()).as_bytes();
        hash_bytes.hash(state);
    }
}

// Redacted Debug implementation
impl<T> core::fmt::Debug for Fixed<T> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str("[REDACTED]")
    }
}

// Serde deserialization for generic Fixed<T> (simple delegation)

// Zeroize integration
#[cfg(feature = "zeroize")]
impl<T: zeroize::Zeroize> zeroize::Zeroize for Fixed<T> {
    fn zeroize(&mut self) {
        self.inner.zeroize();
    }
}

/// Zeroize on drop integration
#[cfg(feature = "zeroize")]
impl<T: zeroize::Zeroize> zeroize::ZeroizeOnDrop for Fixed<T> {}



================================================================================
// SECTION 008: src/lib.rs
// Created:  2026-01-20 06:27:04.017
// Modified: 2026-01-23 09:20:21.086
================================================================================
// uncomment for doctest runs
// #![doc = include_str!("../EXAMPLES.md")]
// #![doc = include_str!("../README.md")]

// Forbid unsafe code unconditionally
#![forbid(unsafe_code)]
//! Zero-cost secure wrappers for secrets — [`Dynamic<T>`] for heap-allocated variable-length data,
//! [`Fixed<T>`] for stack-allocated fixed-size data.
//!
//! This crate provides explicit, guarded wrappers for sensitive values (e.g. keys, tokens, ciphertexts)
//! with controlled exposure via `.expose_secret()` / `.expose_secret_mut()`. No accidental leaks via
//! `Deref`, `AsRef`, or implicit conversions.
//!
//! See [README.md](../README.md) for usage examples, feature overview, and macros for custom aliases.
//!
//! ## Equality Options
//!
//!
//! [`ConstantTimeEq`] (via `ct-eq` feature): Direct byte-by-byte constant-time comparison using `subtle`.
//! Best for small/fixed-size secrets (< ~256–512 bytes) where speed matters most.
//!
//! [`HashEq`] (via `hash-eq` feature): BLAKE3 hash -> constant-time compare on fixed 32-byte digest.
//! Faster for large/variable secrets (e.g. ML-KEM ciphertexts ~1–1.5 KiB, ML-DSA signatures ~2–4 KiB),
//! with length hiding and optional keyed mode (`rand` for per-process random key).
//!
//! See the HashEq trait documentation for performance numbers, security properties (probabilistic, timing-safe), and guidance on when to choose each (or hybrid).
extern crate alloc;

/// Dynamic secret wrapper types - always available with zero dependencies.
/// These provide fundamental secure storage abstractions for dynamic data.
mod dynamic;

/// Fixed-size secret wrapper types - always available with zero dependencies.
/// These provide fundamental secure storage abstractions for fixed-size data.
mod fixed;

/// Centralized error types - always available.
mod error;

/// Core traits for wrapper polymorphism - always available.
mod traits;

/// Re-export of the [`Dynamic`] type.
pub use dynamic::Dynamic;
/// Re-export of the [`Fixed`] type.
pub use fixed::Fixed;

#[cfg(feature = "cloneable")]
pub use traits::CloneableType;
/// Re-export of the traits.
#[cfg(feature = "ct-eq")]
pub use traits::ConstantTimeEq;
#[cfg(feature = "hash-eq")]
pub use traits::HashEq;
#[cfg(feature = "serde-serialize")]
pub use traits::SerializableType;
pub use traits::{ExposeSecret, ExposeSecretMut};

/// Type alias macros (always available).
/// Convenient macros for creating custom secret wrapper types.
mod macros;

/// Available macros (exported globally for convenience):
/// - `dynamic_alias!`: Create type aliases for heap-allocated secrets (`Dynamic<T>`).
/// - `dynamic_generic_alias!`: Create generic heap-allocated secret aliases.
/// - `fixed_alias!`: Create type aliases for fixed-size secrets (`Fixed<[u8; N]>`).
/// - `fixed_generic_alias!`: Create generic fixed-size secret aliases.
///   Re-export of [`SecureEncoding`] trait for convenient encoding extensions.
///   Re-export of the [`SecureEncoding`] trait.
#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub use traits::SecureEncoding;

/// Re-export of [`Bech32Error`] for convenience when using bech32 encoding/decoding.
#[cfg(feature = "encoding-bech32")]
pub use error::Bech32Error;

/// Re-export of [`Base64Error`] for convenience when using base64 decoding.
#[cfg(feature = "encoding-base64")]
pub use error::Base64Error;

/// Re-export of [`HexError`] for convenience when using hex decoding.
#[cfg(feature = "encoding-hex")]
pub use error::HexError;

/// Re-export of [`DecodingError`] for convenience in decoding operations.
pub use error::DecodingError;



================================================================================
// SECTION 009: src/macros/dynamic_alias.rs
// Created:  2026-01-23 06:35:31.835
// Modified: 2026-01-23 06:35:31.835
================================================================================
/// Creates a type alias for a dynamic-sized heap-allocated secure secret.
///
/// This macro generates a type alias to `Dynamic<T>` with optional visibility and custom documentation.
/// The generated type inherits all methods from `Dynamic`, including `.expose_secret()`.
///
/// # Syntax
///
/// - `dynamic_alias!(vis Name, Type);` — visibility required (e.g., `pub`, `pub(crate)`, or omit for private)
/// - `dynamic_alias!(vis Name, Type, doc);` — with optional custom doc string
///
/// # Examples
///
/// Public alias:
/// ```
/// use secure_gate::{dynamic_alias, ExposeSecret};
/// dynamic_alias!(pub Password, String);
/// let pw: Password = "hunter2".into();
/// assert_eq!(pw.expose_secret(), "hunter2");
/// ```
///
/// Private alias:
/// ```
/// use secure_gate::{dynamic_alias, ExposeSecret};
/// dynamic_alias!(SecretString, String); // No visibility modifier = private
/// let secret: SecretString = "hidden".to_string().into();
/// assert_eq!(secret.expose_secret(), "hidden");
/// ```
///
/// With custom visibility:
/// ```
/// use secure_gate::dynamic_alias;
/// dynamic_alias!(pub(crate) InternalSecret, String); // Crate-visible
/// ```
///
/// With custom documentation:
/// ```
/// use secure_gate::{dynamic_alias, ExposeSecret};
/// dynamic_alias!(pub Token, Vec<u8>, "OAuth token for API access");
/// let token: Token = vec![1, 2, 3].into();
/// assert_eq!(token.expose_secret(), &[1, 2, 3]);
/// ```
///
/// The generated type is zero-cost and works with all features.
/// For random initialization, use `Type::from_random(n)` (requires 'rand' feature).
#[macro_export]
macro_rules! dynamic_alias {
    ($vis:vis $name:ident, $inner:ty, $doc:literal) => {
        #[doc = $doc]
        $vis type $name = $crate::Dynamic<$inner>;
    };
    ($vis:vis $name:ident, $inner:ty) => {
        #[doc = concat!("Secure heap-allocated ", stringify!($inner))]
        $vis type $name = $crate::Dynamic<$inner>;
    };
    ($name:ident, $inner:ty, $doc:literal) => {
        #[doc = $doc]
        type $name = $crate::Dynamic<$inner>;
    };
    ($name:ident, $inner:ty) => {
        #[doc = concat!("Secure heap-allocated ", stringify!($inner))]
        type $name = $crate::Dynamic<$inner>;
    };
}



================================================================================
// SECTION 010: src/macros/dynamic_generic_alias.rs
// Created:  2026-01-23 06:35:31.835
// Modified: 2026-01-23 06:35:31.835
================================================================================
/// Creates a generic dynamic-sized heap-allocated secure secret type.
///
/// This macro generates a type alias to `Dynamic<T>` with a custom doc string.
/// Useful for libraries providing generic dynamic-sized secret wrappers.
///
/// # Examples
///
/// With custom doc:
/// ```
/// use secure_gate::dynamic_generic_alias;
/// dynamic_generic_alias!(pub SecureVec, "Secure dynamic byte vector");
/// ```
///
/// With default doc:
/// ```
/// use secure_gate::dynamic_generic_alias;
/// dynamic_generic_alias!(pub(crate) Wrapper);
/// ```
#[macro_export]
macro_rules! dynamic_generic_alias {
    ($vis:vis $name:ident, $doc:literal) => {
        #[doc = $doc]
        $vis type $name<T> = $crate::Dynamic<T>;
    };
    ($vis:vis $name:ident) => {
        #[doc = "Generic secure heap wrapper"]
        $vis type $name<T> = $crate::Dynamic<T>;
    };
}



================================================================================
// SECTION 011: src/macros/fixed_alias.rs
// Created:  2026-01-23 06:35:31.837
// Modified: 2026-01-23 06:35:31.837
================================================================================
/// Creates a type alias for a fixed-size stack-allocated secure secret.
///
/// This macro generates a type alias to `Fixed<[u8; N]>` with optional visibility and custom documentation.
/// The generated type inherits all methods from `Fixed`, including `.expose_secret()`.
///
/// # Syntax
///
/// - `fixed_alias!(vis Name, size);` — visibility required (e.g., `pub`, `pub(crate)`, or omit for private)
/// - `fixed_alias!(vis Name, size, doc);` — with optional custom doc string
///
/// # Examples
///
/// Public alias:
/// ```
/// use secure_gate::{fixed_alias, ExposeSecret};
/// fixed_alias!(pub Aes256Key, 32);
/// let key: Aes256Key = [42u8; 32].into();
/// assert_eq!(key.expose_secret(), &[42u8; 32]);
/// ```
///
/// Private alias:
/// ```
/// use secure_gate::{fixed_alias, ExposeSecret};
/// fixed_alias!(private_key, 32); // No visibility modifier = private
/// let key: private_key = [0u8; 32].into();
/// assert_eq!(key.expose_secret(), &[0u8; 32]);
/// ```
///
/// With custom visibility:
/// ```
/// use secure_gate::fixed_alias;
/// fixed_alias!(pub(crate) InternalKey, 64); // Crate-visible
/// ```
///
/// With custom documentation:
/// ```
/// use secure_gate::{fixed_alias, ExposeSecret};
/// fixed_alias!(pub ApiKey, 32, "API key for external service");
/// let key: ApiKey = [0u8; 32].into();
/// assert_eq!(key.expose_secret(), &[0u8; 32]);
/// ```
#[macro_export]
macro_rules! fixed_alias {
    ($vis:vis $name:ident, $size:literal, $doc:literal) => {
        #[doc = $doc]
        const _: () = { let _ = [(); $size][0]; };
        $vis type $name = $crate::Fixed<[u8; $size]>;
    };
    ($vis:vis $name:ident, $size:literal) => {
        #[doc = concat!("Fixed-size secure secret (", stringify!($size), " bytes)")]
        const _: () = { let _ = [(); $size][0]; };
        $vis type $name = $crate::Fixed<[u8; $size]>;
    };
    ($name:ident, $size:literal, $doc:literal) => {
        #[doc = $doc]
        const _: () = { let _ = [(); $size][0]; };
        type $name = $crate::Fixed<[u8; $size]>;
    };
    ($name:ident, $size:literal) => {
        #[doc = concat!("Fixed-size secure secret (", stringify!($size), " bytes)")]
        const _: () = { let _ = [(); $size][0]; };
        type $name = $crate::Fixed<[u8; $size]>;
    };
}



================================================================================
// SECTION 012: src/macros/fixed_generic_alias.rs
// Created:  2026-01-23 06:35:31.837
// Modified: 2026-01-23 06:35:31.837
================================================================================
/// Creates a generic fixed-size stack-allocated secure secret type.
///
/// This macro generates a type alias to `Fixed<[u8; N]>` with a custom doc string.
/// Useful for libraries providing generic fixed-size stack-allocated secret buffers.
///
/// # Examples
///
/// With custom doc:
/// ```
/// use secure_gate::fixed_generic_alias;
/// fixed_generic_alias!(pub GenericBuffer, "Generic secure byte buffer");
/// ```
///
/// With default doc:
/// ```
/// use secure_gate::fixed_generic_alias;
/// fixed_generic_alias!(pub(crate) Buffer);
/// ```
#[macro_export]
macro_rules! fixed_generic_alias {
    ($vis:vis $name:ident, $doc:literal) => {
        #[doc = $doc]
        $vis type $name<const N: usize> = $crate::Fixed<[u8; N]>;
    };
    ($vis:vis $name:ident) => {
        #[doc = "Fixed-size secure byte buffer"]
        $vis type $name<const N: usize> = $crate::Fixed<[u8; N]>;
    };
}



================================================================================
// SECTION 013: src/macros/mod.rs
// Created:  2026-01-20 06:27:04.131
// Modified: 2026-01-23 07:59:58.687
================================================================================
//! Convenience macros for creating type aliases to secure secret wrappers.
//!
//! This module provides macros that generate type aliases for common secure secret patterns,
//! making it easier to define custom secret types in your application.
//!
//! - `dynamic_alias!`: For heap-allocated secrets (`Dynamic<T>`)
//! - `dynamic_generic_alias!`: For generic heap-allocated secrets
//! - `fixed_alias!`: For fixed-size secrets (`Fixed<[u8; N]>`)
//! - `fixed_generic_alias!`: For generic fixed-size secrets

/// Public type-alias macros.
/// Dynamic and fixed aliases.
mod dynamic_alias;
mod dynamic_generic_alias;
mod fixed_alias;
mod fixed_generic_alias;



================================================================================
// SECTION 014: src/traits/cloneable_type.rs
// Created:  2026-01-23 06:35:31.838
// Modified: 2026-01-23 07:59:58.687
================================================================================
//! Marker trait for opt-in safe cloning with zeroization.

/// Implement this trait on types that require safe duplication while maintaining
/// security guarantees. The trait itself is a marker and does not provide methods,
/// but implementations must ensure proper zeroization.
///
/// # Examples
///
/// ```rust
/// #[cfg(feature = "cloneable")]
/// {
///     use secure_gate::{CloneableType, Dynamic};
///
///     #[derive(Clone)]
///     struct MyKey([u8; 32]);
///
///     impl CloneableType for MyKey {}  // Opt-in to safe cloning
///
///     let key: Dynamic<MyKey> = MyKey([0; 32]).into();
///     let copy = key.clone();  // Now allowed, with zeroization on drop
/// }
/// ```
#[cfg(feature = "cloneable")]
pub trait CloneableType: Clone {}



================================================================================
// SECTION 015: src/traits/constant_time_eq.rs
// Created:  2026-01-20 06:27:04.201
// Modified: 2026-01-23 07:59:58.687
================================================================================
//! Constant-time equality comparison for cryptographic secrets (gated behind `ct-eq`).
//!
//! This module provides the ConstantTimeEq trait, which performs equality
//! comparisons in constant time to prevent timing attacks. Regular equality
//! operations can take different amounts of time depending on the data,
//! potentially leaking information about secret values.
//!
//! Uses the `subtle` crate for secure, constant-time implementations.
//!
//! # Security Warning
//!
//! Always use `ct_eq()` instead of `==` when comparing cryptographic secrets,
//! authentication tokens, or other sensitive data that should not leak through
//! timing differences.

/// Trait for constant-time equality comparison to prevent timing attacks.
///
/// This trait provides equality comparison that takes the same amount of time
/// regardless of the input values, preventing attackers from using timing
/// differences to learn about secret data.
///
/// Implemented for byte slices and fixed-size byte arrays.
/// Uses the `subtle` crate's secure constant-time comparison.
///
/// # Security
///
/// Regular `==` comparison can short-circuit early when bytes differ,
/// creating timing differences that leak information. This trait ensures
/// all comparisons take constant time.
///
/// # Examples
///
/// Basic usage:
/// ```rust
/// # #[cfg(feature = "ct-eq")]
/// # {
/// fn main() {
/// use secure_gate::ConstantTimeEq;
/// let a = [1u8, 2u8, 3u8].as_slice();
/// let b = [1u8, 2u8, 3u8].as_slice();
/// let c = [1u8, 5u8, 3u8].as_slice();
///
/// assert!(bool::from(a.ct_eq(&b)));  // true
/// assert!(bool::from(!a.ct_eq(&c))); // false, but takes same time as true case
/// }
/// # }
/// ```
#[cfg(feature = "ct-eq")]
pub trait ConstantTimeEq {
    /// Compare two values in constant time.
    ///
    /// Returns `true` if they are equal, `false` otherwise.
    /// Safe against timing attacks.
    fn ct_eq(&self, other: &Self) -> bool;
}

#[cfg(feature = "ct-eq")]
/// Constant-time equality for byte slices.
impl ConstantTimeEq for [u8] {
    fn ct_eq(&self, other: &Self) -> bool {
        subtle::ConstantTimeEq::ct_eq(self, other).into()
    }
}

#[cfg(feature = "ct-eq")]
impl<const N: usize> ConstantTimeEq for [u8; N] {
    fn ct_eq(&self, other: &Self) -> bool {
        self.as_slice().ct_eq(other.as_slice())
    }
}

#[cfg(feature = "ct-eq")]
impl ConstantTimeEq for alloc::vec::Vec<u8> {
    fn ct_eq(&self, other: &Self) -> bool {
        self.as_slice().ct_eq(other.as_slice())
    }
}

#[cfg(feature = "ct-eq")]
impl ConstantTimeEq for alloc::string::String {
    fn ct_eq(&self, other: &Self) -> bool {
        self.as_bytes().ct_eq(other.as_bytes())
    }
}



================================================================================
// SECTION 016: src/traits/expose_secret.rs
// Created:  2026-01-20 07:05:59.548
// Modified: 2026-01-23 07:59:58.689
================================================================================
//! # Secret Exposure Traits
//!
//! This module defines traits for polymorphic secret access with controlled mutability and metadata.
//! These traits enable writing generic code that works across different secret wrapper types
//! while enforcing security guarantees.
//!
//! ## Key Traits
//!
//! - [`ExposeSecret`]: Read-only access to secret values including metadata
//!
//! ## Security Model
//!
//! - **Full access**: Core wrappers ([`crate::Fixed`], [`crate::Dynamic`]) implement [`ExposeSecret`], with mutable variants implementing [`ExposeSecretMut`]
//! - **Read-only**: Encoding wrappers only implement [`ExposeSecret`] to prevent mutation
//! - **Zero-cost**: All implementations use `#[inline(always)]`
//!
/// Trait for read-only access to secrets, including metadata.
///
/// ## Usage
///
/// Import these traits to access secret values and their metadata ergonomically.
///
/// Import this to enable `.with_secret()`, `.expose_secret()`, `.len()`, and `.is_empty()`.
/// For mutable access, see [`crate::ExposeSecretMut`].
///
/// ## Security Note
///
/// Prefer `with_secret` for scoped access to avoid accidental leaks through long-lived borrows.
/// `expose_secret` is provided for cases where a direct reference is needed, but use with caution.
pub trait ExposeSecret {
    /// The inner secret type being exposed.
    ///
    /// This can be a sized type (like `[u8; N]`) or unsized (like `str` or `[u8]`).
    type Inner: ?Sized;

    /// Provide scoped read-only access to the secret.
    ///
    /// This is the preferred method for accessing secrets, as it prevents accidental leaks
    /// through long-lived borrows. The closure receives a reference to the inner secret
    /// and returns a value.
    ///
    /// # Examples
    ///
    /// ```
    /// use secure_gate::{Fixed, ExposeSecret};
    /// let secret = Fixed::new([42u8; 4]);
    /// let sum: u32 = secret.with_secret(|bytes| bytes.iter().map(|&b| b as u32).sum());
    /// assert_eq!(sum, 42 * 4);
    /// ```
    fn with_secret<F, R>(&self, f: F) -> R
    where
        F: FnOnce(&Self::Inner) -> R;

    /// Expose the secret for read-only access.
    ///
    /// # Security Warning
    ///
    /// This returns a direct reference that can be accidentally leaked. Prefer `with_secret`
    /// for most use cases to ensure the secret is only accessed within a controlled scope.
    fn expose_secret(&self) -> &Self::Inner;

    /// Returns the length of the secret.
    fn len(&self) -> usize;

    /// Returns true if the secret is empty.
    #[inline(always)]
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}



================================================================================
// SECTION 017: src/traits/expose_secret_mut.rs
// Created:  2026-01-20 06:27:04.286
// Modified: 2026-01-23 07:59:58.689
================================================================================
//! # Mutable Secret Exposure Traits
//!
//! This module defines the trait for mutable access to secrets.
//!
//! ## Key Traits
//!
//! - [`ExposeSecretMut`]: Mutable access to secret values
//!
//! ## Security Model
//!
//! - **Mutable access**: Only core wrappers ([`crate::Fixed`], [`crate::Dynamic`]) implement [`ExposeSecretMut`]
//! - **Zero-cost**: All implementations use `#[inline(always)]`
use crate::ExposeSecret;

/// ## Usage
///
/// Import this trait to enable `.with_secret_mut()` and `.expose_secret_mut()`.
/// Extends [`ExposeSecret`], so read access and metadata are also available.
/// Trait for mutable access to secrets.
///
/// Extends [`ExposeSecret`], so metadata and read access are included.
/// Import this for `.with_secret_mut()` and `.expose_secret_mut()`.
///
/// ## Security Note
///
/// Prefer `with_secret_mut` for scoped access to avoid accidental leaks through long-lived borrows.
/// `expose_secret_mut` is provided for cases where a direct mutable reference is needed, but use with caution.
pub trait ExposeSecretMut: ExposeSecret {
    /// Provide scoped mutable access to the secret.
    ///
    /// This is the preferred method for mutating secrets, as it prevents accidental leaks
    /// through long-lived mutable borrows. The closure receives a mutable reference to the inner secret
    /// and returns a value.
    ///
    /// # Examples
    ///
    /// ```
    /// use secure_gate::{Fixed, ExposeSecretMut};
    /// let mut secret = Fixed::new([0u8; 4]);
    /// secret.with_secret_mut(|bytes| {
    ///     bytes[0] = 42;
    /// });
    /// ```
    fn with_secret_mut<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Self::Inner) -> R;

    /// Expose the secret for mutable access.
    ///
    /// # Security Warning
    ///
    /// This returns a direct mutable reference that can be accidentally leaked. Prefer `with_secret_mut`
    /// for most use cases to ensure the secret is only mutated within a controlled scope.
    fn expose_secret_mut(&mut self) -> &mut Self::Inner;
}



================================================================================
// SECTION 018: src/traits/hash_eq.rs
// Created:  2026-01-23 06:35:31.840
// Modified: 2026-01-23 07:59:58.689
================================================================================
/// Probabilistic constant-time equality via BLAKE3 hashing.
///
/// Provides fast equality checks for secrets by hashing inputs (BLAKE3) then
/// comparing the fixed 32-byte digests in constant time (via `ct_eq`/`subtle`).
///
/// Ideal for **large or variable-length secrets** (e.g. ML-KEM ciphertexts ~1–1.5 KiB,
/// ML-DSA signatures ~2–4 KiB) where direct byte-by-byte `ct_eq` becomes slow or
/// increases side-channel surface.
///
/// ## Security Properties
/// - **Timing-safe**: BLAKE3 is data-independent; final 32-byte compare is constant-time.
/// - **Length hiding**: Original length not observable via timing/cache.
/// - **Keyed mode** (with `"rand"` feature): Per-process random key resists precomputation /
///   multi-target attacks across comparisons.
/// - **Probabilistic**: Collision probability ~2⁻¹²⁸ — negligible for equality checks,
///   but use [`crate::ConstantTimeEq`] for strict deterministic equality.
///
/// ## Performance
/// - Fixed overhead (~120–150 ns on small inputs) + very low per-byte cost.
/// - Beats full `ct_eq` for > ~300–500 bytes (2× at 1 KiB, 5–8× at 100 KiB+).
/// - Prefer [`crate::ConstantTimeEq`] for tiny fixed-size tags (< 128–256 bytes).
///
/// ## Warnings
/// - **DoS risk**: Hashing very large untrusted inputs is costly — rate-limit or bound sizes.
/// - **Not zero-collision**: Extremely unlikely false positives; don't rely on it for uniqueness.
///
/// ## Example
/// ```
/// # #[cfg(feature = "hash-eq")]
/// # {
/// use secure_gate::{Dynamic, HashEq};
/// let a: Dynamic<Vec<u8>> = vec![42u8; 2048].into();  // e.g. ML-DSA signature
/// let b: Dynamic<Vec<u8>> = vec![42u8; 2048].into();  // matching value
/// if a.hash_eq(&b) {
///     // constant-time, fast for large blobs
/// }
/// # }
/// ```
#[cfg(feature = "hash-eq")]
pub trait HashEq {
    /// Probabilistic constant-time equality check using BLAKE3 hashing.
    ///
    /// This trait provides a fast, constant-time equality comparison that uses cryptographic
    /// hashing (BLAKE3) instead of direct byte comparison. This is useful for comparing large or
    /// variable-length secrets where direct comparison would be inefficient or variable-time.
    ///
    /// # Security Warnings
    ///
    /// - **Probabilistic nature**: Hash collisions are extremely unlikely but not impossible.
    /// - **Probabilistic nature**: Hash collisions are extremely unlikely but not impossible.
    ///   Use [`crate::ConstantTimeEq`] for strict cryptographic equality.
    /// - **DoS amplification**: Hashing can be slower for large inputs; rate-limit in untrusted contexts.
    /// - **Deterministic vs keyed**: Plain hashing is deterministic (useful for tests); keyed mode
    ///   with `rand` enabled mitigates precomputation attacks.
    /// - **Not suitable for small/fixed secrets**: Prefer [`crate::ConstantTimeEq`] for <32 bytes.
    ///
    /// # Performance
    ///
    /// - Flat timing: ~120–130ns variance across input sizes.
    /// - Better than ct_eq for >32 bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # #[cfg(feature = "hash-eq")]
    /// # {
    /// use secure_gate::{Fixed, HashEq};
    /// let a = Fixed::new([1u8; 32]);
    /// let b = Fixed::new([1u8; 32]);
    /// assert!(a.hash_eq(&b));
    /// # }
    /// ```
    /// Perform constant-time equality check using BLAKE3 hashing.
    fn hash_eq(&self, other: &Self) -> bool;
}



================================================================================
// SECTION 019: src/traits/mod.rs
// Created:  2026-01-20 06:27:04.331
// Modified: 2026-01-23 07:59:58.691
================================================================================
/// # Traits for Polymorphic Secret Handling
///
/// This module provides the fundamental traits for working with secrets in a polymorphic,
/// zero-cost way. These traits enable generic code that can operate on different secret
/// wrapper types while maintaining strong security guarantees.
///
/// ## Traits Overview
///
/// - [`ExposeSecret`] - Read-only secret access with metadata
/// - [`ExposeSecretMut`] - Mutable secret access
/// - [`CloneableType`] - Opt-in safe cloning with zeroization (requires cloneable feature)
/// - [`ConstantTimeEq`] - Constant-time equality to prevent timing attacks (requires ct-eq feature)
/// - [`SecureEncoding`] - Extension trait for secure byte encoding to strings (requires encoding features)
/// - [`SerializableType`] - Marker for types allowing secure serialization (requires serde-serialize feature)
///
/// ## Security Guarantees
///
/// - **Read-only enforcement**: Random and encoding wrappers only expose read-only access
/// - **Controlled mutability**: Core wrappers provide full access while others remain read-only
/// - **Zero-cost abstractions**: All traits use `#[inline(always)]` for optimal performance
/// - **Type safety**: Polymorphic operations preserve secret wrapper invariants
///
/// ## Feature Gates
///
/// Some traits require optional Cargo features:
/// - rand: Enables random wrapper implementations
/// - cloneable: Enables [`CloneableType`] for safe cloning
/// - ct-eq: Enables [`ConstantTimeEq`] for constant-time comparisons
/// - encoding (or encoding-hex, encoding-base64, encoding-bech32): Enables [`SecureEncoding`] for byte encoding
/// - serde-serialize: Enables [`SerializableType`] for opt-in serialization
pub mod expose_secret;
pub use expose_secret::ExposeSecret;

pub mod expose_secret_mut;
pub use expose_secret_mut::ExposeSecretMut;

#[cfg(feature = "ct-eq")]
pub mod constant_time_eq;
#[cfg(feature = "ct-eq")]
pub use constant_time_eq::ConstantTimeEq;

#[cfg(feature = "hash-eq")]
pub mod hash_eq;
#[cfg(feature = "hash-eq")]
pub use hash_eq::HashEq;

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub mod secure_encoding;
#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub use secure_encoding::SecureEncoding;

#[cfg(feature = "cloneable")]
pub mod cloneable_type;
#[cfg(feature = "cloneable")]
pub use cloneable_type::CloneableType;

#[cfg(feature = "serde-serialize")]
pub mod serializable_type;
#[cfg(feature = "serde-serialize")]
pub use serializable_type::SerializableType;



================================================================================
// SECTION 020: src/traits/secure_encoding.rs
// Created:  2026-01-20 06:27:04.362
// Modified: 2026-01-23 07:59:58.692
================================================================================
//! # Secure Encoding Trait
//!
//! Extension trait for safe, explicit encoding of secret byte data to strings.
//!
//! All methods require the caller to first call `.expose_secret()` (or similar).
//! This makes every secret access loud, grep-able, and auditable.
//!
//! For Bech32 encoding, use the trait methods with an HRP.
//!
//! ## Security Warning
//!
//! These methods produce human-readable strings containing the full secret.
//! Use only when intentionally exposing the secret (e.g., QR codes, user export, audited logging).
//! For debugging/logging, prefer redacted helpers like `to_hex_prefix`.
//! All calls require explicit `.expose_secret()` first — no implicit paths exist.
//!
//! ## Example
//!
//! ```
//! # #[cfg(feature = "encoding-hex")]
//! # {
//! use secure_gate::SecureEncoding;
//! let bytes = [0x42u8; 32];
//! let hex_string = bytes.to_hex();
//! // hex_string is now String: "424242..."
//! # }
//! ```
#[cfg(feature = "encoding-hex")]
use ::hex as hex_crate;

#[cfg(feature = "encoding-base64")]
use ::base64 as base64_crate;
#[cfg(feature = "encoding-base64")]
use base64_crate::engine::general_purpose::URL_SAFE_NO_PAD;
#[cfg(feature = "encoding-base64")]
use base64_crate::Engine;

#[cfg(feature = "encoding-bech32")]
use ::bech32;

#[cfg(feature = "encoding-bech32")]
use crate::error::Bech32Error;

/// Local implementation of bit conversion for Bech32, since bech32 crate doesn't expose it in v0.11.
#[cfg(feature = "encoding-bech32")]
fn convert_bits(
    from: u8,
    to: u8,
    pad: bool,
    data: &[u8],
) -> Result<(alloc::vec::Vec<u8>, usize), ()> {
    if !(1..=8).contains(&from) || !(1..=8).contains(&to) {
        return Err(());
    }
    let mut acc = 0u64;
    let mut bits = 0u8;
    let mut ret = alloc::vec::Vec::new();
    let maxv = (1u64 << to) - 1;
    let _max_acc = (1u64 << (from + to - 1)) - 1;
    for &v in data {
        if ((v as u32) >> from) != 0 {
            return Err(());
        }
        acc = (acc << from) | (v as u64);
        bits += from;
        while bits >= to {
            bits -= to;
            ret.push(((acc >> bits) & maxv) as u8);
        }
    }
    if pad {
        if bits > 0 {
            ret.push(((acc << (to - bits)) & maxv) as u8);
        }
    } else if bits >= from || ((acc << (to - bits)) & maxv) != 0 {
        return Err(());
    }
    Ok((ret, bits as usize))
}

/// Extension trait for safe, explicit encoding of secret byte data to strings.
///
/// All methods require the caller to first call `.expose_secret()` (or similar).
/// This makes every secret access loud, grep-able, and auditable.
///
/// For Bech32 encoding, use the trait methods with an HRP.
///
/// # Security Warning
///
/// These methods produce human-readable strings containing the full secret.
/// Use only when intentionally exposing the secret (e.g., QR codes, user export, audited logging).
/// For debugging/logging, prefer redacted helpers like `to_hex_prefix`.
/// All calls require explicit `.expose_secret()` first — no implicit paths exist.
///
/// # Example
///
/// ```
/// # #[cfg(feature = "encoding-hex")]
/// # {
/// use secure_gate::SecureEncoding;
/// let bytes = [0x42u8; 32];
/// let hex_string = bytes.to_hex();
/// // hex_string is now String: "424242..."
/// # }
/// ```
pub trait SecureEncoding {
    /// Encode secret bytes as lowercase hexadecimal.
    #[cfg(feature = "encoding-hex")]
    fn to_hex(&self) -> alloc::string::String;

    /// Encode secret bytes as uppercase hexadecimal.
    #[cfg(feature = "encoding-hex")]
    fn to_hex_upper(&self) -> alloc::string::String;

    /// Encode secret bytes as lowercase hexadecimal, truncated to `prefix_bytes` with "…" if longer.
    /// Useful for redacted logging or debugging without exposing the full secret.
    #[cfg(feature = "encoding-hex")]
    fn to_hex_prefix(&self, prefix_bytes: usize) -> alloc::string::String {
        let full = self.to_hex();
        if full.len() <= prefix_bytes * 2 {
            full
        } else {
            format!("{}…", &full[..prefix_bytes * 2])
        }
    }

    /// Encode secret bytes as URL-safe base64 (no padding).
    #[cfg(feature = "encoding-base64")]
    fn to_base64url(&self) -> alloc::string::String;

    /// Encode secret bytes as Bech32 with the specified HRP.
    #[cfg(feature = "encoding-bech32")]
    fn to_bech32(&self, hrp: &str) -> alloc::string::String;

    /// Encode secret bytes as Bech32m with the specified HRP.
    #[cfg(feature = "encoding-bech32")]
    fn to_bech32m(&self, hrp: &str) -> alloc::string::String;

    /// Fallibly encode secret bytes as Bech32 with the specified HRP and optional expected HRP validation.
    #[cfg(feature = "encoding-bech32")]
    fn try_to_bech32(
        &self,
        hrp: &str,
        expected_hrp: Option<&str>,
    ) -> Result<alloc::string::String, Bech32Error>;

    /// Fallibly encode secret bytes as Bech32m with the specified HRP and optional expected HRP validation.
    #[cfg(feature = "encoding-bech32")]
    fn try_to_bech32m(
        &self,
        hrp: &str,
        expected_hrp: Option<&str>,
    ) -> Result<alloc::string::String, Bech32Error>;
}

// Blanket impl to cover any AsRef<[u8]> (e.g., &[u8], Vec<u8>, [u8; N], etc.)
impl<T: AsRef<[u8]> + ?Sized> SecureEncoding for T {
    #[cfg(feature = "encoding-hex")]
    #[inline(always)]
    fn to_hex(&self) -> alloc::string::String {
        hex_crate::encode(self.as_ref())
    }

    #[cfg(feature = "encoding-hex")]
    #[inline(always)]
    fn to_hex_upper(&self) -> alloc::string::String {
        hex_crate::encode_upper(self.as_ref())
    }

    #[cfg(feature = "encoding-hex")]
    fn to_hex_prefix(&self, prefix_bytes: usize) -> alloc::string::String {
        let full = self.as_ref().to_hex();
        if full.len() <= prefix_bytes * 2 {
            full
        } else {
            format!("{}…", &full[..prefix_bytes * 2])
        }
    }

    #[cfg(feature = "encoding-base64")]
    #[inline(always)]
    fn to_base64url(&self) -> alloc::string::String {
        URL_SAFE_NO_PAD.encode(self.as_ref())
    }

    #[cfg(feature = "encoding-bech32")]
    #[inline(always)]
    fn to_bech32(&self, hrp: &str) -> alloc::string::String {
        let (converted, _) =
            convert_bits(8, 5, true, self.as_ref()).expect("bech32 bit conversion failed");
        let hrp_parsed = bech32::Hrp::parse(hrp).expect("invalid hrp");
        bech32::encode::<bech32::Bech32>(hrp_parsed, &converted).expect("bech32 encoding failed")
    }

    #[cfg(feature = "encoding-bech32")]
    #[inline(always)]
    fn to_bech32m(&self, hrp: &str) -> alloc::string::String {
        let (converted, _) =
            convert_bits(8, 5, true, self.as_ref()).expect("bech32 bit conversion failed");
        let hrp_parsed = bech32::Hrp::parse(hrp).expect("invalid hrp");
        bech32::encode::<bech32::Bech32m>(hrp_parsed, &converted).expect("bech32m encoding failed")
    }

    #[cfg(feature = "encoding-bech32")]
    #[inline(always)]
    fn try_to_bech32(
        &self,
        hrp: &str,
        expected_hrp: Option<&str>,
    ) -> Result<alloc::string::String, Bech32Error> {
        let (converted, _) =
            convert_bits(8, 5, true, self.as_ref()).map_err(|_| Bech32Error::ConversionFailed)?;
        let hrp_parsed = bech32::Hrp::parse(hrp).map_err(|_| Bech32Error::InvalidHrp)?;
        if let Some(exp) = expected_hrp {
            if hrp != exp {
                return Err(Bech32Error::UnexpectedHrp {
                    expected: exp.to_string(),
                    got: hrp.to_string(),
                });
            }
        }
        bech32::encode::<bech32::Bech32>(hrp_parsed, &converted)
            .map_err(|_| Bech32Error::OperationFailed)
    }

    #[cfg(feature = "encoding-bech32")]
    #[inline(always)]
    fn try_to_bech32m(
        &self,
        hrp: &str,
        expected_hrp: Option<&str>,
    ) -> Result<alloc::string::String, Bech32Error> {
        let (converted, _) =
            convert_bits(8, 5, true, self.as_ref()).map_err(|_| Bech32Error::ConversionFailed)?;
        let hrp_parsed = bech32::Hrp::parse(hrp).map_err(|_| Bech32Error::InvalidHrp)?;
        if let Some(exp) = expected_hrp {
            if hrp != exp {
                return Err(Bech32Error::UnexpectedHrp {
                    expected: exp.to_string(),
                    got: hrp.to_string(),
                });
            }
        }
        bech32::encode::<bech32::Bech32m>(hrp_parsed, &converted)
            .map_err(|_| Bech32Error::OperationFailed)
    }
}



================================================================================
// SECTION 021: src/traits/serializable_type.rs
// Created:  2026-01-23 06:35:31.842
// Modified: 2026-01-23 07:59:58.692
================================================================================
//! Marker trait for opt-in serialization of raw secrets.

/// Implement this on types that can be deliberately serialized while maintaining security.
/// The trait itself is a marker and does not provide methods, but implementations must
/// ensure that serialization does not leak secrets unintentionally.
///
/// # Examples
///
/// ```rust
/// # #[cfg(feature = "serde-serialize")]
/// # {
/// use secure_gate::SerializableType;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize)]
/// struct MySecret {
///     data: Vec<u8>,
/// }
///
/// impl SerializableType for MySecret {}
///
/// // Now MySecret can be serialized securely, as it's marked with SerializableType
/// # }
/// ```
#[cfg(feature = "serde-serialize")]
pub trait SerializableType: serde::Serialize {}
