diff --git a/Cargo.toml b/Cargo.toml index 64323eb..6194cd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ num-bigint-dig = { version = "0.8.4", features = ["prime"] } criterion = "0.5.1" [features] -default = ["interactive_mp"] interactive_mp = [] non_interactive_mp = [] diff --git a/src/bool/evaluator.rs b/src/bool/evaluator.rs index 8456799..d58c9d7 100644 --- a/src/bool/evaluator.rs +++ b/src/bool/evaluator.rs @@ -134,6 +134,16 @@ pub struct NonInteractiveMultiPartyCrs { pub(super) seed: S, } +impl NonInteractiveMultiPartyCrs<[u8; 32]> { + pub(super) fn random() -> Self { + DefaultSecureRng::with_local_mut(|rng| { + let mut seed = [0u8; 32]; + rng.fill_bytes(&mut seed); + Self { seed } + }) + } +} + impl NonInteractiveMultiPartyCrs { fn key_seed + RandomFill>(&self) -> S { let mut p_rng = R::new_with_seed(self.seed); @@ -2289,14 +2299,11 @@ mod tests { NonInteractiveServerKeyEvaluationDomain, PublicKey, ShoupNonInteractiveServerKeyEvaluationDomain, }, - parameters::{ - MP_BOOL_PARAMS, NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS, SMALL_MP_BOOL_PARAMS, - SP_TEST_BOOL_PARAMS, - }, + parameters::{MP_BOOL_PARAMS, NI_2P, SMALL_MP_BOOL_PARAMS, SP_TEST_BOOL_PARAMS}, }, evaluator, ntt::NttBackendU64, - parameters::OPTIMISED_SMALL_MP_BOOL_PARAMS, + parameters::I_2P, random::{RandomElementInModulus, DEFAULT_RNG}, rgsw::{ self, measure_noise, public_key_encrypt_rlwe, secret_key_encrypt_rlwe, @@ -2317,7 +2324,7 @@ mod tests { ModularOpsU64>, ModulusPowerOf2>, ShoupNonInteractiveServerKeyEvaluationDomain>>, - >::new(NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS); + >::new(NI_2P); let mp_seed = NonInteractiveMultiPartyCrs { seed: [1u8; 32] }; let ring_size = evaluator.parameters().rlwe_n().0; @@ -2433,5 +2440,4 @@ mod tests { } println!("Stats: {}", stats.std_dev().abs().log2()); } - } diff --git a/src/bool/keys.rs b/src/bool/keys.rs index 159dc1e..beb877b 100644 --- a/src/bool/keys.rs +++ b/src/bool/keys.rs @@ -751,6 +751,22 @@ pub(super) mod impl_server_key_eval_domain { &self.lwe_ksk } } + + #[cfg(test)] + impl super::super::print_noise::CollectRuntimeServerKeyStats + for ServerKeyEvaluationDomain + { + type M = M; + fn galois_key_for_auto(&self, k: usize) -> &Self::M { + self.galois_keys.get(&k).unwrap() + } + fn lwe_ksk(&self) -> &Self::M { + &self.lwe_ksk + } + fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M { + &self.rgsw_cts[s_index] + } + } } pub(crate) struct NonInteractiveServerKeyEvaluationDomain { @@ -935,6 +951,22 @@ pub(super) mod impl_non_interactive_server_key_eval_domain { } } } + + #[cfg(test)] + impl super::super::print_noise::CollectRuntimeServerKeyStats + for NonInteractiveServerKeyEvaluationDomain + { + type M = M; + fn galois_key_for_auto(&self, k: usize) -> &Self::M { + self.auto_keys.get(&k).unwrap() + } + fn lwe_ksk(&self) -> &Self::M { + &self.lwe_ksk + } + fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M { + &self.rgsw_cts[s_index] + } + } } pub struct SeededNonInteractiveMultiPartyServerKey { diff --git a/src/bool/mod.rs b/src/bool/mod.rs index 774c48a..08261dc 100644 --- a/src/bool/mod.rs +++ b/src/bool/mod.rs @@ -7,7 +7,6 @@ use keys::tests; pub(crate) use keys::PublicKey; #[cfg(feature = "interactive_mp")] -#[cfg(not(feature = "non_interactive_mp"))] mod mp_api; #[cfg(feature = "non_interactive_mp")] mod ni_mp_api; @@ -16,7 +15,6 @@ mod ni_mp_api; pub use ni_mp_api::*; #[cfg(feature = "interactive_mp")] -#[cfg(not(feature = "non_interactive_mp"))] pub use mp_api::*; pub type ClientKey = keys::ClientKey<[u8; 32], u64>; diff --git a/src/bool/ni_mp_api.rs b/src/bool/ni_mp_api.rs index 86961df..0110b24 100644 --- a/src/bool/ni_mp_api.rs +++ b/src/bool/ni_mp_api.rs @@ -15,7 +15,7 @@ use super::{ NonInteractiveServerKeyEvaluationDomain, SeededNonInteractiveMultiPartyServerKey, ShoupNonInteractiveServerKeyEvaluationDomain, }, - parameters::{BoolParameters, CiphertextModulus, NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS}, + parameters::{BoolParameters, CiphertextModulus, NI_2P}, ClientKey, ParameterSelector, }; @@ -39,9 +39,7 @@ static MULTI_PARTY_CRS: OnceLock> = OnceLo pub fn set_parameter_set(select: ParameterSelector) { match select { ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16 => { - BOOL_EVALUATOR.with_borrow_mut(|v| { - *v = Some(BoolEvaluator::new(NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS)) - }); + BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(NI_2P))); } _ => { panic!("Paramerters not supported") @@ -358,7 +356,13 @@ mod tests { use crate::{ backend::{GetModulus, Modulus}, - bool::{evaluator::BooleanGates, keys::SinglePartyClientKey}, + bool::{ + evaluator::BooleanGates, + keys::{ + tests::{ideal_sk_rlwe, measure_noise_lwe}, + SinglePartyClientKey, + }, + }, lwe::decrypt_lwe, rgsw::decrypt_rlwe, utils::{tests::Stats, TryConvertFrom1}, @@ -368,8 +372,6 @@ mod tests { use super::*; - - #[test] fn non_interactive_mp_bool_nand() { set_parameter_set(ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16); diff --git a/src/bool/noise.rs b/src/bool/noise.rs index 6851f9d..a84c255 100644 --- a/src/bool/noise.rs +++ b/src/bool/noise.rs @@ -13,7 +13,7 @@ mod test { }, evaluator::MultiPartyCrs, ntt::NttBackendU64, - parameters::OPTIMISED_SMALL_MP_BOOL_PARAMS, + parameters::I_2P, random::DefaultSecureRng, }; @@ -26,7 +26,7 @@ mod test { ModularOpsU64>, ModulusPowerOf2>, ShoupServerKeyEvaluationDomain>>, - >::new(OPTIMISED_SMALL_MP_BOOL_PARAMS); + >::new(I_2P); let parties = 2; diff --git a/src/bool/parameters.rs b/src/bool/parameters.rs index f6f801f..fc64e85 100644 --- a/src/bool/parameters.rs +++ b/src/bool/parameters.rs @@ -24,6 +24,7 @@ trait SingleDecomposerParams { impl DoubleDecomposerParams for ( DecompostionLogBase, + // Assume (Decomposition count for A, Decomposition count for B) (DecompositionCount, DecompositionCount), ) { @@ -486,7 +487,7 @@ pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters = BoolParameters:: = BoolParameters:: { +pub(crate) const I_2P: BoolParameters = BoolParameters:: { rlwe_q: CiphertextModulus::new_non_native(18014398509404161), lwe_q: CiphertextModulus::new_non_native(1 << 15), br_q: 1 << 11, @@ -508,7 +509,7 @@ pub(crate) const OPTIMISED_SMALL_MP_BOOL_PARAMS: BoolParameters = BoolParam variant: ParameterVariant::MultiParty, }; -pub(crate) const NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS: BoolParameters = BoolParameters:: { +pub(crate) const NI_2P: BoolParameters = BoolParameters:: { rlwe_q: CiphertextModulus::new_non_native(36028797018820609), lwe_q: CiphertextModulus::new_non_native(1 << 20), br_q: 1 << 11, diff --git a/src/bool/print_noise.rs b/src/bool/print_noise.rs index fb055b5..020e73e 100644 --- a/src/bool/print_noise.rs +++ b/src/bool/print_noise.rs @@ -1,29 +1,34 @@ -use std::{fmt::Debug, iter::Sum, thread::panicking}; +use std::{fmt::Debug, iter::Sum}; use itertools::izip; -use num_traits::{FromPrimitive, Pow, PrimInt, Zero}; +use num_traits::{FromPrimitive, PrimInt, Zero}; use rand_distr::uniform::SampleUniform; use crate::{ backend::{GetModulus, Modulus}, decomposer::RlweDecomposer, lwe::{decrypt_lwe, lwe_key_switch}, - parameters::{self, BoolParameters, CiphertextModulus}, - pbs::PbsKey, + parameters::{BoolParameters, CiphertextModulus}, random::{DefaultSecureRng, RandomFillUniformInModulus}, rgsw::{decrypt_rlwe, galois_auto, IsTrivial, RlweCiphertext}, - utils::{encode_x_pow_si_with_emebedding_factor, tests::Stats, TryConvertFrom1, WithLocal}, - ArithmeticOps, ClientKey, Decomposer, DefaultDecomposer, MatrixEntity, MatrixMut, ModInit, Ntt, - NttInit, RowEntity, RowMut, VectorOps, + utils::{encode_x_pow_si_with_emebedding_factor, tests::Stats, TryConvertFrom1}, + ArithmeticOps, ClientKey, Decomposer, MatrixEntity, MatrixMut, ModInit, Ntt, NttInit, + RowEntity, RowMut, VectorOps, }; -use super::{ - keys::{ - tests::{ideal_sk_lwe, ideal_sk_rlwe}, - SeededMultiPartyServerKey, ServerKeyEvaluationDomain, - }, - BoolEvaluator, -}; +use super::keys::tests::{ideal_sk_lwe, ideal_sk_rlwe}; + +pub(crate) trait CollectRuntimeServerKeyStats { + type M; + /// RGSW ciphertext X^{s[s_index]} in evaluation domain where s the LWE + /// secret + fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M; + /// Auto key in evaluation domain for automorphism g^k. For auto key for + /// automorphism corresponding to -g, set k = 0 + fn galois_key_for_auto(&self, k: usize) -> &Self::M; + /// LWE key switching key + fn lwe_ksk(&self) -> &Self::M; +} struct ServerKeyStats { brk_rgsw_cts: (Stats, Stats), @@ -68,10 +73,11 @@ fn collect_server_key_stats< + ArithmeticOps + ModInit> + GetModulus, Element = M::MatElement>, + S: CollectRuntimeServerKeyStats, >( parameters: BoolParameters, client_keys: &[ClientKey], - server_key: &ServerKeyEvaluationDomain, DefaultSecureRng, NttOp>, + server_key: &S, ) -> ServerKeyStats where M::R: RowMut + RowEntity + TryConvertFrom1<[i32], CiphertextModulus> + Clone, @@ -103,7 +109,9 @@ where // RGSW ciphertext noise // Check noise in RGSW ciphertexts of ideal LWE secret elements { - izip!(ideal_sk_lwe.iter(), server_key.rgsw_cts().iter()).for_each(|(s_i, rgsw_ct_i)| { + ideal_sk_lwe.iter().enumerate().for_each(|(s_index, s_i)| { + let rgsw_ct_i = server_key.rgsw_cts_lwe_si(s_index); + // X^{s[i]} let m_si = encode_x_pow_si_with_emebedding_factor::( *s_i, @@ -347,22 +355,23 @@ where mod tests { use itertools::Itertools; - use crate::{ - aggregate_public_key_shares, aggregate_server_key_shares, - bool::keys::ServerKeyEvaluationDomain, - evaluator::MultiPartyCrs, - gen_client_key, gen_mp_keys_phase1, gen_mp_keys_phase2, - parameters::{BoolParameters, CiphertextModulus}, - random::DefaultSecureRng, - set_mp_seed, set_parameter_set, - utils::WithLocal, - BoolEvaluator, DefaultDecomposer, ModularOpsU64, Ntt, NttBackendU64, - }; - use super::collect_server_key_stats; #[test] + #[cfg(feature = "interactive_mp")] fn qwerty() { + use crate::{ + aggregate_public_key_shares, aggregate_server_key_shares, + bool::keys::ServerKeyEvaluationDomain, + evaluator::MultiPartyCrs, + gen_client_key, gen_mp_keys_phase1, gen_mp_keys_phase2, + parameters::{BoolParameters, CiphertextModulus}, + random::DefaultSecureRng, + set_mp_seed, set_parameter_set, + utils::WithLocal, + BoolEvaluator, DefaultDecomposer, ModularOpsU64, Ntt, NttBackendU64, + }; + set_parameter_set(crate::ParameterSelector::HighCommunicationButFast2Party); set_mp_seed(MultiPartyCrs::random().seed); let parties = 2; @@ -386,6 +395,7 @@ mod tests { DefaultDecomposer, NttBackendU64, ModularOpsU64>, + _, >(parameters, &cks, &server_key_eval); println!( @@ -405,643 +415,58 @@ mod tests { server_key_stats.post_lwe_key_switch.std_dev().abs().log2() ); } -} - -// #[test] -// fn noise_tester() { -// let bool_evaluator = BoolEvaluator::< -// Vec>, -// NttBackendU64, -// ModularOpsU64>, -// ModularOpsU64>, -// ShoupServerKeyEvaluationDomain>>, -// >::new(OPTIMISED_SMALL_MP_BOOL_PARAMS); - -// // let (_, collective_pk, _, _, server_key_eval, ideal_client_key) = -// // _multi_party_all_keygen(&bool_evaluator, 20); -// 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; -// let rlwe_n = bool_evaluator.pbs_info.parameters.rlwe_n().0; -// let lwe_modop = &bool_evaluator.pbs_info.lwe_modop; -// let rlwe_nttop = &bool_evaluator.pbs_info.rlwe_nttop; -// let rlwe_modop = &bool_evaluator.pbs_info.rlwe_modop; - -// // let rgsw_rgsw_decomposer = &bool_evaluator -// // .pbs_info -// // .parameters -// // .rgsw_rgsw_decomposer::>(); -// // let rgsw_rgsw_gadget_a = rgsw_rgsw_decomposer.0.gadget_vector(); -// // let rgsw_rgsw_gadget_b = rgsw_rgsw_decomposer.1.gadget_vector(); - -// let rlwe_rgsw_decomposer = -// &bool_evaluator.pbs_info.rlwe_rgsw_decomposer; let rlwe_rgsw_gadget_a -// = rlwe_rgsw_decomposer.0.gadget_vector(); let rlwe_rgsw_gadget_b = -// rlwe_rgsw_decomposer.1.gadget_vector(); - -// let auto_decomposer = &bool_evaluator.pbs_info.auto_decomposer; -// let auto_gadget = auto_decomposer.gadget_vector(); - -// let parties = (0..no_of_parties) -// .map(|_| bool_evaluator.client_key()) -// .collect_vec(); - -// let int_mp_seed = MultiPartyCrs::random(); - -// let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.pbs_info.rlwe_n()]; -// parties.iter().for_each(|k| { -// izip!( -// ideal_rlwe_sk.iter_mut(), -// InteractiveMultiPartyClientKey::sk_rlwe(k).iter() -// ) -// .for_each(|(ideal_i, s_i)| { -// *ideal_i = *ideal_i + s_i; -// }); -// }); -// let mut ideal_lwe_sk = vec![0i32; bool_evaluator.pbs_info.lwe_n()]; -// parties.iter().for_each(|k| { -// izip!( -// ideal_lwe_sk.iter_mut(), -// InteractiveMultiPartyClientKey::sk_lwe(k).iter() -// ) -// .for_each(|(ideal_i, s_i)| { -// *ideal_i = *ideal_i + s_i; -// }); -// }); - -// let mut rng = DefaultSecureRng::new(); - -// // check noise in freshly encrypted RLWE ciphertext (ie var_fresh) -// if false { -// let mut rng = DefaultSecureRng::new(); -// let mut check = Stats { samples: vec![] }; -// for _ in 0..10 { -// // generate a new collective public key -// let mut pk_cr_seed = [0u8; 32]; -// rng.fill_bytes(&mut pk_cr_seed); -// let public_key_share = parties -// .iter() -// .map(|k| -// bool_evaluator.multi_party_public_key_share(&int_mp_seed, k)) -// .collect_vec(); let collective_pk = PublicKey::< -// Vec>, -// DefaultSecureRng, -// ModularOpsU64>, -// >::from(public_key_share.as_slice()); - -// let mut m = vec![0u64; rlwe_n]; -// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, -// m.as_mut_slice()); let mut rlwe_ct = vec![vec![0u64; rlwe_n]; -// 2]; public_key_encrypt_rlwe::<_, _, _, _, i32, _>( -// &mut rlwe_ct, -// collective_pk.key(), -// &m, -// rlwe_modop, -// rlwe_nttop, -// &mut rng, -// ); - -// let mut m_back = vec![0u64; rlwe_n]; -// decrypt_rlwe( -// &rlwe_ct, -// &ideal_rlwe_sk, -// &mut m_back, -// rlwe_nttop, -// rlwe_modop, -// ); - -// rlwe_modop.elwise_sub_mut(m_back.as_mut_slice(), -// m.as_slice()); - -// check.add_more(Vec::::try_convert_from(&m_back, -// rlwe_q).as_slice()); } - -// println!("Public key Std: {}", check.std_dev().abs().log2()); -// } - -// if true { -// // Generate server key shares -// let public_key_share = parties -// .iter() -// .map(|k| -// bool_evaluator.multi_party_public_key_share(&int_mp_seed, k)) -// .collect_vec(); let collective_pk = PublicKey::< -// Vec>, -// DefaultSecureRng, -// ModularOpsU64>, -// >::from(public_key_share.as_slice()); - -// let server_key_shares = parties -// .iter() -// .enumerate() -// .map(|(user_id, k)| { -// bool_evaluator.multi_party_server_key_share( -// user_id, -// no_of_parties, -// &int_mp_seed, -// collective_pk.key(), -// k, -// ) -// }) -// .collect_vec(); - -// let seeded_server_key = -// -// bool_evaluator.aggregate_multi_party_server_key_shares(&server_key_shares); -// } - -// // server key in Evaluation domain -// let runtime_server_key = -// ShoupServerKeyEvaluationDomain::from(ServerKeyEvaluationDomain::< -// _, -// _, -// DefaultSecureRng, -// NttBackendU64, -// >::from(&seeded_server_key)); - -// // check noise in RLWE x RGSW(X^{s_i}) where RGSW is accunulated RGSW -// ciphertext if false { -// let mut check = Stats { samples: vec![] }; - -// ideal_lwe_sk.iter().enumerate().for_each(|(index, s_i)| { -// let rgsw_ct_i = -// runtime_server_key.rgsw_ct_lwe_si(index).as_ref(); - -// let mut m = vec![0u64; rlwe_n]; -// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, -// m.as_mut_slice()); let mut rlwe_ct = vec![vec![0u64; rlwe_n]; -// 2]; public_key_encrypt_rlwe::<_, _, _, _, i32, _>( -// &mut rlwe_ct, -// collective_pk.key(), -// &m, -// rlwe_modop, -// rlwe_nttop, -// &mut rng, -// ); - -// let mut rlwe_after = RlweCiphertext::<_, DefaultSecureRng> { -// data: rlwe_ct.clone(), -// is_trivial: false, -// _phatom: PhantomData, -// }; -// let mut scratch = vec![ -// vec![0u64; rlwe_n]; -// std::cmp::max( -// rlwe_rgsw_decomposer.0.decomposition_count(), -// rlwe_rgsw_decomposer.1.decomposition_count() -// ) + 2 -// ]; -// rlwe_by_rgsw( -// &mut rlwe_after, -// rgsw_ct_i, -// &mut scratch, -// rlwe_rgsw_decomposer, -// rlwe_nttop, -// rlwe_modop, -// ); - -// // m1 = X^{s[i]} -// let mut m1 = vec![0u64; rlwe_n]; -// let s_i = *s_i * (bool_evaluator.pbs_info.embedding_factor as -// i32); if s_i < 0 { -// m1[rlwe_n - (s_i.abs() as usize)] = rlwe_q.neg_one() -// } else { -// m1[s_i as usize] = 1; -// } - -// // (m+e) * m1 -// let mut m_plus_e_times_m1 = vec![0u64; rlwe_n]; -// decrypt_rlwe( -// &rlwe_ct, -// &ideal_rlwe_sk, -// &mut m_plus_e_times_m1, -// rlwe_nttop, -// rlwe_modop, -// ); -// rlwe_nttop.forward(m_plus_e_times_m1.as_mut_slice()); -// rlwe_nttop.forward(m1.as_mut_slice()); - -// rlwe_modop.elwise_mul_mut(m_plus_e_times_m1.as_mut_slice(), -// m1.as_slice()); -// rlwe_nttop.backward(m_plus_e_times_m1.as_mut_slice()); - -// // Resulting RLWE ciphertext will equal: (m0m1 + em1) + -// e_{rlsw x rgsw}. // Hence, resulting rlwe ciphertext will -// have error em1 + e_{rlwe x rgsw}. // Here we're only -// concerned with e_{rlwe x rgsw}, that is noise added by // -// RLWExRGSW. Also note in practice m1 is a monomial, for ex, X^{s_{i}}, for -// // some i and var(em1) = var(e). -// let mut m_plus_e_times_m1_more_e = vec![0u64; rlwe_n]; -// decrypt_rlwe( -// &rlwe_after, -// &ideal_rlwe_sk, -// &mut m_plus_e_times_m1_more_e, -// rlwe_nttop, -// rlwe_modop, -// ); - -// // diff -// rlwe_modop.elwise_sub_mut( -// m_plus_e_times_m1_more_e.as_mut_slice(), -// m_plus_e_times_m1.as_slice(), -// ); - -// // let noise = measure_noise( -// // &rlwe_after, -// // &m_plus_e_times_m1, -// // rlwe_nttop, -// // rlwe_modop, -// // ideal_client_key.sk_rlwe.values(), -// // ); -// // print!("NOISE: {}", noise); - -// check.add_more(&Vec::::try_convert_from( -// &m_plus_e_times_m1_more_e, -// rlwe_q, -// )); -// }); -// println!( -// "RLWE x RGSW, where RGSW has noise var_brk, std: {} {}", -// check.std_dev(), -// check.std_dev().abs().log2() -// ) -// } - -// // check noise in Auto key -// if false { -// let mut check = Stats { samples: vec![] }; - -// let mut neg_s_poly = -// Vec::::try_convert_from(ideal_rlwe_sk.as_slice(), rlwe_q); -// rlwe_modop.elwise_neg_mut(neg_s_poly.as_mut_slice()); - -// let g = bool_evaluator.pbs_info.g(); -// let br_q = bool_evaluator.pbs_info.br_q(); -// let auto_element_dlogs = -// bool_evaluator.pbs_info.parameters.auto_element_dlogs(); for i in -// auto_element_dlogs.into_iter() { let g_pow = if i == 0 { -// -g -// } else { -// (((g as usize).pow(i as u32)) % br_q) as isize -// }; - -// // -s[X^k] -// let (auto_indices, auto_sign) = generate_auto_map(rlwe_n, -// g_pow); let mut neg_s_poly_auto_i = vec![0u64; rlwe_n]; -// izip!(neg_s_poly.iter(), auto_indices.iter(), -// auto_sign.iter()).for_each( |(v, to_i, to_sign)| { -// if !to_sign { -// neg_s_poly_auto_i[*to_i] = rlwe_modop.neg(v); -// } else { -// neg_s_poly_auto_i[*to_i] = *v; -// } -// }, -// ); - -// let mut auto_key_i = -// runtime_server_key.galois_key_for_auto(i).as_ref().clone(); //send i^th auto -// key to coefficient domain auto_key_i -// .iter_mut() -// .for_each(|r| rlwe_nttop.backward(r.as_mut_slice())); -// auto_gadget.iter().enumerate().for_each(|(i, b_i)| { -// // B^i * -s[X^k] -// let mut m_ideal = neg_s_poly_auto_i.clone(); - -// rlwe_modop.elwise_scalar_mul_mut(m_ideal.as_mut_slice(), -// b_i); - -// let mut m_out = vec![0u64; rlwe_n]; -// let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; -// rlwe_ct[0].copy_from_slice(&auto_key_i[i]); -// rlwe_ct[1] -// -// .copy_from_slice(&auto_key_i[auto_decomposer.decomposition_count() + i]); -// decrypt_rlwe(&rlwe_ct, &ideal_rlwe_sk, &mut m_out, -// rlwe_nttop, rlwe_modop); - -// // diff -// rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(), -// m_ideal.as_slice()); - -// check.add_more(&Vec::::try_convert_from(&m_out, -// rlwe_q)); }); -// } - -// println!("Auto key noise std dev: {}", -// check.std_dev().abs().log2()); } - -// // check noise in RLWE(X^k) after sending RLWE(X) -> RLWE(X^k)using -// collective // auto key -// if false { -// 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() { for _ in 0..10 { -// let mut m = vec![0u64; rlwe_n]; -// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, -// m.as_mut_slice()); let mut rlwe_ct = RlweCiphertext::<_, -// DefaultSecureRng> { data: vec![vec![0u64; rlwe_n]; -// 2], is_trivial: false, -// _phatom: PhantomData, -// }; -// public_key_encrypt_rlwe::<_, _, _, _, i32, _>( -// &mut rlwe_ct, -// collective_pk.key(), -// &m, -// rlwe_modop, -// rlwe_nttop, -// &mut rng, -// ); - -// // We're only interested in noise increased as a result -// of automorphism. // Hence, we take m+e as the bench. -// let mut m_plus_e = vec![0u64; rlwe_n]; -// decrypt_rlwe( -// &rlwe_ct, -// &ideal_rlwe_sk, -// &mut m_plus_e, -// rlwe_nttop, -// rlwe_modop, -// ); - -// let auto_key = -// runtime_server_key.galois_key_for_auto(i).as_ref(); 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( -// &mut rlwe_ct, -// auto_key, -// &mut scratch, -// &auto_map_index, -// &auto_map_sign, -// rlwe_modop, -// rlwe_nttop, -// auto_decomposer, -// ); - -// // send m+e from X to X^k -// let mut m_plus_e_auto = vec![0u64; rlwe_n]; -// izip!(m_plus_e.iter(), auto_map_index.iter(), -// auto_map_sign.iter()).for_each( |(v, to_index, -// to_sign)| { if !to_sign { -// m_plus_e_auto[*to_index] = rlwe_modop.neg(v); -// } else { -// m_plus_e_auto[*to_index] = *v -// } -// }, -// ); - -// let mut m_out = vec![0u64; rlwe_n]; -// decrypt_rlwe(&rlwe_ct, &ideal_rlwe_sk, &mut m_out, -// rlwe_nttop, rlwe_modop); - -// // diff -// rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(), -// m_plus_e_auto.as_slice()); - -// -// check.add_more(&Vec::::try_convert_from(m_out.as_slice(), rlwe_q)); -// } -// } - -// println!("Rlwe Auto Noise Std: {}", -// check.std_dev().abs().log2()); } - -// // Check noise growth in ksk -// // TODO check in LWE key switching keys -// if false { -// // 1. encrypt LWE ciphertext -// // 2. Key switching -// // 3. -// let mut check = Stats { samples: vec![] }; - -// for _ in 0..1024 { -// // Encrypt m \in Q_{ks} using RLWE sk -// let mut lwe_in_ct = vec![0u64; rlwe_n + 1]; -// let m = RandomElementInModulus::random(&mut rng, -// &lwe_q.q().unwrap()); encrypt_lwe(&mut lwe_in_ct, &m, -// &ideal_rlwe_sk, lwe_modop, &mut rng); - -// // Key switch -// let mut lwe_out = vec![0u64; lwe_n + 1]; -// lwe_key_switch( -// &mut lwe_out, -// &lwe_in_ct, -// runtime_server_key.lwe_ksk(), -// lwe_modop, -// bool_evaluator.pbs_info.lwe_decomposer(), -// ); -// // We only care about noise added by LWE key switch -// // m+e -// let m_plus_e = decrypt_lwe(&lwe_in_ct, &ideal_rlwe_sk, -// lwe_modop); - -// let m_plus_e_plus_lwe_ksk_noise = decrypt_lwe(&lwe_out, -// &ideal_lwe_sk, lwe_modop); - -// let diff = lwe_modop.sub(&m_plus_e_plus_lwe_ksk_noise, -// &m_plus_e); - -// check.add_more(&vec![lwe_q.map_element_to_i64(&diff)]); -// } - -// println!("Lwe ksk std dev: {}", check.std_dev().abs().log2()); -// } -// } - -// // Check noise in fresh RGSW ciphertexts, ie X^{s_j[i]}, must equalnoise -// in // // fresh RLWE ciphertext -// if true {} -// // test LWE ksk from RLWE -> LWE -// // if false { -// // let logp = 2; -// // let mut rng = DefaultSecureRng::new(); - -// // let m = 1; -// // let encoded_m = m << (lwe_logq - logp); - -// // // Encrypt -// // let mut lwe_ct = vec![0u64; rlwe_n + 1]; -// // encrypt_lwe( -// // &mut lwe_ct, -// // &encoded_m, -// // ideal_client_key.sk_rlwe.values(), -// // lwe_modop, -// // &mut rng, -// // ); - -// // // key switch -// // let lwe_decomposer = &bool_evaluator.decomposer_lwe; -// // let mut lwe_out = vec![0u64; lwe_n + 1]; -// // lwe_key_switch( -// // &mut lwe_out, -// // &lwe_ct, -// // &server_key_eval.lwe_ksk, -// // lwe_modop, -// // lwe_decomposer, -// // ); - -// // let encoded_m_back = decrypt_lwe(&lwe_out, -// // ideal_client_key.sk_lwe.values(), lwe_modop); let m_back -// // = ((encoded_m_back as f64 * (1 << logp) as f64) / -// // (lwe_q as f64)).round() as u64; dbg!(m_back, m); - -// // let noise = measure_noise_lwe( -// // &lwe_out, -// // ideal_client_key.sk_lwe.values(), -// // lwe_modop, -// // &encoded_m, -// // ); - -// // println!("Noise: {noise}"); -// // } - -// // Measure noise in RGSW ciphertexts of ideal LWE secrets -// // if true { -// // let gadget_vec = gadget_vector( -// // bool_evaluator.parameters.rlwe_logq, -// // bool_evaluator.parameters.logb_rgsw, -// // bool_evaluator.parameters.d_rgsw, -// // ); - -// // for i in 0..20 { -// // // measure noise in RGSW(s[i]) -// // let si = -// // ideal_client_key.sk_lwe.values[i] * -// // (bool_evaluator.embedding_factor as i32); let mut -// // si_poly = vec![0u64; rlwe_n]; if si < 0 { -// // si_poly[rlwe_n - (si.abs() as usize)] = rlwe_q - 1; -// // } else { -// // si_poly[(si.abs() as usize)] = 1; -// // } - -// // let mut rgsw_si = server_key_eval.rgsw_cts[i].clone(); -// // rgsw_si -// // .iter_mut() -// // .for_each(|ri| rlwe_nttop.backward(ri.as_mut())); - -// // println!("####### Noise in RGSW(X^s_{i}) #######"); -// // _measure_noise_rgsw( -// // &rgsw_si, -// // &si_poly, -// // ideal_client_key.sk_rlwe.values(), -// // &gadget_vec, -// // rlwe_q, -// // ); -// // println!("####### ##################### #######"); -// // } -// // } - -// // // measure noise grwoth in RLWExRGSW -// // if true { -// // let mut rng = DefaultSecureRng::new(); -// // let mut carry_m = vec![0u64; rlwe_n]; -// // RandomUniformDist1::random_fill(&mut rng, &rlwe_q, -// // carry_m.as_mut_slice()); - -// // // RGSW(carrym) -// // let trivial_rlwect = vec![vec![0u64; rlwe_n],carry_m.clone()]; -// // let mut rlwe_ct = RlweCiphertext::<_, -// // DefaultSecureRng>::from_raw(trivial_rlwect, true); - -// // let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; -// // d_rgsw + 2]; let mul_mod = -// // |v0: &u64, v1: &u64| (((*v0 as u128 * *v1 as u128) % (rlwe_q -// as u128)) as u64); - -// // for i in 0..bool_evaluator.parameters.lwe_n { -// // rlwe_by_rgsw( -// // &mut rlwe_ct, -// // server_key_eval.rgsw_ct_lwe_si(i), -// // &mut scratch_matrix_dplus2_ring, -// // rlwe_decomposer, -// // rlwe_nttop, -// // rlwe_modop, -// // ); - -// // // carry_m[X] * s_i[X] -// // let si = -// // ideal_client_key.sk_lwe.values[i] * -// // (bool_evaluator.embedding_factor as i32); let mut -// // si_poly = vec![0u64; rlwe_n]; if si < 0 { -// // si_poly[rlwe_n - (si.abs() as usize)] = rlwe_q - 1; -// // } else { -// // si_poly[(si.abs() as usize)] = 1; -// // } -// // carry_m = negacyclic_mul(&carry_m, &si_poly, mul_mod, -// // rlwe_q); - -// // let noise = measure_noise( -// // &rlwe_ct, -// // &carry_m, -// // rlwe_nttop, -// // rlwe_modop, -// // ideal_client_key.sk_rlwe.values(), -// // ); -// // println!("Noise RLWE(carry_m) accumulating {i}^th secret -// // monomial: {noise}"); } -// // } - -// // // Check galois keys -// // if false { -// // let g = bool_evaluator.g() as isize; -// // let mut rng = DefaultSecureRng::new(); -// // let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; -// // d_rgsw + 2]; for i in [g, -g] { -// // let mut m = vec![0u64; rlwe_n]; -// // RandomUniformDist1::random_fill(&mut rng, &rlwe_q, -// // m.as_mut_slice()); let mut rlwe_ct = { -// // let mut data = vec![vec![0u64; rlwe_n]; 2]; -// // public_key_encrypt_rlwe( -// // &mut data, -// // &collective_pk.key, -// // &m, -// // rlwe_modop, -// // rlwe_nttop, -// // &mut rng, -// // ); -// // RlweCiphertext::<_, DefaultSecureRng>::from_raw(data, -// // false) }; + #[test] + #[cfg(feature = "non_interactive_mp")] + fn querty2() { + use crate::{ + aggregate_server_key_shares, bool::keys::NonInteractiveServerKeyEvaluationDomain, + evaluator::NonInteractiveMultiPartyCrs, gen_client_key, gen_server_key_share, + parameters::CiphertextModulus, random::DefaultSecureRng, set_common_reference_seed, + set_parameter_set, utils::WithLocal, BoolEvaluator, DefaultDecomposer, ModularOpsU64, + NttBackendU64, + }; -// // let auto_key = server_key_eval.galois_key_for_auto(i); -// // let (auto_map_index, auto_map_sign) = -// // generate_auto_map(rlwe_n, i); galois_auto( -// // &mut rlwe_ct, -// // auto_key, -// // &mut scratch_matrix_dplus2_ring, -// // &auto_map_index, -// // &auto_map_sign, -// // rlwe_modop, -// // rlwe_nttop, -// // rlwe_decomposer, -// // ); + set_parameter_set(crate::ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16); + set_common_reference_seed(NonInteractiveMultiPartyCrs::random().seed); + let parties = 2; + let cks = (0..parties).map(|i| gen_client_key()).collect_vec(); + let server_key_shares = cks + .iter() + .enumerate() + .map(|(user_id, k)| gen_server_key_share(user_id, parties, k)) + .collect_vec(); + let server_key = aggregate_server_key_shares(&server_key_shares); -// // // send m(X) -> m(X^i) -// // let mut m_k = vec![0u64; rlwe_n]; -// // izip!(m.iter(), auto_map_index.iter(), -// // auto_map_sign.iter()).for_each( |(mi, to_index,to_sign)| -// // // { if !to_sign { -// // m_k[*to_index] = rlwe_q - *mi; } else { -// // m_k[*to_index] = *mi; -// // } -// // }, -// // ); + let server_key_eval = + NonInteractiveServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from( + &server_key, + ); -// // // measure noise -// // let noise = measure_noise( -// // &rlwe_ct, -// // &m_k, -// // rlwe_nttop, -// // rlwe_modop, -// // ideal_client_key.sk_rlwe.values(), -// // ); + let parameters = BoolEvaluator::with_local(|e| e.parameters().clone()); + let server_key_stats = collect_server_key_stats::< + _, + DefaultDecomposer, + NttBackendU64, + ModularOpsU64>, + _, + >(parameters, &cks, &server_key_eval); -// // println!("Noise after auto k={i}: {noise}"); -// // } -// // } -// } + println!( + "Rgsw nsm std log2 {}", + server_key_stats.brk_rgsw_cts.0.std_dev().abs().log2() + ); + println!( + "Rgsw m std log2 {}", + server_key_stats.brk_rgsw_cts.1.std_dev().abs().log2() + ); + println!( + "rlwe post 1 auto std log2 {}", + server_key_stats.post_1_auto.std_dev().abs().log2() + ); + println!( + "key switching noise rlwe secret s to lwe secret z std log2 {}", + server_key_stats.post_lwe_key_switch.std_dev().abs().log2() + ); + } +}