arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/layouts/prepared/ggsw_ct.rs
poulpy-core/src/layouts/prepared/ggsw_ct.rsRaw
  1use poulpy_hal::{
  2    api::{VmpPMatAlloc, VmpPMatAllocBytes, VmpPrepare},
  3    layouts::{Backend, Data, DataMut, DataRef, Module, Scratch, VmpPMat, ZnxInfos},
  4    oep::VmpPMatAllocBytesImpl,
  5};
  6
  7use crate::layouts::{
  8    Base2K, BuildError, Degree, Digits, GGSWCiphertext, GGSWInfos, GLWEInfos, LWEInfos, Rank, Rows, TorusPrecision,
  9    prepared::{Prepare, PrepareAlloc},
 10};
 11
 12#[derive(PartialEq, Eq)]
 13pub struct GGSWCiphertextPrepared<D: Data, B: Backend> {
 14    pub(crate) data: VmpPMat<D, B>,
 15    pub(crate) k: TorusPrecision,
 16    pub(crate) base2k: Base2K,
 17    pub(crate) digits: Digits,
 18}
 19
 20impl<D: Data, B: Backend> LWEInfos for GGSWCiphertextPrepared<D, B> {
 21    fn n(&self) -> Degree {
 22        Degree(self.data.n() as u32)
 23    }
 24
 25    fn base2k(&self) -> Base2K {
 26        self.base2k
 27    }
 28
 29    fn k(&self) -> TorusPrecision {
 30        self.k
 31    }
 32
 33    fn size(&self) -> usize {
 34        self.data.size()
 35    }
 36}
 37
 38impl<D: Data, B: Backend> GLWEInfos for GGSWCiphertextPrepared<D, B> {
 39    fn rank(&self) -> Rank {
 40        Rank(self.data.cols_out() as u32 - 1)
 41    }
 42}
 43
 44impl<D: Data, B: Backend> GGSWInfos for GGSWCiphertextPrepared<D, B> {
 45    fn digits(&self) -> Digits {
 46        self.digits
 47    }
 48
 49    fn rows(&self) -> Rows {
 50        Rows(self.data.rows() as u32)
 51    }
 52}
 53
 54pub struct GGSWCiphertextPreparedBuilder<D: Data, B: Backend> {
 55    data: Option<VmpPMat<D, B>>,
 56    base2k: Option<Base2K>,
 57    k: Option<TorusPrecision>,
 58    digits: Option<Digits>,
 59}
 60
 61impl<D: Data, B: Backend> GGSWCiphertextPrepared<D, B> {
 62    #[inline]
 63    pub fn builder() -> GGSWCiphertextPreparedBuilder<D, B> {
 64        GGSWCiphertextPreparedBuilder {
 65            data: None,
 66            base2k: None,
 67            k: None,
 68            digits: None,
 69        }
 70    }
 71}
 72
 73impl<B: Backend> GGSWCiphertextPreparedBuilder<Vec<u8>, B> {
 74    #[inline]
 75    pub fn layout<A>(mut self, infos: &A) -> Self
 76    where
 77        A: GGSWInfos,
 78        B: VmpPMatAllocBytesImpl<B>,
 79    {
 80        debug_assert!(
 81            infos.size() as u32 > infos.digits().0,
 82            "invalid ggsw: ceil(k/base2k): {} <= digits: {}",
 83            infos.size(),
 84            infos.digits()
 85        );
 86
 87        assert!(
 88            infos.rows().0 * infos.digits().0 <= infos.size() as u32,
 89            "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {}",
 90            infos.rows(),
 91            infos.digits(),
 92            infos.size(),
 93        );
 94
 95        self.data = Some(VmpPMat::alloc(
 96            infos.n().into(),
 97            infos.rows().into(),
 98            (infos.rank() + 1).into(),
 99            (infos.rank() + 1).into(),
100            infos.size(),
101        ));
102        self.base2k = Some(infos.base2k());
103        self.k = Some(infos.k());
104        self.digits = Some(infos.digits());
105        self
106    }
107}
108
109impl<D: Data, B: Backend> GGSWCiphertextPreparedBuilder<D, B> {
110    #[inline]
111    pub fn data(mut self, data: VmpPMat<D, B>) -> Self {
112        self.data = Some(data);
113        self
114    }
115    #[inline]
116    pub fn base2k(mut self, base2k: Base2K) -> Self {
117        self.base2k = Some(base2k);
118        self
119    }
120    #[inline]
121    pub fn k(mut self, k: TorusPrecision) -> Self {
122        self.k = Some(k);
123        self
124    }
125
126    #[inline]
127    pub fn digits(mut self, digits: Digits) -> Self {
128        self.digits = Some(digits);
129        self
130    }
131
132    pub fn build(self) -> Result<GGSWCiphertextPrepared<D, B>, BuildError> {
133        let data: VmpPMat<D, B> = self.data.ok_or(BuildError::MissingData)?;
134        let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
135        let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
136        let digits: Digits = self.digits.ok_or(BuildError::MissingDigits)?;
137
138        if base2k == 0_u32 {
139            return Err(BuildError::ZeroBase2K);
140        }
141
142        if digits == 0_u32 {
143            return Err(BuildError::ZeroBase2K);
144        }
145
146        if k == 0_u32 {
147            return Err(BuildError::ZeroTorusPrecision);
148        }
149
150        if data.n() == 0 {
151            return Err(BuildError::ZeroDegree);
152        }
153
154        if data.cols() == 0 {
155            return Err(BuildError::ZeroCols);
156        }
157
158        if data.size() == 0 {
159            return Err(BuildError::ZeroLimbs);
160        }
161
162        Ok(GGSWCiphertextPrepared {
163            data,
164            base2k,
165            k,
166            digits,
167        })
168    }
169}
170
171impl<B: Backend> GGSWCiphertextPrepared<Vec<u8>, B> {
172    pub fn alloc<A>(module: &Module<B>, infos: &A) -> Self
173    where
174        A: GGSWInfos,
175        Module<B>: VmpPMatAlloc<B>,
176    {
177        Self::alloc_with(
178            module,
179            infos.base2k(),
180            infos.k(),
181            infos.rows(),
182            infos.digits(),
183            infos.rank(),
184        )
185    }
186
187    pub fn alloc_with(module: &Module<B>, base2k: Base2K, k: TorusPrecision, rows: Rows, digits: Digits, rank: Rank) -> Self
188    where
189        Module<B>: VmpPMatAlloc<B>,
190    {
191        let size: usize = k.0.div_ceil(base2k.0) as usize;
192        debug_assert!(
193            size as u32 > digits.0,
194            "invalid ggsw: ceil(k/base2k): {size} <= digits: {}",
195            digits.0
196        );
197
198        assert!(
199            rows.0 * digits.0 <= size as u32,
200            "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}",
201            rows.0,
202            digits.0,
203        );
204
205        Self {
206            data: module.vmp_pmat_alloc(
207                rows.into(),
208                (rank + 1).into(),
209                (rank + 1).into(),
210                k.0.div_ceil(base2k.0) as usize,
211            ),
212            k,
213            base2k,
214            digits,
215        }
216    }
217
218    pub fn alloc_bytes<A>(module: &Module<B>, infos: &A) -> usize
219    where
220        A: GGSWInfos,
221        Module<B>: VmpPMatAllocBytes,
222    {
223        Self::alloc_bytes_with(
224            module,
225            infos.base2k(),
226            infos.k(),
227            infos.rows(),
228            infos.digits(),
229            infos.rank(),
230        )
231    }
232
233    pub fn alloc_bytes_with(
234        module: &Module<B>,
235        base2k: Base2K,
236        k: TorusPrecision,
237        rows: Rows,
238        digits: Digits,
239        rank: Rank,
240    ) -> usize
241    where
242        Module<B>: VmpPMatAllocBytes,
243    {
244        let size: usize = k.0.div_ceil(base2k.0) as usize;
245        debug_assert!(
246            size as u32 > digits.0,
247            "invalid ggsw: ceil(k/base2k): {size} <= digits: {}",
248            digits.0
249        );
250
251        assert!(
252            rows.0 * digits.0 <= size as u32,
253            "invalid ggsw: rows: {} * digits:{} > ceil(k/base2k): {size}",
254            rows.0,
255            digits.0,
256        );
257
258        module.vmp_pmat_alloc_bytes(rows.into(), (rank + 1).into(), (rank + 1).into(), size)
259    }
260}
261
262impl<D: DataRef, B: Backend> GGSWCiphertextPrepared<D, B> {
263    pub fn data(&self) -> &VmpPMat<D, B> {
264        &self.data
265    }
266}
267
268impl<D: DataMut, DR: DataRef, B: Backend> Prepare<B, GGSWCiphertext<DR>> for GGSWCiphertextPrepared<D, B>
269where
270    Module<B>: VmpPrepare<B>,
271{
272    fn prepare(&mut self, module: &Module<B>, other: &GGSWCiphertext<DR>, scratch: &mut Scratch<B>) {
273        module.vmp_prepare(&mut self.data, &other.data, scratch);
274        self.k = other.k;
275        self.base2k = other.base2k;
276        self.digits = other.digits;
277    }
278}
279
280impl<D: DataRef, B: Backend> PrepareAlloc<B, GGSWCiphertextPrepared<Vec<u8>, B>> for GGSWCiphertext<D>
281where
282    Module<B>: VmpPMatAlloc<B> + VmpPrepare<B>,
283{
284    fn prepare_alloc(&self, module: &Module<B>, scratch: &mut Scratch<B>) -> GGSWCiphertextPrepared<Vec<u8>, B> {
285        let mut ggsw_prepared: GGSWCiphertextPrepared<Vec<u8>, B> = GGSWCiphertextPrepared::alloc(module, self);
286        ggsw_prepared.prepare(module, self, scratch);
287        ggsw_prepared
288    }
289}