// ============================================================================
// secure-gate – Full library source + Cargo.toml
// Generated by: package_it.py
// Generated at: 2026-01-24 19:06:14.049
// ============================================================================

// ============================================================================
// 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/decoding/base64_url.rs
// 017. src/traits/decoding/bech32.rs
// 018. src/traits/decoding/bech32m.rs
// 019. src/traits/decoding/hex.rs
// 020. src/traits/decoding/mod.rs
// 021. src/traits/encoding/base64_url.rs
// 022. src/traits/encoding/bech32.rs
// 023. src/traits/encoding/bech32m.rs
// 024. src/traits/encoding/hex.rs
// 025. src/traits/encoding/mod.rs
// 026. src/traits/expose_secret.rs
// 027. src/traits/expose_secret_mut.rs
// 028. src/traits/hash_eq.rs
// 029. src/traits/mod.rs
// 030. src/traits/serializable_type.rs
// 031. src/utilities/decoding.rs
// 032. src/utilities/encoding.rs
// 033. src/utilities/mod.rs
// ============================================================================




================================================================================
// SECTION 001: Cargo.toml
// Created:  2026-01-06 16:42:07.300
// Modified: 2026-01-24 18:19:02.585
================================================================================
[package]
name = "secure-gate"
version = "0.7.0-rc.11"
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", "dep:rand"]

# Full: batteries-included for most real-world usage
# Includes secure defaults + all encodings + fast equality + cloning + serde round-trip + secure RNG
full = ["secure", "encoding", "hash-eq", "cloneable", "serde", "rand"]

# 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-24 18:21:54.353
================================================================================
# 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-24

### Added

- **Secure-by-default exposure model** 
  Private `inner` fields in `Dynamic<T>` and `Fixed<T>`; all access now requires explicit `.expose_secret()` / `.with_secret()` (scoped, recommended) or `.expose_secret_mut()` / `.with_secret_mut()`. No `Deref`, `AsRef`, or implicit borrowing — prevents accidental leaks.

- **Opt-in cloning & serialization** 
  New marker traits `CloneableType` and `SerializableType`. Cloning and serde serialization now require explicit impls on the inner type — no automatic risk.

- **Polymorphic access traits** 
  `ExposeSecret` and `ExposeSecretMut` traits provide generic, zero-cost access with metadata (`len()`, `is_empty()`) without exposing contents. Implemented for both `Dynamic<T>` and `Fixed<T>`.

- **Per-format encoding/decoding traits**
  Symmetric, orthogonal traits (e.g., `ToHex`/`FromHexStr`, `ToBech32`/`FromBech32Str`). Umbrella traits `SecureEncoding`/`SecureDecoding` for aggregation. Multi-format auto-decoding (`try_decode_any`). Granular features: `encoding-hex`, `encoding-base64`, `encoding-bech32`.

- **Timing-safe equality** 
  `ConstantTimeEq` trait (`ct-eq` feature) with `.ct_eq()` methods on `Fixed<[u8; N]>` and `Dynamic<T: AsRef<[u8]>>`.

- **Fast probabilistic equality for large secrets** 
  `HashEq` trait (`hash-eq` feature) using BLAKE3 + constant-time digest comparison. New **recommended** method `hash_eq_opt(…, threshold: Option<usize>)` automatically switches between `ct_eq` (small inputs) and `hash_eq` (large inputs).

- **Secure random generation** 
  `from_random()` on `Fixed<[u8; N]>` and `Dynamic<Vec<u8>>` using `OsRng` (panics on failure).

- **Fallible fixed-size construction** 
  `TryFrom<&[u8]>` for `Fixed<[u8; N]>` with `FromSliceError` (safe alternative to panicking conversions).

- **Centralized errors** 
  Unified error types (`Bech32Error`, `DecodingError`, `FromSliceError`) via `thiserror`.

- **Testing & CI** 
  `trybuild` compile-fail tests, serde fuzz target, expanded CI matrix covering all feature combinations.

- **Documentation** 
  New `SECURITY.md`, enhanced README, custom rustdoc for alias macros.

### Changed (Breaking)

- **Default features**
  Now `secure` meta-feature (`zeroize` + `ct-eq`). `full` includes `secure` + `encoding` + `hash-eq` + `cloneable` + `serde` + `rand`. Added `insecure` for explicit opt-out (testing/low-resource only — strongly discouraged).

- **Cloning**
  Removed implicit `Clone` on wrappers; now opt-in via `CloneableType` marker on inner type.

- **Serialization**
  Split `serde` into `serde-deserialize` (always available) and `serde-serialize` (gated by `SerializableType` marker).

- **Exposure API**
  Removed any implicit borrowing paths. All access now explicit.

- **Encoding API refactor: per-format orthogonal traits**
  Removed monolithic `SecureEncoding` trait (clean slate). Introduced symmetric per-format traits: `ToHex`/`FromHexStr`, `ToBase64Url`/`FromBase64UrlStr`, `ToBech32`/`FromBech32Str`, `ToBech32m`/`FromBech32mStr`. Umbrella traits `SecureEncoding`/`SecureDecoding` (feature-gated). Added `try_decode_any` for multi-format auto-decoding. Bech32/BIP-173 & Bech32m/BIP-350 now distinct.

- **Bech32 encoding**
  Now fallible (`try_to_bech32` / `try_to_bech32m`); no panics on invalid HRP/data. Strict variant differentiation.

- **Error handling**
  Unified and renamed error types; removed panicking fallbacks.

### Migration (Encoding Refactor)
- Bounds: `T: SecureEncoding` → same (umbrella) or explicit `T: ToHex + …`
- Calls: `.to_hex()` → same via blanket impl; `.to_bech32(hrp)` → same
- Decoding: use `str.try_from_hex()?` / `try_decode_any()?` for auto-detection

### Fixed

- Doc-tests now pass across all feature combinations
- Improved Bech32/BIP-173 & Bech32m/BIP-350 variant/HRP handling
- Proper `Display`/`Error` impls for custom errors
- Strict format validation in per-format traits (rejects invalid checksums/variants)

### Removed

- Monolithic `SecureEncoding` trait
- Implicit `Clone` and `Serialize` on wrappers
- Panicking `from_slice` and `new_boxed` methods
- Old encoding helpers (`RandomHex`, etc.)
- Conditional `unsafe` blocks (now unconditionally forbidden)

## [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-24 18:10:09.869
================================================================================
# 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)]`).

Secure-gate provides `Dynamic<T>` (heap-allocated) and `Fixed<T>` (stack-allocated) wrappers that **force explicit access** to secrets via `.expose_secret()` or scoped `.with_secret()` — preventing accidental leaks while remaining zero-cost and `no_std` + `alloc` compatible.

## Why secure-gate?

- **Orthogonal encoding/decoding** — per-format traits (e.g., `ToHex`/`FromHexStr`) with symmetric APIs and umbrella traits for aggregation
- **Extensible** — adding new formats (e.g., base58) requires only one new trait pair + impls

