arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/base2k/src/svp.rs
base2k/src/svp.rsRaw
  1use crate::ffi::svp;
  2use crate::ffi::vec_znx_dft::vec_znx_dft_t;
  3use crate::{assert_alignement, Module, VecZnx, VecZnxDft};
  4
  5use crate::{alloc_aligned, cast_mut, Infos};
  6use rand::seq::SliceRandom;
  7use rand_core::RngCore;
  8use rand_distr::{Distribution, WeightedIndex};
  9use sampling::source::Source;
 10
 11pub struct Scalar {
 12    pub n: usize,
 13    pub data: Vec<i64>,
 14    pub ptr: *mut i64,
 15}
 16
 17impl Module {
 18    pub fn new_scalar(&self) -> Scalar {
 19        Scalar::new(self.n())
 20    }
 21}
 22
 23impl Scalar {
 24    pub fn new(n: usize) -> Self {
 25        let mut data: Vec<i64> = alloc_aligned::<i64>(n);
 26        let ptr: *mut i64 = data.as_mut_ptr();
 27        Self {
 28            n: n,
 29            data: data,
 30            ptr: ptr,
 31        }
 32    }
 33
 34    pub fn n(&self) -> usize {
 35        self.n
 36    }
 37
 38    pub fn buffer_size(n: usize) -> usize {
 39        n
 40    }
 41
 42    pub fn from_buffer(&mut self, n: usize, bytes: &mut [u8]) -> Self {
 43        let size: usize = Self::buffer_size(n);
 44        debug_assert!(
 45            bytes.len() == size,
 46            "invalid buffer: bytes.len()={} < self.buffer_size(n={})={}",
 47            bytes.len(),
 48            n,
 49            size
 50        );
 51        #[cfg(debug_assertions)]
 52        {
 53            assert_alignement(bytes.as_ptr())
 54        }
 55        unsafe {
 56            let bytes_i64: &mut [i64] = cast_mut::<u8, i64>(bytes);
 57            let ptr: *mut i64 = bytes_i64.as_mut_ptr();
 58            Self {
 59                n: n,
 60                data: Vec::from_raw_parts(bytes_i64.as_mut_ptr(), bytes.len(), bytes.len()),
 61                ptr: ptr,
 62            }
 63        }
 64    }
 65
 66    pub fn as_ptr(&self) -> *const i64 {
 67        self.ptr
 68    }
 69
 70    pub fn raw(&self) -> &[i64] {
 71        unsafe { std::slice::from_raw_parts_mut(self.ptr, self.n) }
 72    }
 73
 74    pub fn fill_ternary_prob(&mut self, prob: f64, source: &mut Source) {
 75        let choices: [i64; 3] = [-1, 0, 1];
 76        let weights: [f64; 3] = [prob / 2.0, 1.0 - prob, prob / 2.0];
 77        let dist: WeightedIndex<f64> = WeightedIndex::new(&weights).unwrap();
 78        self.data
 79            .iter_mut()
 80            .for_each(|x: &mut i64| *x = choices[dist.sample(source)]);
 81    }
 82
 83    pub fn fill_ternary_hw(&mut self, hw: usize, source: &mut Source) {
 84        assert!(hw <= self.n());
 85        self.data[..hw]
 86            .iter_mut()
 87            .for_each(|x: &mut i64| *x = (((source.next_u32() & 1) as i64) << 1) - 1);
 88        self.data.shuffle(source);
 89    }
 90}
 91
 92pub struct SvpPPol(pub *mut svp::svp_ppol_t, pub usize);
 93
 94/// A prepared [crate::Scalar] for [SvpPPolOps::svp_apply_dft].
 95/// An [SvpPPol] an be seen as a [VecZnxDft] of one limb.
 96/// The backend array of an [SvpPPol] is allocated in C and must be freed manually.
 97impl SvpPPol {
 98    /// Returns the ring degree of the [SvpPPol].
 99    pub fn n(&self) -> usize {
100        self.1
101    }
102
103    pub fn from_bytes(size: usize, bytes: &mut [u8]) -> SvpPPol {
104        #[cfg(debug_assertions)]
105        {
106            assert_alignement(bytes.as_ptr())
107        }
108        debug_assert!(bytes.len() << 3 >= size);
109        SvpPPol(bytes.as_mut_ptr() as *mut svp::svp_ppol_t, size)
110    }
111
112    /// Returns the number of cols of the [SvpPPol], which is always 1.
113    pub fn cols(&self) -> usize {
114        1
115    }
116}
117
118pub trait SvpPPolOps {
119    /// Allocates a new [SvpPPol].
120    fn new_svp_ppol(&self) -> SvpPPol;
121
122    /// Returns the minimum number of bytes necessary to allocate
123    /// a new [SvpPPol] through [SvpPPol::from_bytes].
124    fn bytes_of_svp_ppol(&self) -> usize;
125
126    /// Prepares a [crate::Scalar] for a [SvpPPolOps::svp_apply_dft].
127    fn svp_prepare(&self, svp_ppol: &mut SvpPPol, a: &Scalar);
128
129    /// Applies the [SvpPPol] x [VecZnxDft] product, where each limb of
130    /// the [VecZnxDft] is multiplied with [SvpPPol].
131    fn svp_apply_dft(&self, c: &mut VecZnxDft, a: &SvpPPol, b: &VecZnx, b_cols: usize);
132}
133
134impl SvpPPolOps for Module {
135    fn new_svp_ppol(&self) -> SvpPPol {
136        unsafe { SvpPPol(svp::new_svp_ppol(self.ptr), self.n()) }
137    }
138
139    fn bytes_of_svp_ppol(&self) -> usize {
140        unsafe { svp::bytes_of_svp_ppol(self.ptr) as usize }
141    }
142
143    fn svp_prepare(&self, svp_ppol: &mut SvpPPol, a: &Scalar) {
144        unsafe { svp::svp_prepare(self.ptr, svp_ppol.0, a.as_ptr()) }
145    }
146
147    fn svp_apply_dft(&self, c: &mut VecZnxDft, a: &SvpPPol, b: &VecZnx, b_cols: usize) {
148        debug_assert!(
149            c.cols() >= b_cols,
150            "invalid c_vector: c_vector.cols()={} < b.cols()={}",
151            c.cols(),
152            b_cols
153        );
154        unsafe {
155            svp::svp_apply_dft(
156                self.ptr,
157                c.ptr as *mut vec_znx_dft_t,
158                b_cols as u64,
159                a.0,
160                b.as_ptr(),
161                b_cols as u64,
162                b.n() as u64,
163            )
164        }
165    }
166}