poulpy/core/src/layouts/compressed/gglwe_ct.rs
core/src/layouts/compressed/gglwe_ct.rsRaw
1use backend::hal::{
2 api::{FillUniform, Reset, VecZnxCopy, VecZnxFillUniform},
3 layouts::{Backend, Data, DataMut, DataRef, MatZnx, Module, ReaderFrom, WriterTo},
4};
5
6use crate::layouts::{GGLWECiphertext, Infos, compressed::GLWECiphertextCompressed};
7use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
8use std::fmt;
9
10use crate::trait_families::Decompress;
11
12#[derive(PartialEq, Eq, Clone)]
13pub struct GGLWECiphertextCompressed<D: Data> {
14 pub(crate) data: MatZnx<D>,
15 pub(crate) basek: usize,
16 pub(crate) k: usize,
17 pub(crate) rank_out: usize,
18 pub(crate) digits: usize,
19 pub(crate) seed: Vec<[u8; 32]>,
20}
21
22impl<D: DataRef> fmt::Debug for GGLWECiphertextCompressed<D> {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 write!(f, "{}", self)
25 }
26}
27
28impl<D: DataMut> FillUniform for GGLWECiphertextCompressed<D> {
29 fn fill_uniform(&mut self, source: &mut sampling::source::Source) {
30 self.data.fill_uniform(source);
31 }
32}
33
34impl<D: DataMut> Reset for GGLWECiphertextCompressed<D>
35where
36 MatZnx<D>: Reset,
37{
38 fn reset(&mut self) {
39 self.data.reset();
40 self.basek = 0;
41 self.k = 0;
42 self.digits = 0;
43 self.rank_out = 0;
44 self.seed = Vec::new();
45 }
46}
47
48impl<D: DataRef> fmt::Display for GGLWECiphertextCompressed<D> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(
51 f,
52 "(GGLWECiphertextCompressed: basek={} k={} digits={}) {}",
53 self.basek, self.k, self.digits, self.data
54 )
55 }
56}
57
58impl GGLWECiphertextCompressed<Vec<u8>> {
59 pub fn alloc(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
60 let size: usize = k.div_ceil(basek);
61 debug_assert!(
62 size > digits,
63 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
64 size,
65 digits
66 );
67
68 assert!(
69 rows * digits <= size,
70 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
71 rows,
72 digits,
73 size
74 );
75
76 Self {
77 data: MatZnx::alloc(n, rows, rank_in, 1, size),
78 basek: basek,
79 k,
80 rank_out,
81 digits,
82 seed: vec![[0u8; 32]; rows * rank_in],
83 }
84 }
85
86 pub fn bytes_of(n: usize, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize) -> usize {
87 let size: usize = k.div_ceil(basek);
88 debug_assert!(
89 size > digits,
90 "invalid gglwe: ceil(k/basek): {} <= digits: {}",
91 size,
92 digits
93 );
94
95 assert!(
96 rows * digits <= size,
97 "invalid gglwe: rows: {} * digits:{} > ceil(k/basek): {}",
98 rows,
99 digits,
100 size
101 );
102
103 MatZnx::alloc_bytes(n, rows, rank_in, 1, rows)
104 }
105}
106
107impl<D: Data> Infos for GGLWECiphertextCompressed<D> {
108 type Inner = MatZnx<D>;
109
110 fn inner(&self) -> &Self::Inner {
111 &self.data
112 }
113
114 fn basek(&self) -> usize {
115 self.basek
116 }
117
118 fn k(&self) -> usize {
119 self.k
120 }
121}
122
123impl<D: Data> GGLWECiphertextCompressed<D> {
124 pub fn rank(&self) -> usize {
125 self.rank_out
126 }
127
128 pub fn digits(&self) -> usize {
129 self.digits
130 }
131
132 pub fn rank_in(&self) -> usize {
133 self.data.cols_in()
134 }
135
136 pub fn rank_out(&self) -> usize {
137 self.rank_out
138 }
139}
140
141impl<D: DataRef> GGLWECiphertextCompressed<D> {
142 pub(crate) fn at(&self, row: usize, col: usize) -> GLWECiphertextCompressed<&[u8]> {
143 GLWECiphertextCompressed {
144 data: self.data.at(row, col),
145 basek: self.basek,
146 k: self.k,
147 rank: self.rank_out,
148 seed: self.seed[self.rank_in() * row + col],
149 }
150 }
151}
152
153impl<D: DataMut> GGLWECiphertextCompressed<D> {
154 pub(crate) fn at_mut(&mut self, row: usize, col: usize) -> GLWECiphertextCompressed<&mut [u8]> {
155 let rank_in: usize = self.rank_in();
156 GLWECiphertextCompressed {
157 data: self.data.at_mut(row, col),
158 basek: self.basek,
159 k: self.k,
160 rank: self.rank_out,
161 seed: self.seed[rank_in * row + col], // Warning: value is copied and not borrow mut
162 }
163 }
164}
165
166impl<D: DataMut> ReaderFrom for GGLWECiphertextCompressed<D> {
167 fn read_from<R: std::io::Read>(&mut self, reader: &mut R) -> std::io::Result<()> {
168 self.k = reader.read_u64::<LittleEndian>()? as usize;
169 self.basek = reader.read_u64::<LittleEndian>()? as usize;
170 self.digits = reader.read_u64::<LittleEndian>()? as usize;
171 self.rank_out = reader.read_u64::<LittleEndian>()? as usize;
172 let seed_len = reader.read_u64::<LittleEndian>()? as usize;
173 self.seed = vec![[0u8; 32]; seed_len];
174 for s in &mut self.seed {
175 reader.read_exact(s)?;
176 }
177 self.data.read_from(reader)
178 }
179}
180
181impl<D: DataRef> WriterTo for GGLWECiphertextCompressed<D> {
182 fn write_to<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
183 writer.write_u64::<LittleEndian>(self.k as u64)?;
184 writer.write_u64::<LittleEndian>(self.basek as u64)?;
185 writer.write_u64::<LittleEndian>(self.digits as u64)?;
186 writer.write_u64::<LittleEndian>(self.rank_out as u64)?;
187 writer.write_u64::<LittleEndian>(self.seed.len() as u64)?;
188 for s in &self.seed {
189 writer.write_all(s)?;
190 }
191 self.data.write_to(writer)
192 }
193}
194
195impl<D: DataMut, B: Backend, DR: DataRef> Decompress<B, GGLWECiphertextCompressed<DR>> for GGLWECiphertext<D> {
196 fn decompress(&mut self, module: &Module<B>, other: &GGLWECiphertextCompressed<DR>)
197 where
198 Module<B>: VecZnxFillUniform + VecZnxCopy,
199 {
200 #[cfg(debug_assertions)]
201 {
202 use backend::hal::api::ZnxInfos;
203
204 assert_eq!(
205 self.n(),
206 other.data.n(),
207 "invalid receiver: self.n()={} != other.n()={}",
208 self.n(),
209 other.data.n()
210 );
211 assert_eq!(
212 self.size(),
213 other.size(),
214 "invalid receiver: self.size()={} != other.size()={}",
215 self.size(),
216 other.size()
217 );
218 assert_eq!(
219 self.rank_in(),
220 other.rank_in(),
221 "invalid receiver: self.rank_in()={} != other.rank_in()={}",
222 self.rank_in(),
223 other.rank_in()
224 );
225 assert_eq!(
226 self.rank_out(),
227 other.rank_out(),
228 "invalid receiver: self.rank_out()={} != other.rank_out()={}",
229 self.rank_out(),
230 other.rank_out()
231 );
232
233 assert_eq!(
234 self.rows(),
235 other.rows(),
236 "invalid receiver: self.rows()={} != other.rows()={}",
237 self.rows(),
238 other.rows()
239 );
240 }
241
242 let rank_in: usize = self.rank_in();
243 let rows: usize = self.rows();
244
245 (0..rank_in).for_each(|col_i| {
246 (0..rows).for_each(|row_i| {
247 self.at_mut(row_i, col_i)
248 .decompress(module, &other.at(row_i, col_i));
249 });
250 });
251 }
252}