clean lwe

This commit is contained in:
Janmajaya Mall
2024-06-28 17:51:40 +05:30
parent 3eeae8b47f
commit 8e6cde2d89
9 changed files with 257 additions and 325 deletions

View File

@@ -5,23 +5,18 @@ use std::{
usize,
};
use itertools::{izip, partition, Itertools};
use num_traits::{
zero, FromPrimitive, Num, One, Pow, PrimInt, ToPrimitive, WrappingAdd, WrappingSub, Zero,
};
use rand::Rng;
use itertools::{izip, Itertools};
use num_traits::{FromPrimitive, One, PrimInt, ToPrimitive, WrappingAdd, WrappingSub, Zero};
use rand_distr::uniform::SampleUniform;
use crate::{
backend::{
ArithmeticOps, GetModulus, ModInit, ModularOpsU64, Modulus, ShoupMatrixFMA, VectorOps,
},
backend::{ArithmeticOps, GetModulus, ModInit, Modulus, ShoupMatrixFMA, VectorOps},
bool::parameters::ParameterVariant,
decomposer::{Decomposer, DefaultDecomposer, NumInfo, RlweDecomposer},
lwe::{decrypt_lwe, encrypt_lwe, lwe_key_switch, lwe_ksk_keygen, measure_noise_lwe, LweSecret},
lwe::{decrypt_lwe, encrypt_lwe, seeded_lwe_ksk_keygen},
multi_party::{
non_interactive_ksk_gen, non_interactive_ksk_zero_encryptions_for_other_party_i,
non_interactive_rgsw_ct, public_key_share,
public_key_share,
},
ntt::{self, Ntt, NttBackendU64, NttInit},
pbs::{pbs, sample_extract, PbsInfo, PbsKey, WithShoupRepr},
@@ -48,8 +43,7 @@ use super::{
CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare,
InteractiveMultiPartyClientKey, NonInteractiveMultiPartyClientKey,
SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey,
SeededSinglePartyServerKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain,
SinglePartyClientKey,
SeededSinglePartyServerKey, SinglePartyClientKey,
},
parameters::{
BoolParameters, CiphertextModulus, DecompositionCount, DecompostionLogBase,
@@ -67,9 +61,8 @@ use super::{
/// Initial Seed:
/// Puncture 1 -> Public key share seed
/// Puncture 2 -> Main server key share seed
/// Puncture 1 -> RGSW cuphertexts seed
/// Puncture 2 -> Auto keys cipertexts seed
/// Puncture 3 -> LWE ksk seed
/// Puncture 1 -> Auto keys cipertexts seed
/// Puncture 2 -> LWE ksk seed
#[derive(Clone, PartialEq)]
pub struct MultiPartyCrs<S> {
pub(super) seed: S,
@@ -97,19 +90,14 @@ impl<S: Default + Copy> MultiPartyCrs<S> {
puncture_p_rng(&mut prng, 2)
}
pub(super) fn rgsw_cts_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
pub(super) fn auto_keys_cts_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
puncture_p_rng(&mut key_prng, 1)
}
pub(super) fn auto_keys_cts_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
puncture_p_rng(&mut key_prng, 2)
}
pub(super) fn lwe_ksk_cts_seed_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
puncture_p_rng(&mut key_prng, 3)
puncture_p_rng(&mut key_prng, 2)
}
}
@@ -119,7 +107,8 @@ impl<S: Default + Copy> MultiPartyCrs<S> {
/// Puncture 1 -> Key Seed
/// Puncture 1 -> Rgsw ciphertext seed
/// Puncture l+1 -> Seed for zero encs and non-interactive
/// multi-party RGSW ciphertext corresponding to l^th LWE index.
/// multi-party RGSW ciphertexts of
/// l^th LWE index.
/// Puncture 2 -> auto keys seed
/// Puncture 3 -> Lwe key switching key seed
/// Puncture 2 -> user specific seed for u_j to s ksk
@@ -931,12 +920,9 @@ where
// LWE KSK from RLWE secret s -> LWE secret z
let d_lwe_gadget = self.pbs_info.lwe_decomposer.gadget_vector();
let mut lwe_ksk =
M::R::zeros(self.pbs_info.lwe_decomposer.decomposition_count() * ring_size);
lwe_ksk_keygen(
let lwe_ksk = seeded_lwe_ksk_keygen(
&sk_rlwe,
&sk_lwe,
&mut lwe_ksk,
&d_lwe_gadget,
&self.pbs_info.lwe_modop,
&mut main_prng,
@@ -2049,21 +2035,16 @@ where
) -> M::R {
DefaultSecureRng::with_local_mut(|rng| {
let mut p_rng = DefaultSecureRng::new_seeded(lwe_ksk_seed);
let mut lwe_ksk = M::R::zeros(
self.pbs_info.lwe_decomposer.decomposition_count() * self.parameters().rlwe_n().0,
);
let lwe_modop = &self.pbs_info.lwe_modop;
let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector();
lwe_ksk_keygen(
seeded_lwe_ksk_keygen(
sk_rlwe,
sk_lwe,
&mut lwe_ksk,
&d_lwe_gadget_vec,
lwe_modop,
&mut p_rng,
rng,
);
lwe_ksk
)
})
}
@@ -2238,15 +2219,7 @@ where
};
DefaultSecureRng::with_local_mut(|rng| {
let mut lwe_out = M::R::zeros(self.pbs_info.parameters.rlwe_n().0 + 1);
encrypt_lwe(
&mut lwe_out,
&m,
&client_key.sk_rlwe(),
&self.pbs_info.rlwe_modop,
rng,
);
lwe_out
encrypt_lwe(&m, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop, rng)
})
}

