arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/layouts/compressed/ggsw_ct.rs
poulpy-core/src/layouts/compressed/ggsw_ct.rsRaw
  1use poulpy_hal::{
  2    layouts::{
  3        Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
  4    },
  5    source::Source,
  6};
  7
  8use crate::layouts::{
  9    Base2K, Degree, Dnum, Dsize, GGSW, GGSWInfos, GGSWToMut, GLWEInfos, GetDegree, LWEInfos, Rank, TorusPrecision,
 10    compressed::{GLWECompressed, GLWEDecompress},
 11};
 12use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 13use std::fmt;
 14
 15#[derive(PartialEq, Eq, Clone)]
 16pub struct GGSWCompressed<D: Data> {
 17    pub(crate) data: MatZnx<D>,
 18    pub(crate) k: TorusPrecision,
 19    pub(crate) base2k: Base2K,
 20    pub(crate) dsize: Dsize,
 21    pub(crate) rank: Rank,
 22    pub(crate) seed: Vec<[u8; 32]>,
 23}
 24
 25pub trait GGSWCompressedSeedMut {
 26    fn seed_mut(&mut self) -> &mut Vec<[u8; 32]>;
 27}
 28
 29impl<D: DataMut> GGSWCompressedSeedMut for GGSWCompressed<D> {
 30    fn seed_mut(&mut self) -> &mut Vec<[u8; 32]> {
 31        &mut self.seed
 32    }
 33}
 34
 35pub trait GGSWCompressedSeed {
 36    fn seed(&self) -> &Vec<[u8; 32]>;
 37}
 38
 39impl<D: DataRef> GGSWCompressedSeed for GGSWCompressed<D> {
 40    fn seed(&self) -> &Vec<[u8; 32]> {
 41        &self.seed
 42    }
 43}
 44
 45impl<D: Data> LWEInfos for GGSWCompressed<D> {
 46    fn n(&self) -> Degree {
 47        Degree(self.data.n() as u32)
 48    }
 49
 50    fn base2k(&self) -> Base2K {
 51        self.base2k
 52    }
 53
 54    fn k(&self) -> TorusPrecision {
 55        self.k
 56    }
 57    fn size(&self) -> usize {
 58        self.data.size()
 59    }
 60}
 61impl<D: Data> GLWEInfos for GGSWCompressed<D> {
 62    fn rank(&self) -> Rank {
 63        self.rank
 64    }
 65}
 66
 67impl<D: Data> GGSWInfos for GGSWCompressed<D> {
 68    fn dsize(&self) -> Dsize {
 69        self.dsize
 70    }
 71
 72    fn dnum(&self) -> Dnum {
 73        Dnum(self.data.rows() as u32)
 74    }
 75}
 76
 77impl<D: DataRef> fmt::Debug for GGSWCompressed<D> {
 78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 79        write!(f, "{}", self.data)
 80    }
 81}
 82
 83impl<D: DataRef> fmt::Display for GGSWCompressed<D> {
 84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 85        write!(
 86            f,
 87            "(GGSWCompressed: base2k={} k={} dsize={}) {}",
 88            self.base2k, self.k, self.dsize, self.data
 89        )
 90    }
 91}
 92
 93impl<D: DataMut> FillUniform for GGSWCompressed<D> {
 94    fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
 95        self.data.fill_uniform(log_bound, source);
 96    }
 97}
 98
 99impl<BE: Backend> GGSWCompressedAlloc for Module<BE> where Self: GetDegree {}
