poulpy/poulpy-core/src/keyswitching/lwe_ct.rs
poulpy-core/src/keyswitching/lwe_ct.rsRaw
1use poulpy_hal::{
2 api::{
3 ScratchAvailable, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxCopy, VecZnxDftApply,
4 VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft,
5 VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
6 },
7 layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero},
8};
9
10use crate::{
11 keyswitching::glwe_ct::GLWEKeySwitch,
12 layouts::{prepared::LWESwitchingKeyPrepared, GGLWEInfos, GLWEAlloc, GLWELayout, GetDegree, LWEToRef, LWEInfos, Rank, TorusPrecision, GLWE, LWE},
13};
14
15pub trait LWEKeySwitch<BE: Backend>
16where
17 Self: GLWEKeySwitch<BE> + GLWEAlloc,
18{
19 fn keyswitch_tmp_bytes<B: Backend, R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
20 where
21 R: LWEInfos,
22 A: LWEInfos,
23 K: GGLWEInfos,
24 {
25 let max_k: TorusPrecision = a_infos.k().max(res_infos.k());
26
27 let glwe_a_infos: GLWELayout = GLWELayout {
28 n: GetDegree::n(self),
29 base2k: a_infos.base2k(),
30 k: max_k,
31 rank: Rank(1),
32 };
33
34 let glwe_res_infos: GLWELayout = GLWELayout {
35 n: GetDegree::n(self),
36 base2k: res_infos.base2k(),
37 k: max_k,
38 rank: Rank(1),
39 };
40
41 let glwe_in: usize = GLWE::bytes_of_from_infos(self, &glwe_a_infos);
42 let glwe_out: usize = GLWE::bytes_of_from_infos(self, &glwe_res_infos);
43 let ks: usize = self.glwe_keyswitch_tmp_bytes(&glwe_res_infos, &glwe_a_infos, key_infos);
44
45 glwe_in + glwe_out + ks
46 }
47
48 fn keyswitch<A, DKs, B: Backend>(
49 &mut self,
50 module: &Module<B>,
51 a: &A,
52 ksk: &K,
53 scratch: &mut Scratch<B>,
54 ) where
55 A: LWEToRef,
56 DKs: DataRef,
57 Scratch<B>: ScratchAvailable,
58 {
59 assert!(self.n() <= module.n() as u32);
60 assert!(a.n() <= module.n() as u32);
61 assert!(scratch.available() >= LWE::keyswitch_tmp_bytes(module, self, a, ksk));
62
63 let max_k: TorusPrecision = self.k().max(a.k());
64
65 let a_size: usize = a.k().div_ceil(ksk.base2k()) as usize;
66
67 let (mut glwe_in, scratch_1) = scratch.take_glwe_ct(&GLWELayout {
68 n: ksk.n(),
69 base2k: a.base2k(),
70 k: max_k,
71 rank: Rank(1),
72 });
73 glwe_in.data.zero();
74
75 let (mut glwe_out, scratch_1) = scratch_1.take_glwe_ct(&GLWELayout {
76 n: ksk.n(),
77 base2k: self.base2k(),
78 k: max_k,
79 rank: Rank(1),
80 });
81
82 let n_lwe: usize = a.n().into();
83
84 for i in 0..a_size {
85 let data_lwe: &[i64] = a.data.at(0, i);
86 glwe_in.data.at_mut(0, i)[0] = data_lwe[0];
87 glwe_in.data.at_mut(1, i)[..n_lwe].copy_from_slice(&data_lwe[1..]);
88 }
89
90 glwe_out.keyswitch(module, &glwe_in, &ksk.0, scratch_1);
91 self.sample_extract(&glwe_out);
92 }
93}
94
95impl LWE<Vec<u8>> {}
96
97impl<DLwe: DataMut> LWE<DLwe> {
98
99}