poulpy/base2k/src/vec_znx.rs
base2k/src/vec_znx.rsRaw
1use crate::Backend;
2use crate::Module;
3use crate::assert_alignement;
4use crate::cast_mut;
5use crate::ffi::znx;
6use crate::znx_base::{GetZnxBase, ZnxAlloc, ZnxBase, ZnxBasics, ZnxInfos, ZnxLayout, ZnxSliceSize, switch_degree};
7use std::cmp::min;
8
9pub const VEC_ZNX_ROWS: usize = 1;
10
11/// [VecZnx] represents collection of contiguously stacked vector of small norm polynomials of
12/// Zn\[X\] with [i64] coefficients.
13/// A [VecZnx] is composed of multiple Zn\[X\] polynomials stored in a single contiguous array
14/// in the memory.
15///
16/// # Example
17///
18/// Given 3 polynomials (a, b, c) of Zn\[X\], each with 4 columns, then the memory
19/// layout is: `[a0, b0, c0, a1, b1, c1, a2, b2, c2, a3, b3, c3]`, where ai, bi, ci
20/// are small polynomials of Zn\[X\].
21pub struct VecZnx {
22 pub inner: ZnxBase,
23}
24
25impl GetZnxBase for VecZnx {
26 fn znx(&self) -> &ZnxBase {
27 &self.inner
28 }
29
30 fn znx_mut(&mut self) -> &mut ZnxBase {
31 &mut self.inner
32 }
33}
34
35impl ZnxInfos for VecZnx {}
36
37impl ZnxSliceSize for VecZnx {
38 fn sl(&self) -> usize {
39 self.cols() * self.n()
40 }
41}
42
43impl ZnxLayout for VecZnx {
44 type Scalar = i64;
45}
46
47impl ZnxBasics for VecZnx {}
48
49impl<B: Backend> ZnxAlloc<B> for VecZnx {
50 type Scalar = i64;
51
52 fn from_bytes_borrow(module: &Module<B>, _rows: usize, cols: usize, size: usize, bytes: &mut [u8]) -> VecZnx {
53 debug_assert_eq!(bytes.len(), Self::bytes_of(module, _rows, cols, size));
54 VecZnx {
55 inner: ZnxBase::from_bytes_borrow(module.n(), VEC_ZNX_ROWS, cols, size, bytes),
56 }
57 }
58
59 fn bytes_of(module: &Module<B>, _rows: usize, cols: usize, size: usize) -> usize {
60 debug_assert_eq!(
61 _rows, VEC_ZNX_ROWS,
62 "rows != {} not supported for VecZnx",
63 VEC_ZNX_ROWS
64 );
65 module.n() * cols * size * size_of::<Self::Scalar>()
66 }
67}
68
69/// Copies the coefficients of `a` on the receiver.
70/// Copy is done with the minimum size matching both backing arrays.
71/// Panics if the cols do not match.
72pub fn copy_vec_znx_from(b: &mut VecZnx, a: &VecZnx) {
73 assert_eq!(b.cols(), a.cols());
74 let data_a: &[i64] = a.raw();
75 let data_b: &mut [i64] = b.raw_mut();
76 let size = min(data_b.len(), data_a.len());
77 data_b[..size].copy_from_slice(&data_a[..size])
78}
79
80impl VecZnx {
81 /// Truncates the precision of the [VecZnx] by k bits.
82 ///
83 /// # Arguments
84 ///
85 /// * `log_base2k`: the base two logarithm of the coefficients decomposition.
86 /// * `k`: the number of bits of precision to drop.
87 pub fn trunc_pow2(&mut self, log_base2k: usize, k: usize) {
88 if k == 0 {
89 return;
90 }
91
92 if !self.borrowing() {
93 self.inner
94 .data
95 .truncate(self.n() * self.cols() * (self.size() - k / log_base2k));
96 }
97
98 self.inner.size -= k / log_base2k;
99
100 let k_rem: usize = k % log_base2k;
101
102 if k_rem != 0 {
103 let mask: i64 = ((1 << (log_base2k - k_rem - 1)) - 1) << k_rem;
104 self.at_limb_mut(self.size() - 1)
105 .iter_mut()
106 .for_each(|x: &mut i64| *x &= mask)
107 }
108 }
109
110 pub fn copy_from(&mut self, a: &Self) {
111 copy_vec_znx_from(self, a);
112 }
113
114 pub fn normalize(&mut self, log_base2k: usize, carry: &mut [u8]) {
115 normalize(log_base2k, self, carry)
116 }
117
118 pub fn switch_degree(&self, col: usize, a: &mut Self, col_a: usize) {
119 switch_degree(a, col_a, self, col)
120 }
121
122 // Prints the first `n` coefficients of each limb
123 pub fn print(&self, n: usize) {
124 (0..self.size()).for_each(|i| println!("{}: {:?}", i, &self.at_limb(i)[..n]))
125 }
126}
127
128fn normalize_tmp_bytes(n: usize, size: usize) -> usize {
129 n * size * std::mem::size_of::<i64>()
130}
131
132fn normalize(log_base2k: usize, a: &mut VecZnx, tmp_bytes: &mut [u8]) {
133 let n: usize = a.n();
134 let cols: usize = a.cols();
135
136 debug_assert!(
137 tmp_bytes.len() >= normalize_tmp_bytes(n, cols),
138 "invalid tmp_bytes: tmp_bytes.len()={} < normalize_tmp_bytes({}, {})",
139 tmp_bytes.len(),
140 n,
141 cols,
142 );
143 #[cfg(debug_assertions)]
144 {
145 assert_alignement(tmp_bytes.as_ptr())
146 }
147
148 let carry_i64: &mut [i64] = cast_mut(tmp_bytes);
149
150 unsafe {
151 znx::znx_zero_i64_ref(n as u64, carry_i64.as_mut_ptr());
152 (0..a.size()).rev().for_each(|i| {
153 znx::znx_normalize(
154 (n * cols) as u64,
155 log_base2k as u64,
156 a.at_mut_ptr(0, i),
157 carry_i64.as_mut_ptr(),
158 a.at_mut_ptr(0, i),
159 carry_i64.as_mut_ptr(),
160 )
161 });
162 }
163}