poulpy/poulpy-backend/src/cpu_spqlios/fft64/vec_znx.rs
poulpy-backend/src/cpu_spqlios/fft64/vec_znx.rsRaw
1use itertools::izip;
2use rand_distr::Normal;
3
4use poulpy_hal::{
5 api::{
6 TakeSlice, TakeVecZnx, VecZnxAddDistF64, VecZnxCopy, VecZnxFillDistF64, VecZnxNormalizeTmpBytes, VecZnxRotate,
7 VecZnxRotateInplace, VecZnxSwithcDegree, ZnxInfos, ZnxSliceSize, ZnxView, ZnxViewMut, ZnxZero,
8 },
9 layouts::{Backend, Module, ScalarZnx, ScalarZnxToRef, Scratch, VecZnx, VecZnxToMut, VecZnxToRef},
10 oep::{
11 TakeSliceImpl, TakeVecZnxImpl, VecZnxAddDistF64Impl, VecZnxAddImpl, VecZnxAddInplaceImpl, VecZnxAddNormalImpl,
12 VecZnxAddScalarInplaceImpl, VecZnxAutomorphismImpl, VecZnxAutomorphismInplaceImpl, VecZnxCopyImpl, VecZnxFillDistF64Impl,
13 VecZnxFillNormalImpl, VecZnxFillUniformImpl, VecZnxLshInplaceImpl, VecZnxMergeImpl, VecZnxMulXpMinusOneImpl,
14 VecZnxMulXpMinusOneInplaceImpl, VecZnxNegateImpl, VecZnxNegateInplaceImpl, VecZnxNormalizeImpl,
15 VecZnxNormalizeInplaceImpl, VecZnxNormalizeTmpBytesImpl, VecZnxRotateImpl, VecZnxRotateInplaceImpl, VecZnxRshInplaceImpl,
16 VecZnxSplitImpl, VecZnxSubABInplaceImpl, VecZnxSubBAInplaceImpl, VecZnxSubImpl, VecZnxSubScalarInplaceImpl,
17 VecZnxSwithcDegreeImpl,
18 },
19 source::Source,
20};
21
22use crate::cpu_spqlios::{
23 FFT64,
24 ffi::{module::module_info_t, vec_znx, znx},
25};
26
27unsafe impl VecZnxNormalizeTmpBytesImpl<Self> for FFT64 {
28 fn vec_znx_normalize_tmp_bytes_impl(module: &Module<Self>) -> usize {
29 unsafe { vec_znx::vec_znx_normalize_base2k_tmp_bytes(module.ptr() as *const module_info_t) as usize }
30 }
31}
32
33unsafe impl VecZnxNormalizeImpl<Self> for FFT64
34where
35 Self: TakeSliceImpl<Self> + VecZnxNormalizeTmpBytesImpl<Self>,
36{
37 fn vec_znx_normalize_impl<R, A>(
38 module: &Module<Self>,
39 basek: usize,
40 res: &mut R,
41 res_col: usize,
42 a: &A,
43 a_col: usize,
44 scratch: &mut Scratch<Self>,
45 ) where
46 R: VecZnxToMut,
47 A: VecZnxToRef,
48 {
49 let a: VecZnx<&[u8]> = a.to_ref();
50 let mut res: VecZnx<&mut [u8]> = res.to_mut();
51
52 #[cfg(debug_assertions)]
53 {
54 assert_eq!(res.n(), a.n());
55 }
56
57 let (tmp_bytes, _) = scratch.take_slice(module.vec_znx_normalize_tmp_bytes());
58
59 unsafe {
60 vec_znx::vec_znx_normalize_base2k(
61 module.ptr() as *const module_info_t,
62 basek as u64,
63 res.at_mut_ptr(res_col, 0),
64 res.size() as u64,
65 res.sl() as u64,
66 a.at_ptr(a_col, 0),
67 a.size() as u64,
68 a.sl() as u64,
69 tmp_bytes.as_mut_ptr(),
70 );
71 }
72 }
73}
74
75unsafe impl VecZnxNormalizeInplaceImpl<Self> for FFT64
76where
77 Self: TakeSliceImpl<Self> + VecZnxNormalizeTmpBytesImpl<Self>,
78{
79 fn vec_znx_normalize_inplace_impl<A>(
80 module: &Module<Self>,
81 basek: usize,
82 a: &mut A,
83 a_col: usize,
84 scratch: &mut Scratch<Self>,
85 ) where
86 A: VecZnxToMut,
87 {
88 let mut a: VecZnx<&mut [u8]> = a.to_mut();
89
90 let (tmp_bytes, _) = scratch.take_slice(module.vec_znx_normalize_tmp_bytes());
91
92 unsafe {
93 vec_znx::vec_znx_normalize_base2k(
94 module.ptr() as *const module_info_t,
95 basek as u64,
96 a.at_mut_ptr(a_col, 0),
97 a.size() as u64,
98 a.sl() as u64,
99 a.at_ptr(a_col, 0),
100 a.size() as u64,
101 a.sl() as u64,
102 tmp_bytes.as_mut_ptr(),
103 );
104 }
105 }
106}
107
108unsafe impl VecZnxAddImpl<Self> for FFT64 {
109 fn vec_znx_add_impl<R, A, C>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &C, b_col: usize)
110 where
111 R: VecZnxToMut,
112 A: VecZnxToRef,
113 C: VecZnxToRef,
114 {
115 let a: VecZnx<&[u8]> = a.to_ref();
116 let b: VecZnx<&[u8]> = b.to_ref();
117 let mut res: VecZnx<&mut [u8]> = res.to_mut();
118
119 #[cfg(debug_assertions)]
120 {
121 assert_eq!(a.n(), res.n());
122 assert_eq!(b.n(), res.n());
123 assert_ne!(a.as_ptr(), b.as_ptr());
124 }
125 unsafe {
126 vec_znx::vec_znx_add(
127 module.ptr() as *const module_info_t,
128 res.at_mut_ptr(res_col, 0),
129 res.size() as u64,
130 res.sl() as u64,
131 a.at_ptr(a_col, 0),
132 a.size() as u64,
133 a.sl() as u64,
134 b.at_ptr(b_col, 0),
135 b.size() as u64,
136 b.sl() as u64,
137 )
138 }
139 }
140}
141
142unsafe impl VecZnxAddInplaceImpl<Self> for FFT64 {
143 fn vec_znx_add_inplace_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
144 where
145 R: VecZnxToMut,
146 A: VecZnxToRef,
147 {
148 let a: VecZnx<&[u8]> = a.to_ref();
149 let mut res: VecZnx<&mut [u8]> = res.to_mut();
150
151 #[cfg(debug_assertions)]
152 {
153 assert_eq!(a.n(), res.n());
154 }
155 unsafe {
156 vec_znx::vec_znx_add(
157 module.ptr() as *const module_info_t,
158 res.at_mut_ptr(res_col, 0),
159 res.size() as u64,
160 res.sl() as u64,
161 a.at_ptr(a_col, 0),
162 a.size() as u64,
163 a.sl() as u64,
164 res.at_ptr(res_col, 0),
165 res.size() as u64,
166 res.sl() as u64,
167 )
168 }
169 }
170}
171
172unsafe impl VecZnxAddScalarInplaceImpl<Self> for FFT64 {
173 fn vec_znx_add_scalar_inplace_impl<R, A>(
174 module: &Module<Self>,
175 res: &mut R,
176 res_col: usize,
177 res_limb: usize,
178 a: &A,
179 a_col: usize,
180 ) where
181 R: VecZnxToMut,
182 A: ScalarZnxToRef,
183 {
184 let mut res: VecZnx<&mut [u8]> = res.to_mut();
185 let a: ScalarZnx<&[u8]> = a.to_ref();
186
187 #[cfg(debug_assertions)]
188 {
189 assert_eq!(a.n(), res.n());
190 }
191
192 unsafe {
193 vec_znx::vec_znx_add(
194 module.ptr() as *const module_info_t,
195 res.at_mut_ptr(res_col, res_limb),
196 1_u64,
197 res.sl() as u64,
198 a.at_ptr(a_col, 0),
199 a.size() as u64,
200 a.sl() as u64,
201 res.at_ptr(res_col, res_limb),
202 1_u64,
203 res.sl() as u64,
204 )
205 }
206 }
207}
208
209unsafe impl VecZnxSubImpl<Self> for FFT64 {
210 fn vec_znx_sub_impl<R, A, C>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize, b: &C, b_col: usize)
211 where
212 R: VecZnxToMut,
213 A: VecZnxToRef,
214 C: VecZnxToRef,
215 {
216 let a: VecZnx<&[u8]> = a.to_ref();
217 let b: VecZnx<&[u8]> = b.to_ref();
218 let mut res: VecZnx<&mut [u8]> = res.to_mut();
219
220 #[cfg(debug_assertions)]
221 {
222 assert_eq!(a.n(), res.n());
223 assert_eq!(b.n(), res.n());
224 assert_ne!(a.as_ptr(), b.as_ptr());
225 }
226 unsafe {
227 vec_znx::vec_znx_sub(
228 module.ptr() as *const module_info_t,
229 res.at_mut_ptr(res_col, 0),
230 res.size() as u64,
231 res.sl() as u64,
232 a.at_ptr(a_col, 0),
233 a.size() as u64,
234 a.sl() as u64,
235 b.at_ptr(b_col, 0),
236 b.size() as u64,
237 b.sl() as u64,
238 )
239 }
240 }
241}
242
243unsafe impl VecZnxSubABInplaceImpl<Self> for FFT64 {
244 fn vec_znx_sub_ab_inplace_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
245 where
246 R: VecZnxToMut,
247 A: VecZnxToRef,
248 {
249 let a: VecZnx<&[u8]> = a.to_ref();
250 let mut res: VecZnx<&mut [u8]> = res.to_mut();
251 #[cfg(debug_assertions)]
252 {
253 assert_eq!(a.n(), res.n());
254 }
255 unsafe {
256 vec_znx::vec_znx_sub(
257 module.ptr() as *const module_info_t,
258 res.at_mut_ptr(res_col, 0),
259 res.size() as u64,
260 res.sl() as u64,
261 res.at_ptr(res_col, 0),
262 res.size() as u64,
263 res.sl() as u64,
264 a.at_ptr(a_col, 0),
265 a.size() as u64,
266 a.sl() as u64,
267 )
268 }
269 }
270}
271
272unsafe impl VecZnxSubBAInplaceImpl<Self> for FFT64 {
273 fn vec_znx_sub_ba_inplace_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
274 where
275 R: VecZnxToMut,
276 A: VecZnxToRef,
277 {
278 let a: VecZnx<&[u8]> = a.to_ref();
279 let mut res: VecZnx<&mut [u8]> = res.to_mut();
280 #[cfg(debug_assertions)]
281 {
282 assert_eq!(a.n(), res.n());
283 }
284 unsafe {
285 vec_znx::vec_znx_sub(
286 module.ptr() as *const module_info_t,
287 res.at_mut_ptr(res_col, 0),
288 res.size() as u64,
289 res.sl() as u64,
290 a.at_ptr(a_col, 0),
291 a.size() as u64,
292 a.sl() as u64,
293 res.at_ptr(res_col, 0),
294 res.size() as u64,
295 res.sl() as u64,
296 )
297 }
298 }
299}
300
301unsafe impl VecZnxSubScalarInplaceImpl<Self> for FFT64 {
302 fn vec_znx_sub_scalar_inplace_impl<R, A>(
303 module: &Module<Self>,
304 res: &mut R,
305 res_col: usize,
306 res_limb: usize,
307 a: &A,
308 a_col: usize,
309 ) where
310 R: VecZnxToMut,
311 A: ScalarZnxToRef,
312 {
313 let mut res: VecZnx<&mut [u8]> = res.to_mut();
314 let a: ScalarZnx<&[u8]> = a.to_ref();
315
316 #[cfg(debug_assertions)]
317 {
318 assert_eq!(a.n(), res.n());
319 }
320
321 unsafe {
322 vec_znx::vec_znx_sub(
323 module.ptr() as *const module_info_t,
324 res.at_mut_ptr(res_col, res_limb),
325 1_u64,
326 res.sl() as u64,
327 a.at_ptr(a_col, 0),
328 a.size() as u64,
329 a.sl() as u64,
330 res.at_ptr(res_col, res_limb),
331 1_u64,
332 res.sl() as u64,
333 )
334 }
335 }
336}
337
338unsafe impl VecZnxNegateImpl<Self> for FFT64 {
339 fn vec_znx_negate_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
340 where
341 R: VecZnxToMut,
342 A: VecZnxToRef,
343 {
344 let a: VecZnx<&[u8]> = a.to_ref();
345 let mut res: VecZnx<&mut [u8]> = res.to_mut();
346 #[cfg(debug_assertions)]
347 {
348 assert_eq!(a.n(), res.n());
349 }
350 unsafe {
351 vec_znx::vec_znx_negate(
352 module.ptr() as *const module_info_t,
353 res.at_mut_ptr(res_col, 0),
354 res.size() as u64,
355 res.sl() as u64,
356 a.at_ptr(a_col, 0),
357 a.size() as u64,
358 a.sl() as u64,
359 )
360 }
361 }
362}
363
364unsafe impl VecZnxNegateInplaceImpl<Self> for FFT64 {
365 fn vec_znx_negate_inplace_impl<A>(module: &Module<Self>, a: &mut A, a_col: usize)
366 where
367 A: VecZnxToMut,
368 {
369 let mut a: VecZnx<&mut [u8]> = a.to_mut();
370 unsafe {
371 vec_znx::vec_znx_negate(
372 module.ptr() as *const module_info_t,
373 a.at_mut_ptr(a_col, 0),
374 a.size() as u64,
375 a.sl() as u64,
376 a.at_ptr(a_col, 0),
377 a.size() as u64,
378 a.sl() as u64,
379 )
380 }
381 }
382}
383
384unsafe impl VecZnxLshInplaceImpl<Self> for FFT64 {
385 fn vec_znx_lsh_inplace_impl<A>(_module: &Module<Self>, basek: usize, k: usize, a: &mut A)
386 where
387 A: VecZnxToMut,
388 {
389 vec_znx_lsh_inplace_ref(basek, k, a)
390 }
391}
392
393pub fn vec_znx_lsh_inplace_ref<A>(basek: usize, k: usize, a: &mut A)
394where
395 A: VecZnxToMut,
396{
397 let mut a: VecZnx<&mut [u8]> = a.to_mut();
398
399 let n: usize = a.n();
400 let cols: usize = a.cols();
401 let size: usize = a.size();
402 let steps: usize = k / basek;
403
404 a.raw_mut().rotate_left(n * steps * cols);
405 (0..cols).for_each(|i| {
406 (size - steps..size).for_each(|j| {
407 a.zero_at(i, j);
408 })
409 });
410
411 let k_rem: usize = k % basek;
412
413 if k_rem != 0 {
414 let shift: usize = i64::BITS as usize - k_rem;
415 (0..cols).for_each(|i| {
416 (0..steps).for_each(|j| {
417 a.at_mut(i, j).iter_mut().for_each(|xi| {
418 *xi <<= shift;
419 });
420 });
421 });
422 }
423}
424
425unsafe impl VecZnxRshInplaceImpl<Self> for FFT64 {
426 fn vec_znx_rsh_inplace_impl<A>(_module: &Module<Self>, basek: usize, k: usize, a: &mut A)
427 where
428 A: VecZnxToMut,
429 {
430 vec_znx_rsh_inplace_ref(basek, k, a)
431 }
432}
433
434pub fn vec_znx_rsh_inplace_ref<A>(basek: usize, k: usize, a: &mut A)
435where
436 A: VecZnxToMut,
437{
438 let mut a: VecZnx<&mut [u8]> = a.to_mut();
439 let n: usize = a.n();
440 let cols: usize = a.cols();
441 let size: usize = a.size();
442 let steps: usize = k / basek;
443
444 a.raw_mut().rotate_right(n * steps * cols);
445 (0..cols).for_each(|i| {
446 (0..steps).for_each(|j| {
447 a.zero_at(i, j);
448 })
449 });
450
451 let k_rem: usize = k % basek;
452
453 if k_rem != 0 {
454 let mut carry: Vec<i64> = vec![0i64; n]; // ALLOC (but small so OK)
455 let shift: usize = i64::BITS as usize - k_rem;
456 (0..cols).for_each(|i| {
457 carry.fill(0);
458 (steps..size).for_each(|j| {
459 izip!(carry.iter_mut(), a.at_mut(i, j).iter_mut()).for_each(|(ci, xi)| {
460 *xi += *ci << basek;
461 *ci = (*xi << shift) >> shift;
462 *xi = (*xi - *ci) >> k_rem;
463 });
464 });
465 })
466 }
467}
468
469unsafe impl VecZnxRotateImpl<Self> for FFT64 {
470 fn vec_znx_rotate_impl<R, A>(_module: &Module<Self>, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
471 where
472 R: VecZnxToMut,
473 A: VecZnxToRef,
474 {
475 let a: VecZnx<&[u8]> = a.to_ref();
476 let mut res: VecZnx<&mut [u8]> = res.to_mut();
477 #[cfg(debug_assertions)]
478 {
479 assert_eq!(res.n(), a.n());
480 }
481 unsafe {
482 (0..a.size()).for_each(|j| {
483 znx::znx_rotate_i64(
484 a.n() as u64,
485 k,
486 res.at_mut_ptr(res_col, j),
487 a.at_ptr(a_col, j),
488 );
489 });
490 }
491 }
492}
493
494unsafe impl VecZnxRotateInplaceImpl<Self> for FFT64 {
495 fn vec_znx_rotate_inplace_impl<A>(_module: &Module<Self>, k: i64, a: &mut A, a_col: usize)
496 where
497 A: VecZnxToMut,
498 {
499 let mut a: VecZnx<&mut [u8]> = a.to_mut();
500 unsafe {
501 (0..a.size()).for_each(|j| {
502 znx::znx_rotate_inplace_i64(a.n() as u64, k, a.at_mut_ptr(a_col, j));
503 });
504 }
505 }
506}
507
508unsafe impl VecZnxAutomorphismImpl<Self> for FFT64 {
509 fn vec_znx_automorphism_impl<R, A>(module: &Module<Self>, k: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
510 where
511 R: VecZnxToMut,
512 A: VecZnxToRef,
513 {
514 let a: VecZnx<&[u8]> = a.to_ref();
515 let mut res: VecZnx<&mut [u8]> = res.to_mut();
516 #[cfg(debug_assertions)]
517 {
518 assert_eq!(a.n(), res.n());
519 }
520 unsafe {
521 vec_znx::vec_znx_automorphism(
522 module.ptr() as *const module_info_t,
523 k,
524 res.at_mut_ptr(res_col, 0),
525 res.size() as u64,
526 res.sl() as u64,
527 a.at_ptr(a_col, 0),
528 a.size() as u64,
529 a.sl() as u64,
530 )
531 }
532 }
533}
534
535unsafe impl VecZnxAutomorphismInplaceImpl<Self> for FFT64 {
536 fn vec_znx_automorphism_inplace_impl<A>(module: &Module<Self>, k: i64, a: &mut A, a_col: usize)
537 where
538 A: VecZnxToMut,
539 {
540 let mut a: VecZnx<&mut [u8]> = a.to_mut();
541 #[cfg(debug_assertions)]
542 {
543 assert!(
544 k & 1 != 0,
545 "invalid galois element: must be odd but is {}",
546 k
547 );
548 }
549 unsafe {
550 vec_znx::vec_znx_automorphism(
551 module.ptr() as *const module_info_t,
552 k,
553 a.at_mut_ptr(a_col, 0),
554 a.size() as u64,
555 a.sl() as u64,
556 a.at_ptr(a_col, 0),
557 a.size() as u64,
558 a.sl() as u64,
559 )
560 }
561 }
562}
563
564unsafe impl VecZnxMulXpMinusOneImpl<Self> for FFT64 {
565 fn vec_znx_mul_xp_minus_one_impl<R, A>(module: &Module<Self>, p: i64, res: &mut R, res_col: usize, a: &A, a_col: usize)
566 where
567 R: VecZnxToMut,
568 A: VecZnxToRef,
569 {
570 let a: VecZnx<&[u8]> = a.to_ref();
571 let mut res: VecZnx<&mut [u8]> = res.to_mut();
572 #[cfg(debug_assertions)]
573 {
574 assert_eq!(a.n(), res.n());
575 assert_eq!(res.n(), res.n());
576 }
577 unsafe {
578 vec_znx::vec_znx_mul_xp_minus_one(
579 module.ptr() as *const module_info_t,
580 p,
581 res.at_mut_ptr(res_col, 0),
582 res.size() as u64,
583 res.sl() as u64,
584 a.at_ptr(a_col, 0),
585 a.size() as u64,
586 a.sl() as u64,
587 )
588 }
589 }
590}
591
592unsafe impl VecZnxMulXpMinusOneInplaceImpl<Self> for FFT64 {
593 fn vec_znx_mul_xp_minus_one_inplace_impl<R>(module: &Module<Self>, p: i64, res: &mut R, res_col: usize)
594 where
595 R: VecZnxToMut,
596 {
597 let mut res: VecZnx<&mut [u8]> = res.to_mut();
598 #[cfg(debug_assertions)]
599 {
600 assert_eq!(res.n(), res.n());
601 }
602 unsafe {
603 vec_znx::vec_znx_mul_xp_minus_one(
604 module.ptr() as *const module_info_t,
605 p,
606 res.at_mut_ptr(res_col, 0),
607 res.size() as u64,
608 res.sl() as u64,
609 res.at_ptr(res_col, 0),
610 res.size() as u64,
611 res.sl() as u64,
612 )
613 }
614 }
615}
616
617unsafe impl VecZnxSplitImpl<Self> for FFT64
618where
619 Self: TakeVecZnxImpl<Self>
620 + TakeVecZnxImpl<Self>
621 + VecZnxSwithcDegreeImpl<Self>
622 + VecZnxRotateImpl<Self>
623 + VecZnxRotateInplaceImpl<Self>,
624{
625 fn vec_znx_split_impl<R, A>(
626 module: &Module<Self>,
627 res: &mut [R],
628 res_col: usize,
629 a: &A,
630 a_col: usize,
631 scratch: &mut Scratch<Self>,
632 ) where
633 R: VecZnxToMut,
634 A: VecZnxToRef,
635 {
636 vec_znx_split_ref(module, res, res_col, a, a_col, scratch)
637 }
638}
639
640pub fn vec_znx_split_ref<R, A, B>(
641 module: &Module<B>,
642 res: &mut [R],
643 res_col: usize,
644 a: &A,
645 a_col: usize,
646 scratch: &mut Scratch<B>,
647) where
648 B: Backend + TakeVecZnxImpl<B> + VecZnxSwithcDegreeImpl<B> + VecZnxRotateImpl<B> + VecZnxRotateInplaceImpl<B>,
649 R: VecZnxToMut,
650 A: VecZnxToRef,
651{
652 let a: VecZnx<&[u8]> = a.to_ref();
653
654 let (n_in, n_out) = (a.n(), res[0].to_mut().n());
655
656 let (mut buf, _) = scratch.take_vec_znx(n_in.max(n_out), 1, a.size());
657
658 debug_assert!(
659 n_out < n_in,
660 "invalid a: output ring degree should be smaller"
661 );
662 res[1..].iter_mut().for_each(|bi| {
663 debug_assert_eq!(
664 bi.to_mut().n(),
665 n_out,
666 "invalid input a: all VecZnx must have the same degree"
667 )
668 });
669
670 res.iter_mut().enumerate().for_each(|(i, bi)| {
671 if i == 0 {
672 module.vec_znx_switch_degree(bi, res_col, &a, a_col);
673 module.vec_znx_rotate(-1, &mut buf, 0, &a, a_col);
674 } else {
675 module.vec_znx_switch_degree(bi, res_col, &buf, a_col);
676 module.vec_znx_rotate_inplace(-1, &mut buf, a_col);
677 }
678 })
679}
680
681unsafe impl VecZnxMergeImpl<Self> for FFT64
682where
683 Self: VecZnxSwithcDegreeImpl<Self> + VecZnxRotateInplaceImpl<Self>,
684{
685 fn vec_znx_merge_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &[A], a_col: usize)
686 where
687 R: VecZnxToMut,
688 A: VecZnxToRef,
689 {
690 vec_znx_merge_ref(module, res, res_col, a, a_col)
691 }
692}
693
694pub fn vec_znx_merge_ref<R, A, B>(module: &Module<B>, res: &mut R, res_col: usize, a: &[A], a_col: usize)
695where
696 B: Backend + VecZnxSwithcDegreeImpl<B> + VecZnxRotateInplaceImpl<B>,
697 R: VecZnxToMut,
698 A: VecZnxToRef,
699{
700 let mut res: VecZnx<&mut [u8]> = res.to_mut();
701
702 let (n_in, n_out) = (res.n(), a[0].to_ref().n());
703
704 debug_assert!(
705 n_out < n_in,
706 "invalid a: output ring degree should be smaller"
707 );
708 a[1..].iter().for_each(|ai| {
709 debug_assert_eq!(
710 ai.to_ref().n(),
711 n_out,
712 "invalid input a: all VecZnx must have the same degree"
713 )
714 });
715
716 a.iter().for_each(|ai| {
717 module.vec_znx_switch_degree(&mut res, res_col, ai, a_col);
718 module.vec_znx_rotate_inplace(-1, &mut res, res_col);
719 });
720
721 module.vec_znx_rotate_inplace(a.len() as i64, &mut res, res_col);
722}
723
724unsafe impl VecZnxSwithcDegreeImpl<Self> for FFT64
725where
726 Self: VecZnxCopyImpl<Self>,
727{
728 fn vec_znx_switch_degree_impl<R, A>(module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
729 where
730 R: VecZnxToMut,
731 A: VecZnxToRef,
732 {
733 vec_znx_switch_degree_ref(module, res, res_col, a, a_col)
734 }
735}
736
737pub fn vec_znx_switch_degree_ref<R, A, B>(module: &Module<B>, res: &mut R, res_col: usize, a: &A, a_col: usize)
738where
739 B: Backend + VecZnxCopyImpl<B>,
740 R: VecZnxToMut,
741 A: VecZnxToRef,
742{
743 let a: VecZnx<&[u8]> = a.to_ref();
744 let mut res: VecZnx<&mut [u8]> = res.to_mut();
745
746 let (n_in, n_out) = (a.n(), res.n());
747
748 if n_in == n_out {
749 module.vec_znx_copy(&mut res, res_col, &a, a_col);
750 return;
751 }
752
753 let (gap_in, gap_out): (usize, usize);
754 if n_in > n_out {
755 (gap_in, gap_out) = (n_in / n_out, 1)
756 } else {
757 (gap_in, gap_out) = (1, n_out / n_in);
758 res.zero();
759 }
760
761 let size: usize = a.size().min(res.size());
762
763 (0..size).for_each(|i| {
764 izip!(
765 a.at(a_col, i).iter().step_by(gap_in),
766 res.at_mut(res_col, i).iter_mut().step_by(gap_out)
767 )
768 .for_each(|(x_in, x_out)| *x_out = *x_in);
769 });
770}
771
772unsafe impl VecZnxCopyImpl<Self> for FFT64 {
773 fn vec_znx_copy_impl<R, A>(_module: &Module<Self>, res: &mut R, res_col: usize, a: &A, a_col: usize)
774 where
775 R: VecZnxToMut,
776 A: VecZnxToRef,
777 {
778 vec_znx_copy_ref(res, res_col, a, a_col)
779 }
780}
781
782pub fn vec_znx_copy_ref<R, A>(res: &mut R, res_col: usize, a: &A, a_col: usize)
783where
784 R: VecZnxToMut,
785 A: VecZnxToRef,
786{
787 let mut res_mut: VecZnx<&mut [u8]> = res.to_mut();
788 let a_ref: VecZnx<&[u8]> = a.to_ref();
789
790 let min_size: usize = res_mut.size().min(a_ref.size());
791
792 (0..min_size).for_each(|j| {
793 res_mut
794 .at_mut(res_col, j)
795 .copy_from_slice(a_ref.at(a_col, j));
796 });
797 (min_size..res_mut.size()).for_each(|j| {
798 res_mut.zero_at(res_col, j);
799 })
800}
801
802unsafe impl VecZnxFillUniformImpl<Self> for FFT64 {
803 fn vec_znx_fill_uniform_impl<R>(
804 _module: &Module<Self>,
805 basek: usize,
806 res: &mut R,
807 res_col: usize,
808 k: usize,
809 source: &mut Source,
810 ) where
811 R: VecZnxToMut,
812 {
813 let mut a: VecZnx<&mut [u8]> = res.to_mut();
814 let base2k: u64 = 1 << basek;
815 let mask: u64 = base2k - 1;
816 let base2k_half: i64 = (base2k >> 1) as i64;
817 (0..k.div_ceil(basek)).for_each(|j| {
818 a.at_mut(res_col, j)
819 .iter_mut()
820 .for_each(|x| *x = (source.next_u64n(base2k, mask) as i64) - base2k_half);
821 })
822 }
823}
824
825unsafe impl VecZnxFillDistF64Impl<Self> for FFT64 {
826 fn vec_znx_fill_dist_f64_impl<R, D: rand::prelude::Distribution<f64>>(
827 _module: &Module<Self>,
828 basek: usize,
829 res: &mut R,
830 res_col: usize,
831 k: usize,
832 source: &mut Source,
833 dist: D,
834 bound: f64,
835 ) where
836 R: VecZnxToMut,
837 {
838 let mut a: VecZnx<&mut [u8]> = res.to_mut();
839 assert!(
840 (bound.log2().ceil() as i64) < 64,
841 "invalid bound: ceil(log2(bound))={} > 63",
842 (bound.log2().ceil() as i64)
843 );
844
845 let limb: usize = k.div_ceil(basek) - 1;
846 let basek_rem: usize = (limb + 1) * basek - k;
847
848 if basek_rem != 0 {
849 a.at_mut(res_col, limb).iter_mut().for_each(|a| {
850 let mut dist_f64: f64 = dist.sample(source);
851 while dist_f64.abs() > bound {
852 dist_f64 = dist.sample(source)
853 }
854 *a = (dist_f64.round() as i64) << basek_rem;
855 });
856 } else {
857 a.at_mut(res_col, limb).iter_mut().for_each(|a| {
858 let mut dist_f64: f64 = dist.sample(source);
859 while dist_f64.abs() > bound {
860 dist_f64 = dist.sample(source)
861 }
862 *a = dist_f64.round() as i64
863 });
864 }
865 }
866}
867
868unsafe impl VecZnxAddDistF64Impl<Self> for FFT64 {
869 fn vec_znx_add_dist_f64_impl<R, D: rand::prelude::Distribution<f64>>(
870 _module: &Module<Self>,
871 basek: usize,
872 res: &mut R,
873 res_col: usize,
874 k: usize,
875 source: &mut Source,
876 dist: D,
877 bound: f64,
878 ) where
879 R: VecZnxToMut,
880 {
881 let mut a: VecZnx<&mut [u8]> = res.to_mut();
882 assert!(
883 (bound.log2().ceil() as i64) < 64,
884 "invalid bound: ceil(log2(bound))={} > 63",
885 (bound.log2().ceil() as i64)
886 );
887
888 let limb: usize = k.div_ceil(basek) - 1;
889 let basek_rem: usize = (limb + 1) * basek - k;
890
891 if basek_rem != 0 {
892 a.at_mut(res_col, limb).iter_mut().for_each(|a| {
893 let mut dist_f64: f64 = dist.sample(source);
894 while dist_f64.abs() > bound {
895 dist_f64 = dist.sample(source)
896 }
897 *a += (dist_f64.round() as i64) << basek_rem;
898 });
899 } else {
900 a.at_mut(res_col, limb).iter_mut().for_each(|a| {
901 let mut dist_f64: f64 = dist.sample(source);
902 while dist_f64.abs() > bound {
903 dist_f64 = dist.sample(source)
904 }
905 *a += dist_f64.round() as i64
906 });
907 }
908 }
909}
910
911unsafe impl VecZnxFillNormalImpl<Self> for FFT64
912where
913 Self: VecZnxFillDistF64Impl<Self>,
914{
915 fn vec_znx_fill_normal_impl<R>(
916 module: &Module<Self>,
917 basek: usize,
918 res: &mut R,
919 res_col: usize,
920 k: usize,
921 source: &mut Source,
922 sigma: f64,
923 bound: f64,
924 ) where
925 R: VecZnxToMut,
926 {
927 module.vec_znx_fill_dist_f64(
928 basek,
929 res,
930 res_col,
931 k,
932 source,
933 Normal::new(0.0, sigma).unwrap(),
934 bound,
935 );
936 }
937}
938
939unsafe impl VecZnxAddNormalImpl<Self> for FFT64
940where
941 Self: VecZnxAddDistF64Impl<Self>,
942{
943 fn vec_znx_add_normal_impl<R>(
944 module: &Module<Self>,
945 basek: usize,
946 res: &mut R,
947 res_col: usize,
948 k: usize,
949 source: &mut Source,
950 sigma: f64,
951 bound: f64,
952 ) where
953 R: VecZnxToMut,
954 {
955 module.vec_znx_add_dist_f64(
956 basek,
957 res,
958 res_col,
959 k,
960 source,
961 Normal::new(0.0, sigma).unwrap(),
962 bound,
963 );
964 }
965}