phantom-zone/src/bool/keys.rs
src/bool/keys.rsRaw
1use std::{collections::HashMap, hash::Hash, marker::PhantomData};
2
3use crate::{
4 backend::{ModInit, VectorOps},
5 lwe::LweSecret,
6 pbs::WithShoupRepr,
7 random::{NewWithSeed, RandomFillUniformInModulus},
8 rgsw::RlweSecret,
9 utils::{ToShoup, WithLocal},
10 Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut,
11};
12
13use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus};
14
15/// Client key with RLWE and LWE secrets
16#[derive(Clone)]
17pub struct ClientKey {
18 sk_rlwe: RlweSecret,
19 sk_lwe: LweSecret,
20}
21
22/// Client key with RLWE and LWE secrets
23#[derive(Clone)]
24pub struct NonInteractiveClientKey {
25 sk_rlwe: RlweSecret,
26 sk_u_rlwe: RlweSecret,
27 sk_lwe: LweSecret,
28}
29
30mod impl_ck {
31 use super::*;
32
33 // Client key
34 impl ClientKey {
35 pub(in super::super) fn random() -> Self {
36 let sk_rlwe = RlweSecret::random(0, 0);
37 let sk_lwe = LweSecret::random(0, 0);
38 Self { sk_rlwe, sk_lwe }
39 }
40
41 pub(in super::super) fn new(sk_rlwe: RlweSecret, sk_lwe: LweSecret) -> Self {
42 Self { sk_rlwe, sk_lwe }
43 }
44
45 pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret {
46 &self.sk_rlwe
47 }
48
49 pub(in super::super) fn sk_lwe(&self) -> &LweSecret {
50 &self.sk_lwe
51 }
52 }
53
54 // Client key
55 impl NonInteractiveClientKey {
56 pub(in super::super) fn random() -> Self {
57 let sk_rlwe = RlweSecret::random(0, 0);
58 let sk_u_rlwe = RlweSecret::random(0, 0);
59 let sk_lwe = LweSecret::random(0, 0);
60 Self {
61 sk_rlwe,
62 sk_u_rlwe,
63 sk_lwe,
64 }
65 }
66
67 pub(in super::super) fn new(
68 sk_rlwe: RlweSecret,
69 sk_u_rlwe: RlweSecret,
70 sk_lwe: LweSecret,
71 ) -> Self {
72 Self {
73 sk_rlwe,
74 sk_u_rlwe,
75 sk_lwe,
76 }
77 }
78
79 pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret {
80 &self.sk_rlwe
81 }
82
83 pub(in super::super) fn sk_u_rlwe(&self) -> &RlweSecret {
84 &self.sk_u_rlwe
85 }
86
87 pub(in super::super) fn sk_lwe(&self) -> &LweSecret {
88 &self.sk_lwe
89 }
90 }
91
92 impl Encryptor<bool, Vec<u64>> for ClientKey {
93 fn encrypt(&self, m: &bool) -> Vec<u64> {
94 BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self))
95 }
96 }
97
98 impl Decryptor<bool, Vec<u64>> for ClientKey {
99 fn decrypt(&self, c: &Vec<u64>) -> bool {
100 BoolEvaluator::with_local(|e| e.sk_decrypt(c, self))
101 }
102 }
103
104 impl MultiPartyDecryptor<bool, Vec<u64>> for ClientKey {
105 type DecryptionShare = u64;
106
107 fn gen_decryption_share(&self, c: &Vec<u64>) -> Self::DecryptionShare {
108 BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, &self))
109 }
110
111 fn aggregate_decryption_shares(
112 &self,
113 c: &Vec<u64>,
114 shares: &[Self::DecryptionShare],
115 ) -> bool {
116 BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c))
117 }
118 }
119}
120
121/// Public key
122pub struct PublicKey<M, Rng, ModOp> {
123 key: M,
124 _phantom: PhantomData<(Rng, ModOp)>,
125}
126
127pub(super) mod impl_pk {
128 use super::*;
129
130 impl<M, R, Mo> PublicKey<M, R, Mo> {
131 pub(in super::super) fn key(&self) -> &M {
132 &self.key
133 }
134 }
135
136 impl<Rng, ModOp> Encryptor<bool, Vec<u64>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
137 fn encrypt(&self, m: &bool) -> Vec<u64> {
138 BoolEvaluator::with_local(|e| e.pk_encrypt(&self.key, *m))
139 }
140 }
141
142 impl<Rng, ModOp> Encryptor<[bool], Vec<Vec<u64>>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
143 fn encrypt(&self, m: &[bool]) -> Vec<Vec<u64>> {
144 BoolEvaluator::with_local(|e| e.pk_encrypt_batched(&self.key, m))
145 }
146 }
147
148 impl<
149 M: MatrixMut + MatrixEntity,
150 Rng: NewWithSeed
151 + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
152 ModOp,
153 > From<SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>>
154 for PublicKey<M, Rng, ModOp>
155 where
156 <M as Matrix>::R: RowMut,
157 M::MatElement: Copy,
158 {
159 fn from(
160 value: SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>,
161 ) -> Self {
162 let mut prng = Rng::new_with_seed(value.seed);
163
164 let mut key = M::zeros(2, value.parameters.rlwe_n().0);
165 // sample A
166 RandomFillUniformInModulus::random_fill(
167 &mut prng,
168 value.parameters.rlwe_q(),
169 key.get_row_mut(0),
170 );
171 // Copy over B
172 key.get_row_mut(1).copy_from_slice(value.part_b.as_ref());
173
174 PublicKey {
175 key,
176 _phantom: PhantomData,
177 }
178 }
179 }
180
181 impl<
182 M: MatrixMut + MatrixEntity,
183 Rng: NewWithSeed
184 + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
185 ModOp: VectorOps<Element = M::MatElement> + ModInit<M = CiphertextModulus<M::MatElement>>,
186 >
187 From<
188 &[CommonReferenceSeededCollectivePublicKeyShare<
189 M::R,
190 Rng::Seed,
191 BoolParameters<M::MatElement>,
192 >],
193 > for PublicKey<M, Rng, ModOp>
194 where
195 <M as Matrix>::R: RowMut,
196 Rng::Seed: Copy + PartialEq,
197 M::MatElement: PartialEq + Copy,
198 {
199 fn from(
200 value: &[CommonReferenceSeededCollectivePublicKeyShare<
201 M::R,
202 Rng::Seed,
203 BoolParameters<M::MatElement>,
204 >],
205 ) -> Self {
206 assert!(value.len() > 0);
207
208 let parameters = &value[0].parameters;
209 let mut key = M::zeros(2, parameters.rlwe_n().0);
210
211 // sample A
212 let seed = value[0].cr_seed;
213 let mut main_rng = Rng::new_with_seed(seed);
214 RandomFillUniformInModulus::random_fill(
215 &mut main_rng,
216 parameters.rlwe_q(),
217 key.get_row_mut(0),
218 );
219
220 // Sum all Bs
221 let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
222 value.iter().for_each(|share_i| {
223 assert!(share_i.cr_seed == seed);
224 assert!(&share_i.parameters == parameters);
225
226 rlweq_modop.elwise_add_mut(key.get_row_mut(1), share_i.share.as_ref());
227 });
228
229 PublicKey {
230 key,
231 _phantom: PhantomData,
232 }
233 }
234 }
235}
236
237/// Seeded public key
238struct SeededPublicKey<Ro, S, P, ModOp> {
239 part_b: Ro,
240 seed: S,
241 parameters: P,
242 _phantom: PhantomData<ModOp>,
243}
244
245mod impl_seeded_pk {
246 use super::*;
247
248 impl<R, S, ModOp>
249 From<&[CommonReferenceSeededCollectivePublicKeyShare<R, S, BoolParameters<R::Element>>]>
250 for SeededPublicKey<R, S, BoolParameters<R::Element>, ModOp>
251 where
252 ModOp: VectorOps<Element = R::Element> + ModInit<M = CiphertextModulus<R::Element>>,
253 S: PartialEq + Clone,
254 R: RowMut + RowEntity + Clone,
255 R::Element: Clone + PartialEq,
256 {
257 fn from(
258 value: &[CommonReferenceSeededCollectivePublicKeyShare<
259 R,
260 S,
261 BoolParameters<R::Element>,
262 >],
263 ) -> Self {
264 assert!(value.len() > 0);
265
266 let parameters = &value[0].parameters;
267 let cr_seed = value[0].cr_seed.clone();
268
269 // Sum all Bs
270 let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
271 let mut part_b = value[0].share.clone();
272 value.iter().skip(1).for_each(|share_i| {
273 assert!(&share_i.cr_seed == &cr_seed);
274 assert!(&share_i.parameters == parameters);
275
276 rlweq_modop.elwise_add_mut(part_b.as_mut(), share_i.share.as_ref());
277 });
278
279 Self {
280 part_b,
281 seed: cr_seed,
282 parameters: parameters.clone(),
283 _phantom: PhantomData,
284 }
285 }
286 }
287}
288
289/// CRS seeded collective public key share
290pub struct CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
291 share: Ro,
292 cr_seed: S,
293 parameters: P,
294}
295impl<Ro, S, P> CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
296 pub(super) fn new(share: Ro, cr_seed: S, parameters: P) -> Self {
297 CommonReferenceSeededCollectivePublicKeyShare {
298 share,
299 cr_seed,
300 parameters,
301 }
302 }
303}
304
305/// CRS seeded Multi-party server key share
306pub struct CommonReferenceSeededMultiPartyServerKeyShare<M: Matrix, P, S> {
307 rgsw_cts: Vec<M>,
308 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
309 /// to -g is at 0
310 auto_keys: HashMap<usize, M>,
311 lwe_ksk: M::R,
312 /// Common reference seed
313 cr_seed: S,
314 parameters: P,
315}
316
317impl<M: Matrix, P, S> CommonReferenceSeededMultiPartyServerKeyShare<M, P, S> {
318 pub(super) fn new(
319 rgsw_cts: Vec<M>,
320 auto_keys: HashMap<usize, M>,
321 lwe_ksk: M::R,
322 cr_seed: S,
323 parameters: P,
324 ) -> Self {
325 CommonReferenceSeededMultiPartyServerKeyShare {
326 rgsw_cts,
327 auto_keys,
328 lwe_ksk,
329 cr_seed,
330 parameters,
331 }
332 }
333
334 pub(super) fn cr_seed(&self) -> &S {
335 &self.cr_seed
336 }
337
338 pub(super) fn parameters(&self) -> &P {
339 &self.parameters
340 }
341
342 pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
343 &self.auto_keys
344 }
345
346 pub(super) fn rgsw_cts(&self) -> &[M] {
347 &self.rgsw_cts
348 }
349
350 pub(super) fn lwe_ksk(&self) -> &M::R {
351 &self.lwe_ksk
352 }
353}
354
355/// CRS seeded MultiParty server key
356pub struct SeededMultiPartyServerKey<M: Matrix, S, P> {
357 rgsw_cts: Vec<M>,
358 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
359 /// to -g is at 0
360 auto_keys: HashMap<usize, M>,
361 lwe_ksk: M::R,
362 cr_seed: S,
363 parameters: P,
364}
365
366impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
367 pub(super) fn new(
368 rgsw_cts: Vec<M>,
369 auto_keys: HashMap<usize, M>,
370 lwe_ksk: M::R,
371 cr_seed: S,
372 parameters: P,
373 ) -> Self {
374 SeededMultiPartyServerKey {
375 rgsw_cts,
376 auto_keys,
377 lwe_ksk,
378 cr_seed,
379 parameters,
380 }
381 }
382
383 pub(super) fn rgsw_cts(&self) -> &[M] {
384 &self.rgsw_cts
385 }
386}
387
388/// Seeded single party server key
389pub struct SeededServerKey<M: Matrix, P, S> {
390 /// Rgsw cts of LWE secret elements
391 pub(crate) rgsw_cts: Vec<M>,
392 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
393 /// to -g is at 0
394 pub(crate) auto_keys: HashMap<usize, M>,
395 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
396 pub(crate) lwe_ksk: M::R,
397 /// Parameters
398 pub(crate) parameters: P,
399 /// Main seed
400 pub(crate) seed: S,
401}
402impl<M: Matrix, S> SeededServerKey<M, BoolParameters<M::MatElement>, S> {
403 pub(super) fn from_raw(
404 auto_keys: HashMap<usize, M>,
405 rgsw_cts: Vec<M>,
406 lwe_ksk: M::R,
407 parameters: BoolParameters<M::MatElement>,
408 seed: S,
409 ) -> Self {
410 // sanity checks
411 auto_keys.iter().for_each(|v| {
412 assert!(
413 v.1.dimension()
414 == (
415 parameters.auto_decomposition_count().0,
416 parameters.rlwe_n().0
417 )
418 )
419 });
420
421 let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
422 rgsw_cts.iter().for_each(|v| {
423 assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
424 });
425 assert!(
426 lwe_ksk.as_ref().len()
427 == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
428 );
429
430 SeededServerKey {
431 rgsw_cts,
432 auto_keys,
433 lwe_ksk,
434 parameters,
435 seed,
436 }
437 }
438}
439
440/// Server key in evaluation domain
441pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
442 /// Rgsw cts of LWE secret elements
443 rgsw_cts: Vec<M>,
444 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
445 /// to -g is at 0
446 galois_keys: HashMap<usize, M>,
447 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
448 lwe_ksk: M,
449 parameters: P,
450 _phanton: PhantomData<(R, N)>,
451}
452
453pub(super) mod impl_server_key_eval_domain {
454 use itertools::{izip, Itertools};
455
456 use crate::{
457 backend::Modulus,
458 ntt::{Ntt, NttInit},
459 pbs::PbsKey,
460 };
461
462 use super::*;
463
464 impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
465 pub(in super::super) fn rgsw_cts(&self) -> &[M] {
466 &self.rgsw_cts
467 }
468 }
469
470 impl<
471 M: MatrixMut + MatrixEntity,
472 R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
473 + NewWithSeed,
474 N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
475 > From<&SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
476 for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
477 where
478 <M as Matrix>::R: RowMut,
479 M::MatElement: Copy,
480 R::Seed: Clone,
481 {
482 fn from(value: &SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>) -> Self {
483 let mut main_prng = R::new_with_seed(value.seed.clone());
484 let parameters = &value.parameters;
485 let g = parameters.g() as isize;
486 let ring_size = value.parameters.rlwe_n().0;
487 let lwe_n = value.parameters.lwe_n().0;
488 let rlwe_q = value.parameters.rlwe_q();
489 let lwq_q = value.parameters.lwe_q();
490
491 let nttop = N::new(rlwe_q, ring_size);
492
493 // galois keys
494 let mut auto_keys = HashMap::new();
495 let auto_decomp_count = parameters.auto_decomposition_count().0;
496 let auto_element_dlogs = parameters.auto_element_dlogs();
497 for i in auto_element_dlogs.into_iter() {
498 let seeded_auto_key = value.auto_keys.get(&i).unwrap();
499 assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
500
501 let mut data = M::zeros(auto_decomp_count * 2, ring_size);
502
503 // sample RLWE'_A(-s(X^k))
504 data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
505 RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
506 });
507
508 // copy over RLWE'B_(-s(X^k))
509 izip!(
510 data.iter_rows_mut().skip(auto_decomp_count),
511 seeded_auto_key.iter_rows()
512 )
513 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
514
515 // Send to Evaluation domain
516 data.iter_rows_mut()
517 .for_each(|ri| nttop.forward(ri.as_mut()));
518
519 auto_keys.insert(i, data);
520 }
521
522 // RGSW ciphertexts
523 let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
524 let rgsw_cts = value
525 .rgsw_cts
526 .iter()
527 .map(|seeded_rgsw_si| {
528 assert!(
529 seeded_rgsw_si.dimension()
530 == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
531 );
532
533 let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
534
535 // copy over RLWE'(-sm)
536 izip!(
537 data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
538 seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
539 )
540 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
541
542 // sample RLWE'_A(m)
543 data.iter_rows_mut()
544 .skip(rlrg_a_decomp.0 * 2)
545 .take(rlrg_b_decomp.0)
546 .for_each(|ri| {
547 RandomFillUniformInModulus::random_fill(
548 &mut main_prng,
549 &rlwe_q,
550 ri.as_mut(),
551 )
552 });
553
554 // copy over RLWE'_B(m)
555 izip!(
556 data.iter_rows_mut()
557 .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
558 seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
559 )
560 .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
561
562 // send polynomials to evaluation domain
563 data.iter_rows_mut()
564 .for_each(|ri| nttop.forward(ri.as_mut()));
565
566 data
567 })
568 .collect_vec();
569
570 // LWE ksk
571 let lwe_ksk = {
572 let d = parameters.lwe_decomposition_count().0;
573 assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
574
575 let mut data = M::zeros(d * ring_size, lwe_n + 1);
576 izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
577 |(lwe_i, bi)| {
578 RandomFillUniformInModulus::random_fill(
579 &mut main_prng,
580 &lwq_q,
581 &mut lwe_i.as_mut()[1..],
582 );
583 lwe_i.as_mut()[0] = *bi;
584 },
585 );
586
587 data
588 };
589
590 ServerKeyEvaluationDomain {
591 rgsw_cts,
592 galois_keys: auto_keys,
593 lwe_ksk,
594 parameters: parameters.clone(),
595 _phanton: PhantomData,
596 }
597 }
598 }
599
600 impl<
601 M: MatrixMut + MatrixEntity,
602 Rng: NewWithSeed,
603 N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
604 > From<&SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>>
605 for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
606 where
607 <M as Matrix>::R: RowMut,
608 Rng::Seed: Copy,
609 Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
610 M::MatElement: Copy,
611 {
612 fn from(
613 value: &SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>,
614 ) -> Self {
615 let g = value.parameters.g() as isize;
616 let rlwe_n = value.parameters.rlwe_n().0;
617 let lwe_n = value.parameters.lwe_n().0;
618 let rlwe_q = value.parameters.rlwe_q();
619 let lwe_q = value.parameters.lwe_q();
620
621 let mut main_prng = Rng::new_with_seed(value.cr_seed);
622
623 let rlwe_nttop = N::new(rlwe_q, rlwe_n);
624
625 // auto keys
626 let mut auto_keys = HashMap::new();
627 let auto_d_count = value.parameters.auto_decomposition_count().0;
628 let auto_element_dlogs = value.parameters.auto_element_dlogs();
629 for i in auto_element_dlogs.into_iter() {
630 let mut key = M::zeros(auto_d_count * 2, rlwe_n);
631
632 // sample a
633 key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
634 RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
635 });
636
637 let key_part_b = value.auto_keys.get(&i).unwrap();
638 assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
639 izip!(
640 key.iter_rows_mut().skip(auto_d_count),
641 key_part_b.iter_rows()
642 )
643 .for_each(|(to_ri, from_ri)| {
644 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
645 });
646
647 // send to evaluation domain
648 key.iter_rows_mut()
649 .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
650
651 auto_keys.insert(i, key);
652 }
653
654 // rgsw cts
655 let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
656 let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
657 let rgsw_cts = value
658 .rgsw_cts
659 .iter()
660 .map(|ct_i_in| {
661 assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
662 let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
663
664 izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
665 |(to_ri, from_ri)| {
666 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
667 rlwe_nttop.forward(to_ri.as_mut());
668 },
669 );
670
671 eval_ct_i_out
672 })
673 .collect_vec();
674
675 // lwe ksk
676 let d_lwe = value.parameters.lwe_decomposition_count().0;
677 let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
678 izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
679 |(lwe_i, bi)| {
680 RandomFillUniformInModulus::random_fill(
681 &mut main_prng,
682 &lwe_q,
683 &mut lwe_i.as_mut()[1..],
684 );
685 lwe_i.as_mut()[0] = *bi;
686 },
687 );
688
689 ServerKeyEvaluationDomain {
690 rgsw_cts,
691 galois_keys: auto_keys,
692 lwe_ksk,
693 parameters: value.parameters.clone(),
694 _phanton: PhantomData,
695 }
696 }
697 }
698
699 impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
700 type AutoKey = M;
701 type LweKskKey = M;
702 type RgswCt = M;
703
704 fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
705 self.galois_keys.get(&k).unwrap()
706 }
707 fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
708 &self.rgsw_cts[si]
709 }
710
711 fn lwe_ksk(&self) -> &Self::LweKskKey {
712 &self.lwe_ksk
713 }
714 }
715}
716
717/// Server key in evaluation domain
718pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
719 /// Rgsw cts of LWE secret elements
720 rgsw_cts: Vec<NormalAndShoup<M>>,
721 /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
722 /// to -g is at 0
723 galois_keys: HashMap<usize, NormalAndShoup<M>>,
724 /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
725 lwe_ksk: M,
726}
727
728/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
729pub(crate) struct NormalAndShoup<M>(M, M);
730
731impl<M: ToShoup> NormalAndShoup<M> {
732 fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
733 let value_shoup = M::to_shoup(&value, modulus);
734 NormalAndShoup(value, value_shoup)
735 }
736}
737
738impl<M> AsRef<M> for NormalAndShoup<M> {
739 fn as_ref(&self) -> &M {
740 &self.0
741 }
742}
743
744impl<M> WithShoupRepr for NormalAndShoup<M> {
745 type M = M;
746 fn shoup_repr(&self) -> &Self::M {
747 &self.1
748 }
749}
750
751mod shoup_server_key_eval_domain {
752 use itertools::{izip, Itertools};
753 use num_traits::{FromPrimitive, PrimInt};
754
755 use crate::{backend::Modulus, pbs::PbsKey};
756
757 use super::*;
758
759 impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
760 From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
761 for ShoupServerKeyEvaluationDomain<M>
762 where
763 <M as Matrix>::R: RowMut,
764 M::MatElement: PrimInt + FromPrimitive,
765 {
766 fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
767 let q = value.parameters.rlwe_q().q().unwrap();
768 // Rgsw ciphertexts
769 let rgsw_cts = value
770 .rgsw_cts
771 .into_iter()
772 .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
773 .collect_vec();
774
775 let mut auto_keys = HashMap::new();
776 value.galois_keys.into_iter().for_each(|(index, key)| {
777 auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
778 });
779
780 Self {
781 rgsw_cts,
782 galois_keys: auto_keys,
783 lwe_ksk: value.lwe_ksk,
784 }
785 }
786 }
787
788 impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
789 type AutoKey = NormalAndShoup<M>;
790 type LweKskKey = M;
791 type RgswCt = NormalAndShoup<M>;
792
793 fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
794 self.galois_keys.get(&k).unwrap()
795 }
796 fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
797 &self.rgsw_cts[si]
798 }
799
800 fn lwe_ksk(&self) -> &Self::LweKskKey {
801 &self.lwe_ksk
802 }
803 }
804}