- **Explicit exposure** — no silent `Deref`/`AsRef` leaks
- **Zeroize on drop** (`zeroize` feature)
- **Timing-safe equality** (`ct-eq` feature)
- **Fast probabilistic equality for large secrets** (`hash-eq` → BLAKE3 + fixed digest compare)
- **Secure random generation** (`rand` feature)
- **Encoding** (symmetric per-format traits: hex, base64url, bech32/BIP-173, bech32m/BIP-350) + **serde** auto-detection (hex/base64url/bech32/bech32m)
- **Macros** for ergonomic aliases (`dynamic_alias!`, `fixed_alias!`)
- **Auditable** — every exposure and encoding call is grep-able

## Installation

```toml
[dependencies]
secure-gate = "0.7.0-rc.11"  # or latest stable version
```

**Recommended secure defaults**:
```toml
secure-gate = { version = "0.7.0-rc.11", features = ["secure"] }  # zeroize + ct-eq
```

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

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

See [Features](#features) for the full list.

## Features

| Feature                | Description                                                                 |
|------------------------|-----------------------------------------------------------------------------|
| `secure` (default)     | Meta: `zeroize` + `ct-eq` (wiping + timing-safe equality)                   |
| `zeroize`              | Zero memory on drop                                                         |
| `ct-eq`                | `ConstantTimeEq` trait (prevents timing attacks)                            |
| `hash-eq`              | `HashEq` trait: BLAKE3-based equality (fast for large/variable secrets)     |
| `rand`                 | Secure random via `OsRng` (`from_random()`)                                 |
| `serde`                | Meta: `serde-deserialize` + `serde-serialize`                               |
| `serde-deserialize`    | Auto-detect hex/base64/bech32/bech32m when loading secrets                  |
| `serde-serialize`      | Export secrets (gated by `SerializableType`)                                |
| `encoding`             | Meta: symmetric per-format encoding/decoding (hex, base64url, bech32/bech32m) |
| `encoding-hex`         | `ToHex` (`.to_hex()`, `.to_hex_upper()`) + `FromHexStr` (`.try_from_hex()`)  |
| `encoding-base64`      | `ToBase64Url` (`.to_base64url()`) + `FromBase64UrlStr` (`.try_from_base64url()`) |
| `encoding-bech32`      | Bech32/BIP-173 & Bech32m/BIP-350: `ToBech32`, `ToBech32m`, `FromBech32Str`, `FromBech32mStr` |
| `cloneable`            | Opt-in cloning via `CloneableType` marker                                   |
| `full`                 | All of the above (convenient for development)                               |

`no_std` + `alloc` compatible. Disabled features have **zero overhead**.

## Quick Start

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

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

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

// Scoped (recommended)
pw.with_secret(|s| println!("length: {}", s.len()));

// Direct (auditable)
assert_eq!(pw.expose_secret(), "hunter2");

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

// Symmetric encoding/decoding example (new per-format traits)
#[cfg(all(feature = "encoding-hex", feature = "encoding-bech32"))]
{
    use secure_gate::{FromHexStr, ToBech32, ToHex};
    let hex    = key.expose_secret().to_hex();          // "2a2a2a..."
    let bech32 = key.expose_secret().to_bech32("key");  // "key1q..." (BIP-173)
    let roundtrip = hex.try_from_hex().unwrap();        // Decode back
}
```

> **Note**: Encoding API updated in 0.7.0 — old `SecureEncoding` removed in favor of per-format traits (e.g., `ToHex`, `FromHexStr`). Existing code like `data.to_hex()` still works via blanket impls. For new symmetric encoding/decoding, use individual traits or umbrellas (`SecureEncoding`/`SecureDecoding`).

## Recommended Equality

Use **`hash_eq_opt`** — it automatically chooses the best method:

- Small inputs (≤32 bytes default): fast deterministic `ct_eq`
- Large/variable inputs: fast BLAKE3 hashing + digest compare

```rust
#[cfg(feature = "hash-eq")]
{
    use secure_gate::{Dynamic, HashEq};
    extern crate alloc;

    let sig_a: Dynamic<Vec<u8>> = vec![0xAA; 2048].into();  // e.g. ML-DSA signature
    let sig_b: Dynamic<Vec<u8>> = vec![0xAA; 2048].into();

    // Recommended: smart path selection
    if sig_a.hash_eq_opt(&sig_b, None) {
        // equal
    }

    // Force ct_eq even on large input
    sig_a.hash_eq_opt(&sig_b, Some(4096));
}
```

Plain `hash_eq` is still available for uniform probabilistic behavior.

See [docs](https://docs.rs/secure-gate) for full API.

## Security Model

- **Explicit access only** — `.expose_secret()` / `.with_secret()` required
- **No implicit leaks** — no `Deref`/`AsRef`/`Copy` by default
- **Zeroize** on drop (`zeroize` feature)
- **Timing-safe** equality (`ct-eq`)
- **Probabilistic fast equality** for big data (`hash-eq`)
- **No unsafe code** — enforced with `#![forbid(unsafe_code)]`

Read [SECURITY.md](SECURITY.md) for threat model and mitigations.

## Advanced Usage

### Macros for Aliases

```rust
use secure_gate::{dynamic_alias, fixed_alias};

dynamic_alias!(pub RefreshToken, String, "OAuth refresh token");
fixed_alias!(pub ApiKey, 32, "32-byte API key");
```

### Random Generation

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

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

### Encoding (symmetric per-format traits)

secure-gate provides **orthogonal, symmetric encoding/decoding traits** for extensibility:

- `ToHex` / `FromHexStr`: Hex encoding/decoding
- `ToBase64Url` / `FromBase64UrlStr`: Base64url encoding/decoding
- `ToBech32` / `FromBech32Str`: BIP-173 Bech32 encoding/decoding
- `ToBech32m` / `FromBech32mStr`: BIP-350 Bech32m encoding/decoding

Umbrellas (`SecureEncoding` / `SecureDecoding`) aggregate all enabled traits for convenience. Each format is independent—adding base58 later requires only one new pair.

All methods are blanket-implemented over `AsRef<[u8]>` (encoding) or `AsRef<str>` (decoding) for zero-overhead ergonomics.

```rust
#[cfg(all(feature = "rand", feature = "encoding-bech32", feature = "encoding-hex"))]
{
    use secure_gate::{fixed_alias, Fixed, ExposeSecret, ToBech32, ToHex, FromHexStr};
    extern crate alloc;

    fixed_alias!(Aes256Key, 32);
    let key: Aes256Key = Aes256Key::from_random();

    let hex    = key.expose_secret().to_hex();          // "2a2a2a..."
    let bech32 = key.expose_secret().to_bech32("key");  // "key1q..." (BIP-173)
    let bech32m = key.expose_secret().to_bech32m("key"); // "key1p..." (BIP-350)

    // Symmetric decoding
    let decoded_hex: Vec<u8> = "2a2a2a".try_from_hex().unwrap();
    let decoded_bech32 = "key1q...".try_from_bech32_expect_hrp("key").unwrap();
}
```

### Serde (auto-detects hex/base64url/bech32/bech32m on deserialize)

```rust
#[cfg(all(feature = "serde-deserialize", feature = "encoding-bech32", feature = "rand"))]
{
    use secure_gate::{fixed_alias, ExposeSecret, ToBech32};
    use serde_json;
    extern crate alloc;

    fixed_alias!(Aes256Key, 32);
    // Generate a key and encode to bech32
    let original: Aes256Key = Aes256Key::from_random();
    let bech32 = original.with_secret(|s| s.to_bech32("key"));
    let decoded: Aes256Key = serde_json::from_str(&format!("\"{}\"", bech32)).unwrap();
    // Auto-detection handles decoding transparently
}
```

## License

MIT OR Apache-2.0



================================================================================
// SECTION 004: SECURITY.md
// Created:  2026-01-20 06:27:20.560
// Modified: 2026-01-24 18:05:38.949
================================================================================
# Security Considerations for secure-gate

## TL;DR
- **No independent audit** — review the source code yourself before production use.
- **No unsafe code** — `#![forbid(unsafe_code)]` enforced unconditionally.
- **Explicit exposure only** — all secret access requires `.expose_secret()` / `.with_secret()` or mutable equivalents; no `Deref`, `AsRef`, or implicit borrowing.
- **Zeroization on drop** — full buffer (including slack capacity) wiped when `zeroize` feature is enabled.
- **Timing-safe equality** — use `ConstantTimeEq` (`ct-eq`) or `HashEq` / `hash_eq_opt` (`hash-eq`); `==` is deliberately not implemented.
- **Opt-in risk** — cloning and serialization require explicit marker traits (`CloneableType`, `SerializableType`).
- **Vulnerability reporting** — preferred: GitHub private vulnerability reporting (Security tab); public issues acceptable.

This document outlines the security model, design choices, strengths, known limitations, and review guidance for `secure-gate`.

## Audit Status

`secure-gate` has **not** undergone an independent security audit.

The crate is intentionally small and relies on well-vetted dependencies:

- `zeroize` — memory wiping
- `subtle` — constant-time comparison primitives
- `blake3` — cryptographic hashing
- `rand_core` + `getrandom` — secure randomness
- Encoding crates (`hex`, `base64`, `bech32`) — battle-tested (supports bech32 / bech32m)

**Before production use**, review:

- Source code
- Tests (especially `hash_eq_tests.rs` and `proptest_tests.rs`)
- Dependency versions and their security history

## Core Security Model

| Property                          | Guarantee / Design Choice                                                                 |
|-----------------------------------|--------------------------------------------------------------------------------------------|
| Explicit exposure                 | Private inner fields; access only via audited methods (`expose_secret`, `with_secret`)   |
| Scoped exposure (preferred)       | Closures limit borrow lifetime; prevents long-lived references                             |
| Direct exposure (escape hatch)    | `expose_secret()` / `expose_secret_mut()` — grep-able, auditable                           |
| No implicit leaks                 | No `Deref`, `AsRef`, `Copy`, `Clone` (unless `cloneable` + marker)                         |
| Zeroization                       | Full allocation wiped on drop (`zeroize` feature); includes `Vec`/`String` slack capacity |
| Timing safety                     | `ConstantTimeEq` for direct comparison; `HashEq` / `hash_eq_opt` for large/variable data   |
| Probabilistic equality (`hash-eq`) | BLAKE3 + fixed 32-byte digest compare; collision risk ~2⁻¹²⁸ (negligible)                 |
| Opt-in risky features             | Cloning/serialization gated by marker traits (`CloneableType`, `SerializableType`)         |
| Redacted debug                    | `Debug` impl always prints `[REDACTED]`                                                    |
| No unsafe code                    | `#![forbid(unsafe_code)]` enforced at crate level                                          |

## Feature Security Implications

| Feature              | Security Impact                                                                 | Recommendation                              |
|----------------------|----------------------------------------------------------------------------------|---------------------------------------------|
| `secure` (default)   | Enables `zeroize` + `ct-eq` — secure-by-default baseline                         | Always enable unless extreme constraints    |
| `zeroize`            | Wipes memory on drop; enables safe opt-in cloning/serialization                  | Strongly recommended                        |
| `ct-eq`              | Timing-safe direct byte comparison                                               | Strongly recommended; avoid `==`            |
| `hash-eq`            | Fast BLAKE3-based equality for large secrets; probabilistic but cryptographically safe | Prefer `hash_eq_opt` for most cases         |
| `rand`               | Secure random via `OsRng`; panics on failure                                     | Use only in trusted entropy environments    |
| `serde-deserialize`  | Auto-decodes hex/base64url/bech32/bech32m via fallible per-format traits; temporary buffers zeroized on failure | Enable only for trusted input sources       |
| `serde-serialize`    | Opt-in export via marker trait; audit all implementations                        | Enable sparingly; monitor exfiltration risk |
| `encoding-*`         | Per-format symmetric encoding/decoding traits (e.g., `ToHex`/`FromHexStr`); explicit, fallible, rejects invalid formats | Validate inputs upstream; prefer specific traits over umbrellas for strictness |
| `cloneable`          | Opt-in cloning via marker trait; increases exposure surface                      | Use minimally; prefer move semantics        |
| `full`               | All features enabled — convenient but increases attack surface                   | Development only; audit for production      |

## Module-by-Module Security Notes

### Wrappers (`dynamic.rs`, `fixed.rs`)

**Strengths**
- Private `inner` field prevents direct access
- Dual exposure model: scoped closures (leak-resistant) + direct refs (auditable)
- Full-capacity zeroization (`zeroize`)
- Redacted `Debug` output

**Potential weaknesses**
- Long-lived `expose_secret()` references can defeat scoping
- Macro-generated aliases lack runtime size checks
- Error messages may leak length metadata

**Mitigations**
- Prefer `with_secret()` / `with_secret_mut()`
- Audit all `expose_secret()` calls
- Contextualize errors to avoid side-channel information

### Traits (`traits/`)

**Strengths**
- Marker traits (`CloneableType`, `SerializableType`) force deliberate opt-in
- `ConstantTimeEq` and `HashEq` provide safe equality alternatives

**Potential weaknesses**
- Generic impls assume caller trustworthiness

**Mitigations**
- Audit custom marker impls
- Validate inputs before trait usage

### Encoding/Decoding (Traits & Errors)

**Strengths**
- Symmetric per-format traits: encoding (e.g., `ToHex`, `ToBech32`) and decoding (e.g., `FromHexStr`, `FromBech32Str`)
- Explicit, fallible methods; typed errors prevent silent failures
- Bech32/BIP-173 & Bech32m/BIP-350 HRP validation prevents injection attacks
- Strict format adherence: invalid strings rejected; only valid decodings accepted

**Potential weaknesses**
- Decoding is inherently fallible; untrusted input may cause errors or temporary allocations
- Length/format hints in errors (e.g., invalid HRP)
- Temporary buffers during multi-format auto-detection (`try_decode_any`)

**Mitigations**
- Treat all decoding input as untrusted; validate upstream
- Use specific traits (e.g., `FromBech32Str`) for strict format enforcement
- Fuzz parsers; sanitize inputs before decoding

## Best Practices

- Enable the `secure` feature unless you have extreme constraints
- Prefer scoped `with_secret()` over long-lived `expose_secret()`
- Use `hash_eq_opt(…, None)` for general-purpose equality checks
- Audit every `CloneableType` / `SerializableType` impl
- Validate and sanitize all inputs before encoding/decoding
- Monitor dependency CVEs and update regularly
- Treat secrets as radioactive — minimize exposure surface

## Vulnerability Reporting

- **Preferred**: GitHub private vulnerability reporting (Repository → Security → Report a vulnerability)
- **Alternative**: Public issue or draft
- **Expected response**: Acknowledgment within 48 hours; coordinated disclosure
- **Public disclosure**: After fix is released and users have reasonable time to update

## Disclaimer

This document reflects design intent and observed properties as of the current release.

**No warranties are provided**. Users are solely responsible for their own security evaluation, threat modeling, and audit.



================================================================================
// SECTION 005: src/dynamic.rs
// Created:  2026-01-20 06:27:03.727
// Modified: 2026-01-24 18:05:38.951
================================================================================
extern crate alloc;
use alloc::boxed::Box;

/// 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).
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: ?Sized> 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]> + crate::ConstantTimeEq + ?Sized,
{
    fn hash_eq(&self, other: &Self) -> bool {
        // Length is public metadata — safe to compare in variable time
        if (*self.inner).as_ref().len() != (*other.inner).as_ref().len() {
            return false;
        }

        crate::utilities::hash_eq_bytes((*self.inner).as_ref(), (*other.inner).as_ref())
    }

    fn hash_eq_opt(&self, other: &Self, hash_threshold_bytes: Option<usize>) -> bool {
        crate::utilities::hash_eq_opt_bytes(
            (*self.inner).as_ref(),
            (*other.inner).as_ref(),
            hash_threshold_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),
        }
    }
}

