use poulpy_core::layouts::{ GGLWEAutomorphismKey, GGLWEAutomorphismKeyLayout, GGLWELayoutInfos, GGLWETensorKey, GGLWETensorKeyLayout, GGSWInfos, GLWECiphertext, GLWEInfos, GLWESecret, LWEInfos, LWESecret, prepared::{GGLWEAutomorphismKeyPrepared, GGLWETensorKeyPrepared, GLWESecretPrepared, PrepareAlloc}, }; use std::collections::HashMap; use poulpy_hal::{ api::{ ScratchAvailable, SvpApplyDftToDft, SvpApplyDftToDftInplace, SvpPPolAlloc, SvpPPolAllocBytes, SvpPrepare, TakeScalarZnx, TakeSvpPPol, TakeVecZnx, TakeVecZnxBig, TakeVecZnxDft, VecZnxAddInplace, VecZnxAddNormal, VecZnxAddScalarInplace, VecZnxAutomorphism, VecZnxBigNormalize, VecZnxDftAllocBytes, VecZnxDftApply, 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 layout_brk(&self) -> BlindRotationKeyLayout; fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout; fn layout_tsk(&self) -> GGLWETensorKeyLayout; } pub struct CircuitBootstrappingKeyLayout { pub layout_brk: BlindRotationKeyLayout, pub layout_atk: GGLWEAutomorphismKeyLayout, pub layout_tsk: GGLWETensorKeyLayout, } impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyLayout { fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout { self.layout_atk } fn layout_brk(&self) -> BlindRotationKeyLayout { self.layout_brk } fn layout_tsk(&self) -> GGLWETensorKeyLayout { 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: GGLWETensorKey>, pub(crate) atk: HashMap>>, } impl CircuitBootstrappingKeyEncryptSk for CircuitBootstrappingKey, BRA> where BlindRotationKey, BRA>: BlindRotationKeyAlloc + BlindRotationKeyEncryptSk, Module: SvpApplyDftToDft + VecZnxIdftApplyTmpA + VecZnxAddScalarInplace + VecZnxDftAllocBytes + VecZnxBigNormalize + VecZnxDftApply + SvpApplyDftToDftInplace + VecZnxIdftApplyConsume + VecZnxNormalizeTmpBytes + VecZnxFillUniform + VecZnxSubInplace + VecZnxAddInplace + VecZnxNormalizeInplace + VecZnxAddNormal + VecZnxNormalize + VecZnxSub + SvpPrepare + VecZnxSwitchRing + SvpPPolAllocBytes + 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, Module:, { assert_eq!(sk_lwe.n(), cbt_infos.layout_brk().n_lwe()); assert_eq!(sk_glwe.n(), cbt_infos.layout_brk().n_glwe()); assert_eq!(sk_glwe.n(), cbt_infos.layout_atk().n()); assert_eq!(sk_glwe.n(), cbt_infos.layout_tsk().n()); let atk_infos: GGLWEAutomorphismKeyLayout = cbt_infos.layout_atk(); let brk_infos: BlindRotationKeyLayout = cbt_infos.layout_brk(); let trk_infos: GGLWETensorKeyLayout = cbt_infos.layout_tsk(); let mut auto_keys: HashMap>> = HashMap::new(); let gal_els: Vec = GLWECiphertext::trace_galois_elements(module); gal_els.iter().for_each(|gal_el| { let mut key: GGLWEAutomorphismKey> = GGLWEAutomorphismKey::alloc(&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: GGLWETensorKey> = GGLWETensorKey::alloc(&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: GGLWETensorKeyPrepared, B>, pub(crate) atk: HashMap, B>>, } impl CircuitBootstrappingKeyInfos for CircuitBootstrappingKeyPrepared { fn layout_atk(&self) -> GGLWEAutomorphismKeyLayout { let (_, atk) = self.atk.iter().next().expect("atk is empty"); GGLWEAutomorphismKeyLayout { n: atk.n(), base2k: atk.base2k(), k: atk.k(), rows: atk.rows(), digits: atk.digits(), rank: atk.rank(), } } fn layout_brk(&self) -> BlindRotationKeyLayout { BlindRotationKeyLayout { n_glwe: self.brk.n_glwe(), n_lwe: self.brk.n_lwe(), base2k: self.brk.base2k(), k: self.brk.k(), rows: self.brk.rows(), rank: self.brk.rank(), } } fn layout_tsk(&self) -> GGLWETensorKeyLayout { GGLWETensorKeyLayout { n: self.tsk.n(), base2k: self.tsk.base2k(), k: self.tsk.k(), rows: self.tsk.rows(), digits: self.tsk.digits(), rank: self.tsk.rank(), } } } impl PrepareAlloc, BRA, B>> for CircuitBootstrappingKey where Module: VmpPMatAlloc + VmpPrepare, BlindRotationKey: PrepareAlloc, BRA, B>>, GGLWETensorKey: PrepareAlloc, B>>, GGLWEAutomorphismKey: 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: GGLWETensorKeyPrepared, 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 } } }