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, 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
135impl<D: DataRef> GGLWE<D> {
136 pub fn data(&self) -> &MatZnx<D> {
137 &self.data
138 }
139}
140
141impl<D: DataMut> GGLWE<D> {
142 pub fn data_mut(&mut self) -> &mut MatZnx<D> {
143 &mut self.data
144 }
145}
146
147impl<D: DataRef> fmt::Debug for GGLWE<D> {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 write!(f, "{self}")
150 }
151}
152
153impl<D: DataMut> FillUniform for GGLWE<D> {
154 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
155 self.data.fill_uniform(log_bound, source);
156 }
157}
158
159impl<D: DataRef> fmt::Display for GGLWE<D> {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(
162 f,
163 "(GGLWECiphertext: k={} base2k={} dsize={}) {}",
164 self.k().0,
165 self.base2k().0,
166 self.dsize().0,
167 self.data
168 )
169 }
170}
171
172impl<D: DataRef> GGLWE<D> {
173 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
174 GLWECiphertext {
175 k: self.k,
176 base2k: self.base2k,
177 data: self.data.at(row, col),
178 }
179 }
180}
181
182impl<D: DataMut> GGLWE<D> {
183 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
184 GLWECiphertext {
185 k: self.k,
186 base2k: self.base2k,
187 data: self.data.at_mut(row, col),
188 }
189 }
190}
191
192impl GGLWE<Vec<u8>> {
193 pub fn alloc<A>(infos: &A) -> Self
194 where
195 A: GGLWEInfos,
196 {
197 Self::alloc_with(
198 infos.n(),
199 infos.base2k(),
200 infos.k(),
201 infos.rank_in(),
202 infos.rank_out(),
203 infos.dnum(),
204 infos.dsize(),
205 )
206 }
207
208 pub fn alloc_with(
209 n: Degree,
210 base2k: Base2K,
211 k: TorusPrecision,
212 rank_in: Rank,
213 rank_out: Rank,
214 dnum: Dnum,
215 dsize: Dsize,
216 ) -> Self {
217 let size: usize = k.0.div_ceil(base2k.0) as usize;
218 debug_assert!(
219 size as u32 > dsize.0,
220 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
221 dsize.0
222 );
223
224 assert!(
225 dnum.0 * dsize.0 <= size as u32,
226 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
227 dnum.0,
228 dsize.0,
229 );
230
231 Self {
232 data: MatZnx::alloc(
233 n.into(),
234 dnum.into(),
235 rank_in.into(),
236 (rank_out + 1).into(),
237 k.0.div_ceil(base2k.0) as usize,
238 ),
239 k,
240 base2k,
241 dsize,
242 }
243 }
244
245 pub fn alloc_bytes<A>(infos: &A) -> usize
246 where
247 A: GGLWEInfos,
248 {
249 Self::alloc_bytes_with(
250 infos.n(),
251 infos.base2k(),
252 infos.k(),
253 infos.rank_in(),
254 infos.rank_out(),
255 infos.dnum(),
256 infos.dsize(),
257 )
258 }
259
260 pub fn alloc_bytes_with(
261 n: Degree,
262 base2k: Base2K,
263 k: TorusPrecision,
264 rank_in: Rank,
265 rank_out: Rank,
266 dnum: Dnum,
267 dsize: Dsize,
268 ) -> usize {
269 let size: usize = k.0.div_ceil(base2k.0) as usize;
270 debug_assert!(
271 size as u32 > dsize.0,
272 "invalid gglwe: ceil(k/base2k): {size} <= dsize: {}",
273 dsize.0
274 );
275
276 assert!(
277 dnum.0 * dsize.0 <= size as u32,
278 "invalid gglwe: dnum: {} * dsize:{} > ceil(k/base2k): {size}",
279 dnum.0,
280 dsize.0,
281 );
282
283 MatZnx::alloc_bytes(
284 n.into(),
285 dnum.into(),
286 rank_in.into(),
287 (rank_out + 1).into(),
288 k.0.div_ceil(base2k.0) as usize,
289 )
290 }
291}
292
293pub trait GGLWECiphertextToMut {
294 fn to_mut(&mut self) -> GGLWE<&mut [u8]>;
295}
296
297impl<D: DataMut> GGLWECiphertextToMut for GGLWE<D> {
298 fn to_mut(&mut self) -> GGLWE<&mut [u8]> {
299 GGLWE {
300 k: self.k(),
301 base2k: self.base2k(),
302 dsize: self.dsize(),
303 data: self.data.to_mut(),
304 }
305 }
306}
307
308pub trait GGLWEToRef {
309 fn to_ref(&self) -> GGLWE<&[u8]>;
310}
311
312impl<D: DataRef> GGLWEToRef for GGLWE<D> {
313 fn to_ref(&self) -> GGLWE<&[u8]> {
314 GGLWE {
315 k: self.k(),
316 base2k: self.base2k(),
317 dsize: self.dsize(),
318 data: self.data.to_ref(),
319 }
320 }
321}
322
323impl<D: DataMut> ReaderFrom for GGLWE<D> {
324 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
325 self.k = TorusPrecision(reader.read_u32::<LittleEndian>()?);
326 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
327 self.dsize = Dsize(reader.read_u32::<LittleEndian>()?);
328 self.data.read_from(reader)
329 }
330}
331
332impl<D: DataRef> WriterTo for GGLWE<D> {
333 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
334 writer.write_u32::<LittleEndian>(self.k.0)?;
335 writer.write_u32::<LittleEndian>(self.base2k.0)?;
336 writer.write_u32::<LittleEndian>(self.dsize.0)?;
337 self.data.write_to(writer)
338 }
339}