arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/glwe_trace.rs
poulpy-core/src/glwe_trace.rsRaw
  1use poulpy_hal::{
  2    api::{ModuleLogN, VecZnxNormalize, VecZnxNormalizeTmpBytes},
  3    layouts::{Backend, CyclotomicOrder, DataMut, GaloisElement, Module, Scratch, VecZnx, galois_element},
  4};
  5
  6use crate::{
  7    GLWEAutomorphism, GLWECopy, GLWEShift, ScratchTakeCore,
  8    layouts::{
  9        GGLWEInfos, GGLWELayout, GGLWEPreparedToRef, GLWE, GLWEAutomorphismKeyHelper, GLWEInfos, GLWELayout, GLWEToMut,
 10        GLWEToRef, GetGaloisElement, LWEInfos,
 11    },
 12};
 13
 14impl GLWE<Vec<u8>> {
 15    pub fn trace_galois_elements<M, BE: Backend>(module: &M) -> Vec<i64>
 16    where
 17        M: GLWETrace<BE>,
 18    {
 19        module.glwe_trace_galois_elements()
 20    }
 21
 22    pub fn trace_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
 23    where
 24        R: GLWEInfos,
 25        A: GLWEInfos,
 26        K: GGLWEInfos,
 27        M: GLWETrace<BE>,
 28    {
 29        module.glwe_trace_tmp_bytes(res_infos, a_infos, key_infos)
 30    }
 31}
 32
 33impl<D: DataMut> GLWE<D> {
 34    pub fn trace<A, H, K, M, BE: Backend>(&mut self, module: &M, skip: usize, a: &A, keys: &H, scratch: &mut Scratch<BE>)
 35    where
 36        A: GLWEToRef + GLWEInfos,
 37        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 38        H: GLWEAutomorphismKeyHelper<K, BE>,
 39        Scratch<BE>: ScratchTakeCore<BE>,
 40        M: GLWETrace<BE>,
 41    {
 42        module.glwe_trace(self, skip, a, keys, scratch);
 43    }
 44
 45    pub fn trace_inplace<H, K, M, BE: Backend>(&mut self, module: &M, skip: usize, keys: &H, scratch: &mut Scratch<BE>)
 46    where
 47        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 48        H: GLWEAutomorphismKeyHelper<K, BE>,
 49        Scratch<BE>: ScratchTakeCore<BE>,
 50        M: GLWETrace<BE>,
 51    {
 52        module.glwe_trace_inplace(self, skip, keys, scratch);
 53    }
 54}
 55
 56#[inline(always)]
 57pub fn trace_galois_elements(log_n: usize, cyclotomic_order: i64) -> Vec<i64> {
 58    (0..log_n)
 59        .map(|i| {
 60            if i == 0 {
 61                -1
 62            } else {
 63                galois_element(1 << (i - 1), cyclotomic_order)
 64            }
 65        })
 66        .collect()
 67}
 68
 69impl<BE: Backend> GLWETrace<BE> for Module<BE>
 70where
 71    Self: ModuleLogN
 72        + GaloisElement
 73        + GLWEAutomorphism<BE>
 74        + GLWEShift<BE>
 75        + GLWECopy
 76        + CyclotomicOrder
 77        + VecZnxNormalizeTmpBytes
 78        + VecZnxNormalize<BE>,
 79    Scratch<BE>: ScratchTakeCore<BE>,
 80{
 81    fn glwe_trace_galois_elements(&self) -> Vec<i64> {
 82        trace_galois_elements(self.log_n(), self.cyclotomic_order())
 83    }
 84
 85    fn glwe_trace_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
 86    where
 87        R: GLWEInfos,
 88        A: GLWEInfos,
 89        K: GGLWEInfos,
 90    {
 91        let trace: usize = self.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos);
 92        if a_infos.base2k() != key_infos.base2k() {
 93            let glwe_conv: usize = VecZnx::bytes_of(
 94                self.n(),
 95                (key_infos.rank_out() + 1).into(),
 96                res_infos.k().min(a_infos.k()).div_ceil(key_infos.base2k()) as usize,
 97            ) + self.vec_znx_normalize_tmp_bytes();
 98            return glwe_conv + trace;
 99        }
100
101        let tmp = if res_infos.k() > a_infos.k() {
102            GLWE::bytes_of_from_infos(res_infos)
103        } else {
104            GLWE::bytes_of_from_infos(a_infos)
105        };
106
107        trace + tmp
108    }
109
110    fn glwe_trace<R, A, K, H>(&self, res: &mut R, skip: usize, a: &A, keys: &H, scratch: &mut Scratch<BE>)
111    where
112        R: GLWEToMut + GLWEInfos,
113        A: GLWEToRef + GLWEInfos,
114        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
115        H: GLWEAutomorphismKeyHelper<K, BE>,
116    {
117        let (mut tmp, scratch_1) = if a.k() > res.k() {
118            scratch.take_glwe(a)
119        } else {
120            scratch.take_glwe(res)
121        };
122
123        self.glwe_copy(&mut tmp, a);
124        self.glwe_trace_inplace(&mut tmp, skip, keys, scratch_1);
125        self.glwe_copy(res, &tmp);
126    }
127
128    fn glwe_trace_inplace<R, K, H>(&self, res: &mut R, skip: usize, keys: &H, scratch: &mut Scratch<BE>)
129    where
130        R: GLWEToMut,
131        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
132        H: GLWEAutomorphismKeyHelper<K, BE>,
133    {
134        let res: &mut GLWE<&mut [u8]> = &mut res.to_mut();
135
136        let ksk_infos: &GGLWELayout = &keys.automorphism_key_infos();
137        let log_n: usize = self.log_n();
138
139        assert_eq!(res.n(), self.n() as u32);
140        assert_eq!(ksk_infos.n(), self.n() as u32);
141        assert!(skip <= log_n);
142        assert_eq!(ksk_infos.rank_in(), res.rank());
143        assert_eq!(ksk_infos.rank_out(), res.rank());
144
145        if res.base2k() != ksk_infos.base2k() {
146            let (mut self_conv, scratch_1) = scratch.take_glwe(&GLWELayout {
147                n: self.n().into(),
148                base2k: ksk_infos.base2k(),
149                k: res.k(),
150                rank: res.rank(),
151            });
152
153            for j in 0..(res.rank() + 1).into() {
154                self.vec_znx_normalize(
155                    ksk_infos.base2k().into(),
156                    &mut self_conv.data,
157                    j,
158                    res.base2k().into(),
159                    res.data(),
160                    j,
161                    scratch_1,
162                );
163            }
164
165            for i in skip..log_n {
166                self.glwe_rsh(1, &mut self_conv, scratch_1);
167
168                let p: i64 = if i == 0 {
169                    -1
170                } else {
171                    self.galois_element(1 << (i - 1))
172                };
173
174                if let Some(key) = keys.get_automorphism_key(p) {
175                    self.glwe_automorphism_add_inplace(&mut self_conv, key, scratch_1);
176                } else {
177                    panic!("keys[{p}] is empty")
178                }
179            }
180
181            for j in 0..(res.rank() + 1).into() {
182                self.vec_znx_normalize(
183                    res.base2k().into(),
184                    res.data_mut(),
185                    j,
186                    ksk_infos.base2k().into(),
187                    &self_conv.data,
188                    j,
189                    scratch_1,
190                );
191            }
192        } else {
193            for i in skip..log_n {
194                self.glwe_rsh(1, res, scratch);
195
196                let p: i64 = if i == 0 {
197                    -1
198                } else {
199                    self.galois_element(1 << (i - 1))
200                };
201
202                if let Some(key) = keys.get_automorphism_key(p) {
203                    self.glwe_automorphism_add_inplace(res, key, scratch);
204                } else {
205                    panic!("keys[{p}] is empty")
206                }
207            }
208        }
209    }
210}
211
212pub trait GLWETrace<BE: Backend> {
213    fn glwe_trace_galois_elements(&self) -> Vec<i64>;
214
215    fn glwe_trace_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
216    where
217        R: GLWEInfos,
218        A: GLWEInfos,
219        K: GGLWEInfos;
220
221    fn glwe_trace<R, A, K, H>(&self, res: &mut R, skip: usize, a: &A, keys: &H, scratch: &mut Scratch<BE>)
222    where
223        R: GLWEToMut + GLWEInfos,
224        A: GLWEToRef + GLWEInfos,
225        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
226        H: GLWEAutomorphismKeyHelper<K, BE>;
227
228    fn glwe_trace_inplace<R, K, H>(&self, res: &mut R, skip: usize, keys: &H, scratch: &mut Scratch<BE>)
229    where
230        R: GLWEToMut,
231        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
232        H: GLWEAutomorphismKeyHelper<K, BE>;
233}