//! F6 — Crypto monomers: MC_48–MC_55
//!
//! Cryptographic operations. SHA-256 requires the `sha2` feature.

/// MC_48 — HASH: SHA-256 hash of a byte slice.
///
/// Requires the `sha2` feature flag.
///
/// ```rust,ignore
/// use brik64_core::mc::hash_sha256;
/// let digest = hash_sha256(b"hello world");
/// assert_eq!(digest.len(), 32);
/// ```
#[cfg(feature = "sha2")]
pub fn hash_sha256(data: &[u8]) -> [u8; 32] {
    use sha2::{Digest, Sha256};
    let mut hasher = Sha256::new();
    hasher.update(data);
    hasher.finalize().into()
}

/// MC_49 — HASH_HEX: SHA-256 hash returned as lowercase hex string.
#[cfg(feature = "sha2")]
pub fn hash_hex(data: &[u8]) -> String {
    let bytes = hash_sha256(data);
    bytes.iter().map(|b| format!("{:02x}", b)).collect()
}

/// MC_50 — XOR_BYTES: XOR two byte slices (length = min of both).
///
/// ```
/// use brik64_core::mc::xor_bytes;
/// let a = [0xAA, 0xBB, 0xCC];
/// let b = [0xFF, 0xFF, 0xFF];
/// assert_eq!(xor_bytes(&a, &b), vec![0x55, 0x44, 0x33]);
/// ```
pub fn xor_bytes(a: &[u8], b: &[u8]) -> Vec<u8> {
    a.iter().zip(b.iter()).map(|(x, y)| x ^ y).collect()
}

/// MC_51 — ROTATE_LEFT: Bit-rotate a u64 value left by n positions.
pub fn rotate_left(val: u64, n: u32) -> u64 {
    val.rotate_left(n % 64)
}

/// MC_52 — ROTATE_RIGHT: Bit-rotate a u64 value right by n positions.
pub fn rotate_right(val: u64, n: u32) -> u64 {
    val.rotate_right(n % 64)
}

/// MC_53 — CONSTANT_EQ: Constant-time byte slice equality comparison.
///
/// Avoids timing side-channels present in `==`.
///
/// ```
/// use brik64_core::mc::constant_eq;
/// assert!(constant_eq(b"secret", b"secret"));
/// assert!(!constant_eq(b"secret", b"notit!"));
/// ```
pub fn constant_eq(a: &[u8], b: &[u8]) -> bool {
    if a.len() != b.len() {
        return false;
    }
    let mut diff = 0u8;
    for (x, y) in a.iter().zip(b.iter()) {
        diff |= x ^ y;
    }
    diff == 0
}

/// MC_54 — ZERO_BYTES: Create a zeroed byte vector of length n (max 4096).
pub fn zero_bytes(n: usize) -> Vec<u8> {
    vec![0u8; n.min(4096)]
}

/// MC_55 — BYTES_TO_HEX: Encode bytes as lowercase hex string.
///
/// ```
/// use brik64_core::mc::bytes_to_hex;
/// assert_eq!(bytes_to_hex(&[0xDE, 0xAD, 0xBE, 0xEF]), "deadbeef");
/// ```
pub fn bytes_to_hex(data: &[u8]) -> String {
    data.iter().map(|b| format!("{:02x}", b)).collect()
}
