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