phantom-zone/src/bool/print_noise.rs
src/bool/print_noise.rsRaw
1use std::{fmt::Debug, iter::Sum, thread::panicking};
2
3use itertools::izip;
4use num_traits::{FromPrimitive, Pow, PrimInt, Zero};
5use rand_distr::uniform::SampleUniform;
6
7use crate::{
8 backend::{GetModulus, Modulus},
9 decomposer::RlweDecomposer,
10 lwe::{decrypt_lwe, lwe_key_switch},
11 parameters::{self, BoolParameters, CiphertextModulus},
12 pbs::PbsKey,
13 random::{DefaultSecureRng, RandomFillUniformInModulus},
14 rgsw::{decrypt_rlwe, galois_auto, IsTrivial, RlweCiphertext},
15 utils::{encode_x_pow_si_with_emebedding_factor, tests::Stats, TryConvertFrom1, WithLocal},
16 ArithmeticOps, ClientKey, Decomposer, DefaultDecomposer, MatrixEntity, MatrixMut, ModInit, Ntt,
17 NttInit, RowEntity, RowMut, VectorOps,
18};
19
20use super::{
21 keys::{
22 tests::{ideal_sk_lwe, ideal_sk_rlwe},
23 SeededMultiPartyServerKey, ServerKeyEvaluationDomain,
24 },
25 BoolEvaluator,
26};
27
28struct ServerKeyStats<T> {
29 brk_rgsw_cts: (Stats<T>, Stats<T>),
30 post_1_auto: Stats<T>,
31 post_lwe_key_switch: Stats<T>,
32}
33
34impl<T: PrimInt + FromPrimitive + Debug + Sum> ServerKeyStats<T>
35where
36 T: for<'a> Sum<&'a T>,
37{
38 fn new() -> Self {
39 ServerKeyStats {
40 brk_rgsw_cts: (Stats::default(), Stats::default()),
41 post_1_auto: Stats::default(),
42 post_lwe_key_switch: Stats::default(),
43 }
44 }
45
46 fn add_noise_brk_rgsw_cts_nsm(&mut self, noise: &[T]) {
47 self.brk_rgsw_cts.0.add_more(noise);
48 }
49
50 fn add_noise_brk_rgsw_cts_m(&mut self, noise: &[T]) {
51 self.brk_rgsw_cts.1.add_more(noise);
52 }
53
54 fn add_noise_post_1_auto(&mut self, noise: &[T]) {
55 self.post_1_auto.add_more(&noise);
56 }
57
58 fn add_noise_post_kwe_key_switch(&mut self, noise: &[T]) {
59 self.post_lwe_key_switch.add_more(&noise);
60 }
61}
62
63fn collect_server_key_stats<
64 M: MatrixEntity + MatrixMut,
65 D: Decomposer<Element = M::MatElement>,
66 NttOp: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
67 ModOp: VectorOps<Element = M::MatElement>
68 + ArithmeticOps<Element = M::MatElement>
69 + ModInit<M = CiphertextModulus<M::MatElement>>
70 + GetModulus<M = CiphertextModulus<M::MatElement>, Element = M::MatElement>,
71>(
72 parameters: BoolParameters<M::MatElement>,
73 client_keys: &[ClientKey],
74 server_key: &ServerKeyEvaluationDomain<M, BoolParameters<u64>, DefaultSecureRng, NttOp>,
75) -> ServerKeyStats<i64>
76where
77 M::R: RowMut + RowEntity + TryConvertFrom1<[i32], CiphertextModulus<M::MatElement>> + Clone,
78 M::MatElement: Copy + PrimInt + FromPrimitive + SampleUniform + Zero + Debug,
79{
80 let ideal_sk_rlwe = ideal_sk_rlwe(client_keys);
81 let ideal_sk_lwe = ideal_sk_lwe(client_keys);
82
83 let embedding_factor = (2 * parameters.rlwe_n().0) / parameters.br_q();
84 let rlwe_n = parameters.rlwe_n().0;
85 let rlwe_q = parameters.rlwe_q();
86 let lwe_q = parameters.lwe_q();
87 let rlwe_modop = ModOp::new(rlwe_q.clone());
88 let rlwe_nttop = NttOp::new(rlwe_q, rlwe_n);
89 let lwe_modop = ModOp::new(*parameters.lwe_q());
90
91 let rlwe_x_rgsw_decomposer = parameters.rlwe_rgsw_decomposer::<D>();
92 let (rlwe_x_rgsw_gadget_a, rlwe_x_rgsw_gadget_b) = (
93 rlwe_x_rgsw_decomposer.a().gadget_vector(),
94 rlwe_x_rgsw_decomposer.b().gadget_vector(),
95 );
96
97 let lwe_ks_decomposer = parameters.lwe_decomposer::<D>();
98
99 let mut server_key_stats = ServerKeyStats::new();
100
101 let mut rng = DefaultSecureRng::new();
102
103 // RGSW ciphertext noise
104 // Check noise in RGSW ciphertexts of ideal LWE secret elements
105 {
106 izip!(ideal_sk_lwe.iter(), server_key.rgsw_cts().iter()).for_each(|(s_i, rgsw_ct_i)| {
107 // X^{s[i]}
108 let m_si = encode_x_pow_si_with_emebedding_factor::<M::R, _>(
109 *s_i,
110 embedding_factor,
111 rlwe_n,
112 rlwe_q,
113 );
114
115 // RLWE'(-sm)
116 let mut neg_s_eval = M::R::try_convert_from(ideal_sk_rlwe.as_slice(), rlwe_q);
117 rlwe_modop.elwise_neg_mut(neg_s_eval.as_mut());
118 rlwe_nttop.forward(neg_s_eval.as_mut());
119
120 for j in 0..rlwe_x_rgsw_decomposer.a().decomposition_count() {
121 // RLWE(B^{j} * -s[X]*X^{s_lwe[i]})
122
123 // -s[X]*X^{s_lwe[i]}*B_j
124 let mut m_ideal = m_si.clone();
125 rlwe_nttop.forward(m_ideal.as_mut());
126 rlwe_modop.elwise_mul_mut(m_ideal.as_mut(), neg_s_eval.as_ref());
127 rlwe_nttop.backward(m_ideal.as_mut());
128 rlwe_modop.elwise_scalar_mul_mut(m_ideal.as_mut(), &rlwe_x_rgsw_gadget_a[j]);
129
130 // RLWE(-s*X^{s_lwe[i]}*B_j)
131 let mut rlwe_ct = M::zeros(2, rlwe_n);
132 rlwe_ct
133 .get_row_mut(0)
134 .copy_from_slice(rgsw_ct_i.get_row_slice(j));
135 rlwe_ct.get_row_mut(1).copy_from_slice(
136 rgsw_ct_i.get_row_slice(j + rlwe_x_rgsw_decomposer.a().decomposition_count()),
137 );
138 // RGSW ciphertexts are in eval domain. We put RLWE ciphertexts back in
139 // coefficient domain
140 rlwe_ct
141 .iter_rows_mut()
142 .for_each(|r| rlwe_nttop.backward(r.as_mut()));
143
144 let mut m_back = M::R::zeros(rlwe_n);
145 decrypt_rlwe(
146 &rlwe_ct,
147 &ideal_sk_rlwe,
148 &mut m_back,
149 &rlwe_nttop,
150 &rlwe_modop,
151 );
152
153 // diff
154 rlwe_modop.elwise_sub_mut(m_back.as_mut(), m_ideal.as_ref());
155 server_key_stats.add_noise_brk_rgsw_cts_nsm(&Vec::<i64>::try_convert_from(
156 m_back.as_ref(),
157 rlwe_q,
158 ));
159 }
160
161 // RLWE'(m)
162 for j in 0..rlwe_x_rgsw_decomposer.b().decomposition_count() {
163 // RLWE(B^{j} * X^{s_lwe[i]})
164
165 // X^{s_lwe[i]}*B_j
166 let mut m_ideal = m_si.clone();
167 rlwe_modop.elwise_scalar_mul_mut(m_ideal.as_mut(), &rlwe_x_rgsw_gadget_b[j]);
168
169 // RLWE(X^{s_lwe[i]}*B_j)
170 let mut rlwe_ct = M::zeros(2, rlwe_n);
171 rlwe_ct.get_row_mut(0).copy_from_slice(
172 rgsw_ct_i
173 .get_row_slice(j + (2 * rlwe_x_rgsw_decomposer.a().decomposition_count())),
174 );
175 rlwe_ct
176 .get_row_mut(1)
177 .copy_from_slice(rgsw_ct_i.get_row_slice(
178 j + (2 * rlwe_x_rgsw_decomposer.a().decomposition_count())
179 + rlwe_x_rgsw_decomposer.b().decomposition_count(),
180 ));
181 rlwe_ct
182 .iter_rows_mut()
183 .for_each(|r| rlwe_nttop.backward(r.as_mut()));
184
185 let mut m_back = M::R::zeros(rlwe_n);
186 decrypt_rlwe(
187 &rlwe_ct,
188 &ideal_sk_rlwe,
189 &mut m_back,
190 &rlwe_nttop,
191 &rlwe_modop,
192 );
193
194 // diff
195 rlwe_modop.elwise_sub_mut(m_back.as_mut(), m_ideal.as_ref());
196 server_key_stats.add_noise_brk_rgsw_cts_m(&Vec::<i64>::try_convert_from(
197 m_back.as_ref(),
198 rlwe_q,
199 ));
200 }
201 });
202 }
203
204 // Noise in ciphertext after 1 auto
205 // For each auto key g^k. Sample random polynomial m(X) and multiply with
206 // -s(X^{g^k}) using key corresponding to auto g^k. Then check the noise in
207 // resutling RLWE(m(X) * -s(X^{g^k}))
208 {
209 let neg_s = {
210 let mut s = M::R::try_convert_from(ideal_sk_rlwe.as_slice(), rlwe_q);
211 rlwe_modop.elwise_neg_mut(s.as_mut());
212 s
213 };
214 let g = parameters.g();
215 let br_q = parameters.br_q();
216 let g_dlogs = parameters.auto_element_dlogs();
217 let auto_decomposer = parameters.auto_decomposer::<D>();
218 let mut scratch_matrix = M::zeros(auto_decomposer.decomposition_count() + 2, rlwe_n);
219
220 g_dlogs.iter().for_each(|k| {
221 let g_pow_k = if *k == 0 {
222 -(g as isize)
223 } else {
224 (g.pow(*k as u32) % br_q) as isize
225 };
226
227 // Send s(X) -> s(X^{g^k})
228 let (auto_index_map, auto_sign_map) = crate::rgsw::generate_auto_map(rlwe_n, g_pow_k);
229 let mut neg_s_g_k = M::R::zeros(rlwe_n);
230 izip!(
231 neg_s.as_ref().iter(),
232 auto_index_map.iter(),
233 auto_sign_map.iter()
234 )
235 .for_each(|(el, to_index, to_sign)| {
236 if !to_sign {
237 neg_s_g_k.as_mut()[*to_index] = rlwe_modop.neg(el);
238 } else {
239 neg_s_g_k.as_mut()[*to_index] = *el;
240 }
241 });
242
243 let mut m = M::R::zeros(rlwe_n);
244 RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q, m.as_mut());
245
246 // We want -m(X^{g^k})s(X^{g^k}) after key switch
247 let want_m = {
248 let mut m_g_k_eval = M::R::zeros(rlwe_n);
249 // send m(X) -> m(X^{g^k})
250 izip!(
251 m.as_ref().iter(),
252 auto_index_map.iter(),
253 auto_sign_map.iter()
254 )
255 .for_each(|(el, to_index, to_sign)| {
256 if !to_sign {
257 m_g_k_eval.as_mut()[*to_index] = rlwe_modop.neg(el);
258 } else {
259 m_g_k_eval.as_mut()[*to_index] = *el;
260 }
261 });
262
263 rlwe_nttop.forward(m_g_k_eval.as_mut());
264 let mut s_g_k = neg_s_g_k.clone();
265 rlwe_nttop.forward(s_g_k.as_mut());
266 rlwe_modop.elwise_mul_mut(m_g_k_eval.as_mut(), s_g_k.as_ref());
267 rlwe_nttop.backward(m_g_k_eval.as_mut());
268 m_g_k_eval
269 };
270
271 // RLWE auto sends part A, A(X), of RLWE to A(X^{g^k}) and then multiplies it
272 // with -s(X^{g^k}) using auto key. Deliberately set RLWE = (0, m(X))
273 // (ie. m in part A) to get back RLWE(-m(X^{g^k})s(X^{g^k}))
274 let mut rlwe = RlweCiphertext::<_, DefaultSecureRng>::new_trivial(M::zeros(2, rlwe_n));
275 rlwe.data.get_row_mut(0).copy_from_slice(m.as_ref());
276 rlwe.set_not_trivial();
277
278 galois_auto(
279 &mut rlwe,
280 server_key.galois_key_for_auto(*k),
281 &mut scratch_matrix,
282 &auto_index_map,
283 &auto_sign_map,
284 &rlwe_modop,
285 &rlwe_nttop,
286 &auto_decomposer,
287 );
288
289 // decrypt RLWE(-m(X)s(X^{g^k]}))
290 let mut back_m = M::R::zeros(rlwe_n);
291 decrypt_rlwe(&rlwe, &ideal_sk_rlwe, &mut back_m, &rlwe_nttop, &rlwe_modop);
292
293 // check difference
294 let mut diff = back_m;
295 rlwe_modop.elwise_sub_mut(diff.as_mut(), want_m.as_ref());
296 server_key_stats
297 .add_noise_post_1_auto(&Vec::<i64>::try_convert_from(diff.as_ref(), rlwe_q));
298 });
299
300 // sample random m
301
302 // key switch
303 }
304
305 // LWE Key switch
306 // LWE key switches LWE_in = LWE_{Q_ks,N, s}(m) = (b, a_0, ... a_N) -> LWE_out =
307 // LWE_{Q_{ks}, n, z}(m) = (b', a'_0, ..., a'n)
308 // If LWE_in = (0, a = {a_0, ..., a_N}), then LWE_out = LWE(-a \cdot s_{rlwe})
309 for _ in 0..1000 {
310 let mut lwe_in = M::R::zeros(rlwe_n + 1);
311 RandomFillUniformInModulus::random_fill(&mut rng, lwe_q, &mut lwe_in.as_mut()[1..]);
312
313 // Key switch
314 let mut lwe_out = M::R::zeros(parameters.lwe_n().0 + 1);
315 lwe_key_switch(
316 &mut lwe_out,
317 &lwe_in,
318 server_key.lwe_ksk(),
319 &lwe_modop,
320 &lwe_ks_decomposer,
321 );
322
323 // -a \cdot s
324 let mut want_m = M::MatElement::zero();
325 izip!(lwe_in.as_ref().iter().skip(1), ideal_sk_rlwe.iter()).for_each(|(a, b)| {
326 want_m = lwe_modop.add(
327 &want_m,
328 &lwe_modop.mul(a, &lwe_q.map_element_from_i64(*b as i64)),
329 );
330 });
331 want_m = lwe_modop.neg(&want_m);
332
333 // decrypt lwe out
334 let back_m = decrypt_lwe(&lwe_out, &ideal_sk_lwe, &lwe_modop);
335
336 let noise = lwe_modop.sub(&want_m, &back_m);
337 server_key_stats.add_noise_post_kwe_key_switch(&vec![lwe_q.map_element_to_i64(&noise)]);
338 }
339
340 server_key_stats
341 // Auto keys noise
342
343 // Ksk noise
344}
345
346#[cfg(test)]
347mod tests {
348 use itertools::Itertools;
349
350 use crate::{
351 aggregate_public_key_shares, aggregate_server_key_shares,
352 bool::keys::ServerKeyEvaluationDomain,
353 evaluator::MultiPartyCrs,
354 gen_client_key, gen_mp_keys_phase1, gen_mp_keys_phase2,
355 parameters::{BoolParameters, CiphertextModulus},
356 random::DefaultSecureRng,
357 set_mp_seed, set_parameter_set,
358 utils::WithLocal,
359 BoolEvaluator, DefaultDecomposer, ModularOpsU64, Ntt, NttBackendU64,
360 };
361
362 use super::collect_server_key_stats;
363
364 #[test]
365 fn qwerty() {
366 set_parameter_set(crate::ParameterSelector::HighCommunicationButFast2Party);
367 set_mp_seed(MultiPartyCrs::random().seed);
368 let parties = 2;
369 let cks = (0..parties).map(|_| gen_client_key()).collect_vec();
370 let pk_shares = cks.iter().map(|k| gen_mp_keys_phase1(k)).collect_vec();
371 let pk = aggregate_public_key_shares(&pk_shares);
372 let server_key_shares = cks
373 .iter()
374 .enumerate()
375 .map(|(index, k)| gen_mp_keys_phase2(k, index, parties, &pk))
376 .collect_vec();
377 let seeded_server_key = aggregate_server_key_shares(&server_key_shares);
378 let server_key_eval =
379 ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(
380 &seeded_server_key,
381 );
382
383 let parameters = BoolEvaluator::with_local(|e| e.parameters().clone());
384 let server_key_stats = collect_server_key_stats::<
385 _,
386 DefaultDecomposer<u64>,
387 NttBackendU64,
388 ModularOpsU64<CiphertextModulus<u64>>,
389 >(parameters, &cks, &server_key_eval);
390
391 println!(
392 "Rgsw nsm std log2 {}",
393 server_key_stats.brk_rgsw_cts.0.std_dev().abs().log2()
394 );
395 println!(
396 "Rgsw m std log2 {}",
397 server_key_stats.brk_rgsw_cts.1.std_dev().abs().log2()
398 );
399 println!(
400 "rlwe post 1 auto std log2 {}",
401 server_key_stats.post_1_auto.std_dev().abs().log2()
402 );
403 println!(
404 "key switching noise rlwe secret s to lwe secret z std log2 {}",
405 server_key_stats.post_lwe_key_switch.std_dev().abs().log2()
406 );
407 }
408}
409
410// #[test]
411// fn noise_tester() {
412// let bool_evaluator = BoolEvaluator::<
413// Vec<Vec<u64>>,
414// NttBackendU64,
415// ModularOpsU64<CiphertextModulus<u64>>,
416// ModularOpsU64<CiphertextModulus<u64>>,
417// ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
418// >::new(OPTIMISED_SMALL_MP_BOOL_PARAMS);
419
420// // let (_, collective_pk, _, _, server_key_eval, ideal_client_key) =
421// // _multi_party_all_keygen(&bool_evaluator, 20);
422// let no_of_parties = 2;
423// let lwe_q = bool_evaluator.pbs_info.parameters.lwe_q();
424// let rlwe_q = bool_evaluator.pbs_info.parameters.rlwe_q();
425// let lwe_n = bool_evaluator.pbs_info.parameters.lwe_n().0;
426// let rlwe_n = bool_evaluator.pbs_info.parameters.rlwe_n().0;
427// let lwe_modop = &bool_evaluator.pbs_info.lwe_modop;
428// let rlwe_nttop = &bool_evaluator.pbs_info.rlwe_nttop;
429// let rlwe_modop = &bool_evaluator.pbs_info.rlwe_modop;
430
431// // let rgsw_rgsw_decomposer = &bool_evaluator
432// // .pbs_info
433// // .parameters
434// // .rgsw_rgsw_decomposer::<DefaultDecomposer<u64>>();
435// // let rgsw_rgsw_gadget_a = rgsw_rgsw_decomposer.0.gadget_vector();
436// // let rgsw_rgsw_gadget_b = rgsw_rgsw_decomposer.1.gadget_vector();
437
438// let rlwe_rgsw_decomposer =
439// &bool_evaluator.pbs_info.rlwe_rgsw_decomposer; let rlwe_rgsw_gadget_a
440// = rlwe_rgsw_decomposer.0.gadget_vector(); let rlwe_rgsw_gadget_b =
441// rlwe_rgsw_decomposer.1.gadget_vector();
442
443// let auto_decomposer = &bool_evaluator.pbs_info.auto_decomposer;
444// let auto_gadget = auto_decomposer.gadget_vector();
445
446// let parties = (0..no_of_parties)
447// .map(|_| bool_evaluator.client_key())
448// .collect_vec();
449
450// let int_mp_seed = MultiPartyCrs::random();
451
452// let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.pbs_info.rlwe_n()];
453// parties.iter().for_each(|k| {
454// izip!(
455// ideal_rlwe_sk.iter_mut(),
456// InteractiveMultiPartyClientKey::sk_rlwe(k).iter()
457// )
458// .for_each(|(ideal_i, s_i)| {
459// *ideal_i = *ideal_i + s_i;
460// });
461// });
462// let mut ideal_lwe_sk = vec![0i32; bool_evaluator.pbs_info.lwe_n()];
463// parties.iter().for_each(|k| {
464// izip!(
465// ideal_lwe_sk.iter_mut(),
466// InteractiveMultiPartyClientKey::sk_lwe(k).iter()
467// )
468// .for_each(|(ideal_i, s_i)| {
469// *ideal_i = *ideal_i + s_i;
470// });
471// });
472
473// let mut rng = DefaultSecureRng::new();
474
475// // check noise in freshly encrypted RLWE ciphertext (ie var_fresh)
476// if false {
477// let mut rng = DefaultSecureRng::new();
478// let mut check = Stats { samples: vec![] };
479// for _ in 0..10 {
480// // generate a new collective public key
481// let mut pk_cr_seed = [0u8; 32];
482// rng.fill_bytes(&mut pk_cr_seed);
483// let public_key_share = parties
484// .iter()
485// .map(|k|
486// bool_evaluator.multi_party_public_key_share(&int_mp_seed, k))
487// .collect_vec(); let collective_pk = PublicKey::<
488// Vec<Vec<u64>>,
489// DefaultSecureRng,
490// ModularOpsU64<CiphertextModulus<u64>>,
491// >::from(public_key_share.as_slice());
492
493// let mut m = vec![0u64; rlwe_n];
494// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q,
495// m.as_mut_slice()); let mut rlwe_ct = vec![vec![0u64; rlwe_n];
496// 2]; public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
497// &mut rlwe_ct,
498// collective_pk.key(),
499// &m,
500// rlwe_modop,
501// rlwe_nttop,
502// &mut rng,
503// );
504
505// let mut m_back = vec![0u64; rlwe_n];
506// decrypt_rlwe(
507// &rlwe_ct,
508// &ideal_rlwe_sk,
509// &mut m_back,
510// rlwe_nttop,
511// rlwe_modop,
512// );
513
514// rlwe_modop.elwise_sub_mut(m_back.as_mut_slice(),
515// m.as_slice());
516
517// check.add_more(Vec::<i64>::try_convert_from(&m_back,
518// rlwe_q).as_slice()); }
519
520// println!("Public key Std: {}", check.std_dev().abs().log2());
521// }
522
523// if true {
524// // Generate server key shares
525// let public_key_share = parties
526// .iter()
527// .map(|k|
528// bool_evaluator.multi_party_public_key_share(&int_mp_seed, k))
529// .collect_vec(); let collective_pk = PublicKey::<
530// Vec<Vec<u64>>,
531// DefaultSecureRng,
532// ModularOpsU64<CiphertextModulus<u64>>,
533// >::from(public_key_share.as_slice());
534
535// let server_key_shares = parties
536// .iter()
537// .enumerate()
538// .map(|(user_id, k)| {
539// bool_evaluator.multi_party_server_key_share(
540// user_id,
541// no_of_parties,
542// &int_mp_seed,
543// collective_pk.key(),
544// k,
545// )
546// })
547// .collect_vec();
548
549// let seeded_server_key =
550//
551// bool_evaluator.aggregate_multi_party_server_key_shares(&server_key_shares);
552// }
553
554// // server key in Evaluation domain
555// let runtime_server_key =
556// ShoupServerKeyEvaluationDomain::from(ServerKeyEvaluationDomain::<
557// _,
558// _,
559// DefaultSecureRng,
560// NttBackendU64,
561// >::from(&seeded_server_key));
562
563// // check noise in RLWE x RGSW(X^{s_i}) where RGSW is accunulated RGSW
564// ciphertext if false {
565// let mut check = Stats { samples: vec![] };
566
567// ideal_lwe_sk.iter().enumerate().for_each(|(index, s_i)| {
568// let rgsw_ct_i =
569// runtime_server_key.rgsw_ct_lwe_si(index).as_ref();
570
571// let mut m = vec![0u64; rlwe_n];
572// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q,
573// m.as_mut_slice()); let mut rlwe_ct = vec![vec![0u64; rlwe_n];
574// 2]; public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
575// &mut rlwe_ct,
576// collective_pk.key(),
577// &m,
578// rlwe_modop,
579// rlwe_nttop,
580// &mut rng,
581// );
582
583// let mut rlwe_after = RlweCiphertext::<_, DefaultSecureRng> {
584// data: rlwe_ct.clone(),
585// is_trivial: false,
586// _phatom: PhantomData,
587// };
588// let mut scratch = vec![
589// vec![0u64; rlwe_n];
590// std::cmp::max(
591// rlwe_rgsw_decomposer.0.decomposition_count(),
592// rlwe_rgsw_decomposer.1.decomposition_count()
593// ) + 2
594// ];
595// rlwe_by_rgsw(
596// &mut rlwe_after,
597// rgsw_ct_i,
598// &mut scratch,
599// rlwe_rgsw_decomposer,
600// rlwe_nttop,
601// rlwe_modop,
602// );
603
604// // m1 = X^{s[i]}
605// let mut m1 = vec![0u64; rlwe_n];
606// let s_i = *s_i * (bool_evaluator.pbs_info.embedding_factor as
607// i32); if s_i < 0 {
608// m1[rlwe_n - (s_i.abs() as usize)] = rlwe_q.neg_one()
609// } else {
610// m1[s_i as usize] = 1;
611// }
612
613// // (m+e) * m1
614// let mut m_plus_e_times_m1 = vec![0u64; rlwe_n];
615// decrypt_rlwe(
616// &rlwe_ct,
617// &ideal_rlwe_sk,
618// &mut m_plus_e_times_m1,
619// rlwe_nttop,
620// rlwe_modop,
621// );
622// rlwe_nttop.forward(m_plus_e_times_m1.as_mut_slice());
623// rlwe_nttop.forward(m1.as_mut_slice());
624
625// rlwe_modop.elwise_mul_mut(m_plus_e_times_m1.as_mut_slice(),
626// m1.as_slice());
627// rlwe_nttop.backward(m_plus_e_times_m1.as_mut_slice());
628
629// // Resulting RLWE ciphertext will equal: (m0m1 + em1) +
630// e_{rlsw x rgsw}. // Hence, resulting rlwe ciphertext will
631// have error em1 + e_{rlwe x rgsw}. // Here we're only
632// concerned with e_{rlwe x rgsw}, that is noise added by //
633// RLWExRGSW. Also note in practice m1 is a monomial, for ex, X^{s_{i}}, for
634// // some i and var(em1) = var(e).
635// let mut m_plus_e_times_m1_more_e = vec![0u64; rlwe_n];
636// decrypt_rlwe(
637// &rlwe_after,
638// &ideal_rlwe_sk,
639// &mut m_plus_e_times_m1_more_e,
640// rlwe_nttop,
641// rlwe_modop,
642// );
643
644// // diff
645// rlwe_modop.elwise_sub_mut(
646// m_plus_e_times_m1_more_e.as_mut_slice(),
647// m_plus_e_times_m1.as_slice(),
648// );
649
650// // let noise = measure_noise(
651// // &rlwe_after,
652// // &m_plus_e_times_m1,
653// // rlwe_nttop,
654// // rlwe_modop,
655// // ideal_client_key.sk_rlwe.values(),
656// // );
657// // print!("NOISE: {}", noise);
658
659// check.add_more(&Vec::<i64>::try_convert_from(
660// &m_plus_e_times_m1_more_e,
661// rlwe_q,
662// ));
663// });
664// println!(
665// "RLWE x RGSW, where RGSW has noise var_brk, std: {} {}",
666// check.std_dev(),
667// check.std_dev().abs().log2()
668// )
669// }
670
671// // check noise in Auto key
672// if false {
673// let mut check = Stats { samples: vec![] };
674
675// let mut neg_s_poly =
676// Vec::<u64>::try_convert_from(ideal_rlwe_sk.as_slice(), rlwe_q);
677// rlwe_modop.elwise_neg_mut(neg_s_poly.as_mut_slice());
678
679// let g = bool_evaluator.pbs_info.g();
680// let br_q = bool_evaluator.pbs_info.br_q();
681// let auto_element_dlogs =
682// bool_evaluator.pbs_info.parameters.auto_element_dlogs(); for i in
683// auto_element_dlogs.into_iter() { let g_pow = if i == 0 {
684// -g
685// } else {
686// (((g as usize).pow(i as u32)) % br_q) as isize
687// };
688
689// // -s[X^k]
690// let (auto_indices, auto_sign) = generate_auto_map(rlwe_n,
691// g_pow); let mut neg_s_poly_auto_i = vec![0u64; rlwe_n];
692// izip!(neg_s_poly.iter(), auto_indices.iter(),
693// auto_sign.iter()).for_each( |(v, to_i, to_sign)| {
694// if !to_sign {
695// neg_s_poly_auto_i[*to_i] = rlwe_modop.neg(v);
696// } else {
697// neg_s_poly_auto_i[*to_i] = *v;
698// }
699// },
700// );
701
702// let mut auto_key_i =
703// runtime_server_key.galois_key_for_auto(i).as_ref().clone(); //send i^th auto
704// key to coefficient domain auto_key_i
705// .iter_mut()
706// .for_each(|r| rlwe_nttop.backward(r.as_mut_slice()));
707// auto_gadget.iter().enumerate().for_each(|(i, b_i)| {
708// // B^i * -s[X^k]
709// let mut m_ideal = neg_s_poly_auto_i.clone();
710
711// rlwe_modop.elwise_scalar_mul_mut(m_ideal.as_mut_slice(),
712// b_i);
713
714// let mut m_out = vec![0u64; rlwe_n];
715// let mut rlwe_ct = vec![vec![0u64; rlwe_n]; 2];
716// rlwe_ct[0].copy_from_slice(&auto_key_i[i]);
717// rlwe_ct[1]
718//
719// .copy_from_slice(&auto_key_i[auto_decomposer.decomposition_count() + i]);
720// decrypt_rlwe(&rlwe_ct, &ideal_rlwe_sk, &mut m_out,
721// rlwe_nttop, rlwe_modop);
722
723// // diff
724// rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(),
725// m_ideal.as_slice());
726
727// check.add_more(&Vec::<i64>::try_convert_from(&m_out,
728// rlwe_q)); });
729// }
730
731// println!("Auto key noise std dev: {}",
732// check.std_dev().abs().log2()); }
733
734// // check noise in RLWE(X^k) after sending RLWE(X) -> RLWE(X^k)using
735// collective // auto key
736// if false {
737// let mut check = Stats { samples: vec![] };
738// let br_q = bool_evaluator.pbs_info.br_q();
739// let g = bool_evaluator.pbs_info.g();
740// let auto_element_dlogs =
741// bool_evaluator.pbs_info.parameters.auto_element_dlogs(); for i in
742// auto_element_dlogs.into_iter() { for _ in 0..10 {
743// let mut m = vec![0u64; rlwe_n];
744// RandomFillUniformInModulus::random_fill(&mut rng, rlwe_q,
745// m.as_mut_slice()); let mut rlwe_ct = RlweCiphertext::<_,
746// DefaultSecureRng> { data: vec![vec![0u64; rlwe_n];
747// 2], is_trivial: false,
748// _phatom: PhantomData,
749// };
750// public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
751// &mut rlwe_ct,
752// collective_pk.key(),
753// &m,
754// rlwe_modop,
755// rlwe_nttop,
756// &mut rng,
757// );
758
759// // We're only interested in noise increased as a result
760// of automorphism. // Hence, we take m+e as the bench.
761// let mut m_plus_e = vec![0u64; rlwe_n];
762// decrypt_rlwe(
763// &rlwe_ct,
764// &ideal_rlwe_sk,
765// &mut m_plus_e,
766// rlwe_nttop,
767// rlwe_modop,
768// );
769
770// let auto_key =
771// runtime_server_key.galois_key_for_auto(i).as_ref(); let
772// (auto_map_index, auto_map_sign) = bool_evaluator.pbs_info.rlwe_auto_map(i);
773// let mut scratch =
774// vec![vec![0u64; rlwe_n];
775// auto_decomposer.decomposition_count() + 2]; galois_auto(
776// &mut rlwe_ct,
777// auto_key,
778// &mut scratch,
779// &auto_map_index,
780// &auto_map_sign,
781// rlwe_modop,
782// rlwe_nttop,
783// auto_decomposer,
784// );
785
786// // send m+e from X to X^k
787// let mut m_plus_e_auto = vec![0u64; rlwe_n];
788// izip!(m_plus_e.iter(), auto_map_index.iter(),
789// auto_map_sign.iter()).for_each( |(v, to_index,
790// to_sign)| { if !to_sign {
791// m_plus_e_auto[*to_index] = rlwe_modop.neg(v);
792// } else {
793// m_plus_e_auto[*to_index] = *v
794// }
795// },
796// );
797
798// let mut m_out = vec![0u64; rlwe_n];
799// decrypt_rlwe(&rlwe_ct, &ideal_rlwe_sk, &mut m_out,
800// rlwe_nttop, rlwe_modop);
801
802// // diff
803// rlwe_modop.elwise_sub_mut(m_out.as_mut_slice(),
804// m_plus_e_auto.as_slice());
805
806//
807// check.add_more(&Vec::<i64>::try_convert_from(m_out.as_slice(), rlwe_q));
808// }
809// }
810
811// println!("Rlwe Auto Noise Std: {}",
812// check.std_dev().abs().log2()); }
813
814// // Check noise growth in ksk
815// // TODO check in LWE key switching keys
816// if false {
817// // 1. encrypt LWE ciphertext
818// // 2. Key switching
819// // 3.
820// let mut check = Stats { samples: vec![] };
821
822// for _ in 0..1024 {
823// // Encrypt m \in Q_{ks} using RLWE sk
824// let mut lwe_in_ct = vec![0u64; rlwe_n + 1];
825// let m = RandomElementInModulus::random(&mut rng,
826// &lwe_q.q().unwrap()); encrypt_lwe(&mut lwe_in_ct, &m,
827// &ideal_rlwe_sk, lwe_modop, &mut rng);
828
829// // Key switch
830// let mut lwe_out = vec![0u64; lwe_n + 1];
831// lwe_key_switch(
832// &mut lwe_out,
833// &lwe_in_ct,
834// runtime_server_key.lwe_ksk(),
835// lwe_modop,
836// bool_evaluator.pbs_info.lwe_decomposer(),
837// );
838
839// // We only care about noise added by LWE key switch
840// // m+e
841// let m_plus_e = decrypt_lwe(&lwe_in_ct, &ideal_rlwe_sk,
842// lwe_modop);
843
844// let m_plus_e_plus_lwe_ksk_noise = decrypt_lwe(&lwe_out,
845// &ideal_lwe_sk, lwe_modop);
846
847// let diff = lwe_modop.sub(&m_plus_e_plus_lwe_ksk_noise,
848// &m_plus_e);
849
850// check.add_more(&vec![lwe_q.map_element_to_i64(&diff)]);
851// }
852
853// println!("Lwe ksk std dev: {}", check.std_dev().abs().log2());
854// }
855// }
856
857// // Check noise in fresh RGSW ciphertexts, ie X^{s_j[i]}, must equalnoise
858// in // // fresh RLWE ciphertext
859// if true {}
860// // test LWE ksk from RLWE -> LWE
861// // if false {
862// // let logp = 2;
863// // let mut rng = DefaultSecureRng::new();
864
865// // let m = 1;
866// // let encoded_m = m << (lwe_logq - logp);
867
868// // // Encrypt
869// // let mut lwe_ct = vec![0u64; rlwe_n + 1];
870// // encrypt_lwe(
871// // &mut lwe_ct,
872// // &encoded_m,
873// // ideal_client_key.sk_rlwe.values(),
874// // lwe_modop,
875// // &mut rng,
876// // );
877
878// // // key switch
879// // let lwe_decomposer = &bool_evaluator.decomposer_lwe;
880// // let mut lwe_out = vec![0u64; lwe_n + 1];
881// // lwe_key_switch(
882// // &mut lwe_out,
883// // &lwe_ct,
884// // &server_key_eval.lwe_ksk,
885// // lwe_modop,
886// // lwe_decomposer,
887// // );
888
889// // let encoded_m_back = decrypt_lwe(&lwe_out,
890// // ideal_client_key.sk_lwe.values(), lwe_modop); let m_back
891// // = ((encoded_m_back as f64 * (1 << logp) as f64) /
892// // (lwe_q as f64)).round() as u64; dbg!(m_back, m);
893
894// // let noise = measure_noise_lwe(
895// // &lwe_out,
896// // ideal_client_key.sk_lwe.values(),
897// // lwe_modop,
898// // &encoded_m,
899// // );
900
901// // println!("Noise: {noise}");
902// // }
903
904// // Measure noise in RGSW ciphertexts of ideal LWE secrets
905// // if true {
906// // let gadget_vec = gadget_vector(
907// // bool_evaluator.parameters.rlwe_logq,
908// // bool_evaluator.parameters.logb_rgsw,
909// // bool_evaluator.parameters.d_rgsw,
910// // );
911
912// // for i in 0..20 {
913// // // measure noise in RGSW(s[i])
914// // let si =
915// // ideal_client_key.sk_lwe.values[i] *
916// // (bool_evaluator.embedding_factor as i32); let mut
917// // si_poly = vec![0u64; rlwe_n]; if si < 0 {
918// // si_poly[rlwe_n - (si.abs() as usize)] = rlwe_q - 1;
919// // } else {
920// // si_poly[(si.abs() as usize)] = 1;
921// // }
922
923// // let mut rgsw_si = server_key_eval.rgsw_cts[i].clone();
924// // rgsw_si
925// // .iter_mut()
926// // .for_each(|ri| rlwe_nttop.backward(ri.as_mut()));
927
928// // println!("####### Noise in RGSW(X^s_{i}) #######");
929// // _measure_noise_rgsw(
930// // &rgsw_si,
931// // &si_poly,
932// // ideal_client_key.sk_rlwe.values(),
933// // &gadget_vec,
934// // rlwe_q,
935// // );
936// // println!("####### ##################### #######");
937// // }
938// // }
939
940// // // measure noise grwoth in RLWExRGSW
941// // if true {
942// // let mut rng = DefaultSecureRng::new();
943// // let mut carry_m = vec![0u64; rlwe_n];
944// // RandomUniformDist1::random_fill(&mut rng, &rlwe_q,
945// // carry_m.as_mut_slice());
946
947// // // RGSW(carrym)
948// // let trivial_rlwect = vec![vec![0u64; rlwe_n],carry_m.clone()];
949// // let mut rlwe_ct = RlweCiphertext::<_,
950// // DefaultSecureRng>::from_raw(trivial_rlwect, true);
951
952// // let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n];
953// // d_rgsw + 2]; let mul_mod =
954// // |v0: &u64, v1: &u64| (((*v0 as u128 * *v1 as u128) % (rlwe_q
955// as u128)) as u64);
956
957// // for i in 0..bool_evaluator.parameters.lwe_n {
958// // rlwe_by_rgsw(
959// // &mut rlwe_ct,
960// // server_key_eval.rgsw_ct_lwe_si(i),
961// // &mut scratch_matrix_dplus2_ring,
962// // rlwe_decomposer,
963// // rlwe_nttop,
964// // rlwe_modop,
965// // );
966
967// // // carry_m[X] * s_i[X]
968// // let si =
969// // ideal_client_key.sk_lwe.values[i] *
970// // (bool_evaluator.embedding_factor as i32); let mut
971// // si_poly = vec![0u64; rlwe_n]; if si < 0 {
972// // si_poly[rlwe_n - (si.abs() as usize)] = rlwe_q - 1;
973// // } else {
974// // si_poly[(si.abs() as usize)] = 1;
975// // }
976// // carry_m = negacyclic_mul(&carry_m, &si_poly, mul_mod,
977// // rlwe_q);
978
979// // let noise = measure_noise(
980// // &rlwe_ct,
981// // &carry_m,
982// // rlwe_nttop,
983// // rlwe_modop,
984// // ideal_client_key.sk_rlwe.values(),
985// // );
986// // println!("Noise RLWE(carry_m) accumulating {i}^th secret
987// // monomial: {noise}"); }
988// // }
989
990// // // Check galois keys
991// // if false {
992// // let g = bool_evaluator.g() as isize;
993// // let mut rng = DefaultSecureRng::new();
994// // let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n];
995// // d_rgsw + 2]; for i in [g, -g] {
996// // let mut m = vec![0u64; rlwe_n];
997// // RandomUniformDist1::random_fill(&mut rng, &rlwe_q,
998// // m.as_mut_slice()); let mut rlwe_ct = {
999// // let mut data = vec![vec![0u64; rlwe_n]; 2];
1000// // public_key_encrypt_rlwe(
1001// // &mut data,
1002// // &collective_pk.key,
1003// // &m,
1004// // rlwe_modop,
1005// // rlwe_nttop,
1006// // &mut rng,
1007// // );
1008// // RlweCiphertext::<_, DefaultSecureRng>::from_raw(data,
1009// // false) };
1010
1011// // let auto_key = server_key_eval.galois_key_for_auto(i);
1012// // let (auto_map_index, auto_map_sign) =
1013// // generate_auto_map(rlwe_n, i); galois_auto(
1014// // &mut rlwe_ct,
1015// // auto_key,
1016// // &mut scratch_matrix_dplus2_ring,
1017// // &auto_map_index,
1018// // &auto_map_sign,
1019// // rlwe_modop,
1020// // rlwe_nttop,
1021// // rlwe_decomposer,
1022// // );
1023
1024// // // send m(X) -> m(X^i)
1025// // let mut m_k = vec![0u64; rlwe_n];
1026// // izip!(m.iter(), auto_map_index.iter(),
1027// // auto_map_sign.iter()).for_each( |(mi, to_index,to_sign)|
1028// // // { if !to_sign {
1029// // m_k[*to_index] = rlwe_q - *mi; } else {
1030// // m_k[*to_index] = *mi;
1031// // }
1032// // },
1033// // );
1034
1035// // // measure noise
1036// // let noise = measure_noise(
1037// // &rlwe_ct,
1038// // &m_k,
1039// // rlwe_nttop,
1040// // rlwe_modop,
1041// // ideal_client_key.sk_rlwe.values(),
1042// // );
1043
1044// // println!("Noise after auto k={i}: {noise}");
1045// // }
1046// // }
1047// }