1use crate::constants::COEFFICIENTS_IN_RING_ELEMENT;
4
5#[must_use]
7pub const fn simple_bit_pack_len(w: usize) -> usize {
8 (COEFFICIENTS_IN_RING_ELEMENT * w).div_ceil(8)
9}
10
11pub fn simple_bit_pack(w: u8, coeffs: &[i32; COEFFICIENTS_IN_RING_ELEMENT], out: &mut [u8]) {
18 let w = usize::from(w);
19 assert_eq!(out.len(), simple_bit_pack_len(w), "output length mismatch");
20 let max = 1i32.checked_shl(w as u32).expect("w too large");
21 out.fill(0);
22 let mut bit_idx = 0usize;
23 for &c in coeffs {
24 assert!(c >= 0 && c < max, "coefficient out of range for w={w}");
25 let u = c as u32;
26 for b in 0..w {
27 let bit = (u >> b) & 1;
28 let byte_i = bit_idx / 8;
29 let bit_in_byte = bit_idx % 8;
30 out[byte_i] |= (bit as u8) << bit_in_byte;
31 bit_idx += 1;
32 }
33 }
34}
35
36pub fn simple_bit_unpack(w: u8, data: &[u8], out: &mut [i32; COEFFICIENTS_IN_RING_ELEMENT]) {
42 let w = usize::from(w);
43 let need = simple_bit_pack_len(w);
44 assert!(data.len() >= need, "input too short");
45 let mask = (1u32 << w) - 1;
46 let mut bit_idx = 0usize;
47 for o in out.iter_mut() {
48 let mut v = 0u32;
49 for b in 0..w {
50 let byte_i = bit_idx / 8;
51 let bit_in_byte = bit_idx % 8;
52 let bit = ((data[byte_i] >> bit_in_byte) & 1) as u32;
53 v |= bit << b;
54 bit_idx += 1;
55 }
56 *o = (v & mask) as i32;
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn bit_pack_roundtrip_w4_w6_w20() {
66 for w in [4u8, 6, 10, 20] {
67 let mut coeffs = [0i32; COEFFICIENTS_IN_RING_ELEMENT];
68 for (i, c) in coeffs.iter_mut().enumerate() {
69 *c = (i % (1 << (w as usize))) as i32;
70 }
71 let len = simple_bit_pack_len(w as usize);
72 let mut buf = [0u8; 800];
73 simple_bit_pack(w, &coeffs, &mut buf[..len]);
74 let mut back = [0i32; COEFFICIENTS_IN_RING_ELEMENT];
75 simple_bit_unpack(w, &buf[..len], &mut back);
76 assert_eq!(coeffs, back);
77 }
78 }
79}