arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
change LWE secret distribution to Error distribution for all parameters
Janmajaya Mall janmajayamall@protonmail.com
Tue, 02 Jul 2024 16:15:09 +0530
commit

7cbe55691f9e8aaf17d71c4d0e646fcdee245e95

parent

4e6a9aa3a755e92832f74ab6094f23b78df741b8

4 files changed, 116 insertions(+), 18 deletions(-)

jump to
M src/bool/keys.rs → src/bool/keys.rs

@@ -54,7 +54,8 @@ }

mod impl_ck { use crate::{ - random::DefaultSecureRng, + parameters::SecretKeyDistribution, + random::{DefaultSecureRng, RandomFillGaussian}, utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng}, };

@@ -76,15 +77,29 @@ let mut p_rng = DefaultSecureRng::new_seeded(self.seed);

let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2); let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed); + let mut out = vec![0i32; self.parameters.lwe_n().0]; - fill_random_ternary_secret_with_hamming_weight( - &mut out, - self.parameters.lwe_n().0 >> 1, - &mut lwe_prng, - ); + + match self.parameters.lwe_secret_key_dist() { + &SecretKeyDistribution::ErrorDistribution => { + RandomFillGaussian::random_fill(&mut lwe_prng, &mut out); + } + &SecretKeyDistribution::TernaryDistribution => { + 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> { + assert!( + self.parameters.rlwe_secret_key_dist() + == &SecretKeyDistribution::TernaryDistribution + ); + let mut p_rng = DefaultSecureRng::new_seeded(self.seed); let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1);

@@ -120,6 +135,11 @@ fn sk_rlwe(&self) -> Vec<Self::Element> {

<Self as SinglePartyClientKey>::sk_rlwe(&self) } fn sk_u_rlwe(&self) -> Vec<Self::Element> { + assert!( + self.parameters.rlwe_secret_key_dist() + == &SecretKeyDistribution::TernaryDistribution + ); + let mut p_rng = DefaultSecureRng::new_seeded(self.seed); let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3);

@@ -1486,7 +1506,7 @@ backend::{GetModulus, Modulus},

bool::ClientKey, decomposer::NumInfo, lwe::decrypt_lwe, - parameters::CiphertextModulus, + parameters::{CiphertextModulus, I_2P}, utils::TryConvertFrom1, ArithmeticOps, Row, };

@@ -1540,4 +1560,11 @@ .to_f64()

.unwrap() .log2() } + // #[test] + // fn trial() { + // let parameters = I_2P; + // let ck = ClientKey::new(parameters); + // let lwe = ck.sk_lwe(); + // dbg!(lwe); + // } }
M src/bool/ni_mp_api.rs → src/bool/ni_mp_api.rs

@@ -447,23 +447,26 @@ use itertools::Itertools;

use rand::{thread_rng, RngCore}; use crate::{ + backend::Modulus, bool::{ keys::tests::{ideal_sk_rlwe, measure_noise_lwe}, BooleanGates, }, - Encoder, Encryptor, KeySwitchWithId, MultiPartyDecryptor, + lwe::decrypt_lwe, + utils::tests::Stats, + ArithmeticOps, Encoder, Encryptor, KeySwitchWithId, MultiPartyDecryptor, }; use super::*; #[test] fn non_interactive_mp_bool_nand() { - set_parameter_set(ParameterSelector::NonInteractiveLTE4Party); + set_parameter_set(ParameterSelector::NonInteractiveLTE2Party); let mut seed = [0u8; 32]; thread_rng().fill_bytes(&mut seed); set_common_reference_seed(seed); - let parties = 3; + let parties = 2; let cks = (0..parties).map(|_| gen_client_key()).collect_vec();

@@ -495,6 +498,8 @@ let ct = ct.key_switch(1);

ct.extract(0) }; + let mut stats = Stats::new(); + for _ in 0..1000 { // let now = std::time::Instant::now(); let ct_out =

@@ -510,13 +515,17 @@

let m_expected = m0 ^ m1; { - let noise = measure_noise_lwe( - &ct_out, - parameters.rlwe_q().encode(m_expected), - &ideal_sk_rlwe, - &rlwe_modop, - ); - println!("Noise: {noise}"); + // let noise = measure_noise_lwe( + // &ct_out, + // parameters.rlwe_q().encode(m_expected), + // &ideal_sk_rlwe, + // &rlwe_modop, + // ); + // println!("Noise: {noise}"); + + let noisy_m = decrypt_lwe(&ct_out, &ideal_sk_rlwe, &rlwe_modop); + let noise = rlwe_modop.sub(&parameters.rlwe_q().encode(m_expected), &noisy_m); + stats.add_more(&vec![parameters.rlwe_q().map_element_to_i64(&noise)]); } assert!(m_out == m_expected, "Expected {m_expected} but got {m_out}");

@@ -527,5 +536,7 @@

ct1 = ct0; ct0 = ct_out; } + + println!("Noise std dev log2: {}", stats.std_dev().abs().log2()); } }
M src/bool/parameters.rs → src/bool/parameters.rs

