mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-11 16:41:29 +01:00
non interactive mp works
This commit is contained in:
@@ -20,6 +20,7 @@ use crate::{
|
||||
backend::{
|
||||
ArithmeticOps, GetModulus, ModInit, ModularOpsU64, 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},
|
||||
multi_party::{
|
||||
@@ -48,10 +49,12 @@ use crate::{
|
||||
use super::{
|
||||
keys::{
|
||||
ClientKey, CommonReferenceSeededCollectivePublicKeyShare,
|
||||
CommonReferenceSeededMultiPartyServerKeyShare, InteractiveMultiPartyClientKey,
|
||||
NonInteractiveMultiPartyClientKey, SeededMultiPartyServerKey,
|
||||
SeededNonInteractiveMultiPartyServerKey, SeededSinglePartyServerKey,
|
||||
ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, SinglePartyClientKey,
|
||||
CommonReferenceSeededMultiPartyServerKeyShare,
|
||||
CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare,
|
||||
InteractiveMultiPartyClientKey, NonInteractiveMultiPartyClientKey,
|
||||
SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey,
|
||||
SeededSinglePartyServerKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain,
|
||||
SinglePartyClientKey,
|
||||
},
|
||||
parameters::{
|
||||
BoolParameters, CiphertextModulus, DecompositionCount, DecompostionLogBase,
|
||||
@@ -59,30 +62,6 @@ use super::{
|
||||
},
|
||||
};
|
||||
|
||||
pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
|
||||
/// (ak*si + e + \beta ui, ak*si + e)
|
||||
ni_rgsw_cts: (Vec<M>, Vec<M>),
|
||||
ui_to_s_ksk: M,
|
||||
others_ksk_zero_encs: Vec<M>,
|
||||
|
||||
auto_keys_share: HashMap<usize, M>,
|
||||
lwe_ksk_share: M::R,
|
||||
|
||||
user_index: usize,
|
||||
cr_seed: S,
|
||||
}
|
||||
|
||||
impl<M: Matrix, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, S> {
|
||||
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 {
|
||||
&self.others_ksk_zero_encs[user_i]
|
||||
} else {
|
||||
&self.others_ksk_zero_encs[user_i - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiPartyCrs<S> {
|
||||
pub(super) seed: S,
|
||||
}
|
||||
@@ -405,19 +384,25 @@ where
|
||||
nor_test_vec: M::R,
|
||||
xor_test_vec: M::R,
|
||||
xnor_test_vec: M::R,
|
||||
/// Non-interactive u_i -> s key switch decomposer
|
||||
ni_ui_to_s_ks_decomposer: Option<DefaultDecomposer<M::MatElement>>,
|
||||
_phantom: PhantomData<SKey>,
|
||||
}
|
||||
|
||||
impl<M: Matrix, NttOp, RlweModOp, LweModOp, Skey>
|
||||
BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
|
||||
{
|
||||
pub(super) fn parameters(&self) -> &BoolParameters<M::MatElement> {
|
||||
pub(crate) fn parameters(&self) -> &BoolParameters<M::MatElement> {
|
||||
&self.pbs_info.parameters
|
||||
}
|
||||
|
||||
pub(super) fn pbs_info(&self) -> &BoolPbsInfo<M, NttOp, RlweModOp, LweModOp> {
|
||||
&self.pbs_info
|
||||
}
|
||||
|
||||
pub(super) fn ni_ui_to_s_ks_decomposer(&self) -> &Option<DefaultDecomposer<M::MatElement>> {
|
||||
&self.ni_ui_to_s_ks_decomposer
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_rgsw_ct_matrix_from_rgrg_to_rlrg<
|
||||
@@ -628,6 +613,15 @@ where
|
||||
|
||||
let scratch_memory = ScratchMemory::new(¶meters);
|
||||
|
||||
let ni_ui_to_s_ks_decomposer = if parameters.variant()
|
||||
== &ParameterVariant::NonInteractiveMultiParty
|
||||
{
|
||||
Some(parameters
|
||||
.non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pbs_info = BoolPbsInfo {
|
||||
auto_decomposer: parameters.auto_decomposer(),
|
||||
lwe_decomposer: parameters.lwe_decomposer(),
|
||||
@@ -651,6 +645,7 @@ where
|
||||
nor_test_vec,
|
||||
xnor_test_vec,
|
||||
xor_test_vec,
|
||||
ni_ui_to_s_ks_decomposer,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -665,6 +660,8 @@ where
|
||||
&self,
|
||||
client_key: &K,
|
||||
) -> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> {
|
||||
assert_eq!(self.parameters().variant(), &ParameterVariant::SingleParty);
|
||||
|
||||
DefaultSecureRng::with_local_mut(|rng| {
|
||||
let mut main_seed = [0u8; 32];
|
||||
rng.fill_bytes(&mut main_seed);
|
||||
@@ -773,6 +770,8 @@ where
|
||||
client_key: &K,
|
||||
) -> CommonReferenceSeededMultiPartyServerKeyShare<M, BoolParameters<M::MatElement>, [u8; 32]>
|
||||
{
|
||||
assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
|
||||
|
||||
DefaultSecureRng::with_local_mut(|rng| {
|
||||
let mut main_prng = DefaultSecureRng::new_seeded(cr_seed);
|
||||
|
||||
@@ -908,9 +907,14 @@ where
|
||||
where
|
||||
M: Clone + Debug,
|
||||
{
|
||||
assert_eq!(
|
||||
self.parameters().variant(),
|
||||
&ParameterVariant::NonInteractiveMultiParty
|
||||
);
|
||||
|
||||
// sanity checks
|
||||
let key_order = {
|
||||
let existing_key_order = key_shares.iter().map(|s| s.user_index).collect_vec();
|
||||
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
|
||||
@@ -940,15 +944,15 @@ where
|
||||
let mut ui_to_s_ksks = key_shares
|
||||
.iter()
|
||||
.map(|share| {
|
||||
let mut useri_ui_to_s_ksk = share.ui_to_s_ksk.clone();
|
||||
let mut useri_ui_to_s_ksk = share.ui_to_s_ksk().clone();
|
||||
assert!(
|
||||
useri_ui_to_s_ksk.dimension() == (ui_to_s_ksk_decomposition_count.0, ring_size)
|
||||
);
|
||||
key_shares
|
||||
.iter()
|
||||
.filter(|x| x.user_index != share.user_index)
|
||||
.filter(|x| x.user_index() != share.user_index())
|
||||
.for_each(|(other_share)| {
|
||||
let op2 = other_share.ui_to_s_ksk_zero_encs_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));
|
||||
izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each(
|
||||
|(add_to, add_from)| {
|
||||
@@ -982,7 +986,7 @@ where
|
||||
.map(|share| {
|
||||
let mut ksk_prng = DefaultSecureRng::new_seeded(
|
||||
cr_seed
|
||||
.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index),
|
||||
.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);
|
||||
|
||||
@@ -1036,7 +1040,7 @@ where
|
||||
key_shares.iter().for_each(|s| {
|
||||
rlwe_modop.elwise_add_mut(
|
||||
tmp_space.as_mut(),
|
||||
s.ni_rgsw_cts.1[lwe_index].get_row_slice(d_index),
|
||||
s.ni_rgsw_cts().1[lwe_index].get_row_slice(d_index),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1130,7 +1134,7 @@ where
|
||||
|(share, user_uitos_ksk_partb_eval, user_uitos_ksk_parta_eval)| {
|
||||
// RGSW_s(X^{s[i]})
|
||||
let rgsw_cts_user_i_eval = izip!(
|
||||
share.ni_rgsw_cts.0.iter(),
|
||||
share.ni_rgsw_cts().0.iter(),
|
||||
decomp_ni_rgsw_neg_ais.iter(),
|
||||
decomp_ni_rgsws_part_1_acc.iter()
|
||||
)
|
||||
@@ -1370,7 +1374,8 @@ where
|
||||
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");
|
||||
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)
|
||||
@@ -1393,10 +1398,10 @@ where
|
||||
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()
|
||||
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_modop.elwise_add_mut(lwe_ksk.as_mut(), s.lwe_ksk_share().as_ref());
|
||||
});
|
||||
lwe_ksk
|
||||
};
|
||||
@@ -1425,6 +1430,11 @@ where
|
||||
M,
|
||||
NonInteractiveMultiPartyCrs<[u8; 32]>,
|
||||
> {
|
||||
assert_eq!(
|
||||
self.parameters().variant(),
|
||||
&ParameterVariant::NonInteractiveMultiParty
|
||||
);
|
||||
|
||||
// TODO: check whether parameters support `total_users`
|
||||
let nttop = self.pbs_info().nttop_rlweq();
|
||||
let rlwe_modop = self.pbs_info().modop_rlweq();
|
||||
@@ -1539,15 +1549,15 @@ where
|
||||
self._common_rountine_multi_party_lwe_ksk_share_gen(lwe_ksk_seed, &sk_rlwe, &sk_lwe)
|
||||
};
|
||||
|
||||
CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare {
|
||||
CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare::new(
|
||||
ni_rgsw_cts,
|
||||
ui_to_s_ksk,
|
||||
others_ksk_zero_encs: zero_encs_for_others,
|
||||
user_index: self_index,
|
||||
zero_encs_for_others,
|
||||
auto_keys_share,
|
||||
lwe_ksk_share,
|
||||
cr_seed: cr_seed.clone(),
|
||||
}
|
||||
self_index,
|
||||
cr_seed.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn _common_rountine_multi_party_auto_keys_share_gen(
|
||||
@@ -1826,6 +1836,7 @@ where
|
||||
S: PartialEq + Clone,
|
||||
M: Clone,
|
||||
{
|
||||
assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
|
||||
assert!(shares.len() > 0);
|
||||
let parameters = shares[0].parameters().clone();
|
||||
let cr_seed = shares[0].cr_seed();
|
||||
@@ -3174,7 +3185,7 @@ mod tests {
|
||||
);
|
||||
let server_key_evaluation_domain =
|
||||
NonInteractiveServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(
|
||||
seeded_server_key,
|
||||
&seeded_server_key,
|
||||
);
|
||||
|
||||
let mut ideal_rlwe = vec![0; ring_size];
|
||||
|
||||
121
src/bool/keys.rs
121
src/bool/keys.rs
@@ -752,7 +752,7 @@ pub(super) mod impl_non_interactive_server_key_eval_domain {
|
||||
|
||||
impl<M, Rng, N>
|
||||
From<
|
||||
SeededNonInteractiveMultiPartyServerKey<
|
||||
&SeededNonInteractiveMultiPartyServerKey<
|
||||
M,
|
||||
NonInteractiveMultiPartyCrs<Rng::Seed>,
|
||||
BoolParameters<M::MatElement>,
|
||||
@@ -769,7 +769,7 @@ pub(super) mod impl_non_interactive_server_key_eval_domain {
|
||||
Rng::Seed: Clone + Copy + Default,
|
||||
{
|
||||
fn from(
|
||||
value: SeededNonInteractiveMultiPartyServerKey<
|
||||
value: &SeededNonInteractiveMultiPartyServerKey<
|
||||
M,
|
||||
NonInteractiveMultiPartyCrs<Rng::Seed>,
|
||||
BoolParameters<M::MatElement>,
|
||||
@@ -802,7 +802,7 @@ pub(super) mod impl_non_interactive_server_key_eval_domain {
|
||||
|
||||
assert!(auto_part_b.dimension() == (d_auto, ring_size));
|
||||
|
||||
let mut auto_ct = M::zeros(d_auto, ring_size);
|
||||
let mut auto_ct = M::zeros(d_auto * 2, ring_size);
|
||||
|
||||
// sample part A
|
||||
auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
|
||||
@@ -862,7 +862,7 @@ pub(super) mod impl_non_interactive_server_key_eval_domain {
|
||||
.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)
|
||||
let ui_to_s_ksks = (0..total_users + 1)
|
||||
.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);
|
||||
@@ -963,6 +963,12 @@ mod impl_shoup_non_interactive_server_key_eval_domain {
|
||||
use super::*;
|
||||
use crate::{backend::Modulus, pbs::PbsKey};
|
||||
|
||||
impl<M> ShoupNonInteractiveServerKeyEvaluationDomain<M> {
|
||||
pub(in super::super) fn ui_to_s_ksk(&self, user_id: usize) -> &NormalAndShoup<M> {
|
||||
&self.ui_to_s_ksks[user_id]
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
|
||||
From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
|
||||
for ShoupNonInteractiveServerKeyEvaluationDomain<M>
|
||||
@@ -974,23 +980,55 @@ mod impl_shoup_non_interactive_server_key_eval_domain {
|
||||
) -> Self {
|
||||
let rlwe_q = value.parameters.rlwe_q().q().unwrap();
|
||||
|
||||
let rgsw_dim = (
|
||||
value.parameters.rlwe_rgsw_decomposition_count().0 .0 * 2
|
||||
+ value.parameters.rlwe_rgsw_decomposition_count().1 .0 * 2,
|
||||
value.parameters.rlwe_n().0,
|
||||
);
|
||||
let rgsw_cts = value
|
||||
.rgsw_cts
|
||||
.into_iter()
|
||||
.map(|m| NormalAndShoup::new_with_modulus(m, rlwe_q))
|
||||
.map(|m| {
|
||||
assert!(m.dimension() == rgsw_dim);
|
||||
NormalAndShoup::new_with_modulus(m, rlwe_q)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
let auto_dim = (
|
||||
value.parameters.auto_decomposition_count().0 * 2,
|
||||
value.parameters.rlwe_n().0,
|
||||
);
|
||||
let mut auto_keys = HashMap::new();
|
||||
value.auto_keys.into_iter().for_each(|(k, v)| {
|
||||
assert!(v.dimension() == auto_dim);
|
||||
auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
|
||||
});
|
||||
|
||||
let ui_ks_dim = (
|
||||
value
|
||||
.parameters
|
||||
.non_interactive_ui_to_s_key_switch_decomposition_count()
|
||||
.0
|
||||
* 2,
|
||||
value.parameters.rlwe_n().0,
|
||||
);
|
||||
let ui_to_s_ksks = value
|
||||
.ui_to_s_ksks
|
||||
.into_iter()
|
||||
.map(|m| NormalAndShoup::new_with_modulus(m, rlwe_q))
|
||||
.map(|m| {
|
||||
assert!(m.dimension() == ui_ks_dim);
|
||||
NormalAndShoup::new_with_modulus(m, rlwe_q)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
assert!(
|
||||
value.lwe_ksk.dimension()
|
||||
== (
|
||||
value.parameters.rlwe_n().0 * value.parameters.lwe_decomposition_count().0,
|
||||
value.parameters.lwe_n().0 + 1
|
||||
)
|
||||
);
|
||||
|
||||
Self {
|
||||
rgsw_cts,
|
||||
auto_keys,
|
||||
@@ -1006,7 +1044,8 @@ mod impl_shoup_non_interactive_server_key_eval_domain {
|
||||
type RgswCt = NormalAndShoup<M>;
|
||||
|
||||
fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
|
||||
self.auto_keys.get(&k).unwrap()
|
||||
let d = self.auto_keys.get(&k).unwrap();
|
||||
d
|
||||
}
|
||||
fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
|
||||
&self.rgsw_cts[si]
|
||||
@@ -1084,6 +1123,74 @@ mod shoup_server_key_eval_domain {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
|
||||
/// (ak*si + e + \beta ui, ak*si + e)
|
||||
ni_rgsw_cts: (Vec<M>, Vec<M>),
|
||||
ui_to_s_ksk: M,
|
||||
others_ksk_zero_encs: Vec<M>,
|
||||
|
||||
auto_keys_share: HashMap<usize, M>,
|
||||
lwe_ksk_share: M::R,
|
||||
|
||||
user_index: usize,
|
||||
cr_seed: S,
|
||||
}
|
||||
|
||||
mod impl_common_ref_non_interactive_multi_party_server_share {
|
||||
use super::*;
|
||||
|
||||
impl<M: Matrix, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, S> {
|
||||
pub(in super::super) fn new(
|
||||
ni_rgsw_cts: (Vec<M>, Vec<M>),
|
||||
ui_to_s_ksk: M,
|
||||
others_ksk_zero_encs: Vec<M>,
|
||||
auto_keys_share: HashMap<usize, M>,
|
||||
lwe_ksk_share: M::R,
|
||||
user_index: usize,
|
||||
cr_seed: S,
|
||||
) -> Self {
|
||||
Self {
|
||||
ni_rgsw_cts,
|
||||
ui_to_s_ksk,
|
||||
others_ksk_zero_encs,
|
||||
auto_keys_share,
|
||||
lwe_ksk_share,
|
||||
user_index,
|
||||
cr_seed,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in super::super) fn ni_rgsw_cts(&self) -> &(Vec<M>, Vec<M>) {
|
||||
&self.ni_rgsw_cts
|
||||
}
|
||||
|
||||
pub(in super::super) fn ui_to_s_ksk(&self) -> &M {
|
||||
&self.ui_to_s_ksk
|
||||
}
|
||||
|
||||
pub(in super::super) fn user_index(&self) -> usize {
|
||||
self.user_index
|
||||
}
|
||||
|
||||
pub(in super::super) fn auto_keys_share(&self) -> &HashMap<usize, M> {
|
||||
&self.auto_keys_share
|
||||
}
|
||||
|
||||
pub(in super::super) fn lwe_ksk_share(&self) -> &M::R {
|
||||
&self.lwe_ksk_share
|
||||
}
|
||||
|
||||
pub(in super::super) 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 {
|
||||
&self.others_ksk_zero_encs[user_i]
|
||||
} else {
|
||||
&self.others_ksk_zero_encs[user_i - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
|
||||
pub(crate) struct NormalAndShoup<M>(M, M);
|
||||
|
||||
|
||||
@@ -4,9 +4,14 @@ mod mp_api;
|
||||
mod ni_mp_api;
|
||||
mod noise;
|
||||
pub(crate) mod parameters;
|
||||
mod sp_api;
|
||||
|
||||
pub(crate) use keys::PublicKey;
|
||||
|
||||
pub type FheBool = Vec<u64>;
|
||||
pub use ni_mp_api::*;
|
||||
pub type ClientKey = keys::ClientKey<[u8; 32], u64>;
|
||||
|
||||
pub use mp_api::*;
|
||||
pub enum ParameterSelector {
|
||||
MultiPartyLessThanOrEqualTo16,
|
||||
NonInteractiveMultiPartyLessThanOrEqualTo16,
|
||||
}
|
||||
|
||||
@@ -7,27 +7,32 @@ use crate::{
|
||||
utils::{Global, WithLocal},
|
||||
};
|
||||
|
||||
use super::{evaluator::*, keys::*, parameters::*};
|
||||
use super::{evaluator::MultiPartyCrs, keys::*, parameters::*, ClientKey, ParameterSelector};
|
||||
|
||||
pub type BoolEvaluator = super::evaluator::BoolEvaluator<
|
||||
Vec<Vec<u64>>,
|
||||
NttBackendU64,
|
||||
ModularOpsU64<CiphertextModulus<u64>>,
|
||||
ModulusPowerOf2<CiphertextModulus<u64>>,
|
||||
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
||||
>;
|
||||
|
||||
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_EVALUATOR: RefCell<Option<BoolEvaluator>> = 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 type ClientKey = super::keys::ClientKey<[u8; 32], u64>;
|
||||
|
||||
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)));
|
||||
}
|
||||
_ => {
|
||||
panic!("Paramerters not supported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,15 +139,7 @@ impl Global for MultiPartyCrs<[u8; 32]> {
|
||||
}
|
||||
|
||||
// BOOL EVALUATOR //
|
||||
impl WithLocal
|
||||
for BoolEvaluator<
|
||||
Vec<Vec<u64>>,
|
||||
NttBackendU64,
|
||||
ModularOpsU64<CiphertextModulus<u64>>,
|
||||
ModulusPowerOf2<CiphertextModulus<u64>>,
|
||||
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
||||
>
|
||||
{
|
||||
impl WithLocal for BoolEvaluator {
|
||||
fn with_local<F, R>(func: F) -> R
|
||||
where
|
||||
F: Fn(&Self) -> R,
|
||||
@@ -174,74 +171,61 @@ impl Global for RuntimeServerKey {
|
||||
|
||||
mod impl_enc_dec {
|
||||
use crate::{
|
||||
bool::evaluator::BoolEncoding,
|
||||
pbs::{sample_extract, PbsInfo},
|
||||
rgsw::public_key_encrypt_rlwe,
|
||||
Decryptor, Encryptor, Matrix, MatrixEntity, MultiPartyDecryptor, RowEntity,
|
||||
Encryptor, Matrix, MatrixEntity, MultiPartyDecryptor, RowEntity,
|
||||
};
|
||||
use num_traits::Zero;
|
||||
use itertools::Itertools;
|
||||
use num_traits::{ToPrimitive, Zero};
|
||||
|
||||
use super::*;
|
||||
|
||||
type Mat = Vec<Vec<u64>>;
|
||||
|
||||
impl<E> Encryptor<bool, Vec<u64>> for super::super::keys::ClientKey<[u8; 32], E> {
|
||||
fn encrypt(&self, m: &bool) -> Vec<u64> {
|
||||
BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Decryptor<bool, Vec<u64>> for super::super::keys::ClientKey<[u8; 32], E> {
|
||||
fn decrypt(&self, c: &Vec<u64>) -> bool {
|
||||
BoolEvaluator::with_local(|e| e.sk_decrypt(c, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> MultiPartyDecryptor<bool, <Mat as Matrix>::R>
|
||||
for super::super::keys::ClientKey<[u8; 32], E>
|
||||
{
|
||||
type DecryptionShare = <Mat as Matrix>::MatElement;
|
||||
|
||||
fn gen_decryption_share(&self, c: &<Mat as Matrix>::R) -> Self::DecryptionShare {
|
||||
BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, self))
|
||||
}
|
||||
|
||||
fn aggregate_decryption_shares(
|
||||
&self,
|
||||
c: &<Mat as Matrix>::R,
|
||||
shares: &[Self::DecryptionShare],
|
||||
) -> bool {
|
||||
BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rng, ModOp> Encryptor<[bool], Mat> for PublicKey<Mat, Rng, ModOp> {
|
||||
fn encrypt(&self, m: &[bool]) -> Mat {
|
||||
impl<Rng, ModOp> Encryptor<[bool], Vec<Mat>> for PublicKey<Mat, Rng, ModOp> {
|
||||
fn encrypt(&self, m: &[bool]) -> Vec<Mat> {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
DefaultSecureRng::with_local_mut(|rng| {
|
||||
let parameters = e.parameters();
|
||||
let mut rlwe_out = <Mat as MatrixEntity>::zeros(2, parameters.rlwe_n().0);
|
||||
assert!(m.len() <= parameters.rlwe_n().0);
|
||||
let ring_size = parameters.rlwe_n().0;
|
||||
|
||||
let mut message =
|
||||
vec![<Mat as Matrix>::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()
|
||||
}
|
||||
});
|
||||
let rlwe_count = ((m.len() as f64 / ring_size as f64).ceil())
|
||||
.to_usize()
|
||||
.unwrap();
|
||||
|
||||
// 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
|
||||
// encrypt `m` into ceil(len(m)/N) RLWE ciphertexts
|
||||
let rlwes = (0..rlwe_count)
|
||||
.map(|index| {
|
||||
let mut message = vec![<Mat as Matrix>::MatElement::zero(); ring_size];
|
||||
m[(index * ring_size)..std::cmp::min(m.len(), (index + 1) * ring_size)]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| {
|
||||
if *v {
|
||||
message[i] = parameters.rlwe_q().true_el()
|
||||
} else {
|
||||
message[i] = parameters.rlwe_q().false_el()
|
||||
}
|
||||
});
|
||||
|
||||
// encrypt message
|
||||
let mut rlwe_out =
|
||||
<Mat as MatrixEntity>::zeros(2, parameters.rlwe_n().0);
|
||||
|
||||
public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
|
||||
&mut rlwe_out,
|
||||
self.key(),
|
||||
&message,
|
||||
e.pbs_info().modop_rlweq(),
|
||||
e.pbs_info().nttop_rlweq(),
|
||||
rng,
|
||||
);
|
||||
|
||||
rlwe_out
|
||||
})
|
||||
.collect_vec();
|
||||
rlwes
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -250,10 +234,10 @@ mod impl_enc_dec {
|
||||
impl<Rng, ModOp> Encryptor<bool, <Mat as Matrix>::R> for PublicKey<Mat, Rng, ModOp> {
|
||||
fn encrypt(&self, m: &bool) -> <Mat as Matrix>::R {
|
||||
let m = vec![*m];
|
||||
let rlwe = self.encrypt(m.as_slice());
|
||||
let rlwe = &self.encrypt(m.as_slice())[0];
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let mut lwe = <Mat as Matrix>::R::zeros(e.parameters().rlwe_n().0 + 1);
|
||||
sample_extract(&mut lwe, &rlwe, e.pbs_info().modop_rlweq(), 0);
|
||||
sample_extract(&mut lwe, rlwe, e.pbs_info().modop_rlweq(), 0);
|
||||
lwe
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,66 +1,544 @@
|
||||
use std::{cell::RefCell, sync::OnceLock};
|
||||
|
||||
use crate::{
|
||||
backend::ModulusPowerOf2,
|
||||
bool::parameters::ParameterVariant,
|
||||
random::DefaultSecureRng,
|
||||
utils::{Global, WithLocal},
|
||||
ModularOpsU64, NttBackendU64,
|
||||
};
|
||||
|
||||
use super::{
|
||||
evaluator::NonInteractiveMultiPartyCrs,
|
||||
keys::{
|
||||
CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare,
|
||||
NonInteractiveServerKeyEvaluationDomain, SeededNonInteractiveMultiPartyServerKey,
|
||||
ShoupNonInteractiveServerKeyEvaluationDomain,
|
||||
},
|
||||
parameters::{BoolParameters, CiphertextModulus, NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS},
|
||||
ClientKey, ParameterSelector,
|
||||
};
|
||||
|
||||
pub type BoolEvaluator = super::evaluator::BoolEvaluator<
|
||||
Vec<Vec<u64>>,
|
||||
NttBackendU64,
|
||||
ModularOpsU64<CiphertextModulus<u64>>,
|
||||
ModulusPowerOf2<CiphertextModulus<u64>>,
|
||||
ShoupNonInteractiveServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
||||
>;
|
||||
|
||||
thread_local! {
|
||||
static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator>> = RefCell::new(None);
|
||||
|
||||
}
|
||||
static BOOL_SERVER_KEY: OnceLock<ShoupNonInteractiveServerKeyEvaluationDomain<Vec<Vec<u64>>>> =
|
||||
OnceLock::new();
|
||||
|
||||
static MULTI_PARTY_CRS: OnceLock<NonInteractiveMultiPartyCrs<[u8; 32]>> = OnceLock::new();
|
||||
|
||||
pub fn set_parameter_set(select: ParameterSelector) {
|
||||
match select {
|
||||
ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16 => {
|
||||
BOOL_EVALUATOR.with_borrow_mut(|v| {
|
||||
*v = Some(BoolEvaluator::new(NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS))
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
panic!("Paramerters not supported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_common_reference_seed(seed: [u8; 32]) {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
assert_eq!(
|
||||
e.parameters().variant(),
|
||||
&ParameterVariant::NonInteractiveMultiParty,
|
||||
"Set parameters do not support Non interactive multi-party"
|
||||
);
|
||||
});
|
||||
|
||||
assert!(
|
||||
MULTI_PARTY_CRS
|
||||
.set(NonInteractiveMultiPartyCrs { seed: seed })
|
||||
.is_ok(),
|
||||
"Attempted to set MP SEED twice."
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gen_client_key() -> ClientKey {
|
||||
BoolEvaluator::with_local(|e| e.client_key())
|
||||
}
|
||||
|
||||
pub fn gen_server_key_share(
|
||||
user_id: usize,
|
||||
total_users: usize,
|
||||
client_key: &ClientKey,
|
||||
) -> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
|
||||
Vec<Vec<u64>>,
|
||||
NonInteractiveMultiPartyCrs<[u8; 32]>,
|
||||
> {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let cr_seed = NonInteractiveMultiPartyCrs::global();
|
||||
e.non_interactive_multi_party_key_share(cr_seed, user_id, total_users, client_key)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn aggregate_server_key_shares(
|
||||
shares: &[CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
|
||||
Vec<Vec<u64>>,
|
||||
NonInteractiveMultiPartyCrs<[u8; 32]>,
|
||||
>],
|
||||
) -> SeededNonInteractiveMultiPartyServerKey<
|
||||
Vec<Vec<u64>>,
|
||||
NonInteractiveMultiPartyCrs<[u8; 32]>,
|
||||
BoolParameters<u64>,
|
||||
> {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let cr_seed = NonInteractiveMultiPartyCrs::global();
|
||||
e.aggregate_non_interactive_multi_party_key_share(cr_seed, shares.len(), shares)
|
||||
})
|
||||
}
|
||||
|
||||
impl
|
||||
SeededNonInteractiveMultiPartyServerKey<
|
||||
Vec<Vec<u64>>,
|
||||
NonInteractiveMultiPartyCrs<[u8; 32]>,
|
||||
BoolParameters<u64>,
|
||||
>
|
||||
{
|
||||
pub fn set_server_key(&self) {
|
||||
let eval_key = NonInteractiveServerKeyEvaluationDomain::<
|
||||
_,
|
||||
BoolParameters<u64>,
|
||||
DefaultSecureRng,
|
||||
NttBackendU64,
|
||||
>::from(self);
|
||||
assert!(
|
||||
BOOL_SERVER_KEY
|
||||
.set(ShoupNonInteractiveServerKeyEvaluationDomain::from(eval_key))
|
||||
.is_ok(),
|
||||
"Attempted to set server key twice!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Global for NonInteractiveMultiPartyCrs<[u8; 32]> {
|
||||
fn global() -> &'static Self {
|
||||
MULTI_PARTY_CRS
|
||||
.get()
|
||||
.expect("Non-interactive multi-party common reference string not set")
|
||||
}
|
||||
}
|
||||
|
||||
// BOOL EVALUATOR //
|
||||
impl WithLocal for BoolEvaluator {
|
||||
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 = ShoupNonInteractiveServerKeyEvaluationDomain<Vec<Vec<u64>>>;
|
||||
impl Global for RuntimeServerKey {
|
||||
fn global() -> &'static Self {
|
||||
BOOL_SERVER_KEY.get().expect("Server key not set!")
|
||||
}
|
||||
}
|
||||
|
||||
/// Non interactive multi-party specfic encryptor decryptor routines
|
||||
mod impl_enc_dec {
|
||||
use crate::{
|
||||
bool::{
|
||||
evaluator::{BoolEncoding, BoolEvaluator},
|
||||
keys::NonInteractiveMultiPartyClientKey,
|
||||
parameters::CiphertextModulus,
|
||||
},
|
||||
pbs::PbsInfo,
|
||||
random::{DefaultSecureRng, NewWithSeed},
|
||||
rgsw::secret_key_encrypt_rlwe,
|
||||
bool::{evaluator::BoolEncoding, keys::NonInteractiveMultiPartyClientKey},
|
||||
pbs::{sample_extract, PbsInfo, WithShoupRepr},
|
||||
random::{DefaultSecureRng, NewWithSeed, RandomFillUniformInModulus},
|
||||
rgsw::{key_switch, secret_key_encrypt_rlwe},
|
||||
utils::{TryConvertFrom1, WithLocal},
|
||||
Encryptor, Matrix, RowEntity,
|
||||
Encryptor, KeySwitchWithId, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor,
|
||||
RowEntity, RowMut,
|
||||
};
|
||||
use num_traits::Zero;
|
||||
use itertools::Itertools;
|
||||
use num_traits::{ToPrimitive, Zero};
|
||||
|
||||
trait SeededCiphertext<M, S> {
|
||||
fn new_with_seed(data: M, seed: S) -> Self;
|
||||
}
|
||||
use super::*;
|
||||
|
||||
type Mat = Vec<Vec<u64>>;
|
||||
|
||||
impl<K, C> Encryptor<[bool], C> for K
|
||||
pub(super) struct BatchedFheBools<C> {
|
||||
pub(super) data: Vec<C>,
|
||||
}
|
||||
|
||||
impl<C: MatrixMut<MatElement = u64>> BatchedFheBools<C>
|
||||
where
|
||||
C::R: RowEntity + RowMut,
|
||||
{
|
||||
pub(super) fn extract(&self, index: usize) -> C::R {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let ring_size = e.parameters().rlwe_n().0;
|
||||
let ct_index = index / ring_size;
|
||||
let coeff_index = index % ring_size;
|
||||
let mut lwe_out = C::R::zeros(e.parameters().rlwe_n().0 + 1);
|
||||
sample_extract(
|
||||
&mut lwe_out,
|
||||
&self.data[ct_index],
|
||||
e.pbs_info().modop_rlweq(),
|
||||
coeff_index,
|
||||
);
|
||||
lwe_out
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct NonInteractiveBatchedFheBools<C> {
|
||||
data: Vec<C>,
|
||||
}
|
||||
|
||||
impl<M: MatrixEntity + MatrixMut<MatElement = u64>> From<&(Vec<M::R>, [u8; 32])>
|
||||
for NonInteractiveBatchedFheBools<M>
|
||||
where
|
||||
<M as Matrix>::R: RowMut,
|
||||
{
|
||||
fn from(value: &(Vec<M::R>, [u8; 32])) -> Self {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let parameters = e.parameters();
|
||||
let ring_size = parameters.rlwe_n().0;
|
||||
let rlwe_q = parameters.rlwe_q();
|
||||
|
||||
let mut prng = DefaultSecureRng::new_seeded(value.1);
|
||||
let rlwes = value
|
||||
.0
|
||||
.iter()
|
||||
.map(|partb| {
|
||||
let mut rlwe = M::zeros(2, ring_size);
|
||||
|
||||
// sample A
|
||||
RandomFillUniformInModulus::random_fill(
|
||||
&mut prng,
|
||||
rlwe_q,
|
||||
rlwe.get_row_mut(0),
|
||||
);
|
||||
|
||||
// Copy over B
|
||||
rlwe.get_row_mut(1).copy_from_slice(partb.as_ref());
|
||||
|
||||
rlwe
|
||||
})
|
||||
.collect_vec();
|
||||
Self { data: rlwes }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K> Encryptor<[bool], NonInteractiveBatchedFheBools<Mat>> for K
|
||||
where
|
||||
K: Encryptor<[bool], (Mat, [u8; 32])>,
|
||||
{
|
||||
fn encrypt(&self, m: &[bool]) -> NonInteractiveBatchedFheBools<Mat> {
|
||||
NonInteractiveBatchedFheBools::from(&K::encrypt(&self, m))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K> Encryptor<[bool], (Mat, [u8; 32])> for K
|
||||
where
|
||||
K: NonInteractiveMultiPartyClientKey,
|
||||
C: SeededCiphertext<<Mat as Matrix>::R, <DefaultSecureRng as NewWithSeed>::Seed>,
|
||||
<Mat as Matrix>::R:
|
||||
TryConvertFrom1<[K::Element], CiphertextModulus<<Mat as Matrix>::MatElement>>,
|
||||
{
|
||||
fn encrypt(&self, m: &[bool]) -> C {
|
||||
fn encrypt(&self, m: &[bool]) -> (Mat, [u8; 32]) {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let parameters = e.parameters();
|
||||
assert!(m.len() <= parameters.rlwe_n().0);
|
||||
|
||||
let mut message = vec![<Mat as Matrix>::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 parameters = e.parameters();
|
||||
let ring_size = parameters.rlwe_n().0;
|
||||
|
||||
let rlwe_count = ((m.len() as f64 / ring_size as f64).ceil())
|
||||
.to_usize()
|
||||
.unwrap();
|
||||
|
||||
let mut seed = <DefaultSecureRng as NewWithSeed>::Seed::default();
|
||||
rng.fill_bytes(&mut seed);
|
||||
let mut prng = DefaultSecureRng::new_seeded(seed);
|
||||
|
||||
let mut rlwe_out =
|
||||
<<Mat as Matrix>::R as RowEntity>::zeros(parameters.rlwe_n().0);
|
||||
let sk_u = self.sk_u_rlwe();
|
||||
|
||||
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,
|
||||
);
|
||||
// encrypt `m` into ceil(len(m)/N) RLWE ciphertexts
|
||||
let rlwes = (0..rlwe_count)
|
||||
.map(|index| {
|
||||
let mut message = vec![<Mat as Matrix>::MatElement::zero(); ring_size];
|
||||
m[(index * ring_size)..std::cmp::min(m.len(), (index + 1) * ring_size)]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| {
|
||||
if *v {
|
||||
message[i] = parameters.rlwe_q().true_el()
|
||||
} else {
|
||||
message[i] = parameters.rlwe_q().false_el()
|
||||
}
|
||||
});
|
||||
|
||||
C::new_with_seed(rlwe_out, seed)
|
||||
// encrypt message
|
||||
let mut rlwe_out =
|
||||
<<Mat as Matrix>::R as RowEntity>::zeros(parameters.rlwe_n().0);
|
||||
|
||||
secret_key_encrypt_rlwe(
|
||||
&message,
|
||||
&mut rlwe_out,
|
||||
&sk_u,
|
||||
e.pbs_info().modop_rlweq(),
|
||||
e.pbs_info().nttop_rlweq(),
|
||||
&mut prng,
|
||||
rng,
|
||||
);
|
||||
|
||||
rlwe_out
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
(rlwes, seed)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl KeySwitchWithId<Mat> for Mat {
|
||||
fn key_switch(&self, user_id: usize) -> Mat {
|
||||
BoolEvaluator::with_local(|e| {
|
||||
let server_key = BOOL_SERVER_KEY.get().unwrap();
|
||||
let ksk = server_key.ui_to_s_ksk(user_id);
|
||||
let decomposer = e.ni_ui_to_s_ks_decomposer().as_ref().unwrap();
|
||||
|
||||
// perform key switch
|
||||
key_switch(
|
||||
self,
|
||||
ksk.as_ref(),
|
||||
ksk.shoup_repr(),
|
||||
decomposer,
|
||||
e.pbs_info().nttop_rlweq(),
|
||||
e.pbs_info().modop_rlweq(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> KeySwitchWithId<BatchedFheBools<C>> for NonInteractiveBatchedFheBools<C>
|
||||
where
|
||||
C: KeySwitchWithId<C>,
|
||||
{
|
||||
fn key_switch(&self, user_id: usize) -> BatchedFheBools<C> {
|
||||
let data = self
|
||||
.data
|
||||
.iter()
|
||||
.map(|c| c.key_switch(user_id))
|
||||
.collect_vec();
|
||||
BatchedFheBools { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> MultiPartyDecryptor<bool, <Mat as Matrix>::R>
|
||||
for super::super::keys::ClientKey<[u8; 32], E>
|
||||
{
|
||||
type DecryptionShare = <Mat as Matrix>::MatElement;
|
||||
|
||||
fn gen_decryption_share(&self, c: &<Mat as Matrix>::R) -> Self::DecryptionShare {
|
||||
BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, self))
|
||||
}
|
||||
|
||||
fn aggregate_decryption_shares(
|
||||
&self,
|
||||
c: &<Mat as Matrix>::R,
|
||||
shares: &[Self::DecryptionShare],
|
||||
) -> bool {
|
||||
BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use impl_enc_dec::NonInteractiveBatchedFheBools;
|
||||
use itertools::{izip, Itertools};
|
||||
use num_traits::ToPrimitive;
|
||||
use rand::{thread_rng, RngCore};
|
||||
|
||||
use crate::{
|
||||
backend::Modulus,
|
||||
bool::{
|
||||
evaluator::{BoolEncoding, BooleanGates},
|
||||
keys::SinglePartyClientKey,
|
||||
},
|
||||
lwe::decrypt_lwe,
|
||||
rgsw::decrypt_rlwe,
|
||||
utils::{Stats, TryConvertFrom1},
|
||||
ArithmeticOps, Encryptor, KeySwitchWithId, ModInit, MultiPartyDecryptor, NttInit,
|
||||
VectorOps,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn non_interactive_mp_bool_nand() {
|
||||
set_parameter_set(ParameterSelector::NonInteractiveMultiPartyLessThanOrEqualTo16);
|
||||
let mut seed = [0u8; 32];
|
||||
thread_rng().fill_bytes(&mut seed);
|
||||
set_common_reference_seed(seed);
|
||||
|
||||
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 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 mut m0 = false;
|
||||
let mut m1 = true;
|
||||
|
||||
let mut ct0 = {
|
||||
let ct: NonInteractiveBatchedFheBools<_> = cks[0].encrypt(vec![m0].as_slice());
|
||||
let ct = ct.key_switch(0);
|
||||
ct.extract(0)
|
||||
};
|
||||
let mut ct1 = {
|
||||
let ct: NonInteractiveBatchedFheBools<_> = cks[1].encrypt(vec![m1].as_slice());
|
||||
let ct = ct.key_switch(1);
|
||||
ct.extract(0)
|
||||
};
|
||||
|
||||
for _ in 0..100 {
|
||||
let ct_out =
|
||||
BoolEvaluator::with_local_mut(|e| e.xor(&ct0, &ct1, RuntimeServerKey::global()));
|
||||
|
||||
let decryption_shares = cks
|
||||
.iter()
|
||||
.map(|k| k.gen_decryption_share(&ct_out))
|
||||
.collect_vec();
|
||||
let m_out = cks[0].aggregate_decryption_shares(&ct_out, &decryption_shares);
|
||||
|
||||
let m_expected = (m0 ^ m1);
|
||||
|
||||
{
|
||||
let noisy_m = decrypt_lwe(&ct_out, &ideal_rlwe_sk, &rlwe_q_modop);
|
||||
let noise = if m_expected {
|
||||
rlwe_q_modop.sub(¶meters.rlwe_q().true_el(), &noisy_m)
|
||||
} else {
|
||||
rlwe_q_modop.sub(¶meters.rlwe_q().false_el(), &noisy_m)
|
||||
};
|
||||
println!(
|
||||
"Noise: {}",
|
||||
parameters
|
||||
.rlwe_q()
|
||||
.map_element_to_i64(&noise)
|
||||
.abs()
|
||||
.to_f64()
|
||||
.unwrap()
|
||||
.log2()
|
||||
)
|
||||
}
|
||||
|
||||
assert!(m_out == m_expected, "Expected {m_expected} but got {m_out}");
|
||||
|
||||
m1 = m0;
|
||||
m0 = m_out;
|
||||
|
||||
ct1 = ct0;
|
||||
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| {
|
||||
if *b {
|
||||
parameters.rlwe_q().true_el()
|
||||
} else {
|
||||
parameters.rlwe_q().false_el()
|
||||
}
|
||||
})
|
||||
.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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +303,10 @@ impl<El> BoolParameters<El> {
|
||||
});
|
||||
els
|
||||
}
|
||||
|
||||
pub(crate) fn variant(&self) -> &ParameterVariant {
|
||||
&self.variant
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
@@ -506,7 +510,7 @@ pub(crate) const NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = Boo
|
||||
lwe_q: CiphertextModulus::new_non_native(1 << 20),
|
||||
br_q: 1 << 11,
|
||||
rlwe_n: PolynomialSize(1 << 11),
|
||||
lwe_n: LweDimension(10),
|
||||
lwe_n: LweDimension(600),
|
||||
lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
|
||||
rlrg_decomposer_params: (
|
||||
DecompostionLogBase(11),
|
||||
|
||||
25
src/bool/sp_api.rs
Normal file
25
src/bool/sp_api.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
mod impl_enc_dec {
|
||||
use crate::{Decryptor, Encryptor};
|
||||
|
||||
use super::super::keys::SinglePartyClientKey;
|
||||
|
||||
impl<K> Encryptor<bool, Vec<u64>> for K
|
||||
where
|
||||
K: SinglePartyClientKey,
|
||||
{
|
||||
fn encrypt(&self, m: &bool) -> Vec<u64> {
|
||||
todo!()
|
||||
// BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K> Decryptor<bool, Vec<u64>> for K
|
||||
where
|
||||
K: SinglePartyClientKey,
|
||||
{
|
||||
fn decrypt(&self, c: &Vec<u64>) -> bool {
|
||||
todo!()
|
||||
// BoolEvaluator::with_local(|e| e.sk_decrypt(c, self))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user