arnaucube
arnaucube/poulpyPublic Self-hosted repository
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}