clock_hash/
clockpermute.rs1use crate::constants::{P0, ROTATION_SCHEDULE};
7use crate::utils::rotl64;
8
9const ROUNDS: usize = 16;
11
12#[inline]
27pub fn clock_permute(state: &mut [u64; 8]) {
28 for round in 0..ROUNDS {
29 for i in 0..8 {
31 let next_idx = (i + 1) % 8;
32 state[i] = state[i].wrapping_add(state[next_idx]).wrapping_mul(P0);
33 }
34
35 for i in 0..8 {
37 let xor_idx = (i + 3) % 8;
38 let rotation_idx = (round + i) % 16;
39 let rotation = ROTATION_SCHEDULE[rotation_idx];
40 state[i] = rotl64(state[i] ^ state[xor_idx], rotation);
41 }
42
43 state.swap(1, 5);
45 state.swap(2, 6);
46 state.swap(3, 7);
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_clock_permute_zeros() {
56 let mut state = [0u64; 8];
57 let original = state;
58 clock_permute(&mut state);
59 assert_eq!(state, original);
61 }
62
63 #[test]
64 fn test_clock_permute_basic() {
65 let mut state = [0u64; 8];
66 state[0] = 0x1234567890ABCDEF;
67
68 let original = state;
69 clock_permute(&mut state);
70
71 assert_ne!(state, original);
73 }
74
75 #[test]
76 fn test_clock_permute_avalanche() {
77 let mut state1 = [0u64; 8];
78 let mut state2 = [0u64; 8];
79
80 state1[0] = 0x0000000000000000;
81 state2[0] = 0x0000000000000001; clock_permute(&mut state1);
84 clock_permute(&mut state2);
85
86 assert_ne!(state1, state2);
88 }
89
90 #[test]
91 fn test_clock_permute_deterministic() {
92 let mut state = [0u64; 8];
93 state[0] = 0xDEADBEEFCAFEBABE;
94
95 let mut state_copy = state;
96
97 clock_permute(&mut state);
98 clock_permute(&mut state_copy);
99
100 assert_eq!(state, state_copy);
102 }
103
104 #[test]
105 fn test_clock_permute_full_diffusion() {
106 let mut state1 = [0u64; 8];
108 let mut state2 = [0u64; 8];
109
110 state1[0] = 1;
111 state2[0] = 0;
112
113 clock_permute(&mut state1);
114 clock_permute(&mut state2);
115
116 for i in 0..8 {
118 assert_ne!(state1[i], state2[i], "Word {} should differ", i);
119 }
120 }
121}