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