phantom-zone/src/bool/keys.rs
src/bool/keys.rsRaw
1use std::{collections::HashMap, hash::Hash, marker::PhantomData};
2
3use crate::{
4 backend::{ModInit, VectorOps},
5 pbs::WithShoupRepr,
6 random::{NewWithSeed, RandomFillUniformInModulus},
7 utils::{ToShoup, WithLocal},
8 Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut,
9};
10
11use super::{
12 evaluator::BoolEvaluator,
13 parameters::{BoolParameters, CiphertextModulus},
14};
15
16pub(crate) trait SinglePartyClientKey {
17 type Element;
18 fn sk_rlwe(&self) -> Vec<Self::Element>;
19 fn sk_lwe(&self) -> Vec<Self::Element>;
20}
21
22pub(crate) trait InteractiveMultiPartyClientKey {
23 type Element;
24 fn sk_rlwe(&self) -> Vec<Self::Element>;
25 fn sk_lwe(&self) -> Vec<Self::Element>;
26}
27
28pub(crate) trait NonInteractiveMultiPartyClientKey {
29 type Element;
30 fn sk_rlwe(&self) -> Vec<Self::Element>;
31 fn sk_u_rlwe(&self) -> Vec<Self::Element>;
32 fn sk_lwe(&self) -> Vec<Self::Element>;
33}
34
35/// Client key
36///
37/// Key is used for all parameter varians - Single party, interactive
38/// multi-party, and non-interactive multi-party. The only stored the main seed
39/// and seeds of the Rlwe/Lwe secrets are derived at puncturing the seed desired
40/// number of times.
41///
42/// ### Punctures required:
43///
44/// Puncture 1 -> Seed of RLWE secret used as main RLWE secret for
45/// single-party, interactive/non-interactive multi-party
46///
47/// Puncture 2 -> Seed of LWE secret used main LWE secret for single-party,
48/// interactive/non-interactive multi-party
49///
50/// Puncture 3 -> Seed of RLWE secret used as `u` in
51/// interactive/non-interactive multi-party.
52#[derive(Clone)]
53pub struct ClientKey<S, E> {
54 seed: S,
55 parameters: BoolParameters<E>,
56}
57
58mod impl_ck {
59 use crate::{
60 random::DefaultSecureRng,
61 utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng},
62 };
63
64 use super::*;
65
66 impl<E> ClientKey<[u8; 32], E> {
67 pub(in super::super) fn new(parameters: BoolParameters<E>) -> ClientKey<[u8; 32], E> {
68 let mut rng = DefaultSecureRng::new();
69 let mut seed = [0u8; 32];
70 rng.fill_bytes(&mut seed);
71 Self { seed, parameters }
72 }
73 }
74
75 impl<E> SinglePartyClientKey for ClientKey<[u8; 32], E> {
76 type Element = i32;
77 fn sk_lwe(&self) -> Vec<Self::Element> {
78 let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
79 let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2);
80
81 let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed);
82 let mut out = vec![0i32; self.parameters.lwe_n().0];
83 fill_random_ternary_secret_with_hamming_weight(
84 &mut out,
85 self.parameters.lwe_n().0 >> 1,
86 &mut lwe_prng,
87 );
88 out
89 }
90 fn sk_rlwe(&self) -> Vec<Self::Element> {
91 let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
92 let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1);
93
94 let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
95 let mut out = vec![0i32; self.parameters.rlwe_n().0];
96 fill_random_ternary_secret_with_hamming_weight(
97 &mut out,
98 self.parameters.rlwe_n().0 >> 1,
99 &mut rlwe_prng,
100 );
101 out
102 }
103 }
104
105 impl<E> InteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
106 type Element = i32;
107 fn sk_lwe(&self) -> Vec<Self::Element> {
108 <Self as SinglePartyClientKey>::sk_lwe(&self)
109 }
110 fn sk_rlwe(&self) -> Vec<Self::Element> {
111 <Self as SinglePartyClientKey>::sk_rlwe(&self)
112 }
113 }
114
115 impl<E> NonInteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
116 type Element = i32;
117 fn sk_lwe(&self) -> Vec<Self::Element> {
118 <Self as SinglePartyClientKey>::sk_lwe(&self)
119 }
120 fn sk_rlwe(&self) -> Vec<Self::Element> {
121 <Self as SinglePartyClientKey>::sk_rlwe(&self)
122 }
123 fn sk_u_rlwe(&self) -> Vec<Self::Element> {
124 let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
125 let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3);
126
127 let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
128 let mut out = vec![0i32; self.parameters.rlwe_n().0];
129 fill_random_ternary_secret_with_hamming_weight(
130 &mut out,
131 self.parameters.rlwe_n().0 >> 1,
132 &mut rlwe_prng,
133 );
134 out
135 }
136 }
137}
138
139/// Public key
140pub struct PublicKey<M, Rng, ModOp> {
141 key: M,
142 _phantom: PhantomData<(Rng, ModOp)>,
143}
144
145pub(super) mod impl_pk {
146 use crate::evaluator::MultiPartyCrs;
147
148 use super::*;
149
150 impl<M, R, Mo> PublicKey<M, R, Mo> {
151 pub(in super::super) fn key(&self) -> &M {
152 &self.key
153 }
154 }
155
156 impl<
157 M: MatrixMut + MatrixEntity,
158 Rng: NewWithSeed
159 + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
160 ModOp,
161 > From<SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>>
162 for PublicKey<M, Rng, ModOp>
163 where
164 <M as Matrix>::R: RowMut,
165 M::MatElement: Copy,
166 {
167 fn from(
168 value: SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>,
169 ) -> Self {
170 let mut prng = Rng::new_with_seed(value.seed);
171
172 let mut key = M::zeros(2, value.parameters.rlwe_n().0);
173 // sample A
174 RandomFillUniformInModulus::random_fill(
175 &mut prng,
176 value.parameters.rlwe_q(),
177 key.get_row_mut(0),
178 );
179 // Copy over B
180 key.get_row_mut(1).copy_from_slice(value.part_b.as_ref());
181
182 PublicKey {
183 key,
184 _phantom: PhantomData,
185 }
186 }
187 }
188
189 impl<
190 M: MatrixMut + MatrixEntity,
191 Rng: NewWithSeed
192 + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
193 ModOp: VectorOps<Element = M::MatElement> + ModInit<M = CiphertextModulus<M::MatElement>>,
194 >
195 From<
196 &[CommonReferenceSeededCollectivePublicKeyShare<
197 M::R,
198 Rng::Seed,
199 BoolParameters<M::MatElement>,
200 >],
201 > for PublicKey<M, Rng, ModOp>
202 where
203 <M as Matrix>::R: RowMut,
204 Rng::Seed: Copy + PartialEq,
205 M::MatElement: PartialEq + Copy,
206 {
207 fn from(
208 value: &[CommonReferenceSeededCollectivePublicKeyShare<
209 M::R,
210 Rng::Seed,
211 BoolParameters<M::MatElement>,
212 >],
213 ) -> Self {
214 assert!(value.len() > 0);
215
216 let parameters = &value[0].parameters;
217 let mut key = M::zeros(2, parameters.rlwe_n().0);
218
219 // sample A
220 let seed = value[0].cr_seed;
221 let mut main_rng = Rng::new_with_seed(seed);
222 RandomFillUniformInModulus::random_fill(
223 &mut main_rng,
224 parameters.rlwe_q(),
225 key.get_row_mut(0),
226 );
227
228 // Sum all Bs
229 let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
230 value.iter().for_each(|share_i| {
231 assert!(share_i.cr_seed == seed);
232 assert!(&share_i.parameters == parameters);
233
234 rlweq_modop.elwise_add_mut(key.get_row_mut(1), share_i.share.as_ref());
235 });
236
237 PublicKey {
238 key,
239 _phantom: PhantomData,
240 }
241 }
242 }
243}
244
245/// Seeded public key
246struct SeededPublicKey<Ro, S, P, ModOp> {
247 part_b: Ro,
248 seed: S,
249 parameters: P,
250 _phantom: PhantomData<ModOp>,
251}
252
253mod impl_seeded_pk {
254 use super::*;
255
256 impl<R, S, ModOp>
257 From<&[CommonReferenceSeededCollectivePublicKeyShare<R, S, BoolParameters<R::Element>>]>
258 for SeededPublicKey<R, S, BoolParameters<R::Element>, ModOp>
259 where
260 ModOp: VectorOps<Element = R::Element> + ModInit<M = CiphertextModulus<R::Element>>,
261 S: PartialEq + Clone,
262 R: RowMut + RowEntity + Clone,
263 R::Element: Clone + PartialEq,
264 {
265 fn from(
266 value: &[CommonReferenceSeededCollectivePublicKeyShare<
267 R,
268 S,
269 BoolParameters<R::Element>,
270 >],
271 ) -> Self {
272 assert!(value.len() > 0);
273
274 let parameters = &value[0].parameters;
275 let cr_seed = value[0].cr_seed.clone();
276
277 // Sum all Bs
278 let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
279 let mut part_b = value[0].share.clone();
280 value.iter().skip(1).for_each(|share_i| {
281 assert!(&share_i.cr_seed == &cr_seed);
282 assert!(&share_i.parameters == parameters);
283
284 rlweq_modop.elwise_add_mut(part_b.as_mut(), share_i.share.as_ref());
285 });
286
287 Self {
288 part_b,
289 seed: cr_seed,
290 parameters: parameters.clone(),
291 _phantom: PhantomData,
292 }
293 }
294 }
295}
296
297/// CRS seeded collective public key share
298pub struct CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
299 share: Ro,
300 cr_seed: S,
301 parameters: P,
302}
303impl<Ro, S, P> CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
304 pub(super) fn new(share: Ro, cr_seed: S, parameters: P) -> Self {
305 CommonReferenceSeededCollectivePublicKeyShare {
306 share,
307 cr_seed,
308 parameters,
309 }
310 }
311}
312
313/// CRS seeded Multi-party server key share
314pub struct CommonReferenceSeededMultiPartyServerKeyShare<M: Matrix, P, S> {
315 self_leader_rgsws: Vec<M>,
316 not_self_leader_rgsws: Vec<M>,
317 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
318 /// to -g is at 0
319 auto_keys: HashMap<usize, M>,
320 lwe_ksk: M::R,
321 /// Common reference seed
322 cr_seed: S,
323 parameters: P,
324 user_id: usize,
325}
326
327impl<M: Matrix, P, S> CommonReferenceSeededMultiPartyServerKeyShare<M, P, S> {
328 pub(super) fn new(
329 self_leader_rgsws: Vec<M>,
330 not_self_leader_rgsws: Vec<M>,
331 auto_keys: HashMap<usize, M>,
332 lwe_ksk: M::R,
333 cr_seed: S,
334 parameters: P,
335 user_id: usize,
336 ) -> Self {
337 CommonReferenceSeededMultiPartyServerKeyShare {
338 self_leader_rgsws,
339 not_self_leader_rgsws,
340 auto_keys,
341 lwe_ksk,
342 cr_seed,
343 parameters,
344 user_id,
345 }
346 }
347
348 pub(super) fn cr_seed(&self) -> &S {
349 &self.cr_seed
350 }
351
352 pub(super) fn parameters(&self) -> &P {
353 &self.parameters
354 }
355
356 pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
357 &self.auto_keys
358 }
359
360 pub(crate) fn self_leader_rgsws(&self) -> &[M] {
361 &self.self_leader_rgsws
362 }
363
364 pub(super) fn not_self_leader_rgsws(&self) -> &[M] {
365 &self.not_self_leader_rgsws
366 }
367
368 pub(super) fn lwe_ksk(&self) -> &M::R {
369 &self.lwe_ksk
370 }
371
372 pub(super) fn user_id(&self) -> usize {
373 self.user_id
374 }
375}
376
377/// CRS seeded MultiParty server key
378pub struct SeededMultiPartyServerKey<M: Matrix, S, P> {
379 rgsw_cts: Vec<M>,
380 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
381 /// to -g is at 0
382 auto_keys: HashMap<usize, M>,
383 lwe_ksk: M::R,
384 cr_seed: S,
385 parameters: P,
386}
387
388impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
389 pub(super) fn new(
390 rgsw_cts: Vec<M>,
391 auto_keys: HashMap<usize, M>,
392 lwe_ksk: M::R,
393 cr_seed: S,
394 parameters: P,
395 ) -> Self {
396 SeededMultiPartyServerKey {
397 rgsw_cts,
398 auto_keys,
399 lwe_ksk,
400 cr_seed,
401 parameters,
402 }
403 }
404
405 pub(super) fn rgsw_cts(&self) -> &[M] {
406 &self.rgsw_cts
407 }
408}
409
410/// Seeded single party server key
411pub struct SeededSinglePartyServerKey<M: Matrix, P, S> {
412 /// Rgsw cts of LWE secret elements
413 pub(crate) rgsw_cts: Vec<M>,
414 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
415 /// to -g is at 0
416 pub(crate) auto_keys: HashMap<usize, M>,
417 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
418 pub(crate) lwe_ksk: M::R,
419 /// Parameters
420 pub(crate) parameters: P,
421 /// Main seed
422 pub(crate) seed: S,
423}
424impl<M: Matrix, S> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, S> {
425 pub(super) fn from_raw(
426 auto_keys: HashMap<usize, M>,
427 rgsw_cts: Vec<M>,
428 lwe_ksk: M::R,
429 parameters: BoolParameters<M::MatElement>,
430 seed: S,
431 ) -> Self {
432 // sanity checks
433 auto_keys.iter().for_each(|v| {
434 assert!(
435 v.1.dimension()
436 == (
437 parameters.auto_decomposition_count().0,
438 parameters.rlwe_n().0
439 )
440 )
441 });
442
443 let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
444 rgsw_cts.iter().for_each(|v| {
445 assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
446 });
447 assert!(
448 lwe_ksk.as_ref().len()
449 == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
450 );
451
452 SeededSinglePartyServerKey {
453 rgsw_cts,
454 auto_keys,
455 lwe_ksk,
456 parameters,
457 seed,
458 }
459 }
460}
461
462/// Server key in evaluation domain
463pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
464 /// Rgsw cts of LWE secret elements
465 rgsw_cts: Vec<M>,
466 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
467 /// to -g is at 0
468 galois_keys: HashMap<usize, M>,
469 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
470 lwe_ksk: M,
471 parameters: P,
472 _phanton: PhantomData<(R, N)>,
473}
474
475pub(super) mod impl_server_key_eval_domain {
476 use itertools::{izip, Itertools};
477
478 use crate::{
479 evaluator::MultiPartyCrs,
480 ntt::{Ntt, NttInit},
481 pbs::PbsKey,
482 random::RandomFill,
483 };
484
485 use super::*;
486
487 impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
488 pub(in super::super) fn rgsw_cts(&self) -> &[M] {
489 &self.rgsw_cts
490 }
491 }
492
493 impl<
494 M: MatrixMut + MatrixEntity,
495 R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
496 + NewWithSeed,
497 N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
498 > From<&SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
499 for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
500 where
501 <M as Matrix>::R: RowMut,
502 M::MatElement: Copy,
503 R::Seed: Clone,
504 {
505 fn from(
506 value: &SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>,
507 ) -> Self {
508 let mut main_prng = R::new_with_seed(value.seed.clone());
509 let parameters = &value.parameters;
510 let g = parameters.g() as isize;
511 let ring_size = value.parameters.rlwe_n().0;
512 let lwe_n = value.parameters.lwe_n().0;
513 let rlwe_q = value.parameters.rlwe_q();
514 let lwq_q = value.parameters.lwe_q();
515
516 let nttop = N::new(rlwe_q, ring_size);
517
518 // galois keys
519 let mut auto_keys = HashMap::new();
520 let auto_decomp_count = parameters.auto_decomposition_count().0;
521 let auto_element_dlogs = parameters.auto_element_dlogs();
522 for i in auto_element_dlogs.into_iter() {
523 let seeded_auto_key = value.auto_keys.get(&i).unwrap();
524 assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
525
526 let mut data = M::zeros(auto_decomp_count * 2, ring_size);
527
528 // sample RLWE'_A(-s(X^k))
529 data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
530 RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
531 });
532
533 // copy over RLWE'B_(-s(X^k))
534 izip!(
535 data.iter_rows_mut().skip(auto_decomp_count),
536 seeded_auto_key.iter_rows()
537 )
538 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
539
540 // Send to Evaluation domain
541 data.iter_rows_mut()
542 .for_each(|ri| nttop.forward(ri.as_mut()));
543
544 auto_keys.insert(i, data);
545 }
546
547 // RGSW ciphertexts
548 let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
549 let rgsw_cts = value
550 .rgsw_cts
551 .iter()
552 .map(|seeded_rgsw_si| {
553 assert!(
554 seeded_rgsw_si.dimension()
555 == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
556 );
557
558 let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
559
560 // copy over RLWE'(-sm)
561 izip!(
562 data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
563 seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
564 )
565 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
566
567 // sample RLWE'_A(m)
568 data.iter_rows_mut()
569 .skip(rlrg_a_decomp.0 * 2)
570 .take(rlrg_b_decomp.0)
571 .for_each(|ri| {
572 RandomFillUniformInModulus::random_fill(
573 &mut main_prng,
574 &rlwe_q,
575 ri.as_mut(),
576 )
577 });
578
579 // copy over RLWE'_B(m)
580 izip!(
581 data.iter_rows_mut()
582 .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
583 seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
584 )
585 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
586
587 // send polynomials to evaluation domain
588 data.iter_rows_mut()
589 .for_each(|ri| nttop.forward(ri.as_mut()));
590
591 data
592 })
593 .collect_vec();
594
595 // LWE ksk
596 let lwe_ksk = {
597 let d = parameters.lwe_decomposition_count().0;
598 assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
599
600 let mut data = M::zeros(d * ring_size, lwe_n + 1);
601 izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
602 |(lwe_i, bi)| {
603 RandomFillUniformInModulus::random_fill(
604 &mut main_prng,
605 &lwq_q,
606 &mut lwe_i.as_mut()[1..],
607 );
608 lwe_i.as_mut()[0] = *bi;
609 },
610 );
611
612 data
613 };
614
615 ServerKeyEvaluationDomain {
616 rgsw_cts,
617 galois_keys: auto_keys,
618 lwe_ksk,
619 parameters: parameters.clone(),
620 _phanton: PhantomData,
621 }
622 }
623 }
624
625 impl<
626 M: MatrixMut + MatrixEntity,
627 Rng: NewWithSeed,
628 N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
629 >
630 From<&SeededMultiPartyServerKey<M, MultiPartyCrs<Rng::Seed>, BoolParameters<M::MatElement>>>
631 for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
632 where
633 <M as Matrix>::R: RowMut,
634 Rng::Seed: Copy + Default,
635 Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
636 + RandomFill<Rng::Seed>,
637 M::MatElement: Copy,
638 {
639 fn from(
640 value: &SeededMultiPartyServerKey<
641 M,
642 MultiPartyCrs<Rng::Seed>,
643 BoolParameters<M::MatElement>,
644 >,
645 ) -> Self {
646 let g = value.parameters.g() as isize;
647 let rlwe_n = value.parameters.rlwe_n().0;
648 let lwe_n = value.parameters.lwe_n().0;
649 let rlwe_q = value.parameters.rlwe_q();
650 let lwe_q = value.parameters.lwe_q();
651
652 let rlwe_nttop = N::new(rlwe_q, rlwe_n);
653
654 // auto keys
655 let mut auto_keys = HashMap::new();
656 {
657 let mut auto_prng = Rng::new_with_seed(value.cr_seed.auto_keys_cts_seed::<Rng>());
658 let auto_d_count = value.parameters.auto_decomposition_count().0;
659 let auto_element_dlogs = value.parameters.auto_element_dlogs();
660 for i in auto_element_dlogs.into_iter() {
661 let mut key = M::zeros(auto_d_count * 2, rlwe_n);
662
663 // sample a
664 key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
665 RandomFillUniformInModulus::random_fill(
666 &mut auto_prng,
667 &rlwe_q,
668 ri.as_mut(),
669 )
670 });
671
672 let key_part_b = value.auto_keys.get(&i).unwrap();
673 assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
674 izip!(
675 key.iter_rows_mut().skip(auto_d_count),
676 key_part_b.iter_rows()
677 )
678 .for_each(|(to_ri, from_ri)| {
679 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
680 });
681
682 // send to evaluation domain
683 key.iter_rows_mut()
684 .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
685
686 auto_keys.insert(i, key);
687 }
688 }
689
690 // rgsw cts
691 let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
692 let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
693 let rgsw_cts = value
694 .rgsw_cts
695 .iter()
696 .map(|ct_i_in| {
697 assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
698 let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
699
700 izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
701 |(to_ri, from_ri)| {
702 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
703 rlwe_nttop.forward(to_ri.as_mut());
704 },
705 );
706
707 eval_ct_i_out
708 })
709 .collect_vec();
710
711 // lwe ksk
712 let mut lwe_ksk_prng = Rng::new_with_seed(value.cr_seed.lwe_ksk_cts_seed_seed::<Rng>());
713 let d_lwe = value.parameters.lwe_decomposition_count().0;
714 let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
715 izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
716 |(lwe_i, bi)| {
717 RandomFillUniformInModulus::random_fill(
718 &mut lwe_ksk_prng,
719 &lwe_q,
720 &mut lwe_i.as_mut()[1..],
721 );
722 lwe_i.as_mut()[0] = *bi;
723 },
724 );
725
726 ServerKeyEvaluationDomain {
727 rgsw_cts,
728 galois_keys: auto_keys,
729 lwe_ksk,
730 parameters: value.parameters.clone(),
731 _phanton: PhantomData,
732 }
733 }
734 }
735
736 impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
737 type AutoKey = M;
738 type LweKskKey = M;
739 type RgswCt = M;
740
741 fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
742 self.galois_keys.get(&k).unwrap()
743 }
744 fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
745 &self.rgsw_cts[si]
746 }
747
748 fn lwe_ksk(&self) -> &Self::LweKskKey {
749 &self.lwe_ksk
750 }
751 }
752
753 #[cfg(test)]
754 impl<M, P, R, N> super::super::print_noise::CollectRuntimeServerKeyStats
755 for ServerKeyEvaluationDomain<M, P, R, N>
756 {
757 type M = M;
758 fn galois_key_for_auto(&self, k: usize) -> &Self::M {
759 self.galois_keys.get(&k).unwrap()
760 }
761 fn lwe_ksk(&self) -> &Self::M {
762 &self.lwe_ksk
763 }
764 fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M {
765 &self.rgsw_cts[s_index]
766 }
767 }
768}
769
770pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
771 /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
772 rgsw_cts: Vec<M>,
773 /// Automorphism keys under ideal rlwe secret
774 auto_keys: HashMap<usize, M>,
775 /// LWE key switching key from Q -> Q_{ks}
776 lwe_ksk: M,
777 /// Key switching key from user j to ideal secret key s. User j's ksk is at
778 /// j'th element
779 ui_to_s_ksks: Vec<M>,
780 parameters: P,
781 _phanton: PhantomData<(R, N)>,
782}
783
784pub(super) mod impl_non_interactive_server_key_eval_domain {
785 use itertools::{izip, Itertools};
786
787 use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
788
789 use super::*;
790
791 impl<M, P, R, N> NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
792 pub(in super::super) fn rgsw_cts(&self) -> &[M] {
793 &self.rgsw_cts
794 }
795 }
796
797 impl<M, Rng, N>
798 From<
799 &SeededNonInteractiveMultiPartyServerKey<
800 M,
801 NonInteractiveMultiPartyCrs<Rng::Seed>,
802 BoolParameters<M::MatElement>,
803 >,
804 > for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
805 where
806 M: MatrixMut + MatrixEntity + Clone,
807 Rng: NewWithSeed
808 + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
809 + RandomFill<<Rng as NewWithSeed>::Seed>,
810 N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
811 M::R: RowMut,
812 M::MatElement: Copy,
813 Rng::Seed: Clone + Copy + Default,
814 {
815 fn from(
816 value: &SeededNonInteractiveMultiPartyServerKey<
817 M,
818 NonInteractiveMultiPartyCrs<Rng::Seed>,
819 BoolParameters<M::MatElement>,
820 >,
821 ) -> Self {
822 let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
823 let ring_size = value.parameters.rlwe_n().0;
824
825 // RGSW cts
826 // copy over rgsw cts and send to evaluation domain
827 let mut rgsw_cts = value.rgsw_cts.clone();
828 rgsw_cts.iter_mut().for_each(|c| {
829 c.iter_rows_mut()
830 .for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
831 });
832
833 // Auto keys
834 // populate pseudo random part of auto keys. Then send auto keys to
835 // evaluation domain
836 let mut auto_keys = HashMap::new();
837 let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
838 let mut auto_prng = Rng::new_with_seed(auto_seed);
839 let auto_element_dlogs = value.parameters.auto_element_dlogs();
840 let d_auto = value.parameters.auto_decomposition_count().0;
841 auto_element_dlogs.iter().for_each(|el| {
842 let auto_part_b = value
843 .auto_keys
844 .get(el)
845 .expect(&format!("Auto key for element g^{el} not found"));
846
847 assert!(auto_part_b.dimension() == (d_auto, ring_size));
848
849 let mut auto_ct = M::zeros(d_auto * 2, ring_size);
850
851 // sample part A
852 auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
853 RandomFillUniformInModulus::random_fill(
854 &mut auto_prng,
855 value.parameters.rlwe_q(),
856 ri.as_mut(),
857 )
858 });
859
860 // Copy over part B
861 izip!(
862 auto_ct.iter_rows_mut().skip(d_auto),
863 auto_part_b.iter_rows()
864 )
865 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
866
867 // send to evaluation domain
868 auto_ct
869 .iter_rows_mut()
870 .for_each(|r| rlwe_nttop.forward(r.as_mut()));
871
872 auto_keys.insert(*el, auto_ct);
873 });
874
875 // LWE ksk
876 // populate pseudo random part of lwe ciphertexts in ksk and copy over part b
877 // elements
878 let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
879 let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
880 let mut lwe_ksk = M::zeros(
881 value.parameters.lwe_decomposition_count().0 * ring_size,
882 value.parameters.lwe_n().0 + 1,
883 );
884 lwe_ksk.iter_rows_mut().for_each(|ri| {
885 // first element is resereved for part b. Only sample a_is in the rest
886 RandomFillUniformInModulus::random_fill(
887 &mut lwe_ksk_prng,
888 value.parameters.lwe_q(),
889 &mut ri.as_mut()[1..],
890 )
891 });
892 // copy over part bs
893 assert!(
894 value.lwe_ksk.as_ref().len()
895 == value.parameters.lwe_decomposition_count().0 * ring_size
896 );
897 izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
898 |(b_el, lwe_ct)| {
899 lwe_ct.as_mut()[0] = *b_el;
900 },
901 );
902
903 // u_i to s ksk
904 let d_uitos = value
905 .parameters
906 .non_interactive_ui_to_s_key_switch_decomposition_count()
907 .0;
908 let ui_to_s_ksks = value
909 .ui_to_s_ksks
910 .iter()
911 .enumerate()
912 .map(|(user_id, incoming_ksk_partb)| {
913 let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_id);
914 let mut prng = Rng::new_with_seed(user_i_seed);
915
916 let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
917
918 ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
919 RandomFillUniformInModulus::random_fill(
920 &mut prng,
921 value.parameters.rlwe_q(),
922 r.as_mut(),
923 );
924 });
925
926 assert!(incoming_ksk_partb.dimension() == (d_uitos, ring_size));
927 izip!(
928 ksk_ct.iter_rows_mut().skip(d_uitos),
929 incoming_ksk_partb.iter_rows()
930 )
931 .for_each(|(to_ri, from_ri)| {
932 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
933 });
934
935 ksk_ct
936 .iter_rows_mut()
937 .for_each(|r| rlwe_nttop.forward(r.as_mut()));
938 ksk_ct
939 })
940 .collect_vec();
941
942 NonInteractiveServerKeyEvaluationDomain {
943 rgsw_cts,
944 auto_keys,
945 lwe_ksk,
946 ui_to_s_ksks,
947 parameters: value.parameters.clone(),
948 _phanton: PhantomData,
949 }
950 }
951 }
952
953 #[cfg(test)]
954 impl<M, P, R, N> super::super::print_noise::CollectRuntimeServerKeyStats
955 for NonInteractiveServerKeyEvaluationDomain<M, P, R, N>
956 {
957 type M = M;
958 fn galois_key_for_auto(&self, k: usize) -> &Self::M {
959 self.auto_keys.get(&k).unwrap()
960 }
961 fn lwe_ksk(&self) -> &Self::M {
962 &self.lwe_ksk
963 }
964 fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M {
965 &self.rgsw_cts[s_index]
966 }
967 }
968}
969
970pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
971 /// u_i to s key switching keys in random order. Key switchin key for user j
972 /// is stored at j^th index
973 ui_to_s_ksks: Vec<M>,
974 /// RGSW ciphertets
975 rgsw_cts: Vec<M>,
976 auto_keys: HashMap<usize, M>,
977 lwe_ksk: M::R,
978 cr_seed: S,
979 parameters: P,
980}
981
982impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
983 pub(super) fn new(
984 ui_to_s_ksks: Vec<M>,
985
986 rgsw_cts: Vec<M>,
987 auto_keys: HashMap<usize, M>,
988 lwe_ksk: M::R,
989 cr_seed: S,
990 parameters: P,
991 ) -> Self {
992 Self {
993 ui_to_s_ksks,
994
995 rgsw_cts,
996 auto_keys,
997 lwe_ksk,
998 cr_seed,
999 parameters,
1000 }
1001 }
1002}
1003
1004pub(crate) struct ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1005 /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
1006 rgsw_cts: Vec<NormalAndShoup<M>>,
1007 /// Automorphism keys under ideal rlwe secret
1008 auto_keys: HashMap<usize, NormalAndShoup<M>>,
1009 /// LWE key switching key from Q -> Q_{ks}
1010 lwe_ksk: M,
1011 /// Key switching key from user j to ideal secret key s. User j's ksk is at
1012 /// j'th element
1013 ui_to_s_ksks: Vec<NormalAndShoup<M>>,
1014}
1015
1016mod impl_shoup_non_interactive_server_key_eval_domain {
1017 use itertools::Itertools;
1018 use num_traits::{FromPrimitive, PrimInt, ToPrimitive};
1019
1020 use super::*;
1021 use crate::{backend::Modulus, pbs::PbsKey};
1022
1023 impl<M> ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1024 pub(in super::super) fn ui_to_s_ksk(&self, user_id: usize) -> &NormalAndShoup<M> {
1025 &self.ui_to_s_ksks[user_id]
1026 }
1027 }
1028
1029 impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
1030 From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1031 for ShoupNonInteractiveServerKeyEvaluationDomain<M>
1032 where
1033 M::MatElement: FromPrimitive + ToPrimitive + PrimInt,
1034 {
1035 fn from(
1036 value: NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>,
1037 ) -> Self {
1038 let rlwe_q = value.parameters.rlwe_q().q().unwrap();
1039
1040 let rgsw_dim = (
1041 value.parameters.rlwe_rgsw_decomposition_count().0 .0 * 2
1042 + value.parameters.rlwe_rgsw_decomposition_count().1 .0 * 2,
1043 value.parameters.rlwe_n().0,
1044 );
1045 let rgsw_cts = value
1046 .rgsw_cts
1047 .into_iter()
1048 .map(|m| {
1049 assert!(m.dimension() == rgsw_dim);
1050 NormalAndShoup::new_with_modulus(m, rlwe_q)
1051 })
1052 .collect_vec();
1053
1054 let auto_dim = (
1055 value.parameters.auto_decomposition_count().0 * 2,
1056 value.parameters.rlwe_n().0,
1057 );
1058 let mut auto_keys = HashMap::new();
1059 value.auto_keys.into_iter().for_each(|(k, v)| {
1060 assert!(v.dimension() == auto_dim);
1061 auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
1062 });
1063
1064 let ui_ks_dim = (
1065 value
1066 .parameters
1067 .non_interactive_ui_to_s_key_switch_decomposition_count()
1068 .0
1069 * 2,
1070 value.parameters.rlwe_n().0,
1071 );
1072 let ui_to_s_ksks = value
1073 .ui_to_s_ksks
1074 .into_iter()
1075 .map(|m| {
1076 assert!(m.dimension() == ui_ks_dim);
1077 NormalAndShoup::new_with_modulus(m, rlwe_q)
1078 })
1079 .collect_vec();
1080
1081 assert!(
1082 value.lwe_ksk.dimension()
1083 == (
1084 value.parameters.rlwe_n().0 * value.parameters.lwe_decomposition_count().0,
1085 value.parameters.lwe_n().0 + 1
1086 )
1087 );
1088
1089 Self {
1090 rgsw_cts,
1091 auto_keys,
1092 lwe_ksk: value.lwe_ksk,
1093 ui_to_s_ksks,
1094 }
1095 }
1096 }
1097
1098 impl<M: Matrix> PbsKey for ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1099 type AutoKey = NormalAndShoup<M>;
1100 type LweKskKey = M;
1101 type RgswCt = NormalAndShoup<M>;
1102
1103 fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1104 let d = self.auto_keys.get(&k).unwrap();
1105 d
1106 }
1107 fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1108 &self.rgsw_cts[si]
1109 }
1110
1111 fn lwe_ksk(&self) -> &Self::LweKskKey {
1112 &self.lwe_ksk
1113 }
1114 }
1115}
1116
1117/// Server key in evaluation domain with Shoup representations
1118pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
1119 /// Rgsw cts of LWE secret elements
1120 rgsw_cts: Vec<NormalAndShoup<M>>,
1121 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
1122 /// to -g is at 0
1123 galois_keys: HashMap<usize, NormalAndShoup<M>>,
1124 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
1125 lwe_ksk: M,
1126}
1127
1128mod shoup_server_key_eval_domain {
1129 use itertools::{izip, Itertools};
1130 use num_traits::{FromPrimitive, PrimInt};
1131
1132 use crate::{backend::Modulus, pbs::PbsKey};
1133
1134 use super::*;
1135
1136 impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
1137 From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1138 for ShoupServerKeyEvaluationDomain<M>
1139 where
1140 <M as Matrix>::R: RowMut,
1141 M::MatElement: PrimInt + FromPrimitive,
1142 {
1143 fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
1144 let q = value.parameters.rlwe_q().q().unwrap();
1145 // Rgsw ciphertexts
1146 let rgsw_cts = value
1147 .rgsw_cts
1148 .into_iter()
1149 .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
1150 .collect_vec();
1151
1152 let mut auto_keys = HashMap::new();
1153 value.galois_keys.into_iter().for_each(|(index, key)| {
1154 auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
1155 });
1156
1157 Self {
1158 rgsw_cts,
1159 galois_keys: auto_keys,
1160 lwe_ksk: value.lwe_ksk,
1161 }
1162 }
1163 }
1164
1165 impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
1166 type AutoKey = NormalAndShoup<M>;
1167 type LweKskKey = M;
1168 type RgswCt = NormalAndShoup<M>;
1169
1170 fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1171 self.galois_keys.get(&k).unwrap()
1172 }
1173 fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1174 &self.rgsw_cts[si]
1175 }
1176
1177 fn lwe_ksk(&self) -> &Self::LweKskKey {
1178 &self.lwe_ksk
1179 }
1180 }
1181}
1182
1183pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
1184 /// Non-interactive RGSW ciphertexts for secret indices for which user is
1185 /// the leader
1186 self_leader_ni_rgsw_cts: Vec<M>,
1187 /// Non-interactive RGSW ciphertexts for secret indices for which user is
1188 /// not the leader
1189 not_self_leader_ni_rgsw_cts: Vec<M>,
1190 /// Zero encryptions for RGSW ciphertexts for all indicces
1191 ni_rgsw_zero_encs: Vec<M>,
1192
1193 /// (ak*si + e + \beta ui, ak*si + e)
1194 ui_to_s_ksk: M,
1195 ksk_zero_encs_for_others: Vec<M>,
1196
1197 auto_keys_share: HashMap<usize, M>,
1198 lwe_ksk_share: M::R,
1199
1200 user_index: usize,
1201 total_users: usize,
1202 lwe_n: usize,
1203 cr_seed: S,
1204}
1205
1206mod impl_common_ref_non_interactive_multi_party_server_share {
1207 use crate::evaluator::interactive_mult_party_user_id_lwe_segment;
1208
1209 use super::*;
1210
1211 impl<M: Matrix, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, S> {
1212 pub(in super::super) fn new(
1213 self_leader_ni_rgsw_cts: Vec<M>,
1214 not_self_leader_ni_rgsw_cts: Vec<M>,
1215 ni_rgsw_zero_encs: Vec<M>,
1216 ui_to_s_ksk: M,
1217 ksk_zero_encs_for_others: Vec<M>,
1218 auto_keys_share: HashMap<usize, M>,
1219 lwe_ksk_share: M::R,
1220 user_index: usize,
1221 total_users: usize,
1222 lwe_n: usize,
1223 cr_seed: S,
1224 ) -> Self {
1225 Self {
1226 self_leader_ni_rgsw_cts,
1227 not_self_leader_ni_rgsw_cts,
1228 ni_rgsw_zero_encs,
1229 ui_to_s_ksk,
1230 ksk_zero_encs_for_others,
1231 auto_keys_share,
1232 lwe_ksk_share,
1233 user_index,
1234 total_users,
1235 lwe_n,
1236 cr_seed,
1237 }
1238 }
1239
1240 pub(in super::super) fn ni_rgsw_cts_for_self_leader_lwe_index(
1241 &self,
1242 lwe_index: usize,
1243 ) -> &M {
1244 let self_segment = interactive_mult_party_user_id_lwe_segment(
1245 self.user_index,
1246 self.total_users,
1247 self.lwe_n,
1248 );
1249 assert!(lwe_index >= self_segment.0 && lwe_index < self_segment.1);
1250 &self.self_leader_ni_rgsw_cts[lwe_index - self_segment.0]
1251 }
1252
1253 pub(in super::super) fn ni_rgsw_cts_for_self_not_leader_lwe_index(
1254 &self,
1255 lwe_index: usize,
1256 ) -> &M {
1257 let self_segment = interactive_mult_party_user_id_lwe_segment(
1258 self.user_index,
1259 self.total_users,
1260 self.lwe_n,
1261 );
1262 // Non-interactive RGSW cts when self is not leader are stored in
1263 // sorted-order. For ex, if self is the leader for indices (5, 6]
1264 // then self stores NI-RGSW cts for rest of indices like [0, 1, 2,
1265 // 3, 4, 6, 7, 8, 9]
1266 assert!(lwe_index < self.lwe_n);
1267 assert!(lwe_index < self_segment.0 || lwe_index >= self_segment.1);
1268 if lwe_index < self_segment.0 {
1269 &self.not_self_leader_ni_rgsw_cts[lwe_index]
1270 } else {
1271 &self.not_self_leader_ni_rgsw_cts[lwe_index - (self_segment.1 - self_segment.0)]
1272 }
1273 }
1274
1275 pub(in super::super) fn ni_rgsw_zero_enc_for_lwe_index(&self, lwe_index: usize) -> &M {
1276 &self.ni_rgsw_zero_encs[lwe_index]
1277 }
1278
1279 pub(in super::super) fn ui_to_s_ksk(&self) -> &M {
1280 &self.ui_to_s_ksk
1281 }
1282
1283 pub(in super::super) fn user_index(&self) -> usize {
1284 self.user_index
1285 }
1286
1287 pub(in super::super) fn auto_keys_share(&self) -> &HashMap<usize, M> {
1288 &self.auto_keys_share
1289 }
1290
1291 pub(in super::super) fn lwe_ksk_share(&self) -> &M::R {
1292 &self.lwe_ksk_share
1293 }
1294
1295 pub(in super::super) fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M {
1296 assert!(user_i != self.user_index);
1297 if user_i < self.user_index {
1298 &self.ksk_zero_encs_for_others[user_i]
1299 } else {
1300 &self.ksk_zero_encs_for_others[user_i - 1]
1301 }
1302 }
1303 }
1304}
1305
1306/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
1307pub(crate) struct NormalAndShoup<M>(M, M);
1308
1309impl<M: ToShoup> NormalAndShoup<M> {
1310 fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
1311 let value_shoup = M::to_shoup(&value, modulus);
1312 NormalAndShoup(value, value_shoup)
1313 }
1314}
1315
1316impl<M> AsRef<M> for NormalAndShoup<M> {
1317 fn as_ref(&self) -> &M {
1318 &self.0
1319 }
1320}
1321
1322impl<M> WithShoupRepr for NormalAndShoup<M> {
1323 type M = M;
1324 fn shoup_repr(&self) -> &Self::M {
1325 &self.1
1326 }
1327}
1328
1329pub(super) mod tests {
1330 use itertools::izip;
1331 use num_traits::{FromPrimitive, PrimInt, ToPrimitive, Zero};
1332
1333 use crate::{
1334 backend::{GetModulus, Modulus},
1335 bool::ClientKey,
1336 lwe::decrypt_lwe,
1337 parameters::CiphertextModulus,
1338 utils::TryConvertFrom1,
1339 ArithmeticOps, Row,
1340 };
1341
1342 use super::SinglePartyClientKey;
1343
1344 pub(crate) fn ideal_sk_rlwe(cks: &[ClientKey]) -> Vec<i32> {
1345 let mut ideal_rlwe_sk = cks[0].sk_rlwe();
1346 cks.iter().skip(1).for_each(|k| {
1347 let sk_rlwe = k.sk_rlwe();
1348 izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1349 *a = *a + b;
1350 });
1351 });
1352 ideal_rlwe_sk
1353 }
1354
1355 pub(crate) fn ideal_sk_lwe(cks: &[ClientKey]) -> Vec<i32> {
1356 let mut ideal_rlwe_sk = cks[0].sk_lwe();
1357 cks.iter().skip(1).for_each(|k| {
1358 let sk_rlwe = k.sk_lwe();
1359 izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1360 *a = *a + b;
1361 });
1362 });
1363 ideal_rlwe_sk
1364 }
1365
1366 pub(crate) fn measure_noise_lwe<
1367 R: Row,
1368 S,
1369 Modop: ArithmeticOps<Element = R::Element>
1370 + GetModulus<M = CiphertextModulus<R::Element>, Element = R::Element>,
1371 >(
1372 lwe_ct: &R,
1373 m_expected: R::Element,
1374 sk: &[S],
1375 modop: &Modop,
1376 ) -> f64
1377 where
1378 R: TryConvertFrom1<[S], CiphertextModulus<R::Element>>,
1379 R::Element: Zero + FromPrimitive + PrimInt,
1380 {
1381 let noisy_m = decrypt_lwe(lwe_ct, &sk, modop);
1382 let noise = modop.sub(&m_expected, &noisy_m);
1383 modop
1384 .modulus()
1385 .map_element_to_i64(&noise)
1386 .abs()
1387 .to_f64()
1388 .unwrap()
1389 .log2()
1390 }
1391}