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, 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
135impl<D: DataRef> GGLWE<D> {
136    pub fn data(&self) -> &MatZnx<D> {
137        &self.data
138    }
139}
140
141impl<D: DataMut> GGLWE<D> {
142    pub fn data_mut(&mut self) -> &mut MatZnx<D> {
143        &mut self.data
144    }
145}
146
147impl<D: DataRef> fmt::Debug for GGLWE<D> {
148    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149        write!(f, "{self}")
150    }
151}
152
153impl<D: DataMut> FillUniform for GGLWE<D> {
154    fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
155        self.data.fill_uniform(log_bound, source);
156    }
157}
158
159impl<D: DataRef> fmt::Display for GGLWE<D> {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        write!(
162            f,
163            "(GGLWECiphertext: k={} base2k={} dsize={}) {}",
164            self.k().0,
165            self.base2k().0,
166            self.dsize().0,
167            self.data
168        )
169    }
170}
171
172impl<D: DataRef> GGLWE<D> {
173    pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
174        GLWECiphertext {
175            k: self.k,
176            base2k: self.base2k,
177            data: self.data.at(row, col),
178        }
179    }
180}
181
182impl<D: DataMut> GGLWE<D> {
183    pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
184        GLWECiphertext {
185            k: self.k,
186            base2k: self.base2k,
187            data: self.data.at_mut(row, col),
188        }
189    }
190}
191
192impl GGLWE<Vec<u8>> {
193    pub fn alloc<A>(infos: &A) -> Self
194    where
195        A: GGLWEInfos,
196    {
197        Self::alloc_with(
198            infos.n(),
199            infos.base2k(),
200            infos.k(),
201            infos.rank_in(),
202            infos.rank_out(),
203            infos.dnum(),
204            infos.dsize(),
205        )
206    }
207
208    pub fn alloc_with(
209        n: Degree,
210        base2k: Base2K,
211        k: TorusPrecision,
212        rank_in: Rank,
213        rank_out: Rank,
214        dnum: Dnum,
215        dsize: Dsize,
216    ) -> Self {
217        let size: usize = k.0.div_ceil(base2k.0) as usize;
218        debug_assert!(
219            size as u32 > dsize.0,
220            "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
221            dsize.0
222        );
223
224        assert!(
225            dnum.0 * dsize.0 <= size as u32,
226            "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
227            dnum.0,
228            dsize.0,
229        );
230
231        Self {
232            data: MatZnx::alloc(
233                n.into(),
234                dnum.into(),
235                rank_in.into(),
236                (rank_out + 1).into(),
237                k.0.div_ceil(base2k.0) as usize,
238            ),
239            k,
240            base2k,
241            dsize,
242        }
243    }
244
245    pub fn alloc_bytes<A>(infos: &A) -> usize
246    where
247        A: GGLWEInfos,
248    {
249        Self::alloc_bytes_with(
250            infos.n(),
251            infos.base2k(),
252            infos.k(),
253            infos.rank_in(),
254            infos.rank_out(),
255            infos.dnum(),
256            infos.dsize(),
257        )
258    }
259
260    pub fn alloc_bytes_with(
261        n: Degree,
262        base2k: Base2K,
263        k: TorusPrecision,
264        rank_in: Rank,
265        rank_out: Rank,
266        dnum: Dnum,
267        dsize: Dsize,
268    ) -> usize {
269        let size: usize = k.0.div_ceil(base2k.0) as usize;
270        debug_assert!(
271            size as u32 > dsize.0,
272            "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
273            dsize.0
274        );
275
276        assert!(
277            dnum.0 * dsize.0 <= size as u32,
278            "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
279            dnum.0,
280            dsize.0,
281        );
282
283        MatZnx::alloc_bytes(
284            n.into(),
285            dnum.into(),
286            rank_in.into(),
287            (rank_out + 1).into(),
288            k.0.div_ceil(base2k.0) as usize,
289        )
290    }
291}
292
293pub trait GGLWECiphertextToMut {
294    fn to_mut(&mut self) -> GGLWE<&mut [u8]>;
295}
296
297impl<D: DataMut> GGLWECiphertextToMut for GGLWE<D> {
298    fn to_mut(&mut self) -> GGLWE<&mut [u8]> {
299        GGLWE {
300            k: self.k(),
301            base2k: self.base2k(),
302            dsize: self.dsize(),
303            data: self.data.to_mut(),
304        }
305    }
306}
307
308pub trait GGLWEToRef {
309    fn to_ref(&self) -> GGLWE<&[u8]>;
310}
311
312impl<D: DataRef> GGLWEToRef for GGLWE<D> {
313    fn to_ref(&self) -> GGLWE<&[u8]> {
314        GGLWE {
315            k: self.k(),
316            base2k: self.base2k(),
317            dsize: self.dsize(),
318            data: self.data.to_ref(),
319        }
320    }
321}
322
323impl<D: DataMut> ReaderFrom for GGLWE<D> {
324    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
325        self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
326        self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
327        self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
328        self.data.read_from(reader)
329    }
330}
331
332impl<D: DataRef> WriterTo for GGLWE<D> {
333    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
334        writer.write_u32::<LittleEndian>(self.k.0)?;
335        writer.write_u32::<LittleEndian>(self.base2k.0)?;
336        writer.write_u32::<LittleEndian>(self.dsize.0)?;
337        self.data.write_to(writer)
338    }
339}