poulpy/core/src/ggsw/layout_compressed.rs
core/src/ggsw/layout_compressed.rsRaw
1use backend::hal::{
2 api::{MatZnxAlloc, MatZnxAllocBytes, VecZnxCopy, VecZnxFillUniform},
3 layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
4};
5
6use crate::{Decompress, GGSWCiphertext, GLWECiphertextCompressed, Infos};
7
8#[derive(PartialEq, Eq)]
9pub struct GGSWCiphertextCompressed<D: Data> {
10 pub(crate) data: MatZnx<D>,
11 pub(crate) basek: usize,
12 pub(crate) k: usize,
13 pub(crate) digits: usize,
14 pub(crate) rank: usize,
15 pub(crate) seed: Vec<[u8; 32]>,
16}
17
18impl GGSWCiphertextCompressed<Vec<u8>> {
19 pub fn alloc<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> Self
20 where
21 Module<B>: MatZnxAlloc,
22 {
23 let size: usize = k.div_ceil(basek);
24 debug_assert!(digits > 0, "invalid ggsw: `digits` == 0");
25
26 debug_assert!(
27 size > digits,
28 "invalid ggsw: ceil(k/basek): {} <= digits: {}",
29 size,
30 digits
31 );
32
33 assert!(
34 rows * digits <= size,
35 "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
36 rows,
37 digits,
38 size
39 );
40
41 Self {
42 data: module.mat_znx_alloc(rows, rank + 1, 1, k.div_ceil(basek)),
43 basek,
44 k: k,
45 digits,
46 rank,
47 seed: vec![[0u8; 32]; rows * (rank + 1)],
48 }
49 }
50
51 pub fn bytes_of<B: Backend>(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank: usize) -> usize
52 where
53 Module<B>: MatZnxAllocBytes,
54 {
55 let size: usize = k.div_ceil(basek);
56 debug_assert!(
57 size > digits,
58 "invalid ggsw: ceil(k/basek): {} <= digits: {}",
59 size,
60 digits
61 );
62
63 assert!(
64 rows * digits <= size,
65 "invalid ggsw: rows: {} * digits:{} > ceil(k/basek): {}",
66 rows,
67 digits,
68 size
69 );
70
71 module.mat_znx_alloc_bytes(rows, rank + 1, 1, size)
72 }
73}
74
75impl<D: DataRef> GGSWCiphertextCompressed<D> {
76 pub fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
77 GLWECiphertextCompressed {
78 data: self.data.at(row, col),
79 basek: self.basek,
80 k: self.k,
81 rank: self.rank(),
82 seed: self.seed[row * (self.rank() + 1) + col],
83 }
84 }
85}
86
87impl<D: DataMut> GGSWCiphertextCompressed<D> {
88 pub fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
89 let rank: usize = self.rank();
90 GLWECiphertextCompressed {
91 data: self.data.at_mut(row, col),
92 basek: self.basek,
93 k: self.k,
94 rank: rank,
95 seed: self.seed[row * (rank + 1) + col],
96 }
97 }
98}
99
100impl<D: Data> Infos for GGSWCiphertextCompressed<D> {
101 type Inner = MatZnx<D>;
102
103 fn inner(&self) -> &Self::Inner {
104 &self.data
105 }
106
107 fn basek(&self) -> usize {
108 self.basek
109 }
110
111 fn k(&self) -> usize {
112 self.k
113 }
114}
115
116impl<D: Data> GGSWCiphertextCompressed<D> {
117 pub fn rank(&self) -> usize {
118 self.rank
119 }
120
121 pub fn digits(&self) -> usize {
122 self.digits
123 }
124}
125
126impl<D: DataMut> ReaderFrom for GGSWCiphertextCompressed<D> {
127 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
128 self.data.read_from(reader)
129 }
130}
131
132impl<D: DataRef> WriterTo for GGSWCiphertextCompressed<D> {
133 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
134 self.data.write_to(writer)
135 }
136}
137
138impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGSWCiphertextCompressed<DR>> for GGSWCiphertext<D> {
139 fn decompress(&mut self, module: &Module<B>, other: &GGSWCiphertextCompressed<DR>)
140 where
141 Module<B>: VecZnxFillUniform + VecZnxCopy,
142 {
143 #[cfg(debug_assertions)]
144 {
145 assert_eq!(self.rank(), other.rank())
146 }
147
148 let rows: usize = self.rows();
149 let rank: usize = self.rank();
150 (0..rows).for_each(|row_i| {
151 (0..rank + 1).for_each(|col_j| {
152 self.at_mut(row_i, col_j)
153 .decompress(module, &other.at(row_i, col_j));
154 });
155 });
156 }
157}