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