arnaucube
arnaucube/poulpyPublic Self-hosted repository
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}