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