arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/automorphism/gglwe_atk.rs
core/src/automorphism/gglwe_atk.rsRaw
  1use backend::hal::{
  2    api::{ScratchAvailable, TakeVecZnxDft, VecZnxAutomorphism, VecZnxAutomorphismInplace, ZnxZero},
  3    layouts::{Backend, DataMut, DataRef, Module, Scratch},
  4};
  5
  6use crate::{
  7    layouts::{GGLWEAutomorphismKey, GLWECiphertext, Infos, prepared::GGLWEAutomorphismKeyExec},
  8    trait_families::GLWEKeyswitchFamily,
  9};
 10
 11impl GGLWEAutomorphismKey<Vec<u8>> {
 12    pub fn automorphism_scratch_space<B: Backend>(
 13        module: &Module<B>,
 14        n: usize,
 15        basek: usize,
 16        k_out: usize,
 17        k_in: usize,
 18        k_ksk: usize,
 19        digits: usize,
 20        rank: usize,
 21    ) -> usize
 22    where
 23        Module<B>: GLWEKeyswitchFamily<B>,
 24    {
 25        GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_out, k_in, k_ksk, digits, rank, rank)
 26    }
 27
 28    pub fn automorphism_inplace_scratch_space<B: Backend>(
 29        module: &Module<B>,
 30        n: usize,
 31        basek: usize,
 32        k_out: usize,
 33        k_ksk: usize,
 34        digits: usize,
 35        rank: usize,
 36    ) -> usize
 37    where
 38        Module<B>: GLWEKeyswitchFamily<B>,
 39    {
 40        GGLWEAutomorphismKey::automorphism_scratch_space(module, n, basek, k_out, k_out, k_ksk, digits, rank)
 41    }
 42}
 43
 44impl<DataSelf: DataMut> GGLWEAutomorphismKey<DataSelf> {
 45    pub fn automorphism<'a, DataLhs: DataRef, DataRhs: DataRef, B: Backend>(
 46        &mut self,
 47        module: &Module<B>,
 48        lhs: &GGLWEAutomorphismKey<DataLhs>,
 49        rhs: &GGLWEAutomorphismKeyExec<DataRhs, B>,
 50        scratch: &mut Scratch<B>,
 51    ) where
 52        Module<B>: GLWEKeyswitchFamily<B> + VecZnxAutomorphism + VecZnxAutomorphismInplace,
 53        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable,
 54    {
 55        #[cfg(debug_assertions)]
 56        {
 57            assert_eq!(
 58                self.rank_in(),
 59                lhs.rank_in(),
 60                "ksk_out input rank: {} != ksk_in input rank: {}",
 61                self.rank_in(),
 62                lhs.rank_in()
 63            );
 64            assert_eq!(
 65                lhs.rank_out(),
 66                rhs.rank_in(),
 67                "ksk_in output rank: {} != ksk_apply input rank: {}",
 68                self.rank_out(),
 69                rhs.rank_in()
 70            );
 71            assert_eq!(
 72                self.rank_out(),
 73                rhs.rank_out(),
 74                "ksk_out output rank: {} != ksk_apply output rank: {}",
 75                self.rank_out(),
 76                rhs.rank_out()
 77            );
 78            assert!(
 79                self.k() <= lhs.k(),
 80                "output k={} cannot be greater than input k={}",
 81                self.k(),
 82                lhs.k()
 83            )
 84        }
 85
 86        let cols_out: usize = rhs.rank_out() + 1;
 87
 88        let p: i64 = lhs.p();
 89        let p_inv = module.galois_element_inv(p);
 90
 91        (0..self.rank_in()).for_each(|col_i| {
 92            (0..self.rows()).for_each(|row_j| {
 93                let mut res_ct: GLWECiphertext<&mut [u8]> = self.at_mut(row_j, col_i);
 94                let lhs_ct: GLWECiphertext<&[u8]> = lhs.at(row_j, col_i);
 95
 96                // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a)
 97                (0..cols_out).for_each(|i| {
 98                    module.vec_znx_automorphism(lhs.p(), &mut res_ct.data, i, &lhs_ct.data, i);
 99                });
100
101                // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a)
102                res_ct.keyswitch_inplace(module, &rhs.key, scratch);
103
104                // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a)
105                (0..cols_out).for_each(|i| {
106                    module.vec_znx_automorphism_inplace(p_inv, &mut res_ct.data, i);
107                });
108            });
109        });
110
111        (self.rows().min(lhs.rows())..self.rows()).for_each(|row_i| {
112            (0..self.rank_in()).for_each(|col_j| {
113                self.at_mut(row_i, col_j).data.zero();
114            });
115        });
116
117        self.p = (lhs.p * rhs.p) % (module.cyclotomic_order() as i64);
118    }
119
120    pub fn automorphism_inplace<DataRhs: DataRef, B: Backend>(
121        &mut self,
122        module: &Module<B>,
123        rhs: &GGLWEAutomorphismKeyExec<DataRhs, B>,
124        scratch: &mut Scratch<B>,
125    ) where
126        Module<B>: GLWEKeyswitchFamily<B> + VecZnxAutomorphism + VecZnxAutomorphismInplace,
127        Scratch<B>: TakeVecZnxDft<B> + ScratchAvailable,
128    {
129        unsafe {
130            let self_ptr: *mut GGLWEAutomorphismKey<DataSelf> = self as *mut GGLWEAutomorphismKey<DataSelf>;
131            self.automorphism(&module, &*self_ptr, rhs, scratch);
132        }
133    }
134}