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