100
101pub trait GGSWCompressedAlloc
102where
103    Self: GetDegree,
104{
105    fn alloc_ggsw_compressed(
106        &self,
107        base2k: Base2K,
108        k: TorusPrecision,
109        rank: Rank,
110        dnum: Dnum,
111        dsize: Dsize,
112    ) -> GGSWCompressed<Vec<u8>> {
113        let size: usize = k.0.div_ceil(base2k.0) as usize;
114        assert!(
115            size as u32 > dsize.0,
116            "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}",
117            dsize.0
118        );
119
120        assert!(
121            dnum.0 * dsize.0 <= size as u32,
122            "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
123            dnum.0,
124            dsize.0,
125        );
126
127        GGSWCompressed {
128            data: MatZnx::alloc(
129                self.ring_degree().into(),
130                dnum.into(),
131                (rank + 1).into(),
132                1,
133                k.0.div_ceil(base2k.0) as usize,
134            ),
135            k,
136            base2k,
137            dsize,
138            rank,
139            seed: Vec::new(),
140        }
141    }
142
143    fn alloc_ggsw_compressed_from_infos<A>(&self, infos: &A) -> GGSWCompressed<Vec<u8>>
144    where
145        A: GGSWInfos,
146    {
147        self.alloc_ggsw_compressed(
148            infos.base2k(),
149            infos.k(),
150            infos.rank(),
151            infos.dnum(),
152            infos.dsize(),
153        )
154    }
155
156    fn bytes_of_ggsw_compressed(&self, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize {
157        let size: usize = k.0.div_ceil(base2k.0) as usize;
158        assert!(
159            size as u32 > dsize.0,
160            "invalid ggsw: ceil(k/base2k): {size} <= dsize: {}",
161            dsize.0
162        );
163
164        assert!(
165            dnum.0 * dsize.0 <= size as u32,
166            "invalid ggsw: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
167            dnum.0,
168            dsize.0,
169        );
170
171        MatZnx::bytes_of(
172            self.ring_degree().into(),
173            dnum.into(),
174            (rank + 1).into(),
175            1,
176            k.0.div_ceil(base2k.0) as usize,
177        )
178    }
179
180    fn bytes_of_ggsw_compressed_key_from_infos<A>(&self, infos: &A) -> usize
181    where
182        A: GGSWInfos,
183    {
184        self.bytes_of_ggsw_compressed(
185            infos.base2k(),
186            infos.k(),
187            infos.rank(),
188            infos.dnum(),
189            infos.dsize(),
190        )
191    }
192}
193
194impl GGSWCompressed<Vec<u8>> {
195    pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
196    where
197        A: GGSWInfos,
198        M: GGSWCompressedAlloc,
199    {
200        module.alloc_ggsw_compressed_from_infos(infos)
201    }
202
203    pub fn alloc<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> Self
204    where
205        M: GGSWCompressedAlloc,
206    {
207        module.alloc_ggsw_compressed(base2k, k, rank, dnum, dsize)
208    }
209
210    pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
211    where
212        A: GGSWInfos,
213        M: GGSWCompressedAlloc,
214    {
215        module.bytes_of_ggsw_compressed_key_from_infos(infos)
216    }
217
218    pub fn bytes_of<M>(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize
219    where
220        M: GGSWCompressedAlloc,
221    {
222        module.bytes_of_ggsw_compressed(base2k, k, rank, dnum, dsize)
223    }
224}
225
226impl<D: DataRef> GGSWCompressed<D> {
227    pub fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> {
228        let rank: usize = self.rank().into();
229        GLWECompressed {
230            data: self.data.at(row, col),
231            k: self.k,
232            base2k: self.base2k,
233            rank: self.rank,
234            seed: self.seed[row * (rank + 1) + col],
235        }
236    }
237}
238
239impl<D: DataMut> GGSWCompressed<D> {
240    pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> {
241        let rank: usize = self.rank().into();
242        GLWECompressed {
243            data: self.data.at_mut(row, col),
244            k: self.k,
245            base2k: self.base2k,
246            rank: self.rank,
247            seed: self.seed[row * (rank + 1) + col],
248        }
249    }
250}
251
252impl<D: DataMut> ReaderFrom for GGSWCompressed<D> {
253    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
254        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
255        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
256        self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
257        self.rank = Rank(reader.read_u32::<LittleEndian>()?);
258        let seed_len: usize = reader.read_u32::<LittleEndian>()? as usize;
259        self.seed = vec![[0u8; 32]; seed_len];
260        for s in &mut self.seed {
261            reader.read_exact(s)?;
262        }
263        self.data.read_from(reader)
264    }
265}
266
267impl<D: DataRef> WriterTo for GGSWCompressed<D> {
268    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
269        writer.write_u32::<LittleEndian>(self.k.into())?;
270        writer.write_u32::<LittleEndian>(self.base2k.into())?;
271        writer.write_u32::<LittleEndian>(self.dsize.into())?;
272        writer.write_u32::<LittleEndian>(self.rank.into())?;
273        writer.write_u32::<LittleEndian>(self.seed.len() as u32)?;
274        for s in &self.seed {
275            writer.write_all(s)?;
276        }
277        self.data.write_to(writer)
278    }
279}
280
281pub trait GGSWDecompress
282where
283    Self: GLWEDecompress,
284{
285    fn decompress_ggsw<R, O>(&self, res: &mut R, other: &O)
286    where
287        R: GGSWToMut,
288        O: GGSWCompressedToRef,
289    {
290        let res: &mut GGSW<&mut [u8]> = &mut res.to_mut();
291        let other: &GGSWCompressed<&[u8]> = &other.to_ref();
292
293        assert_eq!(res.rank(), other.rank());
294        let dnum: usize = res.dnum().into();
295        let rank: usize = res.rank().into();
296
297        for row_i in 0..dnum {
298            for col_j in 0..rank + 1 {
299                self.decompress_glwe(&mut res.at_mut(row_i, col_j), &other.at(row_i, col_j));
300            }
301        }
302    }
303}
304
305impl<B: Backend> GGSWDecompress for Module<B> where Self: GGSWDecompress {}
306
307impl<D: DataMut> GGSW<D> {
308    pub fn decompress<O, M>(&mut self, module: &M, other: &O)
309    where
310        O: GGSWCompressedToRef,
311        M: GGSWDecompress,
312    {
313        module.decompress_ggsw(self, other);
314    }
315}
316
317pub trait GGSWCompressedToMut {
318    fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]>;
319}
320
321impl<D: DataMut> GGSWCompressedToMut for GGSWCompressed<D> {
322    fn to_mut(&mut self) -> GGSWCompressed<&mut [u8]> {
323        GGSWCompressed {
324            k: self.k(),
325            base2k: self.base2k(),
326            dsize: self.dsize(),
327            rank: self.rank(),
328            seed: self.seed.clone(),
329            data: self.data.to_mut(),
330        }
331    }
332}
333
334pub trait GGSWCompressedToRef {
335    fn to_ref(&self) -> GGSWCompressed<&[u8]>;
336}
337
338impl<D: DataRef> GGSWCompressedToRef for GGSWCompressed<D> {
339    fn to_ref(&self) -> GGSWCompressed<&[u8]> {
340        GGSWCompressed {
341            k: self.k(),
342            base2k: self.base2k(),
343            dsize: self.dsize(),
344            rank: self.rank(),
345            seed: self.seed.clone(),
346            data: self.data.to_ref(),
347        }
348    }
349}