1use poulpy_hal::{
2 layouts::{
3 Backend, Data, FillUniform, HostDataMut, HostDataRef, Module, ReaderFrom, ToOwnedDeep, TransferFrom, VecZnx,
4 VecZnxToBackendMut, VecZnxToBackendRef, WriterTo,
5 },
6 source::Source,
7};
8
9use crate::api::ModuleTransfer;
10use crate::layouts::{Base2K, Degree, LWEInfos, Rank, SetLWEInfos, TorusPrecision};
11use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
12use std::fmt;
13
14pub trait GLWEInfos
20where
21 Self: LWEInfos,
22{
23 fn rank(&self) -> Rank;
25 fn glwe_layout(&self) -> GLWELayout {
27 GLWELayout {
28 n: self.n(),
29 base2k: self.base2k(),
30 k: self.max_k(),
31 rank: self.rank(),
32 }
33 }
34}
35
36#[derive(PartialEq, Eq, Copy, Clone, Debug)]
38pub struct GLWELayout {
39 pub n: Degree,
41 pub base2k: Base2K,
43 pub k: TorusPrecision,
45 pub rank: Rank,
47}
48
49impl LWEInfos for GLWELayout {
50 fn n(&self) -> Degree {
51 self.n
52 }
53
54 fn base2k(&self) -> Base2K {
55 self.base2k
56 }
57
58 fn size(&self) -> usize {
59 self.k.as_usize().div_ceil(self.base2k.as_usize())
60 }
61}
62
63impl GLWEInfos for GLWELayout {
64 fn rank(&self) -> Rank {
65 self.rank
66 }
67}
68
69#[derive(PartialEq, Eq, Clone)]
76pub struct GLWE<D: Data> {
77 pub(crate) data: VecZnx<D>,
78 pub(crate) base2k: Base2K,
79}
80
81pub type GLWEBackendRef<'a, BE> = GLWE<<BE as Backend>::BufRef<'a>>;
82pub type GLWEBackendMut<'a, BE> = GLWE<<BE as Backend>::BufMut<'a>>;
83
84impl<D: Data> SetLWEInfos for GLWE<D> {
85 fn set_base2k(&mut self, base2k: Base2K) {
86 self.base2k = base2k
87 }
88}
89
90impl<D: Data> SetLWEInfos for &mut GLWE<D> {
91 fn set_base2k(&mut self, base2k: Base2K) {
92 self.base2k = base2k
93 }
94}
95
96impl<D: Data> GLWE<D> {
97 pub fn data(&self) -> &VecZnx<D> {
99 &self.data
100 }
101
102 pub fn max_size(&self) -> usize {
105 self.data.max_size()
106 }
107}
108
109impl<D: Data> GLWE<D> {
110 pub fn data_mut(&mut self) -> &mut VecZnx<D> {
112 &mut self.data
113 }
114}
115
116impl<D: Data> LWEInfos for GLWE<D> {
117 fn base2k(&self) -> Base2K {
118 self.base2k
119 }
120
121 fn n(&self) -> Degree {
122 Degree(self.data.n() as u32)
123 }
124
125 fn size(&self) -> usize {
126 self.data.size()
127 }
128}
129
130impl<D: Data> LWEInfos for &GLWE<D> {
131 fn base2k(&self) -> Base2K {
132 self.base2k
133 }
134
135 fn n(&self) -> Degree {
136 Degree(self.data.n() as u32)
137 }
138
139 fn size(&self) -> usize {
140 self.data.size()
141 }
142}
143
144impl<D: Data> LWEInfos for &mut GLWE<D> {
145 fn base2k(&self) -> Base2K {
146 self.base2k
147 }
148
149 fn n(&self) -> Degree {
150 Degree(self.data.n() as u32)
151 }
152
153 fn size(&self) -> usize {
154 self.data.size()
155 }
156}
157
158impl<D: Data> GLWEInfos for GLWE<D> {
159 fn rank(&self) -> Rank {
160 Rank(self.data.cols() as u32 - 1)
161 }
162}
163
164impl<D: Data> GLWEInfos for &GLWE<D> {
165 fn rank(&self) -> Rank {
166 Rank(self.data.cols() as u32 - 1)
167 }
168}
169
170impl<D: Data> GLWEInfos for &mut GLWE<D> {
171 fn rank(&self) -> Rank {
172 Rank(self.data.cols() as u32 - 1)
173 }
174}
175
176impl<D: HostDataRef> ToOwnedDeep for GLWE<D> {
177 type Owned = GLWE<Vec<u8>>;
178 fn to_owned_deep(&self) -> Self::Owned {
179 GLWE {
180 data: self.data.to_owned_deep(),
181 base2k: self.base2k,
182 }
183 }
184}
185
186impl<D: HostDataRef> GLWE<D> {
187 pub fn to_backend<BE, To>(&self, dst: &Module<To>) -> GLWE<To::OwnedBuf>
192 where
193 BE: Backend<OwnedBuf = D>,
194 To: Backend,
195 To: TransferFrom<BE>,
196 {
197 dst.upload_glwe(self)
198 }
199}
200
201impl<D: Data> GLWE<D> {
202 pub fn to_host_owned<BE>(&self) -> GLWE<Vec<u8>>
204 where
205 BE: Backend<OwnedBuf = D>,
206 {
207 GLWE {
208 data: self.data.to_host_owned::<BE>(),
209 base2k: self.base2k,
210 }
211 }
212
213 pub fn display_host<BE>(&self) -> String
215 where
216 BE: Backend<OwnedBuf = D>,
217 {
218 self.to_host_owned::<BE>().to_string()
219 }
220}
221
222impl<D: Data> GLWE<D> {
223 pub fn reinterpret<To>(self) -> GLWE<To::OwnedBuf>
225 where
226 To: Backend<OwnedBuf = D>,
227 {
228 let shape = self.data.shape();
229 let data = self.data.data;
230 GLWE {
231 data: VecZnx::from_data_with_max_size(data, shape.n(), shape.cols(), shape.size(), shape.max_size()),
232 base2k: self.base2k,
233 }
234 }
235}
236
237impl<D: HostDataRef> fmt::Debug for GLWE<D> {
238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239 write!(f, "{self}")
240 }
241}
242
243impl<D: HostDataRef> fmt::Display for GLWE<D> {
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 write!(f, "GLWE: base2k={} k={}: {}", self.base2k().0, self.max_k().0, self.data)
246 }
247}
248
249impl<D: HostDataMut> FillUniform for GLWE<D> {
250 fn fill_uniform(&mut self, log_bound: usize, source: &mut Source) {
251 self.data.fill_uniform(log_bound, source);
252 }
253}
254
255impl GLWE<Vec<u8>> {
256 pub(crate) fn alloc_from_infos<A>(infos: &A) -> Self
258 where
259 A: GLWEInfos,
260 {
261 Self::alloc(infos.n(), infos.base2k(), infos.max_k(), infos.rank())
262 }
263
264 pub(crate) fn alloc(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> Self {
271 let size: usize = k.0.div_ceil(base2k.0) as usize;
272 GLWE {
273 data: VecZnx::from_data(
274 poulpy_hal::layouts::HostBytesBackend::alloc_bytes(VecZnx::<Vec<u8>>::bytes_of(
275 n.into(),
276 (rank + 1).into(),
277 size,
278 )),
279 n.into(),
280 (rank + 1).into(),
281 size,
282 ),
283 base2k,
284 }
285 }
286
287 pub fn bytes_of_from_infos<A>(infos: &A) -> usize
289 where
290 A: GLWEInfos,
291 {
292 Self::bytes_of(infos.n(), infos.base2k(), infos.max_k(), infos.rank())
293 }
294
295 pub fn bytes_of(n: Degree, base2k: Base2K, k: TorusPrecision, rank: Rank) -> usize {
302 VecZnx::bytes_of(n.into(), (rank + 1).into(), k.0.div_ceil(base2k.0) as usize)
303 }
304
305 pub fn reallocate_limbs(&mut self, size: usize) {
307 self.data.reallocate_limbs(size);
308 }
309}
310
311impl<D: HostDataMut> ReaderFrom for GLWE<D> {
312 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
314 self.base2k = Base2K(reader.read_u32::<LittleEndian>()?);
315 self.data.read_from(reader)?;
316 Ok(())
317 }
318}
319
320impl<D: HostDataRef> WriterTo for GLWE<D> {
321 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
323 writer.write_u32::<LittleEndian>(self.base2k.0)?;
324 self.data.write_to(writer)
325 }
326}
327
328pub trait GLWEToBackendRef<BE: Backend>: Sized {
329 fn to_backend_ref(&self) -> GLWEBackendRef<'_, BE>;
330}
331
332impl<BE: Backend, D: Data> GLWEToBackendRef<BE> for GLWE<D>
333where
334 VecZnx<D>: VecZnxToBackendRef<BE>,
335{
336 fn to_backend_ref(&self) -> GLWEBackendRef<'_, BE> {
337 GLWE {
338 base2k: self.base2k,
339 data: self.data.to_backend_ref(),
340 }
341 }
342}
343
344pub fn glwe_backend_ref_from_ref<'a, 'b, BE: Backend>(glwe: &'a GLWE<BE::BufRef<'b>>) -> GLWEBackendRef<'a, BE> {
345 GLWE {
346 base2k: glwe.base2k,
347 data: poulpy_hal::layouts::vec_znx_backend_ref_from_ref::<BE>(&glwe.data),
348 }
349}
350
351impl<'b, BE: Backend + 'b> GLWEToBackendRef<BE> for &GLWE<BE::BufRef<'b>> {
352 fn to_backend_ref(&self) -> GLWEBackendRef<'_, BE> {
353 glwe_backend_ref_from_ref::<BE>(self)
354 }
355}
356
357pub fn glwe_backend_ref_from_mut<'a, 'b, BE: Backend>(glwe: &'a GLWE<BE::BufMut<'b>>) -> GLWEBackendRef<'a, BE> {
358 GLWE {
359 base2k: glwe.base2k,
360 data: poulpy_hal::layouts::vec_znx_backend_ref_from_mut::<BE>(&glwe.data),
361 }
362}
363
364pub trait GLWEToBackendMut<BE: Backend>: GLWEToBackendRef<BE> {
365 fn to_backend_mut(&mut self) -> GLWEBackendMut<'_, BE>;
366}
367
368impl<BE: Backend, D: Data> GLWEToBackendMut<BE> for GLWE<D>
369where
370 VecZnx<D>: VecZnxToBackendRef<BE> + VecZnxToBackendMut<BE>,
371{
372 fn to_backend_mut(&mut self) -> GLWEBackendMut<'_, BE> {
373 GLWE {
374 base2k: self.base2k,
375 data: self.data.to_backend_mut(),
376 }
377 }
378}
379
380impl<'b, BE: Backend + 'b> GLWEToBackendRef<BE> for &mut GLWE<BE::BufMut<'b>> {
381 fn to_backend_ref(&self) -> GLWEBackendRef<'_, BE> {
382 glwe_backend_ref_from_mut::<BE>(self)
383 }
384}
385
386impl<'b, BE: Backend + 'b> GLWEToBackendMut<BE> for &mut GLWE<BE::BufMut<'b>> {
387 fn to_backend_mut(&mut self) -> GLWEBackendMut<'_, BE> {
388 glwe_backend_mut_from_mut::<BE>(self)
389 }
390}
391
392pub fn glwe_backend_mut_from_mut<'a, 'b, BE: Backend>(glwe: &'a mut GLWE<BE::BufMut<'b>>) -> GLWEBackendMut<'a, BE> {
393 GLWE {
394 base2k: glwe.base2k,
395 data: poulpy_hal::layouts::vec_znx_backend_mut_from_mut::<BE>(&mut glwe.data),
396 }
397}