arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/glwe_trace.rs
poulpy-core/src/glwe_trace.rsRaw
  1use std::collections::HashMap;
  2
  3use poulpy_hal::{
  4    api::{
  5        ScratchAvailable, VecZnxBigAddSmallInplace, VecZnxBigAutomorphismInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes,
  6        VecZnxCopy, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes,
  7        VecZnxRshInplace, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes,
  8    },
  9    layouts::{Backend, DataMut, DataRef, Module, Scratch, VecZnx},
 10};
 11
 12use crate::{
 13    layouts::{Base2K, GGLWEInfos, GLWE, GLWEInfos, GLWELayout, LWEInfos, prepared::AutomorphismKeyPrepared},
 14    operations::GLWEOperations,
 15};
 16
 17impl GLWE<Vec<u8>> {
 18    pub fn trace_galois_elements<B: Backend>(module: &Module<B>) -> Vec<i64> {
 19        let mut gal_els: Vec<i64> = Vec::new();
 20        (0..module.log_n()).for_each(|i| {
 21            if i == 0 {
 22                gal_els.push(-1);
 23            } else {
 24                gal_els.push(module.galois_element(1 << (i - 1)));
 25            }
 26        });
 27        gal_els
 28    }
 29
 30    pub fn trace_tmp_bytes<B: Backend, OUT, IN, KEY>(module: &Module<B>, out_infos: &OUT, in_infos: &IN, key_infos: &KEY) -> usize
 31    where
 32        OUT: GLWEInfos,
 33        IN: GLWEInfos,
 34        KEY: GGLWEInfos,
 35        Module<B>: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes,
 36    {
 37        let trace: usize = Self::automorphism_inplace_tmp_bytes(module, out_infos, key_infos);
 38        if in_infos.base2k() != key_infos.base2k() {
 39            let glwe_conv: usize = VecZnx::bytes_of(
 40                module.n(),
 41                (key_infos.rank_out() + 1).into(),
 42                out_infos.k().min(in_infos.k()).div_ceil(key_infos.base2k()) as usize,
 43            ) + module.vec_znx_normalize_tmp_bytes();
 44            return glwe_conv + trace;
 45        }
 46
 47        trace
 48    }
 49
 50    pub fn trace_inplace_tmp_bytes<B: Backend, OUT, KEY>(module: &Module<B>, out_infos: &OUT, key_infos: &KEY) -> usize
 51    where
 52        OUT: GLWEInfos,
 53        KEY: GGLWEInfos,
 54        Module<B>: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes,
 55    {
 56        Self::trace_tmp_bytes(module, out_infos, out_infos, key_infos)
 57    }
 58}
 59
 60impl<DataSelf: DataMut> GLWE<DataSelf> {
 61    pub fn trace<DataLhs: DataRef, DataAK: DataRef, B: Backend>(
 62        &mut self,
 63        module: &Module<B>,
 64        start: usize,
 65        end: usize,
 66        lhs: &GLWE<DataLhs>,
 67        auto_keys: &HashMap<i64, AutomorphismKeyPrepared<DataAK, B>>,
 68        scratch: &mut Scratch<B>,
 69    ) where
 70        Module<B>: VecZnxDftBytesOf
 71            + VmpApplyDftToDftTmpBytes
 72            + VecZnxBigNormalizeTmpBytes
 73            + VmpApplyDftToDft<B>
 74            + VmpApplyDftToDftAdd<B>
 75            + VecZnxDftApply<B>
 76            + VecZnxIdftApplyConsume<B>
 77            + VecZnxBigAddSmallInplace<B>
 78            + VecZnxBigNormalize<B>
 79            + VecZnxBigAutomorphismInplace<B>
 80            + VecZnxRshInplace<B>
 81            + VecZnxCopy
 82            + VecZnxNormalizeTmpBytes
 83            + VecZnxNormalize<B>,
 84        Scratch<B>: ScratchAvailable,
 85    {
 86        self.copy(module, lhs);
 87        self.trace_inplace(module, start, end, auto_keys, scratch);
 88    }
 89
 90    pub fn trace_inplace<DataAK: DataRef, B: Backend>(
 91        &mut self,
 92        module: &Module<B>,
 93        start: usize,
 94        end: usize,
 95        auto_keys: &HashMap<i64, AutomorphismKeyPrepared<DataAK, B>>,
 96        scratch: &mut Scratch<B>,
 97    ) where
 98        Module<B>: VecZnxDftBytesOf
 99            + VmpApplyDftToDftTmpBytes
100            + VecZnxBigNormalizeTmpBytes
101            + VmpApplyDftToDft<B>
102            + VmpApplyDftToDftAdd<B>
103            + VecZnxDftApply<B>
104            + VecZnxIdftApplyConsume<B>
105            + VecZnxBigAddSmallInplace<B>
106            + VecZnxBigNormalize<B>
107            + VecZnxBigAutomorphismInplace<B>
108            + VecZnxRshInplace<B>
109            + VecZnxNormalizeTmpBytes
110            + VecZnxNormalize<B>,
111        Scratch<B>: ScratchAvailable,
112    {
113        let basek_ksk: Base2K = auto_keys
114            .get(auto_keys.keys().next().unwrap())
115            .unwrap()
116            .base2k();
117
118        #[cfg(debug_assertions)]
119        {
120            assert_eq!(self.n(), module.n() as u32);
121            assert!(start < end);
122            assert!(end <= module.log_n());
123            for key in auto_keys.values() {
124                assert_eq!(key.n(), module.n() as u32);
125                assert_eq!(key.base2k(), basek_ksk);
126                assert_eq!(key.rank_in(), self.rank());
127                assert_eq!(key.rank_out(), self.rank());
128            }
129        }
130
131        if self.base2k() != basek_ksk {
132            let (mut self_conv, scratch_1) = scratch.take_glwe_ct(&GLWELayout {
133                n: module.n().into(),
134                base2k: basek_ksk,
135                k: self.k(),
136                rank: self.rank(),
137            });
138
139            for j in 0..(self.rank() + 1).into() {
140                module.vec_znx_normalize(
141                    basek_ksk.into(),
142                    &mut self_conv.data,
143                    j,
144                    basek_ksk.into(),
145                    &self.data,
146                    j,
147                    scratch_1,
148                );
149            }
150
151            for i in start..end {
152                self_conv.rsh(module, 1, scratch_1);
153
154                let p: i64 = if i == 0 {
155                    -1
156                } else {
157                    module.galois_element(1 << (i - 1))
158                };
159
160                if let Some(key) = auto_keys.get(&p) {
161                    self_conv.automorphism_add_inplace(module, key, scratch_1);
162                } else {
163                    panic!("auto_keys[{p}] is empty")
164                }
165            }
166
167            for j in 0..(self.rank() + 1).into() {
168                module.vec_znx_normalize(
169                    self.base2k().into(),
170                    &mut self.data,
171                    j,
172                    basek_ksk.into(),
173                    &self_conv.data,
174                    j,
175                    scratch_1,
176                );
177            }
178        } else {
179            for i in start..end {
180                self.rsh(module, 1, scratch);
181
182                let p: i64 = if i == 0 {
183                    -1
184                } else {
185                    module.galois_element(1 << (i - 1))
186                };
187
188                if let Some(key) = auto_keys.get(&p) {
189                    self.automorphism_add_inplace(module, key, scratch);
190                } else {
191                    panic!("auto_keys[{p}] is empty")
192                }
193            }
194        }
195    }
196}