merkrs 0.3.0

Merkle tree library for Rust, compatible with OpenZeppelin's JavaScript implementation
Documentation
//! 32-byte hash values and hex-string conversion utilities.

use crate::error::{Error, Result};

/// A 32-byte hash value used as tree nodes and leaves.
pub type Bytes32 = [u8; 32];

/// Parse a hex string (with optional `0x` prefix) into [`Bytes32`].
///
/// # Errors
///
/// Returns [`Error::HexDecode`] if the string is not valid hex, or
/// [`Error::InvalidNodeLength`] if the decoded bytes are not exactly 32.
pub fn decode_hex(s: &str) -> Result<Bytes32> {
    let s = s.strip_prefix("0x").unwrap_or(s);
    let bytes = hex::decode(s)?;
    let len = bytes.len();
    bytes.try_into().map_err(|_| Error::InvalidNodeLength(len))
}

/// Encode [`Bytes32`] as a `0x`-prefixed hex string.
#[must_use]
pub fn encode_hex(bytes: &Bytes32) -> String {
    format!("0x{}", hex::encode(bytes))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn hex_roundtrip() {
        let original = [0xab; 32];
        let hex = encode_hex(&original);
        assert!(hex.starts_with("0x"), "should have 0x prefix");
        let recovered = decode_hex(&hex).unwrap();
        assert_eq!(original, recovered);
    }

    #[test]
    fn hex_without_prefix() {
        let hex = "0000000000000000000000000000000000000000000000000000000000000001";
        let bytes = decode_hex(hex).unwrap();
        assert_eq!(bytes[31], 1);
    }

    #[test]
    fn hex_with_prefix() {
        let hex = "0x0000000000000000000000000000000000000000000000000000000000000001";
        let bytes = decode_hex(hex).unwrap();
        assert_eq!(bytes[31], 1);
    }

    #[test]
    fn invalid_hex_length() {
        let result = decode_hex("0x00");
        assert!(matches!(result, Err(Error::InvalidNodeLength(1))));
    }
}