@@ -79,6 +79,16 @@ }

} #[derive(Clone, PartialEq, Debug)] +pub(crate) enum SecretKeyDistribution { + /// Elements of secret key are sample from Gaussian distribitution with + /// \sigma = 3.19 and \mu = 0.0 + ErrorDistribution, + /// Elements of secret key are chosen from the set {1,0,-1} with hamming + /// weight `floor(N/2)` where `N` is the secret dimension. + TernaryDistribution, +} + +#[derive(Clone, PartialEq, Debug)] pub(crate) enum ParameterVariant { SingleParty, MultiParty,

@@ -86,6 +96,10 @@ NonInteractiveMultiParty,

} #[derive(Clone, PartialEq)] pub struct BoolParameters<El> { + /// RLWE secret key distribution + rlwe_secret_key_dist: SecretKeyDistribution, + /// LWE secret key distribtuion + lwe_secret_key_dist: SecretKeyDistribution, /// RLWE ciphertext modulus Q rlwe_q: CiphertextModulus<El>, /// LWE ciphertext modulus q (usually referred to as Q_{ks})

@@ -153,6 +167,14 @@ variant: ParameterVariant,

} impl<El> BoolParameters<El> { + pub(crate) fn rlwe_secret_key_dist(&self) -> &SecretKeyDistribution { + &self.rlwe_secret_key_dist + } + + pub(crate) fn lwe_secret_key_dist(&self) -> &SecretKeyDistribution { + &self.lwe_secret_key_dist + } + pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> { &self.rlwe_q }

@@ -502,6 +524,8 @@ }

} pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(1152921504606830593), lwe_q: CiphertextModulus::new_non_native(1 << 20), br_q: 1 << 11,

@@ -524,6 +548,8 @@ variant: ParameterVariant::MultiParty,

}; pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(36028797018820609), lwe_q: CiphertextModulus::new_non_native(1 << 20), br_q: 1 << 11,

@@ -546,6 +572,8 @@ variant: ParameterVariant::MultiParty,

}; pub(crate) const I_2P: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(18014398509404161), lwe_q: CiphertextModulus::new_non_native(1 << 15), br_q: 1 << 11,

@@ -568,6 +596,8 @@ variant: ParameterVariant::MultiParty,

}; pub(crate) const NI_2P: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(18014398509404161), lwe_q: CiphertextModulus::new_non_native(1 << 15), br_q: 1 << 11,

@@ -593,6 +623,8 @@ variant: ParameterVariant::NonInteractiveMultiParty,

}; pub(crate) const NI_4P: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(18014398509404161), lwe_q: CiphertextModulus::new_non_native(1 << 16), br_q: 1 << 11,

@@ -619,6 +651,8 @@ };

#[cfg(test)] pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { + rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution, + lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution, rlwe_q: CiphertextModulus::new_non_native(268369921u64), lwe_q: CiphertextModulus::new_non_native(1 << 16), br_q: 1 << 9,
M src/random.rs → src/random.rs

@@ -1,7 +1,7 @@

use std::cell::RefCell; use itertools::izip; -use num_traits::{PrimInt, Zero}; +use num_traits::{FromPrimitive, PrimInt, Zero}; use rand::{distributions::Uniform, Rng, RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use rand_distr::{uniform::SampleUniform, Distribution};

@@ -33,6 +33,15 @@ where

M: ?Sized, { /// Fill container with random elements of type of its elements + fn random_fill(&mut self, container: &mut M); +} + +pub trait RandomFillGaussian<M> +where + M: ?Sized, +{ + /// Fill container with random elements sampled from normal distribtuion + /// with \mu = 0.0 and \sigma = 3.19. fn random_fill(&mut self, container: &mut M); }

@@ -129,6 +138,23 @@ container.iter_mut()

) .for_each(|(from, to)| { *to = from; + }); + } +} + +impl<T> RandomFillGaussian<[T]> for DefaultSecureRng +where + T: FromPrimitive, +{ + fn random_fill(&mut self, container: &mut [T]) { + izip!( + rand_distr::Normal::new(0.0, 3.19f64) + .unwrap() + .sample_iter(&mut self.rng), + container.iter_mut() + ) + .for_each(|(from, to)| { + *to = T::from_f64(from).unwrap(); }); } }