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