pub(crate) fn mlkem_frombytes(r: &mut [i16; 256], a: &[u8; 384]) {
let (r_chunks, _) = r.as_chunks_mut::<2>();
let (a_chunks, _) = a.as_chunks::<3>();
for (r, a) in r_chunks.iter_mut().zip(a_chunks.iter()) {
r[0] = (a[0] as i16) | (((a[1] & 0x0f) as i16) << 8);
r[1] = ((a[1] >> 4) as i16) | ((a[2] as i16) << 4);
}
}
pub(crate) fn mlkem_unpack(_a: &mut [i16; 256]) {}
pub(crate) fn mlkem_compress_d10(r: &mut [u8; 320], a: &[i16; 256]) {
let (quads, _) = a.as_chunks::<4>();
let (out_chunks, _) = r.as_chunks_mut::<5>();
for (quad, out) in quads.iter().zip(out_chunks.iter_mut()) {
let t0 = compress_10(quad[0]);
let t1 = compress_10(quad[1]);
let t2 = compress_10(quad[2]);
let t3 = compress_10(quad[3]);
out[0] = t0 as u8;
out[1] = ((t0 >> 8) | (t1 << 2)) as u8;
out[2] = ((t1 >> 6) | (t2 << 4)) as u8;
out[3] = ((t2 >> 4) | (t3 << 6)) as u8;
out[4] = (t3 >> 2) as u8;
}
}
pub(crate) fn mlkem_compress_d4(r: &mut [u8; 128], a: &[i16; 256]) {
let (pairs, _) = a.as_chunks::<2>();
for (pair, byte) in pairs.iter().zip(r.iter_mut()) {
*byte = compress_4(pair[0]) | (compress_4(pair[1]) << 4);
}
}
const Q: i16 = 3329;
const Q_HALF: i16 = (Q + 1) / 2;
fn compress_4(x: i16) -> u8 {
debug_assert!((0..Q).contains(&crate::low::ct::into_public(x)));
let c = x as u64;
let c = c << 4;
let c = c.wrapping_add(Q_HALF as u64);
let c = c.wrapping_mul(80635);
let c = c >> 28;
let c = c & 0xf;
c as u8
}
fn compress_10(x: i16) -> u16 {
debug_assert!((0..Q).contains(&crate::low::ct::into_public(x)));
let c = x as u64;
let c = c << 10;
let c = c.wrapping_add(Q_HALF as u64);
let c = c.wrapping_mul(1290167);
let c = c >> 32;
let c = c & 0x3ff;
c as u16
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unpacks_known_values() {
let mut a = [0u8; 384];
a[0] = 0xbc;
a[1] = 0xfa;
a[2] = 0xde;
let mut r = [0i16; 256];
mlkem_frombytes(&mut r, &a);
assert_eq!(r[0], 0xabc);
assert_eq!(r[1], 0xdef);
assert_eq!(&r[2..], &[0i16; 254]);
}
#[test]
fn output_is_at_most_12_bits() {
let a = [0xffu8; 384];
let mut r = [0i16; 256];
mlkem_frombytes(&mut r, &a);
assert_eq!(r, [0xfff; 256]);
}
}