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>(
 35        &mut self,
 36        module: &M,
 37        start: usize,
 38        end: usize,
 39        a: &A,
 40        keys: &H,
 41        scratch: &mut Scratch<BE>,
 42    ) where
 43        A: GLWEToRef,
 44        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 45        H: GLWEAutomorphismKeyHelper<K, BE>,
 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<H, K, M, BE: Backend>(
 53        &mut self,
 54        module: &M,
 55        start: usize,
 56        end: usize,
 57        keys: &H,
 58        scratch: &mut Scratch<BE>,
 59    ) where
 60        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 61        H: GLWEAutomorphismKeyHelper<K, BE>,
 62        Scratch<BE>: ScratchTakeCore<BE>,
 63        M: GLWETrace<BE>,
 64    {
 65        module.glwe_trace_inplace(self, start, end, keys, scratch);
 66    }
 67}
 68
 69#[inline(always)]
 70pub fn trace_galois_elements(log_n: usize, cyclotomic_order: i64) -> Vec<i64> {
 71    (0..log_n)
 72        .map(|i| {
 73            if i == 0 {
 74                -1
 75            } else {
 76                galois_element(1 << (i - 1), cyclotomic_order)
 77            }
 78        })
 79        .collect()
 80}
 81
 82impl<BE: Backend> GLWETrace<BE> for Module<BE>
 83where
 84    Self: ModuleLogN
 85        + GaloisElement
 86        + GLWEAutomorphism<BE>
 87        + GLWEShift<BE>
 88        + GLWECopy
 89        + CyclotomicOrder
 90        + VecZnxNormalizeTmpBytes
 91        + VecZnxNormalize<BE>,
 92    Scratch<BE>: ScratchTakeCore<BE>,
 93{
 94    fn glwe_trace_galois_elements(&self) -> Vec<i64> {
 95        trace_galois_elements(self.log_n(), self.cyclotomic_order())
 96    }
 97
 98    fn glwe_trace_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
 99    where
100        R: GLWEInfos,
101        A: GLWEInfos,
102        K: GGLWEInfos,
103    {
104        let trace: usize = self.glwe_automorphism_tmp_bytes(res_infos, a_infos, key_infos);
105        if a_infos.base2k() != key_infos.base2k() {
106            let glwe_conv: usize = VecZnx::bytes_of(
107                self.n(),
108                (key_infos.rank_out() + 1).into(),
109                res_infos.k().min(a_infos.k()).div_ceil(key_infos.base2k()) as usize,
110            ) + self.vec_znx_normalize_tmp_bytes();
111            return glwe_conv + trace;
112        }
113
114        trace
115    }
116
117    fn glwe_trace<R, A, K, H>(&self, res: &mut R, start: usize, end: usize, a: &A, keys: &H, scratch: &mut Scratch<BE>)
118    where
119        R: GLWEToMut,
120        A: GLWEToRef,
121        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
122        H: GLWEAutomorphismKeyHelper<K, BE>,
123    {
124        self.glwe_copy(res, a);
125        self.glwe_trace_inplace(res, start, end, keys, scratch);
126    }
127
128    fn glwe_trace_inplace<R, K, H>(&self, res: &mut R, start: usize, end: 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
138        assert_eq!(res.n(), self.n() as u32);
139        assert_eq!(ksk_infos.n(), self.n() as u32);
140        assert!(start < end);
141        assert!(end <= self.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 start..end {
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            // println!("res: {}", res);
194
195            for i in start..end {
196                self.glwe_rsh(1, res, scratch);
197
198                let p: i64 = if i == 0 {
199                    -1
200                } else {
201                    self.galois_element(1 << (i - 1))
202                };
203
204                if let Some(key) = keys.get_automorphism_key(p) {
205                    self.glwe_automorphism_add_inplace(res, key, scratch);
206                } else {
207                    panic!("keys[{p}] is empty")
208                }
209            }
210        }
211    }
212}
213
214pub trait GLWETrace<BE: Backend> {
215    fn glwe_trace_galois_elements(&self) -> Vec<i64>;
216
217    fn glwe_trace_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
218    where
219        R: GLWEInfos,
220        A: GLWEInfos,
221        K: GGLWEInfos;
222
223    fn glwe_trace<R, A, K, H>(&self, res: &mut R, start: usize, end: usize, a: &A, keys: &H, scratch: &mut Scratch<BE>)
224    where
225        R: GLWEToMut,
226        A: GLWEToRef,
227        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
228        H: GLWEAutomorphismKeyHelper<K, BE>;
229
230    fn glwe_trace_inplace<R, K, H>(&self, res: &mut R, start: usize, end: usize, keys: &H, scratch: &mut Scratch<BE>)
231    where
232        R: GLWEToMut,
233        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
234        H: GLWEAutomorphismKeyHelper<K, BE>;
235}