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