poulpy/poulpy-core/src/layouts/compressed/gglwe_ct.rs
poulpy-core/src/layouts/compressed/gglwe_ct.rsRaw
1use poulpy_hal::{
2 api::{VecZnxCopy, VecZnxFillUniform},
3 layouts::{
4 Backend, Data, DataMut, DataRef, FillUniform, MatZnx, MatZnxToMut, MatZnxToRef, Module, ReaderFrom, WriterTo, ZnxInfos,
5 },
6 source::Source,
7};
8
9use crate::layouts::{
10 Base2K, Degree, Dnum, Dsize, GGLWE, GGLWEInfos, GGLWEToMut, GLWEInfos, GetDegree, LWEInfos, Rank, TorusPrecision,
11 compressed::{GLWECompressed, GLWEDecompress},
12};
13use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
14use std::fmt;
15
16#[derive(PartialEq, Eq, Clone)]
17pub struct GGLWECompressed<D: Data> {
18 pub(crate) data: MatZnx<D>,
19 pub(crate) base2k: Base2K,
20 pub(crate) k: TorusPrecision,
21 pub(crate) rank_out: Rank,
22 pub(crate) dsize: Dsize,
23 pub(crate) seed: Vec<[u8; 32]>,
24}
25
26impl<D: Data> LWEInfos for GGLWECompressed<D> {
27 fn n(&self) -> Degree {
28 Degree(self.data.n() as u32)
29 }
30
31 fn base2k(&self) -> Base2K {
32 self.base2k
33 }
34
35 fn k(&self) -> TorusPrecision {
36 self.k
37 }
38
39 fn size(&self) -> usize {
40 self.data.size()
41 }
42}
43impl<D: Data> GLWEInfos for GGLWECompressed<D> {
44 fn rank(&self) -> Rank {
45 self.rank_out()
46 }
47}
48
49impl<D: Data> GGLWEInfos for GGLWECompressed<D> {
50 fn rank_in(&self) -> Rank {
51 Rank(self.data.cols_in() as u32)
52 }
53
54 fn rank_out(&self) -> Rank {
55 self.rank_out
56 }
57
58 fn dsize(&self) -> Dsize {
59 self.dsize
60 }
61
62 fn dnum(&self) -> Dnum {
63 Dnum(self.data.rows() as u32)
64 }
65}
66
67impl<D: DataRef> fmt::Debug for GGLWECompressed<D> {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 write!(f, "{self}")
70 }
71}
72
73impl<D: DataMut> FillUniform for GGLWECompressed<D> {
74 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
75 self.data.fill_uniform(log_bound, source);
76 }
77}
78
79impl<D: DataRef> fmt::Display for GGLWECompressed<D> {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(
82 f,
83 "(GGLWECompressed: base2k={} k={} dsize={}) {}",
84 self.base2k.0, self.k.0, self.dsize.0, self.data
85 )
86 }
87}
88
89pub trait GGLWECompressedAlloc
90where
91 Self: GetDegree,
92{
93 fn alloc_gglwe_compressed(
94 &self,
95 base2k: Base2K,
96 k: TorusPrecision,
97 rank_in: Rank,
98 rank_out: Rank,
99 dnum: Dnum,
100 dsize: Dsize,
101 ) -> GGLWECompressed<Vec<u8>> {
102 let size: usize = k.0.div_ceil(base2k.0) as usize;
103 debug_assert!(
104 size as u32 > dsize.0,
105 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
106 dsize.0
107 );
108
109 assert!(
110 dnum.0 * dsize.0 <= size as u32,
111 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
112 dnum.0,
113 dsize.0,
114 );
115
116 GGLWECompressed {
117 data: MatZnx::alloc(
118 self.n().into(),
119 dnum.into(),
120 rank_in.into(),
121 1,
122 k.0.div_ceil(base2k.0) as usize,
123 ),
124 k,
125 base2k,
126 dsize,
127 rank_out,
128 seed: vec![[0u8; 32]; (dnum.0 * rank_in.0) as usize],
129 }
130 }
131
132 fn alloc_gglwe_compressed_from_infos<A>(&self, infos: &A) -> GGLWECompressed<Vec<u8>>
133 where
134 A: GGLWEInfos,
135 {
136 assert_eq!(infos.n(), self.n());
137 self.alloc_gglwe_compressed(
138 infos.base2k(),
139 infos.k(),
140 infos.rank_in(),
141 infos.rank_out(),
142 infos.dnum(),
143 infos.dsize(),
144 )
145 }
146
147 fn bytes_of_gglwe_compressed(&self, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize {
148 let size: usize = k.0.div_ceil(base2k.0) as usize;
149 debug_assert!(
150 size as u32 > dsize.0,
151 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
152 dsize.0
153 );
154
155 assert!(
156 dnum.0 * dsize.0 <= size as u32,
157 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
158 dnum.0,
159 dsize.0,
160 );
161
162 MatZnx::bytes_of(
163 self.n().into(),
164 dnum.into(),
165 rank_in.into(),
166 1,
167 k.0.div_ceil(base2k.0) as usize,
168 )
169 }
170
171 fn bytes_of_gglwe_compressed_from_infos<A>(&self, infos: &A) -> usize
172 where
173 A: GGLWEInfos,
174 {
175 assert_eq!(infos.n(), self.n());
176 self.bytes_of_gglwe_compressed(
177 infos.base2k(),
178 infos.k(),
179 infos.rank_in(),
180 infos.dnum(),
181 infos.dsize(),
182 )
183 }
184}
185
186impl<B: Backend> GGLWECompressedAlloc for Module<B> where Self: GetDegree {}
187
188impl GGLWECompressed<Vec<u8>> {
189 pub fn alloc_from_infos<A, M>(module: &M, infos: &A) -> Self
190 where
191 A: GGLWEInfos,
192 M: GGLWECompressedAlloc,
193 {
194 module.alloc_gglwe_compressed_from_infos(infos)
195 }
196
197 pub fn alloc<M>(
198 module: &M,
199 base2k: Base2K,
200 k: TorusPrecision,
201 rank_in: Rank,
202 rank_out: Rank,
203 dnum: Dnum,
204 dsize: Dsize,
205 ) -> Self
206 where
207 M: GGLWECompressedAlloc,
208 {
209 module.alloc_gglwe_compressed(base2k, k, rank_in, rank_out, dnum, dsize)
210 }
211
212 pub fn bytes_of_from_infos<A, M>(module: &M, infos: &A) -> usize
213 where
214 A: GGLWEInfos,
215 M: GGLWECompressedAlloc,
216 {
217 module.bytes_of_gglwe_compressed_from_infos(infos)
218 }
219
220 pub fn byte_of<M>(
221 module: &M,
222 base2k: Base2K,
223 k: TorusPrecision,
224 rank_in: Rank,
225 dnum: Dnum,
226 dsize: Dsize,
227 ) -> usize
228 where
229 M: GGLWECompressedAlloc,
230 {
231 module.bytes_of_gglwe_compressed(base2k, k, rank_in, dnum, dsize)
232 }
233}
234
235impl<D: DataRef> GGLWECompressed<D> {
236 pub(crate) fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> {
237 let rank_in: usize = self.rank_in().into();
238 GLWECompressed {
239 data: self.data.at(row, col),
240 k: self.k,
241 base2k: self.base2k,
242 rank: self.rank_out,
243 seed: self.seed[rank_in * row + col],
244 }
245 }
246}
247
248impl<D: DataMut> GGLWECompressed<D> {
249 pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> {
250 let rank_in: usize = self.rank_in().into();
251 GLWECompressed {
252 k: self.k,
253 base2k: self.base2k,
254 rank: self.rank_out,
255 data: self.data.at_mut(row, col),
256 seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
257 }
258 }
259}
260
261impl<D: DataMut> ReaderFrom for GGLWECompressed<D> {
262 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
263 self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
264 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
265 self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
266 self.rank_out = Rank(reader.read_u32::<LittleEndian>()?);
267 let seed_len: u32 = reader.read_u32::<LittleEndian>()?;
268 self.seed = vec![[0u8; 32]; seed_len as usize];
269 for s in &mut self.seed {
270 reader.read_exact(s)?;
271 }
272 self.data.read_from(reader)
273 }
274}
275
276impl<D: DataRef> WriterTo for GGLWECompressed<D> {
277 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
278 writer.write_u32::<LittleEndian>(self.k.into())?;
279 writer.write_u32::<LittleEndian>(self.base2k.into())?;
280 writer.write_u32::<LittleEndian>(self.dsize.into())?;
281 writer.write_u32::<LittleEndian>(self.rank_out.into())?;
282 writer.write_u32::<LittleEndian>(self.seed.len() as u32)?;
283 for s in &self.seed {
284 writer.write_all(s)?;
285 }
286 self.data.write_to(writer)
287 }
288}
289
290pub trait GGLWEDecompress
291where
292 Self: GLWEDecompress,
293{
294 fn decompress_gglwe<R, O>(&self, res: &mut R, other: &O)
295 where
296 R: GGLWEToMut,
297 O: GGLWECompressedToRef,
298 {
299 let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
300 let other: &GGLWECompressed<&[u8]> = &other.to_ref();
301
302 assert_eq!(res.gglwe_layout(), other.gglwe_layout());
303
304 let rank_in: usize = res.rank_in().into();
305 let dnum: usize = res.dnum().into();
306
307 for row_i in 0..dnum {
308 for col_i in 0..rank_in {
309 self.decompress_glwe(&mut res.at_mut(row_i, col_i), &other.at(row_i, col_i));
310 }
311 }
312 }
313}
314
315impl<B: Backend> GGLWEDecompress for Module<B> where Self: VecZnxFillUniform + VecZnxCopy {}
316
317impl<D: DataMut> GGLWE<D> {
318 pub fn decompress<O, M>(&mut self, module: &M, other: &O)
319 where
320 O: GGLWECompressedToRef,
321 M: GGLWEDecompress,
322 {
323 module.decompress_gglwe(self, other);
324 }
325}
326
327pub trait GGLWECompressedToMut {
328 fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]>;
329}
330
331impl<D: DataMut> GGLWECompressedToMut for GGLWECompressed<D> {
332 fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> {
333 GGLWECompressed {
334 k: self.k(),
335 base2k: self.base2k(),
336 dsize: self.dsize(),
337 seed: self.seed.clone(),
338 rank_out: self.rank_out,
339 data: self.data.to_mut(),
340 }
341 }
342}
343
344pub trait GGLWECompressedToRef {
345 fn to_ref(&self) -> GGLWECompressed<&[u8]>;
346}
347
348impl<D: DataRef> GGLWECompressedToRef for GGLWECompressed<D> {
349 fn to_ref(&self) -> GGLWECompressed<&[u8]> {
350 GGLWECompressed {
351 k: self.k(),
352 base2k: self.base2k(),
353 dsize: self.dsize(),
354 seed: self.seed.clone(),
355 rank_out: self.rank_out,
356 data: self.data.to_ref(),
357 }
358 }
359}