uhash-core 0.5.1

UniversalHash v4 - democratic proof-of-work algorithm where phones compete with servers
Documentation
//! Proof verification (lightweight, deterministic).

use uhash_types::{Difficulty, Proof};

/// Check if a hash meets the required difficulty (leading zero bits).
///
/// Difficulty is measured as the number of leading zero bits required.
/// For example, difficulty 16 requires the first 2 bytes to be zero.
///
/// # Example
///
/// ```rust
/// use uhash_core::meets_difficulty;
///
/// // Hash with 20 leading zero bits (0x00, 0x00, 0x0F = 16 + 4 zeros)
/// let hash: [u8; 32] = [
///     0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
///     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
///     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
///     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/// ];
/// assert!(meets_difficulty(&hash, 16));  // 16 leading zeros - pass
/// assert!(meets_difficulty(&hash, 20));  // 20 leading zeros - pass
/// assert!(!meets_difficulty(&hash, 21)); // Only 20 zeros - fail
/// ```
#[inline(always)]
pub fn meets_difficulty(hash: &[u8; 32], difficulty: u32) -> bool {
    let mut zero_bits = 0u32;

    for byte in hash.iter() {
        if *byte == 0 {
            zero_bits += 8;
        } else {
            zero_bits += byte.leading_zeros();
            break;
        }
    }

    zero_bits >= difficulty
}

/// Verify a proof: recompute hash and check difficulty.
pub fn verify(header: &[u8], proof: &Proof, difficulty: Difficulty) -> bool {
    let mut input = Vec::with_capacity(header.len() + 8);
    input.extend_from_slice(header);
    input.extend_from_slice(&proof.nonce.to_le_bytes());
    let computed = crate::hash::hash(&input);
    computed == proof.hash && meets_difficulty(&computed, difficulty.bits())
}

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;