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