use poulpy_core::layouts::{ AutomorphismKey, AutomorphismKeyLayout, GGLWEInfos, GGSWInfos, GLWE, GLWEInfos, GLWESecret, LWEInfos, LWESecret, TensorKey, TensorKeyLayout, prepared::{GLWEAutomorphismKeyPrepared, GLWESecretPrepared, PrepareAlloc, TensorKeyPrepared}, }; use std::collections::HashMap; use poulpy_hal::{ api::{ ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolBytesOf, SvpPrepare, TakeScalarZnx, TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxFillUniform, VecZnxIdftApplyConsume, VecZnxIdftApplyTmpA, VecZnxNormalize, VecZnxNormalizeInplace, VecZnxNormalizeTmpBytes, VecZnxSub, VecZnxSubInplace, VecZnxSwitchRing, VmpPMatAlloc, VmpPrepare, }, layouts::{Backend, Data, DataRef, Module, Scratch}, source::Source, }; use crate::tfhe::blind_rotation::{ BlindRotationAlgo, BlindRotationKey, BlindRotationKeyAlloc, BlindRotationKeyEncryptSk, BlindRotationKeyInfos, BlindRotationKeyLayout, BlindRotationKeyPrepared, }; pub trait CircuitBootstrappingKeyInfos { fn brk_infos(&self) -> BlindRotationKeyLayout; fn atk_infos(&self) -> AutomorphismKeyLayout; fn tsk_infos(&self) -> TensorKeyLayout; } #[derive(Debug, Clone, Copy)] pub struct CircuitBootstrappingKeyLayout { pub layout_brk: BlindRotationKeyLayout, pub layout_atk: AutomorphismKeyLayout, pub layout_tsk: TensorKeyLayout, } impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout { fn atk_infos(&self) -> AutomorphismKeyLayout { self.layout_atk } fn brk_infos(&self) -> BlindRotationKeyLayout { self.layout_brk } fn tsk_infos(&self) -> TensorKeyLayout { self.layout_tsk } } pub trait CircuitBootstrappingKeyEncryptSk { #[allow(clippy::too_many_arguments)] fn encrypt_sk( module: &Module, sk_lwe: &LWESecret, sk_glwe: &GLWESecret, cbt_infos: &INFOS, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, ) -> Self where INFOS: CircuitBootstrappingKeyInfos, DLwe: DataRef, DGlwe: DataRef; } pub struct CircuitBootstrappingKey { pub(crate) brk: BlindRotationKey, pub(crate) tsk: TensorKey>, pub(crate) atk: HashMap>>, } impl CircuitBootstrappingKeyEncryptSk for CircuitBootstrappingKey, BRA> where BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, Module: SvpApplyDftToDft + VecZnxIdftApplyTmpA + VecZnxAddScalarInplace + VecZnxDftBytesOf + VecZnxBigNormalize + VecZnxDftApply + SvpApplyDftToDftInplace + VecZnxIdftApplyConsume + VecZnxNormalizeTmpBytes + VecZnxFillUniform + VecZnxSubInplace + VecZnxAddInplace + VecZnxNormalizeInplace + VecZnxAddNormal + VecZnxNormalize + VecZnxSub + SvpPrepare + VecZnxSwitchRing + SvpPPolBytesOf + SvpPPolAlloc + VecZnxAutomorphism, Scratch: TakeVecZnxDft + ScratchAvailable + TakeVecZnx + TakeScalarZnx + TakeSvpPPol + TakeVecZnxBig, { fn encrypt_sk( module: &Module, sk_lwe: &LWESecret, sk_glwe: &GLWESecret, cbt_infos: &INFOS, source_xa: &mut Source, source_xe: &mut Source, scratch: &mut Scratch, ) -> Self where INFOS: CircuitBootstrappingKeyInfos, DLwe: DataRef, DGlwe: DataRef, { assert_eq!(sk_lwe.n(), cbt_infos.brk_infos().n_lwe()); assert_eq!(sk_glwe.n(), cbt_infos.brk_infos().n_glwe()); assert_eq!(sk_glwe.n(), cbt_infos.atk_infos().n()); assert_eq!(sk_glwe.n(), cbt_infos.tsk_infos().n()); let atk_infos: AutomorphismKeyLayout = cbt_infos.atk_infos(); let brk_infos: BlindRotationKeyLayout = cbt_infos.brk_infos(); let trk_infos: TensorKeyLayout = cbt_infos.tsk_infos(); let mut auto_keys: HashMap>> = HashMap::new(); let gal_els: Vec = GLWE::trace_galois_elements(module); gal_els.iter().for_each(|gal_el| { let mut key: AutomorphismKey> = AutomorphismKey::alloc_from_infos(&atk_infos); key.encrypt_sk(module, *gal_el, sk_glwe, source_xa, source_xe, scratch); auto_keys.insert(*gal_el, key); }); let sk_glwe_prepared: GLWESecretPrepared, B> = sk_glwe.prepare_alloc(module, scratch); let mut brk: BlindRotationKey, BRA> = BlindRotationKey::, BRA>::alloc(&brk_infos); brk.encrypt_sk( module, &sk_glwe_prepared, sk_lwe, source_xa, source_xe, scratch, ); let mut tsk: TensorKey> = TensorKey::alloc_from_infos(&trk_infos); tsk.encrypt_sk(module, sk_glwe, source_xa, source_xe, scratch); Self { brk, atk: auto_keys, tsk, } } } pub struct CircuitBootstrappingKeyPrepared { pub(crate) brk: BlindRotationKeyPrepared, pub(crate) tsk: TensorKeyPrepared, B>, pub(crate) atk: HashMap, B>>, } impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared { fn atk_infos(&self) -> AutomorphismKeyLayout { let (_, atk) = self.atk.iter().next().expect("atk is empty"); AutomorphismKeyLayout { n: atk.n(), base2k: atk.base2k(), k: atk.k(), dnum: atk.dnum(), dsize: atk.dsize(), rank: atk.rank(), } } fn brk_infos(&self) -> BlindRotationKeyLayout { BlindRotationKeyLayout { n_glwe: self.brk.n_glwe(), n_lwe: self.brk.n_lwe(), base2k: self.brk.base2k(), k: self.brk.k(), dnum: self.brk.dnum(), rank: self.brk.rank(), } } fn tsk_infos(&self) -> TensorKeyLayout { TensorKeyLayout { n: self.tsk.n(), base2k: self.tsk.base2k(), k: self.tsk.k(), dnum: self.tsk.dnum(), dsize: self.tsk.dsize(), rank: self.tsk.rank(), } } } impl PrepareAlloc, BRA, B>> for CircuitBootstrappingKey where Module: VmpPMatAlloc + VmpPrepare, BlindRotationKey: PrepareAlloc, BRA, B>>, TensorKey: PrepareAlloc, B>>, AutomorphismKey: PrepareAlloc, B>>, { fn prepare_alloc(&self, module: &Module, scratch: &mut Scratch) -> CircuitBootstrappingKeyPrepared, BRA, B> { let brk: BlindRotationKeyPrepared, BRA, B> = self.brk.prepare_alloc(module, scratch); let tsk: TensorKeyPrepared, B> = self.tsk.prepare_alloc(module, scratch); let mut atk: HashMap, B>> = HashMap::new(); for (key, value) in &self.atk { atk.insert(*key, value.prepare_alloc(module, scratch)); } CircuitBootstrappingKeyPrepared { brk, tsk, atk } } }