make enc and dec variant specific

This commit is contained in:
Janmajaya Mall
2024-06-17 20:13:32 +05:30
parent 691995f1c3
commit 88fdc6ac5c
9 changed files with 905 additions and 847 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -10,112 +10,130 @@ use crate::{
Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut, Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut,
}; };
use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus}; use super::{
evaluator::BoolEvaluator,
parameters::{BoolParameters, CiphertextModulus},
};
trait SinglePartyClientKey { pub(crate) trait SinglePartyClientKey {
type Element; type Element;
fn sk_rlwe(&self) -> &[Self::Element]; fn sk_rlwe(&self) -> Vec<Self::Element>;
fn sk_lwe(&self) -> &[Self::Element]; fn sk_lwe(&self) -> Vec<Self::Element>;
} }
trait InteractiveMultiPartyClientKey { pub(crate) trait InteractiveMultiPartyClientKey {
type Element; type Element;
fn sk_rlwe(&self) -> &[Self::Element]; fn sk_rlwe(&self) -> Vec<Self::Element>;
fn sk_lwe(&self) -> &[Self::Element]; fn sk_lwe(&self) -> Vec<Self::Element>;
} }
trait NonInteractiveMultiPartyClientKey { pub(crate) trait NonInteractiveMultiPartyClientKey {
type Element; type Element;
fn sk_rlwe(&self) -> &[Self::Element]; fn sk_rlwe(&self) -> Vec<Self::Element>;
fn sk_u_rlwe(&self) -> &[Self::Element]; fn sk_u_rlwe(&self) -> Vec<Self::Element>;
fn sk_lwe(&self) -> &[Self::Element]; fn sk_lwe(&self) -> Vec<Self::Element>;
} }
/// Client key with RLWE and LWE secrets /// Client key
///
/// Key is used for all parameter varians - Single party, interactive
/// multi-party, and non-interactive multi-party. The only stored the main seed
/// and seeds of the Rlwe/Lwe secrets are derived at puncturing the seed desired
/// number of times.
///
/// ### Punctures required:
///
/// Puncture 1 -> Seed of RLWE secret used as main RLWE secret for
/// single-party, interactive/non-interactive multi-party
///
/// Puncture 2 -> Seed of LWE secret used main LWE secret for single-party,
/// interactive/non-interactive multi-party
///
/// Puncture 3 -> Seed of RLWE secret used as `u` in
/// interactive/non-interactive multi-party.
#[derive(Clone)] #[derive(Clone)]
pub struct ClientKey { pub struct ClientKey<S, E> {
sk_rlwe: RlweSecret, seed: S,
sk_lwe: LweSecret, parameters: BoolParameters<E>,
}
/// Client key with RLWE and LWE secrets
#[derive(Clone)]
pub struct ThrowMeAwayKey {
sk_rlwe: RlweSecret,
sk_u_rlwe: RlweSecret,
sk_lwe: LweSecret,
} }
mod impl_ck { mod impl_ck {
use crate::{
random::DefaultSecureRng,
utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng},
};
use super::*; use super::*;
// Client key impl<E> ClientKey<[u8; 32], E> {
impl ClientKey { pub(in super::super) fn new(parameters: BoolParameters<E>) -> ClientKey<[u8; 32], E> {
pub(in super::super) fn new(sk_rlwe: RlweSecret, sk_lwe: LweSecret) -> Self { let mut rng = DefaultSecureRng::new();
Self { sk_rlwe, sk_lwe } let mut seed = [0u8; 32];
} rng.fill_bytes(&mut seed);
Self { seed, parameters }
pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret {
&self.sk_rlwe
}
pub(in super::super) fn sk_lwe(&self) -> &LweSecret {
&self.sk_lwe
} }
} }
// Client key impl<E> SinglePartyClientKey for ClientKey<[u8; 32], E> {
impl ThrowMeAwayKey { type Element = i32;
pub(in super::super) fn new( fn sk_lwe(&self) -> Vec<Self::Element> {
sk_rlwe: RlweSecret, let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
sk_u_rlwe: RlweSecret, let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2);
sk_lwe: LweSecret,
) -> Self {
Self {
sk_rlwe,
sk_u_rlwe,
sk_lwe,
}
}
pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret { let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed);
&self.sk_rlwe let mut out = vec![0i32; self.parameters.lwe_n().0];
fill_random_ternary_secret_with_hamming_weight(
&mut out,
self.parameters.lwe_n().0 >> 1,
&mut lwe_prng,
);
out
} }
fn sk_rlwe(&self) -> Vec<Self::Element> {
let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1);
pub(in super::super) fn sk_u_rlwe(&self) -> &RlweSecret { let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
&self.sk_u_rlwe let mut out = vec![0i32; self.parameters.rlwe_n().0];
} fill_random_ternary_secret_with_hamming_weight(
&mut out,
pub(in super::super) fn sk_lwe(&self) -> &LweSecret { self.parameters.rlwe_n().0 >> 1,
&self.sk_lwe &mut rlwe_prng,
);
out
} }
} }
impl Encryptor<bool, Vec<u64>> for ClientKey { impl<E> InteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
fn encrypt(&self, m: &bool) -> Vec<u64> { type Element = i32;
BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self)) fn sk_lwe(&self) -> Vec<Self::Element> {
<Self as SinglePartyClientKey>::sk_lwe(&self)
}
fn sk_rlwe(&self) -> Vec<Self::Element> {
<Self as SinglePartyClientKey>::sk_rlwe(&self)
} }
} }
impl Decryptor<bool, Vec<u64>> for ClientKey { impl<E> NonInteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
fn decrypt(&self, c: &Vec<u64>) -> bool { type Element = i32;
BoolEvaluator::with_local(|e| e.sk_decrypt(c, self)) fn sk_lwe(&self) -> Vec<Self::Element> {
<Self as SinglePartyClientKey>::sk_lwe(&self)
} }
} fn sk_rlwe(&self) -> Vec<Self::Element> {
<Self as SinglePartyClientKey>::sk_rlwe(&self)
impl MultiPartyDecryptor<bool, Vec<u64>> for ClientKey {
type DecryptionShare = u64;
fn gen_decryption_share(&self, c: &Vec<u64>) -> Self::DecryptionShare {
BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, &self))
} }
fn sk_u_rlwe(&self) -> Vec<Self::Element> {
let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3);
fn aggregate_decryption_shares( let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
&self, let mut out = vec![0i32; self.parameters.rlwe_n().0];
c: &Vec<u64>, fill_random_ternary_secret_with_hamming_weight(
shares: &[Self::DecryptionShare], &mut out,
) -> bool { self.parameters.rlwe_n().0 >> 1,
BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c)) &mut rlwe_prng,
);
out
} }
} }
} }
@@ -135,18 +153,6 @@ pub(super) mod impl_pk {
} }
} }
impl<Rng, ModOp> Encryptor<bool, Vec<u64>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
fn encrypt(&self, m: &bool) -> Vec<u64> {
BoolEvaluator::with_local(|e| e.pk_encrypt(&self.key, *m))
}
}
impl<Rng, ModOp> Encryptor<[bool], Vec<Vec<u64>>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
fn encrypt(&self, m: &[bool]) -> Vec<Vec<u64>> {
BoolEvaluator::with_local(|e| e.pk_encrypt_batched(&self.key, m))
}
}
impl< impl<
M: MatrixMut + MatrixEntity, M: MatrixMut + MatrixEntity,
Rng: NewWithSeed Rng: NewWithSeed
@@ -456,8 +462,6 @@ pub(super) mod impl_server_key_eval_domain {
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
use crate::{ use crate::{
backend::Modulus,
bool::{NonInteractiveMultiPartyCrs, SeededNonInteractiveMultiPartyServerKey},
ntt::{Ntt, NttInit}, ntt::{Ntt, NttInit},
pbs::PbsKey, pbs::PbsKey,
}; };
@@ -736,7 +740,7 @@ pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
pub(super) mod impl_non_interactive_server_key_eval_domain { pub(super) mod impl_non_interactive_server_key_eval_domain {
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
use crate::{bool::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit}; use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
use super::*; use super::*;

View File

@@ -1,16 +1,12 @@
pub(crate) mod evaluator; pub(crate) mod evaluator;
pub(crate) mod keys; mod keys;
mod mp_api; mod mp_api;
mod ni_mp_api; mod ni_mp_api;
mod noise; mod noise;
pub(crate) mod parameters; pub(crate) mod parameters;
pub use mp_api::*; pub(crate) use keys::PublicKey;
pub type FheBool = Vec<u64>; pub type FheBool = Vec<u64>;
use std::{cell::RefCell, sync::OnceLock}; pub use mp_api::*;
use evaluator::*;
use keys::*;
use parameters::*;

View File

@@ -1,3 +1,5 @@
use std::{cell::RefCell, sync::OnceLock};
use crate::{ use crate::{
backend::{ModularOpsU64, ModulusPowerOf2}, backend::{ModularOpsU64, ModulusPowerOf2},
ntt::NttBackendU64, ntt::NttBackendU64,
@@ -5,7 +7,7 @@ use crate::{
utils::{Global, WithLocal}, utils::{Global, WithLocal},
}; };
use super::*; use super::{evaluator::*, keys::*, parameters::*};
thread_local! { 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<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModulusPowerOf2<CiphertextModulus<u64>>, ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>>> = RefCell::new(None);
@@ -15,6 +17,8 @@ static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>
static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new(); static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new();
pub type ClientKey = super::keys::ClientKey<[u8; 32], u64>;
pub enum ParameterSelector { pub enum ParameterSelector {
MultiPartyLessThanOrEqualTo16, MultiPartyLessThanOrEqualTo16,
} }
@@ -62,7 +66,7 @@ pub fn gen_mp_keys_phase1(
) -> CommonReferenceSeededCollectivePublicKeyShare<Vec<u64>, [u8; 32], BoolParameters<u64>> { ) -> CommonReferenceSeededCollectivePublicKeyShare<Vec<u64>, [u8; 32], BoolParameters<u64>> {
let seed = MultiPartyCrs::global().public_key_share_seed::<DefaultSecureRng>(); let seed = MultiPartyCrs::global().public_key_share_seed::<DefaultSecureRng>();
BoolEvaluator::with_local(|e| { BoolEvaluator::with_local(|e| {
let pk_share = e.multi_party_public_key_share(seed, &ck); let pk_share = e.multi_party_public_key_share(seed, ck);
pk_share pk_share
}) })
} }
@@ -167,3 +171,91 @@ impl Global for RuntimeServerKey {
BOOL_SERVER_KEY.get().expect("Server key not set!") BOOL_SERVER_KEY.get().expect("Server key not set!")
} }
} }
mod impl_enc_dec {
use crate::{
pbs::{sample_extract, PbsInfo},
rgsw::public_key_encrypt_rlwe,
Decryptor, Encryptor, Matrix, MatrixEntity, MultiPartyDecryptor, RowEntity,
};
use num_traits::Zero;
use super::*;
type Mat = Vec<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 {
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 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()
}
});
// e.pk_encrypt_batched(self.key(), m)
public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
&mut rlwe_out,
self.key(),
&message,
e.pbs_info().modop_rlweq(),
e.pbs_info().nttop_rlweq(),
rng,
);
rlwe_out
})
})
}
}
impl<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());
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);
lwe
})
}
}
}

