From 88fdc6ac5c2ad8a0dd5979a78895db6fa0bed686 Mon Sep 17 00:00:00 2001 From: Janmajaya Mall Date: Mon, 17 Jun 2024 20:13:32 +0530 Subject: [PATCH] make enc and dec variant specific --- src/bool/evaluator.rs | 778 ++++++++++++++++++------------------------ src/bool/keys.rs | 190 ++++++----- src/bool/mod.rs | 10 +- src/bool/mp_api.rs | 96 +++++- src/bool/ni_mp_api.rs | 66 ++++ src/bool/noise.rs | 55 ++- src/noise.rs | 589 ++++++++++++++++---------------- src/shortint/mod.rs | 7 +- src/utils.rs | 11 + 9 files changed, 930 insertions(+), 872 deletions(-) diff --git a/src/bool/evaluator.rs b/src/bool/evaluator.rs index d712445..882bc84 100644 --- a/src/bool/evaluator.rs +++ b/src/bool/evaluator.rs @@ -38,23 +38,28 @@ use crate::{ RlweCiphertext, RlweSecret, }, utils::{ - fill_random_ternary_secret_with_hamming_weight, generate_prime, mod_exponent, Global, - TryConvertFrom1, WithLocal, + fill_random_ternary_secret_with_hamming_weight, generate_prime, mod_exponent, + puncture_p_rng, Global, TryConvertFrom1, WithLocal, }, Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, Row, RowEntity, RowMut, Secret, }; use super::{ - parameters::{BoolParameters, CiphertextModulus}, - ClientKey, CommonReferenceSeededCollectivePublicKeyShare, - CommonReferenceSeededMultiPartyServerKeyShare, DecompositionCount, DecompostionLogBase, - DoubleDecomposerParams, SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey, - SeededSinglePartyServerKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, - ThrowMeAwayKey, + keys::{ + ClientKey, CommonReferenceSeededCollectivePublicKeyShare, + CommonReferenceSeededMultiPartyServerKeyShare, InteractiveMultiPartyClientKey, + NonInteractiveMultiPartyClientKey, SeededMultiPartyServerKey, + SeededNonInteractiveMultiPartyServerKey, SeededSinglePartyServerKey, + ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, SinglePartyClientKey, + }, + parameters::{ + BoolParameters, CiphertextModulus, DecompositionCount, DecompostionLogBase, + DoubleDecomposerParams, + }, }; -pub struct SeededNonInteractiveMultiPartyServerKeyShare { +pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare { /// (ak*si + e + \beta ui, ak*si + e) ni_rgsw_cts: (Vec, Vec), ui_to_s_ksk: M, @@ -67,7 +72,7 @@ pub struct SeededNonInteractiveMultiPartyServerKeyShare { cr_seed: S, } -impl SeededNonInteractiveMultiPartyServerKeyShare { +impl CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare { fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M { assert!(user_i != self.user_index); if user_i < self.user_index { @@ -82,12 +87,14 @@ pub struct MultiPartyCrs { pub(super) seed: S, } -fn puncture_p_rng>(p_rng: &mut R, times: usize) -> S { - let mut out = S::default(); - for _ in 0..times { - RandomFill::::random_fill(p_rng, &mut out); +impl MultiPartyCrs<[u8; 32]> { + pub(super) fn random() -> Self { + DefaultSecureRng::with_local_mut(|rng| { + let mut seed = [0u8; 32]; + rng.fill_bytes(&mut seed); + Self { seed } + }) } - return out; } /// Common reference seed used for non-interactive multi-party. @@ -104,9 +111,6 @@ pub struct NonInteractiveMultiPartyCrs { pub(super) seed: S, } -// impl Clone for NonInteractiveMultiPartyCrs where S: Clone {} -// impl Copy for NonInteractiveMultiPartyCrs where S: Copy {} - impl NonInteractiveMultiPartyCrs { fn key_seed + RandomFill>(&self) -> S { let mut p_rng = R::new_with_seed(self.seed); @@ -651,37 +655,15 @@ where } } - pub(super) fn client_key(&self) -> ClientKey { - let sk_lwe = LweSecret::random( - self.pbs_info.parameters.lwe_n().0 >> 1, - self.pbs_info.parameters.lwe_n().0, - ); - let sk_rlwe = RlweSecret::random( - self.pbs_info.parameters.rlwe_n().0 >> 1, - self.pbs_info.parameters.rlwe_n().0, - ); - ClientKey::new(sk_rlwe, sk_lwe) - } - - pub(super) fn non_interactive_client_key(&self) -> ThrowMeAwayKey { - let sk_lwe = LweSecret::random( - self.pbs_info.parameters.lwe_n().0 >> 1, - self.pbs_info.parameters.lwe_n().0, - ); - let sk_rlwe = RlweSecret::random( - self.pbs_info.parameters.rlwe_n().0 >> 1, - self.pbs_info.parameters.rlwe_n().0, - ); - let sk_u_rlwe = RlweSecret::random( - self.pbs_info.parameters.rlwe_n().0 >> 1, - self.pbs_info.parameters.rlwe_n().0, - ); - ThrowMeAwayKey::new(sk_rlwe, sk_u_rlwe, sk_lwe) + pub(crate) fn client_key( + &self, + ) -> ClientKey<::Seed, M::MatElement> { + ClientKey::new(self.parameters().clone()) } - pub(super) fn single_party_server_key( + pub(super) fn single_party_server_key>( &self, - client_key: &ClientKey, + client_key: &K, ) -> SeededSinglePartyServerKey, [u8; 32]> { DefaultSecureRng::with_local_mut(|rng| { let mut main_seed = [0u8; 32]; @@ -708,7 +690,7 @@ where let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n); galois_key_gen( &mut gk, - sk_rlwe.values(), + &sk_rlwe, g_pow, &auto_gadget, &self.pbs_info.rlwe_modop, @@ -729,7 +711,6 @@ where let rlrg_gadget_a = self.pbs_info.rlwe_rgsw_decomposer.0.gadget_vector(); let rlrg_gadget_b = self.pbs_info.rlwe_rgsw_decomposer.1.gadget_vector(); let rgsw_cts = sk_lwe - .values() .iter() .map(|si| { // X^{si}; assume |emebedding_factor * si| < N @@ -750,7 +731,7 @@ where m.as_ref(), &rlrg_gadget_a, &rlrg_gadget_b, - sk_rlwe.values(), + &sk_rlwe, &self.pbs_info.rlwe_modop, &self.pbs_info.rlwe_nttop, &mut main_prng, @@ -766,8 +747,8 @@ where let mut lwe_ksk = M::R::zeros(self.pbs_info.lwe_decomposer.decomposition_count() * ring_size); lwe_ksk_keygen( - &sk_rlwe.values(), - &sk_lwe.values(), + &sk_rlwe, + &sk_lwe, &mut lwe_ksk, &d_lwe_gadget, &self.pbs_info.lwe_modop, @@ -785,11 +766,11 @@ where }) } - pub(super) fn multi_party_server_key_share( + pub(super) fn multi_party_server_key_share>( &self, cr_seed: [u8; 32], collective_pk: &M, - client_key: &ClientKey, + client_key: &K, ) -> CommonReferenceSeededMultiPartyServerKeyShare, [u8; 32]> { DefaultSecureRng::with_local_mut(|rng| { @@ -807,8 +788,8 @@ where let rlweq_nttop = &self.pbs_info.rlwe_nttop; // sanity check - assert!(sk_rlwe.values().len() == ring_size); - assert!(sk_lwe.values().len() == self.pbs_info.parameters.lwe_n().0); + assert!(sk_rlwe.len() == ring_size); + assert!(sk_lwe.len() == self.pbs_info.parameters.lwe_n().0); // auto keys let mut auto_keys = HashMap::new(); @@ -828,7 +809,7 @@ where ); galois_key_gen( &mut ksk_out, - sk_rlwe.values(), + &sk_rlwe, g_pow, &auto_gadget, rlweq_modop, @@ -853,7 +834,6 @@ where rgsw_rgsw_decomposer.1.gadget_vector(), ); let rgsw_cts = sk_lwe - .values() .iter() .map(|si| { let mut m = M::R::zeros(ring_size); @@ -893,8 +873,8 @@ where let lwe_modop = &self.pbs_info.lwe_modop; let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector(); lwe_ksk_keygen( - sk_rlwe.values(), - sk_lwe.values(), + &sk_rlwe, + &sk_lwe, &mut lwe_ksk, &d_lwe_gadget_vec, lwe_modop, @@ -916,7 +896,7 @@ where &self, cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>, total_users: usize, - key_shares: &[SeededNonInteractiveMultiPartyServerKeyShare< + key_shares: &[CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare< M, NonInteractiveMultiPartyCrs<[u8; 32]>, >], @@ -1432,21 +1412,29 @@ where ) } - pub(super) fn non_interactive_multi_party_key_share( + pub(super) fn non_interactive_multi_party_key_share< + K: NonInteractiveMultiPartyClientKey, + >( &self, // TODO(Jay): Should get a common reference seed here and derive the rest. cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>, self_index: usize, total_users: usize, - client_key: &ThrowMeAwayKey, - ) -> SeededNonInteractiveMultiPartyServerKeyShare> - { + client_key: &K, + ) -> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare< + M, + NonInteractiveMultiPartyCrs<[u8; 32]>, + > { // TODO: check whether parameters support `total_users` let nttop = self.pbs_info().nttop_rlweq(); let rlwe_modop = self.pbs_info().modop_rlweq(); let ring_size = self.pbs_info().rlwe_n(); let rlwe_q = self.parameters().rlwe_q(); + let sk_rlwe = client_key.sk_rlwe(); + let sk_u_rlwe = client_key.sk_u_rlwe(); + let sk_lwe = client_key.sk_lwe(); + let (ui_to_s_ksk, zero_encs_for_others) = DefaultSecureRng::with_local_mut(|rng| { // ui_to_s_ksk let non_interactive_decomposer = self @@ -1460,8 +1448,8 @@ where ); non_interactive_ksk_gen::( - client_key.sk_rlwe().values(), - client_key.sk_u_rlwe().values(), + &sk_rlwe, + &sk_u_rlwe, &non_interactive_gadget_vec, &mut p_rng, rng, @@ -1479,7 +1467,7 @@ where ); let zero_encs = non_interactive_ksk_zero_encryptions_for_other_party_i::( - client_key.sk_rlwe().values(), + &sk_rlwe, &non_interactive_gadget_vec, &mut p_rng, rng, @@ -1511,9 +1499,7 @@ where rgsw_by_rgsw_decomposer.b().gadget_vector() } }; - let ni_rgsw_cts: (Vec, Vec) = client_key - .sk_lwe() - .values() + let ni_rgsw_cts: (Vec, Vec) = sk_lwe .iter() .map(|s_i| { // X^{s[i]} @@ -1527,8 +1513,8 @@ where } non_interactive_rgsw_ct::( - client_key.sk_rlwe().values(), - client_key.sk_u_rlwe().values(), + &sk_rlwe, + &sk_u_rlwe, m.as_ref(), &ni_rgrg_gadget_vec, &mut rgsw_cts_prng, @@ -1544,20 +1530,16 @@ where // Auto key share let auto_keys_share = { let auto_seed = cr_seed.auto_keys_cts_seed::(); - self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, client_key.sk_rlwe()) + self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, &sk_rlwe) }; // Lwe Ksk share let lwe_ksk_share = { let lwe_ksk_seed = cr_seed.lwe_ksk_cts_seed::(); - self._common_rountine_multi_party_lwe_ksk_share_gen( - lwe_ksk_seed, - client_key.sk_rlwe(), - client_key.sk_lwe(), - ) + self._common_rountine_multi_party_lwe_ksk_share_gen(lwe_ksk_seed, &sk_rlwe, &sk_lwe) }; - SeededNonInteractiveMultiPartyServerKeyShare { + CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare { ni_rgsw_cts, ui_to_s_ksk, others_ksk_zero_encs: zero_encs_for_others, @@ -1571,7 +1553,7 @@ where fn _common_rountine_multi_party_auto_keys_share_gen( &self, auto_seed: ::Seed, - sk_rlwe: &RlweSecret, + sk_rlwe: &[i32], ) -> HashMap { let g = self.pbs_info.parameters.g(); let ring_size = self.pbs_info.parameters.rlwe_n().0; @@ -1599,7 +1581,7 @@ where ); galois_key_gen( &mut ksk_out, - sk_rlwe.values(), + sk_rlwe, g_pow, &auto_gadget, rlweq_modop, @@ -1617,8 +1599,8 @@ where fn _common_rountine_multi_party_lwe_ksk_share_gen( &self, lwe_ksk_seed: ::Seed, - sk_rlwe: &RlweSecret, - sk_lwe: &LweSecret, + sk_rlwe: &[i32], + sk_lwe: &[i32], ) -> M::R { DefaultSecureRng::with_local_mut(|rng| { let mut p_rng = DefaultSecureRng::new_seeded(lwe_ksk_seed); @@ -1628,8 +1610,8 @@ where let lwe_modop = &self.pbs_info.lwe_modop; let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector(); lwe_ksk_keygen( - sk_rlwe.values(), - sk_lwe.values(), + sk_rlwe, + sk_lwe, &mut lwe_ksk, &d_lwe_gadget_vec, lwe_modop, @@ -1640,10 +1622,10 @@ where }) } - pub(super) fn multi_party_public_key_share( + pub(super) fn multi_party_public_key_share>( &self, cr_seed: [u8; 32], - client_key: &ClientKey, + client_key: &K, ) -> CommonReferenceSeededCollectivePublicKeyShare< ::R, [u8; 32], @@ -1656,7 +1638,7 @@ where let mut main_prng = DefaultSecureRng::new_seeded(cr_seed); public_key_share( &mut share_out, - client_key.sk_rlwe().values(), + &client_key.sk_rlwe(), modop, nttop, &mut main_prng, @@ -1670,17 +1652,15 @@ where }) } - pub(super) fn multi_party_decryption_share( + pub(super) fn multi_party_decryption_share>( &self, lwe_ct: &M::R, - client_key: &ClientKey, + client_key: &K, ) -> ::MatElement { assert!(lwe_ct.as_ref().len() == self.pbs_info.parameters.rlwe_n().0 + 1); let modop = &self.pbs_info.rlwe_modop; - let mut neg_s = M::R::try_convert_from( - client_key.sk_rlwe().values(), - &self.pbs_info.parameters.rlwe_q(), - ); + let mut neg_s = + M::R::try_convert_from(&client_key.sk_rlwe(), &self.pbs_info.parameters.rlwe_q()); modop.elwise_neg_mut(neg_s.as_mut()); let mut neg_sa = M::MatElement::zero(); @@ -1798,7 +1778,11 @@ where } /// TODO(Jay): Fetch client key from thread local - pub fn sk_encrypt(&self, m: bool, client_key: &ClientKey) -> M::R { + pub fn sk_encrypt>( + &self, + m: bool, + client_key: &K, + ) -> M::R { //FIXME(Jay): Figure out a way to get Q/8 form modulus let m = if m { // Q/8 @@ -1813,7 +1797,7 @@ where encrypt_lwe( &mut lwe_out, &m, - client_key.sk_rlwe().values(), + &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop, rng, ); @@ -1821,12 +1805,12 @@ where }) } - pub fn sk_decrypt(&self, lwe_ct: &M::R, client_key: &ClientKey) -> bool { - let m = decrypt_lwe( - lwe_ct, - client_key.sk_rlwe().values(), - &self.pbs_info.rlwe_modop, - ); + pub fn sk_decrypt>( + &self, + lwe_ct: &M::R, + client_key: &K, + ) -> bool { + let m = decrypt_lwe(lwe_ct, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop); self.pbs_info.rlwe_q().decode(m) } @@ -2159,17 +2143,21 @@ where #[cfg(test)] mod tests { - use bool::parameters::{MP_BOOL_PARAMS, SP_BOOL_PARAMS}; + use rand::{thread_rng, Rng}; use rand_distr::Uniform; use crate::{ backend::ModulusPowerOf2, bool::{ - self, CommonReferenceSeededMultiPartyServerKeyShare, - NonInteractiveServerKeyEvaluationDomain, PublicKey, SeededMultiPartyServerKey, - ShoupNonInteractiveServerKeyEvaluationDomain, NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS, - SMALL_MP_BOOL_PARAMS, + keys::{ + NonInteractiveServerKeyEvaluationDomain, PublicKey, + ShoupNonInteractiveServerKeyEvaluationDomain, + }, + parameters::{ + MP_BOOL_PARAMS, NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS, SMALL_MP_BOOL_PARAMS, + SP_BOOL_PARAMS, + }, }, ntt::NttBackendU64, random::{RandomElementInModulus, DEFAULT_RNG}, @@ -2306,7 +2294,11 @@ mod tests { let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.pbs_info.rlwe_n()]; parties.iter().for_each(|k| { - izip!(ideal_rlwe_sk.iter_mut(), k.sk_rlwe().values()).for_each(|(ideal_i, s_i)| { + izip!( + ideal_rlwe_sk.iter_mut(), + InteractiveMultiPartyClientKey::sk_rlwe(k).iter() + ) + .for_each(|(ideal_i, s_i)| { *ideal_i = *ideal_i + s_i; }); }); @@ -2354,89 +2346,55 @@ mod tests { } } - fn _collecitve_public_key_gen(rlwe_q: u64, parties_rlwe_sk: &[RlweSecret]) -> Vec> { - let ring_size = parties_rlwe_sk[0].values.len(); - assert!(ring_size.is_power_of_two()); - let mut rng = DefaultSecureRng::new(); - let nttop = NttBackendU64::new(&rlwe_q, ring_size); - let modop = ModularOpsU64::new(rlwe_q); - - // Generate Pk shares - let pk_seed = [0u8; 32]; - let pk_shares = parties_rlwe_sk.iter().map(|sk| { - let mut p_rng = DefaultSecureRng::new_seeded(pk_seed); - let mut share_out = vec![0u64; ring_size]; - public_key_share( - &mut share_out, - sk.values(), - &modop, - &nttop, - &mut p_rng, - &mut rng, - ); - share_out - }); - - let mut pk_part_b = vec![0u64; ring_size]; - pk_shares.for_each(|share| modop.elwise_add_mut(&mut pk_part_b, &share)); - let mut pk_part_a = vec![0u64; ring_size]; - let mut p_rng = DefaultSecureRng::new_seeded(pk_seed); - RandomFillUniformInModulus::random_fill(&mut p_rng, &rlwe_q, pk_part_a.as_mut_slice()); - - vec![pk_part_a, pk_part_b] - } - - fn _multi_party_all_keygen( - bool_evaluator: &BoolEvaluator< + #[test] + fn interactive_multi_party_nand() { + let mut bool_evaluator = BoolEvaluator::< Vec>, NttBackendU64, ModularOpsU64>, ModularOpsU64>, ShoupServerKeyEvaluationDomain>>, - >, - no_of_parties: usize, - ) -> ( - Vec, - PublicKey>, DefaultSecureRng, ModularOpsU64>>, - Vec< - CommonReferenceSeededMultiPartyServerKeyShare< - Vec>, - BoolParameters, - [u8; 32], - >, - >, - SeededMultiPartyServerKey>, [u8; 32], BoolParameters>, - ShoupServerKeyEvaluationDomain>>, - ClientKey, - ) { + >::new(MP_BOOL_PARAMS); + + let multi_party_crs = MultiPartyCrs::random(); + + // let (parties, collective_pk, _, _, server_key_eval, ideal_client_key) = + // _multi_party_all_keygen(&bool_evaluator, 2); + + let no_of_parties = 2; let parties = (0..no_of_parties) .map(|_| bool_evaluator.client_key()) .collect_vec(); - let mut rng = DefaultSecureRng::new(); - - // Collective public key - let mut pk_cr_seed = [0u8; 32]; - rng.fill_bytes(&mut pk_cr_seed); - let public_key_share = parties + // generate public key + let pk_shares = parties .iter() - .map(|k| bool_evaluator.multi_party_public_key_share(pk_cr_seed, k)) + .map(|k| { + bool_evaluator.multi_party_public_key_share( + multi_party_crs.public_key_share_seed::(), + k, + ) + }) .collect_vec(); let collective_pk = - PublicKey::>, DefaultSecureRng, _>::from(public_key_share.as_slice()); + PublicKey::<_, DefaultSecureRng, ModularOpsU64>>::from( + pk_shares.as_slice(), + ); - // Server key - let mut pbs_cr_seed = [0u8; 32]; - rng.fill_bytes(&mut pbs_cr_seed); + // generate server key let server_key_shares = parties .iter() .map(|k| { - bool_evaluator.multi_party_server_key_share(pbs_cr_seed, &collective_pk.key(), k) + bool_evaluator.multi_party_server_key_share( + multi_party_crs.server_key_share_seed::(), + collective_pk.key(), + k, + ) }) .collect_vec(); let seeded_server_key = bool_evaluator.aggregate_multi_party_server_key_shares(&server_key_shares); - let runtime_server_key = + let server_key_eval = ShoupServerKeyEvaluationDomain::from(ServerKeyEvaluationDomain::< _, _, @@ -2444,54 +2402,6 @@ mod tests { NttBackendU64, >::from(&seeded_server_key)); - // construct ideal rlwe sk for meauring noise - let ideal_client_key = { - let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.pbs_info.rlwe_n()]; - parties.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; bool_evaluator.pbs_info.lwe_n()]; - parties.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, - }, - ) - }; - - ( - parties, - collective_pk, - server_key_shares, - seeded_server_key, - runtime_server_key, - ideal_client_key, - ) - } - - #[test] - fn interactive_multi_party_nand() { - let mut bool_evaluator = BoolEvaluator::< - Vec>, - NttBackendU64, - ModularOpsU64>, - ModularOpsU64>, - ShoupServerKeyEvaluationDomain>>, - >::new(MP_BOOL_PARAMS); - - let (parties, collective_pk, _, _, server_key_eval, ideal_client_key) = - _multi_party_all_keygen(&bool_evaluator, 2); - let mut m0 = true; let mut m1 = false; @@ -2558,29 +2468,26 @@ mod tests { .map(|_| bool_evaluator.client_key()) .collect_vec(); - let ideal_client_key = { - let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.pbs_info.rlwe_n()]; - parties.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; bool_evaluator.pbs_info.lwe_n()]; - parties.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; - }); + 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; }); - - ClientKey::new( - RlweSecret { - values: ideal_rlwe_sk, - }, - LweSecret { - values: ideal_lwe_sk, - }, + }); + 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; + }); + }); // check noise in freshly encrypted RLWE ciphertext (ie var_fresh) if true { @@ -2615,7 +2522,7 @@ mod tests { let mut m_back = vec![0u64; rlwe_n]; decrypt_rlwe( &rlwe_ct, - ideal_client_key.sk_rlwe().values(), + &ideal_rlwe_sk, &mut m_back, rlwe_nttop, rlwe_modop, @@ -2659,91 +2566,95 @@ mod tests { // Check noise in RGSW ciphertexts of ideal LWE secret elements if false { let mut check = Stats { samples: vec![] }; - izip!( - ideal_client_key.sk_lwe().values.iter(), - seeded_server_key.rgsw_cts().iter() - ) - .for_each(|(s_i, rgsw_ct_i)| { - // X^{s[i]} - let mut m_si = vec![0u64; rlwe_n]; - let s_i = *s_i * (bool_evaluator.pbs_info.embedding_factor as i32); - if s_i < 0 { - m_si[rlwe_n - (s_i.abs() as usize)] = rlwe_q.neg_one(); - } else { - m_si[s_i as usize] = 1; - } + izip!(ideal_lwe_sk.iter(), seeded_server_key.rgsw_cts().iter()).for_each( + |(s_i, rgsw_ct_i)| { + // X^{s[i]} + let mut m_si = vec![0u64; rlwe_n]; + let s_i = *s_i * (bool_evaluator.pbs_info.embedding_factor as i32); + if s_i < 0 { + m_si[rlwe_n - (s_i.abs() as usize)] = rlwe_q.neg_one(); + } else { + m_si[s_i as usize] = 1; + } - // RLWE'(-sm) - let mut neg_s_eval = - Vec::::try_convert_from(ideal_client_key.sk_rlwe().values(), rlwe_q); - rlwe_modop.elwise_neg_mut(&mut neg_s_eval); - rlwe_nttop.forward(&mut neg_s_eval); - for j in 0..rlwe_rgsw_decomposer.a().decomposition_count() { - // RLWE(B^{j} * -s[X]*X^{s_lwe[i]}) - - // -s[X]*X^{s_lwe[i]}*B_j - let mut m_ideal = m_si.clone(); - rlwe_nttop.forward(m_ideal.as_mut_slice()); - rlwe_modop.elwise_mul_mut(m_ideal.as_mut_slice(), neg_s_eval.as_slice()); - rlwe_nttop.backward(m_ideal.as_mut_slice()); - rlwe_modop - .elwise_scalar_mul_mut(m_ideal.as_mut_slice(), &rlwe_rgsw_gadget_a[j]); - - // RLWE(-s*X^{s_lwe[i]}*B_j) - let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; - rlwe_ct[0].copy_from_slice(&rgsw_ct_i[j]); - rlwe_ct[1].copy_from_slice( - &rgsw_ct_i[j + rlwe_rgsw_decomposer.a().decomposition_count()], - ); + // RLWE'(-sm) + let mut neg_s_eval = + Vec::::try_convert_from(ideal_rlwe_sk.as_slice(), rlwe_q); + rlwe_modop.elwise_neg_mut(&mut neg_s_eval); + rlwe_nttop.forward(&mut neg_s_eval); + for j in 0..rlwe_rgsw_decomposer.a().decomposition_count() { + // RLWE(B^{j} * -s[X]*X^{s_lwe[i]}) + + // -s[X]*X^{s_lwe[i]}*B_j + let mut m_ideal = m_si.clone(); + rlwe_nttop.forward(m_ideal.as_mut_slice()); + rlwe_modop + .elwise_mul_mut(m_ideal.as_mut_slice(), neg_s_eval.as_slice()); + rlwe_nttop.backward(m_ideal.as_mut_slice()); + rlwe_modop.elwise_scalar_mul_mut( + m_ideal.as_mut_slice(), + &rlwe_rgsw_gadget_a[j], + ); - let mut m_back = vec![0u64; rlwe_n]; - decrypt_rlwe( - &rlwe_ct, - ideal_client_key.sk_rlwe().values(), - &mut m_back, - rlwe_nttop, - rlwe_modop, - ); + // RLWE(-s*X^{s_lwe[i]}*B_j) + let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; + rlwe_ct[0].copy_from_slice(&rgsw_ct_i[j]); + rlwe_ct[1].copy_from_slice( + &rgsw_ct_i[j + rlwe_rgsw_decomposer.a().decomposition_count()], + ); - // diff - rlwe_modop.elwise_sub_mut(&mut m_back, &m_ideal); - check.add_more(&Vec::::try_convert_from(&m_back, rlwe_q)); - } + let mut m_back = vec![0u64; rlwe_n]; + decrypt_rlwe( + &rlwe_ct, + &ideal_rlwe_sk, + &mut m_back, + rlwe_nttop, + rlwe_modop, + ); - // RLWE'(m) - for j in 0..rlwe_rgsw_decomposer.b().decomposition_count() { - // RLWE(B^{j} * X^{s_lwe[i]}) + // diff + rlwe_modop.elwise_sub_mut(&mut m_back, &m_ideal); + check.add_more(&Vec::::try_convert_from(&m_back, rlwe_q)); + } - // X^{s_lwe[i]}*B_j - let mut m_ideal = m_si.clone(); - rlwe_modop - .elwise_scalar_mul_mut(m_ideal.as_mut_slice(), &rlwe_rgsw_gadget_b[j]); + // RLWE'(m) + for j in 0..rlwe_rgsw_decomposer.b().decomposition_count() { + // RLWE(B^{j} * X^{s_lwe[i]}) - // RLWE(X^{s_lwe[i]}*B_j) - let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; - rlwe_ct[0].copy_from_slice( - &rgsw_ct_i[j + (2 * rlwe_rgsw_decomposer.a().decomposition_count())], - ); - rlwe_ct[1].copy_from_slice( - &rgsw_ct_i[j - + (2 * rlwe_rgsw_decomposer.a().decomposition_count() - + rlwe_rgsw_decomposer.b().decomposition_count())], - ); + // X^{s_lwe[i]}*B_j + let mut m_ideal = m_si.clone(); + rlwe_modop.elwise_scalar_mul_mut( + m_ideal.as_mut_slice(), + &rlwe_rgsw_gadget_b[j], + ); - let mut m_back = vec![0u64; rlwe_n]; - decrypt_rlwe( - &rlwe_ct, - ideal_client_key.sk_rlwe().values(), - &mut m_back, - rlwe_nttop, - rlwe_modop, - ); + // RLWE(X^{s_lwe[i]}*B_j) + let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; + rlwe_ct[0].copy_from_slice( + &rgsw_ct_i + [j + (2 * rlwe_rgsw_decomposer.a().decomposition_count())], + ); + rlwe_ct[1].copy_from_slice( + &rgsw_ct_i[j + + (2 * rlwe_rgsw_decomposer.a().decomposition_count() + + rlwe_rgsw_decomposer.b().decomposition_count())], + ); - // diff - rlwe_modop.elwise_sub_mut(&mut m_back, &m_ideal); - check.add_more(&Vec::::try_convert_from(&m_back, rlwe_q)); - } - }); + let mut m_back = vec![0u64; rlwe_n]; + decrypt_rlwe( + &rlwe_ct, + &ideal_rlwe_sk, + &mut m_back, + rlwe_nttop, + rlwe_modop, + ); + + // diff + rlwe_modop.elwise_sub_mut(&mut m_back, &m_ideal); + check.add_more(&Vec::::try_convert_from(&m_back, rlwe_q)); + } + }, + ); println!( "RGSW Std: {} {} ;; max={}", check.mean(), @@ -2765,105 +2676,100 @@ mod tests { if false { let mut check = Stats { samples: vec![] }; - ideal_client_key - .sk_lwe() - .values() - .iter() - .enumerate() - .for_each(|(index, s_i)| { - let rgsw_ct_i = runtime_server_key.rgsw_ct_lwe_si(index).as_ref(); + 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 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, - ); + 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; - } + // 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_client_key.sk_rlwe().values(), - &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_client_key.sk_rlwe().values(), - &mut m_plus_e_times_m1_more_e, - rlwe_nttop, - rlwe_modop, - ); + // (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(), - ); + // 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, - )); - }); + // 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(), @@ -2875,8 +2781,7 @@ mod tests { if false { let mut check = Stats { samples: vec![] }; - let mut neg_s_poly = - Vec::::try_convert_from(ideal_client_key.sk_rlwe().values(), rlwe_q); + 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(); @@ -2918,13 +2823,7 @@ mod tests { rlwe_ct[1].copy_from_slice( &auto_key_i[auto_decomposer.decomposition_count() + i], ); - decrypt_rlwe( - &rlwe_ct, - ideal_client_key.sk_rlwe().values(), - &mut m_out, - rlwe_nttop, - rlwe_modop, - ); + 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()); @@ -2966,7 +2865,7 @@ mod tests { let mut m_plus_e = vec![0u64; rlwe_n]; decrypt_rlwe( &rlwe_ct, - ideal_client_key.sk_rlwe().values(), + &ideal_rlwe_sk, &mut m_plus_e, rlwe_nttop, rlwe_modop, @@ -3000,13 +2899,7 @@ mod tests { }); let mut m_out = vec![0u64; rlwe_n]; - decrypt_rlwe( - &rlwe_ct, - ideal_client_key.sk_rlwe().values(), - &mut m_out, - rlwe_nttop, - rlwe_modop, - ); + 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()); @@ -3030,13 +2923,7 @@ mod tests { // 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_client_key.sk_rlwe().values(), - lwe_modop, - &mut rng, - ); + 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]; @@ -3050,11 +2937,10 @@ mod tests { // We only care about noise added by LWE key switch // m+e - let m_plus_e = - decrypt_lwe(&lwe_in_ct, ideal_client_key.sk_rlwe().values(), lwe_modop); + 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_client_key.sk_lwe().values(), lwe_modop); + decrypt_lwe(&lwe_out, &ideal_lwe_sk, lwe_modop); let diff = lwe_modop.sub(&m_plus_e_plus_lwe_ksk_noise, &m_plus_e); @@ -3274,9 +3160,7 @@ mod tests { let parties = 2; - let cks = (0..parties) - .map(|_| evaluator.non_interactive_client_key()) - .collect_vec(); + let cks = (0..parties).map(|_| evaluator.client_key()).collect_vec(); let key_shares = (0..parties) .map(|i| evaluator.non_interactive_multi_party_key_share(&mp_seed, i, parties, &cks[i])) @@ -3295,14 +3179,22 @@ mod tests { let mut ideal_rlwe = vec![0; ring_size]; cks.iter().for_each(|k| { - izip!(ideal_rlwe.iter_mut(), k.sk_rlwe().values().iter()).for_each(|(a, b)| { + izip!( + ideal_rlwe.iter_mut(), + NonInteractiveMultiPartyClientKey::sk_rlwe(k).iter() + ) + .for_each(|(a, b)| { *a = *a + b; }); }); let mut ideal_lwe = vec![0; evaluator.parameters().lwe_n().0]; cks.iter().for_each(|k| { - izip!(ideal_lwe.iter_mut(), k.sk_lwe().values().iter()).for_each(|(a, b)| { + izip!( + ideal_lwe.iter_mut(), + NonInteractiveMultiPartyClientKey::sk_lwe(k).iter() + ) + .for_each(|(a, b)| { *a = *a + b; }); }); diff --git a/src/bool/keys.rs b/src/bool/keys.rs index 289e0a9..9fdef09 100644 --- a/src/bool/keys.rs +++ b/src/bool/keys.rs @@ -10,112 +10,130 @@ use crate::{ Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut, }; -use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus}; +use super::{ + evaluator::BoolEvaluator, + parameters::{BoolParameters, CiphertextModulus}, +}; -trait SinglePartyClientKey { +pub(crate) trait SinglePartyClientKey { type Element; - fn sk_rlwe(&self) -> &[Self::Element]; - fn sk_lwe(&self) -> &[Self::Element]; + fn sk_rlwe(&self) -> Vec; + fn sk_lwe(&self) -> Vec; } -trait InteractiveMultiPartyClientKey { +pub(crate) trait InteractiveMultiPartyClientKey { type Element; - fn sk_rlwe(&self) -> &[Self::Element]; - fn sk_lwe(&self) -> &[Self::Element]; + fn sk_rlwe(&self) -> Vec; + fn sk_lwe(&self) -> Vec; } -trait NonInteractiveMultiPartyClientKey { +pub(crate) trait NonInteractiveMultiPartyClientKey { type Element; - fn sk_rlwe(&self) -> &[Self::Element]; - fn sk_u_rlwe(&self) -> &[Self::Element]; - fn sk_lwe(&self) -> &[Self::Element]; + fn sk_rlwe(&self) -> Vec; + fn sk_u_rlwe(&self) -> Vec; + fn sk_lwe(&self) -> Vec; } -/// Client key with RLWE and LWE secrets +/// Client key +/// +/// Key is used for all parameter varians - Single party, interactive +/// multi-party, and non-interactive multi-party. The only stored the main seed +/// and seeds of the Rlwe/Lwe secrets are derived at puncturing the seed desired +/// number of times. +/// +/// ### Punctures required: +/// +/// Puncture 1 -> Seed of RLWE secret used as main RLWE secret for +/// single-party, interactive/non-interactive multi-party +/// +/// Puncture 2 -> Seed of LWE secret used main LWE secret for single-party, +/// interactive/non-interactive multi-party +/// +/// Puncture 3 -> Seed of RLWE secret used as `u` in +/// interactive/non-interactive multi-party. #[derive(Clone)] -pub struct ClientKey { - sk_rlwe: RlweSecret, - sk_lwe: LweSecret, -} - -/// Client key with RLWE and LWE secrets -#[derive(Clone)] -pub struct ThrowMeAwayKey { - sk_rlwe: RlweSecret, - sk_u_rlwe: RlweSecret, - sk_lwe: LweSecret, +pub struct ClientKey { + seed: S, + parameters: BoolParameters, } mod impl_ck { - use super::*; - - // Client key - impl ClientKey { - pub(in super::super) fn new(sk_rlwe: RlweSecret, sk_lwe: LweSecret) -> Self { - Self { sk_rlwe, sk_lwe } - } + use crate::{ + random::DefaultSecureRng, + utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng}, + }; - pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret { - &self.sk_rlwe - } + use super::*; - pub(in super::super) fn sk_lwe(&self) -> &LweSecret { - &self.sk_lwe + impl ClientKey<[u8; 32], E> { + pub(in super::super) fn new(parameters: BoolParameters) -> ClientKey<[u8; 32], E> { + let mut rng = DefaultSecureRng::new(); + let mut seed = [0u8; 32]; + rng.fill_bytes(&mut seed); + Self { seed, parameters } } } - // Client key - impl ThrowMeAwayKey { - pub(in super::super) fn new( - sk_rlwe: RlweSecret, - sk_u_rlwe: RlweSecret, - sk_lwe: LweSecret, - ) -> Self { - Self { - sk_rlwe, - sk_u_rlwe, - sk_lwe, - } - } - - pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret { - &self.sk_rlwe - } - - pub(in super::super) fn sk_u_rlwe(&self) -> &RlweSecret { - &self.sk_u_rlwe + impl SinglePartyClientKey for ClientKey<[u8; 32], E> { + type Element = i32; + fn sk_lwe(&self) -> Vec { + let mut p_rng = DefaultSecureRng::new_seeded(self.seed); + let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2); + + let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed); + let mut out = vec![0i32; self.parameters.lwe_n().0]; + fill_random_ternary_secret_with_hamming_weight( + &mut out, + self.parameters.lwe_n().0 >> 1, + &mut lwe_prng, + ); + out } - - pub(in super::super) fn sk_lwe(&self) -> &LweSecret { - &self.sk_lwe + fn sk_rlwe(&self) -> Vec { + let mut p_rng = DefaultSecureRng::new_seeded(self.seed); + let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1); + + let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed); + let mut out = vec![0i32; self.parameters.rlwe_n().0]; + fill_random_ternary_secret_with_hamming_weight( + &mut out, + self.parameters.rlwe_n().0 >> 1, + &mut rlwe_prng, + ); + out } } - impl Encryptor> for ClientKey { - fn encrypt(&self, m: &bool) -> Vec { - BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self)) + impl InteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> { + type Element = i32; + fn sk_lwe(&self) -> Vec { + ::sk_lwe(&self) } - } - - impl Decryptor> for ClientKey { - fn decrypt(&self, c: &Vec) -> bool { - BoolEvaluator::with_local(|e| e.sk_decrypt(c, self)) + fn sk_rlwe(&self) -> Vec { + ::sk_rlwe(&self) } } - impl MultiPartyDecryptor> for ClientKey { - type DecryptionShare = u64; - - fn gen_decryption_share(&self, c: &Vec) -> Self::DecryptionShare { - BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, &self)) + impl NonInteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> { + type Element = i32; + fn sk_lwe(&self) -> Vec { + ::sk_lwe(&self) } - - fn aggregate_decryption_shares( - &self, - c: &Vec, - shares: &[Self::DecryptionShare], - ) -> bool { - BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c)) + fn sk_rlwe(&self) -> Vec { + ::sk_rlwe(&self) + } + fn sk_u_rlwe(&self) -> Vec { + let mut p_rng = DefaultSecureRng::new_seeded(self.seed); + let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3); + + let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed); + let mut out = vec![0i32; self.parameters.rlwe_n().0]; + fill_random_ternary_secret_with_hamming_weight( + &mut out, + self.parameters.rlwe_n().0 >> 1, + &mut rlwe_prng, + ); + out } } } @@ -135,18 +153,6 @@ pub(super) mod impl_pk { } } - impl Encryptor> for PublicKey>, Rng, ModOp> { - fn encrypt(&self, m: &bool) -> Vec { - BoolEvaluator::with_local(|e| e.pk_encrypt(&self.key, *m)) - } - } - - impl Encryptor<[bool], Vec>> for PublicKey>, Rng, ModOp> { - fn encrypt(&self, m: &[bool]) -> Vec> { - BoolEvaluator::with_local(|e| e.pk_encrypt_batched(&self.key, m)) - } - } - impl< M: MatrixMut + MatrixEntity, Rng: NewWithSeed @@ -456,8 +462,6 @@ pub(super) mod impl_server_key_eval_domain { use itertools::{izip, Itertools}; use crate::{ - backend::Modulus, - bool::{NonInteractiveMultiPartyCrs, SeededNonInteractiveMultiPartyServerKey}, ntt::{Ntt, NttInit}, pbs::PbsKey, }; @@ -736,7 +740,7 @@ pub(crate) struct NonInteractiveServerKeyEvaluationDomain { pub(super) mod impl_non_interactive_server_key_eval_domain { use itertools::{izip, Itertools}; - use crate::{bool::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit}; + use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit}; use super::*; diff --git a/src/bool/mod.rs b/src/bool/mod.rs index 4a06c2b..9d4628d 100644 --- a/src/bool/mod.rs +++ b/src/bool/mod.rs @@ -1,16 +1,12 @@ pub(crate) mod evaluator; -pub(crate) mod keys; +mod keys; mod mp_api; mod ni_mp_api; mod noise; pub(crate) mod parameters; -pub use mp_api::*; +pub(crate) use keys::PublicKey; pub type FheBool = Vec; -use std::{cell::RefCell, sync::OnceLock}; - -use evaluator::*; -use keys::*; -use parameters::*; +pub use mp_api::*; diff --git a/src/bool/mp_api.rs b/src/bool/mp_api.rs index cb3ba33..581a2af 100644 --- a/src/bool/mp_api.rs +++ b/src/bool/mp_api.rs @@ -1,3 +1,5 @@ +use std::{cell::RefCell, sync::OnceLock}; + use crate::{ backend::{ModularOpsU64, ModulusPowerOf2}, ntt::NttBackendU64, @@ -5,7 +7,7 @@ use crate::{ utils::{Global, WithLocal}, }; -use super::*; +use super::{evaluator::*, keys::*, parameters::*}; thread_local! { static BOOL_EVALUATOR: RefCell>, NttBackendU64, ModularOpsU64>, ModulusPowerOf2>, ShoupServerKeyEvaluationDomain>>>>> = RefCell::new(None); @@ -15,6 +17,8 @@ static BOOL_SERVER_KEY: OnceLock>>> static MULTI_PARTY_CRS: OnceLock> = OnceLock::new(); +pub type ClientKey = super::keys::ClientKey<[u8; 32], u64>; + pub enum ParameterSelector { MultiPartyLessThanOrEqualTo16, } @@ -62,7 +66,7 @@ pub fn gen_mp_keys_phase1( ) -> CommonReferenceSeededCollectivePublicKeyShare, [u8; 32], BoolParameters> { let seed = MultiPartyCrs::global().public_key_share_seed::(); BoolEvaluator::with_local(|e| { - let pk_share = e.multi_party_public_key_share(seed, &ck); + let pk_share = e.multi_party_public_key_share(seed, ck); pk_share }) } @@ -167,3 +171,91 @@ impl Global for RuntimeServerKey { BOOL_SERVER_KEY.get().expect("Server key not set!") } } + +mod impl_enc_dec { + use crate::{ + pbs::{sample_extract, PbsInfo}, + rgsw::public_key_encrypt_rlwe, + Decryptor, Encryptor, Matrix, MatrixEntity, MultiPartyDecryptor, RowEntity, + }; + use num_traits::Zero; + + use super::*; + + type Mat = Vec>; + + impl Encryptor> for super::super::keys::ClientKey<[u8; 32], E> { + fn encrypt(&self, m: &bool) -> Vec { + BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self)) + } + } + + impl Decryptor> for super::super::keys::ClientKey<[u8; 32], E> { + fn decrypt(&self, c: &Vec) -> bool { + BoolEvaluator::with_local(|e| e.sk_decrypt(c, self)) + } + } + + impl MultiPartyDecryptor::R> + for super::super::keys::ClientKey<[u8; 32], E> + { + type DecryptionShare = ::MatElement; + + fn gen_decryption_share(&self, c: &::R) -> Self::DecryptionShare { + BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, self)) + } + + fn aggregate_decryption_shares( + &self, + c: &::R, + shares: &[Self::DecryptionShare], + ) -> bool { + BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c)) + } + } + + impl Encryptor<[bool], Mat> for PublicKey { + fn encrypt(&self, m: &[bool]) -> Mat { + BoolEvaluator::with_local(|e| { + DefaultSecureRng::with_local_mut(|rng| { + let parameters = e.parameters(); + let mut rlwe_out = ::zeros(2, parameters.rlwe_n().0); + assert!(m.len() <= parameters.rlwe_n().0); + + let mut message = + vec![::MatElement::zero(); parameters.rlwe_n().0]; + m.iter().enumerate().for_each(|(i, v)| { + if *v { + message[i] = parameters.rlwe_q().true_el() + } else { + message[i] = parameters.rlwe_q().false_el() + } + }); + + // e.pk_encrypt_batched(self.key(), m) + public_key_encrypt_rlwe::<_, _, _, _, i32, _>( + &mut rlwe_out, + self.key(), + &message, + e.pbs_info().modop_rlweq(), + e.pbs_info().nttop_rlweq(), + rng, + ); + rlwe_out + }) + }) + } + } + + impl Encryptor::R> for PublicKey { + fn encrypt(&self, m: &bool) -> ::R { + let m = vec![*m]; + let rlwe = self.encrypt(m.as_slice()); + BoolEvaluator::with_local(|e| { + let mut lwe = ::R::zeros(e.parameters().rlwe_n().0 + 1); + sample_extract(&mut lwe, &rlwe, e.pbs_info().modop_rlweq(), 0); + lwe + }) + } + } +} diff --git a/src/bool/ni_mp_api.rs b/src/bool/ni_mp_api.rs index e69de29..f6e5d74 100644 --- a/src/bool/ni_mp_api.rs +++ b/src/bool/ni_mp_api.rs @@ -0,0 +1,66 @@ +mod impl_enc_dec { + use crate::{ + bool::{ + evaluator::{BoolEncoding, BoolEvaluator}, + keys::NonInteractiveMultiPartyClientKey, + parameters::CiphertextModulus, + }, + pbs::PbsInfo, + random::{DefaultSecureRng, NewWithSeed}, + rgsw::secret_key_encrypt_rlwe, + utils::{TryConvertFrom1, WithLocal}, + Encryptor, Matrix, RowEntity, + }; + use num_traits::Zero; + + trait SeededCiphertext { + fn new_with_seed(data: M, seed: S) -> Self; + } + + type Mat = Vec>; + + impl Encryptor<[bool], C> for K + where + K: NonInteractiveMultiPartyClientKey, + C: SeededCiphertext<::R, ::Seed>, + ::R: + TryConvertFrom1<[K::Element], CiphertextModulus<::MatElement>>, + { + fn encrypt(&self, m: &[bool]) -> C { + BoolEvaluator::with_local(|e| { + let parameters = e.parameters(); + assert!(m.len() <= parameters.rlwe_n().0); + + let mut message = vec![::MatElement::zero(); parameters.rlwe_n().0]; + m.iter().enumerate().for_each(|(i, v)| { + if *v { + message[i] = parameters.rlwe_q().true_el() + } else { + message[i] = parameters.rlwe_q().false_el() + } + }); + + DefaultSecureRng::with_local_mut(|rng| { + let mut seed = ::Seed::default(); + rng.fill_bytes(&mut seed); + let mut prng = DefaultSecureRng::new_seeded(seed); + + let mut rlwe_out = + <::R as RowEntity>::zeros(parameters.rlwe_n().0); + + secret_key_encrypt_rlwe( + &message, + &mut rlwe_out, + &self.sk_u_rlwe(), + e.pbs_info().modop_rlweq(), + e.pbs_info().nttop_rlweq(), + &mut prng, + rng, + ); + + C::new_with_seed(rlwe_out, seed) + }) + }) + } + } +} diff --git a/src/bool/noise.rs b/src/bool/noise.rs index 8979c8b..1354a42 100644 --- a/src/bool/noise.rs +++ b/src/bool/noise.rs @@ -2,19 +2,17 @@ mod test { use itertools::{izip, Itertools}; use crate::{ - backend::{ArithmeticOps, ModularOpsU64, Modulus, ModulusPowerOf2}, + backend::{ModularOpsU64, ModulusPowerOf2}, bool::{ - BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus, ClientKey, PublicKey, - ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, MP_BOOL_PARAMS, - SMALL_MP_BOOL_PARAMS, + evaluator::{BoolEncoding, BoolEvaluator, BooleanGates}, + keys::{ + InteractiveMultiPartyClientKey, PublicKey, ServerKeyEvaluationDomain, + ShoupServerKeyEvaluationDomain, + }, + parameters::{CiphertextModulus, SMALL_MP_BOOL_PARAMS}, }, - lwe::{decrypt_lwe, LweSecret}, ntt::NttBackendU64, - pbs::PbsInfo, random::DefaultSecureRng, - rgsw::RlweSecret, - utils::Stats, - Ntt, Secret, }; #[test] @@ -42,29 +40,26 @@ mod test { .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; - }); + let mut ideal_rlwe_sk = vec![0i32; evaluator.parameters().rlwe_n().0]; + cks.iter().for_each(|k| { + izip!( + ideal_rlwe_sk.iter_mut(), + InteractiveMultiPartyClientKey::sk_rlwe(k) + ) + .for_each(|(ideal_i, s_i)| { + *ideal_i = *ideal_i + s_i; }); - - ClientKey::new( - RlweSecret { - values: ideal_rlwe_sk, - }, - LweSecret { - values: ideal_lwe_sk, - }, + }); + let mut ideal_lwe_sk = vec![0i32; evaluator.parameters().lwe_n().0]; + cks.iter().for_each(|k| { + izip!( + ideal_lwe_sk.iter_mut(), + InteractiveMultiPartyClientKey::sk_lwe(k) ) - }; + .for_each(|(ideal_i, s_i)| { + *ideal_i = *ideal_i + s_i; + }); + }); // round 1 let pk_shares = cks diff --git a/src/noise.rs b/src/noise.rs index e8a8cbb..676a34c 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -1,292 +1,297 @@ -#[cfg(test)] -mod tests { - use itertools::{izip, Itertools}; - use num_traits::zero; - use rand::{thread_rng, Rng}; - - use crate::{ - bool::keys::ClientKey, - ntt, - random::{ - DefaultSecureRng, RandomFill, RandomFillGaussianInModulus, RandomFillUniformInModulus, - }, - utils::{ - fill_random_ternary_secret_with_hamming_weight, generate_prime, Stats, TryConvertFrom1, - }, - ArithmeticOps, Decomposer, DefaultDecomposer, ModInit, ModularOpsU64, Ntt, NttBackendU64, - NttInit, VectorOps, - }; - - #[test] - fn non_interactive_multi_party() { - let logq = 56; - let ring_size = 1usize << 11; - let q = generate_prime(logq, 2 * ring_size as u64, 1 << logq).unwrap(); - let logb = 1; - let d = 56; - let decomposer = DefaultDecomposer::new(q, logb, d); - let gadget_vec = decomposer.gadget_vector(); - let mut rng = DefaultSecureRng::new(); - - let modop = ModularOpsU64::new(q); - let nttop = NttBackendU64::new(&q, ring_size); - - let no_of_parties = 16; - let client_secrets = (0..no_of_parties) - .into_iter() - .map(|_| { - let mut sk = vec![0i64; ring_size]; - fill_random_ternary_secret_with_hamming_weight(&mut sk, ring_size >> 1, &mut rng); - sk - }) - .collect_vec(); - - let mut s_ideal = vec![0i64; ring_size]; - client_secrets.iter().for_each(|s| { - izip!(s_ideal.iter_mut(), s.iter()).for_each(|(add_to, v)| { - *add_to = *add_to + *v; - }); - }); - - let sk_poly_ideal = Vec::::try_convert_from(s_ideal.as_slice(), &q); - let mut sk_poly_ideal_eval = sk_poly_ideal.clone(); - nttop.forward(&mut sk_poly_ideal_eval); - - let mut ksk_seed = [0u8; 32]; - rng.fill_bytes(&mut ksk_seed); - - // zero encryptions for each party for ksk(u) - let client_zero_encs = { - client_secrets - .iter() - .map(|sk| { - let sk_poly = Vec::::try_convert_from(sk.as_slice(), &q); - let mut sk_poly_eval = sk_poly.clone(); - nttop.forward(sk_poly_eval.as_mut_slice()); - - let mut zero_encs = - vec![vec![0u64; ring_size]; decomposer.decomposition_count()]; - let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed); - zero_encs.iter_mut().for_each(|out| { - RandomFillUniformInModulus::random_fill( - &mut ksk_prng, - &q, - out.as_mut_slice(), - ); - nttop.forward(out.as_mut_slice()); - modop.elwise_mul_mut(out.as_mut_slice(), &sk_poly_eval); - nttop.backward(out.as_mut_slice()); - - let mut error = vec![0u64; ring_size]; - RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); - - modop.elwise_add_mut(out.as_mut_slice(), &error); - }); - zero_encs - }) - .collect_vec() - }; - - // main values - let main_a = { - let mut a = vec![0u64; ring_size]; - RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut a); - a - }; - let main_m = { - let mut main_m = vec![0u64; ring_size]; - RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut main_m); - main_m - }; - - let mut main_u = vec![0i64; ring_size]; - fill_random_ternary_secret_with_hamming_weight(&mut main_u, ring_size >> 1, &mut rng); - let u_main_poly = Vec::::try_convert_from(main_u.as_slice(), &q); - let mut u_main_poly_eval = u_main_poly.clone(); - nttop.forward(u_main_poly_eval.as_mut_slice()); - - // party 0 - let (mut party0_ksk_u, mut rlwe_main_m_parta) = { - // party 0's secret - let sk = client_secrets[0].clone(); - let sk_poly = Vec::::try_convert_from(sk.as_slice(), &q); - let mut sk_poly_eval = sk_poly.clone(); - nttop.forward(sk_poly_eval.as_mut_slice()); - - // `main_a*u + main_m` with ephemeral key u - let mut rlwe_main_m = main_a.clone(); - nttop.forward(&mut rlwe_main_m); - modop.elwise_mul_mut(&mut rlwe_main_m, &u_main_poly_eval); - nttop.backward(&mut rlwe_main_m); - let mut error = vec![0u64; ring_size]; - RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); - modop.elwise_add_mut(&mut rlwe_main_m, &error); - modop.elwise_add_mut(&mut rlwe_main_m, &main_m); - - // Generate KSK(u) - let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed); - let mut ksk_u = vec![vec![0u64; ring_size]; 2 * decomposer.decomposition_count()]; - let (ksk_u_a, ksk_u_b) = ksk_u.split_at_mut(decomposer.decomposition_count()); - izip!(ksk_u_b.iter_mut(), ksk_u_a.iter_mut(), gadget_vec.iter()).for_each( - |(row_b, row_a, beta_i)| { - // sample a - RandomFillUniformInModulus::random_fill(&mut ksk_prng, &q, row_a.as_mut()); - - // s_i * a - let mut s_i_a = row_a.clone(); - nttop.forward(&mut s_i_a); - modop.elwise_mul_mut(&mut s_i_a, &sk_poly_eval); - nttop.backward(&mut s_i_a); - - // \beta * u - let mut beta_u = u_main_poly.clone(); - modop.elwise_scalar_mul_mut(beta_u.as_mut_slice(), beta_i); - - // e - RandomFillGaussianInModulus::random_fill(&mut rng, &q, row_b.as_mut_slice()); - // e + \beta * u - modop.elwise_add_mut(row_b.as_mut_slice(), &beta_u); - - // b = e + \beta * u + a * s_i - modop.elwise_add_mut(row_b.as_mut_slice(), &s_i_a); - }, - ); - - // send ksk u from s_0 to s_{ideal} - ksk_u_b.iter_mut().enumerate().for_each(|(index, out_b)| { - // note: skip zero encryption of party 0 - client_zero_encs.iter().skip(1).for_each(|encs| { - modop.elwise_add_mut(out_b, &encs[index]); - }); - }); - - // // put ksk in fourier domain - // ksk_u - // .iter_mut() - // .for_each(|r| nttop.forward(r.as_mut_slice())); - (ksk_u, rlwe_main_m) - }; - - // Check ksk_u is correct - // { - // let (ksk_a, ksk_b) = - // party0_ksk_u.split_at_mut(decomposer.decomposition_count()); - // izip!( - // ksk_a.iter(), - // ksk_b.iter(), - // decomposer.gadget_vector().iter() - // ) - // .for_each(|(row_a, row_b, beta_i)| { - // // a * s - // let mut sa = row_a.clone(); - // nttop.forward(&mut sa); - // modop.elwise_mul_mut(&mut sa, &sk_poly_ideal_eval); - // nttop.backward(&mut sa); - - // // b - a*s - // let mut out = sa; - // modop.elwise_neg_mut(&mut out); - // modop.elwise_add_mut(&mut out, row_b); - - // // beta * u - // let mut expected = u_main_poly.clone(); - // modop.elwise_scalar_mul_mut(&mut expected, beta_i); - // assert_eq!(expected, out); - // }); - // } - - // RLWE(0) = main_a * s + e = \sum main_a*s_i + e_i - let rlwe_to_switch = { - let mut sum = vec![0u64; ring_size]; - client_secrets.iter().for_each(|sk| { - let sk_poly = Vec::::try_convert_from(sk.as_slice(), &q); - let mut sk_poly_eval = sk_poly.clone(); - nttop.forward(sk_poly_eval.as_mut_slice()); - - // a * s - let mut rlwe = main_a.clone(); - nttop.forward(&mut rlwe); - modop.elwise_mul_mut(rlwe.as_mut_slice(), &sk_poly_eval); - nttop.backward(&mut rlwe); - // a * s + e - let mut error = vec![0u64; ring_size]; - RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); - modop.elwise_add_mut(&mut rlwe, &error); - - modop.elwise_add_mut(&mut sum, &rlwe); - }); - sum - }; - // { - // let mut tmp = main_a.clone(); - // nttop.forward(&mut tmp); - // modop.elwise_mul_mut(&mut tmp, &sk_poly_ideal_eval); - // nttop.backward(&mut tmp); - // assert_eq!(&rlwe_to_switch, &tmp); - // } - - // Key switch \sum decomp * KSK(i) - let mut decomp_rlwe = vec![vec![0u64; ring_size]; decomposer.decomposition_count()]; - rlwe_to_switch.iter().enumerate().for_each(|(ri, el)| { - decomposer - .decompose_iter(el) - .enumerate() - .for_each(|(j, d_el)| { - decomp_rlwe[j][ri] = d_el; - }); - }); - - // put ksk_u and decomp in fourier domain - decomp_rlwe - .iter_mut() - .for_each(|r| nttop.forward(r.as_mut_slice())); - party0_ksk_u - .iter_mut() - .for_each(|r| nttop.forward(r.as_mut_slice())); - - let (ksk_u_a, ksk_u_b) = party0_ksk_u.split_at(decomposer.decomposition_count()); - let mut rlwe_main_m_partb_eval = vec![vec![0u64; ring_size]; 2]; - izip!(decomp_rlwe.iter(), ksk_u_a.iter(), ksk_u_b.iter()).for_each(|(o, a, b)| { - // A part - // rlwe[0] += o*a - izip!(rlwe_main_m_partb_eval[0].iter_mut(), o.iter(), a.iter()).for_each( - |(r, o, a)| { - *r = modop.add(r, &modop.mul(o, a)); - }, - ); - - // B part - // rlwe[1] += o*b - izip!(rlwe_main_m_partb_eval[1].iter_mut(), o.iter(), b.iter()).for_each( - |(r, o, b)| { - *r = modop.add(r, &modop.mul(o, b)); - }, - ); - }); - - // construct RLWE_{s_{ideal}}(-sm) - nttop.forward(rlwe_main_m_parta.as_mut_slice()); - modop.elwise_add_mut(&mut rlwe_main_m_partb_eval[0], &rlwe_main_m_parta); - let rlwe_main_m_eval = rlwe_main_m_partb_eval; - - // decrypt RLWE_{s_{ideal}}(m) and check - let mut neg_s_m_main_out = rlwe_main_m_eval[0].clone(); - modop.elwise_mul_mut(&mut neg_s_m_main_out, &sk_poly_ideal_eval); - modop.elwise_neg_mut(&mut neg_s_m_main_out); - modop.elwise_add_mut(&mut neg_s_m_main_out, &rlwe_main_m_eval[1]); - nttop.backward(&mut neg_s_m_main_out); - - let mut neg_s_main_m = main_m.clone(); - nttop.forward(&mut neg_s_main_m); - modop.elwise_mul_mut(&mut neg_s_main_m, &sk_poly_ideal_eval); - modop.elwise_neg_mut(&mut neg_s_main_m); - nttop.backward(&mut neg_s_main_m); - - let mut diff = neg_s_m_main_out.clone(); - modop.elwise_sub_mut(&mut diff, &neg_s_main_m); - - let mut stat = Stats::new(); - stat.add_more(&Vec::::try_convert_from(&diff, &q)); - println!("Log2 Std: {}", stat.std_dev().abs().log2()); - } -} +// #[cfg(test)] +// mod tests { +// use itertools::{izip, Itertools}; +// use num_traits::zero; +// use rand::{thread_rng, Rng}; + +// use crate::{ +// bool::keys::ClientKey, +// ntt, +// random::{ +// DefaultSecureRng, RandomFill, RandomFillGaussianInModulus, +// RandomFillUniformInModulus, }, +// utils::{ +// fill_random_ternary_secret_with_hamming_weight, generate_prime, +// Stats, TryConvertFrom1, }, +// ArithmeticOps, Decomposer, DefaultDecomposer, ModInit, ModularOpsU64, +// Ntt, NttBackendU64, NttInit, VectorOps, +// }; + +// #[test] +// fn non_interactive_multi_party() { +// let logq = 56; +// let ring_size = 1usize << 11; +// let q = generate_prime(logq, 2 * ring_size as u64, 1 << +// logq).unwrap(); let logb = 1; +// let d = 56; +// let decomposer = DefaultDecomposer::new(q, logb, d); +// let gadget_vec = decomposer.gadget_vector(); +// let mut rng = DefaultSecureRng::new(); + +// let modop = ModularOpsU64::new(q); +// let nttop = NttBackendU64::new(&q, ring_size); + +// let no_of_parties = 16; +// let client_secrets = (0..no_of_parties) +// .into_iter() +// .map(|_| { +// let mut sk = vec![0i64; ring_size]; +// fill_random_ternary_secret_with_hamming_weight(&mut sk, +// ring_size >> 1, &mut rng); sk +// }) +// .collect_vec(); + +// let mut s_ideal = vec![0i64; ring_size]; +// client_secrets.iter().for_each(|s| { +// izip!(s_ideal.iter_mut(), s.iter()).for_each(|(add_to, v)| { +// *add_to = *add_to + *v; +// }); +// }); + +// let sk_poly_ideal = Vec::::try_convert_from(s_ideal.as_slice(), +// &q); let mut sk_poly_ideal_eval = sk_poly_ideal.clone(); +// nttop.forward(&mut sk_poly_ideal_eval); + +// let mut ksk_seed = [0u8; 32]; +// rng.fill_bytes(&mut ksk_seed); + +// // zero encryptions for each party for ksk(u) +// let client_zero_encs = { +// client_secrets +// .iter() +// .map(|sk| { +// let sk_poly = Vec::::try_convert_from(sk.as_slice(), +// &q); let mut sk_poly_eval = sk_poly.clone(); +// nttop.forward(sk_poly_eval.as_mut_slice()); + +// let mut zero_encs = +// vec![vec![0u64; ring_size]; +// decomposer.decomposition_count()]; let mut ksk_prng = +// DefaultSecureRng::new_seeded(ksk_seed); +// zero_encs.iter_mut().for_each(|out| { +// RandomFillUniformInModulus::random_fill( &mut +// ksk_prng, &q, +// out.as_mut_slice(), +// ); +// nttop.forward(out.as_mut_slice()); +// modop.elwise_mul_mut(out.as_mut_slice(), +// &sk_poly_eval); nttop.backward(out.as_mut_slice()); + +// let mut error = vec![0u64; ring_size]; +// RandomFillGaussianInModulus::random_fill(&mut rng, +// &q, &mut error); + +// modop.elwise_add_mut(out.as_mut_slice(), &error); +// }); +// zero_encs +// }) +// .collect_vec() +// }; + +// // main values +// let main_a = { +// let mut a = vec![0u64; ring_size]; +// RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut a); +// a +// }; +// let main_m = { +// let mut main_m = vec![0u64; ring_size]; +// RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut +// main_m); main_m +// }; + +// let mut main_u = vec![0i64; ring_size]; +// fill_random_ternary_secret_with_hamming_weight(&mut main_u, ring_size +// >> 1, &mut rng); let u_main_poly = +// Vec::::try_convert_from(main_u.as_slice(), &q); let mut +// u_main_poly_eval = u_main_poly.clone(); nttop. +// forward(u_main_poly_eval.as_mut_slice()); + +// // party 0 +// let (mut party0_ksk_u, mut rlwe_main_m_parta) = { +// // party 0's secret +// let sk = client_secrets[0].clone(); +// let sk_poly = Vec::::try_convert_from(sk.as_slice(), &q); +// let mut sk_poly_eval = sk_poly.clone(); +// nttop.forward(sk_poly_eval.as_mut_slice()); + +// // `main_a*u + main_m` with ephemeral key u +// let mut rlwe_main_m = main_a.clone(); +// nttop.forward(&mut rlwe_main_m); +// modop.elwise_mul_mut(&mut rlwe_main_m, &u_main_poly_eval); +// nttop.backward(&mut rlwe_main_m); +// let mut error = vec![0u64; ring_size]; +// RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut +// error); modop.elwise_add_mut(&mut rlwe_main_m, &error); +// modop.elwise_add_mut(&mut rlwe_main_m, &main_m); + +// // Generate KSK(u) +// let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed); +// let mut ksk_u = vec![vec![0u64; ring_size]; 2 * +// decomposer.decomposition_count()]; let (ksk_u_a, ksk_u_b) = +// ksk_u.split_at_mut(decomposer.decomposition_count()); +// izip!(ksk_u_b.iter_mut(), ksk_u_a.iter_mut(), gadget_vec.iter()).for_each( |(row_b, row_a, beta_i)| { +// // sample a +// RandomFillUniformInModulus::random_fill(&mut ksk_prng, +// &q, row_a.as_mut()); + +// // s_i * a +// let mut s_i_a = row_a.clone(); +// nttop.forward(&mut s_i_a); +// modop.elwise_mul_mut(&mut s_i_a, &sk_poly_eval); +// nttop.backward(&mut s_i_a); + +// // \beta * u +// let mut beta_u = u_main_poly.clone(); +// modop.elwise_scalar_mul_mut(beta_u.as_mut_slice(), +// beta_i); + +// // e +// RandomFillGaussianInModulus::random_fill(&mut rng, &q, +// row_b.as_mut_slice()); // e + \beta * u +// modop.elwise_add_mut(row_b.as_mut_slice(), &beta_u); + +// // b = e + \beta * u + a * s_i +// modop.elwise_add_mut(row_b.as_mut_slice(), &s_i_a); +// }, +// ); + +// // send ksk u from s_0 to s_{ideal} +// ksk_u_b.iter_mut().enumerate().for_each(|(index, out_b)| { +// // note: skip zero encryption of party 0 +// client_zero_encs.iter().skip(1).for_each(|encs| { +// modop.elwise_add_mut(out_b, &encs[index]); +// }); +// }); + +// // // put ksk in fourier domain +// // ksk_u +// // .iter_mut() +// // .for_each(|r| nttop.forward(r.as_mut_slice())); +// (ksk_u, rlwe_main_m) +// }; + +// // Check ksk_u is correct +// // { +// // let (ksk_a, ksk_b) = +// // party0_ksk_u.split_at_mut(decomposer.decomposition_count()); +// // izip!( +// // ksk_a.iter(), +// // ksk_b.iter(), +// // decomposer.gadget_vector().iter() +// // ) +// // .for_each(|(row_a, row_b, beta_i)| { +// // // a * s +// // let mut sa = row_a.clone(); +// // nttop.forward(&mut sa); +// // modop.elwise_mul_mut(&mut sa, &sk_poly_ideal_eval); +// // nttop.backward(&mut sa); + +// // // b - a*s +// // let mut out = sa; +// // modop.elwise_neg_mut(&mut out); +// // modop.elwise_add_mut(&mut out, row_b); + +// // // beta * u +// // let mut expected = u_main_poly.clone(); +// // modop.elwise_scalar_mul_mut(&mut expected, beta_i); +// // assert_eq!(expected, out); +// // }); +// // } + +// // RLWE(0) = main_a * s + e = \sum main_a*s_i + e_i +// let rlwe_to_switch = { +// let mut sum = vec![0u64; ring_size]; +// client_secrets.iter().for_each(|sk| { +// let sk_poly = Vec::::try_convert_from(sk.as_slice(), +// &q); let mut sk_poly_eval = sk_poly.clone(); +// nttop.forward(sk_poly_eval.as_mut_slice()); + +// // a * s +// let mut rlwe = main_a.clone(); +// nttop.forward(&mut rlwe); +// modop.elwise_mul_mut(rlwe.as_mut_slice(), &sk_poly_eval); +// nttop.backward(&mut rlwe); +// // a * s + e +// let mut error = vec![0u64; ring_size]; +// RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut +// error); modop.elwise_add_mut(&mut rlwe, &error); + +// modop.elwise_add_mut(&mut sum, &rlwe); +// }); +// sum +// }; +// // { +// // let mut tmp = main_a.clone(); +// // nttop.forward(&mut tmp); +// // modop.elwise_mul_mut(&mut tmp, &sk_poly_ideal_eval); +// // nttop.backward(&mut tmp); +// // assert_eq!(&rlwe_to_switch, &tmp); +// // } + +// // Key switch \sum decomp * KSK(i) +// let mut decomp_rlwe = vec![vec![0u64; ring_size]; +// decomposer.decomposition_count()]; rlwe_to_switch.iter().enumerate(). +// for_each(|(ri, el)| { decomposer +// .decompose_iter(el) +// .enumerate() +// .for_each(|(j, d_el)| { +// decomp_rlwe[j][ri] = d_el; +// }); +// }); + +// // put ksk_u and decomp in fourier domain +// decomp_rlwe +// .iter_mut() +// .for_each(|r| nttop.forward(r.as_mut_slice())); +// party0_ksk_u +// .iter_mut() +// .for_each(|r| nttop.forward(r.as_mut_slice())); + +// let (ksk_u_a, ksk_u_b) = +// party0_ksk_u.split_at(decomposer.decomposition_count()); let mut +// rlwe_main_m_partb_eval = vec![vec![0u64; ring_size]; 2]; izip! +// (decomp_rlwe.iter(), ksk_u_a.iter(), ksk_u_b.iter()).for_each(|(o, a, b)| { +// // A part +// // rlwe[0] += o*a +// izip!(rlwe_main_m_partb_eval[0].iter_mut(), o.iter(), +// a.iter()).for_each( |(r, o, a)| { +// *r = modop.add(r, &modop.mul(o, a)); +// }, +// ); + +// // B part +// // rlwe[1] += o*b +// izip!(rlwe_main_m_partb_eval[1].iter_mut(), o.iter(), +// b.iter()).for_each( |(r, o, b)| { +// *r = modop.add(r, &modop.mul(o, b)); +// }, +// ); +// }); + +// // construct RLWE_{s_{ideal}}(-sm) +// nttop.forward(rlwe_main_m_parta.as_mut_slice()); +// modop.elwise_add_mut(&mut rlwe_main_m_partb_eval[0], +// &rlwe_main_m_parta); let rlwe_main_m_eval = rlwe_main_m_partb_eval; + +// // decrypt RLWE_{s_{ideal}}(m) and check +// let mut neg_s_m_main_out = rlwe_main_m_eval[0].clone(); +// modop.elwise_mul_mut(&mut neg_s_m_main_out, &sk_poly_ideal_eval); +// modop.elwise_neg_mut(&mut neg_s_m_main_out); +// modop.elwise_add_mut(&mut neg_s_m_main_out, &rlwe_main_m_eval[1]); +// nttop.backward(&mut neg_s_m_main_out); + +// let mut neg_s_main_m = main_m.clone(); +// nttop.forward(&mut neg_s_main_m); +// modop.elwise_mul_mut(&mut neg_s_main_m, &sk_poly_ideal_eval); +// modop.elwise_neg_mut(&mut neg_s_main_m); +// nttop.backward(&mut neg_s_main_m); + +// let mut diff = neg_s_m_main_out.clone(); +// modop.elwise_sub_mut(&mut diff, &neg_s_main_m); + +// let mut stat = Stats::new(); +// stat.add_more(&Vec::::try_convert_from(&diff, &q)); +// println!("Log2 Std: {}", stat.std_dev().abs().log2()); +// } +// } diff --git a/src/shortint/mod.rs b/src/shortint/mod.rs index 82a5205..65774e3 100644 --- a/src/shortint/mod.rs +++ b/src/shortint/mod.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use crate::{ - bool::keys::{ClientKey, PublicKey}, + bool::{ClientKey, PublicKey}, Decryptor, Encryptor, MultiPartyDecryptor, }; @@ -97,10 +97,7 @@ mod frontend { eight_bit_mul, }; use crate::{ - bool::{ - evaluator::{self, BoolEvaluator, BooleanGates}, - keys::{ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain}, - }, + bool::evaluator::{BoolEvaluator, BooleanGates}, utils::{Global, WithLocal}, }; diff --git a/src/utils.rs b/src/utils.rs index 3b23d4a..2cd02a3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -190,6 +190,17 @@ pub fn negacyclic_mul T>( return r; } +pub(crate) fn puncture_p_rng>( + p_rng: &mut R, + times: usize, +) -> S { + let mut out = S::default(); + for _ in 0..times { + RandomFill::::random_fill(p_rng, &mut out); + } + return out; +} + pub trait TryConvertFrom1 { fn try_convert_from(value: &T, parameters: &P) -> Self; }