arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/gglwe_ciphertext.rs
core/src/gglwe_ciphertext.rsRaw
  1use backend::{
  2    Backend, FFT64, MatZnxDft, MatZnxDftAlloc, MatZnxDftOps, Module, ScalarZnx, Scratch, VecZnxAlloc, VecZnxDftAlloc, VecZnxOps,
  3    ZnxInfos, ZnxZero,
  4};
  5use sampling::source::Source;
  6
  7use crate::{GLWECiphertext, GLWECiphertextFourier, GLWESecret, GetRow, Infos, ScratchCore, SetRow, div_ceil};
  8
  9pub struct GGLWECiphertext<C, B: Backend> {
 10    pub(crate) data: MatZnxDft<C, B>,
 11    pub(crate) basek: usize,
 12    pub(crate) k: usize,
 13    pub(crate) digits: usize,
 14}
 15
 16impl<B: Backend> GGLWECiphertext<Vec<u8>, B> {
 17    pub fn alloc(module: &Module<B>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> Self {
 18        Self {
 19            data: module.new_mat_znx_dft(div_ceil(rows, digits), rank_in, rank_out + 1, div_ceil(basek, k)),
 20            basek: basek,
 21            k,
 22            digits,
 23        }
 24    }
 25
 26    pub fn bytes_of(module: &Module<FFT64>, basek: usize, k: usize, rows: usize, digits: usize, rank_in: usize, rank_out: usize) -> usize {
 27        module.bytes_of_mat_znx_dft(div_ceil(rows, digits), rank_in, rank_out + 1, div_ceil(basek, k))
 28    }
 29}
 30
 31impl<T, B: Backend> Infos for GGLWECiphertext<T, B> {
 32    type Inner = MatZnxDft<T, B>;
 33
 34    fn inner(&self) -> &Self::Inner {
 35        &self.data
 36    }
 37
 38    fn basek(&self) -> usize {
 39        self.basek
 40    }
 41
 42    fn k(&self) -> usize {
 43        self.k
 44    }
 45}
 46
 47impl<T, B: Backend> GGLWECiphertext<T, B> {
 48    pub fn rank(&self) -> usize {
 49        self.data.cols_out() - 1
 50    }
 51
 52    pub fn digits(&self) -> usize{
 53        self.digits
 54    }
 55
 56    pub fn rank_in(&self) -> usize {
 57        self.data.cols_in()
 58    }
 59
 60    pub fn rank_out(&self) -> usize {
 61        self.data.cols_out() - 1
 62    }
 63}
 64
 65impl GGLWECiphertext<Vec<u8>, FFT64> {
 66    pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
 67        let size = div_ceil(basek, k);
 68        GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
 69            + module.bytes_of_vec_znx(rank + 1, size)
 70            + module.bytes_of_vec_znx(1, size)
 71            + module.bytes_of_vec_znx_dft(rank + 1, size)
 72    }
 73
 74    pub fn generate_from_pk_scratch_space(_module: &Module<FFT64>, _basek: usize, _k: usize, _rank: usize) -> usize {
 75        unimplemented!()
 76    }
 77}
 78
 79impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GGLWECiphertext<DataSelf, FFT64> {
 80    pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>(
 81        &mut self,
 82        module: &Module<FFT64>,
 83        pt: &ScalarZnx<DataPt>,
 84        sk: &GLWESecret<DataSk, FFT64>,
 85        source_xa: &mut Source,
 86        source_xe: &mut Source,
 87        sigma: f64,
 88        scratch: &mut Scratch,
 89    ) {
 90        #[cfg(debug_assertions)]
 91        {
 92            assert_eq!(self.rank_in(), pt.cols());
 93            assert_eq!(self.rank_out(), sk.rank());
 94            assert_eq!(self.n(), module.n());
 95            assert_eq!(sk.n(), module.n());
 96            assert_eq!(pt.n(), module.n());
 97            assert!(
 98                scratch.available()
 99                    >= GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank()),
100                "scratch.available: {} < GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank()={}, \
101                 self.size()={}): {}",
102                scratch.available(),
103                self.rank(),
104                self.size(),
105                GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank())
106            )
107        }
108
109        let rows: usize = self.rows();
110        let digits: usize = self.digits();
111        let basek: usize = self.basek();
112        let k: usize = self.k();
113        let rank_in: usize = self.rank_in();
114        let rank_out: usize = self.rank_out();
115
116        let (mut tmp_pt, scrach_1) = scratch.tmp_glwe_pt(module, basek, k);
117        let (mut tmp_ct, scrach_2) = scrach_1.tmp_glwe_ct(module, basek, k, rank_out);
118        let (mut tmp_ct_dft, scratch_3) = scrach_2.tmp_glwe_fourier(module, basek, k, rank_out);
119
120        // For each input column (i.e. rank) produces a GGLWE ciphertext of rank_out+1 columns
121        //
122        // Example for ksk rank 2 to rank 3:
123        //
124        // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2)
125        // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2)
126        //
127        // Example ksk rank 2 to rank 1
128        //
129        // (-(a*s) + s0, a)
130        // (-(b*s) + s1, b)
131        (0..rank_in).for_each(|col_i| {
132            (0..rows).for_each(|row_i| {
133                // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
134                tmp_pt.data.zero(); // zeroes for next iteration
135                module.vec_znx_add_scalar_inplace(&mut tmp_pt.data, 0, row_i * digits, pt, col_i);
136                module.vec_znx_normalize_inplace(basek, &mut tmp_pt.data, 0, scratch_3);
137
138                // rlwe encrypt of vec_znx_pt into vec_znx_ct
139                tmp_ct.encrypt_sk(module, &tmp_pt, sk, source_xa, source_xe, sigma, scratch_3);
140
141                // Switch vec_znx_ct into DFT domain
142                tmp_ct.dft(module, &mut tmp_ct_dft);
143
144                // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
145                self.set_row(module, row_i, col_i, &tmp_ct_dft);
146            });
147        });
148    }
149}
150
151impl<C: AsRef<[u8]>> GetRow<FFT64> for GGLWECiphertext<C, FFT64> {
152    fn get_row<R: AsMut<[u8]> + AsRef<[u8]>>(
153        &self,
154        module: &Module<FFT64>,
155        row_i: usize,
156        col_j: usize,
157        res: &mut GLWECiphertextFourier<R, FFT64>,
158    ) {
159        module.vmp_extract_row(&mut res.data, &self.data, row_i, col_j);
160    }
161}
162
163impl<C: AsMut<[u8]> + AsRef<[u8]>> SetRow<FFT64> for GGLWECiphertext<C, FFT64> {
164    fn set_row<R: AsRef<[u8]>>(
165        &mut self,
166        module: &Module<FFT64>,
167        row_i: usize,
168        col_j: usize,
169        a: &GLWECiphertextFourier<R, FFT64>,
170    ) {
171        module.vmp_prepare_row(&mut self.data, row_i, col_j, &a.data);
172    }
173}