// 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]")
    }
}

// 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.
    #[inline]
    pub fn from_random(len: usize) -> Self {
        let mut bytes = vec![0u8; len];
        crate::utilities::fill_random_bytes_mut(&mut bytes);
        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/base64url/bech32 string or byte vector")
            }
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                let bytes = crate::utilities::decoding::try_decode_any(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-24 04:10:57.460
================================================================================
// 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")]
    LengthMismatch,
}

#[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-24 18:05:38.951
================================================================================
/// 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]> + crate::ConstantTimeEq,
{
    fn hash_eq(&self, other: &Self) -> bool {
        // Early length check — length is public metadata, safe to compare normally
        if self.inner.as_ref().len() != other.inner.as_ref().len() {
            return false;
        }

        crate::utilities::hash_eq_bytes(self.inner.as_ref(), other.inner.as_ref())
    }

    fn hash_eq_opt(&self, other: &Self, hash_threshold_bytes: Option<usize>) -> bool {
        crate::utilities::hash_eq_opt_bytes(
            self.inner.as_ref(),
            other.inner.as_ref(),
            hash_threshold_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.
    /// In debug builds, panics with detailed information on length mismatch to aid development.
    /// In release builds, returns an error on length mismatch to prevent information leaks.
    ///
    /// # 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());
    /// ```
    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
        if slice.len() != N {
            #[cfg(debug_assertions)]
            panic!(
                "Fixed<{}> from_slice: expected exactly {} bytes, got {}",
                N,
                N,
                slice.len()
            );
            #[cfg(not(debug_assertions))]
            return Err(crate::error::FromSliceError::LengthMismatch);
        }
        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/base64url/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 = crate::utilities::decoding::try_decode_any(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];
        crate::utilities::fill_random_bytes_mut(&mut bytes);
        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)
    }
}

