arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/layouts/compressed/gglwe_ct.rs
core/src/layouts/compressed/gglwe_ct.rsRaw
  1use backend::hal::{
  2    api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
  3    layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
  4};
  5
  6use crate::layouts::{GGLWECiphertext, Infos, compressed::GLWECiphertextCompressed};
  7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
  8use std::fmt;
  9
 10use crate::trait_families::Decompress;
 11
 12#[derive(PartialEq, Eq, Clone)]
 13pub struct GGLWECiphertextCompressed<D: Data> {
 14    pub(crate) data: MatZnx<D>,
 15    pub(crate) basek: usize,
 16    pub(crate) k: usize,
 17    pub(crate) rank_out: usize,
 18    pub(crate) digits: usize,
 19    pub(crate) seed: Vec<[u8; 32]>,
 20}
 21
 22impl<D: DataRef> fmt::Debug for GGLWECiphertextCompressed<D> {
 23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 24        write!(f, "{}", self)
 25    }
 26}
 27
 28impl<D: DataMut> FillUniform for GGLWECiphertextCompressed<D> {
 29    fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
 30        self.data.fill_uniform(source);
 31    }
 32}
 33
 34impl<D: DataMut> Reset for GGLWECiphertextCompressed<D>
 35where
 36    MatZnx<D>: Reset,
 37{
 38    fn reset(&mut self) {
 39        self.data.reset();
 40        self.basek = 0;
 41        self.k = 0;
 42        self.digits = 0;
 43        self.rank_out = 0;
 44        self.seed = Vec::new();
 45    }
 46}
 47
 48impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> {
 49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 50        write!(
 51            f,
 52            "(GGLWECiphertextCompressed: basek={} k={} digits={}) {}",
 53            self.basek, self.k, self.digits, self.data
 54        )
 55    }
 56}
 57
 58impl GGLWECiphertextCompressed<Vec<u8>> {
 59    pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
 60        let size: usize = k.div_ceil(basek);
 61        debug_assert!(
 62            size > digits,
 63            "invalid gglwe: ceil(k/basek): {} <= digits: {}",
 64            size,
 65            digits
 66        );
 67
 68        assert!(
 69            rows * digits <= size,
 70            "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
 71            rows,
 72            digits,
 73            size
 74        );
 75
 76        Self {
 77            data: MatZnx::alloc(n, rows, rank_in, 1, size),
 78            basek: basek,
 79            k,
 80            rank_out,
 81            digits,
 82            seed: vec![[0u8; 32]; rows * rank_in],
 83        }
 84    }
 85
 86    pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize {
 87        let size: usize = k.div_ceil(basek);
 88        debug_assert!(
 89            size > digits,
 90            "invalid gglwe: ceil(k/basek): {} <= digits: {}",
 91            size,
 92            digits
 93        );
 94
 95        assert!(
 96            rows * digits <= size,
 97            "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
 98            rows,
 99            digits,
100            size
101        );
102
103        MatZnx::alloc_bytes(n, rows, rank_in, 1, rows)
104    }
105}
106
107impl<D: Data> Infos for GGLWECiphertextCompressed<D> {
108    type Inner = MatZnx<D>;
109
110    fn inner(&self) -> &Self::Inner {
111        &self.data
112    }
113
114    fn basek(&self) -> usize {
115        self.basek
116    }
117
118    fn k(&self) -> usize {
119        self.k
120    }
121}
122
123impl<D: Data> GGLWECiphertextCompressed<D> {
124    pub fn rank(&self) -> usize {
125        self.rank_out
126    }
127
128    pub fn digits(&self) -> usize {
129        self.digits
130    }
131
132    pub fn rank_in(&self) -> usize {
133        self.data.cols_in()
134    }
135
136    pub fn rank_out(&self) -> usize {
137        self.rank_out
138    }
139}
140
141impl<D: DataRef> GGLWECiphertextCompressed<D> {
142    pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
143        GLWECiphertextCompressed {
144            data: self.data.at(row, col),
145            basek: self.basek,
146            k: self.k,
147            rank: self.rank_out,
148            seed: self.seed[self.rank_in() * row + col],
149        }
150    }
151}
152
153impl<D: DataMut> GGLWECiphertextCompressed<D> {
154    pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
155        let rank_in: usize = self.rank_in();
156        GLWECiphertextCompressed {
157            data: self.data.at_mut(row, col),
158            basek: self.basek,
159            k: self.k,
160            rank: self.rank_out,
161            seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
162        }
163    }
164}
165
166impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
167    fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
168        self.k = reader.read_u64::<LittleEndian>()? as usize;
169        self.basek = reader.read_u64::<LittleEndian>()? as usize;
170        self.digits = reader.read_u64::<LittleEndian>()? as usize;
171        self.rank_out = reader.read_u64::<LittleEndian>()? as usize;
172        let seed_len = reader.read_u64::<LittleEndian>()? as usize;
173        self.seed = vec![[0u8; 32]; seed_len];
174        for s in &mut self.seed {
175            reader.read_exact(s)?;
176        }
177        self.data.read_from(reader)
178    }
179}
180
181impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
182    fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
183        writer.write_u64::<LittleEndian>(self.k as u64)?;
184        writer.write_u64::<LittleEndian>(self.basek as u64)?;
185        writer.write_u64::<LittleEndian>(self.digits as u64)?;
186        writer.write_u64::<LittleEndian>(self.rank_out as u64)?;
187        writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
188        for s in &self.seed {
189            writer.write_all(s)?;
190        }
191        self.data.write_to(writer)
192    }
193}
194
195impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGLWECiphertextCompressed<DR>> for GGLWECiphertext<D> {
196    fn decompress(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DR>)
197    where
198        Module<B>: VecZnxFillUniform + VecZnxCopy,
199    {
200        #[cfg(debug_assertions)]
201        {
202            use backend::hal::api::ZnxInfos;
203
204            assert_eq!(
205                self.n(),
206                other.data.n(),
207                "invalid receiver: self.n()={} != other.n()={}",
208                self.n(),
209                other.data.n()
210            );
211            assert_eq!(
212                self.size(),
213                other.size(),
214                "invalid receiver: self.size()={} != other.size()={}",
215                self.size(),
216                other.size()
217            );
218            assert_eq!(
219                self.rank_in(),
220                other.rank_in(),
221                "invalid receiver: self.rank_in()={} != other.rank_in()={}",
222                self.rank_in(),
223                other.rank_in()
224            );
225            assert_eq!(
226                self.rank_out(),
227                other.rank_out(),
228                "invalid receiver: self.rank_out()={} != other.rank_out()={}",
229                self.rank_out(),
230                other.rank_out()
231            );
232
233            assert_eq!(
234                self.rows(),
235                other.rows(),
236                "invalid receiver: self.rows()={} != other.rows()={}",
237                self.rows(),
238                other.rows()
239            );
240        }
241
242        let rank_in: usize = self.rank_in();
243        let rows: usize = self.rows();
244
245        (0..rank_in).for_each(|col_i| {
246            (0..rows).for_each(|row_i| {
247                self.at_mut(row_i, col_i)
248                    .decompress(module, &other.at(row_i, col_i));
249            });
250        });
251    }
252}