poulpy/poulpy-core/src/encryption/lwe_ct.rs
poulpy-core/src/encryption/lwe_ct.rsRaw
1use poulpy_hal::{
2 api::{ScratchOwnedAlloc, ScratchOwnedBorrow, ZnAddNormal, ZnFillUniform, ZnNormalizeInplace},
3 layouts::{Backend, DataMut, Module, ScratchOwned, Zn, ZnxView, ZnxViewMut},
4 oep::{ScratchOwnedAllocImpl, ScratchOwnedBorrowImpl},
5 source::Source,
6};
7
8use crate::{
9 encryption::{SIGMA, SIGMA_BOUND},
10 layouts::{LWE, LWEInfos, LWEPlaintext, LWEPlaintextToRef, LWESecret, LWESecretToRef, LWEToMut},
11};
12
13impl<DataSelf: DataMut> LWE<DataSelf> {
14 pub fn encrypt_sk<P, S, M, BE: Backend>(&mut self, module: &M, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source)
15 where
16 P: LWEPlaintextToRef,
17 S: LWESecretToRef,
18 M: LWEEncryptSk<BE>,
19 BE: Backend + ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE>,
20 {
21 module.lwe_encrypt_sk(self, pt, sk, source_xa, source_xe);
22 }
23}
24
25pub trait LWEEncryptSk<BE: Backend> {
26 fn lwe_encrypt_sk<R, P, S>(&self, res: &mut R, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source)
27 where
28 R: LWEToMut,
29 P: LWEPlaintextToRef,
30 S: LWESecretToRef;
31}
32
33impl<BE: Backend> LWEEncryptSk<BE> for Module<BE>
34where
35 Self: Sized + ZnFillUniform + ZnAddNormal + ZnNormalizeInplace<BE>,
36 BE: ScratchOwnedAllocImpl<BE> + ScratchOwnedBorrowImpl<BE>,
37{
38 fn lwe_encrypt_sk<R, P, S>(&self, res: &mut R, pt: &P, sk: &S, source_xa: &mut Source, source_xe: &mut Source)
39 where
40 R: LWEToMut,
41 P: LWEPlaintextToRef,
42 S: LWESecretToRef,
43 {
44 let res: &mut LWE<&mut [u8]> = &mut res.to_mut();
45 let pt: &LWEPlaintext<&[u8]> = &pt.to_ref();
46 let sk: &LWESecret<&[u8]> = &sk.to_ref();
47
48 #[cfg(debug_assertions)]
49 {
50 assert_eq!(res.n(), sk.n())
51 }
52
53 let base2k: usize = res.base2k().into();
54 let k: usize = res.k().into();
55
56 self.zn_fill_uniform((res.n() + 1).into(), base2k, &mut res.data, 0, source_xa);
57
58 let mut tmp_znx: Zn<Vec<u8>> = Zn::alloc(1, 1, res.size());
59
60 let min_size = res.size().min(pt.size());
61
62 (0..min_size).for_each(|i| {
63 tmp_znx.at_mut(0, i)[0] = pt.data.at(0, i)[0]
64 - res.data.at(0, i)[1..]
65 .iter()
66 .zip(sk.data.at(0, 0))
67 .map(|(x, y)| x * y)
68 .sum::<i64>();
69 });
70
71 (min_size..res.size()).for_each(|i| {
72 tmp_znx.at_mut(0, i)[0] -= res.data.at(0, i)[1..]
73 .iter()
74 .zip(sk.data.at(0, 0))
75 .map(|(x, y)| x * y)
76 .sum::<i64>();
77 });
78
79 self.zn_add_normal(
80 1,
81 base2k,
82 &mut res.data,
83 0,
84 k,
85 source_xe,
86 SIGMA,
87 SIGMA_BOUND,
88 );
89
90 self.zn_normalize_inplace(
91 1,
92 base2k,
93 &mut tmp_znx,
94 0,
95 ScratchOwned::alloc(size_of::<i64>()).borrow(),
96 );
97
98 (0..res.size()).for_each(|i| {
99 res.data.at_mut(0, i)[0] = tmp_znx.at(0, i)[0];
100 });
101 }
102}