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