clock-hash 1.0.0

ClockHash-256: Consensus hash function for ClockinChain
Documentation
//! Basic SIMD functionality tests
//!
//! Tests for core SIMD functionality, consistency, and edge cases.

#[cfg(test)]
mod tests {
    extern crate alloc;
    use crate::simd::dispatch::*;
    use crate::simd::scalar::*;
    use alloc::vec::Vec;

    #[test]
    fn test_simd_clock_mix_consistency() {
        let mut msg1 = [0u64; 16];
        let mut msg2 = [0u64; 16];

        // Fill with test data
        for i in 0..16 {
            msg1[i] = (i as u64).wrapping_mul(0x123456789ABCDEF0);
            msg2[i] = msg1[i];
        }

        // Apply both implementations
        scalar_clock_mix(&mut msg1);
        clock_mix_avx2(&mut msg2);

        // Debug output for differences
        if msg1 != msg2 {
            println!("Input: {:?}", [0u64; 16].iter().enumerate().map(|(i, _)| (i as u64).wrapping_mul(0x123456789ABCDEF0)).collect::<Vec<_>>());
            println!("Scalar result: {:?}", msg1);
            println!("AVX2 result:   {:?}", msg2);
            for i in 0..16 {
                if msg1[i] != msg2[i] {
                    println!("Difference at [{}]: Scalar={:016x}, AVX2={:016x}", i, msg1[i], msg2[i]);
                }
            }
        }

        // Results should be identical
        assert_eq!(
            msg1, msg2,
            "SIMD and scalar implementations should produce identical results"
        );
    }


    #[test]
    fn test_simd_edge_cases() {
        // Test with all zeros
        let mut msg1 = [0u64; 16];
        let mut msg2 = [0u64; 16];
        scalar_clock_mix(&mut msg1);
        clock_mix_avx2(&mut msg2);
        assert_eq!(msg1, msg2, "All zeros case should work");

        // Test with all ones
        let mut msg1 = [u64::MAX; 16];
        let mut msg2 = [u64::MAX; 16];
        scalar_clock_mix(&mut msg1);
        clock_mix_avx2(&mut msg2);
        assert_eq!(msg1, msg2, "All ones case should work");

        // Test with alternating pattern
        let mut msg1 = [0u64; 16];
        let mut msg2 = [0u64; 16];
        for i in 0..16 {
            let val = if i % 2 == 0 {
                0xAAAAAAAAAAAAAAAA
            } else {
                0x5555555555555555
            };
            msg1[i] = val;
            msg2[i] = val;
        }
        scalar_clock_mix(&mut msg1);
        clock_mix_avx2(&mut msg2);
        assert_eq!(msg1, msg2, "Alternating pattern should work");
    }

    #[test]
    fn test_simd_no_memory_corruption() {
        // Test that SIMD operations don't corrupt adjacent memory (simplified for no_std)
        let test_data = [0x123456789ABCDEF0u64; 16];
        let mut data = test_data.clone();

        clock_mix_avx2(&mut data);

        // Verify test area was modified
        assert_ne!(data, test_data, "Test data should have been modified");

        // Compare with scalar version
        let mut scalar_data = test_data;
        scalar_clock_mix(&mut scalar_data);
        assert_eq!(data, scalar_data, "SIMD result should match scalar");
    }

    #[test]
    fn test_simd_multiple_calls_consistency() {
        // Test that multiple SIMD calls produce consistent results
        let mut msg1 = [0xCAFEBABEu64; 16];
        let mut msg2 = [0xCAFEBABEu64; 16];

        // Apply operation multiple times
        for _ in 0..3 {
            clock_mix_avx2(&mut msg1);
            scalar_clock_mix(&mut msg2);
        }

        assert_eq!(
            msg1, msg2,
            "Multiple applications should maintain consistency"
        );
    }

    #[test]
    fn test_simd_consistency_under_modification() {
        // Test that SIMD and scalar produce consistent results even with
        // unusual modification patterns
        let patterns = [
            [0u64; 16],               // All zeros
            [u64::MAX; 16],           // All max
            [1u64 << 63; 16],         // High bit set
            [0xAAAAAAAAAAAAAAAA; 16], // Alternating pattern
            [0x5555555555555555; 16], // Inverse alternating
        ];

        for (i, pattern) in patterns.iter().enumerate() {
            let mut msg1 = *pattern;
            let mut msg2 = *pattern;

            scalar_clock_mix(&mut msg1);
            clock_mix_avx2(&mut msg2);

            assert_eq!(
                msg1, msg2,
                "Pattern {} should produce consistent results",
                i
            );
        }
    }

    #[test]
    fn test_endianness_handling() {
        // Test that byte-to-u64 conversion works correctly
        let block = [0u8; 128];
        let mut state1 = [0u64; 8];
        let mut state2 = [0u64; 8];

        // Initialize states
        for i in 0..8 {
            state1[i] = (i as u64) * 0x1111111111111111;
            state2[i] = state1[i];
        }

        process_block_simd_scalar(&block, &mut state1);
        process_block_simd(&block, &mut state2);

        assert_eq!(
            state1, state2,
            "Block processing should handle endianness correctly"
        );
    }

    /// Scalar version of process_block_simd for testing
    fn process_block_simd_scalar(block: &[u8; 128], state: &mut [u64; 8]) {
        // Parse block to 16 u64 words (little-endian)
        let mut words = [0u64; 16];
        for i in 0..16 {
            let offset = i * 8;
            words[i] = u64::from_le_bytes([
                block[offset],
                block[offset + 1],
                block[offset + 2],
                block[offset + 3],
                block[offset + 4],
                block[offset + 5],
                block[offset + 6],
                block[offset + 7],
            ]);
        }

        // Apply ClockMix
        scalar_clock_mix(&mut words);

        // Inject into state
        for i in 0..8 {
            state[i] = state[i].wrapping_add(words[i]);
            let rot_idx = (i + 4) % 8;
            state[i] ^= crate::utils::rotl64(state[rot_idx], 17);
        }

        crate::clockpermute::clock_permute(state);
    }
}