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