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