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