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>(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize
221 where
222 M: GGLWECompressedAlloc,
223 {
224 module.bytes_of_gglwe_compressed(base2k, k, rank_in, dnum, dsize)
225 }
226}
227
228impl<D: DataRef> GGLWECompressed<D> {
229 pub(crate) fn at(&self, row: usize, col: usize) -> GLWECompressed<&[u8]> {
230 let rank_in: usize = self.rank_in().into();
231 GLWECompressed {
232 data: self.data.at(row, col),
233 k: self.k,
234 base2k: self.base2k,
235 rank: self.rank_out,
236 seed: self.seed[rank_in * row + col],
237 }
238 }
239}
240
241impl<D: DataMut> GGLWECompressed<D> {
242 pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECompressed<&mut [u8]> {
243 let rank_in: usize = self.rank_in().into();
244 GLWECompressed {
245 k: self.k,
246 base2k: self.base2k,
247 rank: self.rank_out,
248 data: self.data.at_mut(row, col),
249 seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
250 }
251 }
252}
253
254impl<D: DataMut> ReaderFrom for GGLWECompressed<D> {
255 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
256 self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
257 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
258 self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
259 self.rank_out = Rank(reader.read_u32::<LittleEndian>()?);
260 let seed_len: u32 = reader.read_u32::<LittleEndian>()?;
261 self.seed = vec![[0u8; 32]; seed_len as usize];
262 for s in &mut self.seed {
263 reader.read_exact(s)?;
264 }
265 self.data.read_from(reader)
266 }
267}
268
269impl<D: DataRef> WriterTo for GGLWECompressed<D> {
270 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
271 writer.write_u32::<LittleEndian>(self.k.into())?;
272 writer.write_u32::<LittleEndian>(self.base2k.into())?;
273 writer.write_u32::<LittleEndian>(self.dsize.into())?;
274 writer.write_u32::<LittleEndian>(self.rank_out.into())?;
275 writer.write_u32::<LittleEndian>(self.seed.len() as u32)?;
276 for s in &self.seed {
277 writer.write_all(s)?;
278 }
279 self.data.write_to(writer)
280 }
281}
282
283pub trait GGLWEDecompress
284where
285 Self: GLWEDecompress,
286{
287 fn decompress_gglwe<R, O>(&self, res: &mut R, other: &O)
288 where
289 R: GGLWEToMut,
290 O: GGLWECompressedToRef,
291 {
292 let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
293 let other: &GGLWECompressed<&[u8]> = &other.to_ref();
294
295 assert_eq!(res.gglwe_layout(), other.gglwe_layout());
296
297 let rank_in: usize = res.rank_in().into();
298 let dnum: usize = res.dnum().into();
299
300 for row_i in 0..dnum {
301 for col_i in 0..rank_in {
302 self.decompress_glwe(&mut res.at_mut(row_i, col_i), &other.at(row_i, col_i));
303 }
304 }
305 }
306}
307
308impl<B: Backend> GGLWEDecompress for Module<B> where Self: VecZnxFillUniform + VecZnxCopy {}
309
310impl<D: DataMut> GGLWE<D> {
311 pub fn decompress<O, M>(&mut self, module: &M, other: &O)
312 where
313 O: GGLWECompressedToRef,
314 M: GGLWEDecompress,
315 {
316 module.decompress_gglwe(self, other);
317 }
318}
319
320pub trait GGLWECompressedToMut {
321 fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]>;
322}
323
324impl<D: DataMut> GGLWECompressedToMut for GGLWECompressed<D> {
325 fn to_mut(&mut self) -> GGLWECompressed<&mut [u8]> {
326 GGLWECompressed {
327 k: self.k(),
328 base2k: self.base2k(),
329 dsize: self.dsize(),
330 seed: self.seed.clone(),
331 rank_out: self.rank_out,
332 data: self.data.to_mut(),
333 }
334 }
335}
336
337pub trait GGLWECompressedToRef {
338 fn to_ref(&self) -> GGLWECompressed<&[u8]>;
339}
340
341impl<D: DataRef> GGLWECompressedToRef for GGLWECompressed<D> {
342 fn to_ref(&self) -> GGLWECompressed<&[u8]> {
343 GGLWECompressed {
344 k: self.k(),
345 base2k: self.base2k(),
346 dsize: self.dsize(),
347 seed: self.seed.clone(),
348 rank_out: self.rank_out,
349 data: self.data.to_ref(),
350 }
351 }
352}