use backend::hal::{ api::{MatZnxAlloc, MatZnxAllocBytes, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare}, layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, Scratch, VmpPMat, WriterTo}, }; use crate::{GLWECiphertext, Infos}; pub trait GGSWLayoutFamily = VmpPMatAlloc + VmpPMatAllocBytes + VmpPMatPrepare; #[derive(PartialEq, Eq)] pub struct GGSWCiphertext { pub(crate) data: MatZnx, pub(crate) basek: usize, pub(crate) k: usize, pub(crate) digits: usize, } impl GGSWCiphertext { pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> { GLWECiphertext { data: self.data.at(row, col), basek: self.basek, k: self.k, } } } impl GGSWCiphertext { pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> { GLWECiphertext { data: self.data.at_mut(row, col), basek: self.basek, k: self.k, } } } impl GGSWCiphertext> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self where Module: MatZnxAlloc, { let size: usize = k.div_ceil(basek); debug_assert!(digits > 0, "invalid ggsw: `digits` == 0"); debug_assert!( size > digits, "invalid ggsw: ceil(k/basek): {} <= digits: {}", size, digits ); assert!( rows * digits <= size, "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}", rows, digits, size ); Self { data: module.mat_znx_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)), basek, k: k, digits, } } pub fn bytes_of(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize where Module: MatZnxAllocBytes, { let size: usize = k.div_ceil(basek); debug_assert!( size > digits, "invalid ggsw: ceil(k/basek): {} <= digits: {}", size, digits ); assert!( rows * digits <= size, "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}", rows, digits, size ); module.mat_znx_alloc_bytes(rows, rank + 1, rank + 1, size) } } impl Infos for GGSWCiphertext { type Inner = MatZnx; fn inner(&self) -> &Self::Inner { &self.data } fn basek(&self) -> usize { self.basek } fn k(&self) -> usize { self.k } } impl GGSWCiphertext { pub fn rank(&self) -> usize { self.data.cols_out() - 1 } pub fn digits(&self) -> usize { self.digits } } use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; impl ReaderFrom for GGSWCiphertext { fn read_from(&mut self, reader: &mut R) -> std::io::Result<()> { self.k = reader.read_u64::()? as usize; self.basek = reader.read_u64::()? as usize; self.digits = reader.read_u64::()? as usize; self.data.read_from(reader) } } impl WriterTo for GGSWCiphertext { fn write_to(&self, writer: &mut W) -> std::io::Result<()> { writer.write_u64::(self.k as u64)?; writer.write_u64::(self.basek as u64)?; writer.write_u64::(self.digits as u64)?; self.data.write_to(writer) } } #[derive(PartialEq, Eq)] pub struct GGSWCiphertextExec { pub(crate) data: VmpPMat, pub(crate) basek: usize, pub(crate) k: usize, pub(crate) digits: usize, } impl GGSWCiphertextExec, B> { pub fn alloc(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self where Module: GGSWLayoutFamily, { let size: usize = k.div_ceil(basek); debug_assert!(digits > 0, "invalid ggsw: `digits` == 0"); debug_assert!( size > digits, "invalid ggsw: ceil(k/basek): {} <= digits: {}", size, digits ); assert!( rows * digits <= size, "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}", rows, digits, size ); Self { data: module.vmp_pmat_alloc(rows, rank + 1, rank + 1, k.div_ceil(basek)), basek, k: k, digits, } } pub fn bytes_of(module: &Module, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize where Module: GGSWLayoutFamily, { let size: usize = k.div_ceil(basek); debug_assert!( size > digits, "invalid ggsw: ceil(k/basek): {} <= digits: {}", size, digits ); assert!( rows * digits <= size, "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}", rows, digits, size ); module.vmp_pmat_alloc_bytes(rows, rank + 1, rank + 1, size) } pub fn from( module: &Module, other: &GGSWCiphertext, scratch: &mut Scratch, ) -> GGSWCiphertextExec, B> where Module: GGSWLayoutFamily, { let mut ggsw_exec: GGSWCiphertextExec, B> = Self::alloc( module, other.basek(), other.k(), other.rows(), other.digits(), other.rank(), ); ggsw_exec.prepare(module, other, scratch); ggsw_exec } } impl Infos for GGSWCiphertextExec { type Inner = VmpPMat; fn inner(&self) -> &Self::Inner { &self.data } fn basek(&self) -> usize { self.basek } fn k(&self) -> usize { self.k } } impl GGSWCiphertextExec { pub fn rank(&self) -> usize { self.data.cols_out() - 1 } pub fn digits(&self) -> usize { self.digits } } impl GGSWCiphertextExec { pub fn prepare(&mut self, module: &Module, other: &GGSWCiphertext, scratch: &mut Scratch) where DataOther: DataRef, Module: GGSWLayoutFamily, { module.vmp_prepare(&mut self.data, &other.data, scratch); self.k = other.k; self.basek = other.basek; self.digits = other.digits; } }