arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/layouts/gglwe_ct.rs
poulpy-core/src/layouts/gglwe_ct.rsRaw
  1use poulpy_hal::{
  2    layouts::{Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, ReaderFrom, WriterTo, ZnxInfos},
  3    source::Source,
  4};
  5
  6use crate::layouts::{Base2K, BuildError, Degree, Dnum, Dsize, GLWECiphertext, GLWEInfos, LWEInfos, Rank, TorusPrecision};
  7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
  8
  9use std::fmt;
 10
 11pub trait GGLWEInfos
 12where
 13    Self: GLWEInfos,
 14{
 15    fn dnum(&self) -> Dnum;
 16    fn dsize(&self) -> Dsize;
 17    fn rank_in(&self) -> Rank;
 18    fn rank_out(&self) -> Rank;
 19    fn layout(&self) -> GGLWECiphertextLayout {
 20        GGLWECiphertextLayout {
 21            n: self.n(),
 22            base2k: self.base2k(),
 23            k: self.k(),
 24            rank_in: self.rank_in(),
 25            rank_out: self.rank_out(),
 26            dsize: self.dsize(),
 27            dnum: self.dnum(),
 28        }
 29    }
 30}
 31
 32pub trait SetGGLWEInfos {
 33    fn set_dsize(&mut self, dsize: usize);
 34}
 35
 36#[derive(PartialEq, Eq, Copy, Clone, Debug)]
 37pub struct GGLWECiphertextLayout {
 38    pub n: Degree,
 39    pub base2k: Base2K,
 40    pub k: TorusPrecision,
 41    pub rank_in: Rank,
 42    pub rank_out: Rank,
 43    pub dnum: Dnum,
 44    pub dsize: Dsize,
 45}
 46
 47impl LWEInfos for GGLWECiphertextLayout {
 48    fn base2k(&self) -> Base2K {
 49        self.base2k
 50    }
 51
 52    fn k(&self) -> TorusPrecision {
 53        self.k
 54    }
 55
 56    fn n(&self) -> Degree {
 57        self.n
 58    }
 59}
 60
 61impl GLWEInfos for GGLWECiphertextLayout {
 62    fn rank(&self) -> Rank {
 63        self.rank_out
 64    }
 65}
 66
 67impl GGLWEInfos for GGLWECiphertextLayout {
 68    fn rank_in(&self) -> Rank {
 69        self.rank_in
 70    }
 71
 72    fn dsize(&self) -> Dsize {
 73        self.dsize
 74    }
 75
 76    fn rank_out(&self) -> Rank {
 77        self.rank_out
 78    }
 79
 80    fn dnum(&self) -> Dnum {
 81        self.dnum
 82    }
 83}
 84
 85#[derive(PartialEq, Eq, Clone)]
 86pub struct GGLWE<D: Data> {
 87    pub(crate) data: MatZnx<D>,
 88    pub(crate) k: TorusPrecision,
 89    pub(crate) base2k: Base2K,
 90    pub(crate) dsize: Dsize,
 91}
 92
 93impl<D: Data> LWEInfos for GGLWE<D> {
 94    fn base2k(&self) -> Base2K {
 95        self.base2k
 96    }
 97
 98    fn k(&self) -> TorusPrecision {
 99        self.k
100    }
101
102    fn n(&self) -> Degree {
103        Degree(self.data.n() as u32)
104    }
105
106    fn size(&self) -> usize {
107        self.data.size()
108    }
109}
110
111impl<D: Data> GLWEInfos for GGLWE<D> {
112    fn rank(&self) -> Rank {
113        self.rank_out()
114    }
115}
116
117impl<D: Data> GGLWEInfos for GGLWE<D> {
118    fn rank_in(&self) -> Rank {
119        Rank(self.data.cols_in() as u32)
120    }
121
122    fn rank_out(&self) -> Rank {
123        Rank(self.data.cols_out() as u32 - 1)
124    }
125
126    fn dsize(&self) -> Dsize {
127        self.dsize
128    }
129
130    fn dnum(&self) -> Dnum {
131        Dnum(self.data.rows() as u32)
132    }
133}
134
135pub struct GGLWECiphertextBuilder<D: Data> {
136    data: Option<MatZnx<D>>,
137    base2k: Option<Base2K>,
138    k: Option<TorusPrecision>,
139    dsize: Option<Dsize>,
140}
141
142impl<D: Data> GGLWE<D> {
143    #[inline]
144    pub fn builder() -> GGLWECiphertextBuilder<D> {
145        GGLWECiphertextBuilder {
146            data: None,
147            base2k: None,
148            k: None,
149            dsize: None,
150        }
151    }
152}
153
154impl GGLWECiphertextBuilder<Vec<u8>> {
155    #[inline]
156    pub fn layout<A>(mut self, infos: &A) -> Self
157    where
158        A: GGLWEInfos,
159    {
160        self.data = Some(MatZnx::alloc(
161            infos.n().into(),
162            infos.dnum().into(),
163            infos.rank_in().into(),
164            (infos.rank_out() + 1).into(),
165            infos.size(),
166        ));
167        self.base2k = Some(infos.base2k());
168        self.k = Some(infos.k());
169        self.dsize = Some(infos.dsize());
170        self
171    }
172}
173
174impl<D: Data> GGLWECiphertextBuilder<D> {
175    #[inline]
176    pub fn data(mut self, data: MatZnx<D>) -> Self {
177        self.data = Some(data);
178        self
179    }
180    #[inline]
181    pub fn base2k(mut self, base2k: Base2K) -> Self {
182        self.base2k = Some(base2k);
183        self
184    }
185    #[inline]
186    pub fn k(mut self, k: TorusPrecision) -> Self {
187        self.k = Some(k);
188        self
189    }
190
191    #[inline]
192    pub fn dsize(mut self, dsize: Dsize) -> Self {
193        self.dsize = Some(dsize);
194        self
195    }
196
197    pub fn build(self) -> Result<GGLWE<D>, BuildError> {
198        let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?;
199        let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
200        let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
201        let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
202
203        if base2k == 0_u32 {
204            return Err(BuildError::ZeroBase2K);
205        }
206
207        if dsize == 0_u32 {
208            return Err(BuildError::ZeroBase2K);
209        }
210
211        if k == 0_u32 {
212            return Err(BuildError::ZeroTorusPrecision);
213        }
214
215        if data.n() == 0 {
216            return Err(BuildError::ZeroDegree);
217        }
218
219        if data.cols() == 0 {
220            return Err(BuildError::ZeroCols);
221        }
222
223        if data.size() == 0 {
224            return Err(BuildError::ZeroLimbs);
225        }
226
227        Ok(GGLWE {
228            data,
229            base2k,
230            k,
231            dsize,
232        })
233    }
234}
235
236impl<D: DataRef> GGLWE<D> {
237    pub fn data(&self) -> &MatZnx<D> {
238        &self.data
239    }
240}
241
242impl<D: DataMut> GGLWE<D> {
243    pub fn data_mut(&mut self) -> &mut MatZnx<D> {
244        &mut self.data
245    }
246}
247
248impl<D: DataRef> fmt::Debug for GGLWE<D> {
249    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250        write!(f, "{self}")
251    }
252}
253
254impl<D: DataMut> FillUniform for GGLWE<D> {
255    fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
256        self.data.fill_uniform(log_bound, source);
257    }
258}
259
260impl<D: DataRef> fmt::Display for GGLWE<D> {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        write!(
263            f,
264            "(GGLWECiphertext: k={} base2k={} dsize={}) {}",
265            self.k().0,
266            self.base2k().0,
267            self.dsize().0,
268            self.data
269        )
270    }
271}
272
273impl<D: DataRef> GGLWE<D> {
274    pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
275        GLWECiphertext::builder()
276            .data(self.data.at(row, col))
277            .base2k(self.base2k())
278            .k(self.k())
279            .build()
280            .unwrap()
281    }
282}
283
284impl<D: DataMut> GGLWE<D> {
285    pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
286        GLWECiphertext::builder()
287            .base2k(self.base2k())
288            .k(self.k())
289            .data(self.data.at_mut(row, col))
290            .build()
291            .unwrap()
292    }
293}
294
295impl GGLWE<Vec<u8>> {
296    pub fn alloc<A>(infos: &A) -> Self
297    where
298        A: GGLWEInfos,
299    {
300        Self::alloc_with(
301            infos.n(),
302            infos.base2k(),
303            infos.k(),
304            infos.rank_in(),
305            infos.rank_out(),
306            infos.dnum(),
307            infos.dsize(),
308        )
309    }
310
311    pub fn alloc_with(
312        n: Degree,
313        base2k: Base2K,
314        k: TorusPrecision,
315        rank_in: Rank,
316        rank_out: Rank,
317        dnum: Dnum,
318        dsize: Dsize,
319    ) -> Self {
320        let size: usize = k.0.div_ceil(base2k.0) as usize;
321        debug_assert!(
322            size as u32 > dsize.0,
323            "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
324            dsize.0
325        );
326
327        assert!(
328            dnum.0 * dsize.0 <= size as u32,
329            "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
330            dnum.0,
331            dsize.0,
332        );
333
334        Self {
335            data: MatZnx::alloc(
336                n.into(),
337                dnum.into(),
338                rank_in.into(),
339                (rank_out + 1).into(),
340                k.0.div_ceil(base2k.0) as usize,
341            ),
342            k,
343            base2k,
344            dsize,
345        }
346    }
347
348    pub fn alloc_bytes<A>(infos: &A) -> usize
349    where
350        A: GGLWEInfos,
351    {
352        Self::alloc_bytes_with(
353            infos.n(),
354            infos.base2k(),
355            infos.k(),
356            infos.rank_in(),
357            infos.rank_out(),
358            infos.dnum(),
359            infos.dsize(),
360        )
361    }
362
363    pub fn alloc_bytes_with(
364        n: Degree,
365        base2k: Base2K,
366        k: TorusPrecision,
367        rank_in: Rank,
368        rank_out: Rank,
369        dnum: Dnum,
370        dsize: Dsize,
371    ) -> usize {
372        let size: usize = k.0.div_ceil(base2k.0) as usize;
373        debug_assert!(
374            size as u32 > dsize.0,
375            "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
376            dsize.0
377        );
378
379        assert!(
380            dnum.0 * dsize.0 <= size as u32,
381            "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
382            dnum.0,
383            dsize.0,
384        );
385
386        MatZnx::alloc_bytes(
387            n.into(),
388            dnum.into(),
389            rank_in.into(),
390            (rank_out + 1).into(),
391            k.0.div_ceil(base2k.0) as usize,
392        )
393    }
394}
395
396pub trait GGLWECiphertextToMut {
397    fn to_mut(&mut self) -> GGLWE<&mut [u8]>;
398}
399
400impl<D: DataMut> GGLWECiphertextToMut for GGLWE<D> {
401    fn to_mut(&mut self) -> GGLWE<&mut [u8]> {
402        GGLWE {
403            k: self.k(),
404            base2k: self.base2k(),
405            dsize: self.dsize(),
406            data: self.data.to_mut(),
407        }
408    }
409}
410
411pub trait GGLWEToRef {
412    fn to_ref(&self) -> GGLWE<&[u8]>;
413}
414
415impl<D: DataRef> GGLWEToRef for GGLWE<D> {
416    fn to_ref(&self) -> GGLWE<&[u8]> {
417        GGLWE {
418            k: self.k(),
419            base2k: self.base2k(),
420            dsize: self.dsize(),
421            data: self.data.to_ref(),
422        }
423    }
424}
425
426impl<D: DataMut> ReaderFrom for GGLWE<D> {
427    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
428        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
429        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
430        self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
431        self.data.read_from(reader)
432    }
433}
434
435impl<D: DataRef> WriterTo for GGLWE<D> {
436    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
437        writer.write_u32::<LittleEndian>(self.k.0)?;
438        writer.write_u32::<LittleEndian>(self.base2k.0)?;
439        writer.write_u32::<LittleEndian>(self.dsize.0)?;
440        self.data.write_to(writer)
441    }
442}