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}