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