arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-core/src/automorphism/gglwe_atk.rs
poulpy-core/src/automorphism/gglwe_atk.rsRaw
  1use poulpy_hal::{
  2    api::{VecZnxAutomorphism, VecZnxAutomorphismInplace},
  3    layouts::{Backend, CyclotomicOrder, DataMut, GaloisElement, Module, Scratch},
  4};
  5
  6use crate::{
  7    GLWEKeyswitch, ScratchTakeCore,
  8    layouts::{
  9        GGLWE, GGLWEInfos, GGLWEPreparedToRef, GGLWEToMut, GGLWEToRef, GLWE, GLWEAutomorphismKey, GetGaloisElement,
 10        SetGaloisElement,
 11    },
 12};
 13
 14impl GLWEAutomorphismKey<Vec<u8>> {
 15    pub fn automorphism_tmp_bytes<R, A, K, M, BE: Backend>(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
 16    where
 17        R: GGLWEInfos,
 18        A: GGLWEInfos,
 19        K: GGLWEInfos,
 20        M: GLWEAutomorphismKeyAutomorphism<BE>,
 21    {
 22        module.glwe_automorphism_key_automorphism_tmp_bytes(res_infos, a_infos, key_infos)
 23    }
 24}
 25
 26impl<DataSelf: DataMut> GLWEAutomorphismKey<DataSelf> {
 27    pub fn automorphism<A, K, M, BE: Backend>(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch<BE>)
 28    where
 29        A: GGLWEToRef + GetGaloisElement + GGLWEInfos,
 30        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 31        Scratch<BE>: ScratchTakeCore<BE>,
 32        M: GLWEAutomorphismKeyAutomorphism<BE>,
 33    {
 34        module.glwe_automorphism_key_automorphism(self, a, key, scratch);
 35    }
 36
 37    pub fn automorphism_inplace<K, M, BE: Backend>(&mut self, module: &M, key: &K, scratch: &mut Scratch<BE>)
 38    where
 39        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 40        Scratch<BE>: ScratchTakeCore<BE>,
 41        M: GLWEAutomorphismKeyAutomorphism<BE>,
 42    {
 43        module.glwe_automorphism_key_automorphism_inplace(self, key, scratch);
 44    }
 45}
 46
 47impl<BE: Backend> GLWEAutomorphismKeyAutomorphism<BE> for Module<BE>
 48where
 49    Self: GaloisElement + GLWEKeyswitch<BE> + VecZnxAutomorphism + VecZnxAutomorphismInplace<BE> + CyclotomicOrder,
 50    Scratch<BE>: ScratchTakeCore<BE>,
 51{
 52    fn glwe_automorphism_key_automorphism_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
 53    where
 54        R: GGLWEInfos,
 55        A: GGLWEInfos,
 56        K: GGLWEInfos,
 57    {
 58        if res_infos.glwe_layout() == a_infos.glwe_layout() {
 59            self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos)
 60        } else {
 61            self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) + GLWE::bytes_of_from_infos(a_infos)
 62        }
 63    }
 64
 65    fn glwe_automorphism_key_automorphism<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>)
 66    where
 67        R: GGLWEToMut + SetGaloisElement + GGLWEInfos,
 68        A: GGLWEToRef + GetGaloisElement + GGLWEInfos,
 69        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
 70    {
 71        assert!(
 72            res.dnum().as_u32() <= a.dnum().as_u32(),
 73            "res dnum: {} > a dnum: {}",
 74            res.dnum(),
 75            a.dnum()
 76        );
 77
 78        assert_eq!(res.dsize(), a.dsize(), "res dnum: {} != a dnum: {}", res.dsize(), a.dsize());
 79
 80        assert_eq!(res.base2k(), a.base2k());
 81
 82        let cols_out: usize = (key.rank_out() + 1).into();
 83        let cols_in: usize = key.rank_in().into();
 84
 85        let p: i64 = a.p();
 86        let p_inv: i64 = self.galois_element_inv(p);
 87
 88        let same_layout: bool = res.glwe_layout() == a.glwe_layout();
 89
 90        {
 91            let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
 92            let a: &GGLWE<&[u8]> = &a.to_ref();
 93
 94            for row in 0..res.dnum().as_usize() {
 95                for col in 0..cols_in {
 96                    let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col);
 97                    let a_ct: GLWE<&[u8]> = a.at(row, col);
 98
 99                    if same_layout {
100                        // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
101                        for i in 0..cols_out {
102                            self.vec_znx_automorphism(p, res_tmp.data_mut(), i, &a_ct.data, i);
103                        }
104
105                        // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
106                        self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch);
107                    } else {
108                        let (mut tmp_glwe, scratch_1) = scratch.take_glwe(a);
109
110                        // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
111                        for i in 0..cols_out {
112                            self.vec_znx_automorphism(p, tmp_glwe.data_mut(), i, &a_ct.data, i);
113                        }
114
115                        // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
116                        self.glwe_keyswitch(&mut res_tmp, &tmp_glwe, key, scratch_1);
117                    }
118
119                    // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a)
120                    for i in 0..cols_out {
121                        self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch);
122                    }
123                }
124            }
125        }
126
127        res.set_p((p * key.p()) % self.cyclotomic_order());
128    }
129
130    fn glwe_automorphism_key_automorphism_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>)
131    where
132        R: GGLWEToMut + SetGaloisElement + GetGaloisElement + GGLWEInfos,
133        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos,
134        Scratch<BE>: ScratchTakeCore<BE>,
135    {
136        assert_eq!(res.rank(), key.rank(), "key rank: {} != key rank: {}", res.rank(), key.rank());
137
138        let cols_out: usize = (key.rank_out() + 1).into();
139        let cols_in: usize = key.rank_in().into();
140        let p: i64 = res.p();
141        let p_inv: i64 = self.galois_element_inv(p);
142
143        {
144            let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut();
145            for row in 0..res.dnum().as_usize() {
146                for col in 0..cols_in {
147                    let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col);
148
149                    // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
150                    for i in 0..cols_out {
151                        self.vec_znx_automorphism_inplace(p, res_tmp.data_mut(), i, scratch);
152                    }
153
154                    // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
155                    self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch);
156
157                    // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a)
158                    for i in 0..cols_out {
159                        self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch);
160                    }
161                }
162            }
163        }
164
165        res.set_p((res.p() * key.p()) % self.cyclotomic_order());
166    }
167}
168
169pub trait GLWEAutomorphismKeyAutomorphism<BE: Backend> {
170    fn glwe_automorphism_key_automorphism_tmp_bytes<R, A, K>(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize
171    where
172        R: GGLWEInfos,
173        A: GGLWEInfos,
174        K: GGLWEInfos;
175
176    fn glwe_automorphism_key_automorphism<R, A, K>(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch<BE>)
177    where
178        R: GGLWEToMut + SetGaloisElement + GGLWEInfos,
179        A: GGLWEToRef + GetGaloisElement + GGLWEInfos,
180        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos;
181
182    fn glwe_automorphism_key_automorphism_inplace<R, K>(&self, res: &mut R, key: &K, scratch: &mut Scratch<BE>)
183    where
184        R: GGLWEToMut + SetGaloisElement + GetGaloisElement + GGLWEInfos,
185        K: GGLWEPreparedToRef<BE> + GetGaloisElement + GGLWEInfos;
186}