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