View File

@@ -0,0 +1,66 @@
mod impl_enc_dec {
use crate::{
bool::{
evaluator::{BoolEncoding, BoolEvaluator},
keys::NonInteractiveMultiPartyClientKey,
parameters::CiphertextModulus,
},
pbs::PbsInfo,
random::{DefaultSecureRng, NewWithSeed},
rgsw::secret_key_encrypt_rlwe,
utils::{TryConvertFrom1, WithLocal},
Encryptor, Matrix, RowEntity,
};
use num_traits::Zero;
trait SeededCiphertext<M, S> {
fn new_with_seed(data: M, seed: S) -> Self;
}
type Mat = Vec<Vec<u64>>;
impl<K, C> Encryptor<[bool], C> 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 {
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 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);
secret_key_encrypt_rlwe(
&message,
&mut rlwe_out,
&self.sk_u_rlwe(),
e.pbs_info().modop_rlweq(),
e.pbs_info().nttop_rlweq(),
&mut prng,
rng,
);
C::new_with_seed(rlwe_out, seed)
})
})
}
}
}

View File

@@ -2,19 +2,17 @@ mod test {
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
use crate::{ use crate::{
backend::{ArithmeticOps, ModularOpsU64, Modulus, ModulusPowerOf2}, backend::{ModularOpsU64, ModulusPowerOf2},
bool::{ bool::{
BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus, ClientKey, PublicKey, evaluator::{BoolEncoding, BoolEvaluator, BooleanGates},
ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain, MP_BOOL_PARAMS, keys::{
SMALL_MP_BOOL_PARAMS, InteractiveMultiPartyClientKey, PublicKey, ServerKeyEvaluationDomain,
ShoupServerKeyEvaluationDomain,
},
parameters::{CiphertextModulus, SMALL_MP_BOOL_PARAMS},
}, },
lwe::{decrypt_lwe, LweSecret},
ntt::NttBackendU64, ntt::NttBackendU64,
pbs::PbsInfo,
random::DefaultSecureRng, random::DefaultSecureRng,
rgsw::RlweSecret,
utils::Stats,
Ntt, Secret,
}; };
#[test] #[test]
@@ -42,29 +40,26 @@ mod test {
.collect_vec(); .collect_vec();
// construct ideal rlwe sk for meauring noise // construct ideal rlwe sk for meauring noise
let ideal_client_key = { let mut ideal_rlwe_sk = vec![0i32; evaluator.parameters().rlwe_n().0];
let mut ideal_rlwe_sk = vec![0i32; evaluator.parameters().rlwe_n().0]; cks.iter().for_each(|k| {
cks.iter().for_each(|k| { izip!(
izip!(ideal_rlwe_sk.iter_mut(), k.sk_rlwe().values()).for_each(|(ideal_i, s_i)| { ideal_rlwe_sk.iter_mut(),
*ideal_i = *ideal_i + s_i; InteractiveMultiPartyClientKey::sk_rlwe(k)
});
});
let mut ideal_lwe_sk = vec![0i32; evaluator.parameters().lwe_n().0];
cks.iter().for_each(|k| {
izip!(ideal_lwe_sk.iter_mut(), k.sk_lwe().values()).for_each(|(ideal_i, s_i)| {
*ideal_i = *ideal_i + s_i;
});
});
ClientKey::new(
RlweSecret {
values: ideal_rlwe_sk,
},
LweSecret {
values: ideal_lwe_sk,
},
) )
}; .for_each(|(ideal_i, s_i)| {
*ideal_i = *ideal_i + s_i;
});
});
let mut ideal_lwe_sk = vec![0i32; evaluator.parameters().lwe_n().0];
cks.iter().for_each(|k| {
izip!(
ideal_lwe_sk.iter_mut(),
InteractiveMultiPartyClientKey::sk_lwe(k)
)
.for_each(|(ideal_i, s_i)| {
*ideal_i = *ideal_i + s_i;
});
});
// round 1 // round 1
let pk_shares = cks let pk_shares = cks

View File

@@ -1,292 +1,297 @@
#[cfg(test)] // #[cfg(test)]
mod tests { // mod tests {
use itertools::{izip, Itertools}; // use itertools::{izip, Itertools};
use num_traits::zero; // use num_traits::zero;
use rand::{thread_rng, Rng}; // use rand::{thread_rng, Rng};
use crate::{ // use crate::{
bool::keys::ClientKey, // bool::keys::ClientKey,
ntt, // ntt,
random::{ // random::{
DefaultSecureRng, RandomFill, RandomFillGaussianInModulus, RandomFillUniformInModulus, // DefaultSecureRng, RandomFill, RandomFillGaussianInModulus,
}, // RandomFillUniformInModulus, },
utils::{ // utils::{
fill_random_ternary_secret_with_hamming_weight, generate_prime, Stats, TryConvertFrom1, // fill_random_ternary_secret_with_hamming_weight, generate_prime,
}, // Stats, TryConvertFrom1, },
ArithmeticOps, Decomposer, DefaultDecomposer, ModInit, ModularOpsU64, Ntt, NttBackendU64, // ArithmeticOps, Decomposer, DefaultDecomposer, ModInit, ModularOpsU64,
NttInit, VectorOps, // Ntt, NttBackendU64, NttInit, VectorOps,
}; // };
#[test] // #[test]
fn non_interactive_multi_party() { // fn non_interactive_multi_party() {
let logq = 56; // let logq = 56;
let ring_size = 1usize << 11; // let ring_size = 1usize << 11;
let q = generate_prime(logq, 2 * ring_size as u64, 1 << logq).unwrap(); // let q = generate_prime(logq, 2 * ring_size as u64, 1 <<
let logb = 1; // logq).unwrap(); let logb = 1;
let d = 56; // let d = 56;
let decomposer = DefaultDecomposer::new(q, logb, d); // let decomposer = DefaultDecomposer::new(q, logb, d);
let gadget_vec = decomposer.gadget_vector(); // let gadget_vec = decomposer.gadget_vector();
let mut rng = DefaultSecureRng::new(); // let mut rng = DefaultSecureRng::new();
let modop = ModularOpsU64::new(q); // let modop = ModularOpsU64::new(q);
let nttop = NttBackendU64::new(&q, ring_size); // let nttop = NttBackendU64::new(&q, ring_size);
let no_of_parties = 16; // let no_of_parties = 16;
let client_secrets = (0..no_of_parties) // let client_secrets = (0..no_of_parties)
.into_iter() // .into_iter()
.map(|_| { // .map(|_| {
let mut sk = vec![0i64; ring_size]; // let mut sk = vec![0i64; ring_size];
fill_random_ternary_secret_with_hamming_weight(&mut sk, ring_size >> 1, &mut rng); // fill_random_ternary_secret_with_hamming_weight(&mut sk,
sk // ring_size >> 1, &mut rng); sk
}) // })
.collect_vec(); // .collect_vec();
let mut s_ideal = vec![0i64; ring_size]; // let mut s_ideal = vec![0i64; ring_size];
client_secrets.iter().for_each(|s| { // client_secrets.iter().for_each(|s| {
izip!(s_ideal.iter_mut(), s.iter()).for_each(|(add_to, v)| { // izip!(s_ideal.iter_mut(), s.iter()).for_each(|(add_to, v)| {
*add_to = *add_to + *v; // *add_to = *add_to + *v;
}); // });
}); // });
let sk_poly_ideal = Vec::<u64>::try_convert_from(s_ideal.as_slice(), &q); // let sk_poly_ideal = Vec::<u64>::try_convert_from(s_ideal.as_slice(),
let mut sk_poly_ideal_eval = sk_poly_ideal.clone(); // &q); let mut sk_poly_ideal_eval = sk_poly_ideal.clone();
nttop.forward(&mut sk_poly_ideal_eval); // nttop.forward(&mut sk_poly_ideal_eval);
let mut ksk_seed = [0u8; 32]; // let mut ksk_seed = [0u8; 32];
rng.fill_bytes(&mut ksk_seed); // rng.fill_bytes(&mut ksk_seed);
// zero encryptions for each party for ksk(u) // // zero encryptions for each party for ksk(u)
let client_zero_encs = { // let client_zero_encs = {
client_secrets // client_secrets
.iter() // .iter()
.map(|sk| { // .map(|sk| {
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q); // let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(),
let mut sk_poly_eval = sk_poly.clone(); // &q); let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice()); // nttop.forward(sk_poly_eval.as_mut_slice());
let mut zero_encs = // let mut zero_encs =
vec![vec![0u64; ring_size]; decomposer.decomposition_count()]; // vec![vec![0u64; ring_size];
let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed); // decomposer.decomposition_count()]; let mut ksk_prng =
zero_encs.iter_mut().for_each(|out| { // DefaultSecureRng::new_seeded(ksk_seed);
RandomFillUniformInModulus::random_fill( // zero_encs.iter_mut().for_each(|out| {
&mut ksk_prng, // RandomFillUniformInModulus::random_fill( &mut
&q, // ksk_prng, &q,
out.as_mut_slice(), // out.as_mut_slice(),
); // );
nttop.forward(out.as_mut_slice()); // nttop.forward(out.as_mut_slice());
modop.elwise_mul_mut(out.as_mut_slice(), &sk_poly_eval); // modop.elwise_mul_mut(out.as_mut_slice(),
nttop.backward(out.as_mut_slice()); // &sk_poly_eval); nttop.backward(out.as_mut_slice());
let mut error = vec![0u64; ring_size]; // let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); // RandomFillGaussianInModulus::random_fill(&mut rng,
// &q, &mut error);
modop.elwise_add_mut(out.as_mut_slice(), &error); // modop.elwise_add_mut(out.as_mut_slice(), &error);
}); // });
zero_encs // zero_encs
}) // })
.collect_vec() // .collect_vec()
}; // };
// main values // // main values
let main_a = { // let main_a = {
let mut a = vec![0u64; ring_size]; // let mut a = vec![0u64; ring_size];
RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut a); // RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut a);
a // a
}; // };
let main_m = { // let main_m = {
let mut main_m = vec![0u64; ring_size]; // let mut main_m = vec![0u64; ring_size];
RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut main_m); // RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut
main_m // main_m); main_m
}; // };
let mut main_u = vec![0i64; ring_size]; // let mut main_u = vec![0i64; ring_size];
fill_random_ternary_secret_with_hamming_weight(&mut main_u, ring_size >> 1, &mut rng); // fill_random_ternary_secret_with_hamming_weight(&mut main_u, ring_size
let u_main_poly = Vec::<u64>::try_convert_from(main_u.as_slice(), &q); // >> 1, &mut rng); let u_main_poly =
let mut u_main_poly_eval = u_main_poly.clone(); // Vec::<u64>::try_convert_from(main_u.as_slice(), &q); let mut
nttop.forward(u_main_poly_eval.as_mut_slice()); // u_main_poly_eval = u_main_poly.clone(); nttop.
// forward(u_main_poly_eval.as_mut_slice());
// party 0 // // party 0
let (mut party0_ksk_u, mut rlwe_main_m_parta) = { // let (mut party0_ksk_u, mut rlwe_main_m_parta) = {
// party 0's secret // // party 0's secret
let sk = client_secrets[0].clone(); // let sk = client_secrets[0].clone();
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q); // let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q);
let mut sk_poly_eval = sk_poly.clone(); // let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice()); // nttop.forward(sk_poly_eval.as_mut_slice());
// `main_a*u + main_m` with ephemeral key u // // `main_a*u + main_m` with ephemeral key u
let mut rlwe_main_m = main_a.clone(); // let mut rlwe_main_m = main_a.clone();
nttop.forward(&mut rlwe_main_m); // nttop.forward(&mut rlwe_main_m);
modop.elwise_mul_mut(&mut rlwe_main_m, &u_main_poly_eval); // modop.elwise_mul_mut(&mut rlwe_main_m, &u_main_poly_eval);
nttop.backward(&mut rlwe_main_m); // nttop.backward(&mut rlwe_main_m);
let mut error = vec![0u64; ring_size]; // let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); // RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut
modop.elwise_add_mut(&mut rlwe_main_m, &error); // error); modop.elwise_add_mut(&mut rlwe_main_m, &error);
modop.elwise_add_mut(&mut rlwe_main_m, &main_m); // modop.elwise_add_mut(&mut rlwe_main_m, &main_m);
// Generate KSK(u) // // Generate KSK(u)
let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed); // let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed);
let mut ksk_u = vec![vec![0u64; ring_size]; 2 * decomposer.decomposition_count()]; // let mut ksk_u = vec![vec![0u64; ring_size]; 2 *
let (ksk_u_a, ksk_u_b) = ksk_u.split_at_mut(decomposer.decomposition_count()); // decomposer.decomposition_count()]; let (ksk_u_a, ksk_u_b) =
izip!(ksk_u_b.iter_mut(), ksk_u_a.iter_mut(), gadget_vec.iter()).for_each( // ksk_u.split_at_mut(decomposer.decomposition_count());
|(row_b, row_a, beta_i)| { // izip!(ksk_u_b.iter_mut(), ksk_u_a.iter_mut(), gadget_vec.iter()).for_each( |(row_b, row_a, beta_i)| {
// sample a // // sample a
RandomFillUniformInModulus::random_fill(&mut ksk_prng, &q, row_a.as_mut()); // RandomFillUniformInModulus::random_fill(&mut ksk_prng,
// &q, row_a.as_mut());
// s_i * a // // s_i * a
let mut s_i_a = row_a.clone(); // let mut s_i_a = row_a.clone();
nttop.forward(&mut s_i_a); // nttop.forward(&mut s_i_a);
modop.elwise_mul_mut(&mut s_i_a, &sk_poly_eval); // modop.elwise_mul_mut(&mut s_i_a, &sk_poly_eval);
nttop.backward(&mut s_i_a); // nttop.backward(&mut s_i_a);
// \beta * u // // \beta * u
let mut beta_u = u_main_poly.clone(); // let mut beta_u = u_main_poly.clone();
modop.elwise_scalar_mul_mut(beta_u.as_mut_slice(), beta_i); // modop.elwise_scalar_mul_mut(beta_u.as_mut_slice(),
// beta_i);
// e // // e
RandomFillGaussianInModulus::random_fill(&mut rng, &q, row_b.as_mut_slice()); // RandomFillGaussianInModulus::random_fill(&mut rng, &q,
// e + \beta * u // row_b.as_mut_slice()); // e + \beta * u
modop.elwise_add_mut(row_b.as_mut_slice(), &beta_u); // modop.elwise_add_mut(row_b.as_mut_slice(), &beta_u);
// b = e + \beta * u + a * s_i // // b = e + \beta * u + a * s_i
modop.elwise_add_mut(row_b.as_mut_slice(), &s_i_a); // modop.elwise_add_mut(row_b.as_mut_slice(), &s_i_a);
}, // },
); // );
// send ksk u from s_0 to s_{ideal} // // send ksk u from s_0 to s_{ideal}
ksk_u_b.iter_mut().enumerate().for_each(|(index, out_b)| { // ksk_u_b.iter_mut().enumerate().for_each(|(index, out_b)| {
// note: skip zero encryption of party 0 // // note: skip zero encryption of party 0
client_zero_encs.iter().skip(1).for_each(|encs| { // client_zero_encs.iter().skip(1).for_each(|encs| {
modop.elwise_add_mut(out_b, &encs[index]); // modop.elwise_add_mut(out_b, &encs[index]);
}); // });
}); // });
// // put ksk in fourier domain // // // put ksk in fourier domain
// ksk_u // // ksk_u
// .iter_mut() // // .iter_mut()
// .for_each(|r| nttop.forward(r.as_mut_slice())); // // .for_each(|r| nttop.forward(r.as_mut_slice()));
(ksk_u, rlwe_main_m) // (ksk_u, rlwe_main_m)
}; // };
// Check ksk_u is correct // // Check ksk_u is correct
// { // // {
// let (ksk_a, ksk_b) = // // let (ksk_a, ksk_b) =
// party0_ksk_u.split_at_mut(decomposer.decomposition_count()); // // party0_ksk_u.split_at_mut(decomposer.decomposition_count());
// izip!( // // izip!(
// ksk_a.iter(), // // ksk_a.iter(),
// ksk_b.iter(), // // ksk_b.iter(),
// decomposer.gadget_vector().iter() // // decomposer.gadget_vector().iter()
// ) // // )
// .for_each(|(row_a, row_b, beta_i)| { // // .for_each(|(row_a, row_b, beta_i)| {
// // a * s // // // a * s
// let mut sa = row_a.clone(); // // let mut sa = row_a.clone();
// nttop.forward(&mut sa); // // nttop.forward(&mut sa);
// modop.elwise_mul_mut(&mut sa, &sk_poly_ideal_eval); // // modop.elwise_mul_mut(&mut sa, &sk_poly_ideal_eval);
// nttop.backward(&mut sa); // // nttop.backward(&mut sa);
// // b - a*s // // // b - a*s
// let mut out = sa; // // let mut out = sa;
// modop.elwise_neg_mut(&mut out); // // modop.elwise_neg_mut(&mut out);
// modop.elwise_add_mut(&mut out, row_b); // // modop.elwise_add_mut(&mut out, row_b);
// // beta * u // // // beta * u
// let mut expected = u_main_poly.clone(); // // let mut expected = u_main_poly.clone();
// modop.elwise_scalar_mul_mut(&mut expected, beta_i); // // modop.elwise_scalar_mul_mut(&mut expected, beta_i);
// assert_eq!(expected, out); // // assert_eq!(expected, out);
// }); // // });
// } // // }
// RLWE(0) = main_a * s + e = \sum main_a*s_i + e_i // // RLWE(0) = main_a * s + e = \sum main_a*s_i + e_i
let rlwe_to_switch = { // let rlwe_to_switch = {
let mut sum = vec![0u64; ring_size]; // let mut sum = vec![0u64; ring_size];
client_secrets.iter().for_each(|sk| { // client_secrets.iter().for_each(|sk| {
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q); // let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(),
let mut sk_poly_eval = sk_poly.clone(); // &q); let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice()); // nttop.forward(sk_poly_eval.as_mut_slice());
// a * s // // a * s
let mut rlwe = main_a.clone(); // let mut rlwe = main_a.clone();
nttop.forward(&mut rlwe); // nttop.forward(&mut rlwe);
modop.elwise_mul_mut(rlwe.as_mut_slice(), &sk_poly_eval); // modop.elwise_mul_mut(rlwe.as_mut_slice(), &sk_poly_eval);
nttop.backward(&mut rlwe); // nttop.backward(&mut rlwe);
// a * s + e // // a * s + e
let mut error = vec![0u64; ring_size]; // let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error); // RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut
modop.elwise_add_mut(&mut rlwe, &error); // error); modop.elwise_add_mut(&mut rlwe, &error);
modop.elwise_add_mut(&mut sum, &rlwe); // modop.elwise_add_mut(&mut sum, &rlwe);
}); // });
sum // sum
}; // };
// { // // {
// let mut tmp = main_a.clone(); // // let mut tmp = main_a.clone();
// nttop.forward(&mut tmp); // // nttop.forward(&mut tmp);
// modop.elwise_mul_mut(&mut tmp, &sk_poly_ideal_eval); // // modop.elwise_mul_mut(&mut tmp, &sk_poly_ideal_eval);
// nttop.backward(&mut tmp); // // nttop.backward(&mut tmp);
// assert_eq!(&rlwe_to_switch, &tmp); // // assert_eq!(&rlwe_to_switch, &tmp);
// } // // }
// Key switch \sum decomp<RLWE(0)> * KSK(i) // // Key switch \sum decomp<RLWE(0)> * KSK(i)
let mut decomp_rlwe = vec![vec![0u64; ring_size]; decomposer.decomposition_count()]; // let mut decomp_rlwe = vec![vec![0u64; ring_size];
rlwe_to_switch.iter().enumerate().for_each(|(ri, el)| { // decomposer.decomposition_count()]; rlwe_to_switch.iter().enumerate().
decomposer // for_each(|(ri, el)| { decomposer
.decompose_iter(el) // .decompose_iter(el)
.enumerate() // .enumerate()
.for_each(|(j, d_el)| { // .for_each(|(j, d_el)| {
decomp_rlwe[j][ri] = d_el; // decomp_rlwe[j][ri] = d_el;
}); // });
}); // });
// put ksk_u and decomp<RLWE(main_a*s_ideal + e)> in fourier domain // // put ksk_u and decomp<RLWE(main_a*s_ideal + e)> in fourier domain
decomp_rlwe // decomp_rlwe
.iter_mut() // .iter_mut()
.for_each(|r| nttop.forward(r.as_mut_slice())); // .for_each(|r| nttop.forward(r.as_mut_slice()));
party0_ksk_u // party0_ksk_u
.iter_mut() // .iter_mut()
.for_each(|r| nttop.forward(r.as_mut_slice())); // .for_each(|r| nttop.forward(r.as_mut_slice()));
let (ksk_u_a, ksk_u_b) = party0_ksk_u.split_at(decomposer.decomposition_count()); // let (ksk_u_a, ksk_u_b) =
let mut rlwe_main_m_partb_eval = vec![vec![0u64; ring_size]; 2]; // party0_ksk_u.split_at(decomposer.decomposition_count()); let mut
izip!(decomp_rlwe.iter(), ksk_u_a.iter(), ksk_u_b.iter()).for_each(|(o, a, b)| { // rlwe_main_m_partb_eval = vec![vec![0u64; ring_size]; 2]; izip!
// A part // (decomp_rlwe.iter(), ksk_u_a.iter(), ksk_u_b.iter()).for_each(|(o, a, b)| {
// rlwe[0] += o*a // // A part
izip!(rlwe_main_m_partb_eval[0].iter_mut(), o.iter(), a.iter()).for_each( // // rlwe[0] += o*a
|(r, o, a)| { // izip!(rlwe_main_m_partb_eval[0].iter_mut(), o.iter(),
*r = modop.add(r, &modop.mul(o, a)); // a.iter()).for_each( |(r, o, a)| {
}, // *r = modop.add(r, &modop.mul(o, a));
); // },
// );
// B part // // B part
// rlwe[1] += o*b // // rlwe[1] += o*b
izip!(rlwe_main_m_partb_eval[1].iter_mut(), o.iter(), b.iter()).for_each( // izip!(rlwe_main_m_partb_eval[1].iter_mut(), o.iter(),
|(r, o, b)| { // b.iter()).for_each( |(r, o, b)| {
*r = modop.add(r, &modop.mul(o, b)); // *r = modop.add(r, &modop.mul(o, b));
}, // },
); // );
}); // });
// construct RLWE_{s_{ideal}}(-sm) // // construct RLWE_{s_{ideal}}(-sm)
nttop.forward(rlwe_main_m_parta.as_mut_slice()); // nttop.forward(rlwe_main_m_parta.as_mut_slice());
modop.elwise_add_mut(&mut rlwe_main_m_partb_eval[0], &rlwe_main_m_parta); // modop.elwise_add_mut(&mut rlwe_main_m_partb_eval[0],
let rlwe_main_m_eval = rlwe_main_m_partb_eval; // &rlwe_main_m_parta); let rlwe_main_m_eval = rlwe_main_m_partb_eval;
// decrypt RLWE_{s_{ideal}}(m) and check // // decrypt RLWE_{s_{ideal}}(m) and check
let mut neg_s_m_main_out = rlwe_main_m_eval[0].clone(); // let mut neg_s_m_main_out = rlwe_main_m_eval[0].clone();
modop.elwise_mul_mut(&mut neg_s_m_main_out, &sk_poly_ideal_eval); // modop.elwise_mul_mut(&mut neg_s_m_main_out, &sk_poly_ideal_eval);
modop.elwise_neg_mut(&mut neg_s_m_main_out); // modop.elwise_neg_mut(&mut neg_s_m_main_out);
modop.elwise_add_mut(&mut neg_s_m_main_out, &rlwe_main_m_eval[1]); // modop.elwise_add_mut(&mut neg_s_m_main_out, &rlwe_main_m_eval[1]);
nttop.backward(&mut neg_s_m_main_out); // nttop.backward(&mut neg_s_m_main_out);
let mut neg_s_main_m = main_m.clone(); // let mut neg_s_main_m = main_m.clone();
nttop.forward(&mut neg_s_main_m); // nttop.forward(&mut neg_s_main_m);
modop.elwise_mul_mut(&mut neg_s_main_m, &sk_poly_ideal_eval); // modop.elwise_mul_mut(&mut neg_s_main_m, &sk_poly_ideal_eval);
modop.elwise_neg_mut(&mut neg_s_main_m); // modop.elwise_neg_mut(&mut neg_s_main_m);
nttop.backward(&mut neg_s_main_m); // nttop.backward(&mut neg_s_main_m);
let mut diff = neg_s_m_main_out.clone(); // let mut diff = neg_s_m_main_out.clone();
modop.elwise_sub_mut(&mut diff, &neg_s_main_m); // modop.elwise_sub_mut(&mut diff, &neg_s_main_m);
let mut stat = Stats::new(); // let mut stat = Stats::new();
stat.add_more(&Vec::<i64>::try_convert_from(&diff, &q)); // stat.add_more(&Vec::<i64>::try_convert_from(&diff, &q));
println!("Log2 Std: {}", stat.std_dev().abs().log2()); // println!("Log2 Std: {}", stat.std_dev().abs().log2());
} // }
} // }

View File

@@ -1,7 +1,7 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
bool::keys::{ClientKey, PublicKey}, bool::{ClientKey, PublicKey},
Decryptor, Encryptor, MultiPartyDecryptor, Decryptor, Encryptor, MultiPartyDecryptor,
}; };
@@ -97,10 +97,7 @@ mod frontend {
eight_bit_mul, eight_bit_mul,
}; };
use crate::{ use crate::{
bool::{ bool::evaluator::{BoolEvaluator, BooleanGates},
evaluator::{self, BoolEvaluator, BooleanGates},
keys::{ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain},
},
utils::{Global, WithLocal}, utils::{Global, WithLocal},
}; };

View File

@@ -190,6 +190,17 @@ pub fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>(
return r; return r;
} }
pub(crate) 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;
}
pub trait TryConvertFrom1<T: ?Sized, P> { pub trait TryConvertFrom1<T: ?Sized, P> {
fn try_convert_from(value: &T, parameters: &P) -> Self; fn try_convert_from(value: &T, parameters: &P) -> Self;
} }