// 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-24 18:05:38.952
================================================================================
// 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;

/// Public utility functions.
pub mod utilities;

/// 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-exports of encoding and decoding traits for convenient byte encoding/decoding extensions.

#[cfg(feature = "encoding-base64")]
pub use traits::FromBase64UrlStr;
#[cfg(feature = "encoding-bech32")]
pub use traits::FromBech32Str;
#[cfg(feature = "encoding-bech32")]
pub use traits::FromBech32mStr;
#[cfg(feature = "encoding-hex")]
pub use traits::FromHexStr;

#[cfg(feature = "encoding-base64")]
pub use traits::ToBase64Url;
#[cfg(feature = "encoding-bech32")]
pub use traits::ToBech32;
#[cfg(feature = "encoding-bech32")]
pub use traits::ToBech32m;
#[cfg(feature = "encoding-hex")]
pub use traits::ToHex;

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub use traits::{SecureDecoding, 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-24 00:05:22.847
// Modified: 2026-01-24 00:05:22.848
================================================================================
/// 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-24 00:05:22.859
// Modified: 2026-01-24 00:05:22.859
================================================================================
/// 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-24 00:05:22.870
// Modified: 2026-01-24 00:05:22.870
================================================================================
/// 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-24 00:05:22.885
// Modified: 2026-01-24 00:05:22.886
================================================================================
/// 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-24 00:05:22.896
================================================================================
//! 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-24 00:05:22.913
// Modified: 2026-01-24 00:05:22.913
================================================================================
//! 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-24 00:05:22.928
================================================================================
//! 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/decoding/base64_url.rs
// Created:  2026-01-24 18:05:38.952
// Modified: 2026-01-24 18:05:38.952
================================================================================
// secure-gate/src/traits/decoding/base64_url.rs
//! # FromBase64UrlStr Trait
//!
//! Extension trait for decoding URL-safe base64 strings to byte data.
//!
//! This trait provides secure, explicit decoding of base64url strings to byte vectors.
//! Input should be treated as untrusted; use fallible methods.
//!
//! ## Security Warning
//!
//! Decoding input from untrusted sources should use fallible `try_` methods.
//! Invalid input may indicate tampering or errors.
//!
/// ## Example
///
/// ```rust
/// # #[cfg(feature = "encoding-base64")]
/// use secure_gate::FromBase64UrlStr;
/// # #[cfg(feature = "encoding-base64")]
/// let base64_string = "QkJC";
/// # #[cfg(feature = "encoding-base64")]
/// let bytes = base64_string.try_from_base64url().unwrap();
/// // bytes is now Vec<u8>: [66, 66, 66]
/// ```
/// This trait is gated behind the `encoding-base64` feature.
#[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-base64")]
use crate::error::Base64Error;

/// Extension trait for decoding URL-safe base64 strings to byte data.
///
/// Input should be treated as untrusted; use fallible methods.
///
/// # Security Warning
///
/// Decoding input from untrusted sources should use fallible `try_` methods.
/// Invalid input may indicate tampering or errors.
///
/// ## Example
///
/// ```rust
/// # #[cfg(feature = "encoding-base64")]
/// use secure_gate::FromBase64UrlStr;
/// # #[cfg(feature = "encoding-base64")]
/// let base64_string = "QkJC";
/// # #[cfg(feature = "encoding-base64")]
/// let bytes = base64_string.try_from_base64url().unwrap();
/// // bytes is now Vec<u8>: [66, 66, 66]
/// ```
#[cfg(feature = "encoding-base64")]
pub trait FromBase64UrlStr {
    /// Fallibly decode a URL-safe base64 string to bytes.
    fn try_from_base64url(&self) -> Result<Vec<u8>, Base64Error>;
}

// Blanket impl to cover any AsRef<str> (e.g., &str, String, etc.)
#[cfg(feature = "encoding-base64")]
impl<T: AsRef<str> + ?Sized> FromBase64UrlStr for T {
    fn try_from_base64url(&self) -> Result<Vec<u8>, Base64Error> {
        URL_SAFE_NO_PAD
            .decode(self.as_ref())
            .map_err(|_| Base64Error::InvalidBase64)
    }
}



================================================================================
// SECTION 017: src/traits/decoding/bech32.rs
// Created:  2026-01-24 18:05:38.952
// Modified: 2026-01-24 18:05:38.952
================================================================================
// secure-gate/src/traits/decoding/bech32.rs

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

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

/// Extension trait for decoding Bech32 strings to byte data.
///
/// Input should be treated as untrusted; use fallible methods.
///
/// # Security Warning
///
/// Decoding input from untrusted sources should use fallible `try_` methods.
/// Invalid input may indicate tampering or errors.
///
#[cfg(feature = "encoding-bech32")]
pub trait FromBech32Str {
    /// Fallibly decode a Bech32 string to (HRP, bytes).
    fn try_from_bech32(&self) -> Result<(String, Vec<u8>), Bech32Error>;

    /// Fallibly decode a Bech32 string, expecting the specified HRP, returning bytes.
    fn try_from_bech32_expect_hrp(&self, expected_hrp: &str) -> Result<Vec<u8>, Bech32Error>;
}

// Blanket impl to cover any AsRef<str> (e.g., &str, String, etc.)
#[cfg(feature = "encoding-bech32")]
impl<T: AsRef<str> + ?Sized> FromBech32Str for T {
    fn try_from_bech32(&self) -> Result<(String, Vec<u8>), Bech32Error> {
        let (hrp, data) =
            bech32::decode(self.as_ref()).map_err(|_| Bech32Error::OperationFailed)?;
        // Validate that it is Bech32 variant by re-encoding
        let re_encoded = bech32::encode::<bech32::Bech32>(hrp.clone(), &data)
            .map_err(|_| Bech32Error::OperationFailed)?;
        if re_encoded != self.as_ref() {
            return Err(Bech32Error::OperationFailed);
        }
        if data.is_empty() {
            return Err(Bech32Error::OperationFailed);
        }
        Ok((hrp.as_str().to_string(), fes_to_u8s(data)))
    }

    fn try_from_bech32_expect_hrp(&self, expected_hrp: &str) -> Result<Vec<u8>, Bech32Error> {
        let (hrp, bytes) = self.try_from_bech32()?;
        if hrp != expected_hrp {
            return Err(Bech32Error::UnexpectedHrp {
                expected: expected_hrp.to_string(),
                got: hrp,
            });
        }
        Ok(bytes)
    }
}



================================================================================
// SECTION 018: src/traits/decoding/bech32m.rs
// Created:  2026-01-24 18:05:38.952
// Modified: 2026-01-24 18:05:38.952
================================================================================
//! # FromBech32mStr Trait
//!
//! Extension trait for decoding Bech32m strings to byte data.
//!
//! This trait provides secure, explicit decoding of Bech32m strings (BIP-350 checksum) to byte vectors.
//! Input should be treated as untrusted; use fallible methods.
//!
//! ## Security Warning
//!
//! Decoding input from untrusted sources should use fallible `try_` methods.
//! Invalid input may indicate tampering or errors.
//!

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

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

#[cfg(feature = "encoding-bech32")]
pub trait FromBech32mStr {
    /// Fallibly decode a Bech32m string to (HRP, bytes).
    fn try_from_bech32m(&self) -> Result<(String, Vec<u8>), Bech32Error>;

    /// Fallibly decode a Bech32m string, expecting the specified HRP, returning bytes.
    fn try_from_bech32m_expect_hrp(&self, expected_hrp: &str) -> Result<Vec<u8>, Bech32Error>;
}

// Blanket impl to cover any AsRef<str> (e.g., &str, String, etc.)
#[cfg(feature = "encoding-bech32")]
impl<T: AsRef<str> + ?Sized> FromBech32mStr for T {
    fn try_from_bech32m(&self) -> Result<(String, Vec<u8>), Bech32Error> {
        let (hrp, data) =
            bech32::decode(self.as_ref()).map_err(|_| Bech32Error::OperationFailed)?;
        // Validate that it is Bech32m variant by re-encoding
        let re_encoded = bech32::encode::<bech32::Bech32m>(hrp.clone(), &data)
            .map_err(|_| Bech32Error::OperationFailed)?;
        if re_encoded != self.as_ref() {
            return Err(Bech32Error::OperationFailed);
        }
        if data.is_empty() {
            return Err(Bech32Error::OperationFailed);
        }
        Ok((hrp.as_str().to_string(), fes_to_u8s(data)))
    }

    fn try_from_bech32m_expect_hrp(&self, expected_hrp: &str) -> Result<Vec<u8>, Bech32Error> {
        let (hrp, data) = self.try_from_bech32m()?;
        if hrp != expected_hrp {
            return Err(Bech32Error::UnexpectedHrp {
                expected: expected_hrp.to_string(),
                got: hrp,
            });
        }
        Ok(data)
    }
}



================================================================================
// SECTION 019: src/traits/decoding/hex.rs
// Created:  2026-01-24 18:05:38.952
// Modified: 2026-01-24 18:05:38.952
================================================================================
//! # FromHexStr Trait
//!
//! Extension trait for decoding hex strings to byte data.
//!
//! This trait provides secure, explicit decoding of hex strings to byte vectors.
//! Input should be treated as untrusted; use fallible methods.
//!
//! ## Security Warning
//!
//! Decoding input from untrusted sources should use fallible `try_` methods.
//! Invalid input may indicate tampering or errors.
//!

#[cfg(feature = "encoding-hex")]
use ::hex as hex_crate;

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

/// Extension trait for decoding hex strings to byte data.
///
/// Input should be treated as untrusted; use fallible methods.
///
/// # Security Warning
///
/// Decoding input from untrusted sources should use fallible `try_` methods.
/// Invalid input may indicate tampering or errors.
///
/// ## Example
///
/// ```rust
/// # #[cfg(feature = "encoding-hex")]
/// use secure_gate::FromHexStr;
/// # #[cfg(feature = "encoding-hex")]
/// let hex_string = "424344";
/// # #[cfg(feature = "encoding-hex")]
/// let bytes = hex_string.try_from_hex().unwrap();
/// // bytes is now Vec<u8>: [66, 66, 66]
/// ```
#[cfg(feature = "encoding-hex")]
pub trait FromHexStr {
    /// Fallibly decode a hex string to bytes.
    fn try_from_hex(&self) -> Result<Vec<u8>, HexError>;
}

// Blanket impl to cover any AsRef<str> (e.g., &str, String, etc.)
#[cfg(feature = "encoding-hex")]
impl<T: AsRef<str> + ?Sized> FromHexStr for T {
    fn try_from_hex(&self) -> Result<Vec<u8>, HexError> {
        hex_crate::decode(self.as_ref()).map_err(|_| HexError::InvalidHex)
    }
}



================================================================================
// SECTION 020: src/traits/decoding/mod.rs
// Created:  2026-01-24 18:05:38.952
// Modified: 2026-01-24 18:05:38.952
================================================================================
pub mod base64_url;
pub mod bech32;
pub mod bech32m;
pub mod hex;

#[cfg(feature = "encoding-base64")]
pub use base64_url::FromBase64UrlStr;
#[cfg(feature = "encoding-bech32")]
pub use bech32::FromBech32Str;
#[cfg(feature = "encoding-bech32")]
pub use bech32m::FromBech32mStr;
#[cfg(feature = "encoding-hex")]
pub use hex::FromHexStr;



================================================================================
// SECTION 021: src/traits/encoding/base64_url.rs
// Created:  2026-01-24 18:05:38.956
// Modified: 2026-01-24 19:00:22.854
================================================================================
//! # ToBase64Url Trait
//!
//! Extension trait for encoding byte data to URL-safe base64 strings (no padding).
//!
//! This trait provides secure, explicit encoding of byte slices to base64url strings.
//! All methods require the caller to first call `.expose_secret()` (or similar).
//!
//! ## 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_left`.
//! All calls require explicit `.expose_secret()` first — no implicit paths exist.
//!
/// ## Example
///
/// ```rust
/// # #[cfg(feature = "encoding-base64")]
/// use secure_gate::ToBase64Url;
/// # #[cfg(feature = "encoding-base64")]
/// let bytes = [0x42u8; 32];
/// # #[cfg(feature = "encoding-base64")]
/// let base64_string = bytes.to_base64url();
/// // base64_string is now a URL-safe base64 encoded String
/// ```
#[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-base64")]
/// Extension trait for encoding byte data to URL-safe base64 strings (no padding).
///
/// All methods require the caller to first call `.expose_secret()` (or similar).
///
/// # 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_left` from `ToHex`.
// All calls require explicit `.expose_secret()` first — no implicit paths exist.
///
/// # Example
///
/// ```rust
/// use secure_gate::ToBase64Url;
/// let bytes = [0x42u8; 32];
/// let base64_string = bytes.to_base64url();
/// // base64_string is now a URL-safe base64 encoded String
/// ```
pub trait ToBase64Url {
    /// Encode secret bytes as URL-safe base64 (no padding).
    fn to_base64url(&self) -> alloc::string::String;
}

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



================================================================================
// SECTION 022: src/traits/encoding/bech32.rs
// Created:  2026-01-24 18:05:38.957
// Modified: 2026-01-24 18:59:59.004
================================================================================
#[cfg(feature = "encoding-bech32")]
use ::bech32;

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

//
// Extension trait for encoding byte data to Bech32 strings with a specified Human-Readable Part (HRP).
//
// This trait provides secure, explicit encoding of byte slices to Bech32 strings using BIP-173 checksum.
// All methods require the caller to first call `.expose_secret()` (or similar).
//
// ## 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_left` from `ToHex`.
// All calls require explicit `.expose_secret()` first — no implicit paths exist.
//
// Decoding input from untrusted sources should use fallible `try_` methods.
//
// ## Example
//
// ```rust
// use secure_gate::traits::ToBech32;
// let bytes = [0x42u8; 20];
// let bech32_string = bytes.to_bech32("bc");
// // bech32_string is now a Bech32 encoded String with "bc" HRP
// ```
#[cfg(feature = "encoding-bech32")]
pub trait ToBech32 {
    /// Encode secret bytes as Bech32 with the specified HRP.
    fn to_bech32(&self, hrp: &str) -> alloc::string::String;

    /// Fallibly encode secret bytes as Bech32 with the specified HRP and optional expected HRP validation.
    fn try_to_bech32(
        &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.)
#[cfg(feature = "encoding-bech32")]
impl<T: AsRef<[u8]> + ?Sized> ToBech32 for T {
    #[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")
    }

    #[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)
    }
}



