arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/operations/glwe.rs
poulpy-core/src/operations/glwe.rsRaw
  1use poulpy_hal::{
  2    api::{
  3        Convolution, ModuleN, VecZnxAdd, VecZnxAddInplace, VecZnxCopy, VecZnxMulXpMinusOne, VecZnxMulXpMinusOneInplace, VecZnxNegateInplace, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxRotate, VecZnxRotateInplace, VecZnxRshInplace, VecZnxSub, VecZnxSubInplace, VecZnxSubNegateInplace, VecZnxZero
  4    },
  5    layouts::{Backend, Module, Scratch, VecZnx, ZnxZero},
  6    reference::vec_znx::vec_znx_rotate_inplace_tmp_bytes,
  7};
  8
  9use crate::{
 10    layouts::{GLWEInfos, GLWETensor, GLWETensorToMut, GLWEToMut, GLWEToRef, LWEInfos, SetGLWEInfos, TorusPrecision, GLWE}, ScratchTakeCore
 11};
 12
 13pub trait GLWETensoring<BE: Backend> where Self: Convolution<BE>, Scratch<BE>: ScratchTakeCore<BE> {
 14    fn glwe_tensor<R, A, B>(&self, res: &mut R, res_scale: i64, a: &A, b: &B, scratch: &mut Scratch<BE>) where R: GLWETensorToMut, A: GLWEToRef, B: GLWEToRef{
 15
 16        let res: &mut GLWETensor<&mut [u8]> = &mut res.to_mut();
 17        let a: &mut GLWE<&[u8]> = &mut a.to_ref();
 18        let b: &GLWE<&[u8]> = &b.to_ref();
 19
 20        self.bivariate_convolution(res.data_mut(), res_scale, a, b, scratch);
 21    }
 22}
 23
 24pub trait GLWEAdd
 25where
 26    Self: ModuleN + VecZnxAdd + VecZnxCopy + VecZnxAddInplace,
 27{
 28    fn glwe_add<R, A, B>(&self, res: &mut R, a: &A, b: &B)
 29    where
 30        R: GLWEToMut,
 31        A: GLWEToRef,
 32        B: GLWEToRef,
 33    {
 34        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
 35        let a: &mut GLWE<&[u8]> = &mut a.to_ref();
 36        let b: &GLWE<&[u8]> = &b.to_ref();
 37
 38        assert_eq!(a.n(), self.n() as u32);
 39        assert_eq!(b.n(), self.n() as u32);
 40        assert_eq!(res.n(), self.n() as u32);
 41        assert_eq!(a.base2k(), b.base2k());
 42        assert!(res.rank() >= a.rank().max(b.rank()));
 43
 44        let min_col: usize = (a.rank().min(b.rank()) + 1).into();
 45        let max_col: usize = (a.rank().max(b.rank() + 1)).into();
 46        let self_col: usize = (res.rank() + 1).into();
 47
 48        (0..min_col).for_each(|i| {
 49            self.vec_znx_add(res.data_mut(), i, a.data(), i, b.data(), i);
 50        });
 51
 52        if a.rank() > b.rank() {
 53            (min_col..max_col).for_each(|i| {
 54                self.vec_znx_copy(res.data_mut(), i, a.data(), i);
 55            });
 56        } else {
 57            (min_col..max_col).for_each(|i| {
 58                self.vec_znx_copy(res.data_mut(), i, b.data(), i);
 59            });
 60        }
 61
 62        let size: usize = res.size();
 63        (max_col..self_col).for_each(|i| {
 64            (0..size).for_each(|j| {
 65                res.data.zero_at(i, j);
 66            });
 67        });
 68
 69        res.set_base2k(a.base2k());
 70        res.set_k(set_k_binary(res, a, b));
 71    }
 72
 73    fn glwe_add_inplace<R, A>(&self, res: &mut R, a: &A)
 74    where
 75        R: GLWEToMut,
 76        A: GLWEToRef,
 77    {
 78        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
 79        let a: &GLWE<&[u8]> = &a.to_ref();
 80
 81        assert_eq!(res.n(), self.n() as u32);
 82        assert_eq!(a.n(), self.n() as u32);
 83        assert_eq!(res.base2k(), a.base2k());
 84        assert!(res.rank() >= a.rank());
 85
 86        (0..(a.rank() + 1).into()).for_each(|i| {
 87            self.vec_znx_add_inplace(res.data_mut(), i, a.data(), i);
 88        });
 89
 90        res.set_k(set_k_unary(res, a))
 91    }
 92}
 93
 94impl<BE: Backend> GLWEAdd for Module<BE> where Self: ModuleN + VecZnxAdd + VecZnxCopy + VecZnxAddInplace {}
 95
 96impl<BE: Backend> GLWESub for Module<BE> where
 97    Self: ModuleN + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxSubInplace + VecZnxSubNegateInplace
 98{
 99}
