Browse Source

fix noise test

par-agg-key-shares
Janmajaya Mall 11 months ago
parent
commit
ec01571eb1
3 changed files with 349 additions and 160 deletions
  1. +344
    -155
      src/bool/evaluator.rs
  2. +3
    -3
      src/bool/parameters.rs
  3. +2
    -2
      src/random.rs

+ 344
- 155
src/bool/evaluator.rs

@ -566,76 +566,21 @@ where
} }
// rgsw cts // rgsw cts
let (rgswrgsw_d_a, rgswrgsw_d_b) = value.parameters.rgsw_rgsw_decomposition_count();
let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count(); let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
// d_a and d_b may differ for RGSWxRGSW multiplication and RLWExRGSW
// multiplication. After this point RGSW ciphertexts will only be used for
// RLWExRGSW multiplication (in blind rotation). Thus we drop any additional
// RLWE ciphertexts in incoming collective RGSW ciphertexts, which are
// result of RGSWxRGSW multiplications.
let rgsw_ct_rows_in = rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 * 2;
let rgsw_ct_rows_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
let rgsw_cts = value let rgsw_cts = value
.rgsw_cts .rgsw_cts
.iter() .iter()
.map(|ct_i_in| { .map(|ct_i_in| {
assert!(ct_i_in.dimension() == (rgsw_ct_rows_in, rlwe_n));
let mut eval_ct_i_out = M::zeros(rgsw_ct_rows_out, rlwe_n);
assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
// RLWE'(-sm) part A
izip!(
eval_ct_i_out.iter_rows_mut().take(rlrg_d_a.0),
ct_i_in.iter_rows().take(rlrg_d_a.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlwe_nttop.forward(to_ri.as_mut());
});
// RLWE'(-sm) part B
izip!(
eval_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0)
.take(rlrg_d_a.0),
ct_i_in.iter_rows().skip(rgswrgsw_d_a.0).take(rlrg_d_a.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlwe_nttop.forward(to_ri.as_mut());
});
// RLWE'(m) Part A
izip!(
eval_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0 * 2)
.take(rlrg_d_b.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 * 2)
.take(rlrg_d_b.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlwe_nttop.forward(to_ri.as_mut());
});
// RLWE'(m) Part B
izip!(
eval_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0 * 2 + rlrg_d_b.0)
.take(rlrg_d_b.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0)
.take(rlrg_d_b.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlwe_nttop.forward(to_ri.as_mut());
});
izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlwe_nttop.forward(to_ri.as_mut());
},
);
eval_ct_i_out eval_ct_i_out
}) })
@ -1355,33 +1300,105 @@ where
let mut tmp_rgsw = let mut tmp_rgsw =
RgswCiphertext::<M, _>::empty(rlwe_n, &rgsw_by_rgsw_decomposer, rlwe_q.clone()).data; RgswCiphertext::<M, _>::empty(rlwe_n, &rgsw_by_rgsw_decomposer, rlwe_q.clone()).data;
let rgsw_cts = (0..lwe_n)
.into_iter()
.map(|index| {
// copy over rgsw ciphertext for index^th secret element from first share and
// treat it as accumulating rgsw ciphertext
let mut rgsw_i = shares[0].rgsw_cts[index].clone();
shares.iter().skip(1).for_each(|si| {
// copy over si's RGSW[index] ciphertext and send to evaluation domain
izip!(tmp_rgsw.iter_rows_mut(), si.rgsw_cts[index].iter_rows()).for_each(
|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlweq_nttop.forward(to_ri.as_mut())
},
);
let rgsw_cts = (0..lwe_n).into_iter().map(|index| {
// copy over rgsw ciphertext for index^th secret element from first share and
// treat it as accumulating rgsw ciphertext
let mut rgsw_i = shares[0].rgsw_cts[index].clone();
shares.iter().skip(1).for_each(|si| {
// copy over si's RGSW[index] ciphertext and send to evaluation domain
izip!(tmp_rgsw.iter_rows_mut(), si.rgsw_cts[index].iter_rows()).for_each(
|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
rlweq_nttop.forward(to_ri.as_mut())
},
);
rgsw_by_rgsw_inplace(
&mut rgsw_i,
&tmp_rgsw,
&rgsw_by_rgsw_decomposer,
&mut scratch_matrix,
rlweq_nttop,
rlweq_modop,
);
rgsw_by_rgsw_inplace(
&mut rgsw_i,
&tmp_rgsw,
&rgsw_by_rgsw_decomposer,
&mut scratch_matrix,
rlweq_nttop,
rlweq_modop,
);
});
rgsw_i
});
// d_a and d_b may differ for RGSWxRGSW multiplication and RLWExRGSW
// multiplication. After this point RGSW ciphertexts will only be used for
// RLWExRGSW multiplication (in blind rotation). Thus we drop any additional
// RLWE ciphertexts in RGSW ciphertexts after RGSw x RGSW multiplication
let (rgswrgsw_d_a, rgswrgsw_d_b) = self.pbs_info.parameters.rgsw_rgsw_decomposition_count();
let (rlrg_d_a, rlrg_d_b) = self.pbs_info.parameters.rlwe_rgsw_decomposition_count();
let rgsw_ct_rows_in = rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 * 2;
let rgsw_ct_rows_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
assert!(rgswrgsw_d_a.0 >= rlrg_d_a.0, "RGSWxRGSW part A decomposition count {} must be >= RLWExRGSW part A decomposition count {}", rgswrgsw_d_a.0 , rlrg_d_a.0);
assert!(rgswrgsw_d_b.0 >= rlrg_d_b.0, "RGSWxRGSW part B decomposition count {} must be >= RLWExRGSW part B decomposition count {}", rgswrgsw_d_b.0 , rlrg_d_b.0);
let rgsw_cts = rgsw_cts
.map(|ct_i_in| {
assert!(ct_i_in.dimension() == (rgsw_ct_rows_in, rlwe_n));
let mut reduced_ct_i_out = M::zeros(rgsw_ct_rows_out, rlwe_n);
// RLWE'(-sm) part A
izip!(
reduced_ct_i_out.iter_rows_mut().take(rlrg_d_a.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 - rlrg_d_a.0)
.take(rlrg_d_a.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
});
// RLWE'(-sm) part B
izip!(
reduced_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0)
.take(rlrg_d_a.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 + (rgswrgsw_d_a.0 - rlrg_d_a.0))
.take(rlrg_d_a.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
});
// RLWE'(m) Part A
izip!(
reduced_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0 * 2)
.take(rlrg_d_b.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 * 2 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
.take(rlrg_d_b.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
});
// RLWE'(m) Part B
izip!(
reduced_ct_i_out
.iter_rows_mut()
.skip(rlrg_d_a.0 * 2 + rlrg_d_b.0)
.take(rlrg_d_b.0),
ct_i_in
.iter_rows()
.skip(rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
.take(rlrg_d_b.0)
)
.for_each(|(to_ri, from_ri)| {
to_ri.as_mut().copy_from_slice(from_ri.as_ref());
}); });
rgsw_i
reduced_ct_i_out
}) })
.collect_vec(); .collect_vec();
@ -1875,8 +1892,6 @@ impl WithLocal for PBSTracer>> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::iter::Sum;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use rand_distr::Uniform; use rand_distr::Uniform;
@ -1884,7 +1899,7 @@ mod tests {
backend::{GetModulus, ModInit, ModularOpsU64, WordSizeModulus}, backend::{GetModulus, ModInit, ModularOpsU64, WordSizeModulus},
bool, bool,
ntt::NttBackendU64, ntt::NttBackendU64,
random::DEFAULT_RNG,
random::{RandomElementInModulus, DEFAULT_RNG},
rgsw::{ rgsw::{
self, measure_noise, public_key_encrypt_rlwe, secret_key_encrypt_rlwe, self, measure_noise, public_key_encrypt_rlwe, secret_key_encrypt_rlwe,
tests::{_measure_noise_rgsw, _sk_encrypt_rlwe}, tests::{_measure_noise_rgsw, _sk_encrypt_rlwe},
@ -2232,7 +2247,7 @@ mod tests {
>::new(MP_BOOL_PARAMS); >::new(MP_BOOL_PARAMS);
let (parties, collective_pk, _, _, server_key_eval, ideal_client_key) = let (parties, collective_pk, _, _, server_key_eval, ideal_client_key) =
_multi_party_all_keygen(&bool_evaluator, 2);
_multi_party_all_keygen(&bool_evaluator, 8);
let mut m0 = true; let mut m0 = true;
let mut m1 = false; let mut m1 = false;
@ -2339,23 +2354,7 @@ mod tests {
} }
#[test] #[test]
fn tester() {
// pub(super) const TEST_MP_BOOL_PARAMS: BoolParameters<u64> =
// BoolParameters::<u64> { rlwe_q: 1152921504606830593,
// rlwe_logq: 60,
// lwe_q: 1 << 20,
// lwe_logq: 20,
// br_q: 1 << 11,
// rlwe_n: 1 << 11,
// lwe_n: 500,
// d_rgsw: 4,
// logb_rgsw: 12,
// d_lwe: 5,
// logb_lwe: 4,
// g: 5,
// w: 1,
// };
fn noise_tester() {
let bool_evaluator = BoolEvaluator::< let bool_evaluator = BoolEvaluator::<
Vec<Vec<u64>>, Vec<Vec<u64>>,
NttBackendU64, NttBackendU64,
@ -2365,7 +2364,7 @@ mod tests {
// let (_, collective_pk, _, _, server_key_eval, ideal_client_key) = // let (_, collective_pk, _, _, server_key_eval, ideal_client_key) =
// _multi_party_all_keygen(&bool_evaluator, 20); // _multi_party_all_keygen(&bool_evaluator, 20);
let no_of_parties = 2;
let no_of_parties = 32;
let lwe_q = bool_evaluator.pbs_info.parameters.lwe_q(); let lwe_q = bool_evaluator.pbs_info.parameters.lwe_q();
let rlwe_q = bool_evaluator.pbs_info.parameters.rlwe_q(); let rlwe_q = bool_evaluator.pbs_info.parameters.rlwe_q();
let lwe_n = bool_evaluator.pbs_info.parameters.lwe_n().0; let lwe_n = bool_evaluator.pbs_info.parameters.lwe_n().0;
@ -2374,16 +2373,19 @@ mod tests {
let rlwe_nttop = &bool_evaluator.pbs_info.rlwe_nttop; let rlwe_nttop = &bool_evaluator.pbs_info.rlwe_nttop;
let rlwe_modop = &bool_evaluator.pbs_info.rlwe_modop; let rlwe_modop = &bool_evaluator.pbs_info.rlwe_modop;
let rlwe_rgsw_decomposer = &bool_evaluator.pbs_info.rlwe_rgsw_decomposer;
let rlwe_rgsw_gadget_a = rlwe_rgsw_decomposer.0.gadget_vector();
let rlwe_rgsw_gadget_b = rlwe_rgsw_decomposer.1.gadget_vector();
// let rgsw_rgsw_decomposer = &bool_evaluator // let rgsw_rgsw_decomposer = &bool_evaluator
// .pbs_info // .pbs_info
// .parameters // .parameters
// .rgsw_rgsw_decomposer::<DefaultDecomposer<u64>>(); // .rgsw_rgsw_decomposer::<DefaultDecomposer<u64>>();
// let rgsw_rgsw_gagdet_a = rgsw_rgsw_decomposer.a().gadget_vector();
// let rgsw_rgsw_gagdet_b = rgsw_rgsw_decomposer.b().gadget_vector();
// let rgsw_rgsw_gadget_a = rgsw_rgsw_decomposer.0.gadget_vector();
// let rgsw_rgsw_gadget_b = rgsw_rgsw_decomposer.1.gadget_vector();
let rlwe_rgsw_decomposer = &bool_evaluator.pbs_info.rlwe_rgsw_decomposer;
let rlwe_rgsw_gadget_a = rlwe_rgsw_decomposer.0.gadget_vector();
let rlwe_rgsw_gadget_b = rlwe_rgsw_decomposer.1.gadget_vector();
let auto_decomposer = &bool_evaluator.pbs_info.auto_decomposer;
let auto_gadget = auto_decomposer.gadget_vector();
let parties = (0..no_of_parties) let parties = (0..no_of_parties)
.map(|_| bool_evaluator.client_key()) .map(|_| bool_evaluator.client_key())
@ -2414,7 +2416,7 @@ mod tests {
}; };
// check noise in freshly encrypted RLWE ciphertext (ie var_fresh) // check noise in freshly encrypted RLWE ciphertext (ie var_fresh)
if false {
if true {
let mut rng = DefaultSecureRng::new(); let mut rng = DefaultSecureRng::new();
let mut check = Stats { samples: vec![] }; let mut check = Stats { samples: vec![] };
for _ in 0..10 { for _ in 0..10 {
@ -2504,12 +2506,14 @@ mod tests {
m_si[s_i as usize] = 1; m_si[s_i as usize] = 1;
} }
// RLWE(-sm)
// RLWE'(-sm)
let mut neg_s_eval = let mut neg_s_eval =
Vec::<u64>::try_convert_from(ideal_client_key.sk_rlwe.values(), rlwe_q); Vec::<u64>::try_convert_from(ideal_client_key.sk_rlwe.values(), rlwe_q);
rlwe_modop.elwise_neg_mut(&mut neg_s_eval); rlwe_modop.elwise_neg_mut(&mut neg_s_eval);
rlwe_nttop.forward(&mut neg_s_eval); rlwe_nttop.forward(&mut neg_s_eval);
for j in 0..rlwe_rgsw_decomposer.a().decomposition_count() { for j in 0..rlwe_rgsw_decomposer.a().decomposition_count() {
// RLWE(B^{j} * -s[X]*X^{s_lwe[i]})
// -s[X]*X^{s_lwe[i]}*B_j // -s[X]*X^{s_lwe[i]}*B_j
let mut m_ideal = m_si.clone(); let mut m_ideal = m_si.clone();
rlwe_nttop.forward(m_ideal.as_mut_slice()); rlwe_nttop.forward(m_ideal.as_mut_slice());
@ -2541,6 +2545,8 @@ mod tests {
// RLWE'(m) // RLWE'(m)
for j in 0..rlwe_rgsw_decomposer.b().decomposition_count() { for j in 0..rlwe_rgsw_decomposer.b().decomposition_count() {
// RLWE(B^{j} * X^{s_lwe[i]})
// X^{s_lwe[i]}*B_j // X^{s_lwe[i]}*B_j
let mut m_ideal = m_si.clone(); let mut m_ideal = m_si.clone();
rlwe_modop rlwe_modop
@ -2579,24 +2585,21 @@ mod tests {
); );
} }
// server key in Evaluation domain
let server_key_eval_domain =
ServerKeyEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
&seeded_server_key,
);
// check noise in RLWE x RGSW(X^{s_i}) where RGSW is accunulated RGSW ciphertext // check noise in RLWE x RGSW(X^{s_i}) where RGSW is accunulated RGSW ciphertext
if false {
if true {
let mut check = Stats { samples: vec![] }; let mut check = Stats { samples: vec![] };
// server key in Evaluation domain
let server_key_eval_domain =
ServerKeyEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
&seeded_server_key,
);
izip!( izip!(
ideal_client_key.sk_lwe.values(), ideal_client_key.sk_lwe.values(),
seeded_server_key.rgsw_cts.iter()
server_key_eval_domain.rgsw_cts.iter()
) )
.for_each(|(s_i, rgsw_ct_i)| { .for_each(|(s_i, rgsw_ct_i)| {
let mut rgsw_ct_i = rgsw_ct_i.clone();
rgsw_ct_i
.iter_mut()
.for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
let mut m = vec![0u64; rlwe_n]; let mut m = vec![0u64; rlwe_n];
RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, m.as_mut_slice()); RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, m.as_mut_slice());
let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2]; let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2];
@ -2610,12 +2613,15 @@ mod tests {
); );
// RLWE(m*X^{s[i]}) = RLWE(m) x RGSW(X^{s[i]}) // RLWE(m*X^{s[i]}) = RLWE(m) x RGSW(X^{s[i]})
let mut rlwe_after = RlweCiphertext::<_, DefaultSecureRng>::new_trivial(vec![
vec![0u64; rlwe_n],
m.clone(),
]);
// let mut rlwe_after =
// RlweCiphertext::<_, DefaultSecureRng>::from_raw(rlwe_ct.clone(), false);
// let mut rlwe_after = RlweCiphertext::<_, DefaultSecureRng>::new_trivial(vec![
// vec![0u64; rlwe_n],
// m.clone(),
// ]);
let mut rlwe_after = RlweCiphertext::<_, DefaultSecureRng> {
data: rlwe_ct.clone(),
is_trivial: false,
_phatom: PhantomData,
};
let mut scratch = vec![ let mut scratch = vec![
vec![0u64; rlwe_n]; vec![0u64; rlwe_n];
std::cmp::max( std::cmp::max(
@ -2625,7 +2631,7 @@ mod tests {
]; ];
rlwe_by_rgsw( rlwe_by_rgsw(
&mut rlwe_after, &mut rlwe_after,
&rgsw_ct_i,
rgsw_ct_i,
&mut scratch, &mut scratch,
rlwe_rgsw_decomposer, rlwe_rgsw_decomposer,
rlwe_nttop, rlwe_nttop,
@ -2642,14 +2648,14 @@ mod tests {
} }
// (m+e) * m1 // (m+e) * m1
let mut m_plus_e_times_m1 = m.clone();
// decrypt_rlwe(
// &rlwe_ct,
// ideal_client_key.sk_rlwe.values(),
// &mut m_plus_e_times_m1,
// rlwe_nttop,
// rlwe_modop,
// );
let mut m_plus_e_times_m1 = vec![0u64; rlwe_n];
decrypt_rlwe(
&rlwe_ct,
ideal_client_key.sk_rlwe.values(),
&mut m_plus_e_times_m1,
rlwe_nttop,
rlwe_modop,
);
rlwe_nttop.forward(m_plus_e_times_m1.as_mut_slice()); rlwe_nttop.forward(m_plus_e_times_m1.as_mut_slice());
rlwe_nttop.forward(m1.as_mut_slice()); rlwe_nttop.forward(m1.as_mut_slice());
rlwe_modop.elwise_mul_mut(m_plus_e_times_m1.as_mut_slice(), m1.as_slice()); rlwe_modop.elwise_mul_mut(m_plus_e_times_m1.as_mut_slice(), m1.as_slice());
@ -2657,8 +2663,8 @@ mod tests {
// Resulting RLWE ciphertext will equal: (m0m1 + em1) + e_{rlsw x rgsw}. // Resulting RLWE ciphertext will equal: (m0m1 + em1) + e_{rlsw x rgsw}.
// Hence, resulting rlwe ciphertext will have error em1 + e_{rlwe x rgsw}. // Hence, resulting rlwe ciphertext will have error em1 + e_{rlwe x rgsw}.
// Here we're only concerned with e_{rlwe x rgsw}, that is noise caused due to
// RLWExRGSW. Also note, in practice m1 is a monomial, for ex, X^{s_{i}}, for
// Here we're only concerned with e_{rlwe x rgsw}, that is noise added by
// RLWExRGSW. Also note in practice m1 is a monomial, for ex, X^{s_{i}}, for
// some i and var(em1) = var(e). // some i and var(em1) = var(e).
let mut m_plus_e_times_m1_more_e = vec![0u64; rlwe_n]; let mut m_plus_e_times_m1_more_e = vec![0u64; rlwe_n];
decrypt_rlwe( decrypt_rlwe(
@ -2675,14 +2681,14 @@ mod tests {
m_plus_e_times_m1.as_slice(), m_plus_e_times_m1.as_slice(),
); );
let noise = measure_noise(
&rlwe_after,
&m_plus_e_times_m1,
rlwe_nttop,
rlwe_modop,
ideal_client_key.sk_rlwe.values(),
);
print!("NOISE: {}", noise);
// let noise = measure_noise(
// &rlwe_after,
// &m_plus_e_times_m1,
// rlwe_nttop,
// rlwe_modop,
// ideal_client_key.sk_rlwe.values(),
// );
// print!("NOISE: {}", noise);
check.add_more(&Vec::<i64>::try_convert_from( check.add_more(&Vec::<i64>::try_convert_from(
&m_plus_e_times_m1_more_e, &m_plus_e_times_m1_more_e,
@ -2695,6 +2701,189 @@ mod tests {
check.std_dev().abs().log2() check.std_dev().abs().log2()
) )
} }
// check noise in Auto key
if true {
let mut check = Stats { samples: vec![] };
let mut neg_s_poly =
Vec::<u64>::try_convert_from(ideal_client_key.sk_rlwe.values(), rlwe_q);
rlwe_modop.elwise_neg_mut(neg_s_poly.as_mut_slice());
let g = bool_evaluator.pbs_info.g();
for i in [-g, g] {
// -s[X^k]
let (auto_indices, auto_sign) = generate_auto_map(rlwe_n, i);
let mut neg_s_poly_auto_i = vec![0u64; rlwe_n];
izip!(neg_s_poly.iter(), auto_indices.iter(), auto_sign.iter()).for_each(
|(v, to_i, to_sign)| {
if !to_sign {
neg_s_poly_auto_i[*to_i] = rlwe_modop.neg(v);
} else {
neg_s_poly_auto_i[*to_i] = *v;
}
},
);
let mut auto_key_i = server_key_eval_domain.galois_key_for_auto(i).clone();
// send i^th auto key to coefficient domain
auto_key_i
.iter_mut()
.for_each(|r| rlwe_nttop.backward(r.as_mut_slice()));
auto_gadget.iter().enumerate().for_each(|(i, b_i)| {
// B^i * -s[X^k]
let mut m_ideal = neg_s_poly_auto_i.clone();
rlwe_modop.elwise_scalar_mul_mut(m_ideal.as_mut_slice(), b_i);
let mut m_out = vec![0u64; rlwe_n];
let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2];
rlwe_ct[0].copy_from_slice(&auto_key_i[i]);
rlwe_ct[1].copy_from_slice(
&auto_key_i[auto_decomposer.decomposition_count() + i],
);
decrypt_rlwe(
&rlwe_ct,
ideal_client_key.sk_rlwe.values(),
&mut m_out,
rlwe_nttop,
rlwe_modop,
);
// diff
rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(), m_ideal.as_slice());
check.add_more(&Vec::<i64>::try_convert_from(&m_out, rlwe_q));
});
}
println!("Auto key noise std dev: {}", check.std_dev().abs().log2());
}
// check noise in RLWE(X^k) after sending RLWE(X) -> RLWE(X^k) using collective
// auto key
if true {
let mut check = Stats { samples: vec![] };
let g = bool_evaluator.pbs_info.g();
for i in [-g, g] {
for _ in 0..10 {
let mut m = vec![0u64; rlwe_n];
RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, m.as_mut_slice());
let mut rlwe_ct = RlweCiphertext::<_, DefaultSecureRng> {
data: vec![vec![0u64; rlwe_n]; 2],
is_trivial: false,
_phatom: PhantomData,
};
public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
&mut rlwe_ct,
&collective_pk.key,
&m,
rlwe_modop,
rlwe_nttop,
&mut rng,
);
// We're only interested in noise increased as a result of automorphism.
// Hence, we take m+e as the bench.
let mut m_plus_e = vec![0u64; rlwe_n];
decrypt_rlwe(
&rlwe_ct,
ideal_client_key.sk_rlwe.values(),
&mut m_plus_e,
rlwe_nttop,
rlwe_modop,
);
let auto_key = server_key_eval_domain.galois_key_for_auto(i);
let (auto_map_index, auto_map_sign) = generate_auto_map(rlwe_n, i);
let mut scratch =
vec![vec![0u64; rlwe_n]; auto_decomposer.decomposition_count() + 2];
galois_auto(
&mut rlwe_ct,
auto_key,
&mut scratch,
&auto_map_index,
&auto_map_sign,
rlwe_modop,
rlwe_nttop,
auto_decomposer,
);
// send m+e from X to X^k
let mut m_plus_e_auto = vec![0u64; rlwe_n];
izip!(m_plus_e.iter(), auto_map_index.iter(), auto_map_sign.iter())
.for_each(|(v, to_index, to_sign)| {
if !to_sign {
m_plus_e_auto[*to_index] = rlwe_modop.neg(v);
} else {
m_plus_e_auto[*to_index] = *v
}
});
let mut m_out = vec![0u64; rlwe_n];
decrypt_rlwe(
&rlwe_ct,
ideal_client_key.sk_rlwe.values(),
&mut m_out,
rlwe_nttop,
rlwe_modop,
);
// diff
rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(), m_plus_e_auto.as_slice());
check.add_more(&Vec::<i64>::try_convert_from(m_out.as_slice(), rlwe_q));
}
}
println!("Rlwe Auto Noise Std: {}", check.std_dev().abs().log2());
}
// Check noise growth in ksk
// TODO check in LWE key switching keys
if true {
// 1. encrypt LWE ciphertext
// 2. Key switching
// 3.
let mut check = Stats { samples: vec![] };
for _ in 0..1024 {
// Encrypt m \in Q_{ks} using RLWE sk
let mut lwe_in_ct = vec![0u64; rlwe_n + 1];
let m = RandomElementInModulus::random(&mut rng, &lwe_q.q().unwrap());
encrypt_lwe(
&mut lwe_in_ct,
&m,
ideal_client_key.sk_rlwe.values(),
lwe_modop,
&mut rng,
);
// Key switch
let mut lwe_out = vec![0u64; lwe_n + 1];
lwe_key_switch(
&mut lwe_out,
&lwe_in_ct,
server_key_eval_domain.lwe_ksk(),
lwe_modop,
bool_evaluator.pbs_info.lwe_decomposer(),
);
// We only care about noise added by LWE key switch
// m+e
let m_plus_e =
decrypt_lwe(&lwe_in_ct, ideal_client_key.sk_rlwe.values(), lwe_modop);
let m_plus_e_plus_lwe_ksk_noise =
decrypt_lwe(&lwe_out, ideal_client_key.sk_lwe.values(), lwe_modop);
let diff = lwe_modop.sub(&m_plus_e_plus_lwe_ksk_noise, &m_plus_e);
check.add_more(&vec![lwe_q.map_element_to_i64(&diff)]);
}
println!("Lwe ksk std dev: {}", check.std_dev().abs().log2());
}
} }
// Check noise in fresh RGSW ciphertexts, ie X^{s_j[i]}, must equal noise in // Check noise in fresh RGSW ciphertexts, ie X^{s_j[i]}, must equal noise in

+ 3
- 3
src/bool/parameters.rs

@ -301,15 +301,15 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters = BoolParameters:: {
pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> { pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
rlwe_q: CiphertextModulus::new_non_native(1152921504606830593), rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
lwe_q: CiphertextModulus::new_non_native(1 << 20), lwe_q: CiphertextModulus::new_non_native(1 << 20),
br_q: 1 << 10,
br_q: 1 << 11,
rlwe_n: PolynomialSize(1 << 11), rlwe_n: PolynomialSize(1 << 11),
lwe_n: LweDimension(500), lwe_n: LweDimension(500),
lwe_decomposer_base: DecompostionLogBase(4), lwe_decomposer_base: DecompostionLogBase(4),
lwe_decomposer_count: DecompositionCount(5), lwe_decomposer_count: DecompositionCount(5),
rlrg_decomposer_base: DecompostionLogBase(12), rlrg_decomposer_base: DecompostionLogBase(12),
rlrg_decomposer_count: (DecompositionCount(5), DecompositionCount(5)),
rlrg_decomposer_count: (DecompositionCount(2), DecompositionCount(2)),
rgrg_decomposer_base: DecompostionLogBase(12), rgrg_decomposer_base: DecompostionLogBase(12),
rgrg_decomposer_count: (DecompositionCount(5), DecompositionCount(5)),
rgrg_decomposer_count: (DecompositionCount(5), DecompositionCount(4)),
auto_decomposer_base: DecompostionLogBase(12), auto_decomposer_base: DecompostionLogBase(12),
auto_decomposer_count: DecompositionCount(5), auto_decomposer_count: DecompositionCount(5),
g: 5, g: 5,

+ 2
- 2
src/random.rs

@ -1,7 +1,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use itertools::izip; use itertools::izip;
use num_traits::PrimInt;
use num_traits::{PrimInt, Zero};
use rand::{distributions::Uniform, thread_rng, CryptoRng, Rng, RngCore, SeedableRng}; use rand::{distributions::Uniform, thread_rng, CryptoRng, Rng, RngCore, SeedableRng};
use rand_chacha::ChaCha8Rng; use rand_chacha::ChaCha8Rng;
use rand_distr::{uniform::SampleUniform, Distribution}; use rand_distr::{uniform::SampleUniform, Distribution};
@ -149,7 +149,7 @@ where
impl<T> RandomElementInModulus<T, T> for DefaultSecureRng impl<T> RandomElementInModulus<T, T> for DefaultSecureRng
where where
T: PrimInt + SampleUniform,
T: Zero + SampleUniform,
{ {
fn random(&mut self, modulus: &T) -> T { fn random(&mut self, modulus: &T) -> T {
Uniform::new(T::zero(), modulus).sample(&mut self.rng) Uniform::new(T::zero(), modulus).sample(&mut self.rng)

Loading…
Cancel
Save