use poulpy_hal::{ api::VecZnxAutomorphism, layouts::{Backend, DataMut, GaloisElement, Module, Scratch}, }; use crate::{ ScratchTakeCore, automorphism::glwe_ct::GLWEAutomorphism, layouts::{ GGLWE, GGLWEInfos, GGLWEPreparedToRef, GGLWEToMut, GGLWEToRef, GLWE, GLWEAutomorphismKey, GetGaloisElement, SetGaloisElement, }, }; impl GLWEAutomorphismKey> { pub fn automorphism_tmp_bytes(module: &M, res_infos: &R, a_infos: &A, key_infos: &K) -> usize where R: GGLWEInfos, A: GGLWEInfos, K: GGLWEInfos, M: GLWEAutomorphismKeyAutomorphism, { module.glwe_automorphism_key_automorphism_tmp_bytes(res_infos, a_infos, key_infos) } } impl GLWEAutomorphismKey { pub fn automorphism(&mut self, module: &M, a: &A, key: &K, scratch: &mut Scratch) where A: GGLWEToRef + GetGaloisElement + GGLWEInfos, K: GGLWEPreparedToRef + GetGaloisElement + GGLWEInfos, Scratch: ScratchTakeCore, M: GLWEAutomorphismKeyAutomorphism, { module.glwe_automorphism_key_automorphism(self, a, key, scratch); } pub fn automorphism_inplace(&mut self, module: &M, key: &K, scratch: &mut Scratch) where K: GGLWEPreparedToRef + GetGaloisElement + GGLWEInfos, Scratch: ScratchTakeCore, M: GLWEAutomorphismKeyAutomorphism, { module.glwe_automorphism_key_automorphism_inplace(self, key, scratch); } } impl GLWEAutomorphismKeyAutomorphism for Module where Self: GaloisElement + GLWEAutomorphism + VecZnxAutomorphism { } pub trait GLWEAutomorphismKeyAutomorphism where Self: GaloisElement + GLWEAutomorphism + VecZnxAutomorphism, { fn glwe_automorphism_key_automorphism_tmp_bytes(&self, res_infos: &R, a_infos: &A, key_infos: &K) -> usize where R: GGLWEInfos, A: GGLWEInfos, K: GGLWEInfos, { self.glwe_keyswitch_tmp_bytes(res_infos, a_infos, key_infos) } fn glwe_automorphism_key_automorphism(&self, res: &mut R, a: &A, key: &K, scratch: &mut Scratch) where R: GGLWEToMut + SetGaloisElement + GGLWEInfos, A: GGLWEToRef + GetGaloisElement + GGLWEInfos, K: GGLWEPreparedToRef + GetGaloisElement + GGLWEInfos, Scratch: ScratchTakeCore, { assert!( res.dnum().as_u32() <= a.dnum().as_u32(), "res dnum: {} > a dnum: {}", res.dnum(), a.dnum() ); assert_eq!( res.dsize(), a.dsize(), "res dnum: {} != a dnum: {}", res.dsize(), a.dsize() ); let cols_out: usize = (key.rank_out() + 1).into(); let cols_in: usize = key.rank_in().into(); let p: i64 = a.p(); let p_inv: i64 = self.galois_element_inv(p); { let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); let a: &GGLWE<&[u8]> = &a.to_ref(); for row in 0..res.dnum().as_usize() { for col in 0..cols_in { let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col); let a_ct: GLWE<&[u8]> = a.at(row, col); // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) for i in 0..cols_out { self.vec_znx_automorphism(p, res_tmp.data_mut(), i, &a_ct.data, i); } // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch); // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) (0..cols_out).for_each(|i| { self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch); }); } } } res.set_p((p * key.p()) % (self.cyclotomic_order() as i64)); } fn glwe_automorphism_key_automorphism_inplace(&self, res: &mut R, key: &K, scratch: &mut Scratch) where R: GGLWEToMut + SetGaloisElement + GetGaloisElement + GGLWEInfos, K: GGLWEPreparedToRef + GetGaloisElement + GGLWEInfos, Scratch: ScratchTakeCore, { assert_eq!( res.rank(), key.rank(), "key rank: {} != key rank: {}", res.rank(), key.rank() ); let cols_out: usize = (key.rank_out() + 1).into(); let cols_in: usize = key.rank_in().into(); let p: i64 = res.p(); let p_inv: i64 = self.galois_element_inv(p); { let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); for row in 0..res.dnum().as_usize() { for col in 0..cols_in { let mut res_tmp: GLWE<&mut [u8]> = res.at_mut(row, col); // Reverts the automorphism X^{-k}: (-pi^{-1}_{k}(s)a + s, a) to (-sa + pi_{k}(s), a) for i in 0..cols_out { self.vec_znx_automorphism_inplace(p, res_tmp.data_mut(), i, scratch); } // Key-switch (-sa + pi_{k}(s), a) to (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) self.glwe_keyswitch_inplace(&mut res_tmp, key, scratch); // Applies back the automorphism X^{-k}: (-pi^{-1}_{k'}(s)a + pi_{k}(s), a) to (-pi^{-1}_{k'+k}(s)a + s, a) for i in 0..cols_out { self.vec_znx_automorphism_inplace(p_inv, res_tmp.data_mut(), i, scratch); } } } } res.set_p((res.p() * key.p()) % (self.cyclotomic_order() as i64)); } }