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