View File

@@ -2,7 +2,6 @@ use std::{collections::HashMap, hash::Hash, marker::PhantomData};
use crate::{
backend::{ModInit, VectorOps},
lwe::LweSecret,
pbs::WithShoupRepr,
random::{NewWithSeed, RandomFillUniformInModulus},
rgsw::RlweSecret,

View File

@@ -22,7 +22,8 @@ pub type ClientKey = keys::ClientKey<[u8; 32], u64>;
pub enum ParameterSelector {
HighCommunicationButFast2Party,
MultiPartyLessThanOrEqualTo16,
NonInteractiveMultiPartyLessThanOrEqualTo16,
NonInteractiveLTE2Party,
NonInteractiveLTE4Party,
}
mod common_mp_enc_dec {

View File

@@ -3,6 +3,7 @@ use std::{cell::RefCell, sync::OnceLock};
use crate::{
backend::ModulusPowerOf2,
bool::parameters::ParameterVariant,
parameters::NI_4P,
random::DefaultSecureRng,
utils::{Global, WithLocal},
ModularOpsU64, NttBackendU64,
@@ -38,9 +39,13 @@ static MULTI_PARTY_CRS: OnceLock<NonInteractiveMultiPartyCrs<[u8; 32]>> = OnceLo
pub fn set_parameter_set(select: ParameterSelector) {
match select {
ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16 => {
ParameterSelector::NonInteractiveLTE2Party => {
BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(NI_2P)));
}
ParameterSelector::NonInteractiveLTE4Party => {
BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(NI_4P)));
}
_ => {
panic!("Paramerters not supported")
}
@@ -160,6 +165,13 @@ impl Global for RuntimeServerKey {
}
}
pub(super) struct NonInteractiveBatchedFheBools<C> {
data: Vec<C>,
}
pub(super) struct BatchedFheBools<C> {
pub(in super::super) data: Vec<C>,
}
/// Non interactive multi-party specfic encryptor decryptor routines
mod impl_enc_dec {
use crate::{
@@ -177,10 +189,6 @@ mod impl_enc_dec {
type Mat = Vec<Vec<u64>>;
pub(super) struct BatchedFheBools<C> {
pub(super) data: Vec<C>,
}
impl<C: MatrixMut<MatElement = u64>> BatchedFheBools<C>
where
C::R: RowEntity + RowMut,
@@ -202,10 +210,6 @@ mod impl_enc_dec {
}
}
pub(super) struct NonInteractiveBatchedFheBools<C> {
data: Vec<C>,
}
impl<M: MatrixEntity + MatrixMut<MatElement = u64>> From<&(Vec<M::R>, [u8; 32])>
for NonInteractiveBatchedFheBools<M>
where
@@ -349,10 +353,9 @@ mod impl_enc_dec {
#[cfg(test)]
mod tests {
use impl_enc_dec::NonInteractiveBatchedFheBools;
use itertools::{izip, Itertools};
use num_traits::{FromPrimitive, PrimInt, ToPrimitive, Zero};
use rand::{thread_rng, RngCore};
use rand::{thread_rng, Rng, RngCore};
use crate::{
backend::{GetModulus, Modulus},
@@ -374,7 +377,7 @@ mod tests {
#[test]
fn non_interactive_mp_bool_nand() {
set_parameter_set(ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16);
set_parameter_set(ParameterSelector::NonInteractiveLTE2Party);
let mut seed = [0u8; 32];
thread_rng().fill_bytes(&mut seed);
set_common_reference_seed(seed);
@@ -444,63 +447,4 @@ mod tests {
ct0 = ct_out;
}
}
#[test]
fn trialtest() {
set_parameter_set(ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16);
set_common_reference_seed([2; 32]);
let parties = 2;
let cks = (0..parties).map(|_| gen_client_key()).collect_vec();
let key_shares = cks
.iter()
.enumerate()
.map(|(user_index, ck)| gen_server_key_share(user_index, parties, ck))
.collect_vec();
let seeded_server_key = aggregate_server_key_shares(&key_shares);
seeded_server_key.set_server_key();
let m = vec![false, true];
let ct: NonInteractiveBatchedFheBools<_> = cks[0].encrypt(m.as_slice());
let ct = ct.key_switch(0);
let parameters = BoolEvaluator::with_local(|e| e.parameters().clone());
let nttop = NttBackendU64::new(parameters.rlwe_q(), parameters.rlwe_n().0);
let rlwe_q_modop = ModularOpsU64::new(*parameters.rlwe_q());
let mut ideal_rlwe_sk = vec![0i32; parameters.rlwe_n().0];
cks.iter().for_each(|k| {
let sk_rlwe = k.sk_rlwe();
izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
*a = *a + b;
});
});
let message = m
.iter()
.map(|b| parameters.rlwe_q().encode(*b))
.collect_vec();
let mut m_out = vec![0u64; parameters.rlwe_n().0];
decrypt_rlwe(
&ct.data[0],
&ideal_rlwe_sk,
&mut m_out,
&nttop,
&rlwe_q_modop,
);
let mut diff = m_out;
rlwe_q_modop.elwise_sub_mut(diff.as_mut_slice(), message.as_ref());
let mut stats = Stats::new();
stats.add_more(&Vec::<i64>::try_convert_from(
diff.as_slice(),
parameters.rlwe_q(),
));
println!("Noise: {}", stats.std_dev().abs().log2());
}
}

View File

@@ -534,6 +534,31 @@ pub(crate) const NI_2P: BoolParameters<u64> = BoolParameters::<u64> {
variant: ParameterVariant::NonInteractiveMultiParty,
};
pub(crate) const NI_4P: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
lwe_q: CiphertextModulus::new_non_native(1 << 16),
br_q: 1 << 11,
rlwe_n: PolynomialSize(1 << 11),
lwe_n: LweDimension(510),
lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
rlrg_decomposer_params: (
DecompostionLogBase(17),
(DecompositionCount(1), DecompositionCount(1)),
),
rgrg_decomposer_params: Some((
DecompostionLogBase(4),
(DecompositionCount(10), DecompositionCount(9)),
)),
auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
non_interactive_ui_to_s_key_switch_decomposer: Some((
DecompostionLogBase(1),
DecompositionCount(50),
)),
g: 5,
w: 10,
variant: ParameterVariant::NonInteractiveMultiParty,
};
#[cfg(test)]
pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: CiphertextModulus::new_non_native(268369921u64),

View File

@@ -427,7 +427,7 @@ mod tests {
NttBackendU64,
};
set_parameter_set(crate::ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16);
set_parameter_set(crate::ParameterSelector::NonInteractiveLTE2Party);
set_common_reference_seed(NonInteractiveMultiPartyCrs::random().seed);
let parties = 2;
let cks = (0..parties).map(|i| gen_client_key()).collect_vec();
@@ -469,4 +469,73 @@ mod tests {
server_key_stats.post_lwe_key_switch.std_dev().abs().log2()
);
}
#[test]
#[cfg(feature = "non_interactive_mp")]
fn enc_under_sk_and_key_switch() {
use rand::{thread_rng, Rng};
use crate::{
aggregate_server_key_shares,
bool::{keys::tests::ideal_sk_rlwe, ni_mp_api::NonInteractiveBatchedFheBools},
gen_client_key, gen_server_key_share,
rgsw::decrypt_rlwe,
set_common_reference_seed, set_parameter_set,
utils::{tests::Stats, TryConvertFrom1, WithLocal},
BoolEvaluator, Encoder, Encryptor, KeySwitchWithId, ModInit, ModularOpsU64,
NttBackendU64, NttInit, ParameterSelector, VectorOps,
};
set_parameter_set(ParameterSelector::NonInteractiveLTE2Party);
set_common_reference_seed([2; 32]);
let parties = 2;
let cks = (0..parties).map(|_| gen_client_key()).collect_vec();
let key_shares = cks
.iter()
.enumerate()
.map(|(user_index, ck)| gen_server_key_share(user_index, parties, ck))
.collect_vec();
let seeded_server_key = aggregate_server_key_shares(&key_shares);
seeded_server_key.set_server_key();
let parameters = BoolEvaluator::with_local(|e| e.parameters().clone());
let nttop = NttBackendU64::new(parameters.rlwe_q(), parameters.rlwe_n().0);
let rlwe_q_modop = ModularOpsU64::new(*parameters.rlwe_q());
let m = (0..parameters.rlwe_n().0)
.map(|_| thread_rng().gen_bool(0.5))
.collect_vec();
let ct: NonInteractiveBatchedFheBools<_> = cks[0].encrypt(m.as_slice());
let ct = ct.key_switch(0);
let ideal_rlwe_sk = ideal_sk_rlwe(&cks);
let message = m
.iter()
.map(|b| parameters.rlwe_q().encode(*b))
.collect_vec();
let mut m_out = vec![0u64; parameters.rlwe_n().0];
decrypt_rlwe(
&ct.data[0],
&ideal_rlwe_sk,
&mut m_out,
&nttop,
&rlwe_q_modop,
);
let mut diff = m_out;
rlwe_q_modop.elwise_sub_mut(diff.as_mut_slice(), message.as_ref());
let mut stats = Stats::new();
stats.add_more(&Vec::<i64>::try_convert_from(
diff.as_slice(),
parameters.rlwe_q(),
));
println!("Noise std log2: {}", stats.std_dev().abs().log2());
}
}