100
101pub trait GLWESub
102where
103    Self: ModuleN + VecZnxSub + VecZnxCopy + VecZnxNegateInplace + VecZnxSubInplace + VecZnxSubNegateInplace,
104{
105    fn glwe_sub<R, A, B>(&self, res: &mut R, a: &A, b: &B)
106    where
107        R: GLWEToMut,
108        A: GLWEToRef,
109        B: GLWEToRef,
110    {
111        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
112        let a: &GLWE<&[u8]> = &a.to_ref();
113        let b: &GLWE<&[u8]> = &b.to_ref();
114
115        assert_eq!(a.n(), self.n() as u32);
116        assert_eq!(b.n(), self.n() as u32);
117        assert_eq!(a.base2k(), b.base2k());
118        assert!(res.rank() >= a.rank().max(b.rank()));
119
120        let min_col: usize = (a.rank().min(b.rank()) + 1).into();
121        let max_col: usize = (a.rank().max(b.rank() + 1)).into();
122        let self_col: usize = (res.rank() + 1).into();
123
124        (0..min_col).for_each(|i| {
125            self.vec_znx_sub(res.data_mut(), i, a.data(), i, b.data(), i);
126        });
127
128        if a.rank() > b.rank() {
129            (min_col..max_col).for_each(|i| {
130                self.vec_znx_copy(res.data_mut(), i, a.data(), i);
131            });
132        } else {
133            (min_col..max_col).for_each(|i| {
134                self.vec_znx_copy(res.data_mut(), i, b.data(), i);
135                self.vec_znx_negate_inplace(res.data_mut(), i);
136            });
137        }
138
139        let size: usize = res.size();
140        (max_col..self_col).for_each(|i| {
141            (0..size).for_each(|j| {
142                res.data.zero_at(i, j);
143            });
144        });
145
146        res.set_base2k(a.base2k());
147        res.set_k(set_k_binary(res, a, b));
148    }
149
150    fn glwe_sub_inplace<R, A>(&self, res: &mut R, a: &A)
151    where
152        R: GLWEToMut,
153        A: GLWEToRef,
154    {
155        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
156        let a: &GLWE<&[u8]> = &a.to_ref();
157
158        assert_eq!(res.n(), self.n() as u32);
159        assert_eq!(a.n(), self.n() as u32);
160        assert_eq!(res.base2k(), a.base2k());
161        assert!(res.rank() >= a.rank());
162
163        (0..(a.rank() + 1).into()).for_each(|i| {
164            self.vec_znx_sub_inplace(res.data_mut(), i, a.data(), i);
165        });
166
167        res.set_k(set_k_unary(res, a))
168    }
169
170    fn glwe_sub_negate_inplace<R, A>(&self, res: &mut R, a: &A)
171    where
172        R: GLWEToMut,
173        A: GLWEToRef,
174    {
175        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
176        let a: &GLWE<&[u8]> = &a.to_ref();
177
178        assert_eq!(res.n(), self.n() as u32);
179        assert_eq!(a.n(), self.n() as u32);
180        assert_eq!(res.base2k(), a.base2k());
181        assert!(res.rank() >= a.rank());
182
183        (0..(a.rank() + 1).into()).for_each(|i| {
184            self.vec_znx_sub_negate_inplace(res.data_mut(), i, a.data(), i);
185        });
186
187        res.set_k(set_k_unary(res, a))
188    }
189}
190
191impl<BE: Backend> GLWERotate<BE> for Module<BE> where Self: ModuleN + VecZnxRotate + VecZnxRotateInplace<BE> {}
192
193pub trait GLWERotate<BE: Backend>
194where
195    Self: ModuleN + VecZnxRotate + VecZnxRotateInplace<BE>,
196{
197    fn glwe_rotate_tmp_bytes(&self) -> usize {
198        vec_znx_rotate_inplace_tmp_bytes(self.n())
199    }
200
201    fn glwe_rotate<R, A>(&self, k: i64, res: &mut R, a: &A)
202    where
203        R: GLWEToMut,
204        A: GLWEToRef,
205    {
206        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
207        let a: &GLWE<&[u8]> = &a.to_ref();
208
209        assert_eq!(a.n(), self.n() as u32);
210        assert_eq!(res.rank(), a.rank());
211
212        (0..(a.rank() + 1).into()).for_each(|i| {
213            self.vec_znx_rotate(k, res.data_mut(), i, a.data(), i);
214        });
215
216        res.set_base2k(a.base2k());
217        res.set_k(set_k_unary(res, a))
218    }
219
220    fn glwe_rotate_inplace<R>(&self, k: i64, res: &mut R, scratch: &mut Scratch<BE>)
221    where
222        R: GLWEToMut,
223        Scratch<BE>: ScratchTakeCore<BE>,
224    {
225        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
226
227        (0..(res.rank() + 1).into()).for_each(|i| {
228            self.vec_znx_rotate_inplace(k, res.data_mut(), i, scratch);
229        });
230    }
231}
232
233impl<BE: Backend> GLWEMulXpMinusOne<BE> for Module<BE> where Self: ModuleN + VecZnxMulXpMinusOne + VecZnxMulXpMinusOneInplace<BE> {}
234
235pub trait GLWEMulXpMinusOne<BE: Backend>
236where
237    Self: ModuleN + VecZnxMulXpMinusOne + VecZnxMulXpMinusOneInplace<BE>,
238{
239    fn glwe_mul_xp_minus_one<R, A>(&self, k: i64, res: &mut R, a: &A)
240    where
241        R: GLWEToMut,
242        A: GLWEToRef,
243    {
244        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
245        let a: &GLWE<&[u8]> = &a.to_ref();
246
247        assert_eq!(res.n(), self.n() as u32);
248        assert_eq!(a.n(), self.n() as u32);
249        assert_eq!(res.rank(), a.rank());
250
251        for i in 0..res.rank().as_usize() + 1 {
252            self.vec_znx_mul_xp_minus_one(k, res.data_mut(), i, a.data(), i);
253        }
254
255        res.set_base2k(a.base2k());
256        res.set_k(set_k_unary(res, a))
257    }
258
259    fn glwe_mul_xp_minus_one_inplace<R>(&self, k: i64, res: &mut R, scratch: &mut Scratch<BE>)
260    where
261        R: GLWEToMut,
262    {
263        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
264
265        assert_eq!(res.n(), self.n() as u32);
266
267        for i in 0..res.rank().as_usize() + 1 {
268            self.vec_znx_mul_xp_minus_one_inplace(k, res.data_mut(), i, scratch);
269        }
270    }
271}
272
273impl<BE: Backend> GLWECopy for Module<BE> where Self: ModuleN + VecZnxCopy + VecZnxZero {}
274
275pub trait GLWECopy
276where
277    Self: ModuleN + VecZnxCopy + VecZnxZero,
278{
279    fn glwe_copy<R, A>(&self, res: &mut R, a: &A)
280    where
281        R: GLWEToMut,
282        A: GLWEToRef,
283    {
284        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
285        let a: &GLWE<&[u8]> = &a.to_ref();
286
287        assert_eq!(res.n(), self.n() as u32);
288        assert_eq!(a.n(), self.n() as u32);
289
290        let min_rank: usize = res.rank().min(a.rank()).as_usize() + 1;
291
292        for i in 0..min_rank {
293            self.vec_znx_copy(res.data_mut(), i, a.data(), i);
294        }
295
296        for i in min_rank..(res.rank() + 1).into() {
297            self.vec_znx_zero(res.data_mut(), i);
298        }
299
300        res.set_k(a.k().min(res.max_k()));
301        res.set_base2k(a.base2k());
302    }
303}
304
305impl<BE: Backend> GLWEShift<BE> for Module<BE> where Self: ModuleN + VecZnxRshInplace<BE> {}
306
307pub trait GLWEShift<BE: Backend>
308where
309    Self: ModuleN + VecZnxRshInplace<BE>,
310{
311    fn glwe_rsh_tmp_byte(&self) -> usize {
312        VecZnx::rsh_tmp_bytes(self.n())
313    }
314
315    fn glwe_rsh<R>(&self, k: usize, res: &mut R, scratch: &mut Scratch<BE>)
316    where
317        R: GLWEToMut,
318        Scratch<BE>: ScratchTakeCore<BE>,
319    {
320        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
321        let base2k: usize = res.base2k().into();
322        for i in 0..res.rank().as_usize() + 1 {
323            self.vec_znx_rsh_inplace(base2k, k, res.data_mut(), i, scratch);
324        }
325    }
326}
327
328impl GLWE<Vec<u8>> {
329    pub fn rsh_tmp_bytes<M, BE: Backend>(module: &M) -> usize
330    where
331        M: GLWEShift<BE>,
332    {
333        module.glwe_rsh_tmp_byte()
334    }
335}
336
337impl<BE: Backend> GLWENormalize<BE> for Module<BE> where Self: ModuleN + VecZnxNormalize<BE> + VecZnxNormalizeInplace<BE> {}
338
339pub trait GLWENormalize<BE: Backend>
340where
341    Self: ModuleN + VecZnxNormalize<BE> + VecZnxNormalizeInplace<BE>,
342{
343    fn glwe_normalize<R, A>(&self, res: &mut R, a: &A, scratch: &mut Scratch<BE>)
344    where
345        R: GLWEToMut,
346        A: GLWEToRef,
347        Scratch<BE>: ScratchTakeCore<BE>,
348    {
349        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
350        let a: &GLWE<&[u8]> = &a.to_ref();
351
352        assert_eq!(res.n(), self.n() as u32);
353        assert_eq!(a.n(), self.n() as u32);
354        assert_eq!(res.rank(), a.rank());
355
356        for i in 0..res.rank().as_usize() + 1 {
357            self.vec_znx_normalize(
358                res.base2k().into(),
359                res.data_mut(),
360                i,
361                a.base2k().into(),
362                a.data(),
363                i,
364                scratch,
365            );
366        }
367
368        res.set_k(a.k().min(res.k()));
369    }
370
371    fn glwe_normalize_inplace<R>(&self, res: &mut R, scratch: &mut Scratch<BE>)
372    where
373        R: GLWEToMut,
374        Scratch<BE>: ScratchTakeCore<BE>,
375    {
376        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
377        for i in 0..res.rank().as_usize() + 1 {
378            self.vec_znx_normalize_inplace(res.base2k().into(), res.data_mut(), i, scratch);
379        }
380    }
381}
382
383// c = op(a, b)
384fn set_k_binary(c: &impl GLWEInfos, a: &impl GLWEInfos, b: &impl GLWEInfos) -> TorusPrecision {
385    // If either operands is a ciphertext
386    if a.rank() != 0 || b.rank() != 0 {
387        // If a is a plaintext (but b ciphertext)
388        let k = if a.rank() == 0 {
389            b.k()
390        // If b is a plaintext (but a ciphertext)
391        } else if b.rank() == 0 {
392            a.k()
393        // If a & b are both ciphertexts
394        } else {
395            a.k().min(b.k())
396        };
397        k.min(c.k())
398    // If a & b are both plaintexts
399    } else {
400        c.k()
401    }
402}
403
404// a = op(a, b)
405fn set_k_unary(a: &impl GLWEInfos, b: &impl GLWEInfos) -> TorusPrecision {
406    if a.rank() != 0 || b.rank() != 0 {
407        a.k().min(b.k())
408    } else {
409        a.k()
410    }
411}