#[inline]
pub fn scalar_clock_mix(message: &mut [u64; 16]) {
use crate::constants::{ROTATION_SCHEDULE, SBOX};
use crate::utils::rotl64;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
unsafe {
use core::arch::x86_64::_mm_prefetch;
_mm_prefetch(SBOX.as_ptr() as *const i8, core::arch::x86_64::_MM_HINT_T0);
}
for i in 0..16 {
let next_idx = (i + 1) % 16;
let rotation = ROTATION_SCHEDULE[i];
message[i] ^= rotl64(message[next_idx], rotation);
}
for i in 0..16 {
let sbox_idx = (message[i] & 0xFF) as usize;
message[i] = message[i].wrapping_add(SBOX[sbox_idx] as u64);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::SBOX;
#[test]
fn test_scalar_clock_mix_basic() {
let mut message = [0u64; 16];
for i in 0..16 {
message[i] = i as u64;
}
scalar_clock_mix(&mut message);
assert_ne!(message, [0u64; 16]);
let identity_array: [u64; 16] = (0..16)
.map(|i| i as u64)
.collect::<Vec<_>>()
.try_into()
.unwrap();
assert_ne!(message, identity_array);
}
#[test]
fn test_scalar_clock_mix_invertibility() {
let original = [0x123456789ABCDEF0u64; 16];
let mut modified = original.clone();
scalar_clock_mix(&mut modified);
assert_ne!(original, modified);
assert_ne!(modified, [0u64; 16]);
}
#[test]
fn test_scalar_clock_mix_deterministic() {
let mut msg1 = [0xFEDCBA9876543210u64; 16];
let mut msg2 = [0xFEDCBA9876543210u64; 16];
scalar_clock_mix(&mut msg1);
scalar_clock_mix(&mut msg2);
assert_eq!(msg1, msg2);
}
#[test]
fn test_scalar_clock_mix_edge_cases() {
let mut msg1 = [0u64; 16];
scalar_clock_mix(&mut msg1);
assert_ne!(msg1, [0u64; 16]);
for &val in &msg1 {
assert_eq!(val, SBOX[0] as u64);
}
let mut msg1 = [u64::MAX; 16];
let mut msg2 = [u64::MAX; 16];
scalar_clock_mix(&mut msg1);
scalar_clock_mix(&mut msg2);
assert_eq!(msg1, msg2);
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);
scalar_clock_mix(&mut msg2);
assert_eq!(msg1, msg2);
}
#[test]
fn test_large_value_handling() {
let mut msg1 = [u64::MAX; 16];
let mut msg2 = [u64::MAX; 16];
scalar_clock_mix(&mut msg1);
scalar_clock_mix(&mut msg2);
assert_eq!(msg1, msg2, "Should handle u64::MAX correctly");
}
#[test]
fn test_rotation_schedule_coverage() {
use crate::constants::ROTATION_SCHEDULE;
for &rotation in ROTATION_SCHEDULE.iter() {
assert!(rotation <= 63, "Rotation {} is out of bounds", rotation);
}
assert_eq!(
ROTATION_SCHEDULE.len(),
16,
"Expected 16 rotation values, got {}",
ROTATION_SCHEDULE.len()
);
}
#[test]
fn test_sbox_table_properties() {
use crate::constants::SBOX;
assert_eq!(SBOX.len(), 256, "SBOX should have 256 entries");
let first_value = SBOX[0];
let all_same = SBOX.iter().all(|&v| v == first_value);
assert!(!all_same, "SBOX should not contain all identical values");
let all_zero = SBOX.iter().all(|&v| v == 0);
assert!(!all_zero, "SBOX should not contain all zeros");
}
}