add bool noise
Janmajaya Mall janmajayamall@protonmail.com
Tue, 04 Jun 2024 17:46:08 +0530
6 files changed,
197 insertions(+),
56 deletions(-)
M
src/bool/evaluator.rs
→
src/bool/evaluator.rs
@@ -1,4 +1,5 @@
use std::{ + borrow::BorrowMut, cell::{OnceCell, RefCell}, clone, collections::HashMap,@@ -1808,11 +1809,11 @@ Vec<Vec<u64>>,
NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModularOpsU64<CiphertextModulus<u64>>, - >::new(MP_BOOL_PARAMS); + >::new(SP_BOOL_PARAMS); // let (_, collective_pk, _, _, server_key_eval, ideal_client_key) = // _multi_party_all_keygen(&bool_evaluator, 20); - let no_of_parties = 32; + let no_of_parties = 2; let lwe_q = bool_evaluator.pbs_info.parameters.lwe_q(); let rlwe_q = bool_evaluator.pbs_info.parameters.rlwe_q(); let lwe_n = bool_evaluator.pbs_info.parameters.lwe_n().0;@@ -1938,7 +1939,7 @@ let seeded_server_key =
bool_evaluator.aggregate_multi_party_server_key_shares(&server_key_shares); // Check noise in RGSW ciphertexts of ideal LWE secret elements - if true { + if false { let mut check = Stats { samples: vec![] }; izip!( ideal_client_key.sk_lwe().values.iter(),@@ -2040,7 +2041,7 @@ &seeded_server_key,
); // check noise in RLWE x RGSW(X^{s_i}) where RGSW is accunulated RGSW ciphertext - if true { + if false { let mut check = Stats { samples: vec![] }; izip!(@@ -2151,7 +2152,7 @@ )
} // check noise in Auto key - if true { + if false { let mut check = Stats { samples: vec![] }; let mut neg_s_poly =@@ -2219,7 +2220,7 @@ // check noise in RLWE(X^k) after sending RLWE(X) -> RLWE(X^k) using collective
// auto key if true { let mut check = Stats { samples: vec![] }; - + let br_q = bool_evaluator.pbs_info.br_q(); let g = bool_evaluator.pbs_info.g(); let auto_element_dlogs = bool_evaluator.pbs_info.parameters.auto_element_dlogs(); for i in auto_element_dlogs.into_iter() {@@ -2252,8 +2253,8 @@ rlwe_modop,
); let auto_key = server_key_eval_domain.galois_key_for_auto(i); - let g_pow = if i == 0 { -g } else { g.pow(i as u32) }; - let (auto_map_index, auto_map_sign) = generate_auto_map(rlwe_n, g_pow); + let (auto_map_index, auto_map_sign) = + bool_evaluator.pbs_info.rlwe_auto_map(i); let mut scratch = vec![vec![0u64; rlwe_n]; auto_decomposer.decomposition_count() + 2]; galois_auto(
M
src/bool/mod.rs
→
src/bool/mod.rs
@@ -19,7 +19,7 @@ utils::{Global, WithLocal},
}; thread_local! { - static BOOL_EVALUATOR: RefCell<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModularOpsU64<CiphertextModulus<u64>>>> = RefCell::new(BoolEvaluator::new(MP_BOOL_PARAMS)); + static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModularOpsU64<CiphertextModulus<u64>>>>> = RefCell::new(None); } static BOOL_SERVER_KEY: OnceLock<@@ -29,7 +29,7 @@
static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new(); pub fn set_parameter_set(parameter: &BoolParameters<u64>) { - BoolEvaluator::with_local_mut(|e| *e = BoolEvaluator::new(parameter.clone())) + BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(parameter.clone()))); } pub fn set_mp_seed(seed: [u8; 32]) {@@ -158,20 +158,20 @@ fn with_local<F, R>(func: F) -> R
where F: Fn(&Self) -> R, { - BOOL_EVALUATOR.with_borrow(|s| func(s)) + BOOL_EVALUATOR.with_borrow(|s| func(s.as_ref().expect("Parameters not set"))) } fn with_local_mut<F, R>(func: F) -> R where F: Fn(&mut Self) -> R, { - BOOL_EVALUATOR.with_borrow_mut(|s| func(s)) + BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set"))) } fn with_local_mut_mut<F, R>(func: &mut F) -> R where F: FnMut(&mut Self) -> R, { - BOOL_EVALUATOR.with_borrow_mut(|s| func(s)) + BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set"))) } }
A
src/bool/noise.rs
@@ -0,0 +1,159 @@
+use std::cell::RefCell; + +mod test { + use itertools::{izip, Itertools}; + + use crate::{ + backend::{ArithmeticOps, ModularOpsU64, Modulus}, + bool::{ + set_parameter_set, BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus, + ClientKey, PublicKey, ServerKeyEvaluationDomain, MP_BOOL_PARAMS, SMALL_MP_BOOL_PARAMS, + }, + lwe::{decrypt_lwe, LweSecret}, + ntt::NttBackendU64, + pbs::PbsInfo, + random::DefaultSecureRng, + rgsw::RlweSecret, + utils::Stats, + Secret, + }; + + #[test] + fn mp_noise() { + // set_parameter_set(&SMALL_MP_BOOL_PARAMS); + let mut evaluator = BoolEvaluator::< + Vec<Vec<u64>>, + NttBackendU64, + ModularOpsU64<CiphertextModulus<u64>>, + ModularOpsU64<CiphertextModulus<u64>>, + >::new(SMALL_MP_BOOL_PARAMS); + + let parties = 16; + + let mut rng = DefaultSecureRng::new(); + let mut pk_cr_seed = [0u8; 32]; + let mut bk_cr_seed = [0u8; 32]; + rng.fill_bytes(&mut pk_cr_seed); + rng.fill_bytes(&mut bk_cr_seed); + + let cks = (0..parties) + .into_iter() + .map(|_| evaluator.client_key()) + .collect_vec(); + + // construct ideal rlwe sk for meauring noise + let ideal_client_key = { + let mut ideal_rlwe_sk = vec![0i32; evaluator.parameters().rlwe_n().0]; + cks.iter().for_each(|k| { + izip!(ideal_rlwe_sk.iter_mut(), k.sk_rlwe().values()).for_each(|(ideal_i, s_i)| { + *ideal_i = *ideal_i + s_i; + }); + }); + let mut ideal_lwe_sk = vec![0i32; evaluator.parameters().lwe_n().0]; + cks.iter().for_each(|k| { + izip!(ideal_lwe_sk.iter_mut(), k.sk_lwe().values()).for_each(|(ideal_i, s_i)| { + *ideal_i = *ideal_i + s_i; + }); + }); + + ClientKey::new( + RlweSecret { + values: ideal_rlwe_sk, + }, + LweSecret { + values: ideal_lwe_sk, + }, + ) + }; + + // round 1 + let pk_shares = cks + .iter() + .map(|c| evaluator.multi_party_public_key_share(pk_cr_seed, c)) + .collect_vec(); + + // public key + let pk = PublicKey::<Vec<Vec<u64>>, DefaultSecureRng, ModularOpsU64<CiphertextModulus<u64>>>::from( + pk_shares.as_slice(), + ); + + // round 2 + let server_key_shares = cks + .iter() + .map(|c| evaluator.multi_party_server_key_share(bk_cr_seed, &pk.key(), c)) + .collect_vec(); + + let server_key = evaluator.aggregate_multi_party_server_key_shares(&server_key_shares); + let server_key_eval_domain = ServerKeyEvaluationDomain::from(&server_key); + + let mut m0 = false; + let mut m1 = true; + + let mut c_m0 = evaluator.pk_encrypt(pk.key(), m0); + let mut c_m1 = evaluator.pk_encrypt(pk.key(), m1); + + // println!( + // "Evaluator ciphertext modulus: {:?}", + // evaluator.parameters().rlwe_q() + // ); + + // { + // // let v = LWE_VEC.take(); + // let added = decrypt_lwe( + // &c_m1, + // ideal_client_key.sk_rlwe().values(), + // evaluator.pbs_info().modop_rlweq(), + // ); + // println!("Of interest {added}"); + // } + + let true_el_encoded = evaluator.parameters().rlwe_q().true_el(); + let false_el_encoded = evaluator.parameters().rlwe_q().false_el(); + + let mut stats = Stats::new(); + + for _ in 0..1000 { + let c_out = evaluator.xor(&c_m0, &c_m1, &server_key_eval_domain); + + // mp decrypt + let decryption_shares = cks + .iter() + .map(|c| evaluator.multi_party_decryption_share(&c_out, c)) + .collect_vec(); + let m_out = evaluator.multi_party_decrypt(&decryption_shares, &c_out); + let m_expected = (m0 ^ m1); + assert_eq!(m_expected, m_out, "Expected {m_expected} but got {m_out}"); + + // find noise update + { + let out = decrypt_lwe( + &c_out, + ideal_client_key.sk_rlwe().values(), + evaluator.pbs_info().modop_rlweq(), + ); + + let out_want = { + if m_expected == true { + true_el_encoded + } else { + false_el_encoded + } + }; + let diff = evaluator.pbs_info().modop_rlweq().sub(&out, &out_want); + + stats.add_more(&vec![evaluator + .pbs_info() + .rlwe_q() + .map_element_to_i64(&diff)]); + } + + m1 = m0; + m0 = m_out; + + c_m1 = c_m0; + c_m0 = c_out; + } + + println!("log2 std dev {}", stats.std_dev().abs().log2()); + } +}
M
src/bool/parameters.rs
→
src/bool/parameters.rs
@@ -177,7 +177,7 @@ #[derive(Clone, Copy, PartialEq)]
pub(crate) struct LweDimension(pub(crate) usize); #[derive(Clone, Copy, PartialEq)] pub(crate) struct PolynomialSize(pub(crate) usize); -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Debug)] /// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is /// true when modulus is native, false otherwise.@@ -328,38 +328,20 @@ g: 5,
w: 10, }; -// pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = -// BoolParameters::<u64> { rlwe_q: -// CiphertextModulus::new_non_native(36028797018820609), lwe_q: -// CiphertextModulus::new_non_native(1 << 20), br_q: 1 << 11, -// rlwe_n: PolynomialSize(1 << 11), -// lwe_n: LweDimension(600), -// lwe_decomposer_base: DecompostionLogBase(4), -// lwe_decomposer_count: DecompositionCount(5), -// rlrg_decomposer_base: DecompostionLogBase(11), -// rlrg_decomposer_count: (DecompositionCount(2), DecompositionCount(2)), -// rgrg_decomposer_base: DecompostionLogBase(11), -// rgrg_decomposer_count: (DecompositionCount(5), DecompositionCount(4)), -// auto_decomposer_base: DecompostionLogBase(11), -// auto_decomposer_count: DecompositionCount(2), -// g: 5, -// w: 10, -// }; - pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { rlwe_q: CiphertextModulus::new_non_native(36028797018820609), lwe_q: CiphertextModulus::new_non_native(1 << 20), br_q: 1 << 11, rlwe_n: PolynomialSize(1 << 11), - lwe_n: LweDimension(500), + lwe_n: LweDimension(600), lwe_decomposer_base: DecompostionLogBase(4), lwe_decomposer_count: DecompositionCount(5), rlrg_decomposer_base: DecompostionLogBase(11), - rlrg_decomposer_count: (DecompositionCount(5), DecompositionCount(5)), + rlrg_decomposer_count: (DecompositionCount(2), DecompositionCount(2)), rgrg_decomposer_base: DecompostionLogBase(11), - rgrg_decomposer_count: (DecompositionCount(5), DecompositionCount(5)), + rgrg_decomposer_count: (DecompositionCount(5), DecompositionCount(4)), auto_decomposer_base: DecompostionLogBase(11), - auto_decomposer_count: DecompositionCount(5), + auto_decomposer_count: DecompositionCount(2), g: 5, w: 10, };
M
src/random.rs
→
src/random.rs
@@ -107,19 +107,19 @@ }
impl<T, C> RandomFillGaussianInModulus<[T], C> for DefaultSecureRng where - T: PrimInt + SampleUniform, + T: PrimInt, C: Modulus<Element = T>, { fn random_fill(&mut self, modulus: &C, container: &mut [T]) { - // izip!( - // rand_distr::Normal::new(0.0, 3.19f64) - // .unwrap() - // .sample_iter(&mut self.rng), - // container.iter_mut() - // ) - // .for_each(|(from, to)| { - // *to = modulus.map_element_from_f64(from); - // }); + izip!( + rand_distr::Normal::new(0.0, 3.19f64) + .unwrap() + .sample_iter(&mut self.rng), + container.iter_mut() + ) + .for_each(|(from, to)| { + *to = modulus.map_element_from_f64(from); + }); } }@@ -173,12 +173,11 @@ }
impl<T, M: Modulus<Element = T>> RandomGaussianElementInModulus<T, M> for DefaultSecureRng { fn random(&mut self, modulus: &M) -> T { - // modulus.map_element_from_f64( - // rand_distr::Normal::new(0.0, 3.19f64) - // .unwrap() - // .sample(&mut self.rng), - // ) - modulus.map_element_from_f64(0.0) + modulus.map_element_from_f64( + rand_distr::Normal::new(0.0, 3.19f64) + .unwrap() + .sample(&mut self.rng), + ) } }
M
src/rgsw.rs
→
src/rgsw.rs
@@ -1906,13 +1906,13 @@ }
#[test] fn galois_auto_works() { - let logq = 50; - let ring_size = 1 << 8; + let logq = 55; + let ring_size = 1 << 11; let q = generate_prime(logq, 2 * ring_size, 1u64 << logq).unwrap(); let logp = 3; let p = 1u64 << logp; - let d_rgsw = 10; - let logb = 5; + let d_rgsw = 5; + let logb = 11; let mut rng = DefaultSecureRng::new(); let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);