#[inline(always)]
fn quarter_round(x: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize) {
x[b] ^= x[a].wrapping_add(x[d]).rotate_left(7);
x[c] ^= x[b].wrapping_add(x[a]).rotate_left(9);
x[d] ^= x[c].wrapping_add(x[b]).rotate_left(13);
x[a] ^= x[d].wrapping_add(x[c]).rotate_left(18);
}
pub(crate) fn salsa20_8(block: &mut [u8; 64]) {
let mut x = [0u32; 16];
for (i, w) in x.iter_mut().enumerate() {
*w = u32::from_le_bytes(block[i * 4..i * 4 + 4].try_into().unwrap());
}
let original = x;
for _ in 0..4 {
quarter_round(&mut x, 0, 4, 8, 12);
quarter_round(&mut x, 5, 9, 13, 1);
quarter_round(&mut x, 10, 14, 2, 6);
quarter_round(&mut x, 15, 3, 7, 11);
quarter_round(&mut x, 0, 1, 2, 3);
quarter_round(&mut x, 5, 6, 7, 4);
quarter_round(&mut x, 10, 11, 8, 9);
quarter_round(&mut x, 15, 12, 13, 14);
}
for (i, &w) in x.iter().enumerate() {
let v = w.wrapping_add(original[i]);
block[i * 4..i * 4 + 4].copy_from_slice(&v.to_le_bytes());
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::from_hex;
#[test]
fn rfc7914_salsa20_8_block() {
let mut block = from_hex::<64>(
"7e879a214f3ec9867ca940e641718f26\
baee555b8c61c1b50df846116dcd3b1d\
ee24f319df9b3d8514121e4b5ac5aa32\
76021d2909c74829edebc68db8b8c25e",
);
let expected = from_hex::<64>(
"a41f859c6608cc993b81cacb020cef05\
044b2181a2fd337dfd7b1c6396682f29\
b4393168e3c9e6bcfe6bc5b7a06d96ba\
e424cc102c91745c24ad673dc7618f81",
);
salsa20_8(&mut block);
assert_eq!(block, expected);
}
}