add non-interactive multiparty server key eval domain

This commit is contained in:
Janmajaya Mall
2024-06-17 13:46:24 +05:30
parent b1af696918
commit 6aabfbfd71
6 changed files with 1009 additions and 569 deletions

View File

@@ -46,24 +46,29 @@ use crate::{
}; };
use super::{ use super::{
keys::ClientKey,
parameters::{BoolParameters, CiphertextModulus}, parameters::{BoolParameters, CiphertextModulus},
CommonReferenceSeededCollectivePublicKeyShare, CommonReferenceSeededMultiPartyServerKeyShare, ClientKey, CommonReferenceSeededCollectivePublicKeyShare,
DecompositionCount, DecompostionLogBase, DoubleDecomposerParams, NonInteractiveClientKey, CommonReferenceSeededMultiPartyServerKeyShare, DecompositionCount, DecompostionLogBase,
SeededMultiPartyServerKey, SeededServerKey, ServerKeyEvaluationDomain, DoubleDecomposerParams, SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey,
ShoupServerKeyEvaluationDomain, SeededSinglePartyServerKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain,
ThrowMeAwayKey,
}; };
pub struct NonInteractiveMultiPartyServerKeyShare<M> { pub struct NonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
/// (ak*si + e + \beta ui, ak*si + e) /// (ak*si + e + \beta ui, ak*si + e)
ni_rgsw_cts: (Vec<M>, Vec<M>), ni_rgsw_cts: (Vec<M>, Vec<M>),
ui_to_s_ksk: M, ui_to_s_ksk: M,
others_ksk_zero_encs: Vec<M>, others_ksk_zero_encs: Vec<M>,
auto_keys_share: HashMap<usize, M>,
lwe_ksk_share: M::R,
user_index: usize, user_index: usize,
cr_seed: S,
} }
impl<M> NonInteractiveMultiPartyServerKeyShare<M> { impl<M: Matrix, S> NonInteractiveMultiPartyServerKeyShare<M, S> {
fn zero_enc_for_ui_to_s_ksk_for_user_i(&self, user_i: usize) -> &M { fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M {
assert!(user_i != self.user_index); assert!(user_i != self.user_index);
if user_i < self.user_index { if user_i < self.user_index {
&self.others_ksk_zero_encs[user_i] &self.others_ksk_zero_encs[user_i]
@@ -77,46 +82,68 @@ pub struct MultiPartyCrs<S> {
pub(super) seed: S, pub(super) seed: S,
} }
fn puncture_p_rng<S: Default + Copy, R: RandomFill<S>>(p_rng: &mut R, times: usize) -> S {
let mut out = S::default();
for _ in 0..times {
RandomFill::<S>::random_fill(p_rng, &mut out);
}
return out;
}
/// Common reference seed used for non-interactive multi-party.
///
/// Initial Seed
/// Puncture 1 -> Key Seed
/// Puncture 1 -> Rgsw ciphertext seed
/// Puncture 2 -> auto keys seed
/// Puncture 3 -> Lwe key switching key seed
/// Puncture 2 -> user specific seed for u_j to s ksk
/// Punture j+1 -> user j's seed
#[derive(Clone)]
pub struct NonInteractiveMultiPartyCrs<S> { pub struct NonInteractiveMultiPartyCrs<S> {
pub(super) seed: S, pub(super) seed: S,
} }
// impl<S: Clone> Clone for NonInteractiveMultiPartyCrs<S> where S: Clone {}
// impl<S: Copy> Copy for NonInteractiveMultiPartyCrs<S> where S: Copy {}
impl<S: Default + Copy> NonInteractiveMultiPartyCrs<S> { impl<S: Default + Copy> NonInteractiveMultiPartyCrs<S> {
fn server_key_share_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S { fn key_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut p_rng = R::new_with_seed(self.seed); let mut p_rng = R::new_with_seed(self.seed);
puncture_p_rng(&mut p_rng, 1)
}
// for main server key share seed sample once pub(crate) fn rgsw_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut out = S::default(); let key_seed = self.key_seed::<R>();
RandomFill::<S>::random_fill(&mut p_rng, &mut out); let mut p_rng = R::new_with_seed(key_seed);
puncture_p_rng(&mut p_rng, 1)
}
out pub(crate) fn auto_keys_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let key_seed = self.key_seed::<R>();
let mut p_rng = R::new_with_seed(key_seed);
puncture_p_rng(&mut p_rng, 2)
}
pub(crate) fn lwe_ksk_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let key_seed = self.key_seed::<R>();
let mut p_rng = R::new_with_seed(key_seed);
puncture_p_rng(&mut p_rng, 3)
} }
fn ui_to_s_ks_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S { fn ui_to_s_ks_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
let mut p_rng = R::new_with_seed(self.seed); let mut p_rng = R::new_with_seed(self.seed);
puncture_p_rng(&mut p_rng, 2)
// puncture twice
let mut out = S::default();
RandomFill::<S>::random_fill(&mut p_rng, &mut out);
RandomFill::<S>::random_fill(&mut p_rng, &mut out);
out
} }
fn ui_to_s_ks_seed_for_user_i<R: NewWithSeed<Seed = S> + RandomFill<S>>( pub(crate) fn ui_to_s_ks_seed_for_user_i<R: NewWithSeed<Seed = S> + RandomFill<S>>(
&self, &self,
user_i: usize, user_i: usize,
) -> S { ) -> S {
let ks_seed = self.ui_to_s_ks_seed::<R>(); let ks_seed = self.ui_to_s_ks_seed::<R>();
let mut p_rng = R::new_with_seed(ks_seed); let mut p_rng = R::new_with_seed(ks_seed);
// puncture user_i times puncture_p_rng(&mut p_rng, user_i + 1)
let mut out = S::default();
for _ in 0..user_i + 1 {
RandomFill::<S>::random_fill(&mut p_rng, &mut out);
}
out
} }
} }
@@ -636,7 +663,7 @@ where
ClientKey::new(sk_rlwe, sk_lwe) ClientKey::new(sk_rlwe, sk_lwe)
} }
pub(super) fn non_interactive_client_key(&self) -> NonInteractiveClientKey { pub(super) fn non_interactive_client_key(&self) -> ThrowMeAwayKey {
let sk_lwe = LweSecret::random( let sk_lwe = LweSecret::random(
self.pbs_info.parameters.lwe_n().0 >> 1, self.pbs_info.parameters.lwe_n().0 >> 1,
self.pbs_info.parameters.lwe_n().0, self.pbs_info.parameters.lwe_n().0,
@@ -649,13 +676,13 @@ where
self.pbs_info.parameters.rlwe_n().0 >> 1, self.pbs_info.parameters.rlwe_n().0 >> 1,
self.pbs_info.parameters.rlwe_n().0, self.pbs_info.parameters.rlwe_n().0,
); );
NonInteractiveClientKey::new(sk_rlwe, sk_u_rlwe, sk_lwe) ThrowMeAwayKey::new(sk_rlwe, sk_u_rlwe, sk_lwe)
} }
pub(super) fn single_party_server_key( pub(super) fn single_party_server_key(
&self, &self,
client_key: &ClientKey, client_key: &ClientKey,
) -> SeededServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> { ) -> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> {
DefaultSecureRng::with_local_mut(|rng| { DefaultSecureRng::with_local_mut(|rng| {
let mut main_seed = [0u8; 32]; let mut main_seed = [0u8; 32];
rng.fill_bytes(&mut main_seed); rng.fill_bytes(&mut main_seed);
@@ -748,7 +775,7 @@ where
rng, rng,
); );
SeededServerKey::from_raw( SeededSinglePartyServerKey::from_raw(
auto_keys, auto_keys,
rgsw_cts, rgsw_cts,
lwe_ksk, lwe_ksk,
@@ -889,15 +916,42 @@ where
&self, &self,
cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>, cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
total_users: usize, total_users: usize,
key_shares: &[NonInteractiveMultiPartyServerKeyShare<M>], key_shares: &[NonInteractiveMultiPartyServerKeyShare<
) -> Vec<M> M,
NonInteractiveMultiPartyCrs<[u8; 32]>,
>],
) -> SeededNonInteractiveMultiPartyServerKey<
M,
NonInteractiveMultiPartyCrs<[u8; 32]>,
BoolParameters<M::MatElement>,
>
where where
M: Clone + Debug, M: Clone + Debug,
{ {
// sanity checks
let key_order = {
let existing_key_order = key_shares.iter().map(|s| s.user_index).collect_vec();
// record the order s.t. key_order[i] stores the position of i^th
// users key share in existing order
let mut key_order = Vec::with_capacity(existing_key_order.len());
(0..total_users).map(|i| {
// find i
let index = existing_key_order
.iter()
.position(|x| x == &i)
.expect(&format!("Missing user {i}'s key!"));
key_order.push(index);
});
key_order
};
let rlwe_modop = &self.pbs_info().rlwe_modop; let rlwe_modop = &self.pbs_info().rlwe_modop;
let nttop = &self.pbs_info().rlwe_nttop; let nttop = &self.pbs_info().rlwe_nttop;
let ring_size = self.parameters().rlwe_n().0; let ring_size = self.parameters().rlwe_n().0;
let rlwe_q = self.parameters().rlwe_q(); let rlwe_q = self.parameters().rlwe_q();
let lwe_modop = self.pbs_info().modop_lweq();
// genrate key switching key from u_i to s // genrate key switching key from u_i to s
let ui_to_s_ksk_decomposition_count = self let ui_to_s_ksk_decomposition_count = self
@@ -914,7 +968,7 @@ where
.iter() .iter()
.filter(|x| x.user_index != share.user_index) .filter(|x| x.user_index != share.user_index)
.for_each(|(other_share)| { .for_each(|(other_share)| {
let op2 = other_share.zero_enc_for_ui_to_s_ksk_for_user_i(share.user_index); let op2 = other_share.ui_to_s_ksk_zero_encs_for_user_i(share.user_index);
assert!(op2.dimension() == (ui_to_s_ksk_decomposition_count.0, ring_size)); assert!(op2.dimension() == (ui_to_s_ksk_decomposition_count.0, ring_size));
izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each( izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each(
|(add_to, add_from)| { |(add_to, add_from)| {
@@ -926,8 +980,9 @@ where
}) })
.collect_vec(); .collect_vec();
let mut key_prng = let rgsw_cts = {
DefaultSecureRng::new_seeded(cr_seed.server_key_share_seed::<DefaultSecureRng>()); let mut rgsw_prng =
DefaultSecureRng::new_seeded(cr_seed.rgsw_cts_seed::<DefaultSecureRng>());
let rgsw_by_rgsw_decomposer = self let rgsw_by_rgsw_decomposer = self
.parameters() .parameters()
@@ -946,7 +1001,8 @@ where
.iter() .iter()
.map(|share| { .map(|share| {
let mut ksk_prng = DefaultSecureRng::new_seeded( let mut ksk_prng = DefaultSecureRng::new_seeded(
cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index), cr_seed
.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index),
); );
let mut ais = M::zeros(ui_to_s_ksk_decomposition_count.0, ring_size); let mut ais = M::zeros(ui_to_s_ksk_decomposition_count.0, ring_size);
@@ -1028,8 +1084,7 @@ where
// Decomposition count used for RGSW ct in non-interactive key share gen equals // Decomposition count used for RGSW ct in non-interactive key share gen equals
// max of A and B decomposition required in RGSWxRGSW. This is because same // max of A and B decomposition required in RGSWxRGSW. This is because same
// polynomials are used to generate RLWE'(m) and RLWE'(-sm) // polynomials are used to generate RLWE'(m) and RLWE'(-sm)
let decomp_ni_rgsw_neg_ais = let decomp_ni_rgsw_neg_ais = {
{
let mut tmp_space = M::R::zeros(ring_size); let mut tmp_space = M::R::zeros(ring_size);
(0..self.parameters().lwe_n().0) (0..self.parameters().lwe_n().0)
.into_iter() .into_iter()
@@ -1048,7 +1103,7 @@ where
(0..max_rgrg_deocmposer.decomposition_count()) (0..max_rgrg_deocmposer.decomposition_count())
.map(|_| { .map(|_| {
RandomFillUniformInModulus::random_fill( RandomFillUniformInModulus::random_fill(
&mut key_prng, &mut rgsw_prng,
rlwe_q, rlwe_q,
tmp_space.as_mut(), tmp_space.as_mut(),
); );
@@ -1148,8 +1203,9 @@ where
) )
.for_each( .for_each(
|(rlwe_a, rlwe_b, decomp_ai_s, beta_m_enc_ui)| { |(rlwe_a, rlwe_b, decomp_ai_s, beta_m_enc_ui)| {
// RLWE_s(a_i * s * u_i + u_i * e) = decomp<a_i * s + e> * // RLWE_s(a_i * s * u_i + u_i * e) = decomp<a_i * s + e>
// ksk(u_i -> s) // * ksk(u_i
// -> s)
izip!( izip!(
decomp_ai_s.iter_rows(), decomp_ai_s.iter_rows(),
user_uitos_ksk_partb_eval.iter_rows(), user_uitos_ksk_partb_eval.iter_rows(),
@@ -1157,7 +1213,8 @@ where
) )
.for_each( .for_each(
|(a0, part_b, part_a)| { |(a0, part_b, part_a)| {
// rlwe_b += decomp<a_i * s + e>[i] * ksk part_b[i] // rlwe_b += decomp<a_i * s + e>[i] * ksk
// part_b[i]
rlwe_modop.elwise_mul( rlwe_modop.elwise_mul(
scratch_row.as_mut(), scratch_row.as_mut(),
a0.as_ref(), a0.as_ref(),
@@ -1323,6 +1380,56 @@ where
}) })
.collect_vec(); .collect_vec();
rgsw_cts rgsw_cts
};
// auto keys
let auto_keys = {
let mut auto_keys = HashMap::new();
let auto_elements_dlog = self.parameters().auto_element_dlogs();
for i in auto_elements_dlog.into_iter() {
let mut key = M::zeros(self.parameters().auto_decomposition_count().0, ring_size);
key_shares.iter().for_each(|s| {
let auto_key_share_i = s.auto_keys_share.get(&i).expect("Auto key {i} missing");
assert!(
auto_key_share_i.dimension()
== (self.parameters().auto_decomposition_count().0, ring_size)
);
izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
|(partb_out, partb_share)| {
rlwe_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
},
);
});
auto_keys.insert(i, key);
}
auto_keys
};
// LWE ksk
let lwe_ksk = {
let mut lwe_ksk =
M::R::zeros(self.parameters().lwe_decomposition_count().0 * ring_size);
key_shares.iter().for_each(|s| {
assert!(
s.lwe_ksk_share.as_ref().len()
== self.parameters().lwe_decomposition_count().0 * ring_size
);
lwe_modop.elwise_add_mut(lwe_ksk.as_mut(), s.lwe_ksk_share.as_ref());
});
lwe_ksk
};
SeededNonInteractiveMultiPartyServerKey::new(
ui_to_s_ksks,
key_order,
rgsw_cts,
auto_keys,
lwe_ksk,
cr_seed.clone(),
self.parameters().clone(),
)
} }
pub(super) fn non_interactive_multi_party_key_share( pub(super) fn non_interactive_multi_party_key_share(
@@ -1331,16 +1438,15 @@ where
cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>, cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
self_index: usize, self_index: usize,
total_users: usize, total_users: usize,
client_key: &NonInteractiveClientKey, client_key: &ThrowMeAwayKey,
) -> NonInteractiveMultiPartyServerKeyShare<M> { ) -> NonInteractiveMultiPartyServerKeyShare<M, NonInteractiveMultiPartyCrs<[u8; 32]>> {
// TODO: check whether parameters support `total_users` // TODO: check whether parameters support `total_users`
DefaultSecureRng::with_local_mut(|rng| {
let nttop = self.pbs_info().nttop_rlweq(); let nttop = self.pbs_info().nttop_rlweq();
let rlwe_modop = self.pbs_info().modop_rlweq(); let rlwe_modop = self.pbs_info().modop_rlweq();
let ring_size = self.pbs_info().rlwe_n(); let ring_size = self.pbs_info().rlwe_n();
let rlwe_q = self.parameters().rlwe_q(); let rlwe_q = self.parameters().rlwe_q();
let (ui_to_s_ksk, zero_encs_for_others) = DefaultSecureRng::with_local_mut(|rng| {
// ui_to_s_ksk // ui_to_s_ksk
let non_interactive_decomposer = self let non_interactive_decomposer = self
.parameters() .parameters()
@@ -1383,10 +1489,13 @@ where
}) })
.collect_vec(); .collect_vec();
// Main Key gen follows // (ui_to_s_ksk, zero_encs_for_others)
});
let mut key_prng = // Non-interactive RGSW cts = (a_i * u_j + e + \beta X^{s[i]}, a_i * s_j + e')
DefaultSecureRng::new_seeded(cr_seed.server_key_share_seed::<DefaultSecureRng>()); let ni_rgsw_cts = DefaultSecureRng::with_local_mut(|rng| {
let mut rgsw_cts_prng =
DefaultSecureRng::new_seeded(cr_seed.rgsw_cts_seed::<DefaultSecureRng>());
// generate non-interactive rgsw cts // generate non-interactive rgsw cts
let rgsw_by_rgsw_decomposer = self let rgsw_by_rgsw_decomposer = self
.parameters() .parameters()
@@ -1408,11 +1517,12 @@ where
.map(|s_i| { .map(|s_i| {
// X^{s[i]} // X^{s[i]}
let mut m = M::R::zeros(ring_size); let mut m = M::R::zeros(ring_size);
if *s_i < 0 { let s_i = s_i * (self.pbs_info().embedding_factor() as i32);
if s_i < 0 {
// X^{-s[i]} -> -X^{N+s[i]} // X^{-s[i]} -> -X^{N+s[i]}
m.as_mut()[ring_size - (s_i.abs() as usize)] = rlwe_q.neg_one(); m.as_mut()[ring_size - (s_i.abs() as usize)] = rlwe_q.neg_one();
} else { } else {
m.as_mut()[*s_i as usize] = M::MatElement::one(); m.as_mut()[s_i as usize] = M::MatElement::one();
} }
non_interactive_rgsw_ct::<M, _, _, _, _, _>( non_interactive_rgsw_ct::<M, _, _, _, _, _>(
@@ -1420,20 +1530,112 @@ where
client_key.sk_u_rlwe().values(), client_key.sk_u_rlwe().values(),
m.as_ref(), m.as_ref(),
&ni_rgrg_gadget_vec, &ni_rgrg_gadget_vec,
&mut key_prng, &mut rgsw_cts_prng,
rng, rng,
nttop, nttop,
rlwe_modop, rlwe_modop,
) )
}) })
.unzip(); .unzip();
ni_rgsw_cts
});
// Auto key share
let auto_keys_share = {
let auto_seed = cr_seed.auto_keys_cts_seed::<DefaultSecureRng>();
self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, client_key.sk_rlwe())
};
// Lwe Ksk share
let lwe_ksk_share = {
let lwe_ksk_seed = cr_seed.lwe_ksk_cts_seed::<DefaultSecureRng>();
self._common_rountine_multi_party_lwe_ksk_share_gen(
lwe_ksk_seed,
client_key.sk_rlwe(),
client_key.sk_lwe(),
)
};
NonInteractiveMultiPartyServerKeyShare { NonInteractiveMultiPartyServerKeyShare {
ni_rgsw_cts, ni_rgsw_cts,
ui_to_s_ksk, ui_to_s_ksk,
others_ksk_zero_encs: zero_encs_for_others, others_ksk_zero_encs: zero_encs_for_others,
user_index: self_index, user_index: self_index,
auto_keys_share,
lwe_ksk_share,
cr_seed: cr_seed.clone(),
} }
}
fn _common_rountine_multi_party_auto_keys_share_gen(
&self,
auto_seed: <DefaultSecureRng as NewWithSeed>::Seed,
sk_rlwe: &RlweSecret,
) -> HashMap<usize, M> {
let g = self.pbs_info.parameters.g();
let ring_size = self.pbs_info.parameters.rlwe_n().0;
let br_q = self.pbs_info.parameters.br_q();
let rlweq_modop = &self.pbs_info.rlwe_modop;
let rlweq_nttop = &self.pbs_info.rlwe_nttop;
DefaultSecureRng::with_local_mut(|rng| {
let mut p_rng = DefaultSecureRng::new_seeded(auto_seed);
let mut auto_keys = HashMap::new();
let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
let auto_element_dlogs = self.pbs_info.parameters.auto_element_dlogs();
for i in auto_element_dlogs.into_iter() {
let g_pow = if i == 0 {
-(g as isize)
} else {
(g.pow(i as u32) % br_q) as isize
};
let mut ksk_out = M::zeros(
self.pbs_info.auto_decomposer.decomposition_count(),
ring_size,
);
galois_key_gen(
&mut ksk_out,
sk_rlwe.values(),
g_pow,
&auto_gadget,
rlweq_modop,
rlweq_nttop,
&mut p_rng,
rng,
);
auto_keys.insert(i, ksk_out);
}
auto_keys
})
}
fn _common_rountine_multi_party_lwe_ksk_share_gen(
&self,
lwe_ksk_seed: <DefaultSecureRng as NewWithSeed>::Seed,
sk_rlwe: &RlweSecret,
sk_lwe: &LweSecret,
) -> 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(
sk_rlwe.values(),
sk_lwe.values(),
&mut lwe_ksk,
&d_lwe_gadget_vec,
lwe_modop,
&mut p_rng,
rng,
);
lwe_ksk
}) })
} }
@@ -3104,7 +3306,7 @@ mod tests {
}); });
}); });
let mut stats = Stats::new(); // let mut stats = Stats::new();
let (rlrg_decomp_a, rlrg_decomp_b) = evaluator let (rlrg_decomp_a, rlrg_decomp_b) = evaluator
.parameters() .parameters()
@@ -3118,46 +3320,46 @@ mod tests {
rlwe_modop.elwise_neg_mut(&mut neg_s_poly_eval); rlwe_modop.elwise_neg_mut(&mut neg_s_poly_eval);
nttop.forward(neg_s_poly_eval.as_mut()); nttop.forward(neg_s_poly_eval.as_mut());
rgsw_cts.iter().enumerate().for_each(|(s_index, ct)| { // rgsw_cts.iter().enumerate().for_each(|(s_index, ct)| {
// X^{lwe_s[i]} // // X^{lwe_s[i]}
let mut m = vec![0u64; ring_size]; // let mut m = vec![0u64; ring_size];
if ideal_lwe[s_index] < 0 { // if ideal_lwe[s_index] < 0 {
m[ring_size - (ideal_lwe[s_index].abs() as usize)] = rlwe_q.neg_one(); // m[ring_size - (ideal_lwe[s_index].abs() as usize)] =
} else { // rlwe_q.neg_one(); } else {
m[(ideal_lwe[s_index] as usize)] = 1; // m[(ideal_lwe[s_index] as usize)] = 1;
} // }
let mut neg_sm = m.clone(); // let mut neg_sm = m.clone();
nttop.forward(&mut neg_sm); // nttop.forward(&mut neg_sm);
rlwe_modop.elwise_mul_mut(&mut neg_sm, &neg_s_poly_eval); // rlwe_modop.elwise_mul_mut(&mut neg_sm, &neg_s_poly_eval);
nttop.backward(&mut neg_sm); // nttop.backward(&mut neg_sm);
// RLWE'(-sm) // // RLWE'(-sm)
gadget_vec_a.iter().enumerate().for_each(|(index, beta)| { // gadget_vec_a.iter().enumerate().for_each(|(index, beta)| {
// RLWE(\beta -sm) // // RLWE(\beta -sm)
// \beta * -sX^[lwe_s[i]] // // \beta * -sX^[lwe_s[i]]
let mut beta_neg_sm = neg_sm.clone(); // let mut beta_neg_sm = neg_sm.clone();
rlwe_modop.elwise_scalar_mul_mut(&mut beta_neg_sm, beta); // rlwe_modop.elwise_scalar_mul_mut(&mut beta_neg_sm, beta);
// extract RLWE(-sm \beta) // // extract RLWE(-sm \beta)
let mut rlwe = vec![vec![0u64; ring_size]; 2]; // let mut rlwe = vec![vec![0u64; ring_size]; 2];
rlwe[0].copy_from_slice(&ct[index]); // rlwe[0].copy_from_slice(&ct[index]);
rlwe[1].copy_from_slice(&ct[index + d_a]); // rlwe[1].copy_from_slice(&ct[index + d_a]);
// decrypt // // decrypt
let mut m_out = vec![0u64; ring_size]; // let mut m_out = vec![0u64; ring_size];
decrypt_rlwe(&rlwe, &ideal_rlwe, &mut m_out, nttop, rlwe_modop); // decrypt_rlwe(&rlwe, &ideal_rlwe, &mut m_out, nttop,
// println!("{:?}", &beta_neg_sm); // rlwe_modop); // println!("{:?}", &beta_neg_sm);
let mut diff = m_out; // let mut diff = m_out;
rlwe_modop.elwise_sub_mut(&mut diff, &beta_neg_sm); // rlwe_modop.elwise_sub_mut(&mut diff, &beta_neg_sm);
stats.add_more(&Vec::<i64>::try_convert_from(&diff, rlwe_q)); // stats.add_more(&Vec::<i64>::try_convert_from(&diff, rlwe_q));
}); // });
}); // });
println!("Stats: {}", stats.std_dev().abs().log2()); // println!("Stats: {}", stats.std_dev().abs().log2());
} }
} }

View File

@@ -12,6 +12,25 @@ use crate::{
use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus}; use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus};
trait SinglePartyClientKey {
type Element;
fn sk_rlwe(&self) -> &[Self::Element];
fn sk_lwe(&self) -> &[Self::Element];
}
trait InteractiveMultiPartyClientKey {
type Element;
fn sk_rlwe(&self) -> &[Self::Element];
fn sk_lwe(&self) -> &[Self::Element];
}
trait NonInteractiveMultiPartyClientKey {
type Element;
fn sk_rlwe(&self) -> &[Self::Element];
fn sk_u_rlwe(&self) -> &[Self::Element];
fn sk_lwe(&self) -> &[Self::Element];
}
/// Client key with RLWE and LWE secrets /// Client key with RLWE and LWE secrets
#[derive(Clone)] #[derive(Clone)]
pub struct ClientKey { pub struct ClientKey {
@@ -21,7 +40,7 @@ pub struct ClientKey {
/// Client key with RLWE and LWE secrets /// Client key with RLWE and LWE secrets
#[derive(Clone)] #[derive(Clone)]
pub struct NonInteractiveClientKey { pub struct ThrowMeAwayKey {
sk_rlwe: RlweSecret, sk_rlwe: RlweSecret,
sk_u_rlwe: RlweSecret, sk_u_rlwe: RlweSecret,
sk_lwe: LweSecret, sk_lwe: LweSecret,
@@ -46,7 +65,7 @@ mod impl_ck {
} }
// Client key // Client key
impl NonInteractiveClientKey { impl ThrowMeAwayKey {
pub(in super::super) fn new( pub(in super::super) fn new(
sk_rlwe: RlweSecret, sk_rlwe: RlweSecret,
sk_u_rlwe: RlweSecret, sk_u_rlwe: RlweSecret,
@@ -369,7 +388,7 @@ impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
} }
/// Seeded single party server key /// Seeded single party server key
pub struct SeededServerKey<M: Matrix, P, S> { pub struct SeededSinglePartyServerKey<M: Matrix, P, S> {
/// Rgsw cts of LWE secret elements /// Rgsw cts of LWE secret elements
pub(crate) rgsw_cts: Vec<M>, pub(crate) rgsw_cts: Vec<M>,
/// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
@@ -382,7 +401,7 @@ pub struct SeededServerKey<M: Matrix, P, S> {
/// Main seed /// Main seed
pub(crate) seed: S, pub(crate) seed: S,
} }
impl<M: Matrix, S> SeededServerKey<M, BoolParameters<M::MatElement>, S> { impl<M: Matrix, S> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, S> {
pub(super) fn from_raw( pub(super) fn from_raw(
auto_keys: HashMap<usize, M>, auto_keys: HashMap<usize, M>,
rgsw_cts: Vec<M>, rgsw_cts: Vec<M>,
@@ -410,7 +429,7 @@ impl<M: Matrix, S> SeededServerKey<M, BoolParameters<M::MatElement>, S> {
== (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0) == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
); );
SeededServerKey { SeededSinglePartyServerKey {
rgsw_cts, rgsw_cts,
auto_keys, auto_keys,
lwe_ksk, lwe_ksk,
@@ -438,6 +457,7 @@ pub(super) mod impl_server_key_eval_domain {
use crate::{ use crate::{
backend::Modulus, backend::Modulus,
bool::{NonInteractiveMultiPartyCrs, SeededNonInteractiveMultiPartyServerKey},
ntt::{Ntt, NttInit}, ntt::{Ntt, NttInit},
pbs::PbsKey, pbs::PbsKey,
}; };
@@ -455,14 +475,16 @@ pub(super) mod impl_server_key_eval_domain {
R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>> R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
+ NewWithSeed, + NewWithSeed,
N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>, N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
> From<&SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>> > From<&SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N> for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
where where
<M as Matrix>::R: RowMut, <M as Matrix>::R: RowMut,
M::MatElement: Copy, M::MatElement: Copy,
R::Seed: Clone, R::Seed: Clone,
{ {
fn from(value: &SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>) -> Self { fn from(
value: &SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>,
) -> Self {
let mut main_prng = R::new_with_seed(value.seed.clone()); let mut main_prng = R::new_with_seed(value.seed.clone());
let parameters = &value.parameters; let parameters = &value.parameters;
let g = parameters.g() as isize; let g = parameters.g() as isize;
@@ -697,7 +719,218 @@ pub(super) mod impl_server_key_eval_domain {
} }
} }
/// Server key in evaluation domain pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
/// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
rgsw_cts: Vec<M>,
/// Automorphism keys under ideal rlwe secret
auto_keys: HashMap<usize, M>,
/// LWE key switching key from Q -> Q_{ks}
lwe_ksk: M,
/// Key switching key from user j to ideal secret key s. User j's ksk is at
/// j'th element
ui_to_s_ksks: Vec<M>,
parameters: P,
_phanton: PhantomData<(R, N)>,
}
pub(super) mod impl_non_interactive_server_key_eval_domain {
use itertools::{izip, Itertools};
use crate::{bool::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
use super::*;
impl<M, Rng, N>
From<
SeededNonInteractiveMultiPartyServerKey<
M,
NonInteractiveMultiPartyCrs<Rng::Seed>,
BoolParameters<M::MatElement>,
>,
> for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
where
M: MatrixMut + MatrixEntity + Clone,
Rng: NewWithSeed
+ RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
+ RandomFill<<Rng as NewWithSeed>::Seed>,
N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
M::R: RowMut,
M::MatElement: Copy,
Rng::Seed: Clone + Copy + Default,
{
fn from(
value: SeededNonInteractiveMultiPartyServerKey<
M,
NonInteractiveMultiPartyCrs<Rng::Seed>,
BoolParameters<M::MatElement>,
>,
) -> Self {
let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
let ring_size = value.parameters.rlwe_n().0;
// RGSW cts
// copy over rgsw cts and send to evaluation domain
let mut rgsw_cts = value.rgsw_cts.clone();
rgsw_cts.iter_mut().for_each(|c| {
c.iter_rows_mut()
.for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
});
// Auto keys
// populate pseudo random part of auto keys. Then send auto keys to
// evaluation domain
let mut auto_keys = HashMap::new();
let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
let mut auto_prng = Rng::new_with_seed(auto_seed);
let auto_element_dlogs = value.parameters.auto_element_dlogs();
let d_auto = value.parameters.auto_decomposition_count().0;
auto_element_dlogs.iter().for_each(|el| {
let auto_part_b = value
.auto_keys
.get(el)
.expect(&format!("Auto key for element g^{el} not found"));
assert!(auto_part_b.dimension() == (d_auto, ring_size));
let mut auto_ct = M::zeros(d_auto, ring_size);
// sample part A
auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
RandomFillUniformInModulus::random_fill(
&mut auto_prng,
value.parameters.rlwe_q(),
ri.as_mut(),
)
});
// Copy over part B
izip!(
auto_ct.iter_rows_mut().skip(d_auto),
auto_part_b.iter_rows()
)
.for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
// send to evaluation domain
auto_ct
.iter_rows_mut()
.for_each(|r| rlwe_nttop.forward(r.as_mut()));
auto_keys.insert(*el, auto_ct);
});
// LWE ksk
// populate pseudo random part of lwe ciphertexts in ksk and copy over part b
// elements
let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
let mut lwe_ksk = M::zeros(
value.parameters.lwe_decomposition_count().0 * ring_size,
value.parameters.lwe_n().0 + 1,
);
lwe_ksk.iter_rows_mut().for_each(|ri| {
// first element is resereved for part b. Only sample a_is in the rest
RandomFillUniformInModulus::random_fill(
&mut lwe_ksk_prng,
value.parameters.lwe_q(),
&mut ri.as_mut()[1..],
)
});
// copy over part bs
izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
|(b_el, lwe_ct)| {
lwe_ct.as_mut()[0] = *b_el;
},
);
// u_i to s ksk
let d_uitos = value
.parameters
.non_interactive_ui_to_s_key_switch_decomposition_count()
.0;
let total_users = *value.ui_to_s_ksks_key_order.iter().max().unwrap();
let ui_to_s_ksks = (0..total_users)
.map(|user_index| {
let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_index);
let mut prng = Rng::new_with_seed(user_i_seed);
let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
RandomFillUniformInModulus::random_fill(
&mut prng,
value.parameters.rlwe_q(),
r.as_mut(),
);
});
let incoming_ksk_partb_ref =
&value.ui_to_s_ksks[value.ui_to_s_ksks_key_order[user_index]];
assert!(ksk_ct.dimension() == (d_uitos, ring_size));
izip!(
ksk_ct.iter_rows_mut().skip(d_uitos),
incoming_ksk_partb_ref.iter_rows()
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
});
ksk_ct
.iter_rows_mut()
.for_each(|r| rlwe_nttop.forward(r.as_mut()));
ksk_ct
})
.collect_vec();
NonInteractiveServerKeyEvaluationDomain {
rgsw_cts,
auto_keys,
lwe_ksk,
ui_to_s_ksks,
parameters: value.parameters.clone(),
_phanton: PhantomData,
}
}
}
}
pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
/// u_i to s key switching keys in random order
ui_to_s_ksks: Vec<M>,
/// Defines order for u_i to s key switchin keys by storing the index of
/// user j's ksk in `ui_to_s_ksks` at index `j`. Find user j's u_i to s ksk
/// at `ui_to_s_ksks[ui_to_s_ksks_key_order[j]]`
ui_to_s_ksks_key_order: Vec<usize>,
/// RGSW ciphertets
rgsw_cts: Vec<M>,
auto_keys: HashMap<usize, M>,
lwe_ksk: M::R,
cr_seed: S,
parameters: P,
}
impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
pub(super) fn new(
ui_to_s_ksks: Vec<M>,
ui_to_s_ksks_key_order: Vec<usize>,
rgsw_cts: Vec<M>,
auto_keys: HashMap<usize, M>,
lwe_ksk: M::R,
cr_seed: S,
parameters: P,
) -> Self {
Self {
ui_to_s_ksks,
ui_to_s_ksks_key_order,
rgsw_cts,
auto_keys,
lwe_ksk,
cr_seed,
parameters,
}
}
}
/// Server key in evaluation domain with Shoup representations
pub(crate) struct ShoupServerKeyEvaluationDomain<M> { pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
/// Rgsw cts of LWE secret elements /// Rgsw cts of LWE secret elements
rgsw_cts: Vec<NormalAndShoup<M>>, rgsw_cts: Vec<NormalAndShoup<M>>,

View File

@@ -1,8 +1,12 @@
pub(crate) mod evaluator; pub(crate) mod evaluator;
pub(crate) mod keys; pub(crate) mod keys;
pub mod noise; mod mp_api;
mod ni_mp_api;
mod noise;
pub(crate) mod parameters; pub(crate) mod parameters;
pub use mp_api::*;
pub type FheBool = Vec<u64>; pub type FheBool = Vec<u64>;
use std::{cell::RefCell, sync::OnceLock}; use std::{cell::RefCell, sync::OnceLock};
@@ -10,171 +14,3 @@ use std::{cell::RefCell, sync::OnceLock};
use evaluator::*; use evaluator::*;
use keys::*; use keys::*;
use parameters::*; use parameters::*;
use crate::{
backend::{ModularOpsU64, ModulusPowerOf2},
ntt::NttBackendU64,
random::{DefaultSecureRng, NewWithSeed},
utils::{Global, WithLocal},
};
thread_local! {
static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModulusPowerOf2<CiphertextModulus<u64>>, ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>>> = RefCell::new(None);
}
static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>> = OnceLock::new();
static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new();
pub enum ParameterSelector {
MultiPartyLessThanOrEqualTo16,
}
pub fn set_parameter_set(select: ParameterSelector) {
match select {
ParameterSelector::MultiPartyLessThanOrEqualTo16 => {
BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(SMALL_MP_BOOL_PARAMS)));
}
}
}
pub fn set_mp_seed(seed: [u8; 32]) {
assert!(
MULTI_PARTY_CRS.set(MultiPartyCrs { seed: seed }).is_ok(),
"Attempted to set MP SEED twice."
)
}
fn set_server_key(key: ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>) {
assert!(
BOOL_SERVER_KEY.set(key).is_ok(),
"Attempted to set server key twice."
);
}
pub(crate) fn gen_keys() -> (
ClientKey,
SeededServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]>,
) {
BoolEvaluator::with_local_mut(|e| {
let ck = e.client_key();
let sk = e.single_party_server_key(&ck);
(ck, sk)
})
}
pub fn gen_client_key() -> ClientKey {
BoolEvaluator::with_local(|e| e.client_key())
}
pub fn gen_mp_keys_phase1(
ck: &ClientKey,
) -> CommonReferenceSeededCollectivePublicKeyShare<Vec<u64>, [u8; 32], BoolParameters<u64>> {
let seed = MultiPartyCrs::global().public_key_share_seed::<DefaultSecureRng>();
BoolEvaluator::with_local(|e| {
let pk_share = e.multi_party_public_key_share(seed, &ck);
pk_share
})
}
pub fn gen_mp_keys_phase2<R, ModOp>(
ck: &ClientKey,
pk: &PublicKey<Vec<Vec<u64>>, R, ModOp>,
) -> CommonReferenceSeededMultiPartyServerKeyShare<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]> {
let seed = MultiPartyCrs::global().server_key_share_seed::<DefaultSecureRng>();
BoolEvaluator::with_local_mut(|e| {
let server_key_share = e.multi_party_server_key_share(seed, pk.key(), ck);
server_key_share
})
}
pub fn aggregate_public_key_shares(
shares: &[CommonReferenceSeededCollectivePublicKeyShare<
Vec<u64>,
[u8; 32],
BoolParameters<u64>,
>],
) -> PublicKey<Vec<Vec<u64>>, DefaultSecureRng, ModularOpsU64<CiphertextModulus<u64>>> {
PublicKey::from(shares)
}
pub fn aggregate_server_key_shares(
shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
Vec<Vec<u64>>,
BoolParameters<u64>,
[u8; 32],
>],
) -> SeededMultiPartyServerKey<Vec<Vec<u64>>, [u8; 32], BoolParameters<u64>> {
BoolEvaluator::with_local(|e| e.aggregate_multi_party_server_key_shares(shares))
}
// SERVER KEY EVAL (/SHOUP) DOMAIN //
impl SeededServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]> {
pub fn set_server_key(&self) {
let eval = ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(self);
set_server_key(ShoupServerKeyEvaluationDomain::from(eval));
}
}
impl
SeededMultiPartyServerKey<
Vec<Vec<u64>>,
<DefaultSecureRng as NewWithSeed>::Seed,
BoolParameters<u64>,
>
{
pub fn set_server_key(&self) {
set_server_key(ShoupServerKeyEvaluationDomain::from(
ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(self),
))
}
}
// MULTIPARTY CRS //
impl Global for MultiPartyCrs<[u8; 32]> {
fn global() -> &'static Self {
MULTI_PARTY_CRS
.get()
.expect("Multi Party Common Reference String not set")
}
}
// BOOL EVALUATOR //
impl WithLocal
for BoolEvaluator<
Vec<Vec<u64>>,
NttBackendU64,
ModularOpsU64<CiphertextModulus<u64>>,
ModulusPowerOf2<CiphertextModulus<u64>>,
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
>
{
fn with_local<F, R>(func: F) -> R
where
F: Fn(&Self) -> R,
{
BOOL_EVALUATOR.with_borrow(|s| func(s.as_ref().expect("Parameters not set")))
}
fn with_local_mut<F, R>(func: F) -> R
where
F: Fn(&mut Self) -> R,
{
BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
}
fn with_local_mut_mut<F, R>(func: &mut F) -> R
where
F: FnMut(&mut Self) -> R,
{
BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
}
}
pub(crate) type RuntimeServerKey = ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>;
impl Global for RuntimeServerKey {
fn global() -> &'static Self {
BOOL_SERVER_KEY.get().expect("Server key not set!")
}
}

