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