================================================================================
// SECTION 023: src/traits/encoding/bech32m.rs
// Created:  2026-01-24 18:05:38.957
// Modified: 2026-01-24 19:00:03.434
================================================================================
#[cfg(feature = "encoding-bech32")]
use ::bech32;

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

/// Extension trait for encoding byte data to Bech32m strings with a specified Human-Readable Part (HRP).
///
/// All methods require the caller to first call `.expose_secret()` (or similar).
///
/// # 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_left` from `ToHex`.
/// All calls require explicit `.expose_secret()` first — no implicit paths exist.
///
/// Decoding input from untrusted sources should use fallible `try_` methods.
///
/// # Example
///
/// ```rust
/// # #[cfg(feature = "encoding-bech32")]
/// use secure_gate::ToBech32m;
/// # #[cfg(feature = "encoding-bech32")]
/// let bytes = [0x42u8; 20];
/// # #[cfg(feature = "encoding-bech32")]
/// let bech32m_string = bytes.to_bech32m("bc");
/// // bech32m_string is now a Bech32m encoded String with "bc" HRP
/// ```
#[cfg(feature = "encoding-bech32")]
pub trait ToBech32m {
    /// Encode secret bytes as Bech32m with the specified HRP.
    fn to_bech32m(&self, hrp: &str) -> alloc::string::String;

