poulpy/core/src/gglwe/layout.rs
core/src/gglwe/layout.rsRaw
1use backend::hal::{
2 api::{FillUniform, Reset, VmpPMatAlloc, VmpPMatAllocBytes, VmpPMatPrepare},
3 layouts::{Backend, Data, DataMut, DataRef, MatZnx, ReaderFrom, WriterTo},
4};
5
6use crate::{GLWECiphertext, Infos};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8
9pub trait GGLWEExecLayoutFamily<B: Backend> = VmpPMatAlloc<B> + VmpPMatAllocBytes + VmpPMatPrepare<B>;
10use std::fmt;
11
12#[derive(PartialEq, Eq, Clone)]
13pub struct GGLWECiphertext<D: Data> {
14 pub(crate) data: MatZnx<D>,
15 pub(crate) basek: usize,
16 pub(crate) k: usize,
17 pub(crate) digits: usize,
18}
19
20impl<D: DataRef> fmt::Debug for GGLWECiphertext<D> {
21 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22 write!(f, "{}", self)
23 }
24}
25
26impl<D: DataMut> FillUniform for GGLWECiphertext<D> {
27 fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
28 self.data.fill_uniform(source);
29 }
30}
31
32impl<D: DataMut> Reset for GGLWECiphertext<D>
33where
34 MatZnx<D>: Reset,
35{
36 fn reset(&mut self) {
37 self.data.reset();
38 self.basek = 0;
39 self.k = 0;
40 self.digits = 0;
41 }
42}
43
44impl<D: DataRef> fmt::Display for GGLWECiphertext<D> {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(
47 f,
48 "(GGLWECiphertext: basek={} k={} digits={}) {}",
49 self.basek, self.k, self.digits, self.data
50 )
51 }
52}
53
54impl<D: DataRef> GGLWECiphertext<D> {
55 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
56 GLWECiphertext {
57 data: self.data.at(row, col),
58 basek: self.basek,
59 k: self.k,
60 }
61 }
62}
63
64impl<D: DataMut> GGLWECiphertext<D> {
65 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
66 GLWECiphertext {
67 data: self.data.at_mut(row, col),
68 basek: self.basek,
69 k: self.k,
70 }
71 }
72}
73
74impl GGLWECiphertext<Vec<u8>> {
75 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
76 let size: usize = k.div_ceil(basek);
77 debug_assert!(
78 size > digits,
79 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
80 size,
81 digits
82 );
83
84 assert!(
85 rows * digits <= size,
86 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
87 rows,
88 digits,
89 size
90 );
91
92 Self {
93 data: MatZnx::alloc(n, rows, rank_in, rank_out + 1, size),
94 basek: basek,
95 k,
96 digits,
97 }
98 }
99
100 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
101 let size: usize = k.div_ceil(basek);
102 debug_assert!(
103 size > digits,
104 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
105 size,
106 digits
107 );
108
109 assert!(
110 rows * digits <= size,
111 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
112 rows,
113 digits,
114 size
115 );
116
117 MatZnx::alloc_bytes(n, rows, rank_in, rank_out + 1, rows)
118 }
119}
120
121impl<D: Data> Infos for GGLWECiphertext<D> {
122 type Inner = MatZnx<D>;
123
124 fn inner(&self) -> &Self::Inner {
125 &self.data
126 }
127
128 fn basek(&self) -> usize {
129 self.basek
130 }
131
132 fn k(&self) -> usize {
133 self.k
134 }
135}
136
137impl<D: Data> GGLWECiphertext<D> {
138 pub fn rank(&self) -> usize {
139 self.data.cols_out() - 1
140 }
141
142 pub fn digits(&self) -> usize {
143 self.digits
144 }
145
146 pub fn rank_in(&self) -> usize {
147 self.data.cols_in()
148 }
149
150 pub fn rank_out(&self) -> usize {
151 self.data.cols_out() - 1
152 }
153}
154
155impl<D: DataMut> ReaderFrom for GGLWECiphertext<D> {
156 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
157 self.k = reader.read_u64::<LittleEndian>()? as usize;
158 self.basek = reader.read_u64::<LittleEndian>()? as usize;
159 self.digits = reader.read_u64::<LittleEndian>()? as usize;
160 self.data.read_from(reader)
161 }
162}
163
164impl<D: DataRef> WriterTo for GGLWECiphertext<D> {
165 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
166 writer.write_u64::<LittleEndian>(self.k as u64)?;
167 writer.write_u64::<LittleEndian>(self.basek as u64)?;
168 writer.write_u64::<LittleEndian>(self.digits as u64)?;
169 self.data.write_to(writer)
170 }
171}
172
173#[derive(PartialEq, Eq, Clone)]
174pub struct GLWESwitchingKey<D: Data> {
175 pub(crate) key: GGLWECiphertext<D>,
176 pub(crate) sk_in_n: usize, // Degree of sk_in
177 pub(crate) sk_out_n: usize, // Degree of sk_out
178}
179
180impl<D: DataRef> fmt::Debug for GLWESwitchingKey<D> {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 write!(f, "{}", self)
183 }
184}
185
186impl<D: DataRef> fmt::Display for GLWESwitchingKey<D> {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 write!(
189 f,
190 "(GLWESwitchingKey: sk_in_n={} sk_out_n={}) {}",
191 self.sk_in_n, self.sk_out_n, self.key.data
192 )
193 }
194}
195
196impl<D: DataMut> FillUniform for GLWESwitchingKey<D> {
197 fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
198 self.key.fill_uniform(source);
199 }
200}
201
202impl<D: DataMut> Reset for GLWESwitchingKey<D>
203where
204 MatZnx<D>: Reset,
205{
206 fn reset(&mut self) {
207 self.key.reset();
208 self.sk_in_n = 0;
209 self.sk_out_n = 0;
210 }
211}
212
213impl GLWESwitchingKey<Vec<u8>> {
214 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
215 GLWESwitchingKey {
216 key: GGLWECiphertext::alloc(n, basek, k, rows, digits, rank_in, rank_out),
217 sk_in_n: 0,
218 sk_out_n: 0,
219 }
220 }
221
222 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
223 GGLWECiphertext::<Vec<u8>>::bytes_of(n, basek, k, rows, digits, rank_in, rank_out)
224 }
225}
226
227impl<D: Data> Infos for GLWESwitchingKey<D> {
228 type Inner = MatZnx<D>;
229
230 fn inner(&self) -> &Self::Inner {
231 self.key.inner()
232 }
233
234 fn basek(&self) -> usize {
235 self.key.basek()
236 }
237
238 fn k(&self) -> usize {
239 self.key.k()
240 }
241}
242
243impl<D: Data> GLWESwitchingKey<D> {
244 pub fn rank(&self) -> usize {
245 self.key.data.cols_out() - 1
246 }
247
248 pub fn rank_in(&self) -> usize {
249 self.key.data.cols_in()
250 }
251
252 pub fn rank_out(&self) -> usize {
253 self.key.data.cols_out() - 1
254 }
255
256 pub fn digits(&self) -> usize {
257 self.key.digits()
258 }
259
260 pub fn sk_degree_in(&self) -> usize {
261 self.sk_in_n
262 }
263
264 pub fn sk_degree_out(&self) -> usize {
265 self.sk_out_n
266 }
267}
268
269impl<D: DataRef> GLWESwitchingKey<D> {
270 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
271 self.key.at(row, col)
272 }
273}
274
275impl<D: DataMut> GLWESwitchingKey<D> {
276 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
277 self.key.at_mut(row, col)
278 }
279}
280
281impl<D: DataMut> ReaderFrom for GLWESwitchingKey<D> {
282 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
283 self.sk_in_n = reader.read_u64::<LittleEndian>()? as usize;
284 self.sk_out_n = reader.read_u64::<LittleEndian>()? as usize;
285 self.key.read_from(reader)
286 }
287}
288
289impl<D: DataRef> WriterTo for GLWESwitchingKey<D> {
290 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
291 writer.write_u64::<LittleEndian>(self.sk_in_n as u64)?;
292 writer.write_u64::<LittleEndian>(self.sk_out_n as u64)?;
293 self.key.write_to(writer)
294 }
295}
296
297#[derive(PartialEq, Eq, Clone)]
298pub struct AutomorphismKey<D: Data> {
299 pub(crate) key: GLWESwitchingKey<D>,
300 pub(crate) p: i64,
301}
302
303impl<D: DataRef> fmt::Debug for AutomorphismKey<D> {
304 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305 write!(f, "{}", self)
306 }
307}
308
309impl<D: DataMut> FillUniform for AutomorphismKey<D> {
310 fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
311 self.key.fill_uniform(source);
312 }
313}
314
315impl<D: DataMut> Reset for AutomorphismKey<D>
316where
317 MatZnx<D>: Reset,
318{
319 fn reset(&mut self) {
320 self.key.reset();
321 self.p = 0;
322 }
323}
324
325impl<D: DataRef> fmt::Display for AutomorphismKey<D> {
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327 write!(f, "(AutomorphismKey: p={}) {}", self.p, self.key)
328 }
329}
330
331impl AutomorphismKey<Vec<u8>> {
332 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
333 AutomorphismKey {
334 key: GLWESwitchingKey::alloc(n, basek, k, rows, digits, rank, rank),
335 p: 0,
336 }
337 }
338
339 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
340 GLWESwitchingKey::bytes_of(n, basek, k, rows, digits, rank, rank)
341 }
342}
343
344impl<D: Data> Infos for AutomorphismKey<D> {
345 type Inner = MatZnx<D>;
346
347 fn inner(&self) -> &Self::Inner {
348 &self.key.inner()
349 }
350
351 fn basek(&self) -> usize {
352 self.key.basek()
353 }
354
355 fn k(&self) -> usize {
356 self.key.k()
357 }
358}
359
360impl<D: Data> AutomorphismKey<D> {
361 pub fn p(&self) -> i64 {
362 self.p
363 }
364
365 pub fn digits(&self) -> usize {
366 self.key.digits()
367 }
368
369 pub fn rank(&self) -> usize {
370 self.key.rank()
371 }
372
373 pub fn rank_in(&self) -> usize {
374 self.key.rank_in()
375 }
376
377 pub fn rank_out(&self) -> usize {
378 self.key.rank_out()
379 }
380}
381
382impl<D: DataRef> AutomorphismKey<D> {
383 pub fn at(&self, row: usize, col: usize) -> GLWECiphertext<&[u8]> {
384 self.key.at(row, col)
385 }
386}
387
388impl<D: DataMut> AutomorphismKey<D> {
389 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertext<&mut [u8]> {
390 self.key.at_mut(row, col)
391 }
392}
393
394impl<D: DataMut> ReaderFrom for AutomorphismKey<D> {
395 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
396 self.p = reader.read_u64::<LittleEndian>()? as i64;
397 self.key.read_from(reader)
398 }
399}
400
401impl<D: DataRef> WriterTo for AutomorphismKey<D> {
402 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
403 writer.write_u64::<LittleEndian>(self.p as u64)?;
404 self.key.write_to(writer)
405 }
406}
407
408#[derive(PartialEq, Eq, Clone)]
409pub struct GLWETensorKey<D: Data> {
410 pub(crate) keys: Vec<GLWESwitchingKey<D>>,
411}
412
413impl<D: DataRef> fmt::Debug for GLWETensorKey<D> {
414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415 write!(f, "{}", self)
416 }
417}
418
419impl<D: DataMut> FillUniform for GLWETensorKey<D> {
420 fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
421 self.keys
422 .iter_mut()
423 .for_each(|key: &mut GLWESwitchingKey<D>| key.fill_uniform(source))
424 }
425}
426
427impl<D: DataMut> Reset for GLWETensorKey<D>
428where
429 MatZnx<D>: Reset,
430{
431 fn reset(&mut self) {
432 self.keys
433 .iter_mut()
434 .for_each(|key: &mut GLWESwitchingKey<D>| key.reset())
435 }
436}
437
438impl<D: DataRef> fmt::Display for GLWETensorKey<D> {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 writeln!(f, "(GLWETensorKey)",)?;
441 for (i, key) in self.keys.iter().enumerate() {
442 write!(f, "{}: {}", i, key)?;
443 }
444 Ok(())
445 }
446}
447
448impl GLWETensorKey<Vec<u8>> {
449 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self {
450 let mut keys: Vec<GLWESwitchingKey<Vec<u8>>> = Vec::new();
451 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
452 (0..pairs).for_each(|_| {
453 keys.push(GLWESwitchingKey::alloc(n, basek, k, rows, digits, 1, rank));
454 });
455 Self { keys: keys }
456 }
457
458 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize {
459 let pairs: usize = (((rank + 1) * rank) >> 1).max(1);
460 pairs * GLWESwitchingKey::<Vec<u8>>::bytes_of(n, basek, k, rows, digits, 1, rank)
461 }
462}
463
464impl<D: Data> Infos for GLWETensorKey<D> {
465 type Inner = MatZnx<D>;
466
467 fn inner(&self) -> &Self::Inner {
468 &self.keys[0].inner()
469 }
470
471 fn basek(&self) -> usize {
472 self.keys[0].basek()
473 }
474
475 fn k(&self) -> usize {
476 self.keys[0].k()
477 }
478}
479
480impl<D: Data> GLWETensorKey<D> {
481 pub fn rank(&self) -> usize {
482 self.keys[0].rank()
483 }
484
485 pub fn rank_in(&self) -> usize {
486 self.keys[0].rank_in()
487 }
488
489 pub fn rank_out(&self) -> usize {
490 self.keys[0].rank_out()
491 }
492
493 pub fn digits(&self) -> usize {
494 self.keys[0].digits()
495 }
496}
497
498impl<D: DataMut> GLWETensorKey<D> {
499 // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j])
500 pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKey<D> {
501 if i > j {
502 std::mem::swap(&mut i, &mut j);
503 };
504 let rank: usize = self.rank();
505 &mut self.keys[i * rank + j - (i * (i + 1) / 2)]
506 }
507}
508
509impl<D: DataRef> GLWETensorKey<D> {
510 // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j])
511 pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKey<D> {
512 if i > j {
513 std::mem::swap(&mut i, &mut j);
514 };
515 let rank: usize = self.rank();
516 &self.keys[i * rank + j - (i * (i + 1) / 2)]
517 }
518}
519
520impl<D: DataMut> ReaderFrom for GLWETensorKey<D> {
521 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
522 let len: usize = reader.read_u64::<LittleEndian>()? as usize;
523 if self.keys.len() != len {
524 return Err(std::io::Error::new(
525 std::io::ErrorKind::InvalidData,
526 format!("self.keys.len()={} != read len={}", self.keys.len(), len),
527 ));
528 }
529 for key in &mut self.keys {
530 key.read_from(reader)?;
531 }
532 Ok(())
533 }
534}
535
536impl<D: DataRef> WriterTo for GLWETensorKey<D> {
537 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
538 writer.write_u64::<LittleEndian>(self.keys.len() as u64)?;
539 for key in &self.keys {
540 key.write_to(writer)?;
541 }
542 Ok(())
543 }
544}