arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/gglwe/encryption.rs
core/src/gglwe/encryption.rsRaw
  1use backend::{
  2    FFT64, Module, ScalarZnx, ScalarZnxDftOps, ScalarZnxOps, Scratch, VecZnxAlloc, VecZnxDftAlloc, VecZnxOps, ZnxInfos, ZnxZero,
  3};
  4use sampling::source::Source;
  5
  6use crate::{
  7    FourierGLWESecret, GGLWECiphertext, GLWEAutomorphismKey, GLWECiphertext, GLWESecret, GLWESwitchingKey, GLWETensorKey, Infos,
  8    ScratchCore, SetRow, div_ceil,
  9};
 10
 11impl GGLWECiphertext<Vec<u8>, FFT64> {
 12    pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
 13        let size = div_ceil(k, basek);
 14        GLWECiphertext::encrypt_sk_scratch_space(module, basek, k)
 15            + module.bytes_of_vec_znx(rank + 1, size)
 16            + module.bytes_of_vec_znx(1, size)
 17            + module.bytes_of_vec_znx_dft(rank + 1, size)
 18    }
 19
 20    pub fn generate_from_pk_scratch_space(_module: &Module<FFT64>, _basek: usize, _k: usize, _rank: usize) -> usize {
 21        unimplemented!()
 22    }
 23}
 24
 25impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GGLWECiphertext<DataSelf, FFT64> {
 26    pub fn encrypt_sk<DataPt: AsRef<[u8]>, DataSk: AsRef<[u8]>>(
 27        &mut self,
 28        module: &Module<FFT64>,
 29        pt: &ScalarZnx<DataPt>,
 30        sk: &FourierGLWESecret<DataSk, FFT64>,
 31        source_xa: &mut Source,
 32        source_xe: &mut Source,
 33        sigma: f64,
 34        scratch: &mut Scratch,
 35    ) {
 36        #[cfg(debug_assertions)]
 37        {
 38            assert_eq!(self.rank_in(), pt.cols());
 39            assert_eq!(self.rank_out(), sk.rank());
 40            assert_eq!(self.n(), module.n());
 41            assert_eq!(sk.n(), module.n());
 42            assert_eq!(pt.n(), module.n());
 43            assert!(
 44                scratch.available()
 45                    >= GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank()),
 46                "scratch.available: {} < GGLWECiphertext::generate_from_sk_scratch_space(module, self.rank()={}, \
 47                 self.size()={}): {}",
 48                scratch.available(),
 49                self.rank(),
 50                self.size(),
 51                GGLWECiphertext::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank())
 52            );
 53            assert!(
 54                self.rows() * self.digits() * self.basek() <= self.k(),
 55                "self.rows() : {} * self.digits() : {} * self.basek() : {} = {} >= self.k() = {}",
 56                self.rows(),
 57                self.digits(),
 58                self.basek(),
 59                self.rows() * self.digits() * self.basek(),
 60                self.k()
 61            );
 62        }
 63
 64        let rows: usize = self.rows();
 65        let digits: usize = self.digits();
 66        let basek: usize = self.basek();
 67        let k: usize = self.k();
 68        let rank_in: usize = self.rank_in();
 69        let rank_out: usize = self.rank_out();
 70
 71        let (mut tmp_pt, scrach_1) = scratch.tmp_glwe_pt(module, basek, k);
 72        let (mut tmp_ct, scrach_2) = scrach_1.tmp_glwe_ct(module, basek, k, rank_out);
 73        let (mut tmp_ct_dft, scratch_3) = scrach_2.tmp_glwe_fourier(module, basek, k, rank_out);
 74
 75        // For each input column (i.e. rank) produces a GGLWE ciphertext of rank_out+1 columns
 76        //
 77        // Example for ksk rank 2 to rank 3:
 78        //
 79        // (-(a0*s0 + a1*s1 + a2*s2) + s0', a0, a1, a2)
 80        // (-(b0*s0 + b1*s1 + b2*s2) + s0', b0, b1, b2)
 81        //
 82        // Example ksk rank 2 to rank 1
 83        //
 84        // (-(a*s) + s0, a)
 85        // (-(b*s) + s1, b)
 86        (0..rank_in).for_each(|col_i| {
 87            (0..rows).for_each(|row_i| {
 88                // Adds the scalar_znx_pt to the i-th limb of the vec_znx_pt
 89                tmp_pt.data.zero(); // zeroes for next iteration
 90                module.vec_znx_add_scalar_inplace(
 91                    &mut tmp_pt.data,
 92                    0,
 93                    (digits - 1) + row_i * digits,
 94                    pt,
 95                    col_i,
 96                );
 97                module.vec_znx_normalize_inplace(basek, &mut tmp_pt.data, 0, scratch_3);
 98
 99                // rlwe encrypt of vec_znx_pt into vec_znx_ct
100                tmp_ct.encrypt_sk(module, &tmp_pt, sk, source_xa, source_xe, sigma, scratch_3);
101
102                // Switch vec_znx_ct into DFT domain
103                tmp_ct.dft(module, &mut tmp_ct_dft);
104
105                // Stores vec_znx_dft_ct into thw i-th row of the MatZnxDft
106                self.set_row(module, row_i, col_i, &tmp_ct_dft);
107            });
108        });
109    }
110}
111
112impl GLWESwitchingKey<Vec<u8>, FFT64> {
113    pub fn encrypt_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
114        GGLWECiphertext::generate_from_sk_scratch_space(module, basek, k, rank)
115    }
116
117    pub fn encrypt_pk_scratch_space(module: &Module<FFT64>, _basek: usize, _k: usize, _rank: usize) -> usize {
118        GGLWECiphertext::generate_from_pk_scratch_space(module, _basek, _k, _rank)
119    }
120}
121
122impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWESwitchingKey<DataSelf, FFT64> {
123    pub fn generate_from_sk<DataSkIn: AsRef<[u8]>, DataSkOut: AsRef<[u8]>>(
124        &mut self,
125        module: &Module<FFT64>,
126        sk_in: &GLWESecret<DataSkIn>,
127        sk_out: &FourierGLWESecret<DataSkOut, FFT64>,
128        source_xa: &mut Source,
129        source_xe: &mut Source,
130        sigma: f64,
131        scratch: &mut Scratch,
132    ) {
133        self.0.encrypt_sk(
134            module,
135            &sk_in.data,
136            sk_out,
137            source_xa,
138            source_xe,
139            sigma,
140            scratch,
141        );
142    }
143}
144
145impl GLWEAutomorphismKey<Vec<u8>, FFT64> {
146    pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
147        GGLWECiphertext::generate_from_sk_scratch_space(module, basek, k, rank) + GLWESecret::bytes_of(module, rank)
148    }
149
150    pub fn generate_from_pk_scratch_space(module: &Module<FFT64>, _basek: usize, _k: usize, _rank: usize) -> usize {
151        GGLWECiphertext::generate_from_pk_scratch_space(module, _basek, _k, _rank)
152    }
153}
154
155impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWEAutomorphismKey<DataSelf, FFT64> {
156    pub fn generate_from_sk<DataSk: AsRef<[u8]>>(
157        &mut self,
158        module: &Module<FFT64>,
159        p: i64,
160        sk: &GLWESecret<DataSk>,
161        source_xa: &mut Source,
162        source_xe: &mut Source,
163        sigma: f64,
164        scratch: &mut Scratch,
165    ) {
166        #[cfg(debug_assertions)]
167        {
168            assert_eq!(self.n(), module.n());
169            assert_eq!(sk.n(), module.n());
170            assert_eq!(self.rank_out(), self.rank_in());
171            assert_eq!(sk.rank(), self.rank());
172            assert!(
173                scratch.available()
174                    >= GLWEAutomorphismKey::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank()),
175                "scratch.available(): {} < AutomorphismKey::generate_from_sk_scratch_space(module, self.rank()={}, \
176                 self.size()={}): {}",
177                scratch.available(),
178                self.rank(),
179                self.size(),
180                GLWEAutomorphismKey::generate_from_sk_scratch_space(module, self.basek(), self.k(), self.rank())
181            )
182        }
183
184        let (mut sk_out_dft, scratch_1) = scratch.tmp_fourier_sk(module, sk.rank());
185
186        {
187            let (mut sk_out, _) = scratch_1.tmp_sk(module, sk.rank());
188            (0..self.rank()).for_each(|i| {
189                module.scalar_znx_automorphism(
190                    module.galois_element_inv(p),
191                    &mut sk_out.data,
192                    i,
193                    &sk.data,
194                    i,
195                );
196            });
197            sk_out_dft.set(module, &sk_out);
198        }
199
200        self.key.generate_from_sk(
201            module,
202            &sk,
203            &sk_out_dft,
204            source_xa,
205            source_xe,
206            sigma,
207            scratch_1,
208        );
209
210        self.p = p;
211    }
212}
213
214impl GLWETensorKey<Vec<u8>, FFT64> {
215    pub fn generate_from_sk_scratch_space(module: &Module<FFT64>, basek: usize, k: usize, rank: usize) -> usize {
216        GLWESecret::bytes_of(module, 1)
217            + FourierGLWESecret::bytes_of(module, 1)
218            + GLWESwitchingKey::encrypt_sk_scratch_space(module, basek, k, rank)
219    }
220}
221
222impl<DataSelf: AsMut<[u8]> + AsRef<[u8]>> GLWETensorKey<DataSelf, FFT64> {
223    pub fn generate_from_sk<DataSk: AsRef<[u8]>>(
224        &mut self,
225        module: &Module<FFT64>,
226        sk: &FourierGLWESecret<DataSk, FFT64>,
227        source_xa: &mut Source,
228        source_xe: &mut Source,
229        sigma: f64,
230        scratch: &mut Scratch,
231    ) {
232        #[cfg(debug_assertions)]
233        {
234            assert_eq!(self.rank(), sk.rank());
235            assert_eq!(self.n(), module.n());
236            assert_eq!(sk.n(), module.n());
237        }
238
239        let rank: usize = self.rank();
240
241        let (mut sk_ij, scratch1) = scratch.tmp_sk(module, 1);
242        let (mut sk_ij_dft, scratch2) = scratch1.tmp_fourier_sk(module, 1);
243
244        (0..rank).for_each(|i| {
245            (i..rank).for_each(|j| {
246                module.svp_apply(&mut sk_ij_dft.data, 0, &sk.data, i, &sk.data, j);
247                module.scalar_znx_idft(&mut sk_ij.data, 0, &sk_ij_dft.data, 0, scratch2);
248                self.at_mut(i, j)
249                    .generate_from_sk(module, &sk_ij, sk, source_xa, source_xe, sigma, scratch2);
250            });
251        })
252    }
253}