    /// Fallibly encode secret bytes as Bech32m with the specified HRP and optional expected HRP validation.
    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.)
#[cfg(feature = "encoding-bech32")]
impl<T: AsRef<[u8]> + ?Sized> ToBech32m for T {
    #[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")
    }

    #[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 024: src/traits/encoding/hex.rs
// Created:  2026-01-24 18:05:38.957
// Modified: 2026-01-24 18:59:49.512
================================================================================
//! # ToHex Trait
//!
//! Extension trait for encoding byte data to lowercase hexadecimal strings.
//!
//! This trait provides secure, explicit encoding of byte slices to hex strings.
//! All methods require the caller to first call `.expose_secret()` (or similar).
//!
//! ## 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_left`.
//! All calls require explicit `.expose_secret()` first — no implicit paths exist.
//!
/// # Example
///
/// ```rust
/// # #[cfg(feature = "encoding-hex")]
/// use secure_gate::ToHex;
/// # #[cfg(feature = "encoding-hex")]
/// let bytes = [0x42u8; 32];
/// # #[cfg(feature = "encoding-hex")]
/// let hex_string = bytes.to_hex();
/// // hex_string is now String: "424242..."
/// ```
#[cfg(feature = "encoding-hex")]
use ::hex as hex_crate;

/// Extension trait for encoding byte data to lowercase hexadecimal strings.
///
/// All methods require the caller to first call `.expose_secret()` (or similar).
///
/// # 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_left`.
/// All calls require explicit `.expose_secret()` first — no implicit paths exist.
///
/// # Example
///
/// ```rust
/// # #[cfg(feature = "encoding-hex")]
/// use secure_gate::ToHex;
/// # #[cfg(feature = "encoding-hex")]
/// let bytes = [0x42u8; 32];
/// # #[cfg(feature = "encoding-hex")]
/// let hex_string = bytes.to_hex();
/// // hex_string is now String: "424242..."
/// ```
#[cfg(feature = "encoding-hex")]
pub trait ToHex {
    /// Encode secret bytes as lowercase hexadecimal.
    fn to_hex(&self) -> alloc::string::String;

