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}