use crate::params::{N, Q};
use crate::poly::Poly;
#[inline]
fn compress_fe(x: u16, d: u32) -> u16 {
let num = (x as u32) << d;
let q = Q as u32;
let r = (num + q / 2) / q;
(r & ((1u32 << d) - 1)) as u16
}
#[inline]
fn decompress_fe(y: u16, d: u32) -> u16 {
let q = Q as u32;
let r = ((y as u32) * q + (1u32 << (d - 1))) >> d;
r as u16
}
#[inline]
pub fn compress_poly_fe_1(x: u16) -> u16 {
compress_fe(x, 1)
}
pub fn compress_poly(p: &Poly, d: u32) -> Poly {
let mut r = [0u16; N];
for i in 0..N {
r[i] = compress_fe(p.0[i], d);
}
Poly(r)
}
pub fn decompress_poly(p: &Poly, d: u32) -> Poly {
let mut r = [0u16; N];
for i in 0..N {
r[i] = decompress_fe(p.0[i], d);
}
Poly(r)
}
#[cfg(kani)]
mod kani_proofs {
use super::*;
#[kani::proof]
fn compress_in_range_d10() {
let x: u16 = kani::any();
kani::assume(x < Q);
let r = compress_fe(x, 10);
assert!(r < (1u16 << 10));
}
#[kani::proof]
fn compress_in_range_d11() {
let x: u16 = kani::any();
kani::assume(x < Q);
let r = compress_fe(x, 11);
assert!(r < (1u16 << 11));
}
#[kani::proof]
fn compress_in_range_d4() {
let x: u16 = kani::any();
kani::assume(x < Q);
let r = compress_fe(x, 4);
assert!(r < (1u16 << 4));
}
#[kani::proof]
fn compress_in_range_d5() {
let x: u16 = kani::any();
kani::assume(x < Q);
let r = compress_fe(x, 5);
assert!(r < (1u16 << 5));
}
#[kani::proof]
fn compress_d1_roundtrip_at_anchors() {
assert_eq!(compress_poly_fe_1(0), 0);
assert_eq!(compress_poly_fe_1(1665), 1);
assert_eq!(compress_poly_fe_1(Q - 1), 0);
}
#[kani::proof]
fn decompress_in_range_d10() {
let y: u16 = kani::any();
kani::assume(y < (1u16 << 10));
let r = decompress_fe(y, 10);
assert!(r < Q);
}
#[kani::proof]
fn decompress_in_range_d11() {
let y: u16 = kani::any();
kani::assume(y < (1u16 << 11));
let r = decompress_fe(y, 11);
assert!(r < Q);
}
}