use poulpy_hal::{ api::{VmpPMatAlloc, VmpPMatAllocBytes}, layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, }; use crate::layouts::{ Base2K, Degree, Dnum, Dsize, GGLWEInfos, GLWEInfos, LWEInfos, Rank, TensorKey, TensorKeyToRef, TorusPrecision, compressed::TensorKeyCompressedToMut, prepared::{ GLWESwitchingKeyPrepare, GLWESwitchingKeyPrepareTmpBytes, GLWESwitchingKeyPrepared, GLWESwitchingKeyPreparedToMut, GLWESwitchingKeyPreparedToRef, }, }; #[derive(PartialEq, Eq)] pub struct TensorKeyPrepared { pub(crate) keys: Vec>, } impl LWEInfos for TensorKeyPrepared { fn n(&self) -> Degree { self.keys[0].n() } fn base2k(&self) -> Base2K { self.keys[0].base2k() } fn k(&self) -> TorusPrecision { self.keys[0].k() } fn size(&self) -> usize { self.keys[0].size() } } impl GLWEInfos for TensorKeyPrepared { fn rank(&self) -> Rank { self.rank_out() } } impl GGLWEInfos for TensorKeyPrepared { fn rank_in(&self) -> Rank { self.rank_out() } fn rank_out(&self) -> Rank { self.keys[0].rank_out() } fn dsize(&self) -> Dsize { self.keys[0].dsize() } fn dnum(&self) -> Dnum { self.keys[0].dnum() } } impl TensorKeyPrepared, B> { pub fn alloc(module: &Module, infos: &A) -> Self where A: GGLWEInfos, Module: VmpPMatAlloc, { assert_eq!( infos.rank_in(), infos.rank_out(), "rank_in != rank_out is not supported for GGLWETensorKeyPrepared" ); Self::alloc_with( module, infos.base2k(), infos.k(), infos.dnum(), infos.dsize(), infos.rank_out(), ) } pub fn alloc_with(module: &Module, base2k: Base2K, k: TorusPrecision, dnum: Dnum, dsize: Dsize, rank: Rank) -> Self where Module: VmpPMatAlloc, { let mut keys: Vec, B>> = Vec::new(); let pairs: u32 = (((rank.0 + 1) * rank.0) >> 1).max(1); (0..pairs).for_each(|_| { keys.push(GLWESwitchingKeyPrepared::alloc( module, base2k, k, Rank(1), rank, dnum, dsize, )); }); Self { keys } } pub fn alloc_bytes(module: &Module, infos: &A) -> usize where A: GGLWEInfos, Module: VmpPMatAllocBytes, { assert_eq!( infos.rank_in(), infos.rank_out(), "rank_in != rank_out is not supported for GGLWETensorKey" ); let rank_out: usize = infos.rank_out().into(); let pairs: usize = (((rank_out + 1) * rank_out) >> 1).max(1); pairs * GLWESwitchingKeyPrepared::alloc_bytes( module, infos.base2k(), infos.k(), Rank(1), infos.rank_out(), infos.dnum(), infos.dsize(), ) } pub fn alloc_bytes_with(module: &Module, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where Module: VmpPMatAllocBytes, { let pairs: usize = (((rank.0 + 1) * rank.0) >> 1).max(1) as usize; pairs * GLWESwitchingKeyPrepared::alloc_bytes(module, base2k, k, Rank(1), rank, dnum, dsize) } } impl TensorKeyPrepared { // Returns a mutable reference to GLWESwitchingKey_{s}(s[i] * s[j]) pub fn at_mut(&mut self, mut i: usize, mut j: usize) -> &mut GLWESwitchingKeyPrepared { if i > j { std::mem::swap(&mut i, &mut j); }; let rank: usize = self.rank_out().into(); &mut self.keys[i * rank + j - (i * (i + 1) / 2)] } } impl TensorKeyPrepared { // Returns a reference to GLWESwitchingKey_{s}(s[i] * s[j]) pub fn at(&self, mut i: usize, mut j: usize) -> &GLWESwitchingKeyPrepared { if i > j { std::mem::swap(&mut i, &mut j); }; let rank: usize = self.rank_out().into(); &self.keys[i * rank + j - (i * (i + 1) / 2)] } } pub trait TensorKeyPrepareTmpBytes { fn tensor_key_prepare_tmp_bytes(&self, infos: &A) -> usize; } impl TensorKeyPrepareTmpBytes for Module where Module: GLWESwitchingKeyPrepareTmpBytes, { fn tensor_key_prepare_tmp_bytes(&self, infos: &A) -> usize { self.glwe_switching_key_prepare_tmp_bytes(infos) } } impl TensorKeyPrepared, B> where Module: TensorKeyPrepareTmpBytes, { fn prepare_tmp_bytes(&self, module: &Module, infos: &A) -> usize where A: GGLWEInfos, { module.tensor_key_prepare_tmp_bytes(infos) } } pub trait TensorKeyPrepare { fn tensor_key_prepare(&self, res: &mut R, other: &O, scratch: &Scratch) where R: TensorKeyPreparedToMut, O: TensorKeyToRef; } impl TensorKeyPrepare for Module where Module: GLWESwitchingKeyPrepare, { fn tensor_key_prepare(&self, res: &mut R, other: &O, scratch: &Scratch) where R: TensorKeyPreparedToMut, O: TensorKeyToRef, { let res = res.to_mut(); let other = other.to_ref(); assert_eq!(self.keys.len(), other.keys.len()); for (a, b) in res.keys.iter_mut().zip(other.keys.iter()) { self.glwe_switching_prepare(a, b, scratch); } } } impl TensorKeyPrepared where Module: TensorKeyPrepare, { fn prepare(&mut self, module: &Module, other: &O, scratch: &mut Scratch) where O: TensorKeyToRef, { module.tensor_key_prepare(self, other, scratch); } } pub trait TensorKeyPrepareAlloc { fn tensor_key_prepare_alloc(&self, other: &O, scratch: &mut Scratch) where O: TensorKeyToRef; } impl TensorKeyPrepareAlloc for Module where Module: TensorKeyPrepare, { fn tensor_key_prepare_alloc(&self, other: &O, scratch: &mut Scratch) where O: TensorKeyToRef, { let mut ct_prepared: TensorKeyPrepared, B> = TensorKeyPrepared::alloc(self, other); self.tensor_key_prepare(ct_prepared, other, scratch); ct_prepared } } impl TensorKey { pub fn prepare_alloc(&self, module: &Module, scratch: &Scratch) where Module: TensorKeyPrepareAlloc, { module.tensor_key_prepare_alloc(self, scratch); } } pub trait TensorKeyPreparedToMut { fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B>; } impl TensorKeyPreparedToMut for TensorKeyPrepared where GLWESwitchingKeyPrepared: GLWESwitchingKeyPreparedToMut, { fn to_mut(&mut self) -> TensorKeyPrepared<&mut [u8], B> { TensorKeyPrepared { keys: self.keys.iter_mut().map(|c| c.to_mut()).collect(), } } } pub trait TensorKeyPreparedToRef { fn to_ref(&self) -> TensorKeyPrepared<&[u8], B>; } impl TensorKeyPreparedToRef for TensorKeyPrepared where GLWESwitchingKeyPrepared: GLWESwitchingKeyPreparedToRef, { fn to_ref(&self) -> TensorKeyPrepared<&[u8], B> { TensorKeyPrepared { keys: self.keys.iter().map(|c| c.to_ref()).collect(), } } }