arnaucube
arnaucube/poulpyPublic Self-hosted repository
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, ZnxInfos, ZnxLayout, ZnxRsh, ZnxSliceSize, ZnxZero, 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 ZnxZero for VecZnx {}
 48
 49impl ZnxRsh for VecZnx {}
 50
 51impl<B: Backend> ZnxAlloc<B> for VecZnx {
 52    type Scalar = i64;
 53
 54    fn from_bytes_borrow(module: &Module<B>, _rows: usize, cols: usize, size: usize, bytes: &mut [u8]) -> VecZnx {
 55        debug_assert_eq!(bytes.len(), Self::bytes_of(module, _rows, cols, size));
 56        VecZnx {
 57            inner: ZnxBase::from_bytes_borrow(module.n(), VEC_ZNX_ROWS, cols, size, bytes),
 58        }
 59    }
 60
 61    fn bytes_of(module: &Module<B>, _rows: usize, cols: usize, size: usize) -> usize {
 62        debug_assert_eq!(
 63            _rows, VEC_ZNX_ROWS,
 64            "rows != {} not supported for VecZnx",
 65            VEC_ZNX_ROWS
 66        );
 67        module.n() * cols * size * size_of::<Self::Scalar>()
 68    }
 69}
 70
 71/// Copies the coefficients of `a` on the receiver.
 72/// Copy is done with the minimum size matching both backing arrays.
 73/// Panics if the cols do not match.
 74pub fn copy_vec_znx_from(b: &mut VecZnx, a: &VecZnx) {
 75    assert_eq!(b.cols(), a.cols());
 76    let data_a: &[i64] = a.raw();
 77    let data_b: &mut [i64] = b.raw_mut();
 78    let size = min(data_b.len(), data_a.len());
 79    data_b[..size].copy_from_slice(&data_a[..size])
 80}
 81
 82impl VecZnx {
 83    /// Truncates the precision of the [VecZnx] by k bits.
 84    ///
 85    /// # Arguments
 86    ///
 87    /// * `log_base2k`: the base two logarithm of the coefficients decomposition.
 88    /// * `k`: the number of bits of precision to drop.
 89    pub fn trunc_pow2(&mut self, log_base2k: usize, k: usize, col: usize) {
 90        if k == 0 {
 91            return;
 92        }
 93
 94        if !self.borrowing() {
 95            self.inner
 96                .data
 97                .truncate(self.n() * self.cols() * (self.size() - k / log_base2k));
 98        }
 99
100        self.inner.size -= k / log_base2k;
101
102        let k_rem: usize = k % log_base2k;
103
104        if k_rem != 0 {
105            let mask: i64 = ((1 << (log_base2k - k_rem - 1)) - 1) << k_rem;
106            self.at_mut(col, self.size() - 1)
107                .iter_mut()
108                .for_each(|x: &mut i64| *x &= mask)
109        }
110    }
111
112    pub fn copy_from(&mut self, a: &Self) {
113        copy_vec_znx_from(self, a);
114    }
115
116    pub fn normalize(&mut self, log_base2k: usize, col: usize, carry: &mut [u8]) {
117        normalize(log_base2k, self, col, carry)
118    }
119
120    pub fn switch_degree(&self, col: usize, a: &mut Self, col_a: usize) {
121        switch_degree(a, col_a, self, col)
122    }
123
124    // Prints the first `n` coefficients of each limb
125    pub fn print(&self, n: usize, col: usize) {
126        (0..self.size()).for_each(|j| println!("{}: {:?}", j, &self.at(col, j)[..n]));
127    }
128}
129
130fn normalize_tmp_bytes(n: usize) -> usize {
131    n * std::mem::size_of::<i64>()
132}
133
134fn normalize(log_base2k: usize, a: &mut VecZnx, a_col: usize, tmp_bytes: &mut [u8]) {
135    let n: usize = a.n();
136
137    debug_assert!(
138        tmp_bytes.len() >= normalize_tmp_bytes(n),
139        "invalid tmp_bytes: tmp_bytes.len()={} < normalize_tmp_bytes({})",
140        tmp_bytes.len(),
141        n,
142    );
143
144    #[cfg(debug_assertions)]
145    {
146        assert_alignement(tmp_bytes.as_ptr())
147    }
148
149    let carry_i64: &mut [i64] = cast_mut(tmp_bytes);
150
151    unsafe {
152        znx::znx_zero_i64_ref(n as u64, carry_i64.as_mut_ptr());
153        (0..a.size()).rev().for_each(|i| {
154            znx::znx_normalize(
155                n as u64,
156                log_base2k as u64,
157                a.at_mut_ptr(a_col, i),
158                carry_i64.as_mut_ptr(),
159                a.at_mut_ptr(a_col, i),
160                carry_i64.as_mut_ptr(),
161            )
162        });
163    }
164}