use crate::helpers::ensure;
use crate::types::Z;
use crate::Q;
pub(crate) fn byte_encode(d: u32, integers_f: &[Z; 256], bytes_b: &mut [u8]) {
debug_assert_eq!(bytes_b.len(), 32 * d as usize, "Alg 5: bytes_b len is not 32 * d");
debug_assert!(
integers_f.iter().all(|f| f.get_u32() <= if d < 12 { 1 << d } else { u32::from(Q) }),
"Alg 5: integers_f out of range"
);
let mut temp = 0u32;
let mut bit_index = 0;
let mut byte_index = 0;
for coeff in integers_f {
let coeff = coeff.get_u32() & ((1 << d) - 1);
temp |= coeff << bit_index;
bit_index += d as usize;
while bit_index > 7 {
bytes_b[byte_index] = temp.to_le_bytes()[0];
temp >>= 8;
byte_index += 1;
bit_index -= 8;
}
}
debug_assert_eq!(byte_index, bytes_b.len(), "Alg 5: left over bytes_b");
}
pub(crate) fn byte_decode(d: u32, bytes_b: &[u8]) -> Result<[Z; 256], &'static str> {
let mut integers_f = [Z::default(); 256];
debug_assert_eq!(bytes_b.len(), 32 * d as usize, "Alg 6: bytes len is not 32 * d");
let mut temp = 0u32;
let mut bit_index = 0;
let mut int_index = 0;
for byte in bytes_b {
temp |= u32::from(*byte) << bit_index;
bit_index += 8;
#[allow(clippy::cast_possible_truncation)]
while bit_index >= d {
let mut z = Z::default();
z.set_u16((temp & ((1 << d) - 1)) as u16);
integers_f[int_index] = z;
bit_index -= d;
temp >>= d;
int_index += 1;
}
}
debug_assert_eq!(int_index, integers_f.len(), "Alg 6: left over integers");
let m = if d < 12 { 1 << d } else { u32::from(Q) };
ensure!(integers_f.iter().all(|e| e.get_u32() < m), "Alg 6: integers out of range");
Ok(integers_f)
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use rand::{Rng, SeedableRng};
use crate::byte_fns::{byte_decode, byte_encode};
use crate::types::Z;
#[test]
fn test_decode_and_encode() {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
for num_bits in 2..12_u32 {
for _i in 0..100 {
let num_bytes = 32 * num_bits as usize;
let mut bytes2 = vec![0u8; num_bytes];
let bytes1: Vec<u8> = (0..num_bytes).map(|_| rng.gen()).collect();
let integer_array = byte_decode(num_bits, &bytes1).unwrap();
byte_encode(num_bits, &integer_array, &mut bytes2);
assert_eq!(bytes1, bytes2);
}
}
}
#[test]
fn test_result_errs() {
let mut integer_array = [Z::default(); 256];
let num_bits = 12;
let num_bytes = 32 * num_bits as usize;
let bytes1: Vec<u8> = (0..num_bytes).map(|_| 0xFF).collect();
let ret = byte_decode(num_bits, &bytes1);
assert!(ret.is_err());
integer_array.iter_mut().for_each(|x| x.set_u16(u16::MAX));
}
}