Skip to main content

modo/encoding/
hex.rs

1//! # modo::encoding::hex
2//!
3//! Lowercase hexadecimal encoding and SHA-256 digest helper.
4//!
5//! Provides:
6//! - [`encode`] — encode a byte slice to a lowercase hex string
7//! - [`sha256`] — SHA-256 hash of input, returned as a 64-character hex string
8
9use sha2::{Digest as _, Sha256};
10
11const HEX_TABLE: &[u8; 16] = b"0123456789abcdef";
12
13/// Encode a byte slice as a lowercase hexadecimal string.
14///
15/// # Examples
16///
17/// ```rust
18/// use modo::encoding::hex;
19///
20/// assert_eq!(hex::encode(b"\xde\xad\xbe\xef"), "deadbeef");
21/// assert_eq!(hex::encode(b""), "");
22/// ```
23pub fn encode(bytes: &[u8]) -> String {
24    let mut buf = Vec::with_capacity(bytes.len() * 2);
25    for &b in bytes {
26        buf.push(HEX_TABLE[(b >> 4) as usize]);
27        buf.push(HEX_TABLE[(b & 0x0f) as usize]);
28    }
29    // SAFETY: every byte written is from HEX_TABLE which contains only ASCII.
30    unsafe { String::from_utf8_unchecked(buf) }
31}
32
33/// SHA-256 hash of `data`, returned as a 64-character lowercase hex string.
34///
35/// # Examples
36///
37/// ```rust
38/// use modo::encoding::hex;
39///
40/// let digest = hex::sha256(b"hello world");
41/// assert_eq!(digest.len(), 64);
42/// assert_eq!(
43///     digest,
44///     "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
45/// );
46/// ```
47pub fn sha256(data: impl AsRef<[u8]>) -> String {
48    encode(&Sha256::digest(data.as_ref()))
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn encode_empty() {
57        assert_eq!(encode(b""), "");
58    }
59
60    #[test]
61    fn encode_known_bytes() {
62        assert_eq!(encode(b"\xde\xad\xbe\xef"), "deadbeef");
63    }
64
65    #[test]
66    fn encode_all_zeros() {
67        assert_eq!(encode(&[0u8; 4]), "00000000");
68    }
69
70    #[test]
71    fn encode_sequential() {
72        assert_eq!(
73            encode(&[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]),
74            "0123456789abcdef"
75        );
76    }
77}