#![allow(clippy::unwrap_used, reason = "switch to `as_chunks` when MSRV 1.88")]
use salsa20::{
SalsaCore,
cipher::{StreamCipherCore, typenum::U4},
};
type Salsa20_8 = SalsaCore<U4>;
pub(crate) fn scrypt_block_mix(input: &[u8], output: &mut [u8]) {
debug_assert_eq!(input.len() % 128, 0, "input must be a multiple of 128");
debug_assert_eq!(
output.len(),
input.len(),
"output must be same length as input"
);
let mut x = [0u8; 64];
x.copy_from_slice(&input[input.len() - 64..]);
let mut t = [0u8; 64];
for (i, chunk) in input.chunks(64).enumerate() {
xor(&x, chunk, &mut t);
let mut t2 = [0u32; 16];
for (c, b) in t.chunks_exact(4).zip(t2.iter_mut()) {
*b = u32::from_le_bytes(c.try_into().unwrap());
}
Salsa20_8::from_raw_state(t2).write_keystream_block((&mut x).into());
let pos = if i % 2 == 0 {
(i / 2) * 64
} else {
(i / 2) * 64 + input.len() / 2
};
output[pos..pos + 64].copy_from_slice(&x);
}
}
fn xor(x: &[u8], y: &[u8], output: &mut [u8]) {
for ((out, &x_i), &y_i) in output.iter_mut().zip(x.iter()).zip(y.iter()) {
*out = x_i ^ y_i;
}
}