use bit_vec::BitVec;
pub(crate) fn compress(v: &[i16], slen: usize) -> Option<Vec<u8>> {
let mut bitvector: BitVec = BitVec::with_capacity(slen);
for coeff in v {
bitvector.push(*coeff < 0);
let s = (*coeff).abs();
for i in (0..7).rev() {
bitvector.push(((s >> i) & 1) != 0);
}
for _ in 0..(s >> 7) {
bitvector.push(false);
}
bitvector.push(true);
}
if bitvector.len() > slen {
return None;
}
while bitvector.len() < slen {
bitvector.push(false);
}
Some(bitvector.to_bytes())
}
pub(crate) fn decompress(x: &[u8], bitlength: usize, n: usize) -> Option<Vec<i16>> {
if x.len() * 8 != bitlength {
return None;
}
let bitvector = BitVec::from_bytes(x);
let mut index = 0;
let mut result = Vec::with_capacity(n);
for _ in 0..n {
if index + 8 >= bitvector.len() {
println!(
"index + 8 = {} but bitvector is only {} long",
index + 8,
bitvector.len()
);
return None;
}
let sign = if bitvector[index] { -1 } else { 1 };
index += 1;
let mut low_bits = 0i16;
for _ in 0..7 {
low_bits = (low_bits << 1) | if bitvector[index] { 1 } else { 0 };
index += 1;
}
let mut high_bits = 0;
while !bitvector[index] {
index += 1;
high_bits += 1;
}
index += 1;
let integer = sign * ((high_bits << 7) | low_bits);
result.push(integer);
}
Some(result)
}
#[cfg(test)]
mod test {
use crate::{
encoding::{compress, decompress},
falcon::FalconVariant,
field::Q,
};
use rand::thread_rng;
use rand_distr::{num_traits::ToPrimitive, Distribution, Normal};
#[test]
fn test_compress_decompress() {
let num_iterations = 200;
let sigma = 1.5 * (Q.to_f64().unwrap()).sqrt();
let distribution = Normal::<f64>::new(0.0, sigma).unwrap();
let mut rng = thread_rng();
for _ in 0..num_iterations {
const SALT_LEN: usize = 40;
const HEAD_LEN: usize = 1;
{
const N: usize = 512;
const SIG_BYTELEN: usize = 666;
let slen = SIG_BYTELEN - SALT_LEN - HEAD_LEN;
let initial: [i16; N] = (0..N)
.map(|_| {
(distribution.sample(&mut rng) + 0.5)
.floor()
.to_i32()
.unwrap() as i16
})
.collect::<Vec<_>>()
.try_into()
.unwrap();
let compressed = compress(&initial, slen * 8).unwrap();
let decompressed = decompress(
&compressed,
(FalconVariant::Falcon512.parameters().sig_bytelen - SALT_LEN - HEAD_LEN) * 8,
N,
)
.unwrap();
assert_eq!(initial.to_vec(), decompressed);
}
{
const N: usize = 1024;
const SIG_BYTELEN: usize = 1280;
let slen = SIG_BYTELEN - SALT_LEN - HEAD_LEN;
let initial: [i16; 1024] = (0..N)
.map(|_| {
(distribution.sample(&mut rng) + 0.5)
.floor()
.to_i32()
.unwrap() as i16
})
.collect::<Vec<_>>()
.try_into()
.unwrap();
let compressed = compress(&initial, slen * 8).unwrap();
let decompressed = decompress(&compressed, slen * 8, N).unwrap();
assert_eq!(initial.to_vec(), decompressed);
}
}
}
}