    /// Encode secret bytes as uppercase hexadecimal.
    fn to_hex_upper(&self) -> alloc::string::String;

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

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

    #[inline(always)]
    fn to_hex_upper(&self) -> alloc::string::String {
        hex_crate::encode_upper(self.as_ref())
    }
}



================================================================================
// SECTION 025: src/traits/encoding/mod.rs
// Created:  2026-01-24 18:05:38.959
// Modified: 2026-01-24 18:05:38.959
================================================================================
// secure-gate/src/traits/encoding/mod.rs
pub mod base64_url;
pub mod bech32;
pub mod bech32m;
pub mod hex;

#[cfg(feature = "encoding-base64")]
pub use base64_url::ToBase64Url;
#[cfg(feature = "encoding-bech32")]
pub use bech32::ToBech32;
#[cfg(feature = "encoding-bech32")]
pub use bech32m::ToBech32m;
#[cfg(feature = "encoding-hex")]
pub use hex::ToHex;



================================================================================
// SECTION 026: src/traits/expose_secret.rs
// Created:  2026-01-20 07:05:59.548
// Modified: 2026-01-24 00:05:22.930
================================================================================
//! # 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 027: src/traits/expose_secret_mut.rs
// Created:  2026-01-20 06:27:04.286
// Modified: 2026-01-24 00:05:22.947
================================================================================
//! # 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 028: src/traits/hash_eq.rs
// Created:  2026-01-23 06:35:31.840
// Modified: 2026-01-24 03:42:13.482
================================================================================
/// 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.
///
/// ## Usage Recommendations
/// - For most use cases, prefer [`HashEq::hash_eq_opt`] — it automatically selects the best strategy based on size.
/// - Use plain [`HashEq::hash_eq`] only for large inputs (>32 bytes) or when uniform probabilistic behavior is needed.
/// - Use [`crate::ConstantTimeEq`] for small deterministic equality (<32 bytes).
///
/// ## 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_opt(&b, None) {
///     // constant-time, fast for large blobs
/// }
/// # }
/// ```
#[cfg(feature = "hash-eq")]
pub trait HashEq {
    /// Probabilistic constant-time equality check using BLAKE3 hashing.
    ///
    /// This provides a fast, constant-time equality comparison via BLAKE3 + fixed-size digest compare.
    /// Useful for large/variable-length secrets where direct `ct_eq` is slow or increases side-channel risk.
    ///
    /// # Security Warnings
    /// - Probabilistic: collisions extremely unlikely (~2⁻¹²⁸), but not impossible.
    ///   Use `ConstantTimeEq` for strict deterministic equality.
    /// - DoS risk: hashing large untrusted inputs is costly — bound sizes or rate-limit.
    /// - Deterministic unless `"rand"` feature is enabled (then per-process random key).
    ///
    /// # Performance
    /// - Fixed overhead ~120–150 ns + very low per-byte cost.
    /// - Beats full `ct_eq` for inputs > ~300–500 bytes.
    ///
    fn hash_eq(&self, other: &Self) -> bool;

    /// **Recommended** hybrid equality check: `ct_eq` for small inputs, `hash_eq` for large ones.
    ///
    /// Automatically chooses the faster/appropriate path while preserving constant-time safety.
    ///
    /// - Uses `ct_eq` (deterministic, zero collision risk) if size ≤ threshold
    /// - Uses `hash_eq` (probabilistic, faster for large inputs) if size > threshold
    /// - Default threshold: 32 bytes (conservative crossover point)
    /// - Length mismatch → `false` immediately (length is public metadata)
    ///
    /// # Arguments
    /// - `hash_threshold_bytes`: `None` = use default (32), `Some(n)` = custom threshold
    ///
    /// # When to use
    /// Prefer this method in most cases unless you need:
    /// - strict determinism on all sizes → use `ConstantTimeEq`
    /// - uniform probabilistic behavior → use plain `hash_eq`
    ///
    /// # Examples
    /// ```
    /// # #[cfg(feature = "hash-eq")]
    /// # {
    /// use secure_gate::{Dynamic, Fixed, HashEq};
    ///
    /// let small_a = Fixed::new([42u8; 16]);
    /// let small_b = Fixed::new([42u8; 16]);
    /// assert!(small_a.hash_eq_opt(&small_b, None));           // → ct_eq path
    ///
    /// let large_a: Dynamic<Vec<u8>> = vec![42u8; 2048].into();
    /// let large_b: Dynamic<Vec<u8>> = vec![42u8; 2048].into();
    /// assert!(large_a.hash_eq_opt(&large_b, None));           // → hash_eq path
    ///
    /// // Force hashing even on small input
    /// assert!(small_a.hash_eq_opt(&small_b, Some(0)));
    /// # }
    /// ```
    fn hash_eq_opt(&self, other: &Self, hash_threshold_bytes: Option<usize>) -> bool;
}



================================================================================
// SECTION 029: src/traits/mod.rs
// Created:  2026-01-20 06:27:04.331
// Modified: 2026-01-24 18:05:38.960
================================================================================
// # 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`] - Umbrella trait for secure byte encoding to strings (requires encoding features)
// - [`SecureDecoding`] - Umbrella trait for secure decoding from 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`] and [`SecureDecoding`] for byte encoding/decoding
// - 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;

pub mod decoding;
pub mod encoding;

#[cfg(feature = "encoding-base64")]
pub use decoding::FromBase64UrlStr;
#[cfg(feature = "encoding-bech32")]
pub use decoding::FromBech32Str;
#[cfg(feature = "encoding-bech32")]
pub use decoding::FromBech32mStr;
#[cfg(feature = "encoding-hex")]
pub use decoding::FromHexStr;