169
src/bool/mp_api.rs Normal file
View File

@@ -0,0 +1,169 @@
use crate::{
backend::{ModularOpsU64, ModulusPowerOf2},
ntt::NttBackendU64,
random::{DefaultSecureRng, NewWithSeed},
utils::{Global, WithLocal},
};
use super::*;
thread_local! {
static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModulusPowerOf2<CiphertextModulus<u64>>, ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>>> = RefCell::new(None);
}
static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>> = OnceLock::new();
static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new();
pub enum ParameterSelector {
MultiPartyLessThanOrEqualTo16,
}
pub fn set_parameter_set(select: ParameterSelector) {
match select {
ParameterSelector::MultiPartyLessThanOrEqualTo16 => {
BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(SMALL_MP_BOOL_PARAMS)));
}
}
}
pub fn set_mp_seed(seed: [u8; 32]) {
assert!(
MULTI_PARTY_CRS.set(MultiPartyCrs { seed: seed }).is_ok(),
"Attempted to set MP SEED twice."
)
}
fn set_server_key(key: ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>) {
assert!(
BOOL_SERVER_KEY.set(key).is_ok(),
"Attempted to set server key twice."
);
}
pub(crate) fn gen_keys() -> (
ClientKey,
SeededSinglePartyServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]>,
) {
BoolEvaluator::with_local_mut(|e| {
let ck = e.client_key();
let sk = e.single_party_server_key(&ck);
(ck, sk)
})
}
pub fn gen_client_key() -> ClientKey {
BoolEvaluator::with_local(|e| e.client_key())
}
pub fn gen_mp_keys_phase1(
ck: &ClientKey,
) -> CommonReferenceSeededCollectivePublicKeyShare<Vec<u64>, [u8; 32], BoolParameters<u64>> {
let seed = MultiPartyCrs::global().public_key_share_seed::<DefaultSecureRng>();
BoolEvaluator::with_local(|e| {
let pk_share = e.multi_party_public_key_share(seed, &ck);
pk_share
})
}
pub fn gen_mp_keys_phase2<R, ModOp>(
ck: &ClientKey,
pk: &PublicKey<Vec<Vec<u64>>, R, ModOp>,
) -> CommonReferenceSeededMultiPartyServerKeyShare<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]> {
let seed = MultiPartyCrs::global().server_key_share_seed::<DefaultSecureRng>();
BoolEvaluator::with_local_mut(|e| {
let server_key_share = e.multi_party_server_key_share(seed, pk.key(), ck);
server_key_share
})
}
pub fn aggregate_public_key_shares(
shares: &[CommonReferenceSeededCollectivePublicKeyShare<
Vec<u64>,
[u8; 32],
BoolParameters<u64>,
>],
) -> PublicKey<Vec<Vec<u64>>, DefaultSecureRng, ModularOpsU64<CiphertextModulus<u64>>> {
PublicKey::from(shares)
}
pub fn aggregate_server_key_shares(
shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
Vec<Vec<u64>>,
BoolParameters<u64>,
[u8; 32],
>],
) -> SeededMultiPartyServerKey<Vec<Vec<u64>>, [u8; 32], BoolParameters<u64>> {
BoolEvaluator::with_local(|e| e.aggregate_multi_party_server_key_shares(shares))
}
// SERVER KEY EVAL (/SHOUP) DOMAIN //
impl SeededSinglePartyServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]> {
pub fn set_server_key(&self) {
let eval = ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(self);
set_server_key(ShoupServerKeyEvaluationDomain::from(eval));
}
}
impl
SeededMultiPartyServerKey<
Vec<Vec<u64>>,
<DefaultSecureRng as NewWithSeed>::Seed,
BoolParameters<u64>,
>
{
pub fn set_server_key(&self) {
set_server_key(ShoupServerKeyEvaluationDomain::from(
ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(self),
))
}
}
// MULTIPARTY CRS //
impl Global for MultiPartyCrs<[u8; 32]> {
fn global() -> &'static Self {
MULTI_PARTY_CRS
.get()
.expect("Multi Party Common Reference String not set")
}
}
// BOOL EVALUATOR //
impl WithLocal
for BoolEvaluator<
Vec<Vec<u64>>,
NttBackendU64,
ModularOpsU64<CiphertextModulus<u64>>,
ModulusPowerOf2<CiphertextModulus<u64>>,
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
>
{
fn with_local<F, R>(func: F) -> R
where
F: Fn(&Self) -> R,
{
BOOL_EVALUATOR.with_borrow(|s| func(s.as_ref().expect("Parameters not set")))
}
fn with_local_mut<F, R>(func: F) -> R
where
F: Fn(&mut Self) -> R,
{
BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
}
fn with_local_mut_mut<F, R>(func: &mut F) -> R
where
F: FnMut(&mut Self) -> R,
{
BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
}
}
pub(crate) type RuntimeServerKey = ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>;
impl Global for RuntimeServerKey {
fn global() -> &'static Self {
BOOL_SERVER_KEY.get().expect("Server key not set!")
}
}

0
src/bool/ni_mp_api.rs Normal file
View File

View File

@@ -4,9 +4,9 @@ mod test {
use crate::{ use crate::{
backend::{ArithmeticOps, ModularOpsU64, Modulus, ModulusPowerOf2}, backend::{ArithmeticOps, ModularOpsU64, Modulus, ModulusPowerOf2},
bool::{ bool::{
set_parameter_set, BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus, BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus, ClientKey, PublicKey,
ClientKey, PublicKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, MP_BOOL_PARAMS,
MP_BOOL_PARAMS, SMALL_MP_BOOL_PARAMS, SMALL_MP_BOOL_PARAMS,
}, },
lwe::{decrypt_lwe, LweSecret}, lwe::{decrypt_lwe, LweSecret},
ntt::NttBackendU64, ntt::NttBackendU64,