poulpy/base2k/src/vec_znx.rs
base2k/src/vec_znx.rsRaw
1use crate::DataView;
2use crate::DataViewMut;
3use crate::ZnxSliceSize;
4use crate::alloc_aligned;
5use crate::assert_alignement;
6use crate::cast_mut;
7use crate::ffi::znx;
8use crate::znx_base::{ZnxInfos, ZnxView, ZnxViewMut};
9use std::{cmp::min, fmt};
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<D> {
22 pub data: D,
23 n: usize,
24 cols: usize,
25 size: usize,
26}
27
28impl<D> ZnxInfos for VecZnx<D> {
29 fn cols(&self) -> usize {
30 self.cols
31 }
32
33 fn rows(&self) -> usize {
34 1
35 }
36
37 fn n(&self) -> usize {
38 self.n
39 }
40
41 fn size(&self) -> usize {
42 self.size
43 }
44}
45
46impl<D> ZnxSliceSize for VecZnx<D> {
47 fn sl(&self) -> usize {
48 self.n() * self.cols()
49 }
50}
51
52impl<D> DataView for VecZnx<D> {
53 type D = D;
54 fn data(&self) -> &Self::D {
55 &self.data
56 }
57}
58
59impl<D> DataViewMut for VecZnx<D> {
60 fn data_mut(&mut self) -> &mut Self::D {
61 &mut self.data
62 }
63}
64
65impl<D: AsRef<[u8]>> ZnxView for VecZnx<D> {
66 type Scalar = i64;
67}
68
69impl<D: AsMut<[u8]> + AsRef<[u8]>> VecZnx<D> {
70 /// Truncates the precision of the [VecZnx] by k bits.
71 ///
72 /// # Arguments
73 ///
74 /// * `log_base2k`: the base two logarithm of the coefficients decomposition.
75 /// * `k`: the number of bits of precision to drop.
76 pub fn trunc_pow2(&mut self, log_base2k: usize, k: usize, col: usize) {
77 if k == 0 {
78 return;
79 }
80
81 self.size -= k / log_base2k;
82
83 let k_rem: usize = k % log_base2k;
84
85 if k_rem != 0 {
86 let mask: i64 = ((1 << (log_base2k - k_rem - 1)) - 1) << k_rem;
87 self.at_mut(col, self.size() - 1)
88 .iter_mut()
89 .for_each(|x: &mut i64| *x &= mask)
90 }
91 }
92}
93
94impl<D: From<Vec<u8>>> VecZnx<D> {
95 pub(crate) fn bytes_of<Scalar: Sized>(n: usize, cols: usize, size: usize) -> usize {
96 n * cols * size * size_of::<Scalar>()
97 }
98
99 pub(crate) fn new<Scalar: Sized>(n: usize, cols: usize, size: usize) -> Self {
100 let data = alloc_aligned::<u8>(Self::bytes_of::<Scalar>(n, cols, size));
101 Self {
102 data: data.into(),
103 n,
104 cols,
105 size,
106 }
107 }
108
109 pub(crate) fn new_from_bytes<Scalar: Sized>(n: usize, cols: usize, size: usize, bytes: impl Into<Vec<u8>>) -> Self {
110 let data: Vec<u8> = bytes.into();
111 assert!(data.len() == Self::bytes_of::<Scalar>(n, cols, size));
112 Self {
113 data: data.into(),
114 n,
115 cols,
116 size,
117 }
118 }
119}
120
121impl<D> VecZnx<D> {
122 pub(crate) fn from_data(data: D, n: usize, cols: usize, size: usize) -> Self {
123 Self {
124 data,
125 n,
126 cols,
127 size,
128 }
129 }
130}
131
132/// Copies the coefficients of `a` on the receiver.
133/// Copy is done with the minimum size matching both backing arrays.
134/// Panics if the cols do not match.
135pub fn copy_vec_znx_from<DataMut, Data>(b: &mut VecZnx<DataMut>, a: &VecZnx<Data>)
136where
137 DataMut: AsMut<[u8]> + AsRef<[u8]>,
138 Data: AsRef<[u8]>,
139{
140 assert_eq!(b.cols(), a.cols());
141 let data_a: &[i64] = a.raw();
142 let data_b: &mut [i64] = b.raw_mut();
143 let size = min(data_b.len(), data_a.len());
144 data_b[..size].copy_from_slice(&data_a[..size])
145}
146
147#[allow(dead_code)]
148fn normalize_tmp_bytes(n: usize) -> usize {
149 n * std::mem::size_of::<i64>()
150}
151
152#[allow(dead_code)]
153fn normalize<D: AsMut<[u8]> + AsRef<[u8]>>(log_base2k: usize, a: &mut VecZnx<D>, a_col: usize, tmp_bytes: &mut [u8]) {
154 let n: usize = a.n();
155
156 debug_assert!(
157 tmp_bytes.len() >= normalize_tmp_bytes(n),
158 "invalid tmp_bytes: tmp_bytes.len()={} < normalize_tmp_bytes({})",
159 tmp_bytes.len(),
160 n,
161 );
162
163 #[cfg(debug_assertions)]
164 {
165 assert_alignement(tmp_bytes.as_ptr())
166 }
167
168 let carry_i64: &mut [i64] = cast_mut(tmp_bytes);
169
170 unsafe {
171 znx::znx_zero_i64_ref(n as u64, carry_i64.as_mut_ptr());
172 (0..a.size()).rev().for_each(|i| {
173 znx::znx_normalize(
174 n as u64,
175 log_base2k as u64,
176 a.at_mut_ptr(a_col, i),
177 carry_i64.as_mut_ptr(),
178 a.at_mut_ptr(a_col, i),
179 carry_i64.as_mut_ptr(),
180 )
181 });
182 }
183}
184
185impl<D: AsRef<[u8]>> fmt::Display for VecZnx<D> {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 writeln!(
188 f,
189 "VecZnx(n={}, cols={}, size={})",
190 self.n, self.cols, self.size
191 )?;
192
193 for col in 0..self.cols {
194 writeln!(f, "Column {}:", col)?;
195 for size in 0..self.size {
196 let coeffs = self.at(col, size);
197 write!(f, " Size {}: [", size)?;
198
199 let max_show = 100;
200 let show_count = coeffs.len().min(max_show);
201
202 for (i, &coeff) in coeffs.iter().take(show_count).enumerate() {
203 if i > 0 {
204 write!(f, ", ")?;
205 }
206 write!(f, "{}", coeff)?;
207 }
208
209 if coeffs.len() > max_show {
210 write!(f, ", ... ({} more)", coeffs.len() - max_show)?;
211 }
212
213 writeln!(f, "]")?;
214 }
215 }
216 Ok(())
217 }
218}
219
220pub type VecZnxOwned = VecZnx<Vec<u8>>;
221pub type VecZnxMut<'a> = VecZnx<&'a mut [u8]>;
222pub type VecZnxRef<'a> = VecZnx<&'a [u8]>;
223
224pub trait VecZnxToRef {
225 fn to_ref(&self) -> VecZnx<&[u8]>;
226}
227
228pub trait VecZnxToMut {
229 fn to_mut(&mut self) -> VecZnx<&mut [u8]>;
230}
231
232impl VecZnxToMut for VecZnx<Vec<u8>> {
233 fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
234 VecZnx {
235 data: self.data.as_mut_slice(),
236 n: self.n,
237 cols: self.cols,
238 size: self.size,
239 }
240 }
241}
242
243impl VecZnxToRef for VecZnx<Vec<u8>> {
244 fn to_ref(&self) -> VecZnx<&[u8]> {
245 VecZnx {
246 data: self.data.as_slice(),
247 n: self.n,
248 cols: self.cols,
249 size: self.size,
250 }
251 }
252}
253
254impl VecZnxToMut for VecZnx<&mut [u8]> {
255 fn to_mut(&mut self) -> VecZnx<&mut [u8]> {
256 VecZnx {
257 data: self.data,
258 n: self.n,
259 cols: self.cols,
260 size: self.size,
261 }
262 }
263}
264
265impl VecZnxToRef for VecZnx<&mut [u8]> {
266 fn to_ref(&self) -> VecZnx<&[u8]> {
267 VecZnx {
268 data: self.data,
269 n: self.n,
270 cols: self.cols,
271 size: self.size,
272 }
273 }
274}
275
276impl VecZnxToRef for VecZnx<&[u8]> {
277 fn to_ref(&self) -> VecZnx<&[u8]> {
278 VecZnx {
279 data: self.data,
280 n: self.n,
281 cols: self.cols,
282 size: self.size,
283 }
284 }
285}