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