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