#[cfg(feature = "encoding-base64")]
pub use encoding::ToBase64Url;
#[cfg(feature = "encoding-bech32")]
pub use encoding::ToBech32;
#[cfg(feature = "encoding-bech32")]
pub use encoding::ToBech32m;
#[cfg(feature = "encoding-hex")]
pub use encoding::ToHex;

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub trait SecureEncoding {}

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
impl<T: AsRef<[u8]> + ?Sized> SecureEncoding for T {}

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
pub trait SecureDecoding {}

#[cfg(any(
    feature = "encoding-hex",
    feature = "encoding-base64",
    feature = "encoding-bech32"
))]
impl<T: AsRef<str> + ?Sized> SecureDecoding for T {}

#[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 030: src/traits/serializable_type.rs
// Created:  2026-01-24 00:05:23.018
// Modified: 2026-01-24 00:05:23.018
================================================================================
//! 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 {}



================================================================================
// SECTION 031: src/utilities/decoding.rs
// Created:  2026-01-24 18:05:38.960
// Modified: 2026-01-24 18:05:38.961
================================================================================
// secure-gate/src/utilities/decoding.rs
//! Multi-format decoding helpers for secure-gate.
//!
//! This module provides utilities for decoding strings that may be encoded in various formats.

#[cfg(all(feature = "encoding-bech32", feature = "serde-deserialize"))]
use super::encoding::fes_to_u8s;

/// Attempt to decode a string in priority order: Bech32 → Bech32m → Hex → Base64url.
///
/// Returns `Ok(Vec<u8>)` on success or `Err(DecodingError)` if no format matches.
#[cfg(feature = "serde-deserialize")]
pub fn try_decode_any(s: &str) -> Result<Vec<u8>, crate::DecodingError> {
    #[cfg(feature = "encoding-bech32")]
    {
        use ::bech32;
        // Try Bech32 first; the bech32 crate's decode function automatically handles both Bech32 (BIP-173) and Bech32m (BIP-350), prioritizing Bech32 checksum validation first
        if let Ok((_, data)) = bech32::decode(s) {
            return Ok(fes_to_u8s(data));
        }
    }

    #[cfg(feature = "encoding-hex")]
    if let Ok(data) = ::hex::decode(s) {
        return Ok(data);
    }

    #[cfg(feature = "encoding-base64")]
    {
        use ::base64::engine::general_purpose::URL_SAFE_NO_PAD;
        use ::base64::Engine as _;
        if let Ok(data) = URL_SAFE_NO_PAD.decode(s) {
            return Ok(data);
        }
    }

    Err(crate::DecodingError::InvalidEncoding)
}



================================================================================
// SECTION 032: src/utilities/encoding.rs
// Created:  2026-01-24 18:05:38.961
// Modified: 2026-01-24 18:05:38.961
================================================================================
// secure-gate/src/utilities/encoding.rs
/// Local implementation of bit conversion for Bech32, since bech32 crate doesn't expose it in v0.11.
#[cfg(feature = "encoding-bech32")]
pub(crate) 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))
}

/// Convert 5-bit Fe32 values (from bech32 decode) back into 8-bit bytes.
///
/// Used internally during bech32 deserialization.
#[cfg(feature = "encoding-bech32")]
pub(crate) fn fes_to_u8s(data: Vec<u8>) -> Vec<u8> {
    let mut bytes = Vec::new();
    let mut acc: u64 = 0;
    let mut bits: u8 = 0;

    for fe in data {
        acc = (acc << 5) | (fe as u64);
        bits += 5;

        while bits >= 8 {
            bits -= 8;
            bytes.push(((acc >> bits) & 0xFF) as u8);
        }
    }

    bytes
}



================================================================================
// SECTION 033: src/utilities/mod.rs
// Created:  2026-01-24 18:05:38.961
// Modified: 2026-01-24 18:05:38.961
================================================================================
//! Shared utility functions for the `secure-gate` crate.
//!
//! This module contains helpers used by both `Fixed` and `Dynamic` secret types,
//! especially for random generation, constant-time / hash-based equality,
//! and string decoding during deserialization.

pub mod decoding;
pub mod encoding;

#[cfg(feature = "hash-eq")]
use crate::ConstantTimeEq;

#[cfg(feature = "rand")]
use rand::{rngs::OsRng, TryRngCore};

/// Fills a mutable byte slice with cryptographically secure random bytes
/// using the OS-provided RNG.
///
/// # Panics
/// Panics on RNG failure (fail-fast behavior suitable for cryptographic code).
///
/// # Example
/// ```
/// # #[cfg(feature = "rand")]
/// # {
/// use secure_gate::utilities::fill_random_bytes_mut;
/// let mut key = [0u8; 32];
/// fill_random_bytes_mut(&mut key);
/// # }
/// ```
#[cfg(feature = "rand")]
pub fn fill_random_bytes_mut(bytes: &mut [u8]) {
    OsRng
        .try_fill_bytes(bytes)
        .expect("OsRng failure is a program error");
}

// ─────────────────────────────────────────────────────────────────────────────
//                Hash-based / constant-time equality helpers
// ─────────────────────────────────────────────────────────────────────────────

/// Constant-time / hash-based equality check for arbitrary byte slices.
///
/// When the `rand` feature is enabled, uses a static random key + BLAKE3.
/// Otherwise falls back to plain BLAKE3 (still constant-time via `ct_eq`).
#[cfg(feature = "hash-eq")]
pub(crate) fn hash_eq_bytes(data1: &[u8], data2: &[u8]) -> bool {
    #[cfg(feature = "rand")]
    {
        use once_cell::sync::Lazy;

        static HASH_EQ_KEY: Lazy<[u8; 32]> = Lazy::new(|| {
            let mut key = [0u8; 32];
            fill_random_bytes_mut(&mut key); // now reuses the shared helper
            key
        });

        let mut hasher_a = blake3::Hasher::new_keyed(&HASH_EQ_KEY);
        let mut hasher_b = blake3::Hasher::new_keyed(&HASH_EQ_KEY);

        hasher_a.update(data1);
        hasher_b.update(data2);

        hasher_a
            .finalize()
            .as_bytes()
            .ct_eq(hasher_b.finalize().as_bytes())
    }

    #[cfg(not(feature = "rand"))]
    {
        let hash_a = blake3::hash(data1);
        let hash_b = blake3::hash(data2);
        hash_a.as_bytes().ct_eq(hash_b.as_bytes())
    }
}

/// Equality check that uses direct constant-time comparison for small inputs
/// and hash-based comparison for larger inputs (side-channel resistance).
#[cfg(feature = "hash-eq")]
pub(crate) fn hash_eq_opt_bytes(
    data1: &[u8],
    data2: &[u8],
    hash_threshold_bytes: Option<usize>,
) -> bool {
    if data1.len() != data2.len() {
        return false;
    }

    let threshold = hash_threshold_bytes.unwrap_or(32);

    if data1.len() <= threshold {
        data1.ct_eq(data2)
    } else {
        hash_eq_bytes(data1, data2)
    }
}

// ─────────────────────────────────────────────────────────────────────────────
//                   String → bytes decoding helpers
// ─────────────────────────────────────────────────────────────────────────────
