use poulpy_hal::layouts::{Backend, Module};
use crate::layouts::{Base2K, Degree, GGLWEInfos, GGSWInfos, GLWEInfos, LWEInfos, Rank, TorusPrecision, key_size, pairs};
pub trait GLWEBytesOf<BE: Backend> {
fn glwe_bytes_of(&self, n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize;
fn glwe_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize {
self.glwe_bytes_of(infos.n(), infos.base2k(), infos.k(), infos.rank())
}
fn glwe_plaintext_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize;
fn glwe_secret_bytes_of(&self, n: Degree, rank: Rank) -> usize;
fn glwe_secret_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize {
self.glwe_secret_bytes_of(infos.n(), infos.rank())
}
fn glwe_secret_tensor_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize;
fn glwe_tensor_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize;
fn lwe_bytes_of_from_infos<A: LWEInfos>(&self, infos: &A) -> usize;
fn gglwe_bytes_of_from_infos<A: GGLWEInfos>(&self, infos: &A) -> usize;
fn ggsw_bytes_of_from_infos<A: GGSWInfos>(&self, infos: &A) -> usize;
}
impl<B: Backend> GLWEBytesOf<B> for Module<B> {
fn glwe_bytes_of(&self, n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
B::bytes_of_vec_znx(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
}
fn glwe_plaintext_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize {
B::bytes_of_vec_znx(infos.n().into(), 1, infos.size())
}
fn glwe_secret_bytes_of(&self, n: Degree, rank: Rank) -> usize {
B::bytes_of_scalar_znx(n.into(), rank.into())
}
fn glwe_secret_tensor_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize {
B::bytes_of_scalar_znx(infos.n().into(), pairs(infos.rank().into()))
}
fn glwe_tensor_bytes_of_from_infos<A: GLWEInfos>(&self, infos: &A) -> usize {
let cols: usize = infos.rank().as_usize() + 1;
let pairs: usize = (((cols + 1) * cols) >> 1).max(1);
B::bytes_of_vec_znx(infos.n().into(), pairs, infos.k().0.div_ceil(infos.base2k().0) as usize)
}
fn lwe_bytes_of_from_infos<A: LWEInfos>(&self, infos: &A) -> usize {
let size: usize = infos.k().0.div_ceil(infos.base2k().0) as usize;
let body: usize = B::bytes_of_vec_znx(1, 1, size).next_multiple_of(B::SCRATCH_ALIGN);
body + B::bytes_of_vec_znx(infos.n().as_usize(), 1, size)
}
fn gglwe_bytes_of_from_infos<A: GGLWEInfos>(&self, infos: &A) -> usize {
let size: usize = key_size(infos.base2k(), infos.dnum(), infos.dsize(), infos.k_aux());
B::bytes_of_mat_znx(
infos.n().into(),
infos.dnum().into(),
infos.rank_in().into(),
(infos.rank_out() + 1).into(),
size,
)
}
fn ggsw_bytes_of_from_infos<A: GGSWInfos>(&self, infos: &A) -> usize {
let size: usize = key_size(infos.base2k(), infos.dnum(), infos.dsize(), infos.k_aux());
B::bytes_of_mat_znx(
infos.n().into(),
infos.dnum().into(),
(infos.rank() + 1).into(),
(infos.rank() + 1).into(),
size,
)
}
}