use poulpy_hal::{ api::{ ScratchAvailable, TakeVecZnx, TakeVecZnxDft, VecZnxBigAddSmallInplace, VecZnxBigNormalize, VecZnxBigNormalizeTmpBytes, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, }, layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, }; use crate::layouts::{ AutomorphismKey, GGLWEInfos, GLWE, GLWEInfos, GLWESwitchingKey, prepared::{AutomorphismKeyPrepared, GLWESwitchingKeyPrepared}, }; impl AutomorphismKey> { pub fn keyswitch_scratch_space( module: &Module, out_infos: &OUT, in_infos: &IN, key_infos: &KEY, ) -> usize where OUT: GGLWEInfos, IN: GGLWEInfos, KEY: GGLWEInfos, Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWESwitchingKey::keyswitch_scratch_space(module, out_infos, in_infos, key_infos) } pub fn keyswitch_inplace_scratch_space(module: &Module, out_infos: &OUT, key_infos: &KEY) -> usize where OUT: GGLWEInfos, KEY: GGLWEInfos, Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWESwitchingKey::keyswitch_inplace_scratch_space(module, out_infos, key_infos) } } impl AutomorphismKey { pub fn keyswitch( &mut self, module: &Module, lhs: &AutomorphismKey, rhs: &GLWESwitchingKeyPrepared, scratch: &mut Scratch, ) where Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VmpApplyDftToDft + VmpApplyDftToDftAdd + VecZnxDftApply + VecZnxIdftApplyConsume + VecZnxBigAddSmallInplace + VecZnxBigNormalize + VecZnxNormalize + VecZnxNormalizeTmpBytes, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, { self.key.keyswitch(module, &lhs.key, rhs, scratch); } pub fn keyswitch_inplace( &mut self, module: &Module, rhs: &AutomorphismKeyPrepared, scratch: &mut Scratch, ) where Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VmpApplyDftToDft + VmpApplyDftToDftAdd + VecZnxDftApply + VecZnxIdftApplyConsume + VecZnxBigAddSmallInplace + VecZnxBigNormalize + VecZnxNormalize + VecZnxNormalizeTmpBytes, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx, { self.key.keyswitch_inplace(module, &rhs.key, scratch); } } impl GLWESwitchingKey> { pub fn keyswitch_scratch_space( module: &Module, out_infos: &OUT, in_infos: &IN, key_apply: &KEY, ) -> usize where OUT: GGLWEInfos, IN: GGLWEInfos, KEY: GGLWEInfos, Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWE::keyswitch_scratch_space(module, out_infos, in_infos, key_apply) } pub fn keyswitch_inplace_scratch_space(module: &Module, out_infos: &OUT, key_apply: &KEY) -> usize where OUT: GGLWEInfos + GLWEInfos, KEY: GGLWEInfos + GLWEInfos, Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VecZnxNormalizeTmpBytes, { GLWE::keyswitch_inplace_scratch_space(module, out_infos, key_apply) } } impl GLWESwitchingKey { pub fn keyswitch( &mut self, module: &Module, lhs: &GLWESwitchingKey, rhs: &GLWESwitchingKeyPrepared, scratch: &mut Scratch, ) where Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VmpApplyDftToDft + VmpApplyDftToDftAdd + VecZnxDftApply + VecZnxIdftApplyConsume + VecZnxBigAddSmallInplace + VecZnxBigNormalize + VecZnxNormalize + VecZnxNormalizeTmpBytes, Scratch: ScratchAvailable + TakeVecZnxDft + TakeVecZnx, { #[cfg(debug_assertions)] { assert_eq!( self.rank_in(), lhs.rank_in(), "ksk_out input rank: {} != ksk_in input rank: {}", self.rank_in(), lhs.rank_in() ); assert_eq!( lhs.rank_out(), rhs.rank_in(), "ksk_in output rank: {} != ksk_apply input rank: {}", self.rank_out(), rhs.rank_in() ); assert_eq!( self.rank_out(), rhs.rank_out(), "ksk_out output rank: {} != ksk_apply output rank: {}", self.rank_out(), rhs.rank_out() ); assert!( self.dnum() <= lhs.dnum(), "self.dnum()={} > lhs.dnum()={}", self.dnum(), lhs.dnum() ); assert_eq!( self.dsize(), lhs.dsize(), "ksk_out dsize: {} != ksk_in dsize: {}", self.dsize(), lhs.dsize() ) } (0..self.rank_in().into()).for_each(|col_i| { (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .keyswitch(module, &lhs.at(row_j, col_i), rhs, scratch); }); }); (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { (0..self.rank_in().into()).for_each(|col_j| { self.at_mut(row_i, col_j).data.zero(); }); }); } pub fn keyswitch_inplace( &mut self, module: &Module, rhs: &GLWESwitchingKeyPrepared, scratch: &mut Scratch, ) where Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxBigNormalizeTmpBytes + VmpApplyDftToDft + VmpApplyDftToDftAdd + VecZnxDftApply + VecZnxIdftApplyConsume + VecZnxBigAddSmallInplace + VecZnxBigNormalize + VecZnxNormalize + VecZnxNormalizeTmpBytes, Scratch: ScratchAvailable + TakeVecZnxDft + TakeVecZnx, { #[cfg(debug_assertions)] { assert_eq!( self.rank_out(), rhs.rank_out(), "ksk_out output rank: {} != ksk_apply output rank: {}", self.rank_out(), rhs.rank_out() ); } (0..self.rank_in().into()).for_each(|col_i| { (0..self.dnum().into()).for_each(|row_j| { self.at_mut(row_j, col_i) .keyswitch_inplace(module, rhs, scratch) }); }); } }