1#[cfg(feature = "simd")]
7use crate::simd::clock_mix_avx2;
8
9use crate::constants::{ROTATION_SCHEDULE, SBOX};
10use crate::utils::rotl64;
11
12#[inline]
28pub fn clock_mix(message: &mut [u64; 16]) {
29 #[cfg(feature = "simd")]
30 {
31 clock_mix_avx2(message);
32 }
33
34 #[cfg(not(feature = "simd"))]
35 {
36 for i in 0..16 {
39 let next_idx = (i + 1) % 16;
40 let rotation = ROTATION_SCHEDULE[i];
41 message[i] ^= rotl64(message[next_idx], rotation);
42 }
43
44 for i in 0..16 {
46 let sbox_idx = (message[i] & 0xFF) as usize;
47 message[i] = message[i].wrapping_add(SBOX[sbox_idx] as u64);
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn test_clock_mix_basic() {
58 let mut msg = [0u64; 16];
59 msg[0] = 0x1234567890ABCDEF;
60
61 let original = msg;
62 clock_mix(&mut msg);
63
64 assert_ne!(msg, original);
66 }
67
68 #[test]
69 fn test_clock_mix_avalanche() {
70 let mut msg1 = [0u64; 16];
71 let mut msg2 = [0u64; 16];
72
73 msg1[0] = 0x0000000000000000;
74 msg2[0] = 0x0000000000000001; clock_mix(&mut msg1);
77 clock_mix(&mut msg2);
78
79 assert_ne!(msg1, msg2);
81 }
82
83 #[test]
84 fn test_clock_mix_deterministic() {
85 let mut msg = [0u64; 16];
86 msg[0] = 0xDEADBEEFCAFEBABE;
87
88 let mut msg_copy = msg;
89
90 clock_mix(&mut msg);
91 clock_mix(&mut msg_copy);
92
93 assert_eq!(msg, msg_copy);
95 }
96}