diff --git a/sub_crates/backend/src/hash.rs b/sub_crates/backend/src/hash.rs index 9607455..c11fadf 100644 --- a/sub_crates/backend/src/hash.rs +++ b/sub_crates/backend/src/hash.rs @@ -121,38 +121,31 @@ fn add_buffer_to_state(state: &mut [u64; 4], buffer: &[u8]) { /// The main mix function. Mixes the passed hash state. /// /// Inspired by Skein 1.3, and using its MIX function. -/// -/// The mix rotation constants are: -/// - 40 50 -/// - 27 21 -/// -/// They were selected by an exhaustive search of the four-constant -/// space, selecting for the best single-bit diffusion at a small -/// number of rounds. -/// -/// The permute table is: -/// - Indices: 0 1 2 3 -/// - Become: 0 1 3 2 #[inline(always)] fn mix_state(state: &mut [u64; 4], rounds: usize) { - for _ in 0..rounds { - // MIX function. - state[0] = state[0].wrapping_add(state[2]); - state[2] = state[2].rotate_left(40) ^ state[0]; - state[1] = state[1].wrapping_add(state[3]); - state[3] = state[3].rotate_left(50) ^ state[1]; - - // Permute. - state.swap(2, 3); + const ROTATIONS: &[[u32; 4]] = &[ + [40, 50, 27, 21], + [40, 50, 27, 21], + [40, 50, 27, 21], + [40, 50, 27, 21], + ]; + for round in 0..rounds { + let rot = ROTATIONS[round % ROTATIONS.len()]; // MIX function. state[0] = state[0].wrapping_add(state[2]); - state[2] = state[2].rotate_left(27) ^ state[0]; + state[2] = state[2].rotate_left(rot[0]) ^ state[0]; state[1] = state[1].wrapping_add(state[3]); - state[3] = state[3].rotate_left(21) ^ state[1]; + state[3] = state[3].rotate_left(rot[1]) ^ state[1]; - // Permute. - state.swap(2, 3); + // We flip the indices we use below, as if we did + // a [0 1 2 3] -> [0 1 3 2] permutation. + + // MIX function. + state[0] = state[0].wrapping_add(state[3]); + state[3] = state[3].rotate_left(rot[2]) ^ state[0]; + state[1] = state[1].wrapping_add(state[2]); + state[2] = state[2].rotate_left(rot[3]) ^ state[1]; } }