Added glwe rank switch before glwe -> lwe
jump to
@@ -52,8 +52,8 @@ S: GLWESecretPreparedToRef<BE>,
{ let (mut pt_have, scratch_1) = scratch.take_glwe_plaintext(res); self.glwe_decrypt(res, &mut pt_have, sk_prepared, scratch_1); - //println!("pt_have: {pt_have}"); - //println!("pt_want: {}", pt_want.to_ref()); + // println!("pt_have: {pt_have}"); + // println!("pt_want: {}", pt_want.to_ref()); self.glwe_sub_inplace(&mut pt_have, pt_want); self.glwe_normalize_inplace(&mut pt_have, scratch_1); pt_have.data.stats(pt_have.base2k().into(), 0)
@@ -1,9 +1,10 @@
use poulpy_core::{ - GLWEAdd, GLWECopy, GLWEDecrypt, GLWEEncryptSk, GLWENoise, GLWEPacking, GLWERotate, GLWESub, GLWETrace, LWEFromGLWE, - ScratchTakeCore, + GLWEAdd, GLWECopy, GLWEDecrypt, GLWEEncryptSk, GLWEKeyswitch, GLWENoise, GLWEPacking, GLWERotate, GLWESub, GLWETrace, + LWEFromGLWE, ScratchTakeCore, layouts::{ - Base2K, Degree, GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEAutomorphismKeyHelper, GLWEInfos, GLWEPlaintextLayout, - GLWESecretPreparedToRef, GLWEToMut, GLWEToRef, GetGaloisElement, LWEInfos, LWEToMut, Rank, TorusPrecision, + Base2K, Degree, GGLWEInfos, GGLWEPreparedToRef, GLWE, GLWEAutomorphismKeyHelper, GLWEInfos, GLWELayout, + GLWEPlaintextLayout, GLWESecretPreparedToRef, GLWEToMut, GLWEToRef, GetGaloisElement, LWEInfos, LWEToMut, Rank, + TorusPrecision, }, }; use poulpy_hal::{@@ -323,16 +324,41 @@
impl<T: UnsignedInteger, BE: Backend> ScratchTakeBDD<T, BE> for Scratch<BE> where Self: ScratchTakeCore<BE> {} impl<D: DataRef, T: UnsignedInteger> FheUint<D, T> { - pub fn get_bit_lwe<R, K, M, BE: Backend>(&self, module: &M, bit: usize, res: &mut R, ks: &K, scratch: &mut Scratch<BE>) - where + pub fn get_bit_lwe<R, KGLWE, KLWE, M, BE: Backend>( + &self, + module: &M, + bit: usize, + res: &mut R, + ks_glwe: Option<&KGLWE>, + ks_lwe: &KLWE, + scratch: &mut Scratch<BE>, + ) where R: LWEToMut, - K: GGLWEPreparedToRef<BE> + GGLWEInfos, - M: ModuleLogN + LWEFromGLWE<BE> + GLWERotate<BE>, + KGLWE: GGLWEPreparedToRef<BE> + GGLWEInfos, + KLWE: GGLWEPreparedToRef<BE> + GGLWEInfos, + M: ModuleLogN + LWEFromGLWE<BE> + GLWERotate<BE> + GLWEKeyswitch<BE>, Scratch<BE>: ScratchTakeCore<BE>, { let log_gap: usize = module.log_n() - T::LOG_BITS as usize; - res.to_mut() - .from_glwe(module, self, T::bit_index(bit) << log_gap, ks, scratch); + if let Some(ks_glwe) = ks_glwe { + let (mut res_tmp, scratch_1) = scratch.take_glwe(&GLWELayout { + n: self.n(), + base2k: ks_lwe.base2k(), + k: ks_lwe.k().min(self.k()), + rank: ks_lwe.rank_out(), + }); + module.glwe_keyswitch(&mut res_tmp, self, ks_glwe, scratch_1); + res.to_mut().from_glwe( + module, + &res_tmp, + T::bit_index(bit) << log_gap, + ks_lwe, + scratch_1, + ); + } else { + res.to_mut() + .from_glwe(module, self, T::bit_index(bit) << log_gap, ks_lwe, scratch); + } } pub fn get_bit_glwe<R, K, M, H, BE: Backend>(&self, module: &M, bit: usize, res: &mut R, keys: &H, scratch: &mut Scratch<BE>)
@@ -333,7 +333,7 @@ DK: DataRef,
K: BDDKeyHelper<DK, BRA, BE> + BDDKeyInfos, { let bit_end = bit_start + bit_count; - let (cbt, ks) = key.get_cbt_key(); + let (cbt, ks_glwe, ks_lwe) = key.get_cbt_key(); assert!(bit_end <= T::BITS as usize);@@ -363,7 +363,14 @@ scope.spawn(move || {
let (mut tmp_ggsw, scratch_1) = scratch_thread.take_ggsw(ggsw_infos); let (mut tmp_lwe, scratch_2) = scratch_1.take_lwe(bits); for (local_bit, dst) in res_bits_chunk.iter_mut().enumerate() { - bits.get_bit_lwe(self, start + local_bit, &mut tmp_lwe, ks, scratch_2); + bits.get_bit_lwe( + self, + start + local_bit, + &mut tmp_lwe, + ks_glwe, + ks_lwe, + scratch_2, + ); cbt.execute_to_constant(self, &mut tmp_ggsw, &tmp_lwe, 1, 1, scratch_2); dst.prepare(self, &tmp_ggsw, scratch_2); }
@@ -126,7 +126,14 @@ {
let (_, scratch_1) = scratch.take_ggsw(res); let (mut tmp_lwe, scratch_2) = scratch_1.take_lwe(bits); for (bit, dst) in res.bits.iter_mut().enumerate() { - bits.get_bit_lwe(self, bit, &mut tmp_lwe, &key.ks, scratch_2); + bits.get_bit_lwe( + self, + bit, + &mut tmp_lwe, + key.ks_glwe.as_ref(), + &key.ks_lwe, + scratch_2, + ); key.cbt .execute_to_constant(self, dst, &tmp_lwe, 1, 1, scratch_2); }
@@ -9,7 +9,11 @@ CircuitBootstrappingKeyPrepared, CircuitBootstrappingKeyPreparedFactory,
}, }; -use poulpy_core::layouts::{GGLWEInfos, GLWEAutomorphismKeyHelper, GLWEAutomorphismKeyPrepared}; +use poulpy_core::GLWESwitchingKeyEncryptSk; +use poulpy_core::layouts::{ + GGLWEInfos, GLWEAutomorphismKeyHelper, GLWEAutomorphismKeyPrepared, GLWESecret, GLWESwitchingKey, GLWESwitchingKeyLayout, + GLWESwitchingKeyPrepared, +}; use poulpy_core::{ GLWEToLWESwitchingKeyEncryptSk, GetDistribution, ScratchTakeCore, layouts::{@@ -24,13 +28,15 @@ };
pub trait BDDKeyInfos { fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout; - fn ks_infos(&self) -> GLWEToLWEKeyLayout; + fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout; + fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout>; } #[derive(Debug, Clone, Copy)] pub struct BDDKeyLayout { pub cbt: CircuitBootstrappingKeyLayout, - pub ks: GLWEToLWEKeyLayout, + pub ks_glwe: Option<GLWESwitchingKeyLayout>, + pub ks_lwe: GLWEToLWEKeyLayout, } impl BDDKeyInfos for BDDKeyLayout {@@ -38,8 +44,12 @@ fn cbt_infos(&self) -> CircuitBootstrappingKeyLayout {
self.cbt } - fn ks_infos(&self) -> GLWEToLWEKeyLayout { - self.ks + fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> { + self.ks_glwe + } + + fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout { + self.ks_lwe } }@@ -49,7 +59,8 @@ D: Data,
BRA: BlindRotationAlgo, { pub(crate) cbt: CircuitBootstrappingKey<D, BRA>, - pub(crate) ks: GLWEToLWEKey<D>, + pub(crate) ks_glwe: Option<GLWESwitchingKey<D>>, + pub(crate) ks_lwe: GLWEToLWEKey<D>, } impl<BRA: BlindRotationAlgo> BDDKey<Vec<u8>, BRA>@@ -60,9 +71,16 @@ pub fn alloc_from_infos<A>(infos: &A) -> Self
where A: BDDKeyInfos, { + let ks_glwe: Option<GLWESwitchingKey<Vec<u8>>> = if let Some(ks_infos) = &infos.ks_glwe_infos() { + Some(GLWESwitchingKey::alloc_from_infos(ks_infos)) + } else { + None + }; + Self { cbt: CircuitBootstrappingKey::alloc_from_infos(&infos.cbt_infos()), - ks: GLWEToLWEKey::alloc_from_infos(&infos.ks_infos()), + ks_glwe: ks_glwe, + ks_lwe: GLWEToLWEKey::alloc_from_infos(&infos.ks_lwe_infos()), } } }@@ -88,7 +106,7 @@ }
impl<BE: Backend, BRA: BlindRotationAlgo> BDDKeyEncryptSk<BRA, BE> for Module<BE> where - Self: CircuitBootstrappingKeyEncryptSk<BRA, BE> + GLWEToLWESwitchingKeyEncryptSk<BE>, + Self: CircuitBootstrappingKeyEncryptSk<BRA, BE> + GLWEToLWESwitchingKeyEncryptSk<BE> + GLWESwitchingKeyEncryptSk<BE>, Scratch<BE>: ScratchTakeCore<BE>, { fn bdd_key_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize@@ -96,7 +114,7 @@ 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_infos())) + .max(self.glwe_to_lwe_key_encrypt_sk_tmp_bytes(&infos.ks_lwe_infos())) } fn bdd_key_encrypt_sk<D, S0, S1>(@@ -112,8 +130,17 @@ D: DataMut,
S0: LWESecretToRef + GetDistribution + LWEInfos, S1: GLWESecretToRef + GetDistribution + GLWEInfos, { - res.ks - .encrypt_sk(self, sk_lwe, sk_glwe, source_xa, source_xe, scratch); + if let Some(key) = &mut res.ks_glwe { + let mut sk_out: GLWESecret<Vec<u8>> = 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); }@@ -145,7 +172,8 @@ BRA: BlindRotationAlgo,
BE: Backend, { pub(crate) cbt: CircuitBootstrappingKeyPrepared<D, BRA, BE>, - pub(crate) ks: GLWEToLWEKeyPrepared<D, BE>, + pub(crate) ks_glwe: Option<GLWESwitchingKeyPrepared<D, BE>>, + pub(crate) ks_lwe: GLWEToLWEKeyPrepared<D, BE>, } impl<D: DataRef, BRA: BlindRotationAlgo, BE: Backend> BDDKeyInfos for BDDKeyPrepared<D, BRA, BE> {@@ -156,13 +184,28 @@ layout_atk: self.cbt.atk_infos(),
layout_tsk: self.cbt.tsk_infos(), } } - fn ks_infos(&self) -> GLWEToLWEKeyLayout { + fn ks_glwe_infos(&self) -> Option<GLWESwitchingKeyLayout> { + if let Some(ks_glwe) = &self.ks_glwe { + Some(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(), + }) + } else { + None + } + } + fn ks_lwe_infos(&self) -> GLWEToLWEKeyLayout { GLWEToLWEKeyLayout { - n: self.ks.n(), - base2k: self.ks.base2k(), - k: self.ks.k(), - rank_in: self.ks.rank_in(), - dnum: self.ks.dnum(), + 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(), } } }@@ -187,9 +230,19 @@ fn alloc_bdd_key_from_infos<A>(&self, infos: &A) -> BDDKeyPrepared<Vec<u8>, 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: GLWEToLWEKeyPrepared::alloc_from_infos(self, &infos.ks_infos()), + ks_glwe, + ks_lwe: GLWEToLWEKeyPrepared::alloc_from_infos(self, &infos.ks_lwe_infos()), } }@@ -198,7 +251,7 @@ where
A: BDDKeyInfos, { self.circuit_bootstrapping_key_prepare_tmp_bytes(&infos.cbt_infos()) - .max(self.prepare_glwe_to_lwe_key_tmp_bytes(&infos.ks_infos())) + .max(self.prepare_glwe_to_lwe_key_tmp_bytes(&infos.ks_lwe_infos())) } fn prepare_bdd_key<DM, DR>(&self, res: &mut BDDKeyPrepared<DM, BRA, BE>, other: &BDDKey<DR, BRA>, scratch: &mut Scratch<BE>)@@ -208,7 +261,16 @@ DR: DataRef,
Scratch<BE>: ScratchTakeCore<BE>, { res.cbt.prepare(self, &other.cbt, scratch); - res.ks.prepare(self, &other.ks, 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<BRA: BlindRotationAlgo, BE: Backend> BDDKeyPreparedFactory<BRA, BE> for Module<BE> where@@ -231,9 +293,10 @@ fn get_cbt_key(
&self, ) -> ( &CircuitBootstrappingKeyPrepared<D, BRA, BE>, + Option<&GLWESwitchingKeyPrepared<D, BE>>, &GLWEToLWEKeyPrepared<D, BE>, ) { - (&self.cbt, &self.ks) + (&self.cbt, self.ks_glwe.as_ref(), &self.ks_lwe) } }@@ -242,6 +305,7 @@ fn get_cbt_key(
&self, ) -> ( &CircuitBootstrappingKeyPrepared<D, BRA, BE>, + Option<&GLWESwitchingKeyPrepared<D, BE>>, &GLWEToLWEKeyPrepared<D, BE>, ); }
@@ -15,7 +15,7 @@
use crate::tfhe::{ bdd_arithmetic::{ FheUintPrepared, GGSWBlindRotation, - tests::test_suite::{TEST_BASE2K, TEST_RANK, TestContext}, + tests::test_suite::{TEST_FHEUINT_BASE2K, TEST_RANK, TestContext}, }, blind_rotation::BlindRotationAlgo, };@@ -37,7 +37,7 @@ {
let module: &Module<BE> = &test_context.module; let sk_glwe_prep: &GLWESecretPrepared<Vec<u8>, BE> = &test_context.sk_glwe; - let base2k: Base2K = TEST_BASE2K.into(); + let base2k: Base2K = TEST_FHEUINT_BASE2K.into(); let rank: Rank = TEST_RANK.into(); let k_ggsw_res: TorusPrecision = TorusPrecision(39); let k_ggsw_apply: TorusPrecision = TorusPrecision(52);
@@ -15,7 +15,7 @@
use crate::tfhe::{ bdd_arithmetic::{ FheUintPrepared, GLWEBlindRotation, - tests::test_suite::{TEST_BASE2K, TEST_RANK, TestContext}, + tests::test_suite::{TEST_FHEUINT_BASE2K, TEST_RANK, TestContext}, }, blind_rotation::BlindRotationAlgo, };@@ -35,7 +35,7 @@ {
let module: &Module<BE> = &test_context.module; let sk_glwe_prep: &GLWESecretPrepared<Vec<u8>, BE> = &test_context.sk_glwe; - let base2k: Base2K = TEST_BASE2K.into(); + let base2k: Base2K = TEST_FHEUINT_BASE2K.into(); let rank: Rank = TEST_RANK.into(); let k_glwe: TorusPrecision = TorusPrecision(26); let k_ggsw: TorusPrecision = TorusPrecision(39);
@@ -17,7 +17,7 @@
use crate::tfhe::{ bdd_arithmetic::{ FheUintPrepared, GLWEBlinSelection, - tests::test_suite::{TEST_BASE2K, TEST_RANK, TestContext}, + tests::test_suite::{TEST_FHEUINT_BASE2K, TEST_RANK, TestContext}, }, blind_rotation::BlindRotationAlgo, };@@ -37,7 +37,7 @@ {
let module: &Module<BE> = &test_context.module; let sk_glwe_prep: &GLWESecretPrepared<Vec<u8>, BE> = &test_context.sk_glwe; - let base2k: Base2K = TEST_BASE2K.into(); + let base2k: Base2K = TEST_FHEUINT_BASE2K.into(); let rank: Rank = TEST_RANK.into(); let k_glwe: TorusPrecision = TorusPrecision(26); let k_ggsw: TorusPrecision = TorusPrecision(39);
@@ -41,7 +41,8 @@ use poulpy_core::{
ScratchTakeCore, layouts::{ Base2K, Degree, Dnum, Dsize, GGLWEToGGSWKeyLayout, GGSWLayout, GLWEAutomorphismKeyLayout, GLWELayout, GLWESecret, - GLWESecretPrepared, GLWESecretPreparedFactory, GLWEToLWEKeyLayout, LWESecret, Rank, TorusPrecision, + GLWESecretPrepared, GLWESecretPreparedFactory, GLWESwitchingKeyLayout, GLWEToLWEKeyLayout, LWESecret, Rank, + TorusPrecision, }, };@@ -137,7 +138,11 @@ }
pub(crate) const TEST_N_GLWE: u32 = 256; pub(crate) const TEST_N_LWE: u32 = 77; -pub(crate) const TEST_BASE2K: u32 = 13; +pub(crate) const TEST_FHEUINT_BASE2K: u32 = 13; +pub(crate) const TEST_BRK_BASE2K: u32 = 12; +pub(crate) const TEST_ATK_BASE2K: u32 = 11; +pub(crate) const TEST_TSK_BASE2K: u32 = 10; +pub(crate) const TEST_LWE_BASE2K: u32 = 4; pub(crate) const TEST_K_GLWE: u32 = 26; pub(crate) const TEST_K_GGSW: u32 = 39; pub(crate) const TEST_BLOCK_SIZE: u32 = 7;@@ -145,14 +150,14 @@ pub(crate) const TEST_RANK: u32 = 2;
pub(crate) static TEST_GLWE_INFOS: GLWELayout = GLWELayout { n: Degree(TEST_N_GLWE), - base2k: Base2K(TEST_BASE2K), + base2k: Base2K(TEST_FHEUINT_BASE2K), k: TorusPrecision(TEST_K_GLWE), rank: Rank(TEST_RANK), }; pub(crate) static TEST_GGSW_INFOS: GGSWLayout = GGSWLayout { n: Degree(TEST_N_GLWE), - base2k: Base2K(TEST_BASE2K), + base2k: Base2K(TEST_FHEUINT_BASE2K), k: TorusPrecision(TEST_K_GGSW), rank: Rank(TEST_RANK), dnum: Dnum(2),@@ -164,33 +169,42 @@ cbt: CircuitBootstrappingKeyLayout {
layout_brk: BlindRotationKeyLayout { n_glwe: Degree(TEST_N_GLWE), n_lwe: Degree(TEST_N_LWE), - base2k: Base2K(TEST_BASE2K), + base2k: Base2K(TEST_BRK_BASE2K), k: TorusPrecision(52), - dnum: Dnum(3), + dnum: Dnum(4), rank: Rank(TEST_RANK), }, layout_atk: GLWEAutomorphismKeyLayout { n: Degree(TEST_N_GLWE), - base2k: Base2K(TEST_BASE2K), + base2k: Base2K(TEST_ATK_BASE2K), k: TorusPrecision(52), rank: Rank(TEST_RANK), - dnum: Dnum(3), + dnum: Dnum(4), dsize: Dsize(1), }, layout_tsk: GGLWEToGGSWKeyLayout { n: Degree(TEST_N_GLWE), - base2k: Base2K(TEST_BASE2K), + base2k: Base2K(TEST_TSK_BASE2K), k: TorusPrecision(52), rank: Rank(TEST_RANK), - dnum: Dnum(3), + dnum: Dnum(4), dsize: Dsize(1), }, }, - ks: GLWEToLWEKeyLayout { + ks_glwe: Some(GLWESwitchingKeyLayout { n: Degree(TEST_N_GLWE), - base2k: Base2K(TEST_BASE2K), - k: TorusPrecision(39), + base2k: Base2K(TEST_LWE_BASE2K), + k: TorusPrecision(20), rank_in: Rank(TEST_RANK), - dnum: Dnum(2), + rank_out: Rank(1), + dnum: Dnum(3), + dsize: Dsize(1), + }), + ks_lwe: GLWEToLWEKeyLayout { + n: Degree(TEST_N_GLWE), + base2k: Base2K(TEST_LWE_BASE2K), + k: TorusPrecision(16), + rank_in: Rank(1), + dnum: Dnum(3), }, };
@@ -13,7 +13,7 @@ use crate::tfhe::{
bdd_arithmetic::{ BDDKeyEncryptSk, BDDKeyPrepared, BDDKeyPreparedFactory, ExecuteBDDCircuit2WTo1W, FheUint, FheUintPrepare, FheUintPrepareDebug, FheUintPreparedDebug, FheUintPreparedEncryptSk, FheUintPreparedFactory, - tests::test_suite::{TEST_BASE2K, TEST_GGSW_INFOS, TEST_GLWE_INFOS, TestContext}, + tests::test_suite::{TEST_GGSW_INFOS, TEST_GLWE_INFOS, TestContext}, }, blind_rotation::{BlindRotationAlgo, BlindRotationKey, BlindRotationKeyFactory}, };@@ -73,7 +73,7 @@ // GGSW(value)
c_enc_prep_debug.prepare(module, &c_enc, bdd_key_prepared, scratch_2.borrow()); let max_noise = |col_i: usize| { - let mut noise: f64 = -(ggsw_infos.size() as f64 * TEST_BASE2K as f64) + SIGMA.log2() + 2.0; + let mut noise: f64 = -(ggsw_infos.size() as f64 * ggsw_infos.base2k().as_usize() as f64) + SIGMA.log2() + 2.0; noise += 0.5 * ggsw_infos.log_n() as f64; if col_i != 0 { noise += 0.5 * ggsw_infos.log_n() as f64@@ -87,7 +87,10 @@ let stats: Vec<Stats> = c_enc_prep_debug.noise(module, row, col, value, sk_glwe_prep, scratch.borrow());
for (i, stat) in stats.iter().enumerate() { let noise_have: f64 = stat.std().log2(); let noise_max: f64 = max_noise(col); - assert!(noise_have <= noise_max, "bit: {i} noise_have: {noise_have} > noise_max: {noise_max}") + assert!( + noise_have <= noise_max, + "bit: {i} noise_have: {noise_have} > noise_max: {noise_max}" + ) } } }