use crate::bin_fhe::bdd_arithmetic::FheUintPreparedDebug; use crate::bin_fhe::circuit_bootstrapping::CircuitBootstrappingKeyInfos; use crate::bin_fhe::{ bdd_arithmetic::{FheUint, UnsignedInteger}, blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory}, circuit_bootstrapping::{ CircuitBootstrappingKey, CircuitBootstrappingKeyEncryptSk, CircuitBootstrappingKeyLayout, CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory, }, }; use poulpy_core::GLWESwitchingKeyEncryptSk; use poulpy_core::layouts::{ GGLWEInfos, GLWEAutomorphismKeyHelper, GLWEAutomorphismKeyPrepared, GLWESecret, GLWESwitchingKey, GLWESwitchingKeyLayout, GLWESwitchingKeyPrepared, }; use poulpy_core::{ GLWEToLWESwitchingKeyEncryptSk, GetDistribution, ScratchTakeCore, layouts::{ GLWEInfos, GLWESecretToRef, GLWEToLWEKey, GLWEToLWEKeyLayout, GLWEToLWEKeyPreparedFactory, LWEInfos, LWESecretToRef, prepared::GLWEToLWEKeyPrepared, }, }; use poulpy_hal::{ layouts::{Backend, Data, DataMut, DataRef, Module, Scratch}, source::Source, }; pub trait BDDKeyInfos { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout; fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout; fn ks_glwe_infos(&self) -> Option; } #[derive(Debug, Clone, Copy)] pub struct BDDKeyLayout { pub cbt_layout: CircuitBootstrappingKeyLayout, pub ks_glwe_layout: Option, pub ks_lwe_layout: GLWEToLWEKeyLayout, } impl BDDKeyInfos for BDDKeyLayout { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout { self.cbt_layout } fn ks_glwe_infos(&self) -> Option { self.ks_glwe_layout } fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout { self.ks_lwe_layout } } pub struct BDDKey where D: Data, BRA: BlindRotationAlgo, { pub(crate) cbt: CircuitBootstrappingKey, pub(crate) ks_glwe: Option>, pub(crate) ks_lwe: GLWEToLWEKey, } impl BDDKey, BRA> where BlindRotationKey, BRA>: BlindRotationKeyFactory, { pub fn alloc_from_infos(infos: &A) -> Self where A: BDDKeyInfos, { Self { cbt: CircuitBootstrappingKey::alloc_from_infos(&infos.cbt_infos()), ks_glwe: infos.ks_glwe_infos().as_ref().map(GLWESwitchingKey::alloc_from_infos), ks_lwe: GLWEToLWEKey::alloc_from_infos(&infos.ks_lwe_infos()), } } } pub trait BDDKeyEncryptSk { fn bdd_key_encrypt_sk_tmp_bytes(&self, infos: &A) -> usize where A: BDDKeyInfos; fn bdd_key_encrypt_sk( &self, res: &mut BDDKey, sk_lwe: &S0, sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, ) where D: DataMut, S0: LWESecretToRef + GetDistribution + LWEInfos, S1: GLWESecretToRef + GetDistribution + GLWEInfos; } impl BDDKeyEncryptSk for Module where Self: CircuitBootstrappingKeyEncryptSk + GLWEToLWESwitchingKeyEncryptSk + GLWESwitchingKeyEncryptSk, Scratch: ScratchTakeCore, { fn bdd_key_encrypt_sk_tmp_bytes(&self, infos: &A) -> usize where A: BDDKeyInfos, { self.circuit_bootstrapping_key_encrypt_sk_tmp_bytes(&infos.cbt_infos()) .max(self.glwe_to_lwe_key_encrypt_sk_tmp_bytes(&infos.ks_lwe_infos())) } fn bdd_key_encrypt_sk( &self, res: &mut BDDKey, sk_lwe: &S0, sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, ) where D: DataMut, S0: LWESecretToRef + GetDistribution + LWEInfos, S1: GLWESecretToRef + GetDistribution + GLWEInfos, { if let Some(key) = &mut res.ks_glwe { let mut sk_out: GLWESecret> = GLWESecret::alloc(sk_glwe.n(), key.rank_out()); sk_out.fill_ternary_prob(0.5, source_xe); key.encrypt_sk(self, sk_glwe, &sk_out, source_xa, source_xe, scratch); res.ks_lwe.encrypt_sk(self, sk_lwe, &sk_out, source_xa, source_xe, scratch); } else { res.ks_lwe.encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); } res.cbt.encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); } } impl BDDKey { pub fn encrypt_sk( &mut self, module: &M, sk_lwe: &S0, sk_glwe: &S1, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, ) where S0: LWESecretToRef + GetDistribution + LWEInfos, S1: GLWESecretToRef + GetDistribution + GLWEInfos, M: BDDKeyEncryptSk, Scratch: ScratchTakeCore, { module.bdd_key_encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); } } pub struct BDDKeyPrepared where D: Data, BRA: BlindRotationAlgo, BE: Backend, { pub(crate) cbt: CircuitBootstrappingKeyPrepared, pub(crate) ks_glwe: Option>, pub(crate) ks_lwe: GLWEToLWEKeyPrepared, } impl BDDKeyInfos for BDDKeyPrepared { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout { CircuitBootstrappingKeyLayout { brk_layout: self.cbt.brk_infos(), atk_layout: self.cbt.atk_infos(), tsk_layout: self.cbt.tsk_infos(), } } fn ks_glwe_infos(&self) -> Option { self.ks_glwe.as_ref().map(|ks_glwe| GLWESwitchingKeyLayout { n: ks_glwe.n(), base2k: ks_glwe.base2k(), k: ks_glwe.k(), rank_in: ks_glwe.rank_in(), rank_out: ks_glwe.rank_out(), dnum: ks_glwe.dnum(), dsize: ks_glwe.dsize(), }) } fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout { GLWEToLWEKeyLayout { n: self.ks_lwe.n(), base2k: self.ks_lwe.base2k(), k: self.ks_lwe.k(), rank_in: self.ks_lwe.rank_in(), dnum: self.ks_lwe.dnum(), } } } impl GLWEAutomorphismKeyHelper, BE> for BDDKeyPrepared { fn automorphism_key_infos(&self) -> poulpy_core::layouts::GGLWELayout { self.cbt.automorphism_key_infos() } fn get_automorphism_key(&self, k: i64) -> Option<&GLWEAutomorphismKeyPrepared> { self.cbt.get_automorphism_key(k) } } pub trait BDDKeyPreparedFactory where Self: Sized + CircuitBootstrappingKeyPreparedFactory + GLWEToLWEKeyPreparedFactory, { fn alloc_bdd_key_from_infos(&self, infos: &A) -> BDDKeyPrepared, BRA, BE> where A: BDDKeyInfos, { let ks_glwe = if let Some(ks_glwe_infos) = &infos.ks_glwe_infos() { Some(GLWESwitchingKeyPrepared::alloc_from_infos(self, ks_glwe_infos)) } else { None }; BDDKeyPrepared { cbt: CircuitBootstrappingKeyPrepared::alloc_from_infos(self, &infos.cbt_infos()), ks_glwe, ks_lwe: GLWEToLWEKeyPrepared::alloc_from_infos(self, &infos.ks_lwe_infos()), } } fn prepare_bdd_key_tmp_bytes(&self, infos: &A) -> usize where A: BDDKeyInfos, { self.circuit_bootstrapping_key_prepare_tmp_bytes(&infos.cbt_infos()) .max(self.prepare_glwe_to_lwe_key_tmp_bytes(&infos.ks_lwe_infos())) } fn prepare_bdd_key(&self, res: &mut BDDKeyPrepared, other: &BDDKey, scratch: &mut Scratch) where DM: DataMut, DR: DataRef, Scratch: ScratchTakeCore, { res.cbt.prepare(self, &other.cbt, scratch); if let Some(key_prep) = &mut res.ks_glwe { if let Some(other) = &other.ks_glwe { key_prep.prepare(self, other, scratch); } else { panic!("incompatible keys: res has Some(ks_glwe) but other has none") } } res.ks_lwe.prepare(self, &other.ks_lwe, scratch); } } impl BDDKeyPreparedFactory for Module where Self: Sized + CircuitBootstrappingKeyPreparedFactory + GLWEToLWEKeyPreparedFactory { } impl BDDKeyPrepared, BRA, BE> { pub fn alloc_from_infos(module: &M, infos: &A) -> Self where M: BDDKeyPreparedFactory, A: BDDKeyInfos, { module.alloc_bdd_key_from_infos(infos) } } impl BDDKeyHelper for BDDKeyPrepared { fn get_cbt_key( &self, ) -> ( &CircuitBootstrappingKeyPrepared, Option<&GLWESwitchingKeyPrepared>, &GLWEToLWEKeyPrepared, ) { (&self.cbt, self.ks_glwe.as_ref(), &self.ks_lwe) } } pub trait BDDKeyHelper { #[allow(clippy::type_complexity)] fn get_cbt_key( &self, ) -> ( &CircuitBootstrappingKeyPrepared, Option<&GLWESwitchingKeyPrepared>, &GLWEToLWEKeyPrepared, ); } pub trait FheUintPrepareDebug { fn fhe_uint_debug_prepare( &self, res: &mut FheUintPreparedDebug, bits: &FheUint, key: &BDDKeyPrepared, scratch: &mut Scratch, ) where DM: DataMut, DR0: DataRef, DR1: DataRef; }