poulpy/core/src/rlwe.rs
core/src/rlwe.rsRaw
1use base2k::{
2 AddNormal, Backend, FFT64, FillUniform, MatZnxDft, MatZnxDftToRef, Module, ScalarZnxAlloc, ScalarZnxDft, ScalarZnxDftAlloc,
3 ScalarZnxDftOps, ScalarZnxDftToRef, Scratch, VecZnx, VecZnxAlloc, VecZnxBigAlloc, VecZnxBigOps, VecZnxBigScratch, VecZnxDft,
4 VecZnxDftAlloc, VecZnxDftOps, VecZnxDftToMut, VecZnxDftToRef, VecZnxOps, VecZnxToMut, VecZnxToRef, ZnxInfos,
5};
6use sampling::source::Source;
7
8use crate::{
9 elem::{Infos, MatRLWEProduct, MatRLWEProductScratchSpace, ProdInplace, ProdInplaceScratchSpace, ProdScratchSpace, Product},
10 grlwe::GRLWECt,
11 keys::{PublicKey, SecretDistribution, SecretKeyDft},
12 rgsw::RGSWCt,
13 utils::derive_size,
14};
15
16pub struct RLWECt<C> {
17 pub data: VecZnx<C>,
18 pub log_base2k: usize,
19 pub log_k: usize,
20}
21
22impl RLWECt<Vec<u8>> {
23 pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
24 Self {
25 data: module.new_vec_znx(2, derive_size(log_base2k, log_k)),
26 log_base2k: log_base2k,
27 log_k: log_k,
28 }
29 }
30}
31
32impl<T> Infos for RLWECt<T> {
33 type Inner = VecZnx<T>;
34
35 fn inner(&self) -> &Self::Inner {
36 &self.data
37 }
38
39 fn log_base2k(&self) -> usize {
40 self.log_base2k
41 }
42
43 fn log_k(&self) -> usize {
44 self.log_k
45 }
46}
47
48impl<C> VecZnxToMut for RLWECt<C>
49where
50 VecZnx<C>: VecZnxToMut,
51{
52 fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
53 self.data.to_mut()
54 }
55}
56
57impl<C> VecZnxToRef for RLWECt<C>
58where
59 VecZnx<C>: VecZnxToRef,
60{
61 fn to_ref(&self) -> VecZnx<&[u8]> {
62 self.data.to_ref()
63 }
64}
65
66impl<C> RLWECt<C>
67where
68 VecZnx<C>: VecZnxToRef,
69{
70 #[allow(dead_code)]
71 pub(crate) fn dft<R>(&self, module: &Module<FFT64>, res: &mut RLWECtDft<R, FFT64>)
72 where
73 VecZnxDft<R, FFT64>: VecZnxDftToMut<FFT64> + ZnxInfos,
74 {
75 #[cfg(debug_assertions)]
76 {
77 assert_eq!(self.cols(), 2);
78 assert_eq!(res.cols(), 2);
79 assert_eq!(self.log_base2k(), res.log_base2k())
80 }
81
82 module.vec_znx_dft(res, 0, self, 0);
83 module.vec_znx_dft(res, 1, self, 1);
84 }
85}
86
87impl ProdInplaceScratchSpace for RLWECt<Vec<u8>> {
88 fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
89 <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs)
90 }
91
92 fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
93 <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_inplace_scratch_space(module, lhs, rhs)
94 }
95}
96
97impl ProdScratchSpace for RLWECt<Vec<u8>> {
98 fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
99 <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs)
100 }
101
102 fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
103 <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_scratch_space(module, res_size, lhs, rhs)
104 }
105}
106
107impl<MUT, REF> ProdInplace<MUT, REF> for RLWECt<MUT>
108where
109 VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
110 MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
111{
112 fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
113 rhs.prod_with_rlwe_inplace(module, self, scratch);
114 }
115
116 fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
117 rhs.prod_with_rlwe_inplace(module, self, scratch);
118 }
119}
120
121impl<MUT, REF> Product<MUT, REF> for RLWECt<MUT>
122where
123 VecZnx<MUT>: VecZnxToMut + VecZnxToRef,
124 VecZnx<REF>: VecZnxToRef,
125 MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
126{
127 type Lhs = RLWECt<REF>;
128
129 fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
130 rhs.prod_with_rlwe(module, self, lhs, scratch);
131 }
132
133 fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
134 rhs.prod_with_rlwe(module, self, lhs, scratch);
135 }
136}
137
138impl RLWECt<Vec<u8>> {
139 pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
140 (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
141 }
142
143 pub fn encrypt_pk_scratch_space<B: Backend>(module: &Module<B>, pk_size: usize) -> usize {
144 ((module.bytes_of_vec_znx_dft(1, pk_size) + module.bytes_of_vec_znx_big(1, pk_size)) | module.bytes_of_scalar_znx(1))
145 + module.bytes_of_scalar_znx_dft(1)
146 + module.vec_znx_big_normalize_tmp_bytes()
147 }
148
149 pub fn decrypt_scratch_space<B: Backend>(module: &Module<B>, size: usize) -> usize {
150 (module.vec_znx_big_normalize_tmp_bytes() | module.bytes_of_vec_znx_dft(1, size)) + module.bytes_of_vec_znx_big(1, size)
151 }
152}
153
154pub fn encrypt_rlwe_sk<C, P, S>(
155 module: &Module<FFT64>,
156 ct: &mut RLWECt<C>,
157 pt: Option<(&RLWEPt<P>, usize)>,
158 sk_dft: &SecretKeyDft<S, FFT64>,
159 source_xa: &mut Source,
160 source_xe: &mut Source,
161 sigma: f64,
162 bound: f64,
163 scratch: &mut Scratch,
164) where
165 VecZnx<C>: VecZnxToMut + VecZnxToRef,
166 VecZnx<P>: VecZnxToRef,
167 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
168{
169 let log_base2k: usize = ct.log_base2k();
170 let log_k: usize = ct.log_k();
171 let size: usize = ct.size();
172
173 // c1 = a
174 ct.data.fill_uniform(log_base2k, 1, size, source_xa);
175
176 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
177
178 {
179 let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
180 module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
181
182 // c0_dft = DFT(a) * DFT(s)
183 module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
184
185 // c0_big = IDFT(c0_dft)
186 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
187 }
188
189 // c0_big = m - c0_big
190 if let Some((pt, col)) = pt {
191 match col {
192 0 => module.vec_znx_big_sub_small_b_inplace(&mut c0_big, 0, pt, 0),
193 1 => {
194 module.vec_znx_big_negate_inplace(&mut c0_big, 0);
195 module.vec_znx_add_inplace(ct, 1, pt, 0);
196 module.vec_znx_normalize_inplace(log_base2k, ct, 1, scratch_1);
197 }
198 _ => panic!("invalid target column: {}", col),
199 }
200 } else {
201 module.vec_znx_big_negate_inplace(&mut c0_big, 0);
202 }
203 // c0_big += e
204 c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
205
206 // c0 = norm(c0_big = -as + m + e)
207 module.vec_znx_big_normalize(log_base2k, ct, 0, &c0_big, 0, scratch_1);
208}
209
210pub fn decrypt_rlwe<P, C, S>(
211 module: &Module<FFT64>,
212 pt: &mut RLWEPt<P>,
213 ct: &RLWECt<C>,
214 sk_dft: &SecretKeyDft<S, FFT64>,
215 scratch: &mut Scratch,
216) where
217 VecZnx<P>: VecZnxToMut + VecZnxToRef,
218 VecZnx<C>: VecZnxToRef,
219 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
220{
221 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
222
223 {
224 let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
225 module.vec_znx_dft(&mut c0_dft, 0, ct, 1);
226
227 // c0_dft = DFT(a) * DFT(s)
228 module.svp_apply_inplace(&mut c0_dft, 0, sk_dft, 0);
229
230 // c0_big = IDFT(c0_dft)
231 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
232 }
233
234 // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
235 module.vec_znx_big_add_small_inplace(&mut c0_big, 0, ct, 0);
236
237 // pt = norm(BIG(m + e))
238 module.vec_znx_big_normalize(ct.log_base2k(), pt, 0, &mut c0_big, 0, scratch_1);
239
240 pt.log_base2k = ct.log_base2k();
241 pt.log_k = pt.log_k().min(ct.log_k());
242}
243
244impl<C> RLWECt<C> {
245 pub fn encrypt_sk<P, S>(
246 &mut self,
247 module: &Module<FFT64>,
248 pt: Option<&RLWEPt<P>>,
249 sk_dft: &SecretKeyDft<S, FFT64>,
250 source_xa: &mut Source,
251 source_xe: &mut Source,
252 sigma: f64,
253 bound: f64,
254 scratch: &mut Scratch,
255 ) where
256 VecZnx<C>: VecZnxToMut + VecZnxToRef,
257 VecZnx<P>: VecZnxToRef,
258 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
259 {
260 if let Some(pt) = pt {
261 encrypt_rlwe_sk(
262 module,
263 self,
264 Some((pt, 0)),
265 sk_dft,
266 source_xa,
267 source_xe,
268 sigma,
269 bound,
270 scratch,
271 )
272 } else {
273 encrypt_rlwe_sk::<C, P, S>(
274 module, self, None, sk_dft, source_xa, source_xe, sigma, bound, scratch,
275 )
276 }
277 }
278
279 pub fn decrypt<P, S>(
280 &self,
281 module: &Module<FFT64>,
282 pt: &mut RLWEPt<P>,
283 sk_dft: &SecretKeyDft<S, FFT64>,
284 scratch: &mut Scratch,
285 ) where
286 VecZnx<P>: VecZnxToMut + VecZnxToRef,
287 VecZnx<C>: VecZnxToRef,
288 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
289 {
290 decrypt_rlwe(module, pt, self, sk_dft, scratch);
291 }
292
293 pub fn encrypt_pk<P, S>(
294 &mut self,
295 module: &Module<FFT64>,
296 pt: Option<&RLWEPt<P>>,
297 pk: &PublicKey<S, FFT64>,
298 source_xu: &mut Source,
299 source_xe: &mut Source,
300 sigma: f64,
301 bound: f64,
302 scratch: &mut Scratch,
303 ) where
304 VecZnx<C>: VecZnxToMut + VecZnxToRef,
305 VecZnx<P>: VecZnxToRef,
306 VecZnxDft<S, FFT64>: VecZnxDftToRef<FFT64>,
307 {
308 encrypt_rlwe_pk(
309 module, self, pt, pk, source_xu, source_xe, sigma, bound, scratch,
310 )
311 }
312}
313
314pub(crate) fn encrypt_rlwe_pk<C, P, S>(
315 module: &Module<FFT64>,
316 ct: &mut RLWECt<C>,
317 pt: Option<&RLWEPt<P>>,
318 pk: &PublicKey<S, FFT64>,
319 source_xu: &mut Source,
320 source_xe: &mut Source,
321 sigma: f64,
322 bound: f64,
323 scratch: &mut Scratch,
324) where
325 VecZnx<C>: VecZnxToMut + VecZnxToRef,
326 VecZnx<P>: VecZnxToRef,
327 VecZnxDft<S, FFT64>: VecZnxDftToRef<FFT64>,
328{
329 #[cfg(debug_assertions)]
330 {
331 assert_eq!(ct.log_base2k(), pk.log_base2k());
332 assert_eq!(ct.n(), module.n());
333 assert_eq!(pk.n(), module.n());
334 if let Some(pt) = pt {
335 assert_eq!(pt.log_base2k(), pk.log_base2k());
336 assert_eq!(pt.n(), module.n());
337 }
338 }
339
340 let log_base2k: usize = pk.log_base2k();
341 let size_pk: usize = pk.size();
342
343 // Generates u according to the underlying secret distribution.
344 let (mut u_dft, scratch_1) = scratch.tmp_scalar_znx_dft(module, 1);
345
346 {
347 let (mut u, _) = scratch_1.tmp_scalar_znx(module, 1);
348 match pk.dist {
349 SecretDistribution::NONE => panic!(
350 "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through Self::generate"
351 ),
352 SecretDistribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu),
353 SecretDistribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu),
354 SecretDistribution::ZERO => {}
355 }
356
357 module.svp_prepare(&mut u_dft, 0, &u, 0);
358 }
359
360 let (mut tmp_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, size_pk); // TODO optimize size (e.g. when encrypting at low homomorphic capacity)
361 let (mut tmp_dft, scratch_3) = scratch_2.tmp_vec_znx_dft(module, 1, size_pk); // TODO optimize size (e.g. when encrypting at low homomorphic capacity)
362
363 // ct[0] = pk[0] * u + m + e0
364 module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 0);
365 module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
366 tmp_big.add_normal(log_base2k, 0, pk.log_k(), source_xe, sigma, bound);
367
368 if let Some(pt) = pt {
369 module.vec_znx_big_add_small_inplace(&mut tmp_big, 0, pt, 0);
370 }
371
372 module.vec_znx_big_normalize(log_base2k, ct, 0, &tmp_big, 0, scratch_3);
373
374 // ct[1] = pk[1] * u + e1
375 module.svp_apply(&mut tmp_dft, 0, &u_dft, 0, pk, 1);
376 module.vec_znx_idft_tmp_a(&mut tmp_big, 0, &mut tmp_dft, 0);
377 tmp_big.add_normal(log_base2k, 0, pk.log_k(), source_xe, sigma, bound);
378 module.vec_znx_big_normalize(log_base2k, ct, 1, &tmp_big, 0, scratch_3);
379}
380
381pub struct RLWEPt<C> {
382 pub data: VecZnx<C>,
383 pub log_base2k: usize,
384 pub log_k: usize,
385}
386
387impl<T> Infos for RLWEPt<T> {
388 type Inner = VecZnx<T>;
389
390 fn inner(&self) -> &Self::Inner {
391 &self.data
392 }
393
394 fn log_base2k(&self) -> usize {
395 self.log_base2k
396 }
397
398 fn log_k(&self) -> usize {
399 self.log_k
400 }
401}
402
403impl<C> VecZnxToMut for RLWEPt<C>
404where
405 VecZnx<C>: VecZnxToMut,
406{
407 fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
408 self.data.to_mut()
409 }
410}
411
412impl<C> VecZnxToRef for RLWEPt<C>
413where
414 VecZnx<C>: VecZnxToRef,
415{
416 fn to_ref(&self) -> VecZnx<&[u8]> {
417 self.data.to_ref()
418 }
419}
420
421impl RLWEPt<Vec<u8>> {
422 pub fn new<B: Backend>(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
423 Self {
424 data: module.new_vec_znx(1, derive_size(log_base2k, log_k)),
425 log_base2k: log_base2k,
426 log_k: log_k,
427 }
428 }
429}
430
431pub struct RLWECtDft<C, B: Backend> {
432 pub data: VecZnxDft<C, B>,
433 pub log_base2k: usize,
434 pub log_k: usize,
435}
436
437impl<B: Backend> RLWECtDft<Vec<u8>, B> {
438 pub fn new(module: &Module<B>, log_base2k: usize, log_k: usize) -> Self {
439 Self {
440 data: module.new_vec_znx_dft(2, derive_size(log_base2k, log_k)),
441 log_base2k: log_base2k,
442 log_k: log_k,
443 }
444 }
445}
446
447impl<T, B: Backend> Infos for RLWECtDft<T, B> {
448 type Inner = VecZnxDft<T, B>;
449
450 fn inner(&self) -> &Self::Inner {
451 &self.data
452 }
453
454 fn log_base2k(&self) -> usize {
455 self.log_base2k
456 }
457
458 fn log_k(&self) -> usize {
459 self.log_k
460 }
461}
462
463impl<C, B: Backend> VecZnxDftToMut<B> for RLWECtDft<C, B>
464where
465 VecZnxDft<C, B>: VecZnxDftToMut<B>,
466{
467 fn to_mut(&mut self) -> VecZnxDft<&mut [u8], B> {
468 self.data.to_mut()
469 }
470}
471
472impl<C, B: Backend> VecZnxDftToRef<B> for RLWECtDft<C, B>
473where
474 VecZnxDft<C, B>: VecZnxDftToRef<B>,
475{
476 fn to_ref(&self) -> VecZnxDft<&[u8], B> {
477 self.data.to_ref()
478 }
479}
480
481impl<C> RLWECtDft<C, FFT64>
482where
483 RLWECtDft<C, FFT64>: VecZnxDftToRef<FFT64>,
484{
485 #[allow(dead_code)]
486 pub(crate) fn idft_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
487 module.bytes_of_vec_znx(2, size) + (module.vec_znx_big_normalize_tmp_bytes() | module.vec_znx_idft_tmp_bytes())
488 }
489
490 pub(crate) fn idft<R>(&self, module: &Module<FFT64>, res: &mut RLWECt<R>, scratch: &mut Scratch)
491 where
492 RLWECt<R>: VecZnxToMut,
493 {
494 #[cfg(debug_assertions)]
495 {
496 assert_eq!(self.cols(), 2);
497 assert_eq!(res.cols(), 2);
498 assert_eq!(self.log_base2k(), res.log_base2k())
499 }
500
501 let min_size: usize = self.size().min(res.size());
502
503 let (mut res_big, scratch1) = scratch.tmp_vec_znx_big(module, 2, min_size);
504
505 module.vec_znx_idft(&mut res_big, 0, self, 0, scratch1);
506 module.vec_znx_idft(&mut res_big, 1, self, 1, scratch1);
507 module.vec_znx_big_normalize(self.log_base2k(), res, 0, &res_big, 0, scratch1);
508 module.vec_znx_big_normalize(self.log_base2k(), res, 1, &res_big, 1, scratch1);
509 }
510}
511
512pub(crate) fn encrypt_zero_rlwe_dft_sk<C, S>(
513 module: &Module<FFT64>,
514 ct: &mut RLWECtDft<C, FFT64>,
515 sk: &SecretKeyDft<S, FFT64>,
516 source_xa: &mut Source,
517 source_xe: &mut Source,
518 sigma: f64,
519 bound: f64,
520 scratch: &mut Scratch,
521) where
522 VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
523 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
524{
525 let log_base2k: usize = ct.log_base2k();
526 let log_k: usize = ct.log_k();
527 let size: usize = ct.size();
528
529 #[cfg(debug_assertions)]
530 {
531 match sk.dist {
532 SecretDistribution::NONE => panic!("invalid sk.dist = SecretDistribution::NONE"),
533 _ => {}
534 }
535 assert_eq!(ct.cols(), 2);
536 }
537
538 // ct[1] = DFT(a)
539 {
540 let (mut tmp_znx, _) = scratch.tmp_vec_znx(module, 1, size);
541 tmp_znx.fill_uniform(log_base2k, 0, size, source_xa);
542 module.vec_znx_dft(ct, 1, &tmp_znx, 0);
543 }
544
545 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, size);
546
547 {
548 let (mut tmp_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, size);
549 // c0_dft = ct[1] * DFT(s)
550 module.svp_apply(&mut tmp_dft, 0, sk, 0, ct, 1);
551
552 // c0_big = IDFT(c0_dft)
553 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut tmp_dft, 0);
554 }
555
556 // c0_big += e
557 c0_big.add_normal(log_base2k, 0, log_k, source_xe, sigma, bound);
558
559 // c0 = norm(c0_big = -as - e), NOTE: e is centered at 0.
560 let (mut tmp_znx, scratch_2) = scratch_1.tmp_vec_znx(module, 1, size);
561 module.vec_znx_big_normalize(log_base2k, &mut tmp_znx, 0, &c0_big, 0, scratch_2);
562 module.vec_znx_negate_inplace(&mut tmp_znx, 0);
563 // ct[0] = DFT(-as + e)
564 module.vec_znx_dft(ct, 0, &tmp_znx, 0);
565}
566
567impl RLWECtDft<Vec<u8>, FFT64> {
568 pub fn encrypt_zero_sk_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
569 (module.bytes_of_vec_znx(1, size) | module.bytes_of_vec_znx_dft(1, size))
570 + module.bytes_of_vec_znx_big(1, size)
571 + module.bytes_of_vec_znx(1, size)
572 + module.vec_znx_big_normalize_tmp_bytes()
573 }
574
575 pub fn decrypt_scratch_space(module: &Module<FFT64>, size: usize) -> usize {
576 (module.vec_znx_big_normalize_tmp_bytes()
577 | module.bytes_of_vec_znx_dft(1, size)
578 | (module.bytes_of_vec_znx_big(1, size) + module.vec_znx_idft_tmp_bytes()))
579 + module.bytes_of_vec_znx_big(1, size)
580 }
581}
582
583pub fn decrypt_rlwe_dft<P, C, S>(
584 module: &Module<FFT64>,
585 pt: &mut RLWEPt<P>,
586 ct: &RLWECtDft<C, FFT64>,
587 sk: &SecretKeyDft<S, FFT64>,
588 scratch: &mut Scratch,
589) where
590 VecZnx<P>: VecZnxToMut + VecZnxToRef,
591 VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>,
592 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
593{
594 let (mut c0_big, scratch_1) = scratch.tmp_vec_znx_big(module, 1, ct.size()); // TODO optimize size when pt << ct
595
596 {
597 let (mut c0_dft, _) = scratch_1.tmp_vec_znx_dft(module, 1, ct.size()); // TODO optimize size when pt << ct
598 // c0_dft = DFT(a) * DFT(s)
599 module.svp_apply(&mut c0_dft, 0, sk, 0, ct, 1);
600 // c0_big = IDFT(c0_dft)
601 module.vec_znx_idft_tmp_a(&mut c0_big, 0, &mut c0_dft, 0);
602 }
603
604 {
605 let (mut c1_big, scratch_2) = scratch_1.tmp_vec_znx_big(module, 1, ct.size());
606 // c0_big = (a * s) + (-a * s + m + e) = BIG(m + e)
607 module.vec_znx_idft(&mut c1_big, 0, ct, 0, scratch_2);
608 module.vec_znx_big_add_inplace(&mut c0_big, 0, &c1_big, 0);
609 }
610
611 // pt = norm(BIG(m + e))
612 module.vec_znx_big_normalize(ct.log_base2k(), pt, 0, &mut c0_big, 0, scratch_1);
613
614 pt.log_base2k = ct.log_base2k();
615 pt.log_k = pt.log_k().min(ct.log_k());
616}
617
618impl<C> RLWECtDft<C, FFT64> {
619 pub(crate) fn encrypt_zero_sk<S>(
620 &mut self,
621 module: &Module<FFT64>,
622 sk_dft: &SecretKeyDft<S, FFT64>,
623 source_xa: &mut Source,
624 source_xe: &mut Source,
625 sigma: f64,
626 bound: f64,
627 scratch: &mut Scratch,
628 ) where
629 VecZnxDft<C, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
630 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
631 {
632 encrypt_zero_rlwe_dft_sk(
633 module, self, sk_dft, source_xa, source_xe, sigma, bound, scratch,
634 )
635 }
636
637 pub fn decrypt<P, S>(
638 &self,
639 module: &Module<FFT64>,
640 pt: &mut RLWEPt<P>,
641 sk_dft: &SecretKeyDft<S, FFT64>,
642 scratch: &mut Scratch,
643 ) where
644 VecZnx<P>: VecZnxToMut + VecZnxToRef,
645 VecZnxDft<C, FFT64>: VecZnxDftToRef<FFT64>,
646 ScalarZnxDft<S, FFT64>: ScalarZnxDftToRef<FFT64>,
647 {
648 decrypt_rlwe_dft(module, pt, self, sk_dft, scratch);
649 }
650}
651
652impl ProdInplaceScratchSpace for RLWECtDft<Vec<u8>, FFT64> {
653 fn prod_by_grlwe_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
654 <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs)
655 }
656
657 fn prod_by_rgsw_inplace_scratch_space(module: &Module<FFT64>, lhs: usize, rhs: usize) -> usize {
658 <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_inplace_scratch_space(module, lhs, rhs)
659 }
660}
661
662impl ProdScratchSpace for RLWECtDft<Vec<u8>, FFT64> {
663 fn prod_by_grlwe_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
664 <GRLWECt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs)
665 }
666
667 fn prod_by_rgsw_scratch_space(module: &Module<FFT64>, res_size: usize, lhs: usize, rhs: usize) -> usize {
668 <RGSWCt<Vec<u8>, FFT64> as MatRLWEProductScratchSpace>::prod_with_rlwe_dft_scratch_space(module, res_size, lhs, rhs)
669 }
670}
671
672impl<MUT, REF> ProdInplace<MUT, REF> for RLWECtDft<MUT, FFT64>
673where
674 VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
675 MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
676{
677 fn prod_by_grlwe_inplace(&mut self, module: &Module<FFT64>, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
678 rhs.prod_with_rlwe_dft_inplace(module, self, scratch);
679 }
680
681 fn prod_by_rgsw_inplace(&mut self, module: &Module<FFT64>, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
682 rhs.prod_with_rlwe_dft_inplace(module, self, scratch);
683 }
684}
685
686impl<MUT, REF> Product<MUT, REF> for RLWECtDft<MUT, FFT64>
687where
688 VecZnxDft<MUT, FFT64>: VecZnxDftToMut<FFT64> + VecZnxDftToRef<FFT64>,
689 VecZnxDft<REF, FFT64>: VecZnxDftToRef<FFT64>,
690 MatZnxDft<REF, FFT64>: MatZnxDftToRef<FFT64>,
691{
692 type Lhs = RLWECtDft<REF, FFT64>;
693
694 fn prod_by_grlwe(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &GRLWECt<REF, FFT64>, scratch: &mut Scratch) {
695 rhs.prod_with_rlwe_dft(module, self, lhs, scratch);
696 }
697
698 fn prod_by_rgsw(&mut self, module: &Module<FFT64>, lhs: &Self::Lhs, rhs: &RGSWCt<REF, FFT64>, scratch: &mut Scratch) {
699 rhs.prod_with_rlwe_dft(module, self, lhs, scratch);
700 }
701}