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