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