arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/core/src/automorphism/ggsw_ct.rs
core/src/automorphism/ggsw_ct.rsRaw
  1use backend::hal::{
  2    api::{ScratchAvailable, TakeVecZnxBig, TakeVecZnxDft, VecZnxAutomorphismInplace, VecZnxNormalizeTmpBytes},
  3    layouts::{Backend, DataMut, DataRef, Module, Scratch},
  4};
  5
  6use crate::{
  7    layouts::{
  8        GGSWCiphertext, GLWECiphertext, Infos,
  9        prepared::{GGLWEAutomorphismKeyExec, GGLWETensorKeyExec},
 10    },
 11    trait_families::{GGSWKeySwitchFamily, GLWEKeyswitchFamily},
 12};
 13
 14impl GGSWCiphertext<Vec<u8>> {
 15    pub fn automorphism_scratch_space<B: Backend>(
 16        module: &Module<B>,
 17        n: usize,
 18        basek: usize,
 19        k_out: usize,
 20        k_in: usize,
 21        k_ksk: usize,
 22        digits_ksk: usize,
 23        k_tsk: usize,
 24        digits_tsk: usize,
 25        rank: usize,
 26    ) -> usize
 27    where
 28        Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
 29    {
 30        let out_size: usize = k_out.div_ceil(basek);
 31        let ci_dft: usize = module.vec_znx_dft_alloc_bytes(n, rank + 1, out_size);
 32        let ks_internal: usize =
 33            GLWECiphertext::keyswitch_scratch_space(module, n, basek, k_out, k_in, k_ksk, digits_ksk, rank, rank);
 34        let expand: usize = GGSWCiphertext::expand_row_scratch_space(module, n, basek, k_out, k_tsk, digits_tsk, rank);
 35        ci_dft + (ks_internal | expand)
 36    }
 37
 38    pub fn automorphism_inplace_scratch_space<B: Backend>(
 39        module: &Module<B>,
 40        n: usize,
 41        basek: usize,
 42        k_out: usize,
 43        k_ksk: usize,
 44        digits_ksk: usize,
 45        k_tsk: usize,
 46        digits_tsk: usize,
 47        rank: usize,
 48    ) -> usize
 49    where
 50        Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxNormalizeTmpBytes,
 51    {
 52        GGSWCiphertext::automorphism_scratch_space(
 53            module, n, basek, k_out, k_out, k_ksk, digits_ksk, k_tsk, digits_tsk, rank,
 54        )
 55    }
 56}
 57
 58impl<DataSelf: DataMut> GGSWCiphertext<DataSelf> {
 59    pub fn automorphism<DataLhs: DataRef, DataAk: DataRef, DataTsk: DataRef, B: Backend>(
 60        &mut self,
 61        module: &Module<B>,
 62        lhs: &GGSWCiphertext<DataLhs>,
 63        auto_key: &GGLWEAutomorphismKeyExec<DataAk, B>,
 64        tensor_key: &GGLWETensorKeyExec<DataTsk, B>,
 65        scratch: &mut Scratch<B>,
 66    ) where
 67        Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAutomorphismInplace + VecZnxNormalizeTmpBytes,
 68        Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B>,
 69    {
 70        #[cfg(debug_assertions)]
 71        {
 72            assert_eq!(self.n(), auto_key.n());
 73            assert_eq!(lhs.n(), auto_key.n());
 74
 75            assert_eq!(
 76                self.rank(),
 77                lhs.rank(),
 78                "ggsw_out rank: {} != ggsw_in rank: {}",
 79                self.rank(),
 80                lhs.rank()
 81            );
 82            assert_eq!(
 83                self.rank(),
 84                auto_key.rank(),
 85                "ggsw_in rank: {} != auto_key rank: {}",
 86                self.rank(),
 87                auto_key.rank()
 88            );
 89            assert_eq!(
 90                self.rank(),
 91                tensor_key.rank(),
 92                "ggsw_in rank: {} != tensor_key rank: {}",
 93                self.rank(),
 94                tensor_key.rank()
 95            );
 96            assert!(
 97                scratch.available()
 98                    >= GGSWCiphertext::automorphism_scratch_space(
 99                        module,
100                        self.n(),
101                        self.basek(),
102                        self.k(),
103                        lhs.k(),
104                        auto_key.k(),
105                        auto_key.digits(),
106                        tensor_key.k(),
107                        tensor_key.digits(),
108                        self.rank(),
109                    )
110            )
111        };
112
113        self.automorphism_internal(module, lhs, auto_key, scratch);
114        self.expand_row(module, tensor_key, scratch);
115    }
116
117    pub fn automorphism_inplace<DataKsk: DataRef, DataTsk: DataRef, B: Backend>(
118        &mut self,
119        module: &Module<B>,
120        auto_key: &GGLWEAutomorphismKeyExec<DataKsk, B>,
121        tensor_key: &GGLWETensorKeyExec<DataTsk, B>,
122        scratch: &mut Scratch<B>,
123    ) where
124        Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAutomorphismInplace + VecZnxNormalizeTmpBytes,
125        Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B>,
126    {
127        unsafe {
128            let self_ptr: *mut GGSWCiphertext<DataSelf> = self as *mut GGSWCiphertext<DataSelf>;
129            self.automorphism(module, &*self_ptr, auto_key, tensor_key, scratch);
130        }
131    }
132
133    fn automorphism_internal<DataLhs: DataRef, DataAk: DataRef, B: Backend>(
134        &mut self,
135        module: &Module<B>,
136        lhs: &GGSWCiphertext<DataLhs>,
137        auto_key: &GGLWEAutomorphismKeyExec<DataAk, B>,
138        scratch: &mut Scratch<B>,
139    ) where
140        Module<B>: GLWEKeyswitchFamily<B> + GGSWKeySwitchFamily<B> + VecZnxAutomorphismInplace + VecZnxNormalizeTmpBytes,
141        Scratch<B>: ScratchAvailable + TakeVecZnxDft<B> + TakeVecZnxBig<B>,
142    {
143        // Keyswitch the j-th row of the col 0
144        (0..lhs.rows()).for_each(|row_i| {
145            // Key-switch column 0, i.e.
146            // col 0: (-(a0s0 + a1s1 + a2s2) + M[i], a0, a1, a2) -> (-(a0pi^-1(s0) + a1pi^-1(s1) + a2pi^-1(s2)) + M[i], a0, a1, a2)
147            self.at_mut(row_i, 0)
148                .automorphism(module, &lhs.at(row_i, 0), auto_key, scratch);
149        });
150    }
151}