use super::params::{MAX_K, N, Q};
pub fn decompose(r: i32, gamma2: i32) -> (i32, i32) {
let alpha = 2 * gamma2;
let rp = r % Q + ((r >> 31) & Q); let mut r0 = rp % alpha; if r0 > alpha / 2 {
r0 -= alpha;
}
if rp - r0 == Q - 1 {
(0, r0 - 1)
} else {
((rp - r0) / alpha, r0)
}
}
pub fn high_bits(r: i32, gamma2: i32) -> i32 {
decompose(r, gamma2).0
}
pub fn low_bits(r: i32, gamma2: i32) -> i32 {
decompose(r, gamma2).1
}
pub fn make_hint(z: i32, r: i32, gamma2: i32) -> i32 {
let r1 = high_bits(r, gamma2);
let v1 = high_bits((r + z) % Q + (((r + z) >> 31) & Q), gamma2);
if r1 != v1 { 1 } else { 0 }
}
pub fn use_hint(h: i32, r: i32, gamma2: i32) -> i32 {
let alpha = 2 * gamma2;
let (r1, r0) = decompose(r, gamma2);
if h == 0 {
return r1;
}
let m = (Q - 1) / alpha;
if r0 > 0 { (r1 + 1) % m } else { (r1 - 1 + m) % m }
}
pub fn high_bits_vec(w: &[[i32; N]], gamma2: i32, out: &mut [[i32; N]], len: usize) {
for i in 0..len {
for j in 0..N {
out[i][j] = high_bits(w[i][j], gamma2);
}
}
}
pub fn low_bits_vec(w: &[[i32; N]], gamma2: i32, out: &mut [[i32; N]], len: usize) {
for i in 0..len {
for j in 0..N {
out[i][j] = low_bits(w[i][j], gamma2);
}
}
}
pub fn make_hint_vec(z: &[[i32; N]], r: &[[i32; N]], gamma2: i32, len: usize) -> ([[i32; N]; MAX_K], usize) {
let mut h = [[0i32; N]; MAX_K];
let mut count = 0usize;
for i in 0..len {
for j in 0..N {
h[i][j] = make_hint(z[i][j], r[i][j], gamma2);
count += h[i][j] as usize;
}
}
(h, count)
}
pub fn use_hint_vec(h: &[[i32; N]], r: &[[i32; N]], gamma2: i32, len: usize) -> [[i32; N]; MAX_K] {
let mut w1 = [[0i32; N]; MAX_K];
for i in 0..len {
for j in 0..N {
w1[i][j] = use_hint(h[i][j], r[i][j], gamma2);
}
}
w1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decompose_roundtrip() {
let gamma2 = (Q - 1) / 88;
let alpha = 2 * gamma2;
for r in [0, 1, 100000, Q / 2, Q - 1] {
let (r1, r0) = decompose(r, gamma2);
let reconstructed = (r1 * alpha + r0) % Q + (((r1 * alpha + r0) >> 31) & Q);
assert_eq!(reconstructed, r, "decompose roundtrip failed for r={}", r);
}
}
#[test]
fn test_use_hint_consistency() {
let gamma2 = (Q - 1) / 88;
let r = 1234567;
let r1 = high_bits(r, gamma2);
assert_eq!(use_hint(0, r, gamma2), r1);
}
}