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