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