Skip to main content

codec_hex/
decode.rs

1// SPDX-FileCopyrightText: 2026 ReallyMe LLC
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use crate::HexError;
6use zeroize::Zeroizing;
7
8/// Decode canonical lowercase hexadecimal bytes.
9pub fn lower_hex_to_bytes(input: &str) -> Result<Vec<u8>, HexError> {
10    let (pairs, remainder) = input.as_bytes().as_chunks::<2>();
11    if !remainder.is_empty() {
12        return Err(HexError::OddLength);
13    }
14
15    let mut output = Zeroizing::new(Vec::with_capacity(pairs.len()));
16    for [high_byte, low_byte] in pairs {
17        let high = lower_hex_value(*high_byte)?;
18        let low = lower_hex_value(*low_byte)?;
19        output.push((high << 4) | low);
20    }
21
22    Ok(core::mem::take(&mut *output))
23}
24
25fn lower_hex_value(byte: u8) -> Result<u8, HexError> {
26    match byte {
27        b'0'..=b'9' => Ok(byte - b'0'),
28        b'a'..=b'f' => Ok(byte - b'a' + 10),
29        b'A'..=b'F' => Err(HexError::Uppercase),
30        _ => Err(HexError::InvalidCharacter),
31    }
32}