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, BuildError, 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
135pub struct GGLWECiphertextBuilder<D: Data> {
136 data: Option<MatZnx<D>>,
137 base2k: Option<Base2K>,
138 k: Option<TorusPrecision>,
139 dsize: Option<Dsize>,
140}
141
142impl<D: Data> GGLWE<D> {
143 #[inline]
144 pub fn builder() -> GGLWECiphertextBuilder<D> {
145 GGLWECiphertextBuilder {
146 data: None,
147 base2k: None,
148 k: None,
149 dsize: None,
150 }
151 }
152}
153
154impl GGLWECiphertextBuilder<Vec<u8>> {
155 #[inline]
156 pub fn layout<A>(mut self, infos: &A) -> Self
157 where
158 A: GGLWEInfos,
159 {
160 self.data = Some(MatZnx::alloc(
161 infos.n().into(),
162 infos.dnum().into(),
163 infos.rank_in().into(),
164 (infos.rank_out() + 1).into(),
165 infos.size(),
166 ));
167 self.base2k = Some(infos.base2k());
168 self.k = Some(infos.k());
169 self.dsize = Some(infos.dsize());
170 self
171 }
172}
173
174impl<D: Data> GGLWECiphertextBuilder<D> {
175 #[inline]
176 pub fn data(mut self, data: MatZnx<D>) -> Self {
177 self.data = Some(data);
178 self
179 }
180 #[inline]
181 pub fn base2k(mut self, base2k: Base2K) -> Self {
182 self.base2k = Some(base2k);
183 self
184 }
185 #[inline]
186 pub fn k(mut self, k: TorusPrecision) -> Self {
187 self.k = Some(k);
188 self
189 }
190
191 #[inline]
192 pub fn dsize(mut self, dsize: Dsize) -> Self {
193 self.dsize = Some(dsize);
194 self
195 }
196
197 pub fn build(self) -> Result<GGLWE<D>, BuildError> {
198 let data: MatZnx<D> = self.data.ok_or(BuildError::MissingData)?;
199 let base2k: Base2K = self.base2k.ok_or(BuildError::MissingBase2K)?;
200 let k: TorusPrecision = self.k.ok_or(BuildError::MissingK)?;
201 let dsize: Dsize = self.dsize.ok_or(BuildError::MissingDigits)?;
202
203 if base2k == 0_u32 {
204 return Err(BuildError::ZeroBase2K);
205 }
206
207 if dsize == 0_u32 {
208 return Err(BuildError::ZeroBase2K);
209 }
210
211 if k == 0_u32 {
212 return Err(BuildError::ZeroTorusPrecision);
213 }
214
215 if data.n() == 0 {
216 return Err(BuildError::ZeroDegree);
217 }
218
219 if data.cols() == 0 {
220 return Err(BuildError::ZeroCols);
221 }
222
223 if data.size() == 0 {
224 return Err(BuildError::ZeroLimbs);
225 }
226
227 Ok(GGLWE {
228 data,
229 base2k,
230 k,
231 dsize,
232 })
233 }
234}
235
236impl<D: DataRef> GGLWE<D> {
237 pub fn data(&self) -> &MatZnx<D> {
238 &self.data
239 }
240}
241
242impl<D: DataMut> GGLWE<D> {
243 pub fn data_mut(&mut self) -> &mut MatZnx<D> {
244 &mut self.data
245 }
246}
247
248impl<D: DataRef> fmt::Debug for GGLWE<D> {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 write!(f, "{self}")
251 }
252}
253
254impl<D: DataMut> FillUniform for GGLWE<D> {
255 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
256 self.data.fill_uniform(log_bound, source);
257 }
258}
259
260impl<D: DataRef> fmt::Display for GGLWE<D> {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 write!(
263 f,
264 "(GGLWECiphertext: k={} base2k={} dsize={}) {}",
265 self.k().0,
266 self.base2k().0,
267 self.dsize().0,
268 self.data
269 )
270 }
271}
272
273impl<D: DataRef> GGLWE<D> {
274 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
275 GLWECiphertext::builder()
276 .data(self.data.at(row, col))
277 .base2k(self.base2k())
278 .k(self.k())
279 .build()
280 .unwrap()
281 }
282}
283
284impl<D: DataMut> GGLWE<D> {
285 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
286 GLWECiphertext::builder()
287 .base2k(self.base2k())
288 .k(self.k())
289 .data(self.data.at_mut(row, col))
290 .build()
291 .unwrap()
292 }
293}
294
295impl GGLWE<Vec<u8>> {
296 pub fn alloc<A>(infos: &A) -> Self
297 where
298 A: GGLWEInfos,
299 {
300 Self::alloc_with(
301 infos.n(),
302 infos.base2k(),
303 infos.k(),
304 infos.rank_in(),
305 infos.rank_out(),
306 infos.dnum(),
307 infos.dsize(),
308 )
309 }
310
311 pub fn alloc_with(
312 n: Degree,
313 base2k: Base2K,
314 k: TorusPrecision,
315 rank_in: Rank,
316 rank_out: Rank,
317 dnum: Dnum,
318 dsize: Dsize,
319 ) -> Self {
320 let size: usize = k.0.div_ceil(base2k.0) as usize;
321 debug_assert!(
322 size as u32 > dsize.0,
323 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
324 dsize.0
325 );
326
327 assert!(
328 dnum.0 * dsize.0 <= size as u32,
329 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
330 dnum.0,
331 dsize.0,
332 );
333
334 Self {
335 data: MatZnx::alloc(
336 n.into(),
337 dnum.into(),
338 rank_in.into(),
339 (rank_out + 1).into(),
340 k.0.div_ceil(base2k.0) as usize,
341 ),
342 k,
343 base2k,
344 dsize,
345 }
346 }
347
348 pub fn alloc_bytes<A>(infos: &A) -> usize
349 where
350 A: GGLWEInfos,
351 {
352 Self::alloc_bytes_with(
353 infos.n(),
354 infos.base2k(),
355 infos.k(),
356 infos.rank_in(),
357 infos.rank_out(),
358 infos.dnum(),
359 infos.dsize(),
360 )
361 }
362
363 pub fn alloc_bytes_with(
364 n: Degree,
365 base2k: Base2K,
366 k: TorusPrecision,
367 rank_in: Rank,
368 rank_out: Rank,
369 dnum: Dnum,
370 dsize: Dsize,
371 ) -> usize {
372 let size: usize = k.0.div_ceil(base2k.0) as usize;
373 debug_assert!(
374 size as u32 > dsize.0,
375 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
376 dsize.0
377 );
378
379 assert!(
380 dnum.0 * dsize.0 <= size as u32,
381 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
382 dnum.0,
383 dsize.0,
384 );
385
386 MatZnx::alloc_bytes(
387 n.into(),
388 dnum.into(),
389 rank_in.into(),
390 (rank_out + 1).into(),
391 k.0.div_ceil(base2k.0) as usize,
392 )
393 }
394}
395
396pub trait GGLWECiphertextToMut {
397 fn to_mut(&mut self) -> GGLWE<&mut [u8]>;
398}
399
400impl<D: DataMut> GGLWECiphertextToMut for GGLWE<D> {
401 fn to_mut(&mut self) -> GGLWE<&mut [u8]> {
402 GGLWE {
403 k: self.k(),
404 base2k: self.base2k(),
405 dsize: self.dsize(),
406 data: self.data.to_mut(),
407 }
408 }
409}
410
411pub trait GGLWEToRef {
412 fn to_ref(&self) -> GGLWE<&[u8]>;
413}
414
415impl<D: DataRef> GGLWEToRef for GGLWE<D> {
416 fn to_ref(&self) -> GGLWE<&[u8]> {
417 GGLWE {
418 k: self.k(),
419 base2k: self.base2k(),
420 dsize: self.dsize(),
421 data: self.data.to_ref(),
422 }
423 }
424}
425
426impl<D: DataMut> ReaderFrom for GGLWE<D> {
427 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
428 self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
429 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
430 self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
431 self.data.read_from(reader)
432 }
433}
434
435impl<D: DataRef> WriterTo for GGLWE<D> {
436 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
437 writer.write_u32::<LittleEndian>(self.k.0)?;
438 writer.write_u32::<LittleEndian>(self.base2k.0)?;
439 writer.write_u32::<LittleEndian>(self.dsize.0)?;
440 self.data.write_to(writer)
441 }
442}