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