arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/base2k/src/vec_znx.rs
base2k/src/vec_znx.rsRaw
  1use crate::cast_mut;
  2use crate::ffi::vec_znx;
  3use crate::ffi::znx;
  4use crate::LAYOUT;
  5use crate::{Infos, Module};
  6use crate::{alloc_aligned, assert_alignement};
  7use itertools::izip;
  8use std::cmp::min;
  9
 10/// [VecZnx] represents collection of contiguously stacked vector of small norm polynomials of
 11/// Zn\[X\] with [i64] coefficients.
 12/// A [VecZnx] is composed of multiple Zn\[X\] polynomials stored in a single contiguous array
 13/// in the memory.
 14///
 15/// # Example
 16///
 17/// Given 3 polynomials (a, b, c) of Zn\[X\], each with 4 columns, then the memory
 18/// layout is: `[a0, b0, c0, a1, b1, c1, a2, b2, c2, a3, b3, c3]`, where ai, bi, ci
 19/// are small polynomials of Zn\[X\].
 20#[derive(Clone)]
 21pub struct VecZnx {
 22    /// Polynomial degree.
 23    pub n: usize,
 24
 25    /// Stack size
 26    pub size: usize,
 27
 28    /// Stacking layout
 29    pub layout: LAYOUT,
 30
 31    /// Number of columns.
 32    pub cols: usize,
 33
 34    /// Polynomial coefficients, as a contiguous array. Each col is equally spaced by n.
 35    pub data: Vec<i64>,
 36
 37    /// Pointer to data (data can be enpty if [VecZnx] borrows space instead of owning it).
 38    pub ptr: *mut i64,
 39}
 40
 41pub fn bytes_of_vec_znx(n: usize, size: usize, cols: usize) -> usize {
 42    n * size * cols * 8
 43}
 44
 45impl VecZnx {
 46    /// Returns a new struct implementing [VecZnx] with the provided data as backing array.
 47    ///
 48    /// The struct will take ownership of buf[..[VecZnx::bytes_of]]
 49    ///
 50    /// User must ensure that data is properly alligned and that
 51    /// the size of data is equal to [VecZnx::bytes_of].
 52    pub fn from_bytes(n: usize, size: usize, cols: usize, bytes: &mut [u8]) -> Self {
 53        #[cfg(debug_assertions)]
 54        {
 55            assert!(size > 0);
 56            assert_eq!(bytes.len(), Self::bytes_of(n, size, cols));
 57            assert_alignement(bytes.as_ptr());
 58        }
 59        unsafe {
 60            let bytes_i64: &mut [i64] = cast_mut::<u8, i64>(bytes);
 61            let ptr: *mut i64 = bytes_i64.as_mut_ptr();
 62            VecZnx {
 63                n: n,
 64                size: size,
 65                cols: cols,
 66                layout: LAYOUT::COL,
 67                data: Vec::from_raw_parts(ptr, bytes.len(), bytes.len()),
 68                ptr: ptr,
 69            }
 70        }
 71    }
 72
 73    pub fn from_bytes_borrow(n: usize, size: usize, cols: usize, bytes: &mut [u8]) -> Self {
 74        #[cfg(debug_assertions)]
 75        {
 76            assert!(size > 0);
 77            assert!(bytes.len() >= Self::bytes_of(n, size, cols));
 78            assert_alignement(bytes.as_ptr());
 79        }
 80        VecZnx {
 81            n: n,
 82            size: size,
 83            cols: cols,
 84            layout: LAYOUT::COL,
 85            data: Vec::new(),
 86            ptr: bytes.as_mut_ptr() as *mut i64,
 87        }
 88    }
 89
 90    pub fn bytes_of(n: usize, size: usize, cols: usize) -> usize {
 91        bytes_of_vec_znx(n, size, cols)
 92    }
 93
 94    pub fn copy_from(&mut self, a: &VecZnx) {
 95        copy_vec_znx_from(self, a);
 96    }
 97
 98    pub fn borrowing(&self) -> bool {
 99        self.data.len() == 0
100    }
101
102    /// TODO: when SML refactoring is done, move this to the [Infos] trait.
103    pub fn size(&self) -> usize {
104        self.size
105    }
106
107    /// Total size is [VecZnx::n()] * [VecZnx::size()] * [VecZnx::cols()].
108    pub fn raw(&self) -> &[i64] {
109        unsafe { std::slice::from_raw_parts(self.ptr, self.n * self.size * self.cols) }
110    }
111
112    /// Returns a reference to backend slice of the receiver.
113    /// Total size is [VecZnx::n()] * [VecZnx::size()] * [VecZnx::cols()].
114    pub fn raw_mut(&mut self) -> &mut [i64] {
115        unsafe { std::slice::from_raw_parts_mut(self.ptr, self.n * self.size * self.cols) }
116    }
117
118    /// Returns a non-mutable pointer to the backedn slice of the receiver.
119    pub fn as_ptr(&self) -> *const i64 {
120        self.ptr
121    }
122
123    /// Returns a mutable pointer to the backedn slice of the receiver.
124    pub fn as_mut_ptr(&mut self) -> *mut i64 {
125        self.ptr
126    }
127
128    /// Returns a non-mutable pointer starting a the j-th column.
129    pub fn at_ptr(&self, i: usize) -> *const i64 {
130        #[cfg(debug_assertions)]
131        {
132            assert!(i < self.cols);
133        }
134        let offset: usize = self.n * self.size * i;
135        self.ptr.wrapping_add(offset)
136    }
137
138    /// Returns non-mutable reference to the ith-column.
139    /// The slice contains [VecZnx::size()] small polynomials, each of [VecZnx::n()] coefficients.
140    pub fn at(&self, i: usize) -> &[i64] {
141        unsafe { std::slice::from_raw_parts(self.at_ptr(i), self.n * self.size) }
142    }
143
144    /// Returns a non-mutable pointer starting a the j-th column of the i-th polynomial.
145    pub fn at_poly_ptr(&self, i: usize, j: usize) -> *const i64 {
146        #[cfg(debug_assertions)]
147        {
148            assert!(i < self.size);
149            assert!(j < self.cols);
150        }
151        let offset: usize = self.n * (self.size * j + i);
152        self.ptr.wrapping_add(offset)
153    }
154
155    /// Returns non-mutable reference to the j-th column of the i-th polynomial.
156    /// The slice contains one small polynomial of [VecZnx::n()] coefficients.
157    pub fn at_poly(&self, i: usize, j: usize) -> &[i64] {
158        unsafe { std::slice::from_raw_parts(self.at_poly_ptr(i, j), self.n) }
159    }
160
161    /// Returns a mutable pointer starting a the j-th column.
162    pub fn at_mut_ptr(&self, i: usize) -> *mut i64 {
163        #[cfg(debug_assertions)]
164        {
165            assert!(i < self.cols);
166        }
167        let offset: usize = self.n * self.size * i;
168        self.ptr.wrapping_add(offset)
169    }
170
171    /// Returns mutable reference to the ith-column.
172    /// The slice contains [VecZnx::size()] small polynomials, each of [VecZnx::n()] coefficients.
173    pub fn at_mut(&mut self, i: usize) -> &mut [i64] {
174        unsafe { std::slice::from_raw_parts_mut(self.at_mut_ptr(i), self.n * self.size) }
175    }
176
177    /// Returns a mutable pointer starting a the j-th column of the i-th polynomial.
178    pub fn at_poly_mut_ptr(&mut self, i: usize, j: usize) -> *mut i64 {
179        #[cfg(debug_assertions)]
180        {
181            assert!(i < self.size);
182            assert!(j < self.cols);
183        }
184
185        let offset: usize = self.n * (self.size * j + i);
186        self.ptr.wrapping_add(offset)
187    }
188
189    /// Returns mutable reference to the j-th column of the i-th polynomial.
190    /// The slice contains one small polynomial of [VecZnx::n()] coefficients.
191    pub fn at_poly_mut(&mut self, i: usize, j: usize) -> &mut [i64] {
192        let ptr: *mut i64 = self.at_poly_mut_ptr(i, j);
193        unsafe { std::slice::from_raw_parts_mut(ptr, self.n) }
194    }
195
196    pub fn zero(&mut self) {
197        unsafe { znx::znx_zero_i64_ref((self.n * self.cols * self.size) as u64, self.ptr) }
198    }
199
200    pub fn normalize(&mut self, log_base2k: usize, carry: &mut [u8]) {
201        normalize(log_base2k, self, carry)
202    }
203
204    pub fn rsh(&mut self, log_base2k: usize, k: usize, carry: &mut [u8]) {
205        rsh(log_base2k, self, k, carry)
206    }
207
208    pub fn switch_degree(&self, a: &mut VecZnx) {
209        switch_degree(a, self)
210    }
211
212    pub fn print(&self, poly: usize, cols: usize, n: usize) {
213        (0..cols).for_each(|i| println!("{}: {:?}", i, &self.at_poly(poly, i)[..n]))
214    }
215}
216
217impl Infos for VecZnx {
218    /// Returns the base 2 logarithm of the [VecZnx] degree.
219    fn log_n(&self) -> usize {
220        (usize::BITS - (self.n - 1).leading_zeros()) as _
221    }
222
223    /// Returns the [VecZnx] degree.
224    fn n(&self) -> usize {
225        self.n
226    }
227
228    /// Returns the number of cols of the [VecZnx].
229    fn cols(&self) -> usize {
230        self.cols
231    }
232
233    /// Returns the number of rows of the [VecZnx].
234    fn rows(&self) -> usize {
235        1
236    }
237}
238
239/// Copies the coefficients of `a` on the receiver.
240/// Copy is done with the minimum size matching both backing arrays.
241pub fn copy_vec_znx_from(b: &mut VecZnx, a: &VecZnx) {
242    let data_a: &[i64] = a.raw();
243    let data_b: &mut [i64] = b.raw_mut();
244    let size = min(data_b.len(), data_a.len());
245    data_b[..size].copy_from_slice(&data_a[..size])
246}
247
248impl VecZnx {
249    /// Allocates a new [VecZnx] composed of #cols polynomials of Z\[X\].
250    pub fn new(n: usize, size: usize, cols: usize) -> Self {
251        #[cfg(debug_assertions)]
252        {
253            assert!(n > 0);
254            assert!(n & (n - 1) == 0);
255            assert!(size > 0);
256            assert!(cols > 0);
257        }
258        let mut data: Vec<i64> = alloc_aligned::<i64>(n * size * cols);
259        let ptr: *mut i64 = data.as_mut_ptr();
260        Self {
261            n: n,
262            size: size,
263            layout: LAYOUT::COL,
264            cols: cols,
265            data: data,
266            ptr: ptr,
267        }
268    }
269
270    /// Truncates the precision of the [VecZnx] by k bits.
271    ///
272    /// # Arguments
273    ///
274    /// * `log_base2k`: the base two logarithm of the coefficients decomposition.
275    /// * `k`: the number of bits of precision to drop.
276    pub fn trunc_pow2(&mut self, log_base2k: usize, k: usize) {
277        if k == 0 {
278            return;
279        }
280
281        if !self.borrowing() {
282            self.data
283                .truncate((self.cols() - k / log_base2k) * self.n() * self.size());
284        }
285
286        self.cols -= k / log_base2k;
287
288        let k_rem: usize = k % log_base2k;
289
290        if k_rem != 0 {
291            let mask: i64 = ((1 << (log_base2k - k_rem - 1)) - 1) << k_rem;
292            self.at_mut(self.cols() - 1)
293                .iter_mut()
294                .for_each(|x: &mut i64| *x &= mask)
295        }
296    }
297}
298
299pub fn switch_degree(b: &mut VecZnx, a: &VecZnx) {
300    let (n_in, n_out) = (a.n(), b.n());
301    let (gap_in, gap_out): (usize, usize);
302
303    if n_in > n_out {
304        (gap_in, gap_out) = (n_in / n_out, 1)
305    } else {
306        (gap_in, gap_out) = (1, n_out / n_in);
307        b.zero();
308    }
309
310    let cols = min(a.cols(), b.cols());
311
312    (0..cols).for_each(|i| {
313        izip!(
314            a.at(i).iter().step_by(gap_in),
315            b.at_mut(i).iter_mut().step_by(gap_out)
316        )
317        .for_each(|(x_in, x_out)| *x_out = *x_in);
318    });
319}
320
321fn normalize_tmp_bytes(n: usize, size: usize) -> usize {
322    n * size * std::mem::size_of::<i64>()
323}
324
325fn normalize(log_base2k: usize, a: &mut VecZnx, tmp_bytes: &mut [u8]) {
326    let n: usize = a.n();
327    let size: usize = a.size();
328
329    debug_assert!(
330        tmp_bytes.len() >= normalize_tmp_bytes(n, size),
331        "invalid tmp_bytes: tmp_bytes.len()={} < normalize_tmp_bytes({}, {})",
332        tmp_bytes.len(),
333        n,
334        size,
335    );
336    #[cfg(debug_assertions)]
337    {
338        assert_alignement(tmp_bytes.as_ptr())
339    }
340
341    let carry_i64: &mut [i64] = cast_mut(tmp_bytes);
342
343    unsafe {
344        znx::znx_zero_i64_ref(n as u64, carry_i64.as_mut_ptr());
345        (0..a.cols()).rev().for_each(|i| {
346            znx::znx_normalize(
347                (n * size) as u64,
348                log_base2k as u64,
349                a.at_mut_ptr(i),
350                carry_i64.as_mut_ptr(),
351                a.at_mut_ptr(i),
352                carry_i64.as_mut_ptr(),
353            )
354        });
355    }
356}
357
358pub fn rsh_tmp_bytes(n: usize, size: usize) -> usize {
359    n * size * std::mem::size_of::<i64>()
360}
361
362pub fn rsh(log_base2k: usize, a: &mut VecZnx, k: usize, tmp_bytes: &mut [u8]) {
363    let n: usize = a.n();
364    let size: usize = a.size();
365
366    #[cfg(debug_assertions)]
367    {
368        assert!(
369            tmp_bytes.len() >= rsh_tmp_bytes(n, size),
370            "invalid carry: carry.len()/8={} < rsh_tmp_bytes({}, {})",
371            tmp_bytes.len() >> 3,
372            n,
373            size,
374        );
375        assert_alignement(tmp_bytes.as_ptr());
376    }
377
378    let cols: usize = a.cols();
379    let cols_steps: usize = k / log_base2k;
380
381    a.raw_mut().rotate_right(n * size * cols_steps);
382    unsafe {
383        znx::znx_zero_i64_ref((n * size * cols_steps) as u64, a.as_mut_ptr());
384    }
385
386    let k_rem = k % log_base2k;
387
388    if k_rem != 0 {
389        let carry_i64: &mut [i64] = cast_mut(tmp_bytes);
390
391        unsafe {
392            znx::znx_zero_i64_ref((n * size) as u64, carry_i64.as_mut_ptr());
393        }
394
395        let log_base2k: usize = log_base2k;
396
397        (cols_steps..cols).for_each(|i| {
398            izip!(carry_i64.iter_mut(), a.at_mut(i).iter_mut()).for_each(|(ci, xi)| {
399                *xi += *ci << log_base2k;
400                *ci = get_base_k_carry(*xi, k_rem);
401                *xi = (*xi - *ci) >> k_rem;
402            });
403        })
404    }
405}
406
407#[inline(always)]
408fn get_base_k_carry(x: i64, k: usize) -> i64 {
409    (x << 64 - k) >> (64 - k)
410}
411
412pub trait VecZnxOps {
413    /// Allocates a new [VecZnx].
414    ///
415    /// # Arguments
416    ///
417    /// * `cols`: the number of cols.
418    fn new_vec_znx(&self, size: usize, cols: usize) -> VecZnx;
419
420    /// Returns the minimum number of bytes necessary to allocate
421    /// a new [VecZnx] through [VecZnx::from_bytes].
422    fn bytes_of_vec_znx(&self, size: usize, cols: usize) -> usize;
423
424    fn vec_znx_normalize_tmp_bytes(&self, size: usize) -> usize;
425
426    /// c <- a + b.
427    fn vec_znx_add(&self, c: &mut VecZnx, a: &VecZnx, b: &VecZnx);
428
429    /// b <- b + a.
430    fn vec_znx_add_inplace(&self, b: &mut VecZnx, a: &VecZnx);
431
432    /// c <- a - b.
433    fn vec_znx_sub(&self, c: &mut VecZnx, a: &VecZnx, b: &VecZnx);
434
435    /// b <- a - b.
436    fn vec_znx_sub_ab_inplace(&self, b: &mut VecZnx, a: &VecZnx);
437
438    /// b <- b - a.
439    fn vec_znx_sub_ba_inplace(&self, b: &mut VecZnx, a: &VecZnx);
440
441    /// b <- -a.
442    fn vec_znx_negate(&self, b: &mut VecZnx, a: &VecZnx);
443
444    /// b <- -b.
445    fn vec_znx_negate_inplace(&self, a: &mut VecZnx);
446
447    /// b <- a * X^k (mod X^{n} + 1)
448    fn vec_znx_rotate(&self, k: i64, b: &mut VecZnx, a: &VecZnx);
449
450    /// a <- a * X^k (mod X^{n} + 1)
451    fn vec_znx_rotate_inplace(&self, k: i64, a: &mut VecZnx);
452
453    /// b <- phi_k(a) where phi_k: X^i -> X^{i*k} (mod (X^{n} + 1))
454    fn vec_znx_automorphism(&self, k: i64, b: &mut VecZnx, a: &VecZnx);
455
456    /// a <- phi_k(a) where phi_k: X^i -> X^{i*k} (mod (X^{n} + 1))
457    fn vec_znx_automorphism_inplace(&self, k: i64, a: &mut VecZnx);
458
459    /// Splits b into subrings and copies them them into a.
460    ///
461    /// # Panics
462    ///
463    /// This method requires that all [VecZnx] of b have the same ring degree
464    /// and that b.n() * b.len() <= a.n()
465    fn vec_znx_split(&self, b: &mut Vec<VecZnx>, a: &VecZnx, buf: &mut VecZnx);
466
467    /// Merges the subrings a into b.
468    ///
469    /// # Panics
470    ///
471    /// This method requires that all [VecZnx] of a have the same ring degree
472    /// and that a.n() * a.len() <= b.n()
473    fn vec_znx_merge(&self, b: &mut VecZnx, a: &Vec<VecZnx>);
474}
475
476impl VecZnxOps for Module {
477    fn new_vec_znx(&self, size: usize, cols: usize) -> VecZnx {
478        VecZnx::new(self.n(), size, cols)
479    }
480
481    fn bytes_of_vec_znx(&self, size: usize, cols: usize) -> usize {
482        bytes_of_vec_znx(self.n(), size, cols)
483    }
484
485    fn vec_znx_normalize_tmp_bytes(&self, size: usize) -> usize {
486        unsafe { vec_znx::vec_znx_normalize_base2k_tmp_bytes(self.ptr) as usize * size }
487    }
488
489    // c <- a + b
490    fn vec_znx_add(&self, c: &mut VecZnx, a: &VecZnx, b: &VecZnx) {
491        let n: usize = self.n();
492        #[cfg(debug_assertions)]
493        {
494            assert_eq!(c.n(), n);
495            assert_eq!(a.n(), n);
496            assert_eq!(b.n(), n);
497        }
498        unsafe {
499            vec_znx::vec_znx_add(
500                self.ptr,
501                c.as_mut_ptr(),
502                c.cols() as u64,
503                (n * c.size()) as u64,
504                a.as_ptr(),
505                a.cols() as u64,
506                (n * a.size()) as u64,
507                b.as_ptr(),
508                b.cols() as u64,
509                (n * b.size()) as u64,
510            )
511        }
512    }
513
514    // b <- a + b
515    fn vec_znx_add_inplace(&self, b: &mut VecZnx, a: &VecZnx) {
516        let n: usize = self.n();
517        #[cfg(debug_assertions)]
518        {
519            assert_eq!(a.n(), n);
520            assert_eq!(b.n(), n);
521        }
522        unsafe {
523            vec_znx::vec_znx_add(
524                self.ptr,
525                b.as_mut_ptr(),
526                b.cols() as u64,
527                (n * b.size()) as u64,
528                a.as_ptr(),
529                a.cols() as u64,
530                (n * a.size()) as u64,
531                b.as_ptr(),
532                b.cols() as u64,
533                (n * b.size()) as u64,
534            )
535        }
536    }
537
538    // c <- a + b
539    fn vec_znx_sub(&self, c: &mut VecZnx, a: &VecZnx, b: &VecZnx) {
540        let n: usize = self.n();
541        #[cfg(debug_assertions)]
542        {
543            assert_eq!(c.n(), n);
544            assert_eq!(a.n(), n);
545            assert_eq!(b.n(), n);
546        }
547        unsafe {
548            vec_znx::vec_znx_sub(
549                self.ptr,
550                c.as_mut_ptr(),
551                c.cols() as u64,
552                (n * c.size()) as u64,
553                a.as_ptr(),
554                a.cols() as u64,
555                (n * a.size()) as u64,
556                b.as_ptr(),
557                b.cols() as u64,
558                (n * b.size()) as u64,
559            )
560        }
561    }
562
563    // b <- a - b
564    fn vec_znx_sub_ab_inplace(&self, b: &mut VecZnx, a: &VecZnx) {
565        let n: usize = self.n();
566        #[cfg(debug_assertions)]
567        {
568            assert_eq!(a.n(), n);
569            assert_eq!(b.n(), n);
570        }
571        unsafe {
572            vec_znx::vec_znx_sub(
573                self.ptr,
574                b.as_mut_ptr(),
575                b.cols() as u64,
576                (n * b.size()) as u64,
577                a.as_ptr(),
578                a.cols() as u64,
579                (n * a.size()) as u64,
580                b.as_ptr(),
581                b.cols() as u64,
582                (n * b.size()) as u64,
583            )
584        }
585    }
586
587    // b <- b - a
588    fn vec_znx_sub_ba_inplace(&self, b: &mut VecZnx, a: &VecZnx) {
589        let n: usize = self.n();
590        #[cfg(debug_assertions)]
591        {
592            assert_eq!(a.n(), n);
593            assert_eq!(b.n(), n);
594        }
595        unsafe {
596            vec_znx::vec_znx_sub(
597                self.ptr,
598                b.as_mut_ptr(),
599                b.cols() as u64,
600                (n * b.size()) as u64,
601                b.as_ptr(),
602                b.cols() as u64,
603                (n * b.size()) as u64,
604                a.as_ptr(),
605                a.cols() as u64,
606                (n * a.size()) as u64,
607            )
608        }
609    }
610
611    fn vec_znx_negate(&self, b: &mut VecZnx, a: &VecZnx) {
612        let n: usize = self.n();
613        #[cfg(debug_assertions)]
614        {
615            assert_eq!(a.n(), n);
616            assert_eq!(b.n(), n);
617        }
618        unsafe {
619            vec_znx::vec_znx_negate(
620                self.ptr,
621                b.as_mut_ptr(),
622                b.cols() as u64,
623                (n * b.size()) as u64,
624                a.as_ptr(),
625                a.cols() as u64,
626                (n * a.size()) as u64,
627            )
628        }
629    }
630
631    fn vec_znx_negate_inplace(&self, a: &mut VecZnx) {
632        let n: usize = self.n();
633        #[cfg(debug_assertions)]
634        {
635            assert_eq!(a.n(), n);
636        }
637        unsafe {
638            vec_znx::vec_znx_negate(
639                self.ptr,
640                a.as_mut_ptr(),
641                a.cols() as u64,
642                (n * a.size()) as u64,
643                a.as_ptr(),
644                a.cols() as u64,
645                (n * a.size()) as u64,
646            )
647        }
648    }
649
650    fn vec_znx_rotate(&self, k: i64, b: &mut VecZnx, a: &VecZnx) {
651        let n: usize = self.n();
652        #[cfg(debug_assertions)]
653        {
654            assert_eq!(a.n(), n);
655            assert_eq!(b.n(), n);
656        }
657        unsafe {
658            vec_znx::vec_znx_rotate(
659                self.ptr,
660                k,
661                b.as_mut_ptr(),
662                b.cols() as u64,
663                (n * b.size()) as u64,
664                a.as_ptr(),
665                a.cols() as u64,
666                (n * a.size()) as u64,
667            )
668        }
669    }
670
671    fn vec_znx_rotate_inplace(&self, k: i64, a: &mut VecZnx) {
672        let n: usize = self.n();
673        #[cfg(debug_assertions)]
674        {
675            assert_eq!(a.n(), n);
676        }
677        unsafe {
678            vec_znx::vec_znx_rotate(
679                self.ptr,
680                k,
681                a.as_mut_ptr(),
682                a.cols() as u64,
683                (n * a.size()) as u64,
684                a.as_ptr(),
685                a.cols() as u64,
686                (n * a.size()) as u64,
687            )
688        }
689    }
690
691    /// Maps X^i to X^{ik} mod X^{n}+1. The mapping is applied independently on each cols.
692    ///
693    /// # Arguments
694    ///
695    /// * `a`: input.
696    /// * `b`: output.
697    /// * `k`: the power to which to map each coefficients.
698    /// * `a_cols`: the number of a_cols on which to apply the mapping.
699    ///
700    /// # Panics
701    ///
702    /// The method will panic if the argument `a` is greater than `a.cols()`.
703    fn vec_znx_automorphism(&self, k: i64, b: &mut VecZnx, a: &VecZnx) {
704        let n: usize = self.n();
705        #[cfg(debug_assertions)]
706        {
707            assert_eq!(a.n(), n);
708            assert_eq!(b.n(), n);
709        }
710        unsafe {
711            vec_znx::vec_znx_automorphism(
712                self.ptr,
713                k,
714                b.as_mut_ptr(),
715                b.cols() as u64,
716                (n * b.size()) as u64,
717                a.as_ptr(),
718                a.cols() as u64,
719                (n * a.size()) as u64,
720            );
721        }
722    }
723
724    /// Maps X^i to X^{ik} mod X^{n}+1. The mapping is applied independently on each cols.
725    ///
726    /// # Arguments
727    ///
728    /// * `a`: input and output.
729    /// * `k`: the power to which to map each coefficients.
730    /// * `a_cols`: the number of cols on which to apply the mapping.
731    ///
732    /// # Panics
733    ///
734    /// The method will panic if the argument `cols` is greater than `self.cols()`.
735    fn vec_znx_automorphism_inplace(&self, k: i64, a: &mut VecZnx) {
736        let n: usize = self.n();
737        #[cfg(debug_assertions)]
738        {
739            assert_eq!(a.n(), n);
740        }
741        unsafe {
742            vec_znx::vec_znx_automorphism(
743                self.ptr,
744                k,
745                a.as_mut_ptr(),
746                a.cols() as u64,
747                (n * a.size()) as u64,
748                a.as_ptr(),
749                a.cols() as u64,
750                (n * a.size()) as u64,
751            );
752        }
753    }
754
755    fn vec_znx_split(&self, b: &mut Vec<VecZnx>, a: &VecZnx, buf: &mut VecZnx) {
756        let (n_in, n_out) = (a.n(), b[0].n());
757
758        debug_assert!(
759            n_out < n_in,
760            "invalid a: output ring degree should be smaller"
761        );
762        b[1..].iter().for_each(|bi| {
763            debug_assert_eq!(
764                bi.n(),
765                n_out,
766                "invalid input a: all VecZnx must have the same degree"
767            )
768        });
769
770        b.iter_mut().enumerate().for_each(|(i, bi)| {
771            if i == 0 {
772                switch_degree(bi, a);
773                self.vec_znx_rotate(-1, buf, a);
774            } else {
775                switch_degree(bi, buf);
776                self.vec_znx_rotate_inplace(-1, buf);
777            }
778        })
779    }
780
781    fn vec_znx_merge(&self, b: &mut VecZnx, a: &Vec<VecZnx>) {
782        let (n_in, n_out) = (b.n(), a[0].n());
783
784        debug_assert!(
785            n_out < n_in,
786            "invalid a: output ring degree should be smaller"
787        );
788        a[1..].iter().for_each(|ai| {
789            debug_assert_eq!(
790                ai.n(),
791                n_out,
792                "invalid input a: all VecZnx must have the same degree"
793            )
794        });
795
796        a.iter().enumerate().for_each(|(_, ai)| {
797            switch_degree(b, ai);
798            self.vec_znx_rotate_inplace(-1, b);
799        });
800
801        self.vec_znx_rotate_inplace(a.len() as i64, b);
802    }
803}