use super::params::{MAX_K, MAX_L, N, Params, Q};
use super::sha3;
#[inline]
fn coeff_from_three_bytes(b0: u8, b1: u8, b2: u8) -> Option<i32> {
let b2_masked = b2 & 0x7F; let z = (b0 as i32) | ((b1 as i32) << 8) | ((b2_masked as i32) << 16);
if z < Q { Some(z) } else { None }
}
#[inline]
fn coeff_from_half_byte(b: u8, eta: usize) -> Option<i32> {
let b = b as i32;
if eta == 2 {
if b < 15 { Some(2 - (b % 5)) } else { None }
} else {
if b < 9 { Some(4 - b) } else { None }
}
}
pub fn sample_in_ball<P: Params>(c_tilde: &[u8]) -> [i32; N] {
let tau = P::TAU;
let mut c = [0i32; N];
let mut state = sha3::shake256();
state.absorb(c_tilde);
let mut sign_bytes = [0u8; 8];
state.squeeze(&mut sign_bytes);
let signs = u64::from_le_bytes(sign_bytes);
let mut sign_idx = 0usize;
for i in (N - tau)..N {
let mut j;
loop {
let mut buf = [0u8; 1];
state.squeeze(&mut buf);
j = buf[0] as usize;
if j <= i {
break;
}
}
c[i] = c[j];
let sign_bit = (signs >> sign_idx) & 1;
c[j] = if sign_bit == 1 { -1 } else { 1 };
sign_idx += 1;
}
c
}
pub fn rej_ntt_poly(rho: &[u8; 32], j1: u8, j2: u8) -> [i32; N] {
let mut a = [0i32; N];
let mut state = sha3::shake128();
state.absorb(rho);
state.absorb(&[j1, j2]);
let mut idx = 0;
while idx < N {
let mut buf = [0u8; 3];
state.squeeze(&mut buf);
if let Some(coeff) = coeff_from_three_bytes(buf[0], buf[1], buf[2]) {
a[idx] = coeff;
idx += 1;
}
}
a
}
pub fn rej_bounded_poly(rho_prime: &[u8; 64], nonce: u16, eta: usize) -> [i32; N] {
let mut a = [0i32; N];
let mut state = sha3::shake256();
state.absorb(rho_prime);
state.absorb(&nonce.to_le_bytes());
let mut idx = 0;
while idx < N {
let mut buf = [0u8; 1];
state.squeeze(&mut buf);
let z0 = coeff_from_half_byte(buf[0] & 0x0F, eta);
let z1 = coeff_from_half_byte(buf[0] >> 4, eta);
if let Some(c) = z0 {
if idx < N {
a[idx] = c;
idx += 1;
}
}
if let Some(c) = z1 {
if idx < N {
a[idx] = c;
idx += 1;
}
}
}
a
}
pub fn expand_a<P: Params>(rho: &[u8; 32]) -> [[[i32; N]; MAX_L]; MAX_K] {
let k = P::K;
let l = P::L;
let mut a_hat = [[[0i32; N]; MAX_L]; MAX_K];
for r in 0..k {
for s in 0..l {
a_hat[r][s] = rej_ntt_poly(rho, s as u8, r as u8);
}
}
a_hat
}
pub fn expand_s<P: Params>(rho_prime: &[u8; 64]) -> ([[i32; N]; MAX_L], [[i32; N]; MAX_K]) {
let k = P::K;
let l = P::L;
let eta = P::ETA;
let mut s1 = [[0i32; N]; MAX_L];
for s in 0..l {
s1[s] = rej_bounded_poly(rho_prime, s as u16, eta);
}
let mut s2 = [[0i32; N]; MAX_K];
for s in 0..k {
s2[s] = rej_bounded_poly(rho_prime, (l + s) as u16, eta);
}
(s1, s2)
}
pub fn expand_mask<P: Params>(rho_double_prime: &[u8; 64], kappa: u16) -> [[i32; N]; MAX_L] {
let l = P::L;
let gamma1 = P::GAMMA1 as u32;
let c = P::BITLEN_GAMMA1_MINUS1 + 1;
let poly_bytes = 32 * c;
let mut y = [[0i32; N]; MAX_L];
for r in 0..l {
let nonce = kappa + r as u16;
let mut state = sha3::shake256();
state.absorb(rho_double_prime);
state.absorb(&nonce.to_le_bytes());
let mut buf = [0u8; 640];
state.squeeze(&mut buf[..poly_bytes]);
super::encode::bit_unpack(&buf[..poly_bytes], gamma1 - 1, gamma1, &mut y[r]);
}
y
}