poulpy_core/conversion/
glwe_to_lwe.rs

1use poulpy_hal::{
2    api::{
3        ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
4        VecZnxDftAllocBytes, VecZnxDftApply, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft,
5        VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
6    },
7    layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxView, ZnxViewMut, ZnxZero},
8};
9
10use crate::{
11    TakeGLWECt,
12    layouts::{
13        GGLWELayoutInfos, GLWECiphertext, GLWECiphertextLayout, GLWEInfos, LWECiphertext, LWEInfos, Rank,
14        prepared::GLWEToLWESwitchingKeyPrepared,
15    },
16};
17
18impl LWECiphertext<Vec<u8>> {
19    pub fn from_glwe_scratch_space<B: Backend, OUT, IN, KEY>(
20        module: &Module<B>,
21        lwe_infos: &OUT,
22        glwe_infos: &IN,
23        key_infos: &KEY,
24    ) -> usize
25    where
26        OUT: LWEInfos,
27        IN: GLWEInfos,
28        KEY: GGLWELayoutInfos,
29        Module<B>: VecZnxDftAllocBytes + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes,
30    {
31        let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout {
32            n: module.n().into(),
33            base2k: lwe_infos.base2k(),
34            k: lwe_infos.k(),
35            rank: Rank(1),
36        };
37
38        GLWECiphertext::alloc_bytes_with(
39            module.n().into(),
40            lwe_infos.base2k(),
41            lwe_infos.k(),
42            1u32.into(),
43        ) + GLWECiphertext::keyswitch_scratch_space(module, &glwe_layout, glwe_infos, key_infos)
44    }
45}
46
47impl<DLwe: DataMut> LWECiphertext<DLwe> {
48    pub fn sample_extract<DGlwe: DataRef>(&mut self, a: &GLWECiphertext<DGlwe>) {
49        #[cfg(debug_assertions)]
50        {
51            assert!(self.n() <= a.n());
52            assert!(self.base2k() == a.base2k());
53        }
54
55        let min_size: usize = self.size().min(a.size());
56        let n: usize = self.n().into();
57
58        self.data.zero();
59        (0..min_size).for_each(|i| {
60            let data_lwe: &mut [i64] = self.data.at_mut(0, i);
61            data_lwe[0] = a.data.at(0, i)[0];
62            data_lwe[1..].copy_from_slice(&a.data.at(1, i)[..n]);
63        });
64    }
65
66    pub fn from_glwe<DGlwe, DKs, B: Backend>(
67        &mut self,
68        module: &Module<B>,
69        a: &GLWECiphertext<DGlwe>,
70        ks: &GLWEToLWESwitchingKeyPrepared<DKs, B>,
71        scratch: &mut Scratch<B>,
72    ) where
73        DGlwe: DataRef,
74        DKs: DataRef,
75        Module<B>: VecZnxDftAllocBytes
76            + VmpApplyDftToDftTmpBytes
77            + VecZnxBigNormalizeTmpBytes
78            + VmpApplyDftToDft<B>
79            + VmpApplyDftToDftAdd<B>
80            + VecZnxDftApply<B>
81            + VecZnxIdftApplyConsume<B>
82            + VecZnxBigAddSmallInplace<B>
83            + VecZnxBigNormalize<B>
84            + VecZnxNormalize<B>
85            + VecZnxNormalizeTmpBytes,
86        Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeGLWECt + TakeVecZnx,
87    {
88        #[cfg(debug_assertions)]
89        {
90            assert_eq!(a.n(), module.n() as u32);
91            assert_eq!(ks.n(), module.n() as u32);
92            assert!(self.n() <= module.n() as u32);
93        }
94
95        let glwe_layout: GLWECiphertextLayout = GLWECiphertextLayout {
96            n: module.n().into(),
97            base2k: self.base2k(),
98            k: self.k(),
99            rank: Rank(1),
100        };
101
102        let (mut tmp_glwe, scratch_1) = scratch.take_glwe_ct(&glwe_layout);
103        tmp_glwe.keyswitch(module, a, &ks.0, scratch_1);
104        self.sample_extract(&tmp_glwe);
105    }
106}