arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/glwe/encryption.rs
core/src/glwe/encryption.rsRaw
  1use backend::hal::{
  2    api::{
  3        ScalarZnxAllocBytes, ScratchAvailable, SvpApply, SvpApplyInplace, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx,
  4        TakeSvpPPol, TakeVecZnx, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxBigAddNormal, VecZnxBigAddSmallInplace,
  5        VecZnxBigAllocBytes, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftFromVecZnx, VecZnxDftToVecZnxBigConsume,
  6        VecZnxFillUniform, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSubABInplace, ZnxZero,
  7    },
  8    layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnxBig},
  9};
 10use sampling::source::Source;
 11
 12use crate::{GLWECiphertext, GLWEPlaintext, GLWEPublicKeyExec, GLWESecretExec, Infos, SIX_SIGMA, dist::Distribution};
 13
 14pub trait GLWEEncryptSkFamily<B: Backend> = VecZnxDftAllocBytes
 15    + VecZnxBigNormalize<B>
 16    + VecZnxDftFromVecZnx<B>
 17    + SvpApplyInplace<B>
 18    + VecZnxDftToVecZnxBigConsume<B>
 19    + VecZnxNormalizeTmpBytes
 20    + VecZnxFillUniform
 21    + VecZnxSubABInplace
 22    + VecZnxAddInplace
 23    + VecZnxNormalizeInplace<B>
 24    + VecZnxAddNormal
 25    + VecZnxNormalize<B>;
 26
 27pub trait GLWEEncryptPkFamily<B: Backend> = VecZnxDftAllocBytes
 28    + VecZnxBigAllocBytes
 29    + SvpPPolAllocBytes
 30    + SvpPrepare<B>
 31    + SvpApply<B>
 32    + VecZnxDftToVecZnxBigConsume<B>
 33    + VecZnxBigAddNormal<B>
 34    + VecZnxBigAddSmallInplace<B>
 35    + VecZnxBigNormalize<B>
 36    + ScalarZnxAllocBytes
 37    + VecZnxNormalizeTmpBytes;
 38
 39impl GLWECiphertext<Vec<u8>> {
 40    pub fn encrypt_sk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize) -> usize
 41    where
 42        Module<B>: GLWEEncryptSkFamily<B>,
 43    {
 44        let size: usize = k.div_ceil(basek);
 45        module.vec_znx_normalize_tmp_bytes(module.n())
 46            + module.vec_znx_dft_alloc_bytes(1, size)
 47            + module.vec_znx_dft_alloc_bytes(1, size)
 48    }
 49    pub fn encrypt_pk_scratch_space<B: Backend>(module: &Module<B>, basek: usize, k: usize) -> usize
 50    where
 51        Module<B>: GLWEEncryptPkFamily<B>,
 52    {
 53        let size: usize = k.div_ceil(basek);
 54        ((module.vec_znx_dft_alloc_bytes(1, size) + module.vec_znx_big_alloc_bytes(1, size)) | module.scalar_znx_alloc_bytes(1))
 55            + module.svp_ppol_alloc_bytes(1)
 56            + module.vec_znx_normalize_tmp_bytes(module.n())
 57    }
 58}
 59
 60impl<DataSelf: DataMut> GLWECiphertext<DataSelf> {
 61    pub fn encrypt_sk<DataPt: DataRef, DataSk: DataRef, B: Backend>(
 62        &mut self,
 63        module: &Module<B>,
 64        pt: &GLWEPlaintext<DataPt>,
 65        sk: &GLWESecretExec<DataSk, B>,
 66        source_xa: &mut Source,
 67        source_xe: &mut Source,
 68        sigma: f64,
 69        scratch: &mut Scratch<B>,
 70    ) where
 71        Module<B>: GLWEEncryptSkFamily<B>,
 72        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
 73    {
 74        self.encrypt_sk_private(
 75            module,
 76            Some((pt, 0)),
 77            sk,
 78            source_xa,
 79            source_xe,
 80            sigma,
 81            scratch,
 82        );
 83    }
 84
 85    pub fn encrypt_zero_sk<DataSk: DataRef, B: Backend>(
 86        &mut self,
 87        module: &Module<B>,
 88        sk: &GLWESecretExec<DataSk, B>,
 89        source_xa: &mut Source,
 90        source_xe: &mut Source,
 91        sigma: f64,
 92        scratch: &mut Scratch<B>,
 93    ) where
 94        Module<B>: GLWEEncryptSkFamily<B>,
 95        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
 96    {
 97        self.encrypt_sk_private(
 98            module,
 99            None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
100            sk,
101            source_xa,
102            source_xe,
103            sigma,
104            scratch,
105        );
106    }
107
108    pub fn encrypt_pk<DataPt: DataRef, DataPk: DataRef, B: Backend>(
109        &mut self,
110        module: &Module<B>,
111        pt: &GLWEPlaintext<DataPt>,
112        pk: &GLWEPublicKeyExec<DataPk, B>,
113        source_xu: &mut Source,
114        source_xe: &mut Source,
115        sigma: f64,
116        scratch: &mut Scratch<B>,
117    ) where
118        Module<B>: GLWEEncryptPkFamily<B>,
119        Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
120    {
121        self.encrypt_pk_private::<DataPt, DataPk, B>(
122            module,
123            Some((pt, 0)),
124            pk,
125            source_xu,
126            source_xe,
127            sigma,
128            scratch,
129        );
130    }
131
132    pub fn encrypt_zero_pk<DataPk: DataRef, B: Backend>(
133        &mut self,
134        module: &Module<B>,
135        pk: &GLWEPublicKeyExec<DataPk, B>,
136        source_xu: &mut Source,
137        source_xe: &mut Source,
138        sigma: f64,
139        scratch: &mut Scratch<B>,
140    ) where
141        Module<B>: GLWEEncryptPkFamily<B>,
142        Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
143    {
144        self.encrypt_pk_private::<Vec<u8>, DataPk, B>(
145            module,
146            None::<(&GLWEPlaintext<Vec<u8>>, usize)>,
147            pk,
148            source_xu,
149            source_xe,
150            sigma,
151            scratch,
152        );
153    }
154
155    pub(crate) fn encrypt_sk_private<DataPt: DataRef, DataSk: DataRef, B: Backend>(
156        &mut self,
157        module: &Module<B>,
158        pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
159        sk: &GLWESecretExec<DataSk, B>,
160        source_xa: &mut Source,
161        source_xe: &mut Source,
162        sigma: f64,
163        scratch: &mut Scratch<B>,
164    ) where
165        Module<B>: GLWEEncryptSkFamily<B>,
166        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable + TakeVecZnx<B>,
167    {
168        #[cfg(debug_assertions)]
169        {
170            assert_eq!(self.rank(), sk.rank());
171            assert_eq!(sk.n(), module.n());
172            assert_eq!(self.n(), module.n());
173            if let Some((pt, col)) = pt {
174                assert_eq!(pt.n(), module.n());
175                assert!(col < self.rank() + 1);
176            }
177            assert!(
178                scratch.available() >= GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k()),
179                "scratch.available(): {} < GLWECiphertext::encrypt_sk_scratch_space: {}",
180                scratch.available(),
181                GLWECiphertext::encrypt_sk_scratch_space(module, self.basek(), self.k())
182            )
183        }
184
185        let basek: usize = self.basek();
186        let k: usize = self.k();
187        let size: usize = self.size();
188        let cols: usize = self.rank() + 1;
189
190        let (mut c0, scratch_1) = scratch.take_vec_znx(module, 1, size);
191        c0.zero();
192
193        {
194            // c[i] = uniform
195            // c[0] -= c[i] * s[i],
196            (1..cols).for_each(|i| {
197                let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(module, 1, size);
198
199                // c[i] = uniform
200                module.vec_znx_fill_uniform(basek, &mut self.data, i, k, source_xa);
201
202                // c[i] = norm(IDFT(DFT(c[i]) * DFT(s[i])))
203                module.vec_znx_dft_from_vec_znx(1, 0, &mut ci_dft, 0, &self.data, i);
204                module.svp_apply_inplace(&mut ci_dft, 0, &sk.data, i - 1);
205                let ci_big: VecZnxBig<&mut [u8], B> = module.vec_znx_dft_to_vec_znx_big_consume(ci_dft);
206
207                // use c[0] as buffer, which is overwritten later by the normalization step
208                module.vec_znx_big_normalize(basek, &mut self.data, 0, &ci_big, 0, scratch_2);
209
210                // c0_tmp = -c[i] * s[i] (use c[0] as buffer)
211                module.vec_znx_sub_ab_inplace(&mut c0, 0, &self.data, 0);
212
213                // c[i] += m if col = i
214                if let Some((pt, col)) = pt {
215                    if i == col {
216                        module.vec_znx_add_inplace(&mut self.data, i, &pt.data, 0);
217                        module.vec_znx_normalize_inplace(basek, &mut self.data, i, scratch_2);
218                    }
219                }
220            });
221        }
222
223        // c[0] += e
224        module.vec_znx_add_normal(basek, &mut c0, 0, k, source_xe, sigma, sigma * SIX_SIGMA);
225
226        // c[0] += m if col = 0
227        if let Some((pt, col)) = pt {
228            if col == 0 {
229                module.vec_znx_add_inplace(&mut c0, 0, &pt.data, 0);
230            }
231        }
232
233        // c[0] = norm(c[0])
234        module.vec_znx_normalize(basek, &mut self.data, 0, &c0, 0, scratch_1);
235    }
236
237    pub(crate) fn encrypt_pk_private<DataPt: DataRef, DataPk: DataRef, B: Backend>(
238        &mut self,
239        module: &Module<B>,
240        pt: Option<(&GLWEPlaintext<DataPt>, usize)>,
241        pk: &GLWEPublicKeyExec<DataPk, B>,
242        source_xu: &mut Source,
243        source_xe: &mut Source,
244        sigma: f64,
245        scratch: &mut Scratch<B>,
246    ) where
247        Module<B>: VecZnxDftAllocBytes
248            + SvpPPolAllocBytes
249            + SvpPrepare<B>
250            + SvpApply<B>
251            + VecZnxDftToVecZnxBigConsume<B>
252            + VecZnxBigAddNormal<B>
253            + VecZnxBigAddSmallInplace<B>
254            + VecZnxBigNormalize<B>,
255        Scratch<B>: TakeVecZnxDft<B> + TakeSvpPPol<B> + TakeScalarZnx<B>,
256    {
257        #[cfg(debug_assertions)]
258        {
259            assert_eq!(self.basek(), pk.basek());
260            assert_eq!(self.n(), module.n());
261            assert_eq!(pk.n(), module.n());
262            assert_eq!(self.rank(), pk.rank());
263            if let Some((pt, _)) = pt {
264                assert_eq!(pt.basek(), pk.basek());
265                assert_eq!(pt.n(), module.n());
266            }
267        }
268
269        let basek: usize = pk.basek();
270        let size_pk: usize = pk.size();
271        let cols: usize = self.rank() + 1;
272
273        // Generates u according to the underlying secret distribution.
274        let (mut u_dft, scratch_1) = scratch.take_svp_ppol(module, 1);
275
276        {
277            let (mut u, _) = scratch_1.take_scalar_znx(module, 1);
278            match pk.dist {
279                Distribution::NONE => panic!(
280                    "invalid public key: SecretDistribution::NONE, ensure it has been correctly intialized through \
281                     Self::generate"
282                ),
283                Distribution::TernaryFixed(hw) => u.fill_ternary_hw(0, hw, source_xu),
284                Distribution::TernaryProb(prob) => u.fill_ternary_prob(0, prob, source_xu),
285                Distribution::BinaryFixed(hw) => u.fill_binary_hw(0, hw, source_xu),
286                Distribution::BinaryProb(prob) => u.fill_binary_prob(0, prob, source_xu),
287                Distribution::BinaryBlock(block_size) => u.fill_binary_block(0, block_size, source_xu),
288                Distribution::ZERO => {}
289            }
290
291            module.svp_prepare(&mut u_dft, 0, &u, 0);
292        }
293
294        // ct[i] = pk[i] * u + ei (+ m if col = i)
295        (0..cols).for_each(|i| {
296            let (mut ci_dft, scratch_2) = scratch_1.take_vec_znx_dft(module, 1, size_pk);
297            // ci_dft = DFT(u) * DFT(pk[i])
298            module.svp_apply(&mut ci_dft, 0, &u_dft, 0, &pk.data, i);
299
300            // ci_big = u * p[i]
301            let mut ci_big = module.vec_znx_dft_to_vec_znx_big_consume(ci_dft);
302
303            // ci_big = u * pk[i] + e
304            module.vec_znx_big_add_normal(
305                basek,
306                &mut ci_big,
307                0,
308                pk.k(),
309                source_xe,
310                sigma,
311                sigma * SIX_SIGMA,
312            );
313
314            // ci_big = u * pk[i] + e + m (if col = i)
315            if let Some((pt, col)) = pt {
316                if col == i {
317                    module.vec_znx_big_add_small_inplace(&mut ci_big, 0, &pt.data, 0);
318                }
319            }
320
321            // ct[i] = norm(ci_big)
322            module.vec_znx_big_normalize(basek, &mut self.data, i, &ci_big, 0, scratch_2);
323        });
324    }
325}