1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! Hexadecimal encoding trait.
//!
//! > **Import path:** `use secure_gate::ToHex;`
//!
//! This trait provides secure, explicit encoding of byte data to lowercase
//! (or uppercase) hexadecimal strings. It is intended for intentional export
//! only (QR codes, audited logs, API responses).
//!
//! Requires the `encoding-hex` feature.
//!
//! # Security Notes
//!
//! - **Full secret exposure**: The resulting string contains the **entire** secret.
//! Always treat output as sensitive; do not log or persist without protection.
//! - **Always wiped**: `to_hex()` / `to_hex_upper()` return
//! [`EncodedSecret`](crate::EncodedSecret), which wraps `Zeroizing<String>`, redacts
//! its `Debug`, and wipes on drop.
//! There is no unprotected variant. `.into_inner()` is the named point where that
//! protection ends.
//! - **Audit visibility**: Direct calls (`key.to_hex()` / `key.to_hex_upper()`) do **not** appear in
//! `grep expose_secret` / `grep with_secret` audit sweeps. For audit-first teams or
//! multi-step operations, prefer `with_secret(|b| b.to_hex())` — the borrow checker
//! enforces the reference cannot escape the closure.
//! - **Decoding lives elsewhere**: this module encodes. For the reverse direction and
//! its untrusted-input rules see `FromHexStr`; validate hex
//! strings upstream before wrapping
//! in secrets.
//!
//! # Example
//!
//! ```rust
//! # #[cfg(feature = "encoding-hex")]
//! use secure_gate::{Fixed, ToHex, RevealSecret};
//! # #[cfg(feature = "encoding-hex")]
//! {
//! let secret = Fixed::new([0x0au8, 0x0bu8, 0x0cu8, 0x0du8]);
//!
//! // Blanket impl on the inner byte array (via with_secret):
//! let hex = secret.with_secret(|s| s.to_hex());
//! assert_eq!(&*hex, "0a0b0c0d");
//!
//! let hex_upper = secret.with_secret(|s| s.to_hex_upper());
//! assert_eq!(&*hex_upper, "0A0B0C0D");
//!
//! // Wrapper method (Direct Fixed<[u8; N]> API — same result):
//! assert_eq!(&*secret.to_hex(), "0a0b0c0d");
//! }
//! ```
use base16ct;
/// Extension trait for encoding byte data as hexadecimal strings.
///
/// *Requires feature `encoding-hex`.*
///
/// Blanket-implemented for `AsRef<[u8]>` + [`EncodableBytes`](super::EncodableBytes) (byte slices, arrays, `Vec<u8>`),
/// and implemented directly on the byte-shaped wrappers (`Fixed<[u8; N]>`,
/// `Dynamic<Vec<u8>>`). To encode a secret wrapper, call `key.to_hex()` with this
/// trait in scope (ergonomically safest for single operations — no reference in the
/// caller's hands), or use `with_secret(|b| b.to_hex())` for multi-step operations
/// or when audit-greppability matters.
// Blanket impl over AsRef<[u8]> + EncodableBytes (e.g. &[u8], Vec<u8>, [u8; N]).
// encode_string requires alloc — the trait itself is alloc-gated.