poulpy/rlwe/src/elem_grlwe.rs
rlwe/src/elem_grlwe.rsRaw
1use base2k::{
2 Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, MatZnxDftScratch, MatZnxDftToMut, MatZnxDftToRef, Module, ScalarZnx,
3 ScalarZnxDft, ScalarZnxDftToRef, ScalarZnxToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBig, VecZnxBigOps, VecZnxBigScratch,
4 VecZnxDft, VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos,
5 ZnxZero,
6};
7use sampling::source::Source;
8
9use crate::{
10 elem::Infos,
11 elem_rlwe::{RLWECt, RLWECtDft, RLWEPt},
12 keys::SecretKeyDft,
13 utils::derive_size,
14};
15
16pub struct GRLWECt<C, B: Backend> {
17 pub data: MatZnxDft<C, B>,
18 pub log_base2k: usize,
19 pub log_k: usize,
20}
21
22impl<B: Backend> GRLWECt<Vec<u8>, B> {
23 pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize, rows: usize) -> Self {
24 Self {
25 data: module.new_mat_znx_dft(rows, 1, 2, derive_size(log_base2k, log_k)),
26 log_base2k: log_base2k,
27 log_k: log_k,
28 }
29 }
30}
31
32impl<C> GRLWECt<C, FFT64>
33where
34 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64>,
35{
36 pub fn get_row<R>(&self, module: &Module<FFT64>, row_i: usize, res: &mut RLWECtDft<R, FFT64>)
37 where
38 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64>,
39 {
40 module.vmp_extract_row(res, self, row_i, 0);
41 }
42}
43
44impl<C> GRLWECt<C, FFT64>
45where
46 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
47{
48 pub fn set_row<R>(&mut self, module: &Module<FFT64>, row_i: usize, a: &RLWECtDft<R, FFT64>)
49 where
50 VecZnxDft<R, FFT64>: VecZnxDftToRef<FFT64>,
51 {
52 module.vmp_prepare_row(self, row_i, 0, a);
53 }
54}
55
56impl<T, B: Backend> Infos for GRLWECt<T, B> {
57 type Inner = MatZnxDft<T, B>;
58
59 fn inner(&self) -> &Self::Inner {
60 &self.data
61 }
62
63 fn log_base2k(&self) -> usize {
64 self.log_base2k
65 }
66
67 fn log_k(&self) -> usize {
68 self.log_k
69 }
70}
71
72impl<C, B: Backend> MatZnxDftToMut<B> for GRLWECt<C, B>
73where
74 MatZnxDft<C, B>: MatZnxDftToMut<B>,
75{
76 fn to_mut(&mut self) -> MatZnxDft<&mut [u8], B> {
77 self.data.to_mut()
78 }
79}
80
81impl<C, B: Backend> MatZnxDftToRef<B> for GRLWECt<C, B>
82where
83 MatZnxDft<C, B>: MatZnxDftToRef<B>,
84{
85 fn to_ref(&self) -> MatZnxDft<&[u8], B> {
86 self.data.to_ref()
87 }
88}
89
90impl GRLWECt<Vec<u8>, FFT64> {
91 pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
92 RLWECt::encrypt_sk_scratch_space(module, size)
93 + module.bytes_of_vec_znx(2, size)
94 + module.bytes_of_vec_znx(1, size)
95 + module.bytes_of_vec_znx_dft(2, size)
96 }
97
98 pub fn mul_rlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
99 module.bytes_of_vec_znx_dft(2, grlwe_size)
100 + (module.vec_znx_big_normalize_tmp_bytes()
101 | (module.vmp_apply_tmp_bytes(res_size, a_size, a_size, 1, 2, grlwe_size)
102 + module.bytes_of_vec_znx_dft(1, a_size)))
103 }
104
105 pub fn mul_rlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, grlwe_size: usize) -> usize {
106 Self::mul_rlwe_scratch_space(module, res_size, res_size, grlwe_size)
107 }
108
109 pub fn mul_rlwe_dft_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
110 (Self::mul_rlwe_scratch_space(module, res_size, a_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
111 + module.bytes_of_vec_znx(2, a_size)
112 + module.bytes_of_vec_znx(2, res_size)
113 }
114
115 pub fn mul_rlwe_dft_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, grlwe_size: usize) -> usize {
116 (Self::mul_rlwe_inplace_scratch_space(module, res_size, grlwe_size) | module.vec_znx_idft_tmp_bytes())
117 + module.bytes_of_vec_znx(2, res_size)
118 }
119
120 pub fn mul_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
121 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
122 }
123
124 pub fn mul_grlwe_inplace_scratch_space(module: &Module<FFT64>, res_size: usize, a_size: usize, grlwe_size: usize) -> usize {
125 Self::mul_rlwe_dft_inplace_scratch_space(module, res_size, grlwe_size) + module.bytes_of_vec_znx_dft(2, a_size)
126 }
127}
128
129pub fn encrypt_grlwe_sk<C, P, S>(
130 module: &Module<FFT64>,
131 ct: &mut GRLWECt<C, FFT64>,
132 pt: &ScalarZnx<P>,
133 sk_dft: &SecretKeyDft<S, FFT64>,
134 source_xa: &mut Source,
135 source_xe: &mut Source,
136 sigma: f64,
137 bound: f64,
138 scratch: &mut Scratch,
139) where
140 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
141 ScalarZnx<P>: ScalarZnxToRef,
142 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
143{
144 let rows: usize = ct.rows();
145 let size: usize = ct.size();
146 let log_base2k: usize = ct.log_base2k();
147
148 let (tmp_znx_pt, scrach_1) = scratch.tmp_vec_znx(module, 1, size);
149 let (tmp_znx_ct, scrach_2) = scrach_1.tmp_vec_znx(module, 2, size);
150 let (mut vec_znx_dft_ct, scratch_3) = scrach_2.tmp_vec_znx_dft(module, 2, size);
151
152 let mut vec_znx_pt: RLWEPt<&mut [u8]> = RLWEPt {
153 data: tmp_znx_pt,
154 log_base2k: log_base2k,
155 log_k: ct.log_k(),
156 };
157
158 let mut vec_znx_ct: RLWECt<&mut [u8]> = RLWECt {
159 data: tmp_znx_ct,
160 log_base2k: log_base2k,
161 log_k: ct.log_k(),
162 };
163
164 (0..rows).for_each(|row_i| {
165 // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
166 module.vec_znx_add_scalar_inplace(&mut vec_znx_pt, 0, row_i, pt, 0);
167 module.vec_znx_normalize_inplace(log_base2k, &mut vec_znx_pt, 0, scratch_3);
168
169 // rlwe encrypt of vec_znx_pt into vec_znx_ct
170 vec_znx_ct.encrypt_sk(
171 module,
172 Some(&vec_znx_pt),
173 sk_dft,
174 source_xa,
175 source_xe,
176 sigma,
177 bound,
178 scratch_3,
179 );
180
181 vec_znx_pt.data.zero(); // zeroes for next iteration
182
183 // Switch vec_znx_ct into DFT domain
184 module.vec_znx_dft(&mut vec_znx_dft_ct, 0, &vec_znx_ct, 0);
185 module.vec_znx_dft(&mut vec_znx_dft_ct, 1, &vec_znx_ct, 1);
186
187 // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
188 module.vmp_prepare_row(ct, row_i, 0, &vec_znx_dft_ct);
189 });
190}
191
192impl<C> GRLWECt<C, FFT64> {
193 pub fn encrypt_sk<P, S>(
194 &mut self,
195 module: &Module<FFT64>,
196 pt: &ScalarZnx<P>,
197 sk_dft: &SecretKeyDft<S, FFT64>,
198 source_xa: &mut Source,
199 source_xe: &mut Source,
200 sigma: f64,
201 bound: f64,
202 scratch: &mut Scratch,
203 ) where
204 MatZnxDft<C, FFT64>: MatZnxDftToMut<FFT64>,
205 ScalarZnx<P>: ScalarZnxToRef,
206 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
207 {
208 encrypt_grlwe_sk(
209 module, self, pt, sk_dft, source_xa, source_xe, sigma, bound, scratch,
210 )
211 }
212
213 pub fn mul_rlwe<R, A>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, a: &RLWECt<A>, scratch: &mut Scratch)
214 where
215 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
216 VecZnx<R>: VecZnxToMut,
217 VecZnx<A>: VecZnxToRef,
218 {
219 let log_base2k: usize = self.log_base2k();
220
221 #[cfg(debug_assertions)]
222 {
223 assert_eq!(res.log_base2k(), log_base2k);
224 assert_eq!(a.log_base2k(), log_base2k);
225 assert_eq!(self.n(), module.n());
226 assert_eq!(res.n(), module.n());
227 assert_eq!(a.n(), module.n());
228 }
229
230 let (mut res_dft, scratch1) = scratch.tmp_vec_znx_dft(module, 2, self.size()); // Todo optimise
231
232 {
233 let (mut a1_dft, scratch2) = scratch1.tmp_vec_znx_dft(module, 1, a.size());
234 module.vec_znx_dft(&mut a1_dft, 0, a, 1);
235 module.vmp_apply(&mut res_dft, &a1_dft, self, scratch2);
236 }
237
238 let mut res_big: VecZnxBig<&mut [u8], FFT64> = module.vec_znx_idft_consume(res_dft);
239
240 module.vec_znx_big_add_small_inplace(&mut res_big, 0, a, 0);
241
242 module.vec_znx_big_normalize(log_base2k, res, 0, &res_big, 0, scratch1);
243 module.vec_znx_big_normalize(log_base2k, res, 1, &res_big, 1, scratch1);
244 }
245
246 pub fn mul_rlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch)
247 where
248 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
249 VecZnx<R>: VecZnxToMut + VecZnxToRef,
250 {
251 unsafe {
252 let res_ptr: *mut RLWECt<R> = res as *mut RLWECt<R>; // This is ok because [Self::mul_rlwe] only updates res at the end.
253 self.mul_rlwe(&module, &mut *res_ptr, &*res_ptr, scratch);
254 }
255 }
256
257 pub fn mul_rlwe_dft<R, A>(
258 &self,
259 module: &Module<FFT64>,
260 res: &mut RLWECtDft<R, FFT64>,
261 a: &RLWECtDft<A, FFT64>,
262 scratch: &mut Scratch,
263 ) where
264 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
265 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
266 VecZnxDft<A, FFT64>: VecZnxDftToRef<FFT64> + ZnxInfos,
267 {
268 let log_base2k: usize = self.log_base2k();
269
270 #[cfg(debug_assertions)]
271 {
272 assert_eq!(res.log_base2k(), log_base2k);
273 assert_eq!(self.n(), module.n());
274 assert_eq!(res.n(), module.n());
275 }
276
277 let (a_data, scratch_1) = scratch.tmp_vec_znx(module, 2, a.size());
278
279 let mut a_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
280 data: a_data,
281 log_base2k: a.log_base2k(),
282 log_k: a.log_k(),
283 };
284
285 a.idft(module, &mut a_idft, scratch_1);
286
287 let (res_data, scratch_2) = scratch_1.tmp_vec_znx(module, 2, res.size());
288
289 let mut res_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
290 data: res_data,
291 log_base2k: res.log_base2k(),
292 log_k: res.log_k(),
293 };
294
295 self.mul_rlwe(module, &mut res_idft, &a_idft, scratch_2);
296
297 module.vec_znx_dft(res, 0, &res_idft, 0);
298 module.vec_znx_dft(res, 1, &res_idft, 1);
299 }
300
301 pub fn mul_rlwe_dft_inplace<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>, scratch: &mut Scratch)
302 where
303 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
304 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64> + ZnxInfos,
305 {
306 let log_base2k: usize = self.log_base2k();
307
308 #[cfg(debug_assertions)]
309 {
310 assert_eq!(res.log_base2k(), log_base2k);
311 assert_eq!(self.n(), module.n());
312 assert_eq!(res.n(), module.n());
313 }
314
315 let (res_data, scratch_1) = scratch.tmp_vec_znx(module, 2, res.size());
316
317 let mut res_idft: RLWECt<&mut [u8]> = RLWECt::<&mut [u8]> {
318 data: res_data,
319 log_base2k: res.log_base2k(),
320 log_k: res.log_k(),
321 };
322
323 res.idft(module, &mut res_idft, scratch_1);
324
325 self.mul_rlwe_inplace(module, &mut res_idft, scratch_1);
326
327 module.vec_znx_dft(res, 0, &res_idft, 0);
328 module.vec_znx_dft(res, 1, &res_idft, 1);
329 }
330
331 pub fn mul_grlwe<R, A>(
332 &self,
333 module: &Module<FFT64>,
334 res: &mut GRLWECt<R, FFT64>,
335 a: &GRLWECt<A, FFT64>,
336 scratch: &mut Scratch,
337 ) where
338 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
339 MatZnxDft<R, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64> + ZnxInfos,
340 MatZnxDft<A, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
341 {
342 let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, a.size());
343
344 let mut tmp_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> {
345 data: tmp_row_data,
346 log_base2k: a.log_base2k(),
347 log_k: a.log_k(),
348 };
349
350 let min_rows: usize = res.rows().min(a.rows());
351
352 (0..min_rows).for_each(|row_i| {
353 a.get_row(module, row_i, &mut tmp_row);
354 self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1);
355 res.set_row(module, row_i, &tmp_row);
356 });
357
358 tmp_row.data.zero();
359
360 (min_rows..res.rows()).for_each(|row_i| {
361 res.set_row(module, row_i, &tmp_row);
362 })
363 }
364
365 pub fn mul_grlwe_inplace<R>(&self, module: &Module<FFT64>, res: &mut GRLWECt<R, FFT64>, scratch: &mut Scratch)
366 where
367 MatZnxDft<C, FFT64>: MatZnxDftToRef<FFT64> + ZnxInfos,
368 MatZnxDft<R, FFT64>: MatZnxDftToMut<FFT64> + MatZnxDftToRef<FFT64> + ZnxInfos,
369 {
370 let (tmp_row_data, scratch1) = scratch.tmp_vec_znx_dft(module, 2, res.size());
371
372 let mut tmp_row: RLWECtDft<&mut [u8], FFT64> = RLWECtDft::<&mut [u8], FFT64> {
373 data: tmp_row_data,
374 log_base2k: res.log_base2k(),
375 log_k: res.log_k(),
376 };
377
378 (0..res.rows()).for_each(|row_i| {
379 res.get_row(module, row_i, &mut tmp_row);
380 self.mul_rlwe_dft_inplace(module, &mut tmp_row, scratch1);
381 res.set_row(module, row_i, &tmp_row);
382 });
383 }
384}