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