arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/spqlios/src/poly.rs
spqlios/src/poly.rsRaw
  1use crate::{znx_normalize, znx_zero_i64_ref};
  2use itertools::izip;
  3use std::cmp::min;
  4
  5pub struct Poly {
  6    pub n: usize,
  7    pub k: usize,
  8    pub prec: usize,
  9    pub data: Vec<i64>,
 10}
 11
 12impl Poly {
 13    pub fn new(n: usize, k: usize, prec: usize) -> Self {
 14        Self {
 15            n: n,
 16            k: k,
 17            prec: prec,
 18            data: vec![i64::default(); Self::buffer_size(n, k, prec)],
 19        }
 20    }
 21
 22    pub fn buffer_size(n: usize, k: usize, prec: usize) -> usize {
 23        n * ((prec + k - 1) / k)
 24    }
 25
 26    pub fn from_buffer(&mut self, n: usize, k: usize, prec: usize, buf: &[i64]) {
 27        let size = Self::buffer_size(n, k, prec);
 28        assert!(
 29            buf.len() >= size,
 30            "invalid buffer: buf.len()={} < self.buffer_size(n={}, k={}, prec={})={}",
 31            buf.len(),
 32            n,
 33            k,
 34            prec,
 35            size
 36        );
 37        self.n = n;
 38        self.k = k;
 39        self.prec = prec;
 40        self.data = Vec::from(&buf[..size])
 41    }
 42
 43    pub fn log_n(&self) -> usize {
 44        (u64::BITS - (self.n - 1).leading_zeros()) as _
 45    }
 46
 47    pub fn n(&self) -> usize {
 48        self.n
 49    }
 50
 51    pub fn limbs(&self) -> usize {
 52        self.data.len() / self.n
 53    }
 54
 55    pub fn at(&self, i: usize) -> &[i64] {
 56        &self.data[i * self.n..(i + 1) * self.n]
 57    }
 58
 59    pub fn at_ptr(&self, i: usize) -> *const i64 {
 60        &self.data[i * self.n] as *const i64
 61    }
 62
 63    pub fn at_mut_ptr(&mut self, i: usize) -> *mut i64 {
 64        &mut self.data[i * self.n] as *mut i64
 65    }
 66
 67    pub fn at_mut(&mut self, i: usize) -> &mut [i64] {
 68        &mut self.data[i * self.n..(i + 1) * self.n]
 69    }
 70
 71    pub fn set_i64(&mut self, data: &[i64], log_max: usize) {
 72        let size: usize = min(data.len(), self.n());
 73        let k_rem: usize = self.k - (self.prec % self.k);
 74
 75        // If 2^{base} * 2^{k_rem} < 2^{63}-1, then we can simply copy
 76        // values on the last limb.
 77        // Else we decompose values base k.
 78        if log_max + k_rem < 63 || k_rem == self.k {
 79            self.at_mut(self.limbs() - 1).copy_from_slice(&data[..size]);
 80        } else {
 81            let mask: i64 = (1 << self.k) - 1;
 82            let limbs = self.limbs();
 83            let steps: usize = min(limbs, (log_max + k_rem + self.k - 1) / self.k);
 84            (limbs - steps..limbs)
 85                .rev()
 86                .enumerate()
 87                .for_each(|(i, i_rev)| {
 88                    let shift: usize = i * self.k;
 89                    izip!(self.at_mut(i_rev)[..size].iter_mut(), data[..size].iter())
 90                        .for_each(|(y, x)| *y = (x >> shift) & mask);
 91                })
 92        }
 93
 94        // Case where self.prec % self.k != 0.
 95        if k_rem != self.k {
 96            let limbs = self.limbs();
 97            let steps: usize = min(limbs, (log_max + k_rem + self.k - 1) / self.k);
 98            (limbs - steps..limbs).rev().for_each(|i| {
 99                self.at_mut(i)[..size].iter_mut().for_each(|x| *x <<= k_rem);
100            })
101        }
102    }
103
104    pub fn normalize(&mut self, carry: &mut [i64]) {
105        assert!(
106            carry.len() >= self.n,
107            "invalid carry: carry.len()={} < self.n()={}",
108            carry.len(),
109            self.n()
110        );
111        unsafe {
112            znx_zero_i64_ref(self.n() as u64, carry.as_mut_ptr());
113            (0..self.limbs()).rev().for_each(|i| {
114                znx_normalize(
115                    self.n as u64,
116                    self.k as u64,
117                    self.at_mut_ptr(i),
118                    carry.as_mut_ptr(),
119                    self.at_mut_ptr(i),
120                    carry.as_mut_ptr(),
121                )
122            });
123        }
124    }
125
126    pub fn get_i64(&self, data: &mut [i64]) {
127        assert!(
128            data.len() >= self.n,
129            "invalid data: data.len()={} < self.n()={}",
130            data.len(),
131            self.n
132        );
133        data.copy_from_slice(self.at(0));
134        let rem: usize = self.k - (self.prec % self.k);
135        (1..self.limbs()).for_each(|i| {
136            if i == self.limbs() - 1 && rem != self.k {
137                let k_rem: usize = self.k - rem;
138                izip!(self.at(i).iter(), data.iter_mut()).for_each(|(x, y)| {
139                    *y = (*y << k_rem) + (x >> rem);
140                });
141            } else {
142                izip!(self.at(i).iter(), data.iter_mut()).for_each(|(x, y)| {
143                    *y = (*y << self.k) + x;
144                });
145            }
146        })
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use crate::poly::Poly;
153    use itertools::izip;
154    use sampling::source::Source;
155
156    #[test]
157    fn test_set_get_i64_lo_norm() {
158        let n: usize = 32;
159        let k: usize = 19;
160        let prec: usize = 128;
161        let mut a: Poly = Poly::new(n, k, prec);
162        let mut have: Vec<i64> = vec![i64::default(); n];
163        have.iter_mut()
164            .enumerate()
165            .for_each(|(i, x)| *x = (i as i64) - (n as i64) / 2);
166        a.set_i64(&have, 10);
167        let mut want = vec![i64::default(); n];
168        a.get_i64(&mut want);
169        izip!(want, have).for_each(|(a, b)| assert_eq!(a, b));
170    }
171
172    #[test]
173    fn test_set_get_i64_hi_norm() {
174        let n: usize = 1;
175        let k: usize = 19;
176        let prec: usize = 128;
177        let mut a: Poly = Poly::new(n, k, prec);
178        let mut have: Vec<i64> = vec![i64::default(); n];
179        let mut source = Source::new([1; 32]);
180        have.iter_mut().for_each(|x| {
181            *x = source
182                .next_u64n(u64::MAX, u64::MAX)
183                .wrapping_sub(u64::MAX / 2 + 1) as i64;
184        });
185        a.set_i64(&have, 63);
186        let mut want = vec![i64::default(); n];
187        a.get_i64(&mut want);
188        izip!(want, have).for_each(|(a, b)| assert_eq!(a, b));
189    }
190}